From: Hans Boehm Date: Wed, 14 Jun 1995 00:00:00 +0000 (+0000) Subject: gc4.5 tarball import X-Git-Tag: gc4_5^0 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8853bba3f4abe3e308df3f4c030a979229bb6671;p=gc gc4.5 tarball import --- diff --git a/Makefile b/Makefile index aee1b11a..c1f81750 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ # 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 @@ -30,6 +30,9 @@ CFLAGS= -O -DALL_INTERIOR_POINTERS -DNO_SIGNALS -DSILENT # -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 @@ -54,6 +57,8 @@ CFLAGS= -O -DALL_INTERIOR_POINTERS -DNO_SIGNALS -DSILENT # 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 @@ -138,7 +143,7 @@ cords: $(CORD_OBJS) cord/cordtest gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/gc_cpp.h $(srcdir)/gc.h Makefile $(CXX) -c $(CXXFLAGS) $(srcdir)/gc_cpp.cc - + test_cpp: $(srcdir)/test_cpp.cc $(srcdir)/gc_cpp.h gc_cpp.o $(srcdir)/gc.h gc.a $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a @@ -157,6 +162,10 @@ dyn_load_sunos53.o: dyn_load.c 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 @@ -215,7 +224,6 @@ clean: 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 @@ -224,9 +232,7 @@ gctest: test.o gc.a if_mach if_not_there # 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 @@ -238,7 +244,7 @@ KandRtest: setjmp_test gctest 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) @@ -258,7 +264,7 @@ gc.tar.Z: gc.tar lint: $(CSRCS) test.c lint -DLINT $(CSRCS) test.c | egrep -v "possible pointer alignment problem|abort|exit|sbrk|mprotect|syscall" - + # BTL: added to test shared library version of collector. # Currently works only under SunOS5. Requires GC_INIT call from statically # loaded client code. diff --git a/PCR-Makefile b/PCR-Makefile index fb8a1f54..a5d04dd4 100644 --- a/PCR-Makefile +++ b/PCR-Makefile @@ -39,9 +39,9 @@ LDFLAGS = $(CONFIG_LDFLAGS) # 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 diff --git a/README b/README index 16eab21f..53d4935a 100644 --- a/README +++ b/README @@ -10,7 +10,7 @@ Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. -This is version 4.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 - @@ -93,7 +93,7 @@ is a fairly sophisticated string package "cord" that makes use of the collector. 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 @@ -120,7 +120,7 @@ cause any pointer into an object (or one past the end) to retain the 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. @@ -144,17 +144,16 @@ read-only data. However if the shared library mechanism can introduce 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 @@ -216,7 +215,7 @@ trademarks of their respective holders): 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 @@ -239,7 +238,7 @@ On other machines we recommend that you do one of the following: 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, @@ -266,7 +265,7 @@ following are likely to require change: On some machines, it is difficult to obtain such a value that is valid across a variety of MMUs, OS releases, etc. A number of alternatives exist for using the collector in spite of this. See the - discussion in config.h.h immediately preceding the various + discussion in config.h immediately preceding the various definitions of STACKBOTTOM. 2. mach_dep.c. @@ -345,7 +344,7 @@ good way for the collector to compute this value.) Client code may include 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 @@ -412,7 +411,7 @@ considered as a candidate for collection. Careless use may, of course, result 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: @@ -435,7 +434,7 @@ THE C++ INTERFACE TO THE ALLOCATOR: 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. @@ -504,7 +503,7 @@ NIL. 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 @@ -650,7 +649,7 @@ for PPCR. 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 @@ -705,7 +704,7 @@ for PPCR. 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. @@ -760,7 +759,7 @@ for PPCR. 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. @@ -988,7 +987,7 @@ functionality not tested by the other programs. 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: @@ -1044,3 +1043,39 @@ 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 + .) + - 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 diff --git a/README.debugging b/README.debugging index 9219c5cc..b000acec 100644 --- a/README.debugging +++ b/README.debugging @@ -8,8 +8,9 @@ If the collector dies in GC_malloc while trying to remove a free list element: 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.) diff --git a/README.win32 b/README.win32 index 7963acad..b8fb3cd2 100644 --- a/README.win32 +++ b/README.win32 @@ -11,7 +11,7 @@ scanned for roots. Thus the collector sees pointers in DLL data 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 @@ -40,7 +40,8 @@ This may be suboptimal for some tastes and/or sets of default 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 @@ -51,3 +52,26 @@ I expect that -a1 introduces major performance penalties on a 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. + diff --git a/allchblk.c b/allchblk.c index ab0ccf71..8912590b 100644 --- a/allchblk.c +++ b/allchblk.c @@ -11,7 +11,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, January 31, 1995 3:01 pm PST */ +/* Boehm, June 13, 1995 3:34 pm PDT */ #define DEBUG #undef DEBUG @@ -19,11 +19,11 @@ #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. @@ -42,6 +42,7 @@ struct hblk *GC_savhbp = (struct hblk *)0; /* heap block preceding next */ /* block to be examined by */ /* GC_allochblk. */ +# if !defined(NO_DEBUGGING) void GC_print_hblkfreelist() { struct hblk * h = GC_hblkfreelist; @@ -66,6 +67,8 @@ void GC_print_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. */ @@ -196,7 +199,8 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */ } 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 diff --git a/alloc.c b/alloc.c index e58590a9..d765094a 100644 --- a/alloc.c +++ b/alloc.c @@ -12,7 +12,7 @@ * 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" @@ -568,6 +568,29 @@ word bytes; } } +# 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; diff --git a/checksums.c b/checksums.c index da532637..7d9b7b7d 100644 --- a/checksums.c +++ b/checksums.c @@ -10,7 +10,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, January 31, 1995 12:36 pm PST */ +/* Boehm, March 29, 1995 12:51 pm PST */ # ifdef CHECKSUMS # include "gc_priv.h" @@ -125,7 +125,7 @@ word dummy; GC_bytes_in_used_blocks += bytes; } -GC_check_blocks() +void GC_check_blocks() { word bytes_in_free_blocks = 0; struct hblk * h = GC_hblkfreelist; @@ -152,7 +152,7 @@ GC_check_blocks() void GC_check_dirty() { register int index; - register int i; + register unsigned i; register struct hblk *h; register ptr_t start; diff --git a/config.h b/config.h index 2ccc7742..c0004e63 100644 --- a/config.h +++ b/config.h @@ -11,7 +11,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, February 6, 1995 5:24 pm PST */ +/* Boehm, May 30, 1995 5:04 pm PDT */ #ifndef CONFIG_H @@ -33,6 +33,11 @@ # 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 @@ -74,7 +79,7 @@ # 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 @@ -305,6 +310,12 @@ # 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; @@ -419,7 +430,8 @@ /* 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 @@ -467,6 +479,7 @@ 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" @@ -478,6 +491,7 @@ # define OS_TYPE "MSWIN32" /* STACKBOTTOM and DATASTART are handled specially in */ /* os_dep.c. */ +# define MPROTECT_VDB # endif # ifdef FREEBSD # define OS_TYPE "FREEBSD" @@ -570,6 +584,7 @@ # define HEURISTIC2_LIMIT ((ptr_t)((word)(&__start) & ~(getpagesize()-1))) # define CPP_WORDSZ 64 # define MPROTECT_VDB +# define DYNAMIC_LOADING # endif # ifdef M88K diff --git a/cord/cordxtra.c b/cord/cordxtra.c index e39612c8..0e4a478f 100644 --- a/cord/cordxtra.c +++ b/cord/cordxtra.c @@ -555,6 +555,17 @@ CORD CORD_from_file_lazy_inner(FILE * f, size_t len) 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; diff --git a/cord/gc.h b/cord/gc.h index 9ebbfe42..c9fb14fc 100644 --- a/cord/gc.h +++ b/cord/gc.h @@ -439,7 +439,7 @@ void GC_debug_end_stubborn_change(/* p */); /* 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 @@ -463,7 +463,7 @@ void GC_debug_end_stubborn_change(/* p */); /* 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 @@ -485,7 +485,7 @@ void GC_debug_end_stubborn_change(/* p */); /* 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 @@ -650,7 +650,7 @@ void * GC_malloc_many(size_t lb); * 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 diff --git a/dbg_mlc.c b/dbg_mlc.c index 0baa7c6b..16c19c9d 100644 --- a/dbg_mlc.c +++ b/dbg_mlc.c @@ -11,7 +11,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, 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 */ @@ -153,6 +153,7 @@ ptr_t p, clobbered_addr; } GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int), (unsigned long)(ohdr -> oh_sz)); + PRINT_CALL_CHAIN(ohdr); } } diff --git a/dyn_load.c b/dyn_load.c index a48a3021..601c3650 100644 --- a/dyn_load.c +++ b/dyn_load.c @@ -13,7 +13,7 @@ * 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 @@ -45,7 +45,7 @@ # 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. @@ -202,7 +202,8 @@ void GC_register_dynamic_libraries() 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; @@ -222,7 +223,8 @@ void GC_register_dynamic_libraries() start = ((char *)(p->p_vaddr)) + offset; GC_add_roots_inner( start, - start + p->p_memsz + start + p->p_memsz, + TRUE ); } break; @@ -241,7 +243,7 @@ void GC_register_dynamic_libraries() 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 @@ -341,7 +343,7 @@ void GC_register_dynamic_libraries() } } } - GC_add_roots_inner(start, limit); + GC_add_roots_inner(start, limit, TRUE); irrelevant: ; } } @@ -371,7 +373,7 @@ void GC_register_dynamic_libraries() /* Part of the stack; ignore it. */ return; } - GC_add_roots_inner(base, limit); + GC_add_roots_inner(base, limit, TRUE); } extern bool GC_win32s; @@ -418,6 +420,9 @@ void GC_register_dynamic_libraries() #endif /* MSWIN32 */ #if defined(ALPHA) + +#include + void GC_register_dynamic_libraries() { int status; @@ -510,7 +515,8 @@ void GC_register_dynamic_libraries() /* 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); } } @@ -548,7 +554,8 @@ void GC_register_dynamic_libraries() == 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); } } } diff --git a/gc.h b/gc.h index 9ebbfe42..c9fb14fc 100644 --- a/gc.h +++ b/gc.h @@ -439,7 +439,7 @@ void GC_debug_end_stubborn_change(/* p */); /* 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 @@ -463,7 +463,7 @@ void GC_debug_end_stubborn_change(/* p */); /* 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 @@ -485,7 +485,7 @@ void GC_debug_end_stubborn_change(/* p */); /* 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 @@ -650,7 +650,7 @@ void * GC_malloc_many(size_t lb); * 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 diff --git a/gc_priv.h b/gc_priv.h index 2750a335..bc2b0d59 100644 --- a/gc_priv.h +++ b/gc_priv.h @@ -11,7 +11,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, January 30, 1995 4:01 pm PST */ +/* Boehm, April 18, 1995 2:51 pm PDT */ # ifndef GC_PRIVATE_H @@ -201,8 +201,13 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ #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. */ @@ -606,9 +611,13 @@ extern GC_warn_proc GC_current_warn_proc; * 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]; @@ -822,7 +831,15 @@ struct _GC_arrays { 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]; @@ -1254,6 +1271,9 @@ void GC_stubborn_init(); /* Debugging print routines: */ void GC_print_block_list(); void GC_print_hblkfreelist(); +void GC_print_heap_sects(); +void GC_print_static_roots(); +void GC_dump(); /* Make arguments appear live to compiler */ void GC_noop(); diff --git a/include/gc.h b/include/gc.h index 9ebbfe42..c9fb14fc 100644 --- a/include/gc.h +++ b/include/gc.h @@ -439,7 +439,7 @@ void GC_debug_end_stubborn_change(/* p */); /* 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 @@ -463,7 +463,7 @@ void GC_debug_end_stubborn_change(/* p */); /* 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 @@ -485,7 +485,7 @@ void GC_debug_end_stubborn_change(/* p */); /* 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 @@ -650,7 +650,7 @@ void * GC_malloc_many(size_t lb); * 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 diff --git a/malloc.c b/malloc.c index 56caa485..67e00fc4 100644 --- a/malloc.c +++ b/malloc.c @@ -11,7 +11,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, February 10, 1995 12:55 pm PST */ +/* Boehm, June 13, 1995 3:07 pm PDT */ #include #include "gc_priv.h" @@ -115,7 +115,6 @@ ptr_t GC_generic_malloc_inner_ignore_off_page(lb, k) register size_t lb; register int k; { -# ifdef ALL_INTERIOR_POINTERS register struct hblk * h; register word n_blocks; register word lw; @@ -139,9 +138,6 @@ register int k; } 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) @@ -508,11 +504,15 @@ int obj_kind; 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. */ } diff --git a/mark_rts.c b/mark_rts.c index e0a6d9c4..0b7a48ad 100644 --- a/mark_rts.c +++ b/mark_rts.c @@ -11,19 +11,23 @@ * 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 # 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 @@ -37,6 +41,8 @@ struct roots { # ifndef MSWIN32 struct roots * r_next; # endif + bool r_tmp; + /* Delete before registering new dynamic libraries */ }; static struct roots static_roots[MAX_ROOT_SETS]; @@ -45,6 +51,32 @@ static int n_root_sets = 0; /* 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? */ @@ -134,7 +166,7 @@ char * b; char * e; DISABLE_SIGNALS(); LOCK(); - GC_add_roots_inner(b, e); + GC_add_roots_inner(b, e, FALSE); UNLOCK(); ENABLE_SIGNALS(); } @@ -144,8 +176,11 @@ char * b; char * e; /* 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; @@ -158,8 +193,8 @@ char * b; char * e; } 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; } } @@ -178,10 +213,13 @@ char * b; char * e; 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; } } @@ -196,14 +234,18 @@ char * b; char * e; 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; @@ -224,6 +266,7 @@ char * b; char * e; } 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 @@ -251,6 +294,33 @@ void GC_clear_roots(NO_PARAMS) 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; @@ -282,6 +352,7 @@ bool all; /* 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 */ diff --git a/misc.c b/misc.c index 31e18c03..b0e7e431 100644 --- a/misc.c +++ b/misc.c @@ -11,18 +11,22 @@ * 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 #include -#ifdef SOLARIS_THREADS -# include -#endif #define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */ #include "gc_priv.h" +#ifdef SOLARIS_THREADS +# include +#endif +#ifdef MSWIN32 +# include +#endif + # ifdef THREADS # ifdef PCR # include "il/PCR_IL.h" @@ -453,10 +457,11 @@ void GC_init_inner() 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"); @@ -495,9 +500,12 @@ void GC_init_inner() 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 @@ -511,6 +519,14 @@ void GC_enable_incremental(NO_PARAMS) 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 @@ -540,7 +556,6 @@ out: #ifdef MSWIN32 # define LOG_FILE "gc.log" -# include HANDLE GC_stdout = 0, GC_stderr; int GC_tmp; @@ -549,7 +564,8 @@ out: 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"); @@ -585,23 +601,42 @@ int GC_tmp; /* Should really be local ... */ # 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 */ @@ -691,3 +726,19 @@ void GC_disable() 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 */ diff --git a/os_dep.c b/os_dep.c index 0519bc5a..1cf3240c 100644 --- a/os_dep.c +++ b/os_dep.c @@ -10,7 +10,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, 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) @@ -245,7 +245,7 @@ void GC_enable_signals() /* Get the page size. */ word GC_page_size = 0; -word GC_get_page_size() +word GC_getpagesize() { SYSTEM_INFO sysinfo; @@ -285,7 +285,7 @@ ptr_t GC_get_stack_base() { 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); @@ -564,7 +564,7 @@ void GC_register_data_segments() 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); } } @@ -580,9 +580,17 @@ void GC_register_data_segments() /* 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 */ @@ -599,9 +607,9 @@ void GC_register_data_segments() 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; @@ -661,7 +669,7 @@ void GC_register_data_segments() 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; } @@ -669,7 +677,7 @@ void GC_register_data_segments() 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() @@ -717,7 +725,8 @@ 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); } } } @@ -749,10 +758,21 @@ void GC_register_data_segments() # 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) { @@ -760,11 +780,11 @@ void GC_register_data_segments() 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 } @@ -1035,7 +1055,7 @@ void (*GC_push_other_roots)() = GC_default_push_other_roots; * or write only to the stack. */ -bool GC_dirty_maintained; +bool GC_dirty_maintained = FALSE; # ifdef DEFAULT_VDB @@ -1118,9 +1138,42 @@ struct hblk *h; * not to work under a number of other systems. */ -# include -# include -# include +# ifndef MSWIN32 + +# include +# include +# include + +# 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 + + 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. */ @@ -1130,7 +1183,7 @@ word GC_page_size; 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; @@ -1149,9 +1202,14 @@ word addr; #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 *); @@ -1159,9 +1217,13 @@ word addr; #if defined(SUNOS5SIGS) typedef void (* REAL_SIG_PF)(int, struct siginfo *, void *); #endif +#if defined(LINUX) +# include + 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) @@ -1191,13 +1253,28 @@ SIG_PF GC_old_segv_handler; # 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 @@ -1206,6 +1283,14 @@ SIG_PF GC_old_segv_handler; # 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) { @@ -1221,18 +1306,31 @@ SIG_PF GC_old_segv_handler; 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++) { @@ -1240,17 +1338,18 @@ SIG_PF GC_old_segv_handler; 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"); @@ -1259,11 +1358,13 @@ SIG_PF GC_old_segv_handler; 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); @@ -1273,10 +1374,7 @@ struct hblk *h; } } 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); } } @@ -1288,7 +1386,11 @@ GC_getpagesize() 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() @@ -1299,6 +1401,9 @@ 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) { @@ -1317,7 +1422,7 @@ void GC_dirty_init() # 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!?"); @@ -1346,6 +1451,16 @@ void GC_dirty_init() # 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 } @@ -1357,16 +1472,14 @@ void GC_protect_heap() 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); } } @@ -1431,14 +1544,11 @@ word 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. */ @@ -1476,6 +1586,7 @@ int nbyte; GC_end_syscall(); return(result); } +#endif /* !MSWIN32 */ /*ARGSUSED*/ bool GC_page_was_ever_dirty(h) @@ -1859,12 +1970,12 @@ struct callinfo info[NFRAMES]; GC_err_printf0("\tCall chain at allocation:\n"); for (i = 0; i < NFRAMES; i++) { if (info[i].ci_pc == 0) break; - GC_err_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"); } } diff --git a/pcr_interface.c b/pcr_interface.c index 1c52938d..f4a11789 100644 --- a/pcr_interface.c +++ b/pcr_interface.c @@ -10,7 +10,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, March 28, 1994 1:58 pm PST */ +/* Boehm, April 14, 1995 3:10 pm PDT */ # include "gc_priv.h" # ifdef PCR @@ -25,6 +25,7 @@ # include # define MY_MAGIC 17L +# define MY_DEBUGMAGIC 42L void * GC_AllocProc(size_t size, PCR_Bool ptrFree, PCR_Bool clear ) { @@ -37,9 +38,26 @@ 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); @@ -109,9 +127,21 @@ struct PCR_MM_ProcsRep GC_Rep = { 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 @@ -126,6 +156,7 @@ PCR_GC_Run(void) 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") ) { /* diff --git a/reclaim.c b/reclaim.c index 2278a5a2..7dbd1349 100644 --- a/reclaim.c +++ b/reclaim.c @@ -11,7 +11,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, January 19, 1995 5:39 pm PST */ +/* Boehm, April 18, 1995 1:59 pm PDT */ #include #include "gc_priv.h" @@ -532,6 +532,7 @@ word abort_if_found; /* Abort if a reclaimable object is found */ } } +#if !defined(NO_DEBUGGING) /* Routines to gather and print heap block info */ /* intended for debugging. Otherwise should be called */ /* with lock. */ @@ -593,6 +594,8 @@ void GC_print_block_list() (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). diff --git a/test.c b/test.c index 48191be7..b64695db 100644 --- a/test.c +++ b/test.c @@ -11,7 +11,7 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, 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. */ @@ -269,11 +269,17 @@ void reverse_test() 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; @@ -282,9 +288,24 @@ void reverse_test() 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 @@ -318,6 +339,9 @@ void reverse_test() 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 @@ -661,10 +685,16 @@ void run_one_test() 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; @@ -674,8 +704,12 @@ void run_one_test() 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 @@ -685,7 +719,11 @@ void run_one_test() 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; } @@ -860,7 +898,7 @@ test() 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);