]> granicus.if.org Git - gc/commitdiff
gc4.14alpha2 tarball import gc4_14alpha2
authorHans Boehm <boehm@acm.org>
Fri, 26 Mar 1999 00:00:00 +0000 (00:00 +0000)
committerIvan Maidanski <ivmai@mail.ru>
Sat, 17 May 2014 13:47:31 +0000 (17:47 +0400)
23 files changed:
Makefile
README
allchblk.c
alloc.c
cord/gc.h
dbg_mlc.c
dyn_load.c
gc.h
gc_mark.h
gc_priv.h
gcconfig.h
headers.c
include/gc.h
include/private/gc_priv.h
include/private/gcconfig.h
mach_dep.c
mallocx.c
mark.c
mark_rts.c
os_dep.c
typd_mlc.c
version.h
win32_threads.c

index ffd81281aa7993df30ceea36a55a1170fb2c0b20..063d394a9e9d4d9464792d2cfb9eafc7a6aa2773 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -254,6 +254,19 @@ liblinuxgc.so: $(OBJS) dyn_load.o
        gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o -lo
        ln liblinuxgc.so libgc.so
 
+# Alternative Linux rule.  This is preferable, but is likely to break the
+# Makefile for some non-linux platforms.
+# LIBOBJS= $(patsubst %.o, %.lo, $(OBJS))
+#
+#.SUFFIXES: .lo $(SUFFIXES)
+#
+#.c.lo:
+#      $(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -c $< -o $@
+#
+# liblinuxgc.so: $(LIBOBJS) dyn_load.lo
+#      gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
+#      touch liblinuxgc.so
+
 mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ultrix_mach_dep.s $(srcdir)/rs6000_mach_dep.s $(UTILS)
        rm -f mach_dep.o
        ./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
@@ -369,7 +382,7 @@ 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"
+       lint -DLINT $(CSRCS) test.c | egrep -v "possible pointer alignment problem|abort|exit|sbrk|mprotect|syscall|change in ANSI|improper alignment"
 
 # BTL: added to test shared library version of collector.
 # Currently works only under SunOS5.  Requires GC_INIT call from statically
diff --git a/README b/README
index b245beb8176d1f45ae61df0a1efea74bb9ef790e..1df945e439698075a540ded6da5cbc35b92a6b2c 100644 (file)
--- a/README
+++ b/README
@@ -11,7 +11,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.14alpha1 of a conservative garbage collector for C and C++.
+This is version 4.14alpha2 of a conservative garbage collector for C and C++.
 
 You might find a more recent version of this at
 
@@ -22,7 +22,14 @@ HISTORY -
   Early versions of this collector were developed as a part of research
 projects supported in part by the National Science Foundation
 and the Defense Advance Research Projects Agency.
-Much of the code was rewritten by Hans-J. Boehm at Xerox PARC.
+Much of the code was rewritten by Hans-J. Boehm at Xerox PARC
+and is now maintained by him at SGI (boehm@sgi.com).
+
+Some other contributors:  
+
+More recent contributors are mentioned in the modification history at the
+end of this file.  My apologies for any omissions.
+
 The SPARC specific code was contributed by Mark Weiser
 (weiser@parc.xerox.com).  The Encore Multimax modifications were supplied by
 Kevin Kenny (kenny@m.cs.uiuc.edu).  The adaptation to the RT is largely due
@@ -59,8 +66,7 @@ made it into the released version of the collector, yet.)
 (Blame for misinstallation of these modifications goes to the first author,
 however.)
 
-Credits for some more recent modifications are given in the modification
-history at the end of this file.
+OVERVIEW
 
     This is intended to be a general purpose, garbage collecting storage
 allocator.  The algorithms used are described in:
@@ -89,7 +95,7 @@ of the ACM SIGPLAN '96 Conference on Programming Language Design and
 Implementation.
 
 (Both are also available from
-http://reality.sgi.com/employees/boehm_mti/papers/, among other places.)
+http://reality.sgi.com/boehm/papers/, among other places.)
 
   Unlike the collector described in the second reference, this collector
 operates either with the mutator stopped during the entire collection
@@ -606,7 +612,7 @@ reclaimed.  Exclusive-or'ing forward and backward links in a list
 doesn't cut it.
   Some C optimizers may lose the last undisguised pointer to a memory
 object as a consequence of clever optimizations.  This has almost
-never been observed in practice.  Send mail to boehm@mti.sgi.com
+never been observed in practice.  Send mail to boehm@sgi.com
 for suggestions on how to fix your compiler.
   This is not a real-time collector.  In the standard configuration,
 percentage of time required for collection should be constant across
@@ -615,7 +621,7 @@ heap sizes.  But collection pauses will increase for larger heaps.
 per MB of accessible memory that needs to be scanned.  Your mileage
 may vary.)  The incremental/generational collection facility helps,
 but is portable only if "stubborn" allocation is used.
-  Please address bug reports to boehm@mti.sgi.com.  If you are
+  Please address bug reports to boehm@sgi.com.  If you are
 contemplating a major addition, you might also send mail to ask whether
 it's already been done (or whether we tried and discarded it).
 
@@ -1424,13 +1430,24 @@ Since 4.13:
    after the relevant frame was overwritten, and the new save location
    might be outside the scanned area.  Fixed by more eager stack scanning.)
  - PRINT_BLACK_LIST had some problems.  A few source addresses were garbage.
- - Removed a prototype in code that shouldn't assume prototype support.
  - Replaced Makefile.dj and added -I flags to cord make targets.
    (Thanks to Gary Leavens.)
  - GC_try_to_collect was broken with the nonincremental collector.
  - gc_cleanup destructors could pass the wrong address to
    GC_register_finalizer_ignore_self in the presence of multiple
    inheritance.  (Thanks to Darrell Schiebel.)
+ - Changed PowerPC Linux stack finding code.
+
+Since 4.14alpha1
+ - -DSMALL_CONFIG did not work reliably with large (> 4K) pages.
+   Recycling the mark stack during expansion could result in a size
+   zero heap segment, which confused things.  (This was probably also an
+   issue with the normal config and huge pages.)
+ - Did more work to make sure that callee-save registers were scanned
+   completely, even with the setjmp-based code.  Added USE_GENERIC_PUSH_REGS
+   macro to facilitate testing on machines I have access to.
+ - Added code to explicitly push register contents for win32 threads.
+   This seems to be necessary.  (Thanks to Pierre de Rop.)
 
 
 To do:
index 026288e8d97d6e63d43e669d2f5ae6e9a06170cf..ff94b4803ac0c6409ab0652095ef593f29834cdd 100644 (file)
@@ -164,7 +164,8 @@ unsigned char flags;  /* IGNORE_OFF_PAGE or 0 */
                if (size_avail != size_needed
                    && !GC_incremental
                    && (word)size_needed <= GC_max_hblk_size/2
-                   && GC_in_last_heap_sect(hbp) && GC_should_collect()) {
+                   && GC_in_last_heap_sect((ptr_t)hbp)
+                   && GC_should_collect()) {
                    continue;
                } 
 #          endif
diff --git a/alloc.c b/alloc.c
index 7e1f03ec6bee0ee477677cb2705d8532c8b90024..171dc780b86404323c6577cb7c5051a004bfe48c 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -344,7 +344,7 @@ int n;
     
     if (GC_incremental && GC_collection_in_progress()) {
        for (i = GC_deficit; i < GC_RATE*n; i++) {
-           if (GC_mark_some()) {
+           if (GC_mark_some((ptr_t)0)) {
                /* Need to finish a collection */
 #              ifdef SAVE_CALL_CHAIN
                    GC_save_callers(GC_last_stack);
@@ -393,6 +393,7 @@ GC_bool GC_stopped_mark(stop_func)
 GC_stop_func stop_func;
 {
     register int i;
+    int dummy;
 #   ifdef PRINTSTATS
        CLOCK_TYPE start_time, current_time;
 #   endif
@@ -423,7 +424,7 @@ GC_stop_func stop_func;
                    START_WORLD();
                    return(FALSE);
            }
-           if (GC_mark_some()) break;
+           if (GC_mark_some((ptr_t)(&dummy))) break;
        }
        
     GC_gc_no++;
index 3b9f9ce2421bb255f54a89c63200c004a3d55fed..ceabb02f6eb611e5c4fada97e6dd589c4558ac30 100644 (file)
--- a/cord/gc.h
+++ b/cord/gc.h
@@ -268,6 +268,7 @@ GC_API void GC_gcollect GC_PROTO((void));
 /* than normal pause times for incremental collection.  However,       */
 /* aborted collections do no useful work; the next collection needs    */
 /* to start from the beginning.                                                */
+/* Return 0 if the collection was aborted, 1 if it succeeded.          */
 typedef int (* GC_stop_func) GC_PROTO((void));
 GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
 
index f9ed6f3f3668e0f71092196edc61cad481a2317d..81516258bf68d61f4730276a7710efd76ad82622 100644 (file)
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -139,7 +139,7 @@ ptr_t p;
 {
     register oh * ohdr = (oh *)GC_base(p);
     
-    GC_err_printf1("0x%lx (", (unsigned long)ohdr + sizeof(oh));
+    GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
     GC_err_puts(ohdr -> oh_string);
     GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
                                      (unsigned long)(ohdr -> oh_sz));
@@ -166,7 +166,7 @@ ptr_t p, clobbered_addr;
     if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
         || ohdr -> oh_string == 0) {
         GC_err_printf1("<smashed>, appr. sz = %ld)\n",
-                      GC_size((ptr_t)ohdr) - DEBUG_BYTES);
+                      (GC_size((ptr_t)ohdr) - DEBUG_BYTES));
     } else {
         if (ohdr -> oh_string[0] == '\0') {
             GC_err_puts("EMPTY(smashed?)");
index c228447065e93a3984c220156a272968393af3ff..56aeb3dd4503445cf9f9a70e853c1ab8869f4a6a 100644 (file)
@@ -350,6 +350,8 @@ void GC_register_dynamic_libraries()
 #include <errno.h>
 
 extern void * GC_roots_present();
+       /* The type is a lie, since the real type doesn't make sense here, */
+       /* and we only test for NULL.                                      */
 
 extern ptr_t GC_scratch_last_end_ptr; /* End of GC_scratch_alloc arena */
 
@@ -376,6 +378,8 @@ void GC_register_dynamic_libraries()
 
     if (fd < 0) {
       sprintf(buf, "/proc/%d", getpid());
+       /* The above generates a lint complaint, since pid_t varies.    */
+       /* It's unclear how to improve this.                            */
       fd = open(buf, O_RDONLY);
       if (fd < 0) {
        ABORT("/proc open failed");
@@ -388,7 +392,8 @@ void GC_register_dynamic_libraries()
     if (needed_sz >= current_sz) {
         current_sz = needed_sz * 2 + 1;
                        /* Expansion, plus room for 0 record */
-        addr_map = (prmap_t *)GC_scratch_alloc(current_sz * sizeof(prmap_t));
+        addr_map = (prmap_t *)GC_scratch_alloc((word)
+                                               (current_sz * sizeof(prmap_t)));
     }
     if (ioctl(fd, PIOCMAP, addr_map) < 0) {
         GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
diff --git a/gc.h b/gc.h
index 3b9f9ce2421bb255f54a89c63200c004a3d55fed..ceabb02f6eb611e5c4fada97e6dd589c4558ac30 100644 (file)
--- a/gc.h
+++ b/gc.h
@@ -268,6 +268,7 @@ GC_API void GC_gcollect GC_PROTO((void));
 /* than normal pause times for incremental collection.  However,       */
 /* aborted collections do no useful work; the next collection needs    */
 /* to start from the beginning.                                                */
+/* Return 0 if the collection was aborted, 1 if it succeeded.          */
 typedef int (* GC_stop_func) GC_PROTO((void));
 GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
 
index 406cba6f7d6d33539d8d19ff89fd4184a523432b..8b57c31fdb56af4dda7cdc3d59fbff86f54c4b78 100644 (file)
--- a/gc_mark.h
+++ b/gc_mark.h
@@ -224,7 +224,7 @@ mse * GC_signal_mark_stack_overflow();
     while (!GC_mark_stack_empty()) GC_mark_from_mark_stack(); \
     if (GC_mark_state != MS_NONE) { \
         GC_set_mark_bit(real_ptr); \
-        while (!GC_mark_some()); \
+        while (!GC_mark_some((ptr_t)0)); \
     } \
 }
 
index 46184522d55221f453e0494266006f910eb00a8e..934075fa358c8faf5778e7bba7b34f0fbb52e631 100644 (file)
--- a/gc_priv.h
+++ b/gc_priv.h
@@ -1323,7 +1323,8 @@ void GC_mark_from_mark_stack(); /* Mark from everything on the mark stack. */
                                /* Return after about one pages worth of   */
                                /* work.                                   */
 GC_bool GC_mark_stack_empty();
-GC_bool GC_mark_some();        /* Perform about one pages worth of marking     */
+GC_bool GC_mark_some(/* cold_gc_frame */);
+                       /* Perform about one pages worth of marking     */
                        /* work of whatever kind is needed.  Returns    */
                        /* quickly if no collection is in progress.     */
                        /* Return TRUE if mark phase finished.          */
@@ -1345,7 +1346,31 @@ void GC_push_dirty(/*b,t*/);      /* Push all possibly changed           */
                                /* on the third arg.                    */
 void GC_push_all_stack(/*b,t*/);    /* As above, but consider          */
                                    /*  interior pointers as valid      */
-void GC_push_roots(/* GC_bool all */); /* Push all or dirty roots.     */
+void GC_push_all_eager(/*b,t*/);    /* Same as GC_push_all_stack, but   */
+                                   /* ensures that stack is scanned    */
+                                   /* immediately, not just scheduled  */
+                                   /* for scanning.                    */
+#ifndef THREADS
+  void GC_push_all_stack_partially_eager(/* bottom, top, cold_gc_frame */);
+                       /* Similar to GC_push_all_eager, but only the   */
+                       /* part hotter than cold_gc_frame is scanned    */
+                       /* immediately.  Needed to endure that callee-  */
+                       /* save registers are not missed.               */
+#else
+  /* In the threads case, we push part of the current thread stack     */
+  /* with GC_push_all_eager when we push the registers.  This gets the  */
+  /* callee-save registers that may disappear.  The remainder of the   */
+  /* stacks are scheduled for scanning in *GC_push_other_roots, which  */
+  /* is thread-package-specific.                                       */
+#endif
+void GC_push_current_stack(/* ptr_t cold_gc_frame */);
+                       /* Push enough of the current stack eagerly to  */
+                       /* ensure that callee-save registers saved in   */
+                       /* GC frames are scanned.                       */
+                       /* In the non-threads case, schedule entire     */
+                       /* stack for scanning.                          */
+void GC_push_roots(/* GC_bool all, ptr_t cold_gc_frame */);
+                       /* Push all or dirty roots.     */
 extern void (*GC_push_other_roots)();
                        /* Push system or application specific roots    */
                        /* onto the mark stack.  In some environments   */
index 47545ae44e00f7978e20d1a954f22190c8851ea7..dc1c72bde4d7d417fd1553e63702987a81835e5d 100644 (file)
 #    define HP
 #    define mach_type_known
 # endif
+# if defined(__OpenBSD__) && defined(m68k)
+#    define M68K
+#    define OPENBSD
+#    define mach_type_known
+# endif
 # if defined(__NetBSD__) && defined(m68k)
 #    define M68K
 #    define NETBSD
 #   define NEXT
 #   define mach_type_known
 # endif
+# if defined(__OpenBSD__) && defined(i386)
+#   define I386
+#   define OPENBSD
+#   define mach_type_known
+# endif
 # if defined(__FreeBSD__) && defined(i386)
 #   define I386
 #   define FREEBSD
 # ifdef M68K
 #   define MACH_TYPE "M68K"
 #   define ALIGNMENT 2
+#   ifdef OPENBSD
+#      define OS_TYPE "OPENBSD"
+#      define HEURISTIC2
+       extern char etext;
+#      define DATASTART ((ptr_t)(&etext))
+#   endif
 #   ifdef NETBSD
 #      define OS_TYPE "NETBSD"
 #      define HEURISTIC2
                                                      + _stklen))
                /* This may not be right.  */
 #   endif
+#   ifdef OPENBSD
+#      define OS_TYPE "OPENBSD"
+#   endif
 #   ifdef FREEBSD
 #      define OS_TYPE "FREEBSD"
 #      define MPROTECT_VDB
 #   ifdef BSDI
 #      define OS_TYPE "BSDI"
 #   endif
-#   if defined(FREEBSD) || defined(NETBSD) \
+#   if defined(OPENBSD) || defined(FREEBSD) || defined(NETBSD) \
         || defined(THREE86BSD) || defined(BSDI)
 #      define HEURISTIC2
        extern char etext;
 #   define THREADS
 # endif
 
+# if defined(HP_PA) || defined(M88K) || defined(POWERPC) \
+     || (defined(I386) && defined(OS2)) || defined(UTS4) || defined(LINT)
+       /* Use setjmp based hack to mark from callee-save registers. */
+#      define USE_GENERIC_PUSH_REGS
+# endif
 # if defined(SPARC) && !defined(LINUX)
 #   define SAVE_CALL_CHAIN
 #   define ASM_CLEAR_CODE      /* Stack clearing is crucial, and we    */
index 89d033e2dcc5b1023b85700ddafc38ce768866db..fae683a631556878fbe189d975d57211b8e9f318 100644 (file)
--- a/headers.c
+++ b/headers.c
@@ -125,7 +125,7 @@ hdr * hhdr;
  
 void GC_init_headers()
 {
-    register int i;
+    register unsigned i;
     
     GC_all_nils = (bottom_index *)GC_scratch_alloc((word)sizeof(bottom_index));
     BZERO(GC_all_nils, sizeof(bottom_index));
index 3b9f9ce2421bb255f54a89c63200c004a3d55fed..ceabb02f6eb611e5c4fada97e6dd589c4558ac30 100644 (file)
@@ -268,6 +268,7 @@ GC_API void GC_gcollect GC_PROTO((void));
 /* than normal pause times for incremental collection.  However,       */
 /* aborted collections do no useful work; the next collection needs    */
 /* to start from the beginning.                                                */
+/* Return 0 if the collection was aborted, 1 if it succeeded.          */
 typedef int (* GC_stop_func) GC_PROTO((void));
 GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
 
index 46184522d55221f453e0494266006f910eb00a8e..934075fa358c8faf5778e7bba7b34f0fbb52e631 100644 (file)
@@ -1323,7 +1323,8 @@ void GC_mark_from_mark_stack(); /* Mark from everything on the mark stack. */
                                /* Return after about one pages worth of   */
                                /* work.                                   */
 GC_bool GC_mark_stack_empty();
-GC_bool GC_mark_some();        /* Perform about one pages worth of marking     */
+GC_bool GC_mark_some(/* cold_gc_frame */);
+                       /* Perform about one pages worth of marking     */
                        /* work of whatever kind is needed.  Returns    */
                        /* quickly if no collection is in progress.     */
                        /* Return TRUE if mark phase finished.          */
@@ -1345,7 +1346,31 @@ void GC_push_dirty(/*b,t*/);      /* Push all possibly changed           */
                                /* on the third arg.                    */
 void GC_push_all_stack(/*b,t*/);    /* As above, but consider          */
                                    /*  interior pointers as valid      */
-void GC_push_roots(/* GC_bool all */); /* Push all or dirty roots.     */
+void GC_push_all_eager(/*b,t*/);    /* Same as GC_push_all_stack, but   */
+                                   /* ensures that stack is scanned    */
+                                   /* immediately, not just scheduled  */
+                                   /* for scanning.                    */
+#ifndef THREADS
+  void GC_push_all_stack_partially_eager(/* bottom, top, cold_gc_frame */);
+                       /* Similar to GC_push_all_eager, but only the   */
+                       /* part hotter than cold_gc_frame is scanned    */
+                       /* immediately.  Needed to endure that callee-  */
+                       /* save registers are not missed.               */
+#else
+  /* In the threads case, we push part of the current thread stack     */
+  /* with GC_push_all_eager when we push the registers.  This gets the  */
+  /* callee-save registers that may disappear.  The remainder of the   */
+  /* stacks are scheduled for scanning in *GC_push_other_roots, which  */
+  /* is thread-package-specific.                                       */
+#endif
+void GC_push_current_stack(/* ptr_t cold_gc_frame */);
+                       /* Push enough of the current stack eagerly to  */
+                       /* ensure that callee-save registers saved in   */
+                       /* GC frames are scanned.                       */
+                       /* In the non-threads case, schedule entire     */
+                       /* stack for scanning.                          */
+void GC_push_roots(/* GC_bool all, ptr_t cold_gc_frame */);
+                       /* Push all or dirty roots.     */
 extern void (*GC_push_other_roots)();
                        /* Push system or application specific roots    */
                        /* onto the mark stack.  In some environments   */
index 47545ae44e00f7978e20d1a954f22190c8851ea7..dc1c72bde4d7d417fd1553e63702987a81835e5d 100644 (file)
 #    define HP
 #    define mach_type_known
 # endif
+# if defined(__OpenBSD__) && defined(m68k)
+#    define M68K
+#    define OPENBSD
+#    define mach_type_known
+# endif
 # if defined(__NetBSD__) && defined(m68k)
 #    define M68K
 #    define NETBSD
 #   define NEXT
 #   define mach_type_known
 # endif
+# if defined(__OpenBSD__) && defined(i386)
+#   define I386
+#   define OPENBSD
+#   define mach_type_known
+# endif
 # if defined(__FreeBSD__) && defined(i386)
 #   define I386
 #   define FREEBSD
 # ifdef M68K
 #   define MACH_TYPE "M68K"
 #   define ALIGNMENT 2
+#   ifdef OPENBSD
+#      define OS_TYPE "OPENBSD"
+#      define HEURISTIC2
+       extern char etext;
+#      define DATASTART ((ptr_t)(&etext))
+#   endif
 #   ifdef NETBSD
 #      define OS_TYPE "NETBSD"
 #      define HEURISTIC2
                                                      + _stklen))
                /* This may not be right.  */
 #   endif
+#   ifdef OPENBSD
+#      define OS_TYPE "OPENBSD"
+#   endif
 #   ifdef FREEBSD
 #      define OS_TYPE "FREEBSD"
 #      define MPROTECT_VDB
 #   ifdef BSDI
 #      define OS_TYPE "BSDI"
 #   endif
-#   if defined(FREEBSD) || defined(NETBSD) \
+#   if defined(OPENBSD) || defined(FREEBSD) || defined(NETBSD) \
         || defined(THREE86BSD) || defined(BSDI)
 #      define HEURISTIC2
        extern char etext;
 #   define THREADS
 # endif
 
+# if defined(HP_PA) || defined(M88K) || defined(POWERPC) \
+     || (defined(I386) && defined(OS2)) || defined(UTS4) || defined(LINT)
+       /* Use setjmp based hack to mark from callee-save registers. */
+#      define USE_GENERIC_PUSH_REGS
+# endif
 # if defined(SPARC) && !defined(LINUX)
 #   define SAVE_CALL_CHAIN
 #   define ASM_CLEAR_CODE      /* Stack clearing is crucial, and we    */
index 20931c2bd99c2171164be38e6af8d58b39b7011c..23e270e3de2a35c9389602de09b83a4985f5ee08 100644 (file)
@@ -64,6 +64,7 @@ asm static void PushMacRegisters()
 /* on your architecture.  Run the test_setjmp program to see whether    */
 /* there is any chance it will work.                                    */
 
+#ifndef USE_GENERIC_PUSH_REGS
 void GC_push_regs()
 {
 #       ifdef RT
@@ -309,7 +310,21 @@ void GC_push_regs()
 #       endif /* M68K/SYSV */
 
 
-#     if defined(HP_PA) || defined(M88K) || defined(POWERPC) || (defined(I386) && (defined(OS2) || defined(USE_GENERIC))) || defined(UTS4)
+      /* other machines... */
+#       if !(defined M68K) && !(defined VAX) && !(defined RT) 
+#      if !(defined SPARC) && !(defined I386) && !(defined NS32K)
+#      if !defined(POWERPC) && !defined(UTS4)
+           --> bad news <--
+#       endif
+#       endif
+#       endif
+}
+#endif /* !USE_GENERIC_PUSH_REGS */
+
+#if defined(USE_GENERIC_PUSH_REGS)
+void GC_generic_push_regs(cold_gc_frame)
+ptr_t cold_gc_frame;
+{
        /* Generic code                          */
        /* The idea is due to Parag Patel at HP. */
        /* We're not sure whether he would like  */
@@ -329,21 +344,10 @@ void GC_push_regs()
 #          else
                (void) _setjmp(regs);
 #          endif
-           GC_push_all_stack((ptr_t)regs, lim);
+           GC_push_current_stack(cold_gc_frame);
        }
-#     endif
-
-      /* other machines... */
-#       if !(defined M68K) && !(defined VAX) && !(defined RT) 
-#      if !(defined SPARC) && !(defined I386) && !(defined NS32K)
-#      if !defined(HP_PA) && !defined(M88K) && !defined(POWERPC)
-#      if !defined(UTS4)
-           --> bad news <--
-#      endif
-#       endif
-#       endif
-#       endif
 }
+#endif /* USE_GENERIC_PUSH_REGS */
 
 /* On register window machines, we need a way to force registers into  */
 /* the stack.  Return sp.                                              */
index ae8bfffb8afd416e6f241ba4bee29f0bd1356e1e..b1450215671e6129ebc71854408021cf9aac4a13 100644 (file)
--- a/mallocx.c
+++ b/mallocx.c
@@ -130,7 +130,7 @@ void GC_incr_mem_freed(size_t n)
      ptr_t GC_generic_malloc_words_small(size_t lw, int k)
 #else 
      ptr_t GC_generic_malloc_words_small(lw, k)
-     register size_t lw;
+     register word lw;
      register int k;
 #endif
 {
@@ -148,7 +148,7 @@ DCL_LOCK_STATE;
             GC_init_inner();
         }
        if (kind -> ok_reclaim_list != 0 || GC_alloc_reclaim_list(kind)) {
-           op = GC_clear_stack(GC_allocobj(lw, k));
+           op = GC_clear_stack(GC_allocobj((word)lw, k));
        }
        if (op == 0) {
            UNLOCK();
diff --git a/mark.c b/mark.c
index 2febda3922ca223f488e7b147bbbcab5d3fed2ea..c827af5cd124cb9ae00013294a8704a16366156f 100644 (file)
--- a/mark.c
+++ b/mark.c
@@ -241,7 +241,12 @@ static void alloc_mark_stack();
 /* Perform a small amount of marking.                  */
 /* We try to touch roughly a page of memory.           */
 /* Return TRUE if we just finished a mark phase.       */
-GC_bool GC_mark_some()
+/* Cold_gc_frame is an address inside a GC frame that  */
+/* remains valid until all marking is complete.                */
+/* A zero value indicates that it's OK to miss some    */
+/* register values.                                    */
+GC_bool GC_mark_some(cold_gc_frame)
+ptr_t cold_gc_frame;
 {
     switch(GC_mark_state) {
        case MS_NONE:
@@ -259,7 +264,7 @@ GC_bool GC_mark_some()
                        GC_printf1("Marked from %lu dirty pages\n",
                                   (unsigned long)GC_n_rescuing_pages);
 #                  endif
-                   GC_push_roots(FALSE);
+                   GC_push_roots(FALSE, cold_gc_frame);
                    GC_objects_are_marked = TRUE;
                    if (GC_mark_state != MS_INVALID) {
                        GC_mark_state = MS_ROOTS_PUSHED;
@@ -276,7 +281,7 @@ GC_bool GC_mark_some()
            } else {
                scan_ptr = GC_push_next_marked_uncollectable(scan_ptr);
                if (scan_ptr == 0) {
-                   GC_push_roots(TRUE);
+                   GC_push_roots(TRUE, cold_gc_frame);
                    GC_objects_are_marked = TRUE;
                    if (GC_mark_state != MS_INVALID) {
                        GC_mark_state = MS_ROOTS_PUSHED;
@@ -317,7 +322,7 @@ GC_bool GC_mark_some()
            }
            scan_ptr = GC_push_next_marked(scan_ptr);
            if (scan_ptr == 0 && GC_mark_state == MS_PARTIALLY_INVALID) {
-               GC_push_roots(TRUE);
+               GC_push_roots(TRUE, cold_gc_frame);
                GC_objects_are_marked = TRUE;
                if (GC_mark_state != MS_INVALID) {
                    GC_mark_state = MS_ROOTS_PUSHED;
@@ -516,13 +521,15 @@ word n;
     if (GC_mark_stack_size != 0) {
         if (new_stack != 0) {
           word displ = (word)GC_mark_stack & (GC_page_size - 1);
-          word size = GC_mark_stack_size * sizeof(struct ms_entry);
+          signed_word size = GC_mark_stack_size * sizeof(struct ms_entry);
           
           /* Recycle old space */
              if (0 != displ) displ = GC_page_size - displ;
              size = (size - displ) & ~(GC_page_size - 1);
-             GC_add_to_heap((struct hblk *)
-                               ((word)GC_mark_stack + displ), size);
+             if (size > 0) {
+               GC_add_to_heap((struct hblk *)
+                               ((word)GC_mark_stack + displ), (word)size);
+             }
           GC_mark_stack = new_stack;
           GC_mark_stack_size = n;
 #        ifdef PRINTSTATS
@@ -819,37 +826,34 @@ ptr_t top;
 #   undef GC_least_plausible_heap_addr
 }
 
+#ifndef THREADS
 /*
  * A version of GC_push_all that treats all interior pointers as valid
  * and scans part of the area immediately, to make sure that saved
  * register values are not lost.
+ * Cold_gc_frame delimits the stack section that must be scanned
+ * eagerly.  A zero value indicates that no eager scanning is needed.
  */
-void GC_push_all_stack(bottom, top)
+void GC_push_all_stack_partially_eager(bottom, top, cold_gc_frame)
 ptr_t bottom;
 ptr_t top;
+ptr_t cold_gc_frame;
 {
 # ifdef ALL_INTERIOR_POINTERS
 #   define EAGER_BYTES 1024
     /* Push the hot end of the stack eagerly, so that register values   */
     /* saved inside GC frames are marked before they disappear.                */
     /* The rest of the marking can be deferred until later.            */
-    ptr_t mid;
+    if (0 == cold_gc_frame) {
+       GC_push_all_stack(bottom, top);
+       return;
+    }
 #   ifdef STACK_GROWS_DOWN
-       mid = bottom + 1024;
-       if (mid < top) {
-           GC_push_all_eager(bottom, mid);
-           GC_push_all(mid - sizeof(ptr_t), top);
-       } else {
-           GC_push_all_eager(bottom, top);
-       }
+       GC_push_all_eager(bottom, cold_gc_frame);
+       GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
 #   else /* STACK_GROWS_UP */
-       mid = top - 1024;
-       if (mid > bottom) {
-           GC_push_all_eager(mid, top);
-           GC_push_all(bottom, mid + sizeof(ptr_t));
-       } else {
-           GC_push_all_eager(bottom, top);
-       }
+       GC_push_all_eager(cold_gc_frame, top);
+       GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t));
 #   endif /* STACK_GROWS_UP */
 # else
     GC_push_all_eager(bottom, top);
@@ -858,6 +862,18 @@ ptr_t top;
       GC_add_trace_entry("GC_push_all_stack", bottom, top);
 # endif
 }
+#endif /* !THREADS */
+
+void GC_push_all_stack(bottom, top)
+ptr_t bottom;
+ptr_t top;
+{
+# ifdef ALL_INTERIOR_POINTERS
+    GC_push_all(bottom, top);
+# else
+    GC_push_all_eager(bottom, top);
+# endif
+}
 
 #ifndef SMALL_CONFIG
 /* Push all objects reachable from marked objects in the given block */
index 5b8f8b08215c6b2382516c896bb1918e4c6aaa70..2f21ed324dd7c2d06724d52b12d2063c955b4a41 100644 (file)
@@ -399,14 +399,45 @@ int all;
     }
 }
 
+/*
+ * In the absence of threads, push the stack contents.
+ * In the presence of threads, push enough of the current stack
+ * to ensure that callee-save registers saved in collector frames have been
+ * seen.
+ */
+void GC_push_current_stack(cold_gc_frame)
+ptr_t cold_gc_frame;
+{
+#   if defined(THREADS)
+       if (0 == cold_gc_frame) return;
+#       ifdef STACK_GROWS_DOWN
+         GC_push_all_eager(GC_approx_sp(), cold_gc_frame);
+#       else
+         GC_push_all_eager( cold_gc_frame, GC_approx_sp() );
+#       endif
+#   else
+#      ifdef STACK_GROWS_DOWN
+           GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom,
+                                              cold_gc_frame );
+#       else
+           GC_push_all_stack_partially_eager( GC_stackbottom, GC_approx_sp(),
+                                              cold_gc_frame );
+#       endif
+#   endif /* !THREADS */
+}
+
 /*
  * Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional
  * on groups of pointers) on every top level accessible pointer.
  * If all is FALSE, arrange to push only possibly altered values.
+ * Cold_gc_frame is an address inside a GC frame that
+ * remains valid until all marking is complete.
+ * A zero value indicates that it's OK to miss some
+ * register values.
  */
-
-void GC_push_roots(all)
+void GC_push_roots(all, cold_gc_frame)
 GC_bool all;
+ptr_t cold_gc_frame;
 {
     register int i;
 
@@ -414,7 +445,11 @@ GC_bool all;
      * push registers - i.e., call GC_push_one(r) for each
      * register contents r.
      */
+#   ifdef USE_GENERIC_PUSH_REGS
+       GC_generic_push_regs(cold_gc_frame);
+#   else
         GC_push_regs(); /* usually defined in machine_dep.c */
+#   endif
         
     /*
      * Next push static data.  This must happen early on, since it's
@@ -436,13 +471,12 @@ GC_bool all;
     /*
      * Now traverse stacks.
      */
-#   ifndef THREADS
-        /* Mark everything on the stack.           */
-#        ifdef STACK_GROWS_DOWN
-           GC_push_all_stack( GC_approx_sp(), GC_stackbottom );
-#        else
-           GC_push_all_stack( GC_stackbottom, GC_approx_sp() );
-#        endif
+#   if !defined(USE_GENERIC_PUSH_REGS)
+       GC_push_current_stack(cold_gc_frame);
+       /* IN the threads case, this only pushes collector frames.      */
+       /* In the USE_GENERIC_PUSH_REGS case, this is done inside       */
+       /* GC_push_regs, so that we catch callee-save registers saved   */
+       /* inside the GC_push_regs frame.                               */
 #   endif
     if (GC_push_other_roots != 0) (*GC_push_other_roots)();
        /* In the threads case, this also pushes thread stacks. */
index cbef1ceedbb831580c47b5f6a561e56ed6da8b5a..7b3ba5459d4d53fa02882abc4f652f83dcef0d1e 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
       /* make sure the former gets defined to be the latter if appropriate. */
 #     include <features.h>
 #     if 2 <= __GLIBC__
-#       include <sigcontext.h>
+#       if 0 == __GLIBC_MINOR__
+         /* glibc 2.1 no longer has sigcontext.h.  But signal.h        */
+         /* has the right declaration for glibc 2.1.                   */
+#         include <sigcontext.h>
+#       endif /* 0 == __GLIBC_MINOR__ */
 #     else /* not 2 <= __GLIBC__ */
         /* libc5 doesn't have <sigcontext.h>: go directly with the kernel   */
         /* one.  Check LINUX_VERSION_CODE to see which we should reference. */
index 387d23058296efbb5e367309c8356daf2db59baa..74f455d926cc6619e084ff05f2338fd8ffa18af6 100644 (file)
@@ -632,7 +632,7 @@ ptr_t GC_clear_stack();
     (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
     
 #define GENERAL_MALLOC_IOP(lb,k) \
-    (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page((word)lb, k))
+    (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page(lb, k))
 
 #if defined(__STDC__) || defined(__cplusplus)
   void * GC_malloc_explicitly_typed(size_t lb, GC_descr d)
@@ -702,7 +702,7 @@ DCL_LOCK_STATE;
        FASTLOCK();
         if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
             FASTUNLOCK();
-            op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind);
+            op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
 #          ifdef MERGE_SIZES
                lw = GC_size_map[lb];   /* May have been uninitialized. */            
 #          endif
@@ -712,7 +712,7 @@ DCL_LOCK_STATE;
             FASTUNLOCK();
         }
    } else {
-       op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind);
+       op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
        if (op != NULL)
        lw = BYTES_TO_WORDS(GC_size(op));
    }
index f3b69f0bd53c0a6a0f2ace77c39a747a4ba71017..5c0e114a95a22ef9c3b7d345b06f7fb35c38ee61 100644 (file)
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
 #define GC_VERSION_MAJOR 4
 #define GC_VERSION_MINOR 14
-#define GC_ALPHA_VERSION 1
+#define GC_ALPHA_VERSION 2
 
 #   define GC_NOT_ALPHA 0xff
 
index 2b01c5c637130231bdd040fc5750f5653e69830a..f6f74bd1111939d847e3285cf0c2657a13e98324 100755 (executable)
@@ -91,6 +91,12 @@ void GC_push_all_stacks()
        if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
            || thread_table[i].context.Esp < (DWORD)bottom)
            ABORT("Thread stack pointer out of range");
+       GC_push_one ((word) thread_table[i].context.Edi);
+       GC_push_one ((word) thread_table[i].context.Esi);
+       GC_push_one ((word) thread_table[i].context.Ebx);
+       GC_push_one ((word) thread_table[i].context.Edx);
+       GC_push_one ((word) thread_table[i].context.Ecx);
+       GC_push_one ((word) thread_table[i].context.Eax);
        GC_push_all_stack(thread_table[i].context.Esp, thread_table[i].stack);
       }
     }