# and runs some tests of collector and cords. Does not add cords or
# c++ interface to gc.a
# cord/de - builds dumb editor based on cords.
-CC= gcc
+CC= cc
CXX=g++ -ansi
# Needed only for "make c++", which adds the c++ interface
AS=as
# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
# usually causing it to use less space in such situations.
# Incremental collection no longer works in this case.
+# -DLARGE_CONFIG tunes the collector for unusually large heaps.
+# Necessary for heaps larger than about 500 MB on most machines.
+# Recommended for heaps larger than about 64 MB.
# -DDONT_ADD_BYTE_AT_END is meaningful only with
# -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
# causes all objects to be padded so that pointers just past the end of
# existing code, but it often does. Neither works on all platforms,
# since some ports use malloc or calloc to obtain system memory.
# (Probably works for UNIX, and win32.)
+# -DNO_DEBUG removes GC_dump and the debugging routines it calls.
+# Reduces code size slightly at the expense of debuggability.
CXXFLAGS= $(CFLAGS)
AR= ar
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
libgc.so: $(OBJS) dyn_load_sunos53.o
$(CC) -G -o libgc.so $(OBJS) dyn_load_sunos53.o -ldl
+# Alpha/OSF shared library version of the collector
+libalphagc.so: $(OBJS)
+ ld -shared -o libalphagc.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
gctest: test.o gc.a if_mach if_not_there
rm -f gctest
- ./if_mach ALPHA "" $(CC) $(CFLAGS) -o gctest $(ALPHACFLAGS) test.o gc.a
./if_mach SPARC SUNOS5 $(CC) $(CFLAGS) -o gctest test.o gc.a -lthread -ldl
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o gctest test.o gc.a -lucb
./if_not_there gctest $(CC) $(CFLAGS) -o gctest test.o gc.a
# odds are your compiler is broken. Gctest may still work.
# Try compiling setjmp_t.c unoptimized.
setjmp_test: $(srcdir)/setjmp_t.c $(srcdir)/gc.h if_mach if_not_there
- rm -f setjmp_test
- ./if_mach ALPHA "" $(CC) $(CFLAGS) -o setjmp_test $(ALPHACFLAGS) $(srcdir)/setjmp_t.c
- ./if_not_there setjmp_test $(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c
+ $(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c
test: KandRtest cord/cordtest
cord/cordtest
gc.tar: $(SRCS) $(OTHER_FILES)
tar cvf gc.tar $(SRCS) $(OTHER_FILES)
-
+
pc_gc.tar: $(SRCS) $(OTHER_FILES)
tar cvfX pc_gc.tar pc_excludes $(SRCS) $(OTHER_FILES)
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.
# Fix to point to local pcr installation directory.
PCRDIR= ..
-COBJ= alloc.o reclaim.o allchblk.o misc.o os_dep.o mark_rts.o headers.o mark.o obj_map.o pcr_interface.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o
+COBJ= alloc.o reclaim.o allchblk.o misc.o os_dep.o mark_rts.o headers.o mark.o obj_map.o pcr_interface.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o
-CSRC= 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
+CSRC= 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
SHELL= /bin/sh
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.4 of a conservative garbage collector for C and C++.
+This is version 4.5 of a conservative garbage collector for C and C++.
HISTORY -
GENERAL DESCRIPTION
- This is a garbage colecting storage allocator that is intended to be
+ This is a garbage collecting storage allocator that is intended to be
used as a plug-in replacement for C's malloc.
Since the collector does not require pointers to be tagged, it does not
object. A routine GC_register_displacement is provided to allow for
more controlled interior pointer use in the heap. Defining
ALL_INTERIOR_POINTERS is somewhat dangerous, in that it can result
-in unnecessary memroy retention. However this is much less of a
+in unnecessary memory retention. However this is much less of a
problem than with older collector versions. The routine
GC_register_displacement is described in gc.h.
discontiguous data areas that may contain pointers, then the collector does
need to be informed.
- Signal processing for most signals is normally deferred during collection,
+ Signal processing for most signals may be deferred during collection,
and during uninterruptible parts of the allocation process. Unlike
-standard ANSI C mallocs, it is intended to be safe to invoke malloc
+standard ANSI C mallocs, it can be safe to invoke malloc
from a signal handler while another malloc is in progress, provided
the original malloc is not restarted. (Empirically, many UNIX
-applications already asssume this.) Even this modest level of signal-
-safety may be too expensive on some systems. If so, ENABLE_SIGNALS
-and DISABLE_SIGNALS may be redefined to the empty statement in gc_private.h.
+applications already assume this.) To obtain this level of signal
+safety, remove the definition of -DNO_SIGNALS in Makefile.
The allocator/collector can also be configured for thread-safe operation.
-(Full signal safety can also be acheived, but only at the cost of two system
+(Full signal safety can also be achieved, but only at the cost of two system
calls per malloc, which is usually unacceptable.)
INSTALLATION AND PORTABILITY
DEC Alpha running OSF/1
SGI workstations under IRIX 4 & 5
Sony News
- Apple MacIntosh under A/UX or MacOS
+ Apple Macintosh under A/UX or MacOS
Commodore Amiga (see README.amiga)
NeXT machines
In all cases we assume that pointer alignment is consistent with that
enforced by the standard C compilers. If you use a nonstandard compiler
-you may have to adjust the alignment parameters defined in gc_private.h.
+you may have to adjust the alignment parameters defined in gc_priv.h.
A port to a machine that is not byte addressed, or does not use 32 bit
or 64 bit addresses will require a major effort. A port to MSDOS is hard,
On some machines, it is difficult to obtain such a value that is
valid across a variety of MMUs, OS releases, etc. A number of
alternatives exist for using the collector in spite of this. See the
- discussion in config.h.h immediately preceding the various
+ discussion in config.h immediately preceding the various
definitions of STACKBOTTOM.
2. mach_dep.c.
2) GC_malloc_atomic(nbytes)
- allocate an object of size nbytes that is guaranteed not to contain any
- pointers. The returned object is not guaranteed to be cleeared.
+ pointers. The returned object is not guaranteed to be cleared.
(Can always be replaced by GC_malloc, but results in faster collection
times. The collector will probably run faster if large character
arrays, etc. are allocated with GC_malloc_atomic than if they are
in excessive memory consumption.
Some additional tuning is possible through the parameters defined
-near the top of gc_private.h.
+near the top of gc_priv.h.
If only GC_malloc is intended to be used, it might be appropriate to define:
The Ellis-Hull C++ interface to the collector is included in
the collector distribution. If you intend to use this, type
"make c++" after the initial build of the collector is complete.
-See gc_cpp.h for the difinition of the interface. This interface
+See gc_cpp.h for the definition of the interface. This interface
tries to approximate the Ellis-Detlefs C++ garbage collection
proposal without compiler changes.
GC_debug_malloc checking during garbage collection is enabled
with the first call to GC_debug_malloc. This will result in some
slowdown during collections. If frequent heap checks are desired,
-this can be acheived by explicitly invoking GC_gcollect, e.g. from
+this can be achieved by explicitly invoking GC_gcollect, e.g. from
the debugger.
GC_debug_malloc allocated objects should not be passed to GC_realloc
Version 2.2 added debugging allocation, and fixed various bugs. Among them:
- GC_realloc could fail to extend the size of the object for certain large object sizes.
- A blatant subscript range error in GC_printf, which unfortunately
- wasn't excercised on machines with sufficient stack alignment constraints.
+ wasn't exercised on machines with sufficient stack alignment constraints.
- GC_register_displacement did the wrong thing if it was called after
any allocation had taken place.
- The leak finding code would eventually break after 2048 byte
a dynamic library.
- A fix for a bug in GC_base that could result in a memory fault.
- A fix for a performance bug (and several other misfeatures) pointed
- out by Dave Detelfs and Al Dosser.
+ out by Dave Detlefs and Al Dosser.
- Use of dirty bit information for static data under Solaris 2.X.
- DEC Alpha/OSF1 support (thanks to Al Dosser).
- Incremental collection on more platforms.
that the old version was correct.
- Fixed an incremental collection bug that prevented it from
working at all when HBLKSIZE != getpagesize()
-- Changed dynamic_loading.c to include gc_private.h before testing
+- Changed dynamic_loading.c to include gc_priv.h before testing
DYNAMIC_LOADING. SunOS dynamic library scanning
must have been broken in 3.4.
- Object size rounding now adapts to program behavior.
suggestion).
- Renamed C++ related files so they could live in a FAT
file system. (Charles Fiterman's suggestion.)
-- Changed Windoes NT Makefile to include C++ support in
+- Changed Windows NT Makefile to include C++ support in
gc.lib. Added C++ test as Makefile target.
Since version 4.3:
- Fixed a win32 specific performance bug that could result in scanning of
objects allocated with the system malloc.
- Added REDIRECT_MALLOC.
+
+Since version 4.4:
+ - Fixed many minor and one major README bugs. (Thanks to Franklin Chen
+ (chen@adi.com) for pointing out many of them.)
+ - Fixed ALPHA/OSF/1 dynamic library support. (Thanks to Jonathan Bachrach
+ (jonathan@harlequin.com)).
+ - Added incremental GC support (MPROTECT_VDB) for Linux (with some
+ help from Bruno Haible).
+ - Altered SPARC recognition tests in gc.h and config.h (mostly as
+ suggested by Fergus Henderson).
+ - Added basic incremental GC support for win32, as implemented by
+ Windows NT and Windows 95. GC_enable_incremental is a noop
+ under win32s, which doesn't implement enough of the VM interface.
+ - Added -DLARGE_CONFIG.
+ - Fixed GC_..._ignore_off_page to also function without
+ -DALL_INTERIOR_POINTERS.
+ - (Hopefully) fixed RS/6000 port. (Only the test was broken.)
+ - Fixed a performance bug in the nonincremental collector running
+ on machines supporting incremental collection with MPROTECT_VDB
+ (e.g. SunOS 4, DEC AXP). This turned into a correctness bug under
+ win32s with win32 incremental collection. (Not all memory protection
+ was disabled.)
+ - Fixed some ppcr related bit rot.
+ - Caused dynamic libraries to be unregistered before reregistering.
+ The old way turned out to be a performance bug on some machines.
+ - GC_root_size was not properly maintained under MSWIN32.
+ - Added -DNO_DEBUGGING and GC_dump.
+ - Fixed a couple of bugs arising with SOLARIS_THREADS +
+ REDIRECT_MALLOC.
+ - Added NetBSD/M68K port. (Thanks to Peter Seebach
+ <seebs@taniemarie.solon.com>.)
+ - Fixed a serious realloc bug. For certain object sizes, the collector
+ 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
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.
-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.
+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.
+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.)
segments. Under win32s, only the main data segment is scanned.
(The main data segment should always be scanned. Under some
versions of win32s, other regions may also be scanned.)
-Thus all accessible objects should be excessible from local variables
+Thus all accessible objects should be accessible from local variables
or variables in the main data segment. Alternatively, other data
segments (e.g. in DLLs) may be registered with the collector by
calling GC_init() and then GC_register_root_section(a), where
window colors.)
For Microsoft development tools, rename NT_MAKEFILE as
-MAKEFILE. For Borland tools, use BCC_MAKEFILE. Note that
+MAKEFILE. (Make sure that the CPU environment variable is defined
+to be i386.) For Borland tools, use BCC_MAKEFILE. Note that
Borland's compiler defaults to 1 byte alignment in structures (-a1),
whereas Visual C++ appears to default to 8 byte alignment (/Zp8).
The garbage collector in its default configuration EXPECTS AT
resort, config.h can be changed to allow 1 byte alignment. But
this has significant negative performance implications.)
+Incremental collection support was recently added. This is
+currently pretty simpleminded. Pages are protected. Protection
+faults are caught by a handler installed at the bottom of the handler
+stack. This is both slow and interacts poorly with a debugger.
+Whenever possible, I recommend adding a call to
+GC_enable_incremental at the last possible moment, after most
+debugging is complete. Unlike the UNIX versions, no system
+calls are wrapped by the collector itself. It may be necessary
+to wrap ReadFile calls that use a buffer in the heap, so that the
+call does not encounter a protection fault while it's running.
+(As usual, none of this is an issue unless GC_enable_incremental
+is called.)
+
+Note that incremental collection is disabled with -DSMALL_CONFIG,
+which is the default for win32. If you need incremental collection,
+undefine SMALL_CONFIG.
+
+Incremental collection is not supported under win32s, and it may not
+be possible to do so. However, win32 applications that attempt to use
+incremental collection should continue to run, since the
+colllector detects if it's running under win32s and turns calls to
+GC_enable_incremental() into noops.
+
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, January 31, 1995 3:01 pm PST */
+/* Boehm, June 13, 1995 3:34 pm PDT */
#define DEBUG
#undef DEBUG
#include "gc_priv.h"
-/**/
-/* allocate/free routines for heap blocks
-/* Note that everything called from outside the garbage collector
-/* should be prepared to abort at any point as the result of a signal.
-/**/
+/*
+ * allocate/free routines for heap blocks
+ * Note that everything called from outside the garbage collector
+ * should be prepared to abort at any point as the result of a signal.
+ */
/*
* Free heap blocks are kept on a list sorted by address.
/* block to be examined by */
/* GC_allochblk. */
+# if !defined(NO_DEBUGGING)
void GC_print_hblkfreelist()
{
struct hblk * h = GC_hblkfreelist;
GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free);
}
+# endif /* NO_DEBUGGING */
+
/* Initialize hdr for a block containing the indicated size and */
/* kind of objects. */
/* Return FALSE on failure. */
} else if (size_needed > BL_LIMIT
&& orig_avail - size_needed > BL_LIMIT) {
/* Punt, since anything else risks unreasonable heap growth. */
- WARN("Need to allocated blacklisted block at %ld\n", (word)hbp);
+ WARN("Needed to allocate blacklisted block at %ld\n",
+ (word)hbp);
thishbp = hbp;
size_avail = orig_avail;
} else if (size_avail == 0
* modified is included with the above copyright notice.
*
*/
-/* Boehm, February 10, 1995 1:18 pm PST */
+/* Boehm, April 28, 1995 4:36 pm PDT */
# include "gc_priv.h"
}
}
+# if !defined(NO_DEBUGGING)
+void GC_print_heap_sects()
+{
+ register unsigned i;
+
+ GC_printf1("Total heap size: %lu\n", (unsigned long) GC_heapsize);
+ for (i = 0; i < GC_n_heap_sects; i++) {
+ unsigned long start = (unsigned long) GC_heap_sects[i].hs_start;
+ unsigned long len = (unsigned long) GC_heap_sects[i].hs_bytes;
+ struct hblk *h;
+ unsigned nbl = 0;
+
+ GC_printf3("Section %ld form 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++;
+ }
+ GC_printf2("%lu/%lu blacklisted\n", (unsigned long)nbl,
+ (unsigned long)(len/HBLKSIZE));
+ }
+}
+# endif
+
ptr_t GC_least_plausible_heap_addr = (ptr_t)ONES;
ptr_t GC_greatest_plausible_heap_addr = 0;
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, January 31, 1995 12:36 pm PST */
+/* Boehm, March 29, 1995 12:51 pm PST */
# ifdef CHECKSUMS
# include "gc_priv.h"
GC_bytes_in_used_blocks += bytes;
}
-GC_check_blocks()
+void GC_check_blocks()
{
word bytes_in_free_blocks = 0;
struct hblk * h = GC_hblkfreelist;
void GC_check_dirty()
{
register int index;
- register int i;
+ register unsigned i;
register struct hblk *h;
register ptr_t start;
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, February 6, 1995 5:24 pm PST */
+/* Boehm, May 30, 1995 5:04 pm PDT */
#ifndef CONFIG_H
# 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 RT
# define mach_type_known
# endif
-# if defined(sun) && defined(sparc)
+# if defined(sun) && (defined(sparc) || defined(__sparc))
# define SPARC
/* Test for SunOS 5.x */
# include <errno.h>
# 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;
/* was done by Robert Ehrlich, Manuel Serrano, and Bernard */
/* Serpette of INRIA. */
/* This assumes ZMAGIC, i.e. demand-loadable executables. */
-# define DATASTART ((ptr_t)(*(int *)0x2004+0x2000))
+# define TEXTSTART 0x2000
+# define DATASTART ((ptr_t)(*(int *)(TEXTSTART+0x4)+TEXTSTART))
# define MPROTECT_VDB
# define HEURISTIC1
# endif
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"
# define OS_TYPE "MSWIN32"
/* STACKBOTTOM and DATASTART are handled specially in */
/* os_dep.c. */
+# define MPROTECT_VDB
# endif
# ifdef FREEBSD
# define OS_TYPE "FREEBSD"
# define HEURISTIC2_LIMIT ((ptr_t)((word)(&__start) & ~(getpagesize()-1)))
# define CPP_WORDSZ 64
# define MPROTECT_VDB
+# define DYNAMIC_LOADING
# endif
# ifdef M88K
register int i;
if (state == 0) OUT_OF_MEMORY;
+ if (len != 0) {
+ /* Dummy read to force buffer allocation. */
+ /* This greatly increases the probability */
+ /* of avoiding deadlock if buffer allocation */
+ /* is redirected to GC_malloc and the */
+ /* world is multithreaded. */
+ char buf[1];
+
+ (void) fread(buf, 1, 1, f);
+ rewind(f);
+ }
state -> lf_file = f;
for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
state -> lf_cache[i] = 0;
/* code, and should not be considered in determining */
/* finalization order. */
# if defined(__STDC__) || defined(__cplusplus)
- int GC_register_disappearing_link(void ** link);
+ int GC_register_disappearing_link(void ** /* link */);
# else
int GC_register_disappearing_link(/* void ** link */);
# endif
/* otherwise. */
/* Only exists for backward compatibility. See below: */
# if defined(__STDC__) || defined(__cplusplus)
- int GC_general_register_disappearing_link(void ** link, void * obj);
+ int GC_general_register_disappearing_link(void ** /* link */, void * obj);
# else
int GC_general_register_disappearing_link(/* void ** link, void * obj */);
# endif
/* obj may or may not cause link to eventually be */
/* cleared. */
# if defined(__STDC__) || defined(__cplusplus)
- int GC_unregister_disappearing_link(void ** link);
+ int GC_unregister_disappearing_link(void ** /* link */);
# else
int GC_unregister_disappearing_link(/* void ** link */);
# endif
* from the statically loaded program section.
* This circumvents a Solaris 2.X (X<=4) linker bug.
*/
-#ifdef sparc
+#if defined(sparc) || defined(__sparc)
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
#else
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, October 27, 1994 9:57 am PDT */
+/* Boehm, April 18, 1995 3:29 pm PDT */
# include "gc_priv.h"
/* Do we want to and know how to save the call stack at the time of */
}
GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
(unsigned long)(ohdr -> oh_sz));
+ PRINT_CALL_CHAIN(ohdr);
}
}
* Original author: Bill Janssen
* Heavily modified by Hans Boehm and others
*/
-/* Boehm, September 12, 1994 4:27 pm PDT */
+/* Boehm, April 17, 1995 3:20 pm PDT */
/*
* This is incredibly OS specific code for tracking down data sections in
# endif
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR)
-#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && !defined(MSWIN32)
+#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && !defined(MSWIN32) && !defined(ALPHA)
--> We only know how to find data segments of dynamic libraries under SunOS,
--> IRIX5, DRSNX and Win32. Additional SVR4 variants might not be too
--> hard to add.
e = (struct exec *) lm->lm_addr;
GC_add_roots_inner(
((char *) (N_DATOFF(*e) + lm->lm_addr)),
- ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)));
+ ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)),
+ TRUE);
# endif
# ifdef SUNOS5DL
Elf32_Ehdr * e;
start = ((char *)(p->p_vaddr)) + offset;
GC_add_roots_inner(
start,
- start + p->p_memsz
+ start + p->p_memsz,
+ TRUE
);
}
break;
if (common_start == 0) common_start = GC_first_common();
if (common_start != 0) {
common_end = GC_find_limit(common_start, TRUE);
- GC_add_roots_inner((char *)common_start, (char *)common_end);
+ GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE);
}
}
# endif
}
}
}
- GC_add_roots_inner(start, limit);
+ GC_add_roots_inner(start, limit, TRUE);
irrelevant: ;
}
}
/* Part of the stack; ignore it. */
return;
}
- GC_add_roots_inner(base, limit);
+ GC_add_roots_inner(base, limit, TRUE);
}
extern bool GC_win32s;
#endif /* MSWIN32 */
#if defined(ALPHA)
+
+#include <loader.h>
+
void GC_register_dynamic_libraries()
{
int status;
/* register region as a garbage collection root */
GC_add_roots_inner (
(char *)regioninfo.lri_mapaddr,
- (char *)regioninfo.lri_mapaddr + regioninfo.lri_size);
+ (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
+ TRUE);
}
}
== PCR_IL_SegFlags_Traced_on) {
GC_add_roots_inner
((char *)(q -> ls_addr),
- (char *)(q -> ls_addr) + q -> ls_bytes);
+ (char *)(q -> ls_addr) + q -> ls_bytes,
+ TRUE);
}
}
}
/* code, and should not be considered in determining */
/* finalization order. */
# if defined(__STDC__) || defined(__cplusplus)
- int GC_register_disappearing_link(void ** link);
+ int GC_register_disappearing_link(void ** /* link */);
# else
int GC_register_disappearing_link(/* void ** link */);
# endif
/* otherwise. */
/* Only exists for backward compatibility. See below: */
# if defined(__STDC__) || defined(__cplusplus)
- int GC_general_register_disappearing_link(void ** link, void * obj);
+ int GC_general_register_disappearing_link(void ** /* link */, void * obj);
# else
int GC_general_register_disappearing_link(/* void ** link, void * obj */);
# endif
/* obj may or may not cause link to eventually be */
/* cleared. */
# if defined(__STDC__) || defined(__cplusplus)
- int GC_unregister_disappearing_link(void ** link);
+ int GC_unregister_disappearing_link(void ** /* link */);
# else
int GC_unregister_disappearing_link(/* void ** link */);
# endif
* from the statically loaded program section.
* This circumvents a Solaris 2.X (X<=4) linker bug.
*/
-#ifdef sparc
+#if defined(sparc) || defined(__sparc)
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
#else
* 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:01 pm PST */
+/* Boehm, April 18, 1995 2:51 pm PDT */
# ifndef GC_PRIVATE_H
#endif
-# define MINHINCR 16 /* Minimum heap increment, in blocks of HBLKSIZE */
-# define MAXHINCR 512 /* Maximum heap increment, in blocks */
+# 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. */
* Used by black-listing code, and perhaps by dirty bit maintenance code.
*/
-# define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */
+# 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];
page_hash_table _grungy_pages; /* Pages that were dirty at last */
/* GC_read_dirty. */
# endif
-# define MAX_HEAP_SECTS 256 /* Separately added heap sections. */
+# 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];
/* 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();
/* code, and should not be considered in determining */
/* finalization order. */
# if defined(__STDC__) || defined(__cplusplus)
- int GC_register_disappearing_link(void ** link);
+ int GC_register_disappearing_link(void ** /* link */);
# else
int GC_register_disappearing_link(/* void ** link */);
# endif
/* otherwise. */
/* Only exists for backward compatibility. See below: */
# if defined(__STDC__) || defined(__cplusplus)
- int GC_general_register_disappearing_link(void ** link, void * obj);
+ int GC_general_register_disappearing_link(void ** /* link */, void * obj);
# else
int GC_general_register_disappearing_link(/* void ** link, void * obj */);
# endif
/* obj may or may not cause link to eventually be */
/* cleared. */
# if defined(__STDC__) || defined(__cplusplus)
- int GC_unregister_disappearing_link(void ** link);
+ int GC_unregister_disappearing_link(void ** /* link */);
# else
int GC_unregister_disappearing_link(/* void ** link */);
# endif
* from the statically loaded program section.
* This circumvents a Solaris 2.X (X<=4) linker bug.
*/
-#ifdef sparc
+#if defined(sparc) || defined(__sparc)
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
#else
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, February 10, 1995 12:55 pm PST */
+/* Boehm, June 13, 1995 3:07 pm PDT */
#include <stdio.h>
#include "gc_priv.h"
register size_t lb;
register int k;
{
-# ifdef ALL_INTERIOR_POINTERS
register struct hblk * h;
register word n_blocks;
register word lw;
}
GC_words_allocd += lw;
return((ptr_t)op);
-# else
- return(GC_generic_malloc_inner((word)lb, k));
-# endif
}
ptr_t GC_generic_malloc_ignore_off_page(lb, k)
if (sz > WORDS_TO_BYTES(MAXOBJSZ)) {
/* Round it up to the next whole heap block */
+ register word descr;
sz = (sz+HDR_BYTES+HBLKSIZE-1)
& (~HBLKMASK);
sz -= HDR_BYTES;
hhdr -> hb_sz = BYTES_TO_WORDS(sz);
+ descr = GC_obj_kinds[obj_kind].ok_descriptor;
+ if (GC_obj_kinds[obj_kind].ok_relocate_descr) descr += sz;
+ hhdr -> hb_descr = descr;
if (obj_kind == UNCOLLECTABLE) GC_non_gc_bytes += (sz - orig_sz);
/* Extra area is already cleared by allochblk. */
}
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, September 15, 1994 2:15 pm PDT */
+/* Boehm, April 18, 1995 3:04 pm PDT */
# include <stdio.h>
# include "gc_priv.h"
-# ifdef PCR
-# define MAX_ROOT_SETS 1024
+# ifdef LARGE_CONFIG
+# define MAX_ROOT_SETS 4096
# else
-# ifdef MSWIN32
+# ifdef PCR
+# define MAX_ROOT_SETS 1024
+# else
+# ifdef MSWIN32
# define MAX_ROOT_SETS 512
/* Under NT, we add only written pages, which can result */
/* in many small root sets. */
-# else
+# else
# define MAX_ROOT_SETS 64
+# endif
# endif
# endif
# ifndef MSWIN32
struct roots * r_next;
# endif
+ bool r_tmp;
+ /* Delete before registering new dynamic libraries */
};
static struct roots static_roots[MAX_ROOT_SETS];
/* static_roots[0..n_root_sets) contains the valid root sets. */
+# if !defined(NO_DEBUGGING)
+/* For debugging: */
+void GC_print_static_roots()
+{
+ register int i;
+ size_t total = 0;
+
+ for (i = 0; i < n_root_sets; i++) {
+ GC_printf2("From 0x%lx to 0x%lx ",
+ (unsigned long) static_roots[i].r_start,
+ (unsigned long) static_roots[i].r_end);
+ if (static_roots[i].r_tmp) {
+ GC_printf0(" (temporary)\n");
+ } else {
+ GC_printf0("\n");
+ }
+ total += static_roots[i].r_end - static_roots[i].r_start;
+ }
+ GC_printf1("Total size: %ld\n", (unsigned long) total);
+ if (GC_root_size != total) {
+ GC_printf1("GC_root_size incorrect: %ld!!\n",
+ (unsigned long) GC_root_size);
+ }
+}
+# endif /* NO_DEBUGGING */
+
/* Primarily for debugging support: */
/* Is the address p in one of the registered static */
/* root sections? */
DISABLE_SIGNALS();
LOCK();
- GC_add_roots_inner(b, e);
+ GC_add_roots_inner(b, e, FALSE);
UNLOCK();
ENABLE_SIGNALS();
}
/* is a moderately fast noop, and hence benign. We do not handle */
/* different but overlapping intervals efficiently. (We do handle */
/* them correctly.) */
-void GC_add_roots_inner(b, e)
+/* Tmp specifies that the interval may be deleted before */
+/* reregistering dynamic libraries. */
+void GC_add_roots_inner(b, e, tmp)
char * b; char * e;
+bool tmp;
{
struct roots * old;
} else if ((ptr_t)b >= beginGC_arrays) {
b = (char *)endGC_arrays;
} else {
- GC_add_roots_inner(b, (char *)beginGC_arrays);
- GC_add_roots_inner((char *)endGC_arrays, e);
+ GC_add_roots_inner(b, (char *)beginGC_arrays, tmp);
+ GC_add_roots_inner((char *)endGC_arrays, e, tmp);
return;
}
}
if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
if ((ptr_t)b < old -> r_start) {
old -> r_start = (ptr_t)b;
+ GC_root_size += (old -> r_start - (ptr_t)b);
}
if ((ptr_t)e > old -> r_end) {
old -> r_end = (ptr_t)e;
+ GC_root_size += ((ptr_t)e - old -> r_end);
}
+ old -> r_tmp &= tmp;
break;
}
}
if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
if ((ptr_t)b < old -> r_start) {
old -> r_start = (ptr_t)b;
+ GC_root_size += (old -> r_start - (ptr_t)b);
}
if ((ptr_t)e > old -> r_end) {
old -> r_end = (ptr_t)e;
+ GC_root_size += ((ptr_t)e - old -> r_end);
}
+ old -> r_tmp &= other -> r_tmp;
/* Delete this entry. */
+ GC_root_size -= (other -> r_end - other -> r_start);
other -> r_start = static_roots[n_root_sets-1].r_start;
other -> r_end = static_roots[n_root_sets-1].r_end;
- n_root_sets--;
+ n_root_sets--;
}
}
return;
}
static_roots[n_root_sets].r_start = (ptr_t)b;
static_roots[n_root_sets].r_end = (ptr_t)e;
+ static_roots[n_root_sets].r_tmp = tmp;
# ifndef MSWIN32
static_roots[n_root_sets].r_next = 0;
# endif
ENABLE_SIGNALS();
}
+/* Internal use only; lock held. */
+void GC_remove_tmp_roots()
+{
+ register int i;
+
+ for (i = 0; i < n_root_sets; ) {
+ if (static_roots[i].r_tmp) {
+ GC_root_size -= (static_roots[i].r_end - static_roots[i].r_start);
+ static_roots[i].r_start = static_roots[n_root_sets-1].r_start;
+ static_roots[i].r_end = static_roots[n_root_sets-1].r_end;
+ static_roots[i].r_tmp = static_roots[n_root_sets-1].r_tmp;
+ n_root_sets--;
+ } else {
+ i++;
+ }
+ }
+# ifndef MSWIN32
+ {
+ register int i;
+
+ for (i = 0; i < RT_SIZE; i++) root_index[i] = 0;
+ for (i = 0; i < n_root_sets; i++) add_roots_to_index(static_roots + i);
+ }
+# endif
+
+}
+
ptr_t GC_approx_sp()
{
word dummy;
/* Reregister dynamic libraries, in case one got added. */
# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(PCR)) \
&& !defined(SRC_M3)
+ GC_remove_tmp_roots();
GC_register_dynamic_libraries();
# endif
/* Mark everything in static data areas */
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, February 10, 1995 12:37 pm PST */
+/* Boehm, May 2, 1995 11:20 am PDT */
#include <stdio.h>
#include <signal.h>
-#ifdef SOLARIS_THREADS
-# include <sys/syscall.h>
-#endif
#define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */
#include "gc_priv.h"
+#ifdef SOLARIS_THREADS
+# include <sys/syscall.h>
+#endif
+#ifdef MSWIN32
+# include <windows.h>
+#endif
+
# ifdef THREADS
# ifdef PCR
# include "il/PCR_IL.h"
ABORT("signed_word");
}
- GC_init_headers();
- /* Add initial guess of root sets */
+ /* Add initial guess of root sets. Do this first, since sbrk(0) */
+ /* mightbe used. */
GC_register_data_segments();
- GC_bl_init();
+ GC_init_headers();
+ GC_bl_init();
GC_mark_init();
if (!GC_expand_hp_inner((word)MINHINCR)) {
GC_err_printf0("Can't start up: not enough memory\n");
extern int GC_read();
extern void GC_register_finalizer_no_order();
- GC_noop(GC_copyright, GC_find_header, GC_print_block_list,
+ GC_noop(GC_copyright, GC_find_header,
GC_push_one, GC_call_with_alloc_lock, GC_read,
- GC_print_hblkfreelist, GC_dont_expand,
+ GC_dont_expand,
+# ifndef NO_DEBUGGING
+ GC_dump,
+# endif
GC_register_finalizer_no_order);
}
# endif
DISABLE_SIGNALS();
LOCK();
if (GC_incremental) goto out;
+# ifdef MSWIN32
+ {
+ extern bool GC_is_win32s();
+
+ /* VirtualProtect is not functional under win32s. */
+ if (GC_is_win32s()) goto out;
+ }
+# endif /* MSWIN32 */
# ifndef SOLARIS_THREADS
GC_dirty_init();
# endif
#ifdef MSWIN32
# define LOG_FILE "gc.log"
-# include <windows.h>
HANDLE GC_stdout = 0, GC_stderr;
int GC_tmp;
void GC_set_files()
{
if (!GC_stdout) {
- GC_stdout = CreateFile(LOG_FILE, GENERIC_WRITE, FILE_SHARE_READ,
+ GC_stdout = CreateFile(LOG_FILE, GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
NULL);
if (INVALID_HANDLE_VALUE == GC_stdout) ABORT("Open of log file failed");
# endif
#endif
-#ifdef SOLARIS_THREADS
-# define WRITE(f, buf, len) syscall(SYS_write, (f), (buf), (len))
-#else
-# ifdef MSWIN32
+#if !defined(MSWIN32) && !defined(OS2) && !defined(MACOS)
+int GC_write(fd, buf, len)
+int fd;
+char *buf;
+size_t len;
+{
+ register int bytes_written = 0;
+ register int result;
+
+ while (bytes_written < len) {
+# ifdef SOLARIS_THREADS
+ result = syscall(SYS_write, fd, buf + bytes_written,
+ len - bytes_written);
+# else
+ result = write(fd, buf + bytes_written, len - bytes_written);
+# endif
+ if (-1 == result) return(result);
+ bytes_written += result;
+ }
+ return(bytes_written);
+}
+#endif /* UN*X */
+
+#ifdef MSWIN32
# define WRITE(f, buf, len) (GC_set_files(), \
GC_tmp = WriteFile((f), (buf), \
(len), &GC_junk, NULL),\
(GC_tmp? 1 : -1))
-# else
+#else
# if defined(OS2) || defined(MACOS)
# define WRITE(f, buf, len) (GC_set_files(), \
GC_tmp = fwrite((buf), 1, (len), (f)), \
fflush(f), GC_tmp)
# else
-# define WRITE(f, buf, len) write((f), (buf), (len))
+# define WRITE(f, buf, len) GC_write((f), (buf), (len))
# endif
-# endif
#endif
/* A version of printf that is unlikely to call malloc, and is thus safer */
GC_dont_gc++;
}
# endif
+
+#if !defined(NO_DEBUGGING)
+
+void GC_dump()
+{
+ GC_printf0("***Static roots:\n");
+ GC_print_static_roots();
+ GC_printf0("\n***Heap sections:\n");
+ GC_print_heap_sects();
+ GC_printf0("\n***Free blocks:\n");
+ GC_print_hblkfreelist();
+ GC_printf0("\n***Blocks in use:\n");
+ GC_print_block_list();
+}
+
+# endif /* NO_DEBUGGING */
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, February 10, 1995 1:14 pm PST */
+/* Boehm, May 2, 1995 11:20 am PDT */
# include "gc_priv.h"
# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)
/* Get the page size. */
word GC_page_size = 0;
-word GC_get_page_size()
+word GC_getpagesize()
{
SYSTEM_INFO sysinfo;
{
int dummy;
ptr_t sp = (ptr_t)(&dummy);
- ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_get_page_size() - 1));
+ ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_getpagesize() - 1));
word size = GC_get_writable_length(trunc_sp, 0);
return(trunc_sp + size);
GC_err_printf0("Object with invalid pages?\n");
continue;
}
- GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg));
+ GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg), FALSE);
}
}
/* We rgister the main data segment here. */
bool GC_win32s = FALSE; /* We're running under win32s. */
+ bool GC_is_win32s()
+ {
+ DWORD v = GetVersion();
+
+ /* Check that this is not NT, and Windows major version <= 3 */
+ return ((v & 0x80000000) && (v & 0xff) <= 3);
+ }
+
void GC_init_win32()
{
- if (GetVersion() & 0x80000000) GC_win32s = TRUE;
+ GC_win32s = GC_is_win32s();
}
/* Return the smallest address a such that VirtualQuery */
GetSystemInfo(&sysinfo);
limit = sysinfo.lpMinimumApplicationAddress;
- p = (ptr_t)((word)start & ~(GC_get_page_size() - 1));
+ p = (ptr_t)((word)start & ~(GC_getpagesize() - 1));
for (;;) {
- q = (LPVOID)(p - GC_get_page_size());
+ q = (LPVOID)(p - GC_getpagesize());
if ((ptr_t)q > (ptr_t)p /* underflow */ || q < limit) break;
result = VirtualQuery(q, &buf, sizeof(buf));
if (result != sizeof(buf) || buf.AllocationBase == 0) break;
if ((char *)p == limit) {
limit = new_limit;
} else {
- if (base != limit) GC_add_roots_inner(base, limit);
+ if (base != limit) GC_add_roots_inner(base, limit, FALSE);
base = p;
limit = new_limit;
}
if (p > (LPVOID)new_limit /* overflow */) break;
p = (LPVOID)new_limit;
}
- if (base != limit) GC_add_roots_inner(base, limit);
+ if (base != limit) GC_add_roots_inner(base, limit, FALSE);
}
void GC_register_data_segments()
# else
{
# endif /* AMIGA_SKIP_SEG */
- GC_add_roots_inner((char *)&data[1], ((char *)&data[1]) + data[-1]);
+ GC_add_roots_inner((char *)&data[1],
+ ((char *)&data[1]) + data[-1], FALSE);
}
}
}
# endif
# if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS)
- GC_add_roots_inner(DATASTART, (char *)(&end));
+# if defined(REDIRECT_MALLOC) && defined(SOLARIS_THREADS)
+ /* As of Solaris 2.3, the Solaris threads implementation */
+ /* allocates the data structure for the initial thread with */
+ /* sbrk at process startup. It needs to be scanned, so that */
+ /* we don't lose some malloc allocated data structures */
+ /* hanging from it. We're on thin ice here ... */
+ extern caddr_t sbrk();
+
+ GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
+# else
+ GC_add_roots_inner(DATASTART, (char *)(&end), FALSE);
+# endif
# endif
# if !defined(PCR) && defined(NEXT)
- GC_add_roots_inner(DATASTART, (char *) get_end());
+ GC_add_roots_inner(DATASTART, (char *) get_end(), FALSE);
# endif
# if defined(MACOS)
{
extern void* GC_MacGetDataStart(void);
/* globals begin above stack and end at a5. */
GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
- (ptr_t)LMGetCurrentA5());
+ (ptr_t)LMGetCurrentA5(), FALSE);
# else
# if defined(__MWERKS__)
extern long __datastart, __dataend;
- GC_add_roots_inner((ptr_t)&__datastart, (ptr_t)&__dataend);
+ GC_add_roots_inner((ptr_t)&__datastart, (ptr_t)&__dataend, FALSE);
# endif
# endif
}
* or write only to the stack.
*/
-bool GC_dirty_maintained;
+bool GC_dirty_maintained = FALSE;
# ifdef DEFAULT_VDB
* not to work under a number of other systems.
*/
-# include <sys/mman.h>
-# include <signal.h>
-# include <sys/syscall.h>
+# ifndef MSWIN32
+
+# include <sys/mman.h>
+# include <signal.h>
+# include <sys/syscall.h>
+
+# define PROTECT(addr, len) \
+ if (mprotect((caddr_t)(addr), (int)(len), \
+ PROT_READ | PROT_EXEC) < 0) { \
+ ABORT("mprotect failed"); \
+ }
+# define UNPROTECT(addr, len) \
+ if (mprotect((caddr_t)(addr), (int)(len), \
+ PROT_WRITE | PROT_READ | PROT_EXEC) < 0) { \
+ ABORT("un-mprotect failed"); \
+ }
+
+# else
+
+# include <signal.h>
+
+ static DWORD protect_junk;
+# define PROTECT(addr, len) \
+ if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READ, \
+ &protect_junk)) { \
+ DWORD last_error = GetLastError(); \
+ GC_printf1("Last error code: %lx\n", last_error); \
+ ABORT("VirtualProtect failed"); \
+ }
+# define UNPROTECT(addr, len) \
+ if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READWRITE, \
+ &protect_junk)) { \
+ ABORT("un-VirtualProtect failed"); \
+ }
+
+# endif
VOLATILE page_hash_table GC_dirty_pages;
/* Pages dirtied since last GC_read_dirty. */
bool GC_just_outside_heap(addr)
word addr;
{
- register int i;
+ register unsigned i;
register word start;
register word end;
word mask = GC_page_size-1;
#if defined(SUNOS4) || defined(FREEBSD)
typedef void (* SIG_PF)();
#endif
-#if defined(SUNOS5SIGS) || defined(ALPHA) /* OSF1 */
+#if defined(SUNOS5SIGS) || defined(ALPHA) /* OSF1 */ || defined(LINUX)
typedef void (* SIG_PF)(int);
#endif
+#if defined(MSWIN32)
+ typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
+# undef SIG_DFL
+# define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)
+#endif
#if defined(IRIX5) || defined(ALPHA) /* OSF1 */
typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
#if defined(SUNOS5SIGS)
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
SIG_PF GC_old_bus_handler;
-SIG_PF GC_old_segv_handler;
+SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
/*ARGSUSED*/
# if defined (SUNOS4) || defined(FREEBSD)
# define CODE_OK (code == EACCES)
# endif
# endif
+# if defined(LINUX)
+ void GC_write_fault_handler(int sig, struct sigcontext_struct sc)
+# define SIG_OK (sig == SIGSEGV)
+# define CODE_OK TRUE
+ /* Empirically c.trapno == 14, but is that useful? */
+ /* We assume Intel architecture, so alignment */
+ /* faults are not possible. */
+# endif
# if defined(SUNOS5SIGS)
void GC_write_fault_handler(int sig, struct siginfo *scp, void * context)
# define SIG_OK (sig == SIGSEGV)
# define CODE_OK (scp -> si_code == SEGV_ACCERR)
# endif
+# if defined(MSWIN32)
+ LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
+# define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
+ EXCEPTION_ACCESS_VIOLATION)
+# define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
+ /* Write fault */
+# endif
{
- register int i;
+ register unsigned i;
# ifdef IRIX5
char * addr = (char *) (scp -> sc_badvaddr);
# endif
# endif
# ifdef SUNOS5SIGS
char * addr = (char *) (scp -> si_addr);
+# endif
+# ifdef LINUX
+ char * addr = (char *) (sc.cr2);
+# endif
+# if defined(MSWIN32)
+ char * addr = (char *) (exc_info -> ExceptionRecord
+ -> ExceptionInformation[1]);
+# define sig SIGSEGV
# endif
if (SIG_OK && CODE_OK) {
old_handler = GC_old_bus_handler;
}
if (old_handler == SIG_DFL) {
- ABORT("Unexpected bus error or segmentation fault");
+# ifndef MSWIN32
+ ABORT("Unexpected bus error or segmentation fault");
+# else
+ return(EXCEPTION_CONTINUE_SEARCH);
+# endif
} else {
# if defined (SUNOS4) || defined(FREEBSD)
- (*old_handler) (sig, code, scp, addr);
-# else
-# if defined (SUNOS5SIGS)
+ (*old_handler) (sig, code, scp, addr);
+ return;
+# endif
+# if defined (SUNOS5SIGS)
(*(REAL_SIG_PF)old_handler) (sig, scp, context);
-# else
+ return;
+# endif
+# if defined (LINUX)
+ (*(REAL_SIG_PF)old_handler) (sig, sc);
+ return;
+# endif
+# if defined (IRIX5) || defined(ALPHA)
(*(REAL_SIG_PF)old_handler) (sig, code, scp);
-# endif
+ return;
+# endif
+# ifdef MSWIN32
+ return((*old_handler)(exc_info));
# endif
- return;
}
}
for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
set_pht_entry_from_index(GC_dirty_pages, index);
}
- if (mprotect((caddr_t)h, (int)GC_page_size,
- PROT_WRITE | PROT_READ | PROT_EXEC) < 0) {
- ABORT("mprotect failed in handler");
- }
-# if defined(IRIX5) || defined(ALPHA)
- /* IRIX resets the signal handler each time. */
+ UNPROTECT(h, GC_page_size);
+# if defined(IRIX5) || defined(ALPHA) || defined(LINUX)
+ /* These reset the signal handler each time by default. */
signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
# endif
/* The write may not take place before dirty bits are read. */
/* But then we'll fault again ... */
- return;
+# ifdef MSWIN32
+ return(EXCEPTION_CONTINUE_EXECUTION);
+# else
+ return;
+# endif
}
ABORT("Unexpected bus error or segmentation fault");
void GC_write_hint(h)
struct hblk *h;
{
- register struct hblk * h_trunc =
- (struct hblk *)((word)h & ~(GC_page_size-1));
- register int i;
- register bool found_clean = FALSE;
+ register struct hblk * h_trunc;
+ register unsigned i;
+ register bool found_clean;
+ if (!GC_dirty_maintained) return;
+ h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
+ found_clean = FALSE;
for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
register int index = PHT_HASH(h_trunc+i);
}
}
if (found_clean) {
- if (mprotect((caddr_t)h_trunc, (int)GC_page_size,
- PROT_WRITE | PROT_READ | PROT_EXEC) < 0) {
- ABORT("mprotect failed in GC_write_hint");
- }
+ UNPROTECT(h_trunc, GC_page_size);
}
}
return sysconf(_SC_PAGESIZE);
}
#else
-# define GC_getpagesize() getpagesize()
+# ifdef MSWIN32
+ /* GC_getpagesize() defined above */
+# else
+# define GC_getpagesize() getpagesize()
+# endif
#endif
void GC_dirty_init()
act.sa_flags = SA_RESTART | SA_SIGINFO;
(void)sigemptyset(&act.sa_mask);
#endif
+# ifdef PRINTSTATS
+ GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
+# endif
GC_dirty_maintained = TRUE;
GC_page_size = GC_getpagesize();
if (GC_page_size % HBLKSIZE != 0) {
# endif
}
# endif
-# if defined(IRIX5) || defined(ALPHA) || defined(SUNOS4)
+# if defined(IRIX5) || defined(ALPHA) || defined(SUNOS4) || defined(LINUX)
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!?");
# endif
}
# endif
+# if defined(MSWIN32)
+ GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
+ if (GC_old_segv_handler != NULL) {
+# ifdef PRINTSTATS
+ GC_err_printf0("Replaced other UnhandledExceptionFilter\n");
+# endif
+ } else {
+ GC_old_segv_handler = SIG_DFL;
+ }
+# endif
}
ptr_t start;
word offset;
word len;
- int i;
+ unsigned i;
for (i = 0; i < GC_n_heap_sects; i++) {
offset = (word)(GC_heap_sects[i].hs_start) & pmask;
start = GC_heap_sects[i].hs_start - offset;
len = GC_heap_sects[i].hs_bytes + offset;
len += ps-1; len &= ~pmask;
- if (mprotect((caddr_t)start, (int)len, PROT_READ | PROT_EXEC) < 0) {
- ABORT("mprotect failed");
- }
+ PROTECT(start, len);
}
}
set_pht_entry_from_index(GC_dirty_pages, index);
}
- if (mprotect((caddr_t)start_block,
- (int)((ptr_t)end_block - (ptr_t)start_block)
- + HBLKSIZE,
- PROT_WRITE | PROT_READ | PROT_EXEC) < 0) {
- ABORT("mprotect failed in GC_unprotect_range:");
- }
+ UNPROTECT(start_block,
+ ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
}
+#ifndef MSWIN32
/* Replacement for UNIX system call. */
/* Other calls that write to the heap */
/* should be handled similarly. */
GC_end_syscall();
return(result);
}
+#endif /* !MSWIN32 */
/*ARGSUSED*/
bool GC_page_was_ever_dirty(h)
GC_err_printf0("\tCall chain at allocation:\n");
for (i = 0; i < NFRAMES; i++) {
if (info[i].ci_pc == 0) break;
- GC_err_printf1("\t##PC##= 0x%X\n\t\targs: ", info[i].ci_pc);
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");
}
}
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, March 28, 1994 1:58 pm PST */
+/* Boehm, April 14, 1995 3:10 pm PDT */
# include "gc_priv.h"
# ifdef PCR
# include <errno.h>
# define MY_MAGIC 17L
+# define MY_DEBUGMAGIC 42L
void * GC_AllocProc(size_t size, PCR_Bool ptrFree, PCR_Bool clear )
{
}
}
+void * GC_DebugAllocProc(size_t size, PCR_Bool ptrFree, PCR_Bool clear )
+{
+ if (ptrFree) {
+ void * result = (void *)GC_debug_malloc_atomic(size, __FILE__,
+ __LINE__);
+ if (clear && result != 0) BZERO(result, size);
+ return(result);
+ } else {
+ return((void *)GC_debug_malloc(size, __FILE__, __LINE__));
+ }
+}
+
# define GC_ReallocProc GC_realloc
+void * GC_DebugReallocProc(void * old_object, size_t new_size_in_bytes)
+{
+ return(GC_debug_realloc(old_object, new_size_in_bytes, __FILE__, __LINE__));
+}
# define GC_FreeProc GC_free
+# define GC_DebugFreeProc GC_debug_free
typedef struct {
PCR_ERes (*ed_proc)(void *p, size_t size, PCR_Any data);
GC_DummyShutdownProc /* mmp_shutdown */
};
+struct PCR_MM_ProcsRep GC_DebugRep = {
+ MY_DEBUGMAGIC,
+ GC_DebugAllocProc,
+ GC_DebugReallocProc,
+ GC_DummyFreeProc, /* mmp_free */
+ GC_DebugFreeProc, /* mmp_unsafeFree */
+ GC_EnumerateProc,
+ GC_DummyShutdownProc /* mmp_shutdown */
+};
+
+bool GC_use_debug = 0;
+
void GC_pcr_install()
{
- PCR_MM_Install(&GC_Rep, &GC_old_allocator);
+ PCR_MM_Install((GC_use_debug? &GC_DebugRep : &GC_Rep), &GC_old_allocator);
}
PCR_ERes
if( !PCR_Base_TestPCRArg("-nogc") ) {
GC_quiet = ( PCR_Base_TestPCRArg("-gctrace") ? 0 : 1 );
+ GC_use_debug = (bool)PCR_Base_TestPCRArg("-debug_alloc");
GC_init();
if( !PCR_Base_TestPCRArg("-nogc_incremental") ) {
/*
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, January 19, 1995 5:39 pm PST */
+/* Boehm, April 18, 1995 1:59 pm PDT */
#include <stdio.h>
#include "gc_priv.h"
}
}
+#if !defined(NO_DEBUGGING)
/* Routines to gather and print heap block info */
/* intended for debugging. Otherwise should be called */
/* with lock. */
(unsigned long)total_bytes);
}
+#endif /* NO_DEBUGGING */
+
/*
* Do the same thing on the entire heap, after first clearing small object
* free lists (if we are not just looking for leaks).
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, January 27, 1995 12:58 pm PST */
+/* Boehm, June 13, 1995 2:33 pm PDT */
/* An incomplete test for the garbage collector. */
/* Some more obscure entry points are not tested at all. */
sexpr c;
sexpr d;
sexpr e;
+ sexpr *f, *g, *h;
# if defined(MSWIN32) || defined(MACOS)
/* Win32S only allows 128K stacks */
# define BIG 1000
# else
-# define BIG 4500
+# if defined PCR
+ /* PCR default stack is 100K. Stack frames are up to 120 bytes. */
+# define BIG 700
+# else
+# define BIG 4500
+# endif
# endif
A.dummy = 17;
c = ints(1, BIG);
d = uncollectable_ints(1, 100);
e = uncollectable_ints(1, 1);
+ /* Check that realloc updates object descriptors correctly */
+ f = (sexpr *)GC_malloc(4 * sizeof(sexpr));
+ f = (sexpr *)GC_realloc(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[799] = ints(1,18);
+ h = (sexpr *)GC_malloc(1025 * sizeof(sexpr));
+ h = (sexpr *)GC_realloc(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++) {
+ (void)ints(1, BIG);
+ }
/* Superficially test interior pointer recognition on stack */
c = (sexpr)((char *)c + sizeof(char *));
d = (sexpr)((char *)d + sizeof(char *));
+
# ifdef __STDC__
GC_FREE((void *)e);
# else
d = (sexpr)((char *)d - sizeof(char *));
check_ints(c,1,BIG);
check_uncollectable_ints(d, 1, 100);
+ check_ints(f[5], 1,17);
+ check_ints(g[799], 1,18);
+ check_ints(h[1999], 1,19);
# ifndef THREADS
a = 0;
# endif
GC_is_valid_displacement_print_proc = fail_proc;
GC_is_visible_print_proc = fail_proc;
x = GC_malloc(16);
- if (GC_base(x + 13) != x || GC_base(y) != 0) {
- (void)GC_printf0("GC_base produced incorrect result\n");
+ if (GC_base(x + 13) != x) {
+ (void)GC_printf0("GC_base(heap ptr) produced incorrect result\n");
FAIL;
}
+# ifndef PCR
+ if (GC_base(y) != 0) {
+ (void)GC_printf0("GC_base(fn_ptr) produced incorrect result\n");
+ FAIL;
+ }
+# endif
if (GC_same_obj(x+5, x) != x + 5) {
(void)GC_printf0("GC_same_obj produced incorrect result\n");
FAIL;
FAIL;
}
if (!TEST_FAIL_COUNT(1)) {
- (void)GC_printf0("GC_is_visible produced wrong failure indication\n");
- FAIL;
+# ifndef RS6000
+ /* ON RS6000s function pointers point to a descriptor in the */
+ /* data segment, so there should have been no failures. */
+ (void)GC_printf0("GC_is_visible produced wrong failure indication\n");
+ FAIL;
+# endif
}
if (GC_is_valid_displacement(y) != y
|| GC_is_valid_displacement(x) != x
FAIL;
}
# ifndef ALL_INTERIOR_POINTERS
+# ifdef RS6000
+ if (!TEST_FAIL_COUNT(1)) {
+# else
if (!TEST_FAIL_COUNT(2)) {
+# endif
(void)GC_printf0("GC_is_valid_displacement produced wrong failure indication\n");
FAIL;
}
int code;
n_tests = 0;
- GC_enable_incremental();
+ /* GC_enable_incremental(); */
(void) GC_set_warn_proc(warn_proc);
th1 = PCR_Th_Fork(run_one_test, 0);
th2 = PCR_Th_Fork(run_one_test, 0);