From 87cf2ac8587a863708ad53520a01dc6285f11f1b Mon Sep 17 00:00:00 2001 From: Hans Boehm Date: Tue, 27 Apr 1993 00:00:00 +0000 Subject: [PATCH] gc2.6 tarball import --- Makefile | 47 +++-- OS2_MAKEFILE | 5 +- PCR-Makefile | 55 +++--- README | 15 +- alloc.c | 122 +++++++++---- allochblk.c | 155 ++++++---------- black_list.c | 8 +- config.h | 375 ++++++++++++++++++++++++++++++++++++++ debug_malloc.c | 48 ++--- dynamic_load.c | 170 +++++++++++------ gc.h | 2 +- gc_private.h | 473 +++++++++--------------------------------------- headers.c | 4 +- if_mach.c | 22 +++ if_not_there.c | 24 +++ mach_dep.c | 33 +++- mark.c | 18 +- mark_roots.c | 102 ++++++++--- misc.c | 59 +++--- obj_map.c | 2 +- os_dep.c | 109 +++++++---- pcr_interface.c | 12 +- reclaim.c | 20 +- setjmp_test.c | 14 +- test.c | 29 ++- 25 files changed, 1123 insertions(+), 800 deletions(-) create mode 100644 config.h create mode 100644 if_mach.c create mode 100644 if_not_there.c diff --git a/Makefile b/Makefile index 0f0d9cf8..ab77025e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,12 @@ OBJS= alloc.o reclaim.o allochblk.o misc.o mach_dep.o os_dep.o mark_roots.o head CSRCS= reclaim.c allochblk.c misc.c alloc.c mach_dep.c os_dep.c mark_roots.c headers.c mark.c obj_map.c pcr_interface.c black_list.c finalize.c new_hblk.c real_malloc.c dynamic_load.c debug_malloc.c -SRCS= $(CSRCS) mips_mach_dep.s rs6000_mach_dep.s interface.c gc.h gc_headers.h gc_private.h gc_inline.h gc.man +SRCS= $(CSRCS) mips_mach_dep.s rs6000_mach_dep.s interface.c gc.h gc_headers.h gc_private.h config.h gc_inline.h gc.man if_mach.c if_not_there.c + +# The following is irrelevant on most systems. But a few +# versions of make otherwise fork the shell specified in +# the SHELL environment variable. +SHELL= /bin/sh CC= cc CFLAGS= -O @@ -17,40 +22,34 @@ SPECIALCFLAGS = all: gc.a gctest -pcr: PCR-Makefile gc_private.h gc_headers.h gc.h $(SRCS) +pcr: PCR-Makefile gc_private.h gc_headers.h gc.h config.h mach_dep.o $(SRCS) + make -f PCR-Makefile depend make -f PCR-Makefile -$(OBJS) test.o: gc_private.h gc_headers.h gc.h Makefile +$(OBJS) test.o: gc_private.h gc_headers.h gc.h config.h Makefile -# On some machines, the ranlib command may have to be removed. -# On an SGI for example, ranlib doesn't exist, and is not needed. -# Ditto for Solaris 2.X. gc.a: $(OBJS) ar ru gc.a $(OBJS) - ranlib gc.a - -# On a MIPS-based machine, replace the rule for mach_dep.o by the -# following: -# mach_dep.o: mips_mach_dep.s -# as -o mach_dep.o mips_mach_dep.s -# On an IBM RS6000, use the following two lines: -# mach_dep.o: rs6000_mach_dep.s -# as -o mach_dep.o rs6000_mach_dep.s -mach_dep.o: mach_dep.c - $(CC) -c $(SPECIALCFLAGS) mach_dep.c + ranlib gc.a || cat /dev/null +# ignore ranlib failure; that usually means it doesn't exist, and isn't needed + +mach_dep.o: mach_dep.c mips_mach_dep.s rs6000_mach_dep.s if_mach if_not_there + rm -f mach_dep.o + ./if_mach MIPS "" as -o mach_dep.o mips_mach_dep.s + ./if_mach RS6000 "" as -o mach_dep.o rs6000_mach_dep.s + ./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) mach_dep.c + +if_mach: if_mach.c config.h + $(CC) $(CFLAGS) -o if_mach if_mach.c + +if_not_there: if_not_there.c + $(CC) $(CFLAGS) -o if_not_there if_not_there.c clean: rm -f gc.a test.o gctest output-local output-diff $(OBJS) \ setjmp_test mon.out gmon.out a.out core -rm -f *~ - -# On a MIPS system, the BSD version of libc.a should be used to get -# sigsetmask. I found it necessary to link against the system V -# library first, to get a working version of fprintf. But this may have -# been due to my failure to find the right version of stdio.h or some -# such thing. -# On a Solaris 2.X system, also make sure you're using BSD libraries. gctest: test.o gc.a $(CC) $(CFLAGS) -o gctest test.o gc.a diff --git a/OS2_MAKEFILE b/OS2_MAKEFILE index 249486df..07460d84 100644 --- a/OS2_MAKEFILE +++ b/OS2_MAKEFILE @@ -4,12 +4,13 @@ # look at another threads registers. # We also haven't figured out how to do partial links or build static libraries. Hence a -# client currentlu needs to link against all of the following: +# client currently needs to link against all of the following: OBJS= alloc.obj reclaim.obj allochblk.obj misc.obj mach_dep.obj os_dep.obj mark_roots.obj headers.obj mark.obj obj_map.obj black_list.obj finalize.obj new_hblk.obj real_malloc.obj dynamic_load.obj debug_malloc.obj CC= icc -CFLAGS= /Ti /Q +CFLAGS= /O /Q +# Use /Ti instead of /O for debugging # Setjmp_test may yield overly optimistic results when compiled # without optimization. diff --git a/PCR-Makefile b/PCR-Makefile index 616ffdc7..a432999b 100644 --- a/PCR-Makefile +++ b/PCR-Makefile @@ -1,41 +1,44 @@ OBJS= alloc.o reclaim.o allochblk.o misc.o mach_dep.o os_dep.o mark_roots.o headers.o mark.o obj_map.o pcr_interface.o black_list.o finalize.o new_hblk.o real_malloc.o dynamic_load.o debug_malloc.o +CSRCS= reclaim.c allochblk.c misc.c alloc.c mach_dep.c os_dep.c mark_roots.c headers.c mark.c obj_map.c pcr_interface.c black_list.c finalize.c new_hblk.c real_malloc.c dynamic_load.c debug_malloc.c + +SHELL= /bin/sh + # Fix to point to local pcr installation directory. -PCRDIR= /project/ppcr/dev +PCRDIR= /project/ppcr/v1.5 CC= gcc CFLAGS= -g -DPCR -I$(PCRDIR) -I$(PCRDIR)/pcr -I$(PCRDIR)/pcr/ansi -I$(PCRDIR)/pcr/posix -# On Sun systems under 4.x, it's safer to link with -Bstatic. -# On other systems, -Bstatic usually doesn't make sense, and should be -# removed. -# Setjmp_test may yield overly optimistic results when compiled -# without optimization. - -SPECIALCFLAGS = -# Alternative flags to the C compiler for mach_dep.c. -# Mach_dep.c often doesn't like optimization, and it's -# not time-critical anyway. -# Set SPECIALCFLAGS to -q nodirect_code on Encore. - -PCRINCLS= $(PCRDIR)/pcr/il/PCR_IL.h $(PCRDIR)/pcr/th/PCR_ThCtl.h $(PCRDIR)/pcr/mm/PCR_MM.h +# We assume that mach_dep.o has already been built by top level makefile. It doesn't +# care about pcr vs UNIX, and we don't want to repeat that cruft. all: gc.o test.o gcpcr gcpcr: gc.o test.o $(PCRDIR)/pcr/base/pcr.o $(PCRDIR)/pcr/base/PCR_BaseMain.o - $(CC) -static -o gcpcr $(PCRDIR)/pcr/base/pcr.o $(PCRDIR)/pcr/base/PCR_BaseMain.o gc.o test.o - -$(OBJS) test.o: gc_private.h gc_headers.h gc.h PCR-Makefile $(PCRINCLS) + $(CC) -o gcpcr $(PCRDIR)/pcr/base/pcr.o $(PCRDIR)/pcr/base/PCR_BaseMain.o gc.o test.o -ldl gc.o: $(OBJS) -ld -r -o gc.o $(OBJS) -# On a MIPS machine, replace the rule for mach_dep.o by the -# following: -# mach_dep.o: mips_mach_dep.s -# as -o mach_dep.o mips_mach_dep.s -# On an IBM RS6000, use the following two lines: -# mach_dep.o: rs6000_mach_dep.s -# as -o mach_dep.o rs6000_mach_dep.s -mach_dep.o: mach_dep.c - $(CC) -c ${SPECIALCFLAGS} mach_dep.c +# +# Dependency construction +# +# NOTE: the makefile must include "# DO NOT DELETE THIS LINE" after the +# last target. "make depend" will replace everything following that line +# by a newly-constructed list of dependencies. +# +depend: $(CSRCS) + rm -f makedep eddep ; \ + $(CC) -M $(CFLAGS) $(CSRCS) \ + | sed -e '/:$$/d' > makedep ; \ + echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep ; \ + echo '$$r makedep' >>eddep ; \ + echo 'w' >>eddep ; \ + cp PCR-Makefile PCR-Makefile.bak ; \ + ex - PCR-Makefile < eddep ; \ + rm -f eddep makedep + touch depend + +# DO NOT DELETE THIS LINE + diff --git a/README b/README index 13133fa6..390f50b2 100644 --- a/README +++ b/README @@ -8,7 +8,7 @@ Permission is hereby granted to copy this garbage collector for any purpose, provided the above notices are retained on all copies. -This is version 2.4. Note that functions were renamed since version 1.9 +This is version 2.6. Note that functions were renamed since version 1.9 to make naming consistent with PCR collectors. HISTORY - @@ -542,3 +542,16 @@ for PPCR. under 4.1.1U1, but apparently not 4.1.1. If you have such a machine, use -Bstatic.) + Version 2.5 added Solaris dynamic libary support, Solaris/Intel support, + and fixed the following bugs: +- Removed an explicit call to exit(1) +- Fixed calls to GC_printf and GC_err_printf, so the correct number of + arguments are always supplied. The OS/2 C compiler gets confused if + the number of actuals and the number of formals differ. (ANSI C + doesn't require this to work. The ANSI sanctioned way of doing things + causes too many compatibility problems.) + + Version 2.6 fixed a bug diagnosed by Al Dosser at DEC. The marker + could lose some pointers in the event of a mark stack overflow, a case + it was intended to handle correctly. (He also pointed out a performance + bug that was tickled under the same circumstances.) diff --git a/alloc.c b/alloc.c index e97492f0..1456d529 100644 --- a/alloc.c +++ b/alloc.c @@ -10,7 +10,7 @@ * * This file contains the functions: * static void clear_marks() - * void GC_gcollect_inner(force) + * bool GC_gcollect_inner(force) * void GC_gcollect() * bool GC_expand_hp(n) * ptr_t GC_allocobj(sz, kind) @@ -86,7 +86,12 @@ char * GC_copyright[] = extern signed_word GC_mem_found; /* Number of reclaimed longwords */ /* after garbage collection */ -extern errno; +/* clear all mark bits in the header */ +void GC_clear_hdr_marks(hhdr) +register hdr * hhdr; +{ + bzero((char *)hhdr -> hb_marks, (int)(MARK_BITS_SZ*sizeof(word))); +} /* * Clear all mark bits associated with block h. @@ -97,11 +102,8 @@ struct hblk *h; word dummy; { register hdr * hhdr = HDR(h); - register int j; - for (j = 0; j < MARK_BITS_SZ; j++) { - hhdr -> hb_marks[j] = 0; - } + GC_clear_hdr_marks(hhdr); } /* @@ -136,6 +138,36 @@ static word min_words_allocd() return(BYTES_TO_WORDS(GC_heapsize + total_root_size)/GC_free_space_divisor); } +/* Return the number of words allocated, adjusted for explicit storage */ +/* management. This number can be used in deciding when to trigger */ +/* collections. */ +word GC_adj_words_allocd() +{ + register signed_word result; + register signed_word expl_managed = + BYTES_TO_WORDS((long)GC_non_gc_bytes + - (long)GC_non_gc_bytes_at_gc); + + /* Don't count what was explicitly freed, or newly allocated for */ + /* explicit management. Note that deallocating an explicitly */ + /* managed object should not alter result, assuming the client */ + /* is playing by the rules. */ + result = (signed_word)GC_words_allocd + - (signed_word)GC_mem_freed - expl_managed; + if (result > (signed_word)GC_words_allocd) result = GC_words_allocd; + /* probably client bug or unfortunate scheduling */ + if (result < (signed_word)(GC_words_allocd >> 2)) { + /* Always count at least 1/8 of the allocations. We don't want */ + /* to collect too infrequently, since that would inhibit */ + /* coalescing of free storage blocks. */ + /* This also makes us partially robust against client bugs. */ + return(GC_words_allocd >> 3); + } else { + return(result); + } +} + + /* Clear up a few frames worth og garbage left at the top of the stack. */ /* This is used to prevent us from accidentally treating garbade left */ /* on the stack by other parts of the collector as roots. This */ @@ -156,8 +188,10 @@ void GC_clear_a_few_frames() * garbage collection) * We assume we hold the allocation lock, and are not interruptable by * signals, if that matters. + * If force is FALSE and we didn't do anything, return FALSE. + * Otherwise return TRUE */ -void GC_gcollect_inner(force) +bool GC_gcollect_inner(force) bool force; /* Collect even if only a small amount of allocation */ /* has taken place. Otherwise we refuse, allowing the */ /* heap to grow. */ @@ -169,12 +203,12 @@ bool force; /* Collect even if only a small amount of allocation */ # endif if (!force && !GC_dont_expand - && GC_words_allocd < min_words_allocd()) return; + && GC_adj_words_allocd() < min_words_allocd()) return(FALSE); # ifdef PRINTTIMES GET_TIME(start_time); # endif # ifdef PRINTSTATS - GC_printf("Collection %lu reclaimed %ld bytes\n", + GC_printf2("Collection %lu reclaimed %ld bytes\n", (unsigned long) GC_gc_no, (long)WORDS_TO_BYTES(GC_mem_found)); # endif @@ -185,15 +219,14 @@ bool force; /* Collect even if only a small amount of allocation */ GC_atomic_in_use = 0; # endif # ifdef PRINTSTATS - GC_printf("Collection number %lu after %lu allocated bytes ", + GC_printf2("Collection number %lu after %lu allocated bytes ", (unsigned long) GC_gc_no, (unsigned long) WORDS_TO_BYTES(GC_words_allocd)); - GC_printf("(heapsize = %lu bytes)\n", + GC_printf1("(heapsize = %lu bytes)\n", (unsigned long) GC_heapsize); /* Printf arguments may be pushed in funny places. Clear the */ /* space. */ - GC_printf("", (unsigned long)0, (unsigned long)0, (unsigned long)0, - (unsigned long)0, (unsigned long)0, (unsigned long)0); + GC_printf0(""); # endif clear_marks(); @@ -278,7 +311,7 @@ bool force; /* Collect even if only a small amount of allocation */ # ifdef PRINTSTATS - GC_printf("Bytes recovered before GC_reclaim - f.l. count = %ld\n", + GC_printf1("Bytes recovered before GC_reclaim - f.l. count = %ld\n", (long)WORDS_TO_BYTES(GC_mem_found)); # endif @@ -288,25 +321,29 @@ bool force; /* Collect even if only a small amount of allocation */ # endif /* FIND_LEAK */ # ifdef PRINTSTATS - GC_printf("Immediately reclaimed %ld bytes in heap of size %lu bytes\n", + GC_printf2( + "Immediately reclaimed %ld bytes in heap of size %lu bytes\n", (long)WORDS_TO_BYTES(GC_mem_found), (unsigned long)GC_heapsize); - GC_printf("%lu (atomic) + %lu (composite) bytes in use\n", - (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use), - (unsigned long)WORDS_TO_BYTES(GC_composite_in_use)); + GC_printf2("%lu (atomic) + %lu (composite) bytes in use\n", + (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use), + (unsigned long)WORDS_TO_BYTES(GC_composite_in_use)); # endif /* Reset or increment counters for next cycle */ GC_words_allocd_before_gc += GC_words_allocd; + GC_non_gc_bytes_at_gc = GC_non_gc_bytes; GC_words_allocd = 0; + GC_mem_freed = 0; /* Get final time */ # ifdef PRINTTIMES GET_TIME(done_time); - GC_printf("Garbage collection took %lu + %lu msecs\n", - MS_TIME_DIFF(mark_time,start_time), - MS_TIME_DIFF(done_time,mark_time)); + GC_printf2("Garbage collection took %lu + %lu msecs\n", + MS_TIME_DIFF(mark_time,start_time), + MS_TIME_DIFF(done_time,mark_time)); # endif + return(TRUE); } /* Externally callable version of above */ @@ -319,7 +356,7 @@ void GC_gcollect() if (!GC_is_initialized) GC_init_inner(); /* Minimize junk left in my registers */ GC_noop(0,0,0,0,0,0); - GC_gcollect_inner(TRUE); + (void) GC_gcollect_inner(TRUE); UNLOCK(); ENABLE_SIGNALS(); } @@ -388,7 +425,7 @@ word n; return(FALSE); } # ifdef PRINTSTATS - GC_printf("Increasing heap size by %lu\n", + GC_printf1("Increasing heap size by %lu\n", (unsigned long)bytes); # endif expansion_slop = 8 * WORDS_TO_BYTES(min_words_allocd()); @@ -429,6 +466,26 @@ int n; return(result); } +void GC_collect_or_expand(needed_blocks) +word needed_blocks; +{ + static int count = 0; /* How many failures? */ + + if (GC_dont_gc || !GC_gcollect_inner(FALSE)) { + if (!GC_expand_hp_inner(GC_hincr + needed_blocks) + && !GC_expand_hp_inner(needed_blocks)) { + if (count++ < 20) { + WARN("Out of Memory! Trying to continue ...\n"); + (void) GC_gcollect_inner(TRUE); + } else { + GC_err_printf0("Out of Memory! Giving up!\n"); + EXIT(); + } + } + update_GC_hincr; + } +} + /* * Make sure the object free list for sz is not empty. * Return a pointer to the first object on the free list. @@ -440,25 +497,16 @@ word sz; int kind; { register ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]); + if (sz == 0) return(0); - if (*flh == 0) { + while (*flh == 0) { GC_continue_reclaim(sz, kind); - } - if (*flh == 0) { - if (!GC_sufficient_hb(sz, kind) && !GC_dont_gc) { - if (GC_DIV * GC_non_gc_bytes < GC_MULT * GC_heapsize) { - GC_gcollect_inner(FALSE); - GC_continue_reclaim(sz, kind); - } else { - if (!GC_expand_hp_inner(NON_GC_HINCR)) { - GC_gcollect_inner(FALSE); - GC_continue_reclaim(sz, kind); - } - } + if (*flh == 0) { + GC_new_hblk(sz, kind); } if (*flh == 0) { - GC_new_hblk(sz, kind); + GC_collect_or_expand((word)1); } } return(*flh); diff --git a/allochblk.c b/allochblk.c index 1dcf581b..48212b7f 100644 --- a/allochblk.c +++ b/allochblk.c @@ -38,61 +38,24 @@ struct hblk *GC_savhbp = (struct hblk *)0; /* heap block preceding next */ /* block to be examined by */ /* GC_allochblk. */ -/* - * Return TRUE if there is a heap block sufficient for object size sz, - * FALSE otherwise. Advance GC_savhbp to point to the block prior to the - * first such block. - */ -bool GC_sufficient_hb(sz, kind) -word sz; +/* Initialize hdr for a block containing the indicated size and */ +/* kind of objects. */ +static setup_header(hhdr, sz, kind) +register hdr * hhdr; +word sz; /* object size in words */ int kind; { -register struct hblk *hbp; -register hdr * hhdr; -struct hblk *prevhbp; -signed_word size_needed; -signed_word size_avail; -bool first_time = TRUE; - - size_needed = WORDS_TO_BYTES(sz); - size_needed = (size_needed+HDR_BYTES+HBLKSIZE-1) & ~HBLKMASK; -# ifdef DEBUG - GC_printf("GC_sufficient_hb: sz = %ld, size_needed = 0x%lx\n", - (long)sz, (unsigned long)size_needed); -# endif - /* search for a big enough block in free list */ - hbp = GC_savhbp; - hhdr = HDR(hbp); - for(;;) { - prevhbp = hbp; - hbp = ((prevhbp == (struct hblk *)0) - ? GC_hblkfreelist - : hhdr->hb_next); - hhdr = HDR(hbp); - - if( prevhbp == GC_savhbp && !first_time) { - /* no sufficiently big blocks on free list */ - return(FALSE); - } - first_time = 0; - if( hbp == (struct hblk *)0 ) continue; - size_avail = hhdr->hb_sz; - if ( kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC) { - struct hblk * thishbp; - struct hblk * lasthbp = hbp; - - while ((ptr_t)lasthbp - (ptr_t)hbp < size_avail - && (thishbp = GC_is_black_listed(lasthbp, - (word)size_needed))) { - lasthbp = thishbp; - } - size_avail -= (ptr_t)lasthbp - (ptr_t)hbp; - } - if( size_avail >= size_needed ) { - GC_savhbp = prevhbp; - return(TRUE); - } - } + /* Set size, kind and mark proc fields */ + hhdr -> hb_sz = sz; + hhdr -> hb_obj_kind = kind; + hhdr -> hb_mark_proc = GC_obj_kinds[kind].ok_mark_proc; + + /* Add description of valid object pointers */ + GC_add_map_entry(sz); + hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz]; + + /* Clear mark bits */ + GC_clear_hdr_marks(hhdr); } /* @@ -134,31 +97,10 @@ int kind; hhdr = HDR(hbp); if( prevhbp == GC_savhbp && !first_time) { - /* no sufficiently big blocks on free list, */ - /* let thishbp --> a newly-allocated block, */ - /* free it (to merge into existing block */ - /* list) and start the search again, this */ - /* time with guaranteed success. */ - word size_to_get = size_needed + GC_hincr * HBLKSIZE; - - if (! GC_expand_hp_inner(divHBLKSZ(size_to_get))) { - if (! GC_expand_hp_inner(divHBLKSZ((word)size_needed))) - { - /* GC_printf("Out of Memory! Giving up ...\n"); */ - /* There are other things we could try. It */ - /* would probably be reasonable to clear */ - /* black lists at tthis point. */ - return(0); - } else { - WARN("Out of Memory! Trying to continue ...\n"); - GC_gcollect_inner(TRUE); - } - } - update_GC_hincr; - return (GC_allochblk(sz, kind)); + return(0); } - first_time = 0; + first_time = FALSE; if( hbp == 0 ) continue; @@ -205,7 +147,30 @@ int kind; phdr = hhdr; hbp = thishbp; hhdr = thishdr; - } + } else if (size_avail == 0 + && size_needed == HBLKSIZE + && prevhbp != 0) { + static unsigned count = 0; + + /* The block is completely blacklisted. We need */ + /* to drop some such blocks, since otherwise we spend */ + /* all our time traversing them if pointerfree */ + /* blocks are unpopular. */ + /* A dropped block will be reconsidered at next GC. */ + if ((++count & 3) == 0) { + /* Allocate and drop the block */ + phdr -> hb_next = hhdr -> hb_next; + GC_install_counts(hbp, hhdr->hb_sz); + setup_header(hhdr, + BYTES_TO_WORDS(hhdr->hb_sz - HDR_BYTES), + PTRFREE); + if (GC_savhbp == hbp) GC_savhbp = prevhbp; + /* Restore hbp to point at free block */ + hbp = prevhbp; + hhdr = phdr; + if (hbp == GC_savhbp) first_time = TRUE; + } + } } if( size_avail >= size_needed ) { /* found a big enough block */ @@ -237,34 +202,16 @@ int kind; } } - /* set size and mask field of *thishbp correctly */ - thishdr->hb_sz = sz; - /* Clear block if necessary */ if (sz > MAXOBJSZ && GC_obj_kinds[kind].ok_init) { bzero((char *)thishbp + HDR_BYTES, (int)(size_needed - HDR_BYTES)); } - - /* Clear mark bits */ - { - register word *p = (word *)(&(thishdr -> hb_marks[0])); - register word * plim = - (word *)(&(thishdr -> hb_marks[MARK_BITS_SZ])); - while (p < plim) { - *p++ = 0; - } - } - - /* Add it to data structure describing hblks in use */ - GC_install_counts(thishbp, (word)size_needed); - - /* Add description of valid object pointers. */ - GC_add_map_entry(sz); - thishdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz]; + + /* Set up header */ + setup_header(thishdr, sz, kind); - /* Set kind related fields */ - thishdr -> hb_obj_kind = kind; - thishdr -> hb_mark_proc = GC_obj_kinds[kind].ok_mark_proc; + /* Add it to map of valid blocks */ + GC_install_counts(thishbp, (word)size_needed); return( thishbp ); } @@ -311,10 +258,10 @@ register signed_word size; /* Check for duplicate deallocation in the easy case */ if (hbp != 0 && (ptr_t)p + size > (ptr_t)hbp || prevhbp != 0 && (ptr_t)prevhbp + prevhdr->hb_sz > (ptr_t)p) { - GC_printf("Duplicate large block deallocation of 0x%lx\n", - (unsigned long) p); - GC_printf("Surrounding free blocks are 0x%lx and 0x%lx\n", - (unsigned long) prevhbp, (unsigned long) hbp); + GC_printf1("Duplicate large block deallocation of 0x%lx\n", + (unsigned long) p); + GC_printf2("Surrounding free blocks are 0x%lx and 0x%lx\n", + (unsigned long) prevhbp, (unsigned long) hbp); } /* Coalesce with successor, if possible */ diff --git a/black_list.c b/black_list.c index 9471dc52..ba54f892 100644 --- a/black_list.c +++ b/black_list.c @@ -114,8 +114,8 @@ word p; if (HDR(p) == 0 || get_bl_entry_from_index(GC_new_normal_bl, index)) { # ifdef PRINTBLACKLIST if (!get_bl_entry_from_index(GC_incomplete_normal_bl, index)) { - GC_printf("Black listing (normal) 0x%lx\n", - (unsigned long) p); + GC_printf1("Black listing (normal) 0x%lx\n", + (unsigned long) p); } # endif set_bl_entry_from_index(GC_incomplete_normal_bl, index); @@ -134,8 +134,8 @@ word p; if (HDR(p) == 0 || get_bl_entry_from_index(GC_new_stack_bl, index)) { # ifdef PRINTBLACKLIST if (!get_bl_entry_from_index(GC_incomplete_stack_bl, index)) { - GC_printf("Black listing (stack) 0x%lx\n", - (unsigned long)p); + GC_printf1("Black listing (stack) 0x%lx\n", + (unsigned long)p); } # endif set_bl_entry_from_index(GC_incomplete_stack_bl, index); diff --git a/config.h b/config.h new file mode 100644 index 00000000..48464e43 --- /dev/null +++ b/config.h @@ -0,0 +1,375 @@ +#ifndef CONFIG_H + +# define CONFIG_H + +/* Machine dependent parameters. Some tuning parameters can be found */ +/* near the top of gc_private.h. */ + +/* Machine specific parts contributed by various people. See README file. */ + +/* Determine the machine type: */ +# if defined(sun) && defined(mc68000) +# define M68K +# define SUNOS +# define mach_type_known +# endif +# if defined(hp9000s300) +# define M68K +# define HP +# define mach_type_known +# endif +# if defined(vax) +# define VAX +# ifdef ultrix +# define ULTRIX +# else +# define BSD +# endif +# define mach_type_known +# endif +# if defined(mips) +# define MIPS +# ifdef ultrix +# define ULTRIX +# else +# define RISCOS +# endif +# define mach_type_known +# endif +# if defined(sequent) && defined(i386) +# define I386 +# define SEQUENT +# define mach_type_known +# endif +# if defined(sun) && defined(i386) +# define I386 +# define SUNOS5 +# define mach_type_known +# endif +# if defined(__OS2__) && defined(__32BIT__) +# define I386 +# define OS2 +# define mach_type_known +# endif +# if defined(ibm032) +# define RT +# define mach_type_known +# endif +# if defined(sun) && defined(sparc) +# define SPARC + /* Test for SunOS 5.x */ +# include +# ifdef ECHRNG +# define SUNOS5 +# else +# define SUNOS4 +# endif +# define mach_type_known +# endif +# if defined(_IBMR2) +# define IBMRS6000 +# define mach_type_known +# endif +# if defined(SCO) +# define I386 +# define SCO +# define mach_type_known +/* --> incompletely implemented */ +# endif +# if defined(_AUX_SOURCE) +# define M68K +# define SYSV +# define mach_type_known +# endif +# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) +# define HP_PA +# define mach_type_known +# endif +# if defined(linux) && defined(i386) +# define I386 +# define LINUX +# define mach_type_known +# endif + +/* Feel free to add more clauses here */ + +/* Or manually define the machine type here. A machine type is */ +/* characterized by the architecture. Some */ +/* machine types are further subdivided by OS. */ +/* the macros ULTRIX, RISCOS, and BSD to distinguish. */ +/* Note that SGI IRIX is treated identically to RISCOS. */ +/* SYSV on an M68K actually means A/UX. */ +/* The distinction in these cases is usually the stack starting address */ +# ifndef mach_type_known + --> unknown machine type +# endif + /* Mapping is: M68K ==> Motorola 680X0 */ + /* (SUNOS, HP, and SYSV (A/UX) variants)*/ + /* M68K_HP ==> HP9000/300 */ + /* M68K_SYSV ==> A/UX, maybe others */ + /* I386 ==> Intel 386 */ + /* (SEQUENT, OS2, SCO, LINUX variants) */ + /* SCO is incomplete. */ + /* NS32K ==> Encore Multimax */ + /* MIPS ==> R2000 or R3000 */ + /* (RISCOS, ULTRIX variants) */ + /* VAX ==> DEC VAX */ + /* (BSD, ULTRIX variants) */ + /* RS6000 ==> IBM RS/6000 AIX3.1 */ + /* RT ==> IBM PC/RT */ + /* HP_PA ==> HP9000/700 & /800 */ + /* HP/UX */ + /* SPARC ==> SPARC under SunOS */ + /* (SUNOS4, SUNOS5 variants) + + +/* + * For each architecture and OS, the following need to be defined: + * + * CPP_WORD_SZ is a simple integer constant representing the word size. + * in bits. We assume byte addressibility, where a byte has 8 bits. + * We also assume CPP_WORD_SZ is either 32 or 64. Only 32 is completely + * implemented. (We care about the length of pointers, not hardware + * bus widths. Thus a 64 bit processor with a C compiler that uses + * 32 bit pointers should use CPP_WORD_SZ of 32, not 64.) + * + * MACH_TYPE is a string representation of the machine type. + * OS_TYPE is analogous for the OS. + * + * ALIGNMENT is the largest N, such that + * all pointer are guaranteed to be aligned on N byte boundaries. + * defining it to be 1 will always work, but perform poorly. + * + * DATASTART is the beginning of the data segment. + * On UNIX systems, the collector will scan the area between DATASTART + * and &end for root pointers. + * + * STACKBOTTOM is the cool end of the stack, which is usually the + * highest address in the stack. + * Under PCR or OS/2, we have other ways of finding thread stacks. + * For each machine, the following should: + * 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and + * 2) define exactly one of + * STACKBOTTOM (should be defined to be an expression) + * HEURISTIC1 + * HEURISTIC2 + * If either of the last two macros are defined, then STACKBOTTOM is computed + * during collector startup using one of the following two heuristics: + * HEURISTIC1: Take an address inside GC_init's frame, and round it up to + * the next multiple of 16 MB. + * HEURISTIC2: Take an address inside GC_init's frame, increment it repeatedly + * in small steps (decrement if STACK_GROWS_UP), and read the value + * at each location. Remember the value when the first + * Segmentation violation or Bus error is signalled. Round that + * to the nearest plausible page boundary, and use that instead + * of STACKBOTTOM. + * + * If no expression for STACKBOTTOM can be found, and neither of the above + * heuristics are usable, the collector can still be used with all of the above + * undefined, provided one of the following is done: + * 1) GC_mark_roots can be changed to somehow mark from the correct stack(s) + * without reference to STACKBOTTOM. This is appropriate for use in + * conjunction with thread packages, since there will be multiple stacks. + * (Allocating thread stacks in the heap, and treating them as ordinary + * heap data objects is also possible as a last resort. However, this is + * likely to introduce significant amounts of excess storage retention + * unless the dead parts of the thread stacks are periodically cleared.) + * 2) Client code may set GC_stackbottom before calling any GC_ routines. + * If the author of the client code controls the main program, this is + * easily accomplished by introducing a new main program, setting + * GC_stackbottom to the address of a local variable, and then calling + * the original main program. The new main program would read something + * like: + * + * # include "gc_private.h" + * + * main(argc, argv, envp) + * int argc; + * char **argv, **envp; + * { + * int dummy; + * + * GC_stackbottom = (ptr_t)(&dummy); + * return(real_main(argc, argv, envp)); + * } + */ + + +# ifdef M68K +# define MACH_TYPE "M68K" +# define ALIGNMENT 2 +# ifdef SUNOS +# define OS_TYPE "SUNOS" + extern char etext; +# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1ffff) & ~0x1ffff)) +# define HEURISTIC1 /* differs */ +# endif +# ifdef HP +# define OS_TYPE "HP" + extern char etext; +# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) +# define STACKBOTTOM ((ptr_t) 0xffeffffc) + /* empirically determined. seems to work. */ +# endif +# ifdef SYSV +# define OS_TYPE "SYSV" + extern etext; +# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \ + & ~0x3fffff) \ + +((word)&etext & 0x1fff)) + /* This only works for shared-text binaries with magic number 0413. + The other sorts of SysV binaries put the data at the end of the text, + in which case the default of &etext would work. Unfortunately, + handling both would require having the magic-number available. + -- Parag + */ +# define STACKBOTTOM ((ptr_t)0xFFFFFFFE) + /* The stack starts at the top of memory, but */ + /* 0x0 cannot be used as setjump_test complains */ + /* that the stack direction is incorrect. Two */ + /* bytes down from 0x0 should be safe enough. */ + /* --Parag */ +# endif +# endif + +# ifdef VAX +# define MACH_TYPE "VAX" +# define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */ + extern char etext; +# define DATASTART ((ptr_t)(&etext)) +# ifdef BSD +# define OS_TYPE "BSD" +# define HEURISTIC1 + /* HEURISTIC2 may be OK, but it's hard to test. */ +# endif +# ifdef ULTRIX +# define OS_TYPE "ULTRIX" +# define STACKBOTTOM ((ptr_t) 0x7fffc800) +# endif +# endif + +# ifdef RT +# define MACH_TYPE "RT" +# define ALIGNMENT 4 +# define DATASTART ((ptr_t) 0x10000000) +# define STACKBOTTOM ((ptr_t) 0x1fffd800) +# endif + +# ifdef SPARC +# define MACH_TYPE "SPARC" +# define ALIGNMENT 4 /* Required by hardware */ + extern int etext; +# ifdef SUNOS5 +# define OS_TYPE "SUNOS5" +# define DATASTART ((ptr_t)((((word) (&etext)) + 0x10003) & ~0x3)) + /* Experimentally determined. */ + /* Inconsistent with man a.out, which appears */ + /* to be wrong. */ +# endif +# ifdef SUNOS4 +# define OS_TYPE "SUNOS4" +# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) + /* On very old SPARCs this is too conservative. */ +# endif +# define HEURISTIC1 +# endif + +# ifdef I386 +# define MACH_TYPE "I386" +# define ALIGNMENT 4 /* 32-bit compilers align pointers */ +# ifdef SEQUENT +# define OS_TYPE "SEQUENT" + extern int etext; +# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) +# define STACKBOTTOM ((ptr_t) 0x3ffff000) +# endif +# ifdef SUNOS5 +# define OS_TYPE "SUNOS5" + extern int etext; +# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1003) & ~0x3)) + extern int _start(); +# define STACKBOTTOM ((ptr_t)(&_start)) +# endif +# ifdef SCO +# define OS_TYPE "SCO" +# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \ + & ~0x3fffff) \ + +((word)&etext & 0xfff)) +# define STACKBOTTOM ((ptr_t) 0x7ffffffc) +# endif +# ifdef LINUX +# define OS_TYPE "LINUX" + extern int etext; +# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) +# define STACKBOTTOM ((ptr_t)0xc0000000) +# endif +# ifdef OS2 +# define OS_TYPE "OS2" +# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \ + & ~0x3fffff) \ + +((word)&etext & 0xfff)) + /* STACKBOTTOM is handled specially in GC_init_inner. */ + /* OS2 actually has the right system call! */ +# endif +# endif + +# ifdef NS32K +# define MACH_TYPE "NS32K" +# define ALIGNMENT 4 + extern char **environ; +# define DATASTART ((ptr_t)(&environ)) + /* hideous kludge: environ is the first */ + /* word in crt0.o, and delimits the start */ + /* of the data segment, no matter which */ + /* ld options were passed through. */ +# define STACKBOTTOM ((ptr_t) 0xfffff000) /* for Encore */ +# endif + +# ifdef MIPS +# define MACH_TYPE "MIPS" +# define ALIGNMENT 4 /* Required by hardware */ +# define DATASTART 0x10000000 + /* Could probably be slightly higher since */ + /* startup code allocates lots of junk */ +# define HEURISTIC2 +# endif + +# ifdef RS6000 +# define MACH_TYPE "RS6000" +# define ALIGNMENT 4 +# define DATASTART ((ptr_t)0x20000000) +# define STACKBOTTOM ((ptr_t)0x2ff80000) +# endif + +# ifdef HP_PA +# define MACH_TYPE "HP_PA" +# define ALIGNMENT 4 + extern int __data_start; +# define DATASTART ((ptr_t)(&__data_start)) +# define HEURISTIC2 +# define STACK_GROWS_UP +# endif + +# ifndef STACK_GROWS_UP +# define STACK_GROWS_DOWN +# endif + +# ifndef CPP_WORDSZ +# define CPP_WORDSZ 32 +# endif + +# ifndef OS_TYPE +# define OS_TYPE "" +# endif + +# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 + -> bad word size +# endif + +# ifdef PCR +# undef STACKBOTTOM +# undef HEURISTIC1 +# undef HEURISTIC2 +# endif + +# endif diff --git a/debug_malloc.c b/debug_malloc.c index f8b27d22..6bb61980 100644 --- a/debug_malloc.c +++ b/debug_malloc.c @@ -94,25 +94,25 @@ ptr_t p; { register oh * ohdr = (oh *)GC_base(p); - GC_err_printf("0x%lx (", (unsigned long)ohdr + sizeof(oh)); + GC_err_printf1("0x%lx (", (unsigned long)ohdr + sizeof(oh)); GC_err_puts(ohdr -> oh_string); - GC_err_printf(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int), - (unsigned long)(ohdr -> oh_sz)); + GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int), + (unsigned long)(ohdr -> oh_sz)); } void GC_print_smashed_obj(p, clobbered_addr) ptr_t p, clobbered_addr; { register oh * ohdr = (oh *)GC_base(p); - GC_err_printf("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr, - (unsigned long)p); + GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr, + (unsigned long)p); if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))) { - GC_err_printf(", appr. sz = %ld)\n", - BYTES_TO_WORDS(GC_size((ptr_t)ohdr))); + GC_err_printf1(", appr. sz = %ld)\n", + BYTES_TO_WORDS(GC_size((ptr_t)ohdr))); } else { GC_err_puts(ohdr -> oh_string); - GC_err_printf(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int), - (unsigned long)(ohdr -> oh_sz)); + GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int), + (unsigned long)(ohdr -> oh_sz)); } } @@ -128,10 +128,10 @@ ptr_t p, clobbered_addr; extern_ptr_t result = GC_malloc(lb + DEBUG_BYTES); if (result == 0) { - GC_err_printf("GC_debug_malloc(%ld) returning NIL (", - (unsigned long) lb); + GC_err_printf1("GC_debug_malloc(%ld) returning NIL (", + (unsigned long) lb); GC_err_puts(s); - GC_err_printf(":%ld)\n", (unsigned long)i); + GC_err_printf1(":%ld)\n", (unsigned long)i); return(0); } if (!GC_debugging_started) { @@ -153,10 +153,10 @@ ptr_t p, clobbered_addr; extern_ptr_t result = GC_malloc_atomic(lb + DEBUG_BYTES); if (result == 0) { - GC_err_printf("GC_debug_malloc_atomic(%ld) returning NIL (", + GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (", (unsigned long) lb); GC_err_puts(s); - GC_err_printf(":%ld)\n", (unsigned long)i); + GC_err_printf1(":%ld)\n", (unsigned long)i); return(0); } if (!GC_debugging_started) { @@ -176,17 +176,18 @@ ptr_t p, clobbered_addr; register ptr_t clobbered; if (base == 0) { - GC_err_printf("Attempt to free invalid pointer %lx\n", - (unsigned long)p); + GC_err_printf1("Attempt to free invalid pointer %lx\n", + (unsigned long)p); ABORT("free(invalid pointer)"); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { - GC_err_printf("GC_debug_free called on pointer %lx wo debugging info\n", + GC_err_printf1( + "GC_debug_free called on pointer %lx wo debugging info\n", (unsigned long)p); } else { clobbered = GC_check_annotated_obj((oh *)base); if (clobbered != 0) { - GC_err_printf("GC_debug_free: found smashed object at "); + GC_err_printf0("GC_debug_free: found smashed object at "); GC_print_smashed_obj(p, clobbered); } } @@ -210,19 +211,19 @@ ptr_t p, clobbered_addr; register size_t old_sz; if (base == 0) { - GC_err_printf( + GC_err_printf1( "Attempt to free invalid pointer %lx\n", (unsigned long)p); ABORT("realloc(invalid pointer)"); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { - GC_err_printf( + GC_err_printf1( "GC_debug_realloc called on pointer %lx wo debugging info\n", (unsigned long)p); return(GC_realloc(p, lb)); } clobbered = GC_check_annotated_obj((oh *)base); if (clobbered != 0) { - GC_err_printf("GC_debug_realloc: found smashed object at "); + GC_err_printf0("GC_debug_realloc: found smashed object at "); GC_print_smashed_obj(p, clobbered); } old_sz = ((oh *)base) -> oh_sz; @@ -255,7 +256,7 @@ word dummy; ptr_t clobbered = GC_check_annotated_obj((oh *)p); if (clobbered != 0) { - GC_err_printf( + GC_err_printf0( "GC_check_heap_block: found smashed object at "); GC_print_smashed_obj((ptr_t)p, clobbered); } @@ -305,4 +306,5 @@ struct closure { register struct closure * cl = (struct closure *) data; (*(cl -> cl_fn))((extern_ptr_t)((char *)obj + sizeof(oh)), cl -> cl_data); -} \ No newline at end of file +} + diff --git a/dynamic_load.c b/dynamic_load.c index 80eda3a9..c5e111e1 100644 --- a/dynamic_load.c +++ b/dynamic_load.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1991,1992 by Xerox Corporation. All rights reserved. + * Copyright (c) 1991-1993 by Xerox Corporation. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -9,84 +9,134 @@ * Author: Bill Janssen * Modified by: Hans Boehm */ + +/* + * This is incredibly OS specific code for tracking down data sections in + * dynamic libraries. There appears to be no way of doing this quickly + * without groveling through undocumented data structures. We would argue + * that this is a bug in the design of the dlopen interface. THIS CODE + * MAY BREAK IN FUTURE OS RELEASES. If this matters to you, don't hesitate + * to let your vendor know ... + */ #include "gc_private.h" #ifdef DYNAMIC_LOADING -#if !defined(M68K_SUN) && !defined(SPARC) +#if !(defined(M68K) && defined(SUNOS)) && !defined(SPARC) --> We only know how to find data segments of dynamic libraries under SunOS 4.X #endif -#include + #include -#include -#include -#include -#include +#if defined SUNOS5 +# include +# include +# include +#else +# include +# include +# include + /* struct link_map field overrides */ +# define l_next lm_next +# define l_addr lm_addr +# define l_name lm_name +# endif + -extern struct link_dynamic _DYNAMIC; +#ifdef SUNOS5 -void GC_setup_dynamic_loading() +static struct link_map * +GC_FirstDLOpenedLinkMap() { - struct link_map *lm; - struct exec *e; - - if (&_DYNAMIC == 0) { - /* No dynamic libraries. Furthermore, the rest of this would */ - /* segment fault. */ - return; - } - for (lm = _DYNAMIC.ld_un.ld_1->ld_loaded; - lm != (struct link_map *) 0; lm = lm->lm_next) - { - 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))); + extern Elf32_Dyn _DYNAMIC; + Elf32_Dyn *dp; + struct r_debug *r; + static struct link_map * cachedResult = 0; + + if( &_DYNAMIC == 0) { + return(0); + } + if( cachedResult == 0 ) { + int tag; + for( dp = ((Elf32_Dyn *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) { + if( tag == DT_DEBUG ) { + struct link_map *lm + = ((struct r_debug *)(dp->d_un.d_ptr))->r_map; + if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */ + break; + } + } } + return cachedResult; } -#ifdef DEFINE_DLOPEN -char *GC_dlopen (path, mode) - char *path; - int mode; +# endif + +# ifdef SUNOS4 + +static struct link_map * +GC_FirstDLOpenedLinkMap() { - char *etext, *end; - struct link_map *lm; - struct exec *e; - char *handle; + extern struct link_dynamic _DYNAMIC; - handle = dlopen(path, mode); - if (handle == NULL) - { - fprintf (stderr, - "GC_sun_dlopen: dlopen(%s, %d) failed: %s.\n", - path, mode, dlerror()); - return (NULL); + if( &_DYNAMIC == 0) { + return(0); } + return(_DYNAMIC.ld_un.ld_1->ld_loaded); +} - for (lm = _DYNAMIC.ld_un.ld_1->ld_loaded; - lm != (struct link_map *) 0; lm = lm->lm_next) - { - if (strcmp(path, lm->lm_name) == 0) - { - e = (struct exec *) lm->lm_addr; - etext = (void *) (N_DATOFF(*e) + lm->lm_addr); - end = (void *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr); - GC_add_roots (etext, end); - break; - } - } - if (lm == (struct link_map *) 0) +# endif + +/* Add dynamic library data sections to the root set. */ +# if !defined(PCR) && defined(THREADS) + --> fix mutual exclusion with dlopen +# endif +void GC_register_dynamic_libraries() +{ + struct link_map *lm = GC_FirstDLOpenedLinkMap(); + + + for (lm = GC_FirstDLOpenedLinkMap(); + lm != (struct link_map *) 0; lm = lm->l_next) { - fprintf (stderr, - "GC_sun_dlopen: couldn't find \"%s\" in _DYNAMIC link list.\n", - path); - dlclose(handle); - return (NULL); +# ifdef SUNOS4 + struct exec *e; + + 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))); +# endif +# ifdef SUNOS5 + Elf32_Ehdr * e; + Elf32_Phdr * p; + unsigned long offset; + char * start; + register int i; + + e = (Elf32_Ehdr *) lm->l_addr; + p = ((Elf32_Phdr *)(((char *)(e)) + e->e_phoff)); + offset = ((unsigned long)(lm->l_addr)); + for( i = 0; i < e->e_phnum; ((i++),(p++)) ) { + switch( p->p_type ) { + case PT_LOAD: + { + if( !(p->p_flags & PF_W) ) break; + start = ((char *)(p->p_vaddr)) + offset; + GC_add_roots_inner( + start, + start + p->p_memsz + ); + } + break; + default: + break; + } + } +# endif } - else - return (handle); } -#endif + #else +void GC_register_dynamic_libraries(){} + int GC_no_dynamic_loading; #endif diff --git a/gc.h b/gc.h index e090522d..7814f46c 100644 --- a/gc.h +++ b/gc.h @@ -44,7 +44,7 @@ extern int GC_dont_expand; extern word GC_non_gc_bytes; /* Bytes not considered candidates for collection. */ - + /* Used only to control scheduling of collections. */ extern word GC_free_space_divisor; /* We try to make sure that we allocate at */ diff --git a/gc_private.h b/gc_private.h index 2ef44503..1e09370f 100644 --- a/gc_private.h +++ b/gc_private.h @@ -10,7 +10,6 @@ * provided the above notices are retained on all copies. */ -/* Machine specific parts contributed by various people. See README file. */ # ifndef GC_PRIVATE_H # define GC_PRIVATE_H @@ -19,6 +18,10 @@ # include "gc.h" # endif +# ifndef CONFIG_H +# include "config.h" +# endif + # ifndef HEADERS_H # include "gc_headers.h" # endif @@ -41,6 +44,10 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ typedef char * extern_ptr_t; #endif +# ifndef OS2 +# include +# endif + /*********************************/ /* */ /* Definitions for conservative */ @@ -54,113 +61,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ /* */ /*********************************/ -# if defined(sun) && defined(mc68000) -# define M68K_SUN -# define mach_type_known -# endif -# if defined(hp9000s300) -# define M68K_HP -# define mach_type_known -# endif -# if defined(vax) -# define VAX -# ifdef ultrix -# define ULTRIX -# else -# define BSD -# endif -# define mach_type_known -# endif -# if defined(mips) -# define MIPS -# ifdef ultrix -# define ULTRIX -# else -# define RISCOS -# endif -# define mach_type_known -# endif -# if defined(sequent) && defined(i386) -# define I386 -# define SEQUENT -# define mach_type_known -# endif -# if defined(__OS2__) && defined(__32BIT__) -# define I386 -# define OS2 -# define mach_type_known -# endif -# if defined(ibm032) -# define RT -# define mach_type_known -# endif -# if defined(sun) && defined(sparc) -# define SPARC -# define mach_type_known -# endif -# if defined(_IBMR2) -# define IBMRS6000 -# define mach_type_known -# endif -# if defined(SCO) -# define I386 -# define SCO -# define mach_type_known -/* --> incompletely implemented */ -# endif -# if defined(_AUX_SOURCE) -# define M68K_SYSV -# define mach_type_known -# endif -# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) -# define HP_PA -# define mach_type_known -# endif -# if defined(linux) && defined(i386) -# define I386 -# define LINUX -# define mach_type_known -# endif - -# ifndef OS2 -# include -# endif - -/* Feel free to add more clauses here */ - -/* Or manually define the machine type here. A machine type is */ -/* characterized by the architecture and assembler syntax. Some */ -/* machine types are further subdivided by OS. In that case, we use */ -/* the macros ULTRIX, RISCOS, and BSD to distinguish. */ -/* Note that SGI IRIX is treated identically to RISCOS. */ -/* The distinction in these cases is usually the stack starting address */ -# ifndef mach_type_known -# define M68K_SUN /* Guess "Sun" */ - /* Mapping is: M68K_SUN ==> Sun3 assembler */ - /* M68K_HP ==> HP9000/300 */ - /* M68K_SYSV ==> A/UX, maybe others */ - /* I386 ==> Intel 386 */ - /* (SEQUENT, OS2, SCO, LINUX variants) */ - /* SCO is incomplete. */ - /* NS32K ==> Encore Multimax */ - /* MIPS ==> R2000 or R3000 */ - /* (RISCOS, ULTRIX variants) */ - /* VAX ==> DEC VAX */ - /* (BSD, ULTRIX variants) */ - /* RS6000 ==> IBM RS/6000 AIX3.1 */ - /* RT ==> IBM PC/RT */ - /* HP_PA ==> HP9000/700 & /800 */ - /* HP/UX */ - /* SPARC ==> SPARC under SunOS */ -# endif - -# ifdef SPARC - /* Test for SunOS 5.x */ -# include -# ifdef ECHRNG -# define SUNOS5 -# endif -# endif #define ALL_INTERIOR_POINTERS /* Forces all pointers into the interior of an */ @@ -231,9 +131,11 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ /* apparently required by SPARC architecture. */ #endif -#if defined(SPARC) || defined(M68K_SUN) -# if !defined(PCR) && !defined(SUNOS5) +#if defined(SPARC) || defined(M68K) && defined(SUNOS) +# if !defined(PCR) # define DYNAMIC_LOADING /* Search dynamic libraries for roots. */ +# else + /* PCR handles any dynamic loading whether with dlopen or otherwise */ # endif #endif @@ -253,261 +155,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ # define MERGE_SIZES # endif -#if defined(M68K_SUN) || defined(M68K_SYSV) -# define ALIGNMENT 2 /* Pointers are aligned on 2 byte boundaries */ - /* by the Sun C compiler. */ -#else -# ifdef VAX -# define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */ -# else -# ifdef RT -# define ALIGNMENT 4 -# else -# ifdef SPARC -# define ALIGNMENT 4 -# else -# ifdef I386 -# define ALIGNMENT 4 /* 32-bit compilers align pointers */ -# else -# ifdef NS32K -# define ALIGNMENT 4 /* Pointers are aligned on NS32K */ -# else -# ifdef MIPS -# define ALIGNMENT 4 /* MIPS hardware requires pointer */ - /* alignment */ -# else -# ifdef M68K_HP -# define ALIGNMENT 2 /* 2 byte alignment inside struct/union, */ - /* 4 bytes elsewhere */ -# else -# ifdef IBMRS6000 -# define ALIGNMENT 4 -# else -# ifdef HP_PA -# define ALIGNMENT 4 -# else - --> specify alignment <-- -# endif -# endif -# endif -# endif -# endif -# endif -# endif -# endif -# endif -# endif - -/* - * STACKBOTTOM is the cool end of the stack, which is usually the - * highest address in the stack. - * Under PCR or OS/2, we have other ways of finding thread stacks. - * For each machine, the following should: - * 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and - * 2) define exactly one of - * STACKBOTTOM (should be defined to be an expression) - * HEURISTIC1 - * HEURISTIC2 - * If either of the last two macros are defined, then STACKBOTTOM is computed - * during collector startup using one of the following two heuristics: - * HEURISTIC1: Take an address inside GC_init's frame, and round it up to - * the next multiple of 16 MB. - * HEURISTIC2: Take an address inside GC_init's frame, increment it repeatedly - * in small steps (decrement if STACK_GROWS_UP), and read the value - * at each location. Remember the value when the first - * Segmentation violation or Bus error is signalled. Round that - * to the nearest plausible page boundary, and use that instead - * of STACKBOTTOM. - * - * If no expression for STACKBOTTOM can be found, and neither of the above - * heuristics are usable, the collector can still be used with all of the above - * undefined, provided one of the following is done: - * 1) GC_mark_roots can be changed to somehow mark from the correct stack(s) - * without reference to STACKBOTTOM. This is appropriate for use in - * conjunction with thread packages, since there will be multiple stacks. - * (Allocating thread stacks in the heap, and treating them as ordinary - * heap data objects is also possible as a last resort. However, this is - * likely to introduce significant amounts of excess storage retention - * unless the dead parts of the thread stacks are periodically cleared.) - * 2) Client code may set GC_stackbottom before calling any GC_ routines. - * If the author of the client code controls the main program, this is - * easily accomplished by introducing a new main program, setting - * GC_stackbottom to the address of a local variable, and then calling - * the original main program. The new main program would read something - * like: - * - * # include "gc_private.h" - * - * main(argc, argv, envp) - * int argc; - * char **argv, **envp; - * { - * int dummy; - * - * GC_stackbottom = (ptr_t)(&dummy); - * return(real_main(argc, argv, envp)); - * } - */ -#ifndef PCR -# ifdef RT -# define STACKBOTTOM ((ptr_t) 0x1fffd800) -# else -# ifdef I386 -# ifdef SEQUENT -# define STACKBOTTOM ((ptr_t) 0x3ffff000) /* For Sequent */ -# else -# ifdef SCO -# define STACKBOTTOM ((ptr_t) 0x7ffffffc) -# else -# ifdef LINUX -# define STACKBOTTOM ((ptr_t)0xc0000000) -# else -# ifdef OS2 - /* This is handled specially in GC_init_inner. */ - /* OS2 actually has the right system call! */ -# else - --> Your OS isnt supported yet -# endif -# endif -# endif -# endif -# else -# ifdef NS32K -# define STACKBOTTOM ((ptr_t) 0xfffff000) /* for Encore */ -# else -# ifdef M68K_SYSV -# define STACKBOTTOM ((ptr_t)0xFFFFFFFE) - /* The stack starts at the top of memory, but */ - /* 0x0 cannot be used as setjump_test complains */ - /* that the stack direction is incorrect. Two */ - /* bytes down from 0x0 should be safe enough. */ - /* --Parag */ -# else -# ifdef M68K_HP -# define STACKBOTTOM ((ptr_t) 0xffeffffc) - /* empirically determined. seems to work. */ -# else -# ifdef IBMRS6000 -# define STACKBOTTOM ((ptr_t) 0x2ff80000) -# else -# if defined(VAX) && defined(ULTRIX) -# ifdef ULTRIX -# define STACKBOTTOM ((ptr_t) 0x7fffc800) -# else -# define HEURISTIC1 - /* HEURISTIC2 may be OK, but it's hard to test. */ -# endif -# else - /* Sun systems, HP PA systems, and DEC MIPS systems have */ - /* STACKBOTTOM values that differ between machines that */ - /* are intended to be object code compatible. */ -# if defined(SPARC) || defined(M68K_SUN) -# define HEURISTIC1 -# else -# ifdef HP_PA -# define STACK_GROWS_UP -# endif -# define HEURISTIC2 -# endif -# endif -# endif -# endif -# endif -# endif -# endif -# endif -#endif /* PCR */ - - -# ifndef STACK_GROWS_UP -# define STACK_GROWS_DOWN -# endif - -/* Start of data segment for each of the above systems. Note that the */ -/* default case works only for contiguous text and data, such as on a */ -/* Vax. */ -# ifdef M68K_SUN - extern char etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1ffff) & ~0x1ffff)) -# else -# ifdef RT -# define DATASTART ((ptr_t) 0x10000000) -# else -# if (defined(I386) && (defined(SEQUENT)||defined(LINUX))) || defined(SPARC) - extern int etext; -# ifdef SUNOS5 -# define DATASTART ((ptr_t)((((word) (&etext)) + 0x10003) & ~0x3)) - /* Experimentally determined. */ - /* Inconsistent with man a.out, which appears */ - /* to be wrong. */ -# else -# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) - /* On very old SPARCs this is too conservative. */ -# endif -# else -# ifdef NS32K - extern char **environ; -# define DATASTART ((ptr_t)(&environ)) - /* hideous kludge: environ is the first */ - /* word in crt0.o, and delimits the start */ - /* of the data segment, no matter which */ - /* ld options were passed through. */ -# else -# ifdef MIPS -# define DATASTART 0x10000000 - /* Could probably be slightly higher since */ - /* startup code allocates lots of junk */ -# else -# ifdef M68K_HP - extern char etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) -# else -# ifdef IBMRS6000 -# define DATASTART ((ptr_t)0x20000000) -# else -# ifdef I386 -# ifdef SCO -# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \ - & ~0x3fffff) \ - +((word)&etext & 0xfff)) -# else -# ifdef OS2 -# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \ - & ~0x3fffff) \ - +((word)&etext & 0xfff)) -# else - --> Your OS not supported yet -# endif -# endif -# else -# ifdef M68K_SYSV - /* This only works for shared-text binaries with magic number 0413. - The other sorts of SysV binaries put the data at the end of the text, - in which case the default of &etext would work. Unfortunately, - handling both would require having the magic-number available. - -- Parag - */ - extern etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \ - & ~0x3fffff) \ - +((word)&etext & 0x1fff)) -# else -# ifdef HP_PA - extern int __data_start; -# define DATASTART ((ptr_t)(&__data_start)) -# else - extern char etext; -# define DATASTART ((ptr_t)(&etext)) -# endif -# endif -# endif -# endif -# endif -# endif -# endif -# endif -# endif -# endif # define HINCR 16 /* Initial heap increment, in blocks of 4K */ # define MAXHINCR 512 /* Maximum heap increment, in blocks */ @@ -549,7 +196,17 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ (1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC)) /* We use bzero and bcopy internally. They may not be available. */ -# ifdef OS2 +# if defined(SPARC) && defined(SUNOS4) +# define BCOPY_EXISTS +# endif +# if defined(M68K) && defined(SUNOS) +# define BCOPY_EXISTS +# endif +# if defined(VAX) +# define BCOPY_EXISTS +# endif + +# ifndef BCOPY_EXISTS # include # define bcopy(x,y,n) memcpy(y,x,n) # define bzero(x,n) memset(x, 0, n) @@ -674,7 +331,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ # endif /* Print warning message, e.g. almost out of memory. */ -# define WARN(s) GC_printf(s) +# define WARN(s) GC_printf0(s) /*********************************/ /* */ @@ -682,22 +339,25 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ /* */ /*********************************/ -#define WORDS_TO_BYTES(x) ((x)<<2) -#define BYTES_TO_WORDS(x) ((x)>>2) +#if CPP_WORDSZ == 32 +# define WORDS_TO_BYTES(x) ((x)<<2) +# define BYTES_TO_WORDS(x) ((x)>>2) +# define LOGWL ((word)5) /* log[2] of CPP_WORDSZ */ +# define modWORDSZ(n) ((n) & 0x1f) /* n mod size of word */ +#endif + +#if CPP_WORDSZ == 64 +# define WORDS_TO_BYTES(x) ((x)<<3) +# define BYTES_TO_WORDS(x) ((x)>>3) +# define LOGWL ((word)6) /* log[2] of CPP_WORDSZ */ +# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */ +#endif -#define CPP_WORDSZ 32 #define WORDSZ ((word)CPP_WORDSZ) -#define LOGWL ((word)5) /* log[2] of above */ +#define SIGNB ((word)1 << (WORDSZ-1)) #define BYTES_PER_WORD ((word)(sizeof (word))) -#define ONES 0xffffffff -#define MSBYTE 0xff000000 -#define SIGNB 0x80000000 -#define MAXSHORT 0x7fff -#define modHALFWORDSZ(n) ((n) & 0xf) /* mod n by size of half word */ -#define divHALFWORDSZ(n) ((n) >> 4) /* divide n by size of half word */ -#define modWORDSZ(n) ((n) & 0x1f) /* mod n by size of word */ -#define divWORDSZ(n) ((n) >> 5) /* divide n by size of word */ -#define twice(n) ((n) << 1) /* double n */ +#define ONES ((word)(-1)) +#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */ /*********************/ /* */ @@ -841,6 +501,13 @@ struct _GC_arrays { # endif word _words_allocd; /* Number of words allocated during this collection cycle */ + word _non_gc_bytes_at_gc; + /* Number of explicitly managed bytes of storage */ + /* at last collection. */ + word _mem_freed; + /* Number of explicitly deallocated words of memory */ + /* since last collection. */ + ptr_t _objfreelist[MAXOBJSZ+1]; /* free list for objects */ # ifdef MERGE_SIZES @@ -913,6 +580,8 @@ extern struct _GC_arrays GC_arrays; # define GC_last_heap_addr GC_arrays._last_heap_addr # define GC_prev_heap_addr GC_arrays._prev_heap_addr # define GC_words_allocd GC_arrays._words_allocd +# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc +# define GC_mem_freed GC_arrays._mem_freed # define GC_heapsize GC_arrays._heapsize # define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc # ifdef GATHERSTATS @@ -1031,7 +700,10 @@ void GC_mark_all_stack(/*b,t*/); /* Mark from everything in a range, */ void GC_remark(); /* Mark from all marked objects. Used */ /* only if we had to drop something. */ void GC_tl_mark(/*p*/); /* Mark from a single root. */ +void GC_clear_hdr_marks(/* hhdr */); /* Clear the mark bits in a header */ void GC_add_roots_inner(); +void GC_register_dynamic_libraries(); + /* Add dynamic library data sections to the root set. */ /* Machine dependent startup routines */ ptr_t GC_get_stack_base(); @@ -1099,8 +771,16 @@ void GC_continue_reclaim(/*size, kind*/); /* kind, as long as possible, and */ /* as long as the corr. free list is */ /* empty. */ -void GC_gcollect_inner(); /* Collect; caller must have acquired */ +bool GC_gcollect_inner(/* force */); + /* Collect; caller must have acquired */ /* lock and disabled signals. */ + /* FALSE return indicates nothing was */ + /* done due to insufficient allocation. */ +void GC_collect_or_expand(/* needed_blocks */); + /* Collect or expand heap in an attempt */ + /* make the indicated number of free */ + /* blocks available. Should be called */ + /* until it succeeds or exits. */ void GC_init(); /* Initialize collector. */ ptr_t GC_generic_malloc(/* bytes, kind */); @@ -1147,16 +827,41 @@ void GC_check_heap(); /* debugging info are intact. Print */ /* descriptions of any that are not. */ -void GC_printf(/* format, ... */); +void GC_printf(/* format, a, b, c, d, e, f */); /* A version of printf that doesn't allocate, */ /* is restricted to long arguments, and */ /* (unfortunately) doesn't use varargs for */ /* portability. Restricted to 6 args and */ /* 1K total output length. */ /* (We use sprintf. Hopefully that doesn't */ - /* allocate for long arguments. */ -void GC_err_printf(/* format, ... */); + /* allocate for long arguments.) */ +# define GC_printf0(f) GC_printf(f, 0l, 0l, 0l, 0l, 0l, 0l) +# define GC_printf1(f,a) GC_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l) +# define GC_printf2(f,a,b) GC_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l) +# define GC_printf3(f,a,b,c) GC_printf(f, (long)a, (long)b, (long)c, 0l, 0l, 0l) +# define GC_printf4(f,a,b,c,d) GC_printf(f, (long)a, (long)b, (long)c, \ + (long)d, 0l, 0l) +# define GC_printf5(f,a,b,c,d,e) GC_printf(f, (long)a, (long)b, (long)c, \ + (long)d, (long)e, 0l) +# define GC_printf6(f,a,b,c,d,e,g) GC_printf(f, (long)a, (long)b, (long)c, \ + (long)d, (long)e, (long)g) + +void GC_err_printf(/* format, a, b, c, d, e, f */); +# define GC_err_printf0(f) GC_err_puts(f) +# define GC_err_printf1(f,a) GC_err_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l) +# define GC_err_printf2(f,a,b) GC_err_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l) +# define GC_err_printf3(f,a,b,c) GC_err_printf(f, (long)a, (long)b, (long)c, \ + 0l, 0l, 0l) +# define GC_err_printf4(f,a,b,c,d) GC_err_printf(f, (long)a, (long)b, \ + (long)c, (long)d, 0l, 0l) +# define GC_err_printf5(f,a,b,c,d,e) GC_err_printf(f, (long)a, (long)b, \ + (long)c, (long)d, \ + (long)e, 0l) +# define GC_err_printf6(f,a,b,c,d,e,g) GC_err_printf(f, (long)a, (long)b, \ + (long)c, (long)d, \ + (long)e, (long)g) /* Ditto, writes to stderr. */ + void GC_err_puts(/* char *s */); /* Write s to stderr, don't buffer, don't add */ /* newlines, don't ... */ diff --git a/headers.c b/headers.c index 3873ee8f..15fda415 100644 --- a/headers.c +++ b/headers.c @@ -73,10 +73,10 @@ register word bytes; scratch_free_ptr = (char *)GET_MEM(bytes_to_get); if (scratch_free_ptr == 0) { - GC_printf("Out of memory - trying to allocate less\n"); + GC_err_printf0("Out of memory - trying to allocate less\n"); result = (char *)GET_MEM(bytes); if (result == 0) { - GC_printf("Out of memory - giving up\n"); + GC_err_printf0("Out of memory - giving up\n"); } else { scratch_free_ptr -= bytes; return(result); diff --git a/if_mach.c b/if_mach.c new file mode 100644 index 00000000..7359a4f7 --- /dev/null +++ b/if_mach.c @@ -0,0 +1,22 @@ +/* Conditionally execute a command based on machine and OS from config.h */ +# include "config.h" +# include + +int main(argc, argv, envp) +int argc; +char ** argv; +char ** envp; +{ + if (argc < 4) goto Usage; + if (strcmp(MACH_TYPE, argv[1]) != 0) return(0); + if (strcmp(OS_TYPE, "") != 0 && strcmp(argv[2], "") != 0 + && strcmp(OS_TYPE, argv[2]) != 0) return(0); + execvp(argv[3], argv+3); + +Usage: + fprintf(stderr, "Usage: %s mach_type os_type command\n", argv[0]); + fprintf(stderr, "Currently mach_type = %s, os_type = %s\n", + MACH_TYPE, OS_TYPE); + return(1); +} + diff --git a/if_not_there.c b/if_not_there.c new file mode 100644 index 00000000..806eed62 --- /dev/null +++ b/if_not_there.c @@ -0,0 +1,24 @@ +/* Conditionally execute a command based if the file argv[1] doesn't exist */ +/* Except for execvp, we stick to ANSI C. */ +# include "config.h" +# include + +int main(argc, argv, envp) +int argc; +char ** argv; +char ** envp; +{ + FILE * f; + if (argc < 3) goto Usage; + if ((f = fopen(argv[1], "rb")) != 0 + || (f = fopen(argv[1], "r")) != 0) { + fclose(f); + return(0); + } + execvp(argv[2], argv+2); + +Usage: + fprintf(stderr, "Usage: %s file_name command\n", argv[0]); + return(1); +} + diff --git a/mach_dep.c b/mach_dep.c index 670579d8..8e3ac078 100644 --- a/mach_dep.c +++ b/mach_dep.c @@ -27,8 +27,8 @@ GC_mark_regs() asm("pushl r7"); asm("calls $1,_GC_tl_mark"); asm("pushl r6"); asm("calls $1,_GC_tl_mark"); # endif -# ifdef M68K_SUN - /* M68K_SUN - could be replaced by generic code */ +# if defined(M68K) && defined(SUNOS) + /* M68K SUNOS - could be replaced by generic code */ /* a0, a1 and d1 are caller save */ /* and therefore are on stack or dead. */ @@ -50,8 +50,8 @@ GC_mark_regs() asm("addqw #0x4,sp"); /* put stack back where it was */ # endif -# ifdef M68K_HP - /* M68K_HP - could be replaced by generic code */ +# if defined(M68K) && defined(HP) + /* M68K HP - could be replaced by generic code */ /* a0, a1 and d1 are caller save. */ asm("subq.w &0x4,%sp"); /* allocate word on top of stack */ @@ -70,9 +70,9 @@ GC_mark_regs() asm("mov.l %d7,(%sp)"); asm("jsr _GC_tl_mark"); asm("addq.w &0x4,%sp"); /* put stack back where it was */ -# endif /* M68K_HP */ +# endif /* M68K HP */ -# if defined(I386) && !defined(OS2) +# if defined(I386) && !defined(OS2) && !defined(SUNOS5) /* I386 code, generic code does not appear to work */ /* It does appear to work under OS2, and asms dont */ asm("pushl %eax"); asm("call _GC_tl_mark"); asm("addl $4,%esp"); @@ -83,6 +83,17 @@ GC_mark_regs() asm("pushl %ebx"); asm("call _GC_tl_mark"); asm("addl $4,%esp"); # endif +# if defined(I386) && defined(SUNOS5) + /* I386 code, generic code does not appear to work */ + /* It does appear to work under OS2, and asms dont */ + asm("pushl %eax"); asm("call GC_tl_mark"); asm("addl $4,%esp"); + asm("pushl %ecx"); asm("call GC_tl_mark"); asm("addl $4,%esp"); + asm("pushl %edx"); asm("call GC_tl_mark"); asm("addl $4,%esp"); + asm("pushl %esi"); asm("call GC_tl_mark"); asm("addl $4,%esp"); + asm("pushl %edi"); asm("call GC_tl_mark"); asm("addl $4,%esp"); + asm("pushl %ebx"); asm("call GC_tl_mark"); asm("addl $4,%esp"); +# endif + # ifdef NS32K asm ("movd r3, tos"); asm ("bsr ?_GC_tl_mark"); asm ("adjspb $-4"); asm ("movd r4, tos"); asm ("bsr ?_GC_tl_mark"); asm ("adjspb $-4"); @@ -111,7 +122,7 @@ GC_mark_regs() asm("cas r11, r15, r0"); GC_tl_mark(TMP_SP); # endif -# ifdef M68K_SYSV +# if defined(M68K) && defined(SYSV) /* Once again similar to SUN and HP, though setjmp appears to work. --Parag */ @@ -150,7 +161,7 @@ GC_mark_regs() asm("addq.w &0x4,%sp"); /* put stack back where it was */ # endif /* !__GNUC__ */ -# endif /* M68K_SYSV */ +# endif /* M68K/SYSV */ # if defined(HP_PA) || (defined(I386) && defined(OS2)) @@ -174,9 +185,13 @@ GC_mark_regs() # endif /* other machines... */ -# if !(defined M68K_SUN) && !defined(M68K_HP) && !(defined VAX) && !(defined RT) && !(defined SPARC) && !(defined I386) &&!(defined NS32K) &&!defined(HP_PA) && !defined(M68K_SYSV) +# if !(defined M68K) && !(defined VAX) && !(defined RT) +# if !(defined SPARC) && !(defined I386) &&!(defined NS32K) +# if !defined(HP_PA) --> bad news <-- # endif +# endif +# endif } /* On register window machines, we need a way to force registers into */ diff --git a/mark.c b/mark.c index aab8aa44..96935fb4 100644 --- a/mark.c +++ b/mark.c @@ -31,8 +31,7 @@ /* * Limits of stack for GC_mark routine. Set by caller to GC_mark. * All items between GC_mark_stack_top and GC_mark_stack_bottom-1 still need - * to be marked. All items on the stack satisfy quicktest. They do - * not necessarily reference real objects. + * to be marked. */ mse * GC_mark_stack; @@ -88,9 +87,7 @@ register mse * msp, * msl; /* * Mark all objects pointed to by the regions described by * mark stack entries between GC_mark_stack and GC_mark_stack_top, - * inclusive. We assume and preserve the invariant - * that everything on the mark stack points into a hblk that has an - * allocated header. Assumes the upper limit of a mark stack entry + * inclusive. Assumes the upper limit of a mark stack entry * is never 0. */ void GC_mark() @@ -206,8 +203,8 @@ word n; } } else { if (new_stack == 0) { - GC_printf("No space for mark stack\n"); - exit(1); + GC_err_printf0("No space for mark stack\n"); + EXIT(); } GC_mark_stack = new_stack; GC_mark_stack_size = n; @@ -229,8 +226,8 @@ void GC_mark_reliable() while (dropped_some) { dropped_some = FALSE; # ifdef PRINTSTATS - GC_printf("Mark stack overflow; current size = %lu entries\n", - GC_mark_stack_size); + GC_printf1("Mark stack overflow; current size = %lu entries\n", + GC_mark_stack_size); # endif alloc_mark_stack(2*GC_mark_stack_size); GC_remark(); @@ -332,7 +329,7 @@ word dummy; register word * lim; register mse * GC_mark_stack_top_reg = GC_mark_stack_top; - if (sz < 0) return; + if (hhdr -> hb_obj_kind == PTRFREE) return; if (sz > MAXOBJSZ) { lim = (word *)(h + 1); } else { @@ -348,6 +345,7 @@ word dummy; GC_mark_stack_top_reg -> mse_end = p + sz; } } + GC_mark_stack_top = GC_mark_stack_top_reg; GC_mark(); } diff --git a/mark_roots.c b/mark_roots.c index 5cc55649..132d59e3 100644 --- a/mark_roots.c +++ b/mark_roots.c @@ -1,20 +1,77 @@ # include # include "gc_private.h" -# define MAX_ROOT_SETS 50 + # ifdef PCR +# define MAX_ROOT_SETS 1024 # include "pcr/il/PCR_IL.h" # include "pcr/th/PCR_ThCtl.h" # include "pcr/mm/PCR_MM.h" +# else +# define MAX_ROOT_SETS 64 # endif +/* Data structure for list of root sets. */ +/* We keep a hash table, so that we can filter out duplicate additions. */ struct roots { ptr_t r_start; ptr_t r_end; + struct roots * r_next; }; static struct roots static_roots[MAX_ROOT_SETS]; + static n_root_sets = 0; + /* static_roots[0..n_root_sets) contains the valid root sets. */ + +#define RT_SIZE 64 /* Power of 2, may be != MAX_ROOT_SETS */ +#define LOG_RT_SIZE 6 + +static struct roots * root_index[RT_SIZE]; + /* Hash table header. Used only to check whether a range is */ + /* already present. */ + +static int rt_hash(addr) +char * addr; +{ + word result = (word) addr; +# if CPP_WORDSZ > 8*LOG_RT_SIZE + result ^= result >> 8*LOG_RT_SIZE; +# endif +# if CPP_WORDSZ > 4*LOG_RT_SIZE + result ^= result >> 4*LOG_RT_SIZE; +# endif + result ^= result >> 2*LOG_RT_SIZE; + result ^= result >> LOG_RT_SIZE; + result &= (RT_SIZE-1); + return(result); +} + +/* Is a range starting at addr already in the table? */ +static bool roots_present(b, e) +char *b, *e; +{ + register int h = rt_hash(b); + register struct roots *p = root_index[h]; + + while (p != 0) { + if (p -> r_start == (ptr_t)b && p -> r_end >= (ptr_t)e) return(TRUE); + p = p -> r_next; + } + return(FALSE); +} + +/* Add the given root structure to the index. */ +static void add_roots_to_index(p) +struct roots *p; +{ + register int h = rt_hash(p -> r_start); + + p -> r_next = root_index[h]; + root_index[h] = p; +} + + word GC_root_size = 0; void GC_add_roots(b, e) @@ -30,7 +87,10 @@ char * b; char * e; } - +/* Add [b,e) to the root set. Adding the same interval a second time */ +/* 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) char * b; char * e; { @@ -47,11 +107,14 @@ char * b; char * e; } else if ((ptr_t)b < endGC_arrays && (ptr_t)e > endGC_arrays) { b = (char *)endGC_arrays; } + if (roots_present(b,e)) return; if (n_root_sets == MAX_ROOT_SETS) { ABORT("Too many root sets\n"); } 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_next = 0; + add_roots_to_index(static_roots + n_root_sets); GC_root_size += (ptr_t)e - (ptr_t)b; n_root_sets++; } @@ -125,36 +188,19 @@ GC_mark_roots() /* Add new static data areas of dynamically loaded modules. */ { - PCR_IL_LoadedFile * p = PCR_IL_GetLoadedFiles(); - static PCR_IL_LoadedFile * last_already_added = NIL; - /* Last file that was already added to the list of roots. */ - PCR_IL_LoadedFile * last_committed; + PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile(); PCR_IL_LoadedSegment * q; - if (p != NIL && last_already_added == NIL) { - /* Switch to obtaining roots from the dynamic loader. */ - /* Make sure the loader is properly initialized and that */ - /* it has a correct description of PCR static data. */ - PCR_IL_Lock(PCR_Bool_false, - PCR_allSigsBlocked, PCR_waitForever); - PCR_IL_Unlock(); - /* Discard old root sets. */ - n_root_sets = 0; - GC_root_size = 0; - /* We claim there are no dynamic libraries, or they */ - /* don't contain roots, since they allocate using the */ - /* system malloc, and they can't retain our pointers. */ - } /* Skip uncommited files */ while (p != NIL && !(p -> lf_commitPoint)) { /* The loading of this file has not yet been committed */ /* Hence its description could be inconsistent. */ - /* Furthermore, it hasn't yet been run. Hence it's data */ - /* segments can possibly reference heap allocated objects.*/ + /* Furthermore, it hasn't yet been run. Hence its data */ + /* segments can't possibly reference heap allocated */ + /* objects. */ p = p -> lf_prev; } - last_committed = p; - for (; p != last_already_added; p = p -> lf_prev) { + for (; p != NIL; p = p -> lf_prev) { for (q = p -> lf_ls; q != NIL; q = q -> ls_next) { if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK) == PCR_IL_SegFlags_Traced_on) { @@ -164,7 +210,6 @@ GC_mark_roots() } } } - last_already_added = last_committed; } @@ -181,12 +226,15 @@ GC_mark_roots() # else GC_mark_all_stack( GC_stackbottom, GC_approx_sp() ); # endif + # endif + /* Reregister dynamic libraries, in case one got added. */ + GC_register_dynamic_libraries(); /* Mark everything in static data areas */ - for (i = 0; i < n_root_sets; i++) { + for (i = 0; i < n_root_sets; i++) { GC_mark_all(static_roots[i].r_start, static_roots[i].r_end); - } + } } /* diff --git a/misc.c b/misc.c index a19e0dca..3179ef44 100644 --- a/misc.c +++ b/misc.c @@ -34,8 +34,10 @@ struct _GC_arrays GC_arrays = { 0 }; /* This must be done statically since they may be accessed before */ /* GC_init is called. */ struct obj_kind GC_obj_kinds[MAXOBJKINDS] = { -/* PTRFREE */ { GC_aobjfreelist, GC_areclaim_list, GC_no_mark_proc, FALSE }, -/* NORMAL */ { GC_objfreelist, GC_reclaim_list, GC_normal_mark_proc, TRUE }, +/* PTRFREE */ { &GC_aobjfreelist[0], &GC_areclaim_list[0], + GC_no_mark_proc, FALSE }, +/* NORMAL */ { &GC_objfreelist[0], &GC_reclaim_list[0], + GC_normal_mark_proc, TRUE }, }; ptr_t GC_stackbottom = 0; @@ -235,10 +237,9 @@ DCL_LOCK_STATE; if (!GC_is_initialized) GC_init_inner(); lw = ROUNDED_UP_WORDS(lb); - if (!GC_sufficient_hb(lw, k) && !GC_dont_gc) { - GC_gcollect_inner(FALSE); + while ((h = GC_allochblk(lw, k)) == 0) { + GC_collect_or_expand(divHBLKSZ(lb) + 1); } - h = GC_allochblk(lw, k); if (h == 0) { op = 0; } else { @@ -505,6 +506,7 @@ int obj_kind; h = HBLKPTR(p); hhdr = HDR(h); sz = hhdr -> hb_sz; + GC_mem_freed += sz; ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; if (sz > MAXOBJSZ) { @@ -546,56 +548,59 @@ void GC_init_inner() } # endif if (sizeof (ptr_t) != sizeof(word)) { - GC_printf("sizeof (ptr_t) != sizeof(word)\n"); + GC_err_printf0("sizeof (ptr_t) != sizeof(word)\n"); ABORT("sizeof (ptr_t) != sizeof(word)\n"); } if (sizeof (signed_word) != sizeof(word)) { - GC_printf("sizeof (signed_word) != sizeof(word)\n"); + GC_err_printf0("sizeof (signed_word) != sizeof(word)\n"); ABORT("sizeof (signed_word) != sizeof(word)\n"); } if (sizeof (struct hblk) != HBLKSIZE) { - GC_printf("sizeof (struct hblk) != HBLKSIZE\n"); + GC_err_printf0("sizeof (struct hblk) != HBLKSIZE\n"); ABORT("sizeof (struct hblk) != HBLKSIZE\n"); } # ifndef THREADS # if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN) - GC_printf( + GC_err_printf0( "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n"); ABORT("stack direction 1\n"); # endif # if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN) - GC_printf( + GC_err_printf0( "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n"); ABORT("stack direction 2\n"); # endif # ifdef STACK_GROWS_DOWN if ((word)(&dummy) > (word)GC_stackbottom) { - GC_printf("STACK_GROWS_DOWN is defd, but stack appears to grow up\n"); - GC_printf("sp = 0x%lx, GC_stackbottom = 0x%lx\n", - (unsigned long) (&dummy), - (unsigned long) GC_stackbottom); + GC_err_printf0( + "STACK_GROWS_DOWN is defd, but stack appears to grow up\n"); + GC_err_printf2("sp = 0x%lx, GC_stackbottom = 0x%lx\n", + (unsigned long) (&dummy), + (unsigned long) GC_stackbottom); ABORT("stack direction 3\n"); } # else if ((word)(&dummy) < (word)GC_stackbottom) { - GC_printf("STACK_GROWS_UP is defd, but stack appears to grow down\n"); - GC_printf("sp = 0x%lx, GC_stackbottom = 0x%lx\n", - (unsigned long) (&dummy), - (unsigned long) GC_stackbottom); + GC_err_printf0( + "STACK_GROWS_UP is defd, but stack appears to grow down\n"); + GC_err_printf2("sp = 0x%lx, GC_stackbottom = 0x%lx\n", + (unsigned long) (&dummy), + (unsigned long) GC_stackbottom); ABORT("stack direction 4"); } # endif # endif # if !defined(_AUX_SOURCE) || defined(__GNUC__) if ((word)(-1) < (word)0) { - GC_printf("The type word should be an unsigned integer type\n"); - GC_printf("It appears to be signed\n"); + GC_err_printf0("The type word should be an unsigned integer type\n"); + GC_err_printf0("It appears to be signed\n"); ABORT("word"); } # endif if ((signed_word)(-1) >= (signed_word)0) { - GC_printf("The type signed_word should be a signed integer type\n"); - GC_printf("It appears to be unsigned\n"); + GC_err_printf0( + "The type signed_word should be a signed integer type\n"); + GC_err_printf0("It appears to be unsigned\n"); ABORT("signed_word"); } @@ -604,7 +609,7 @@ void GC_init_inner() GC_bl_init(); GC_mark_init(); if (!GC_expand_hp_inner(GC_hincr)) { - GC_printf("Can't start up: no memory\n"); + GC_printf0("Can't start up: no memory\n"); EXIT(); } GC_register_displacement_inner(0L); @@ -614,11 +619,13 @@ void GC_init_inner() /* Add initial guess of root sets */ GC_register_data_segments(); # ifdef PCR + PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever); + PCR_IL_Unlock(); GC_pcr_install(); # endif /* Get black list set up */ - GC_gcollect_inner(TRUE); - GC_gcollect_inner(TRUE); + (void)GC_gcollect_inner(TRUE); + (void)GC_gcollect_inner(TRUE); /* Convince lint that some things are used */ { extern char * GC_copyright[]; @@ -633,7 +640,6 @@ void GC_init_inner() /* Assumes that all arguments have been converted to something of the */ /* same size as long, and that the format conversions expect something */ /* of that size. */ -/*VARARGS1*/ void GC_printf(format, a, b, c, d, e, f) char * format; long a, b, c, d, e, f; @@ -652,7 +658,6 @@ long a, b, c, d, e, f; # endif } -/*VARARGS1*/ void GC_err_printf(format, a, b, c, d, e, f) char * format; long a, b, c, d, e, f; diff --git a/obj_map.c b/obj_map.c index 6ea00763..fc3bfd99 100644 --- a/obj_map.c +++ b/obj_map.c @@ -100,7 +100,7 @@ word sz; } new_map = GC_scratch_alloc(MAP_SIZE); # ifdef PRINTSTATS - GC_printf("Adding block map for size %lu\n", (unsigned long)sz); + GC_printf1("Adding block map for size %lu\n", (unsigned long)sz); # endif for (displ = 0; displ < HBLKSIZE; displ++) { MAP_ENTRY(new_map,displ) = OBJ_INVALID; diff --git a/os_dep.c b/os_dep.c index c1726d4c..9a8df5f8 100644 --- a/os_dep.c +++ b/os_dep.c @@ -1,7 +1,19 @@ +/* + * Copyright (c) 1991-1993 by Xerox Corporation. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to copy this garbage collector for any purpose, + * provided the above notices are retained on all copies. + */ # include "gc_private.h" # include # include +/* Blatantly OS dependent routines, except for those that are related */ +/* dynamic loading. */ + /* Disable and enable signals during nontrivial allocations */ # ifdef OS2 @@ -43,40 +55,66 @@ void GC_enable_signals(void) # else -static int old_mask; +# ifndef PCR + +# ifdef sigmask + /* Use the traditional BSD interface */ +# define SIGSET_T int +# define SIG_DEL(set, signal) (set) &= ~(sigmask(signal)) +# define SIG_FILL(set) (set) = 0x7fffffff + /* Setting the leading bit appears to provoke a bug in some */ + /* longjmp implementations. Most systems appear not to have */ + /* a signal 32. */ +# define SIGSETMASK(old, new) (old) = sigsetmask(new) +# else + /* Use POSIX/SYSV interface */ +# define SIGSET_T sigset_t +# define SIG_DEL(set, signal) sigdelset(&(set), (signal)) +# define SIG_FILL(set) sigfillset(&set) +# define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old)) +# endif + +static bool mask_initialized = FALSE; + +static SIGSET_T new_mask; + +static SIGSET_T old_mask; + +static SIGSET_T dummy; void GC_disable_signals() { - int mask = 0x7fffffff; - /* Setting the leading bit appears to provoke a bug in some */ - /* longjmp implementations. Most systems appear not to have */ - /* a signal 32. */ - - mask &= ~(1<<(SIGSEGV-1)); - mask &= ~(1<<(SIGILL-1)); - mask &= ~(1<<(SIGQUIT-1)); -# ifdef SIGBUS - mask &= ~(1<<(SIGBUS-1)); -# endif -# ifdef SIGIOT - mask &= ~(1<<(SIGIOT-1)); -# endif -# ifdef SIGEMT - mask &= ~(1<<(SIGEMT-1)); -# endif -# ifdef SIGTRAP - mask &= ~(1<<(SIGTRAP-1)); -# endif - old_mask = sigsetmask(mask); + if (!mask_initialized) { + SIG_FILL(new_mask); + + SIG_DEL(new_mask, SIGSEGV); + SIG_DEL(new_mask, SIGILL); + SIG_DEL(new_mask, SIGQUIT); +# ifdef SIGBUS + SIG_DEL(new_mask, SIGBUS); +# endif +# ifdef SIGIOT + SIG_DEL(new_mask, SIGIOT); +# endif +# ifdef SIGEMT + SIG_DEL(new_mask, SIGEMT); +# endif +# ifdef SIGTRAP + SIG_DEL(new_mask, SIGTRAP); +# endif + mask_initialized = TRUE; + } + SIGSETMASK(old_mask,new_mask); } void GC_enable_signals() { - (void)sigsetmask(old_mask); + SIGSETMASK(dummy,old_mask); } +# endif /* !PCR */ -# endif +# endif /*!OS/2 */ /* * Find the base of the stack. @@ -93,7 +131,7 @@ ptr_t GC_get_stack_base() PPIB ppib; if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) { - fprintf(stderr, "DosGetInfoBlocks failed\n"); + GC_err_printf0("DosGetInfoBlocks failed\n"); ABORT("DosGetInfoBlocks failed\n"); } return((ptr_t)(ptib -> tib_pstacklimit)); @@ -172,8 +210,8 @@ ptr_t GC_get_stack_base() result += MIN_PAGE_SIZE; # endif # endif /* HEURISTIC2 */ + return(result); # endif /* STACKBOTTOM */ - return(result); } # endif /* ! OS2 */ @@ -203,12 +241,12 @@ void GC_register_data_segments() if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) { - fprintf(stderr, "DosGetInfoBlocks failed\n"); + GC_err_printf0("DosGetInfoBlocks failed\n"); ABORT("DosGetInfoBlocks failed\n"); } module_handle = ppib -> pib_hmte; if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) { - fprintf(stderr, "DosQueryModuleName failed\n"); + GC_err_printf0("DosQueryModuleName failed\n"); ABORT("DosGetInfoBlocks failed\n"); } myexefile = fopen(path, "rb"); @@ -269,7 +307,7 @@ void GC_register_data_segments() if (!(flags & OBJWRITE)) continue; if (!(flags & OBJREAD)) continue; if (flags & OBJINVALID) { - fprintf(stderr, "Object with invalid pages?\n"); + GC_err_printf0("Object with invalid pages?\n"); continue; } GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg)); @@ -281,15 +319,12 @@ void GC_register_data_segments() void GC_register_data_segments() { extern int end; - - GC_add_roots_inner(DATASTART, (char *)(&end)); -# ifdef DYNAMIC_LOADING - { - extern void GC_setup_dynamic_loading(); - - GC_setup_dynamic_loading(); - } + +# ifndef PCR + GC_add_roots_inner(DATASTART, (char *)(&end)); # endif + /* Dynamic libraries are added at every collection, since they may */ + /* change. */ } # endif /* ! OS2 */ diff --git a/pcr_interface.c b/pcr_interface.c index 85167804..573d34f7 100644 --- a/pcr_interface.c +++ b/pcr_interface.c @@ -36,8 +36,6 @@ void * GC_AllocProc(size_t size, PCR_Bool ptrFree, PCR_Bool clear ) # define GC_FreeProc GC_free -void GC_NoOpProc () {} - typedef struct { PCR_ERes (*ed_proc)(void *p, size_t size, PCR_Any data); bool ed_pointerfree; @@ -92,14 +90,18 @@ PCR_ERes GC_EnumerateProc( } } +void GC_DummyFreeProc(void *p) {}; + +void GC_DummyShutdownProc(void) {}; + struct PCR_MM_ProcsRep GC_Rep = { MY_MAGIC, GC_AllocProc, GC_ReallocProc, - GC_NoOpProc, /* mmp_free */ - GC_FreeProc, /* mmp_unsafeFree */ + GC_DummyFreeProc, /* mmp_free */ + GC_FreeProc, /* mmp_unsafeFree */ GC_EnumerateProc, - GC_NoOpProc, /* mmp_shutdown */ + GC_DummyShutdownProc /* mmp_shutdown */ }; void GC_pcr_install() diff --git a/reclaim.c b/reclaim.c index 357c0a67..9bf10158 100644 --- a/reclaim.c +++ b/reclaim.c @@ -21,14 +21,14 @@ ptr_t p; word sz; { if (HDR(p) -> hb_obj_kind == PTRFREE) { - GC_err_printf("Leaked atomic object at "); + GC_err_printf0("Leaked atomic object at "); } else { - GC_err_printf("Leaked composite object at "); + GC_err_printf0("Leaked composite object at "); } if (GC_debugging_started && GC_has_debug_info(p)) { GC_print_obj(p); } else { - GC_err_printf("0x%lx (appr. size = %ld)\n", + GC_err_printf1("0x%lx (appr. size = %ld)\n", (unsigned long)WORDS_TO_BYTES(sz)); } } @@ -434,13 +434,13 @@ int abort_if_found; /* Abort if a reclaimable object is found */ sz = hhdr -> hb_sz; ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; # ifdef PRINTBLOCKS - GC_printf("%ld(", (unsigned long)sz); + GC_printf1("%ld(", (unsigned long)sz); if (hhdr -> hb_obj_kind == PTRFREE) { - GC_printf("a"); + GC_printf0("a"); } else if (hhdr -> hb_obj_kind == NORMAL){ - GC_printf("c"); + GC_printf0("c"); } else { - GC_printf("o"); + GC_printf0("o"); } # endif @@ -472,7 +472,7 @@ int abort_if_found; /* Abort if a reclaimable object is found */ } } # ifdef PRINTBLOCKS - if (empty) {GC_printf("e),");} else {GC_printf("n),");} + if (empty) {GC_printf0("e),");} else {GC_printf0("n),");} # endif } @@ -507,7 +507,7 @@ int abort_if_found; /* Abort if a GC_reclaimable object is found */ } # ifdef PRINTBLOCKS - GC_printf("GC_reclaim: current block sizes:\n"); + GC_printf0("GC_reclaim: current block sizes:\n"); # endif /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */ @@ -515,7 +515,7 @@ int abort_if_found; /* Abort if a GC_reclaimable object is found */ GC_apply_to_all_blocks(GC_reclaim_block, abort_if_found); # ifdef PRINTBLOCKS - GC_printf("\n"); + GC_printf0("\n"); # endif } diff --git a/setjmp_test.c b/setjmp_test.c index 8426fd3d..6c2c8737 100644 --- a/setjmp_test.c +++ b/setjmp_test.c @@ -10,7 +10,7 @@ /* code.) */ #include #include -#include "gc_private.h" +#include "config.h" #ifdef __hpux /* X/OPEN PG3 defines "void* sbrk();" and this clashes with the definition */ @@ -26,6 +26,16 @@ getpagesize() } #endif +#if defined(SUNOS5) +#define _CLASSIC_XOPEN_TYPES +#include +int +getpagesize() +{ + return sysconf(_SC_PAGESIZE); +} +#endif + #ifdef _AUX_SOURCE #include int @@ -95,7 +105,7 @@ main() if (y == 1) { if (x == 2) { printf("Generic mark_regs code probably wont work\n"); -# if defined(SPARC) || defined(IBMRS6000) +# if defined(SPARC) || defined(IBMRS6000) || defined(VAX) || defined(MIPS) || defined(M68K) || defined(I386) || defined(NS32K) || defined(RT) printf("Assembly code supplied\n"); # else printf("Need assembly code\n"); diff --git a/test.c b/test.c index 027aa80c..be4fa067 100644 --- a/test.c +++ b/test.c @@ -69,6 +69,24 @@ sexpr y; return(r); } +sexpr small_cons (x, y) +sexpr x; +sexpr y; +{ + register sexpr r; + register int *p; + + r = (sexpr) GC_MALLOC(sizeof(struct SEXPR)); + if (r == 0) { + (void)printf("Out of memory\n"); + exit(1); + } + r -> sexpr_car = x; + r -> sexpr_cdr = y; + return(r); +} + + /* Return reverse(x) concatenated with y */ sexpr reverse1(x, y) sexpr x, y; @@ -92,7 +110,7 @@ int low, up; if (low > up) { return(nil); } else { - return(cons((sexpr)low, ints(low+1, up))); + return(small_cons(small_cons((sexpr)low, 0), ints(low+1, up))); } } @@ -100,7 +118,7 @@ void check_ints(list, low, up) sexpr list; int low, up; { - if ((int)(car(list)) != low) { + if ((int)(car(car(list))) != low) { (void)printf( "List reversal produced incorrect list - collector is broken\n"); exit(1); @@ -122,7 +140,7 @@ sexpr x; if (is_nil(x)) { (void)printf("NIL\n"); } else { - (void)printf("%d", car(x)); + (void)printf("(%d)", car(car(x))); if (!is_nil(cdr(x))) { (void)printf(", "); (void)print_int_list(cdr(x)); @@ -147,9 +165,11 @@ reverse_test() { int i; sexpr b; + sexpr c; a = ints(1, 100); b = ints(1, 50); + c = ints(1, 4500); for (i = 0; i < 50; i++) { b = reverse(reverse(b)); } @@ -168,7 +188,8 @@ reverse_test() } check_ints(a,1,100); check_ints(b,1,50); - a = b = 0; + check_ints(c,1,4500); + a = b = c = 0; } /* -- 2.40.0