summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Boehm <boehm@acm.org>1999-03-26 00:00:00 +0000
committerIvan Maidanski <ivmai@mail.ru>2014-05-17 17:47:31 +0400
commit5939cabd4caa75dd5e68c36178f0886e84451531 (patch)
treefa6180d25d9d88c859e0a805a9450efcb1432674
parent00b82292567d40d089cf9a988bab64078c80e8ea (diff)
downloadbdwgc-gc4_14alpha2.tar.gz
gc4.14alpha2 tarball importgc4_14alpha2
-rw-r--r--Makefile15
-rw-r--r--README33
-rw-r--r--allchblk.c3
-rw-r--r--alloc.c5
-rw-r--r--cord/gc.h1
-rw-r--r--dbg_mlc.c4
-rw-r--r--dyn_load.c7
-rw-r--r--gc.h1
-rw-r--r--gc_mark.h2
-rw-r--r--gc_priv.h29
-rw-r--r--gcconfig.h26
-rw-r--r--headers.c2
-rw-r--r--include/gc.h1
-rw-r--r--include/private/gc_priv.h29
-rw-r--r--include/private/gcconfig.h26
-rw-r--r--mach_dep.c32
-rw-r--r--mallocx.c4
-rw-r--r--mark.c62
-rw-r--r--mark_rts.c52
-rw-r--r--os_dep.c6
-rw-r--r--typd_mlc.c6
-rw-r--r--version.h2
-rwxr-xr-xwin32_threads.c6
23 files changed, 278 insertions, 76 deletions
diff --git a/Makefile b/Makefile
index ffd81281..063d394a 100644
--- 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 b245beb8..1df945e4 100644
--- 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:
diff --git a/allchblk.c b/allchblk.c
index 026288e8..ff94b480 100644
--- a/allchblk.c
+++ b/allchblk.c
@@ -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 7e1f03ec..171dc780 100644
--- 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++;
diff --git a/cord/gc.h b/cord/gc.h
index 3b9f9ce2..ceabb02f 100644
--- 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));
diff --git a/dbg_mlc.c b/dbg_mlc.c
index f9ed6f3f..81516258 100644
--- 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?)");
diff --git a/dyn_load.c b/dyn_load.c
index c2284470..56aeb3dd 100644
--- a/dyn_load.c
+++ b/dyn_load.c
@@ -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 3b9f9ce2..ceabb02f 100644
--- 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));
diff --git a/gc_mark.h b/gc_mark.h
index 406cba6f..8b57c31f 100644
--- 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)); \
} \
}
diff --git a/gc_priv.h b/gc_priv.h
index 46184522..934075fa 100644
--- 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 */
diff --git a/gcconfig.h b/gcconfig.h
index 47545ae4..dc1c72bd 100644
--- a/gcconfig.h
+++ b/gcconfig.h
@@ -38,6 +38,11 @@
# 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
@@ -173,6 +178,11 @@
# 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
@@ -377,6 +387,12 @@
# 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
@@ -729,6 +745,9 @@
+ _stklen))
/* This may not be right. */
# endif
+# ifdef OPENBSD
+# define OS_TYPE "OPENBSD"
+# endif
# ifdef FREEBSD
# define OS_TYPE "FREEBSD"
# define MPROTECT_VDB
@@ -742,7 +761,7 @@
# 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;
@@ -1026,6 +1045,11 @@
# 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 */
diff --git a/headers.c b/headers.c
index 89d033e2..fae683a6 100644
--- 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));
diff --git a/include/gc.h b/include/gc.h
index 3b9f9ce2..ceabb02f 100644
--- a/include/gc.h
+++ b/include/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));
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index 46184522..934075fa 100644
--- a/include/private/gc_priv.h
+++ b/include/private/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 */
diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h
index 47545ae4..dc1c72bd 100644
--- a/include/private/gcconfig.h
+++ b/include/private/gcconfig.h
@@ -38,6 +38,11 @@
# 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
@@ -173,6 +178,11 @@
# 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
@@ -377,6 +387,12 @@
# 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
@@ -729,6 +745,9 @@
+ _stklen))
/* This may not be right. */
# endif
+# ifdef OPENBSD
+# define OS_TYPE "OPENBSD"
+# endif
# ifdef FREEBSD
# define OS_TYPE "FREEBSD"
# define MPROTECT_VDB
@@ -742,7 +761,7 @@
# 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;
@@ -1026,6 +1045,11 @@
# 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 */
diff --git a/mach_dep.c b/mach_dep.c
index 20931c2b..23e270e3 100644
--- a/mach_dep.c
+++ b/mach_dep.c
@@ -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. */
diff --git a/mallocx.c b/mallocx.c
index ae8bfffb..b1450215 100644
--- 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 2febda39..c827af5c 100644
--- 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 */
diff --git a/mark_rts.c b/mark_rts.c
index 5b8f8b08..2f21ed32 100644
--- a/mark_rts.c
+++ b/mark_rts.c
@@ -400,13 +400,44 @@ 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. */
diff --git a/os_dep.c b/os_dep.c
index cbef1cee..7b3ba545 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -31,7 +31,11 @@
/* 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. */
diff --git a/typd_mlc.c b/typd_mlc.c
index 387d2305..74f455d9 100644
--- a/typd_mlc.c
+++ b/typd_mlc.c
@@ -632,7 +632,7 @@ ptr_t GC_clear_stack();
(GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
#define GENERAL_MALLOC_IOP(lb,k) \
- (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page((word)lb, k))
+ (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page(lb, k))
#if defined(__STDC__) || defined(__cplusplus)
void * GC_malloc_explicitly_typed(size_t lb, GC_descr d)
@@ -702,7 +702,7 @@ DCL_LOCK_STATE;
FASTLOCK();
if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
FASTUNLOCK();
- op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind);
+ op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
# ifdef MERGE_SIZES
lw = GC_size_map[lb]; /* May have been uninitialized. */
# endif
@@ -712,7 +712,7 @@ DCL_LOCK_STATE;
FASTUNLOCK();
}
} else {
- op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind);
+ op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
if (op != NULL)
lw = BYTES_TO_WORDS(GC_size(op));
}
diff --git a/version.h b/version.h
index f3b69f0b..5c0e114a 100644
--- 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
diff --git a/win32_threads.c b/win32_threads.c
index 2b01c5c6..f6f74bd1 100755
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -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);
}
}