From 4b6b3b3b1bad96c79817fa99d89b1f9b3551f181 Mon Sep 17 00:00:00 2001 From: bryce Date: Wed, 19 Apr 2000 02:29:16 +0000 Subject: Imported Boehm GC 5.0alpha6 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/boehm@33244 138bc75d-0d04-0410-961f-82ee72b054a4 --- boehm-gc/Makefile | 47 ++++-- boehm-gc/allchblk.c | 56 +++--- boehm-gc/alloc.c | 10 +- boehm-gc/alpha_mach_dep.s | 4 + boehm-gc/cord/cordprnt.c | 2 +- boehm-gc/dbg_mlc.c | 107 ++++-------- boehm-gc/dyn_load.c | 58 +++++-- boehm-gc/finalize.c | 8 + boehm-gc/headers.c | 25 ++- boehm-gc/include/cord.h | 2 +- boehm-gc/include/gc.h | 51 +++++- boehm-gc/include/gc_cpp.h | 21 ++- boehm-gc/include/gc_typed.h | 2 + boehm-gc/include/private/gc_priv.h | 182 +++++++++++++------- boehm-gc/include/private/gcconfig.h | 329 ++++++++++++++++++++++++++++++------ boehm-gc/linux_threads.c | 160 ++++++++++++++---- boehm-gc/mach_dep.c | 68 ++++++-- boehm-gc/malloc.c | 4 + boehm-gc/mallocx.c | 34 ++-- boehm-gc/mark.c | 126 +++++++++++--- boehm-gc/mark_rts.c | 8 +- boehm-gc/misc.c | 24 ++- boehm-gc/new_hblk.c | 9 +- boehm-gc/os_dep.c | 51 ++++-- boehm-gc/reclaim.c | 24 ++- boehm-gc/solaris_pthreads.c | 44 +++-- boehm-gc/solaris_threads.c | 5 +- boehm-gc/threadlibs.c | 11 +- boehm-gc/typd_mlc.c | 7 +- boehm-gc/version.h | 5 +- boehm-gc/win32_threads.c | 6 +- 31 files changed, 1094 insertions(+), 396 deletions(-) diff --git a/boehm-gc/Makefile b/boehm-gc/Makefile index d6eab33f088..d3a3482d25b 100644 --- a/boehm-gc/Makefile +++ b/boehm-gc/Makefile @@ -9,6 +9,7 @@ # cord/de - builds dumb editor based on cords. ABI_FLAG= CC=cc $(ABI_FLAG) +HOSTCC=$(CC) CXX=g++ $(ABI_FLAG) AS=as $(ABI_FLAG) # The above doesn't work with gas, which doesn't run cpp. @@ -58,6 +59,8 @@ CFLAGS= -O -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_PERMISSION -DALL_INT # implementations, and it sometimes has a significant performance # impact. However, it is dangerous for many not-quite-ANSI C # programs that call things like printf in asynchronous signal handlers. +# This is on by default. Turning it off has not been extensively tested with +# compilers that reorder stores. It should have been. # -DNO_EXECUTE_PERMISSION may cause some or all of the heap to not # have execute permission, i.e. it may be impossible to execute # code from the heap. Currently this only affects the incremental @@ -112,12 +115,6 @@ CFLAGS= -O -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_PERMISSION -DALL_INT # like a pointer, print both the address containing the value, and the # value of the near-bogus-pointer. Can be used to identifiy regions of # memory that are likely to contribute misidentified pointers. -# -DOLD_BLOCK_ALLOC Use the old, possibly faster, large block -# allocation strategy. The new strategy tries harder to minimize -# fragmentation, sometimes at the expense of spending more time in the -# large block allocator and/or collecting more frequently. -# If you expect the allocator to promptly use an explicitly expanded -# heap, this is highly recommended. # -DKEEP_BACK_PTRS Add code to save back pointers in debugging headers # for objects allocated with the debugging allocator. If all objects # through GC_MALLOC with GC_DEBUG defined, this allows the client @@ -132,6 +129,24 @@ CFLAGS= -O -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_PERMISSION -DALL_INT # -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly # altered stubborn objects, at substantial performance cost. # Use only for debugging of the incremental collector. +# -DGC_GCJ_SUPPORT includes support for gcj (and possibly other systems +# that include a pointer to a type descriptor in each allocated object). +# Building this way requires an ANSI C compiler. +# -DUSE_I686_PREFETCH causes the collector to issue Pentium III style +# prefetch instructions. No effect except on X86 Linux platforms. +# Assumes a very recent gcc-compatible compiler and assembler. +# (Gas prefetcht0 support was added around May 1999.) +# Empirically the code appears to still run correctly on Pentium II +# processors, though with no performance benefit. May not run on other +# X86 processors? In some cases this improves performance by +# 15% or so. +# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style +# prefetch instructions. Same restrictions as USE_I686_PREFETCH. +# UNTESTED!! +# -DUSE_LD_WRAP in combination with the gld flags listed in README.linux +# causes the collector some system and pthread calls in a more transparent +# fashion than the usual macro-based approach. Requires GNU ld, and +# currently probably works only with Linux. # @@ -151,9 +166,9 @@ RANLIB= ranlib srcdir = . VPATH = $(srcdir) -OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o hpux_irix_threads.o linux_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o +OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o hpux_irix_threads.o linux_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o -CSRCS= 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 hpux_irix_threads.c linux_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c +CSRCS= 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 hpux_irix_threads.c linux_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c cord/cord.h cord/ec.h cord/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC cord/SCOPTIONS.amiga cord/SMakefile.amiga @@ -165,7 +180,8 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \ threadlibs.c if_mach.c if_not_there.c gc_cpp.cc gc_cpp.h weakpointer.h \ gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h gc_alloc.h \ include/new_gc_alloc.h include/javaxfc.h sparc_sunos4_mach_dep.s \ - solaris_threads.h backptr.h hpux_test_and_clear.s $(CORD_SRCS) + solaris_threads.h backptr.h hpux_test_and_clear.s include/gc_gcj.h \ + dbg_mlc.h $(CORD_SRCS) OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \ README test.c test_cpp.cc setjmp_t.c SMakefile.amiga \ @@ -300,7 +316,9 @@ mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ul ./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s ./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s ./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s - ./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.s +# ./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.s +# alpha_mach_dep.s assumes that pointers are not saved in fp registers. +# Gcc on a 21264 can spill pointers to fp registers. Oops. ./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.s ./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s ./if_mach SPARC OPENBSD $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s @@ -343,18 +361,19 @@ cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS) ./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs` ./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs` - ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses + ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs` + ./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs` ./if_mach M68K AMIGA $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses ./if_not_there cord/de $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) `./threadlibs` if_mach: $(srcdir)/if_mach.c $(srcdir)/gcconfig.h - $(CC) $(CFLAGS) -o if_mach $(srcdir)/if_mach.c + $(HOSTCC) $(CFLAGS) -o if_mach $(srcdir)/if_mach.c threadlibs: $(srcdir)/threadlibs.c $(srcdir)/gcconfig.h Makefile - $(CC) $(CFLAGS) -o threadlibs $(srcdir)/threadlibs.c + $(HOSTCC) $(CFLAGS) -o threadlibs $(srcdir)/threadlibs.c if_not_there: $(srcdir)/if_not_there.c - $(CC) $(CFLAGS) -o if_not_there $(srcdir)/if_not_there.c + $(HOSTCC) $(CFLAGS) -o if_not_there $(srcdir)/if_not_there.c clean: rm -f gc.a *.o gctest gctest_dyn_link test_cpp \ diff --git a/boehm-gc/allchblk.c b/boehm-gc/allchblk.c index 189b94214a7..1505f8e2c71 100644 --- a/boehm-gc/allchblk.c +++ b/boehm-gc/allchblk.c @@ -19,6 +19,7 @@ #include #include "gc_priv.h" +GC_bool GC_use_entire_heap = 0; /* * Free heap blocks are kept on one of several free lists, @@ -229,11 +230,15 @@ int n; GC_ASSERT(HDR(GC_hblkfreelist[index]) == hhdr); GC_hblkfreelist[index] = hhdr -> hb_next; } else { - PHDR(hhdr) -> hb_next = hhdr -> hb_next; + hdr *phdr; + GET_HDR(hhdr -> hb_prev, phdr); + phdr -> hb_next = hhdr -> hb_next; } if (0 != hhdr -> hb_next) { + hdr * nhdr; GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr))); - NHDR(hhdr) -> hb_prev = hhdr -> hb_prev; + GET_HDR(hhdr -> hb_next, nhdr); + nhdr -> hb_prev = hhdr -> hb_prev; } } @@ -244,13 +249,20 @@ struct hblk * GC_free_block_ending_at(h) struct hblk *h; { struct hblk * p = h - 1; - hdr * phdr = HDR(p); + hdr * phdr; + GET_HDR(p, phdr); while (0 != phdr && IS_FORWARDING_ADDR_OR_NIL(phdr)) { p = FORWARDED_ADDR(p,phdr); phdr = HDR(p); } - if (0 != phdr && HBLK_IS_FREE(phdr)) return p; + if (0 != phdr) { + if(HBLK_IS_FREE(phdr)) { + return p; + } else { + return 0; + } + } p = GC_prev_block(h - 1); if (0 != p) { phdr = HDR(p); @@ -271,6 +283,7 @@ hdr * hhdr; { int index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz)); struct hblk *second = GC_hblkfreelist[index]; + hdr * second_hdr; # ifdef GC_ASSERTIONS struct hblk *next = (struct hblk *)((word)h + hhdr -> hb_sz); hdr * nexthdr = HDR(next); @@ -283,7 +296,10 @@ hdr * hhdr; GC_hblkfreelist[index] = h; hhdr -> hb_next = second; hhdr -> hb_prev = 0; - if (0 != second) HDR(second) -> hb_prev = h; + if (0 != second) { + GET_HDR(second, second_hdr); + second_hdr -> hb_prev = h; + } GC_invalidate_map(hhdr); } @@ -330,10 +346,10 @@ void GC_merge_unmapped(void) for (i = 0; i <= N_HBLK_FLS; ++i) { h = GC_hblkfreelist[i]; while (h != 0) { - hhdr = HDR(h); + GET_HDR(h, hhdr); size = hhdr->hb_sz; next = (struct hblk *)((word)h + size); - nexthdr = HDR(next); + GET_HDR(next, nexthdr); /* Coalesce with successor, if possible */ if (0 != nexthdr && HBLK_IS_FREE(nexthdr)) { nextsize = nexthdr -> hb_sz; @@ -398,8 +414,8 @@ int index; GC_remove_from_fl(hhdr, index); if (total_size == bytes) return h; rest = (struct hblk *)((word)h + bytes); - if (!GC_install_header(rest)) return(0); - rest_hdr = HDR(rest); + rest_hdr = GC_install_header(rest); + if (0 == rest_hdr) return(0); rest_hdr -> hb_sz = total_size - bytes; rest_hdr -> hb_flags = 0; # ifdef GC_ASSERTIONS @@ -506,16 +522,17 @@ int n; /* search for a big enough block in free list */ hbp = GC_hblkfreelist[n]; - hhdr = HDR(hbp); - for(; 0 != hbp; hbp = hhdr -> hb_next, hhdr = HDR(hbp)) { + for(; 0 != hbp; hbp = hhdr -> hb_next) { + GET_HDR(hbp, hhdr); size_avail = hhdr->hb_sz; if (size_avail < size_needed) continue; -# ifdef PRESERVE_LAST + if (!GC_use_entire_heap) { if (size_avail != size_needed + && USED_HEAP_SIZE >= GC_requested_heapsize && !GC_incremental && GC_should_collect()) { continue; } -# endif + } /* If the next heap block is obviously better, go on. */ /* This prevents us from disassembling a single large block */ /* to get tiny blocks. */ @@ -524,7 +541,7 @@ int n; thishbp = hhdr -> hb_next; if (thishbp != 0) { - thishdr = HDR(thishbp); + GET_HDR(thishbp, thishdr); next_size = (signed_word)(thishdr -> hb_sz); if (next_size < size_avail && next_size >= size_needed @@ -551,7 +568,8 @@ int n; size_avail -= (ptr_t)lasthbp - (ptr_t)hbp; thishbp = lasthbp; if (size_avail >= size_needed) { - if (thishbp != hbp && GC_install_header(thishbp)) { + if (thishbp != hbp && + 0 != (thishdr = GC_install_header(thishbp))) { /* Make sure it's mapped before we mangle it. */ # ifdef USE_MUNMAP if (!IS_MAPPED(hhdr)) { @@ -560,7 +578,6 @@ int n; } # endif /* Split the block at thishbp */ - thishdr = HDR(thishbp); GC_split_block(hbp, hhdr, thishbp, thishdr, n); /* Advance to thishbp */ hbp = thishbp; @@ -598,8 +615,7 @@ int n; GC_large_free_bytes -= total_size; GC_remove_from_fl(hhdr, n); for (h = hbp; h < limit; h++) { - if (h == hbp || GC_install_header(h)) { - hhdr = HDR(h); + if (h == hbp || 0 != (hhdr = GC_install_header(h))) { (void) setup_header( hhdr, BYTES_TO_WORDS(HBLKSIZE - HDR_BYTES), @@ -686,7 +702,7 @@ hdr *hhdr, *prevhdr, *nexthdr; signed_word size; - hhdr = HDR(hbp); + GET_HDR(hbp, hhdr); size = hhdr->hb_sz; size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size); GC_remove_counts(hbp, (word)size); @@ -701,7 +717,7 @@ signed_word size; GC_ASSERT(IS_MAPPED(hhdr)); GC_invalidate_map(hhdr); next = (struct hblk *)((word)hbp + size); - nexthdr = HDR(next); + GET_HDR(next, nexthdr); prev = GC_free_block_ending_at(hbp); /* Coalesce with successor, if possible */ if(0 != nexthdr && HBLK_IS_FREE(nexthdr) && IS_MAPPED(nexthdr)) { diff --git a/boehm-gc/alloc.c b/boehm-gc/alloc.c index 65bb602b22e..233bfb96243 100644 --- a/boehm-gc/alloc.c +++ b/boehm-gc/alloc.c @@ -70,8 +70,6 @@ int GC_full_freq = 19; /* Every 20th collection is a full */ GC_bool GC_need_full_gc = FALSE; /* Need full GC do to heap growth. */ -#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes) - word GC_used_heap_size_after_full = 0; char * GC_copyright[] = @@ -651,7 +649,8 @@ word bytes; if (GC_n_heap_sects >= MAX_HEAP_SECTS) { ABORT("Too many heap sections: Increase MAXHINCR or MAX_HEAP_SECTS"); } - if (!GC_install_header(p)) { + phdr = GC_install_header(p); + if (0 == phdr) { /* This is extremely unlikely. Can't add it. This will */ /* almost certainly result in a 0 return from the allocator, */ /* which is entirely appropriate. */ @@ -661,7 +660,6 @@ word bytes; GC_heap_sects[GC_n_heap_sects].hs_bytes = bytes; GC_n_heap_sects++; words = BYTES_TO_WORDS(bytes - HDR_BYTES); - phdr = HDR(p); phdr -> hb_sz = words; phdr -> hb_map = (char *)1; /* A value != GC_invalid_map */ phdr -> hb_flags = 0; @@ -810,6 +808,7 @@ word n; LOCK(); if (!GC_is_initialized) GC_init_inner(); result = (int)GC_expand_hp_inner(divHBLKSZ((word)bytes)); + if (result) GC_requested_heapsize += bytes; UNLOCK(); ENABLE_SIGNALS(); return(result); @@ -823,7 +822,8 @@ GC_bool GC_collect_or_expand(needed_blocks, ignore_off_page) word needed_blocks; GC_bool ignore_off_page; { - if (!GC_incremental && !GC_dont_gc && GC_should_collect()) { + if (!GC_incremental && !GC_dont_gc && + (GC_dont_expand && GC_words_allocd > 0 || GC_should_collect())) { GC_notify_full_gc(); GC_gcollect_inner(); } else { diff --git a/boehm-gc/alpha_mach_dep.s b/boehm-gc/alpha_mach_dep.s index 087baeacf4a..783ebf1fe10 100644 --- a/boehm-gc/alpha_mach_dep.s +++ b/boehm-gc/alpha_mach_dep.s @@ -1,5 +1,9 @@ # $Id: alpha_mach_dep.s,v 1.2 1993/01/18 22:54:51 dosser Exp $ +# This is BROKEN on a 21264 running gcc, and probably in other cases. +# The compiler may spill pointers to fp registers, and this code doesn't +# scan those. + # define call_push(x) \ lda $16, 0(x); /* copy x to first argument register */ \ jsr $26, GC_push_one; /* call GC_push_one, ret addr in $26 */ \ diff --git a/boehm-gc/cord/cordprnt.c b/boehm-gc/cord/cordprnt.c index 9c8cc8736a9..8d57f0467fb 100644 --- a/boehm-gc/cord/cordprnt.c +++ b/boehm-gc/cord/cordprnt.c @@ -233,7 +233,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args) if (width == NONE && prec == NONE) { register char c; - c = va_arg(args, char); + c = va_arg(args, int); CORD_ec_append(result, c); goto done; } diff --git a/boehm-gc/dbg_mlc.c b/boehm-gc/dbg_mlc.c index 41843be1fa0..d8dca25d765 100644 --- a/boehm-gc/dbg_mlc.c +++ b/boehm-gc/dbg_mlc.c @@ -2,6 +2,7 @@ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. * Copyright (c) 1997 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -12,64 +13,14 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -# define I_HIDE_POINTERS -# include "gc_priv.h" -# ifdef KEEP_BACK_PTRS -# include "backptr.h" -# endif + +#include "dbg_mlc.h" void GC_default_print_heap_obj_proc(); GC_API void GC_register_finalizer_no_order GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, GC_finalization_proc *ofn, GC_PTR *ocd)); -/* Do we want to and know how to save the call stack at the time of */ -/* an allocation? How much space do we want to use in each object? */ - -# define START_FLAG ((word)0xfedcedcb) -# define END_FLAG ((word)0xbcdecdef) - /* Stored both one past the end of user object, and one before */ - /* the end of the object as seen by the allocator. */ - - -/* Object header */ -typedef struct { -# ifdef KEEP_BACK_PTRS - ptr_t oh_back_ptr; -# define MARKED_FOR_FINALIZATION (ptr_t)(-1) - /* Object was marked because it is finalizable. */ -# ifdef ALIGN_DOUBLE - word oh_dummy; -# endif -# endif - char * oh_string; /* object descriptor string */ - word oh_int; /* object descriptor integers */ -# ifdef NEED_CALLINFO - struct callinfo oh_ci[NFRAMES]; -# endif - word oh_sz; /* Original malloc arg. */ - word oh_sf; /* start flag */ -} oh; -/* The size of the above structure is assumed not to dealign things, */ -/* and to be a multiple of the word length. */ - -#define DEBUG_BYTES (sizeof (oh) + sizeof (word)) -#undef ROUNDED_UP_WORDS -#define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1) - - -#ifdef SAVE_CALL_CHAIN -# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci) -# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci) -#else -# ifdef GC_ADD_CALLER -# define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra) -# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci) -# else -# define ADD_CALL_CHAIN(base, ra) -# define PRINT_CALL_CHAIN(base) -# endif -#endif /* Check whether object with base pointer p has debugging info */ /* p is assumed to point to a legitimate object in our part */ @@ -116,7 +67,7 @@ ptr_t p; /* Store information about the object referencing dest in *base_p */ /* and *offset_p. */ - /* source is root ==> *base_p = 0, *offset_p = address */ + /* source is root ==> *base_p = address, *offset_p = 0 */ /* source is heap object ==> *base_p != 0, *offset_p = offset */ /* Returns 1 on success, 0 if source couldn't be determined. */ /* Dest can be any address within a heap object. */ @@ -128,6 +79,7 @@ ptr_t p; if (!GC_has_debug_info((ptr_t) hdr)) return GC_NO_SPACE; bp = hdr -> oh_back_ptr; if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD; + if (MARKED_FROM_REGISTER == bp) return GC_REFD_FROM_REG; if (0 == bp) return GC_UNREFERENCED; bp = REVEAL_POINTER(bp); bp_base = GC_base(bp); @@ -177,18 +129,15 @@ ptr_t p; } } - /* Force a garbage collection and generate a backtrace from a */ - /* random heap address. */ - void GC_generate_random_backtrace(void) + /* Print back trace for p */ + void GC_print_backtrace(void *p) { - void * current; + void *current = p; int i; - void * base; - size_t offset; GC_ref_kind source; - GC_gcollect(); - current = GC_generate_random_valid_address(); - GC_printf1("Chose address 0x%lx in object\n", (unsigned long)current); + size_t offset; + void *base; + GC_print_heap_obj(GC_base(current)); GC_err_printf0("\n"); for (i = 0; ; ++i) { @@ -207,6 +156,9 @@ ptr_t p; case GC_REFD_FROM_ROOT: GC_err_printf1("root at 0x%lx\n", (unsigned long)base); goto out; + case GC_REFD_FROM_REG: + GC_err_printf0("root in register\n"); + goto out; case GC_FINALIZER_REFD: GC_err_printf0("list of finalizable objects\n"); goto out; @@ -221,6 +173,17 @@ ptr_t p; } out:; } + + /* Force a garbage collection and generate a backtrace from a */ + /* random heap address. */ + void GC_generate_random_backtrace(void) + { + void * current; + GC_gcollect(); + current = GC_generate_random_valid_address(); + GC_printf1("Chose address 0x%lx in object\n", (unsigned long)current); + GC_print_backtrace(current); + } #endif /* KEEP_BACK_PTRS */ @@ -342,16 +305,8 @@ void GC_start_debugging() GC_register_displacement((word)sizeof(oh) + offset); } -# ifdef GC_ADD_CALLER -# define EXTRA_ARGS word ra, CONST char * s, int i -# define OPT_RA ra, -# else -# define EXTRA_ARGS CONST char * s, int i -# define OPT_RA -# endif - # ifdef __STDC__ - GC_PTR GC_debug_malloc(size_t lb, EXTRA_ARGS) + GC_PTR GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS) # else GC_PTR GC_debug_malloc(lb, s, i) size_t lb; @@ -380,7 +335,7 @@ void GC_start_debugging() #ifdef STUBBORN_ALLOC # ifdef __STDC__ - GC_PTR GC_debug_malloc_stubborn(size_t lb, EXTRA_ARGS) + GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS) # else GC_PTR GC_debug_malloc_stubborn(lb, s, i) size_t lb; @@ -447,7 +402,7 @@ GC_PTR p; #endif /* STUBBORN_ALLOC */ # ifdef __STDC__ - GC_PTR GC_debug_malloc_atomic(size_t lb, EXTRA_ARGS) + GC_PTR GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS) # else GC_PTR GC_debug_malloc_atomic(lb, s, i) size_t lb; @@ -472,7 +427,7 @@ GC_PTR p; } # ifdef __STDC__ - GC_PTR GC_debug_malloc_uncollectable(size_t lb, EXTRA_ARGS) + GC_PTR GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS) # else GC_PTR GC_debug_malloc_uncollectable(lb, s, i) size_t lb; @@ -498,7 +453,7 @@ GC_PTR p; #ifdef ATOMIC_UNCOLLECTABLE # ifdef __STDC__ - GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, EXTRA_ARGS) + GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS) # else GC_PTR GC_debug_malloc_atomic_uncollectable(lb, s, i) size_t lb; @@ -578,7 +533,7 @@ GC_PTR p; } # ifdef __STDC__ - GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, EXTRA_ARGS) + GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, GC_EXTRA_PARAMS) # else GC_PTR GC_debug_realloc(p, lb, s, i) GC_PTR p; diff --git a/boehm-gc/dyn_load.c b/boehm-gc/dyn_load.c index 8c3ec4186c4..f812843272e 100644 --- a/boehm-gc/dyn_load.c +++ b/boehm-gc/dyn_load.c @@ -32,7 +32,9 @@ #include "gc_priv.h" /* BTL: avoid circular redefinition of dlopen if SOLARIS_THREADS defined */ -# if defined(SOLARIS_THREADS) && defined(dlopen) +# if (defined(LINUX_THREADS) || defined(SOLARIS_THREADS) \ + || defined(HPUX_THREADS) || defined(IRIX_THREADS)) && defined(dlopen) \ + && !defined(USE_LD_WRAP) /* To support threads in Solaris, gc.h interposes on dlopen by */ /* defining "dlopen" to be "GC_dlopen", which is implemented below. */ /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */ @@ -167,24 +169,60 @@ static ptr_t GC_first_common() # endif /* We assume M3 programs don't call dlopen for now */ # endif -# ifdef SOLARIS_THREADS +# if defined(LINUX_THREADS) || defined(SOLARIS_THREADS) \ + || defined(HPUX_THREADS) || defined(IRIX_THREADS) + /* Make sure we're not in the middle of a collection, and make */ + /* sure we don't start any. Returns previous value of GC_dont_gc. */ + /* This is invoked prior to a dlopen call to avoid synchronization */ + /* issues. We can't just acquire the allocation lock, since startup */ + /* code in dlopen may try to allocate. */ + /* This solution risks heap growth in the presence of many dlopen */ + /* calls in either a multithreaded environment, or if the library */ + /* initialization code allocates substantial amounts of GC'ed memory. */ + /* But I don't know of a better solution. */ + /* This can still deadlock if the client explicitly starts a GC */ + /* during the dlopen. He shouldn't do that. */ + static GC_bool disable_gc_for_dlopen() + { + GC_bool result; + LOCK(); + result = GC_dont_gc; + while (GC_incremental && GC_collection_inProgress()) { + GC_collect_a_little_inner(1000); + } + GC_dont_gc = TRUE; + UNLOCK(); + return(result); + } + + /* Redefine dlopen to guarantee mutual exclusion with */ /* GC_register_dynamic_libraries. */ - /* assumes that dlopen doesn't need to call GC_malloc */ - /* and friends. */ -# include -# include + /* Should probably happen for other operating systems, too. */ + +#include -void * GC_dlopen(const char *path, int mode) +#ifdef USE_LD_WRAP + void * __wrap_dlopen(const char *path, int mode) +#else + void * GC_dlopen(path, mode) + GC_CONST char * path; + int mode; +#endif { void * result; + GC_bool dont_gc_save; # ifndef USE_PROC_FOR_LIBRARIES - mutex_lock(&GC_allocate_ml); + dont_gc_save = disable_gc_for_dlopen(); +# endif +# ifdef USE_LD_WRAP + result = __real_dlopen(path, mode); +# else + result = dlopen(path, mode); # endif - result = dlopen(path, mode); # ifndef USE_PROC_FOR_LIBRARIES - mutex_unlock(&GC_allocate_ml); + GC_dont_gc = dont_gc_save; # endif return(result); } diff --git a/boehm-gc/finalize.c b/boehm-gc/finalize.c index 2ee927fe432..1ab56cee82e 100644 --- a/boehm-gc/finalize.c +++ b/boehm-gc/finalize.c @@ -694,6 +694,14 @@ GC_API void GC_finalize_all() } #endif +/* Returns true if it is worth calling GC_invoke_finalizers. (Useful if */ +/* finalizers can only be called from some kind of `safe state' and */ +/* getting into that safe state is expensive.) */ +int GC_should_invoke_finalizers GC_PROTO((void)) +{ + return GC_finalize_now != 0; +} + /* Invoke finalizers for all objects that are ready to be finalized. */ /* Should be called without allocation lock. */ int GC_invoke_finalizers() diff --git a/boehm-gc/headers.c b/boehm-gc/headers.c index 9564a6a5359..6e47bba8e3f 100644 --- a/boehm-gc/headers.c +++ b/boehm-gc/headers.c @@ -50,10 +50,8 @@ ptr_t h; static ptr_t scratch_free_ptr = 0; -ptr_t GC_scratch_end_ptr = 0; - -ptr_t GC_scratch_last_end_ptr = 0; - /* End point of last obtained scratch area */ +/* GC_scratch_last_end_ptr is end point of last obtained scratch area. */ +/* GC_scratch_end_ptr is end point of current scratch area. */ ptr_t GC_scratch_alloc(bytes) register word bytes; @@ -128,6 +126,13 @@ hdr * hhdr; hhdr -> hb_next = (struct hblk *) hdr_free_list; hdr_free_list = hhdr; } + +hdr * GC_invalid_header; + +#ifdef USE_HDR_CACHE + word GC_hdr_cache_hits = 0; + word GC_hdr_cache_misses = 0; +#endif void GC_init_headers() { @@ -138,6 +143,8 @@ void GC_init_headers() for (i = 0; i < TOP_SZ; i++) { GC_top_index[i] = GC_all_nils; } + GC_invalid_header = alloc_hdr(); + GC_invalidate_map(GC_invalid_header); } /* Make sure that there is a bottom level index block for address addr */ @@ -191,10 +198,10 @@ word addr; return(TRUE); } -/* Install a header for block h. */ -/* The header is uninitialized. */ -/* Returns FALSE on failure. */ -GC_bool GC_install_header(h) +/* Install a header for block h. */ +/* The header is uninitialized. */ +/* Returns the header or 0 on failure. */ +struct hblkhdr * GC_install_header(h) register struct hblk * h; { hdr * result; @@ -205,7 +212,7 @@ register struct hblk * h; # ifdef USE_MUNMAP result -> hb_last_reclaimed = GC_gc_no; # endif - return(result != 0); + return(result); } /* Set up forwarding counts for block h of size sz */ diff --git a/boehm-gc/include/cord.h b/boehm-gc/include/cord.h index 584112fd181..926089e86fb 100644 --- a/boehm-gc/include/cord.h +++ b/boehm-gc/include/cord.h @@ -41,7 +41,7 @@ * This interface is fairly big, largely for performance reasons. * The most basic constants and functions: * - * CORD - the type fo a cord; + * CORD - the type of a cord; * CORD_EMPTY - empty cord; * CORD_len(cord) - length of a cord; * CORD_cat(cord1,cord2) - concatenation of two cords; diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h index cc74765d098..e35f54f7d3f 100644 --- a/boehm-gc/include/gc.h +++ b/boehm-gc/include/gc.h @@ -1,7 +1,8 @@ /* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. - * Copyright 1996 by Silicon Graphics. All rights reserved. + * Copyright 1996-1999 by Silicon Graphics. All rights reserved. + * Copyright 1999 by Hewlett-Packard Company. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -35,6 +36,14 @@ #include "libgc_globals.h" #endif +#if defined(__MINGW32__) && defined(WIN32_THREADS) +# ifdef GC_BUILD +# define GC_API __declspec(dllexport) +# else +# define GC_API __declspec(dllimport) +# endif +#endif + #if defined(_MSC_VER) && defined(_DLL) # ifdef GC_BUILD # define GC_API __declspec(dllexport) @@ -130,6 +139,17 @@ GC_API int GC_dont_expand; /* Dont expand heap unless explicitly requested */ /* or forced to. */ +GC_API int GC_use_entire_heap; + /* Causes the nonincremental collector to use the */ + /* entire heap before collecting. This was the only */ + /* option for GC versions < 5.0. This sometimes */ + /* results in more large block fragmentation, since */ + /* very larg blocks will tend to get broken up */ + /* during each GC cycle. It is likely to result in a */ + /* larger working set, but lower collection */ + /* frequencies, and hence fewer instructions executed */ + /* in the collector. */ + GC_API int GC_full_freq; /* Number of partial collections between */ /* full collections. Matters only if */ /* GC_incremental is set. */ @@ -352,11 +372,11 @@ GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb)); #ifdef GC_ADD_CALLER # define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__ -# define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * descr_string, - int descr_int +# define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * s, + int i #else # define GC_EXTRAS __FILE__, __LINE__ -# define GC_EXTRA_PARAMS GC_CONST char * descr_string, int descr_int +# define GC_EXTRA_PARAMS GC_CONST char * s, int i #endif /* Debugging (annotated) allocation. GC_gcollect will check */ @@ -387,6 +407,8 @@ GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR)); GC_debug_register_finalizer(p, f, d, of, od) # define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \ GC_debug_register_finalizer_ignore_self(p, f, d, of, od) +# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \ + GC_debug_register_finalizer_no_order(p, f, d, of, od) # define GC_MALLOC_STUBBORN(sz) GC_debug_malloc_stubborn(sz, GC_EXTRAS); # define GC_CHANGE_STUBBORN(p) GC_debug_change_stubborn(p) # define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p) @@ -403,6 +425,8 @@ GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR)); GC_register_finalizer(p, f, d, of, od) # define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \ GC_register_finalizer_ignore_self(p, f, d, of, od) +# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \ + GC_register_finalizer_no_order(p, f, d, of, od) # define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz) # define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p) # define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p) @@ -481,6 +505,16 @@ GC_API void GC_debug_register_finalizer_ignore_self GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, GC_finalization_proc *ofn, GC_PTR *ocd)); +/* Another version of the above. It ignores all cycles. */ +/* It should probably only be used by Java implementations. */ +GC_API void GC_register_finalizer_no_order + GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, + GC_finalization_proc *ofn, GC_PTR *ocd)); +GC_API void GC_debug_register_finalizer_no_order + GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, + GC_finalization_proc *ofn, GC_PTR *ocd)); + + /* The following routine may be used to break cycles between */ /* finalizable objects, thus causing cyclic finalizable */ /* objects to be finalized in the correct order. Standard */ @@ -537,6 +571,9 @@ GC_API int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */)); GC_API GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data)); GC_API void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data)); +/* Returns !=0 if GC_invoke_finalizers has something to do. */ +GC_API int GC_should_invoke_finalizers GC_PROTO((void)); + GC_API int GC_invoke_finalizers GC_PROTO((void)); /* Run finalizers for all objects that are ready to */ /* be finalized. Return the number of finalizers */ @@ -700,7 +737,8 @@ GC_API void (*GC_is_visible_print_proc) # endif /* SOLARIS_THREADS */ -#if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS) +#if !defined(USE_LD_WRAP) && \ + (defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS)) /* We treat these similarly. */ # include # include @@ -714,8 +752,9 @@ GC_API void (*GC_is_visible_print_proc) # define pthread_create GC_pthread_create # define pthread_sigmask GC_pthread_sigmask # define pthread_join GC_pthread_join +# define dlopen GC_dlopen -#endif /* IRIX_THREADS || LINUX_THREADS */ +#endif /* xxxxx_THREADS */ # if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \ defined(IRIX_THREADS) || defined(LINUX_THREADS) || \ diff --git a/boehm-gc/include/gc_cpp.h b/boehm-gc/include/gc_cpp.h index ad7df5d71fa..36013e135b9 100644 --- a/boehm-gc/include/gc_cpp.h +++ b/boehm-gc/include/gc_cpp.h @@ -16,12 +16,11 @@ the code was modified is included with the above copyright notice. C++ Interface to the Boehm Collector John R. Ellis and Jesse Hull - Last modified on Mon Jul 24 15:43:42 PDT 1995 by ellis This interface provides access to the Boehm collector. It provides basic facilities similar to those described in "Safe, Efficient Garbage Collection for C++", by John R. Elis and David L. Detlefs -(ftp.parc.xerox.com:/pub/ellis/gc). +(ftp://ftp.parc.xerox.com/pub/ellis/gc). All heap-allocated objects are either "collectable" or "uncollectable". Programs must explicitly delete uncollectable @@ -38,7 +37,7 @@ Objects derived from class "gc" are collectable. For example: A* a = new A; // a is collectable. Collectable instances of non-class types can be allocated using the GC -placement: +(or UseGC) placement: typedef int A[ 10 ]; A* a = new (GC) A; @@ -124,6 +123,12 @@ invoked using the ANSI-conforming syntax t->~T(). If you're using cfront 3.0, you'll have to comment out the class gc_cleanup, which uses explicit invocation. +5. GC name conflicts: + +Many other systems seem to use the identifier "GC" as an abbreviation +for "Graphics Context". Since version 5.0, GC placement has been replaced +by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined. + ****************************************************************************/ #include "gc.h" @@ -138,7 +143,11 @@ uses explicit invocation. # define OPERATOR_NEW_ARRAY #endif -enum GCPlacement {GC, NoGC, PointerFreeGC}; +enum GCPlacement {UseGC, +#ifndef GC_NAME_CONFLICT + GC=UseGC, +#endif + NoGC, PointerFreeGC}; class gc {public: inline void* operator new( size_t size ); @@ -211,7 +220,7 @@ inline void* gc::operator new( size_t size ) { return GC_MALLOC( size );} inline void* gc::operator new( size_t size, GCPlacement gcp ) { - if (gcp == GC) + if (gcp == UseGC) return GC_MALLOC( size ); else if (gcp == PointerFreeGC) return GC_MALLOC_ATOMIC( size ); @@ -261,7 +270,7 @@ inline void* operator new( { void* obj; - if (gcp == GC) { + if (gcp == UseGC) { obj = GC_MALLOC( size ); if (cleanup != 0) GC_REGISTER_FINALIZER_IGNORE_SELF( diff --git a/boehm-gc/include/gc_typed.h b/boehm-gc/include/gc_typed.h index e4a6b94756e..2e0598f204c 100644 --- a/boehm-gc/include/gc_typed.h +++ b/boehm-gc/include/gc_typed.h @@ -61,6 +61,7 @@ GC_API GC_PTR GC_malloc_explicitly_typed GC_PROTO((size_t size_in_bytes, GC_descr d)); /* Allocate an object whose layout is described by d. */ /* The resulting object MAY NOT BE PASSED TO REALLOC. */ + /* The returned object is cleared. */ GC_API GC_PTR GC_malloc_explicitly_typed_ignore_off_page GC_PROTO((size_t size_in_bytes, GC_descr d)); @@ -75,6 +76,7 @@ GC_API GC_PTR GC_calloc_explicitly_typed /* alignment required for pointers. E.g. on a 32-bit */ /* machine with 16-bit aligned pointers, size_in_bytes */ /* must be a multiple of 2. */ + /* Returned object is cleared. */ #ifdef GC_DEBUG # define GC_MALLOC_EXPLICTLY_TYPED(bytes, d) GC_MALLOC(bytes) diff --git a/boehm-gc/include/private/gc_priv.h b/boehm-gc/include/private/gc_priv.h index ac4d63a0b26..eabb85f0c20 100644 --- a/boehm-gc/include/private/gc_priv.h +++ b/boehm-gc/include/private/gc_priv.h @@ -44,7 +44,7 @@ typedef GC_word word; typedef GC_signed_word signed_word; -# ifndef CONFIG_H +# ifndef GCCONFIG_H # include "gcconfig.h" # endif @@ -82,6 +82,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ # define GC_FAR #endif + /*********************************/ /* */ /* Definitions for conservative */ @@ -173,15 +174,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ /* May save significant amounts of space for obj_map */ /* entries. */ -#ifndef OLD_BLOCK_ALLOC - /* Macros controlling large block allocation strategy. */ -# define EXACT_FIRST /* Make a complete pass through the large object */ - /* free list before splitting a block */ -# define PRESERVE_LAST /* Do not divide last allocated heap segment */ - /* unless we would otherwise need to expand the */ - /* heap. */ -#endif - /* ALIGN_DOUBLE requires MERGE_SIZES at present. */ # if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES) # define MERGE_SIZES @@ -281,6 +273,13 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); # define MS_TIME_DIFF(a,b) ((double) (a.tv_sec - b.tv_sec) * 1000.0 \ + (double) (a.tv_usec - b.tv_usec) / 1000.0) #else /* !BSD_TIME */ +# ifdef MSWIN32 +# include +# include +# define CLOCK_TYPE DWORD +# define GET_TIME(x) x = GetTickCount() +# define MS_TIME_DIFF(a,b) ((long)((a)-(b))) +# else /* !MSWIN32, !BSD_TIME */ # include # if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4) clock_t clock(); /* Not in time.h, where it belongs */ @@ -306,6 +305,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); # define GET_TIME(x) x = clock() # define MS_TIME_DIFF(a,b) ((unsigned long) \ (1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC)) +# endif /* !MSWIN32 */ #endif /* !BSD_TIME */ /* We use bzero and bcopy internally. They may not be available. */ @@ -437,8 +437,11 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); # define LOCK() mutex_lock(&GC_allocate_ml); # define UNLOCK() mutex_unlock(&GC_allocate_ml); # endif -# ifdef LINUX_THREADS +# if defined(LINUX_THREADS) +# if defined(I386)|| defined(POWERPC) || defined(ALPHA) || defined(IA64) \ + || defined(M68K) # include +# define USE_SPIN_LOCK # if defined(I386) inline static int GC_test_and_set(volatile unsigned int *addr) { int oldval; @@ -448,9 +451,38 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); : "0"(1), "m"(*(addr))); return oldval; } -# else -# if defined(POWERPC) +# endif +# if defined(IA64) inline static int GC_test_and_set(volatile unsigned int *addr) { + int oldval; + __asm__ __volatile__("xchg4 %0=%1,%2" + : "=r"(oldval), "=m"(*addr) + : "r"(1), "1"(*addr)); + return oldval; + } + inline static void GC_clear(volatile unsigned int *addr) { + __asm__ __volatile__("st4.rel %0=r0" : "=m" (*addr)); + } +# define GC_CLEAR_DEFINED +# endif +# ifdef M68K + /* Contributed by Tony Mantler. I'm not sure how well it was */ + /* tested. */ + inline static int GC_test_and_set(volatile unsigned int *addr) { + char oldval; /* this must be no longer than 8 bits */ + + /* The return value is semi-phony. */ + /* 'tas' sets bit 7 while the return */ + /* value pretends bit 0 was set */ + __asm__ __volatile__( + "tas %1@; sne %0; negb %0" + : "=d" (oldval) + : "a" (addr)); + return oldval; + } +# endif +# if defined(POWERPC) + inline static int GC_test_and_set(volatile unsigned int *addr) { int oldval; int temp = 1; // locked value @@ -465,46 +497,61 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); : "r"(temp), "1"(addr) : "memory"); return (int)oldval; - } -# else -# ifdef ALPHA - inline static int GC_test_and_set(volatile unsigned int * -addr) - { - unsigned long oldvalue; - unsigned long temp; - - __asm__ __volatile__( - "1: ldl_l %0,%1\n" - " and %0,%3,%2\n" - " bne %2,2f\n" - " xor %0,%3,%0\n" - " stl_c %0,%1\n" - " beq %0,3f\n" - " mb\n" - "2:\n" - ".section .text2,\"ax\"\n" - "3: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (*addr), "=&r" -(oldvalue) - :"Ir" (1), "m" (*addr)); - - return oldvalue; - } -# else - -- > Need implementation of GC_test_and_set() -# endif -# endif + } + inline static void GC_clear(volatile unsigned int *addr) { + __asm__ __volatile__("eieio"); + *(addr) = 0; + } +# define GC_CLEAR_DEFINED # endif - inline static void GC_clear(volatile unsigned int *addr) { +# ifdef ALPHA + inline static int GC_test_and_set(volatile unsigned int * addr) + { + unsigned long oldvalue; + unsigned long temp; + + __asm__ __volatile__( + "1: ldl_l %0,%1\n" + " and %0,%3,%2\n" + " bne %2,2f\n" + " xor %0,%3,%0\n" + " stl_c %0,%1\n" + " beq %0,3f\n" + " mb\n" + "2:\n" + ".section .text2,\"ax\"\n" + "3: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (*addr), "=&r" (oldvalue) + :"Ir" (1), "m" (*addr)); + + return oldvalue; + } + /* Should probably also define GC_clear, since it needs */ + /* a memory barrier ?? */ +# endif /* ALPHA */ +# ifdef ARM32 + inline static int GC_test_and_set(volatile unsigned int *addr) { + int oldval; + /* SWP on ARM is very similar to XCHG on x86. Doesn't lock the + * bus because there are no SMP ARM machines. If/when there are, + * this code will likely need to be updated. */ + /* See linuxthreads/sysdeps/arm/pt-machine.h in glibc-2.1 */ + __asm__ __volatile__("swp %0, %1, [%2]" + : "=r"(oldval) + : "r"(1), "r"(addr)); + return oldval; + } +# endif +# ifndef GC_CLEAR_DEFINED + inline static void GC_clear(volatile unsigned int *addr) { + /* Try to discourage gcc from moving anything past this. */ + __asm__ __volatile__(" "); *(addr) = 0; - } + } +# endif extern volatile unsigned int GC_allocate_lock; - /* This is not a mutex because mutexes that obey the (optional) */ - /* POSIX scheduling rules are subject to convoys in high contention */ - /* applications. This is basically a spin lock. */ extern pthread_t GC_lock_holder; extern void GC_lock(void); /* Allocation lock holder. Only set if acquired by client through */ @@ -517,12 +564,19 @@ addr) { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } # define UNLOCK() \ GC_clear(&GC_allocate_lock) - extern GC_bool GC_collecting; + extern VOLATILE GC_bool GC_collecting; # define ENTER_GC() \ { \ GC_collecting = 1; \ } # define EXIT_GC() GC_collecting = 0; +# else /* LINUX_THREADS on hardware for which we don't know how */ + /* to do test and set. */ +# include + extern pthread_mutex_t GC_allocate_ml; +# define LOCK() pthread_mutex_lock(&GC_allocate_ml) +# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) +# endif # endif /* LINUX_THREADS */ # if defined(HPUX_THREADS) # include @@ -581,7 +635,7 @@ addr) *(volatile unsigned long *)(&GC_allocate_lock) = 0; } # endif # endif - extern GC_bool GC_collecting; + extern VOLATILE GC_bool GC_collecting; # define ENTER_GC() \ { \ GC_collecting = 1; \ @@ -957,8 +1011,10 @@ struct hblk { /* The type of mark procedures. This really belongs in gc_mark.h. */ /* But we put it here, so that we can avoid scanning the mark proc */ /* table. */ -typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr, - mark_stack_limit, env */); +typedef struct ms_entry * (*mark_proc)(/* word * addr, + struct ms_entry *mark_stack_ptr, + struct ms_entry *mark_stack_limit, + word env */); # define LOG_MAX_MARK_PROCS 6 # define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS) @@ -1035,6 +1091,7 @@ struct roots { struct _GC_arrays { word _heapsize; word _max_heapsize; + word _requested_heapsize; /* Heap size due to explicit expansion */ ptr_t _last_heap_addr; ptr_t _prev_heap_addr; word _large_free_bytes; @@ -1059,6 +1116,10 @@ struct _GC_arrays { word _mem_freed; /* Number of explicitly deallocated words of memory */ /* since last collection. */ + ptr_t _scratch_end_ptr; + ptr_t _scratch_last_end_ptr; + /* Used by headers.c, and can easily appear to point to */ + /* heap. */ mark_proc _mark_procs[MAX_MARK_PROCS]; /* Table of user-defined mark procedures. There is */ /* a small number of these, which can be referenced */ @@ -1223,9 +1284,12 @@ GC_API GC_FAR struct _GC_arrays GC_arrays; # define GC_words_finalized GC_arrays._words_finalized # define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc # define GC_mem_freed GC_arrays._mem_freed +# define GC_scratch_end_ptr GC_arrays._scratch_end_ptr +# define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr # define GC_mark_procs GC_arrays._mark_procs # define GC_heapsize GC_arrays._heapsize # define GC_max_heapsize GC_arrays._max_heapsize +# define GC_requested_heapsize GC_arrays._requested_heapsize # define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc # define GC_heap_sects GC_arrays._heap_sects # define GC_last_stack GC_arrays._last_stack @@ -1260,6 +1324,8 @@ GC_API GC_FAR struct _GC_arrays GC_arrays; # define beginGC_arrays ((ptr_t)(&GC_arrays)) # define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays)) +#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes) + /* Object kinds: */ # define MAXOBJKINDS 16 @@ -1392,10 +1458,7 @@ extern ptr_t GC_greatest_plausible_heap_addr; ptr_t GC_approx_sp(); GC_bool GC_should_collect(); -#ifdef PRESERVE_LAST - GC_bool GC_in_last_heap_sect(/* ptr_t */); - /* In last added heap section? If so, avoid breaking up. */ -#endif + void GC_apply_to_all_blocks(/*fn, client_data*/); /* Invoke fn(hbp, client_data) for each */ /* allocated heap block. */ @@ -1672,9 +1735,10 @@ ptr_t GC_allocobj(/* sz_inn_words, kind */); /* head. */ void GC_init_headers(); -GC_bool GC_install_header(/*h*/); +struct hblkhdr * GC_install_header(/*h*/); /* Install a header for block h. */ - /* Return FALSE on failure. */ + /* Return 0 on failure, or the header */ + /* otherwise. */ GC_bool GC_install_counts(/*h, sz*/); /* Set up forwarding counts for block */ /* h of size sz. */ diff --git a/boehm-gc/include/private/gcconfig.h b/boehm-gc/include/private/gcconfig.h index c9017d371a8..4c4bca31222 100644 --- a/boehm-gc/include/private/gcconfig.h +++ b/boehm-gc/include/private/gcconfig.h @@ -13,9 +13,9 @@ * modified is included with the above copyright notice. */ -#ifndef CONFIG_H +#ifndef GCCONFIG_H -# define CONFIG_H +# define GCCONFIG_H /* Machine dependent parameters. Some tuning parameters can be found */ /* near the top of gc_private.h. */ @@ -53,6 +53,11 @@ # define NETBSD # define mach_type_known # endif +# if defined(__NetBSD__) && defined(arm32) +# define ARM32 +# define NETBSD +# define mach_type_known +# endif # if defined(vax) # define VAX # ifdef ultrix @@ -64,15 +69,18 @@ # endif # if defined(mips) || defined(__mips) # define MIPS -# if defined(ultrix) || defined(__ultrix) || defined(__NetBSD__) -# define ULTRIX -# else -# if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__) -# define IRIX5 /* or IRIX 6.X */ -# else -# define RISCOS /* or IRIX 4.X */ -# endif -# endif +# if !defined(LINUX) +# if defined(ultrix) || defined(__ultrix) || defined(__NetBSD__) +# define ULTRIX +# else +# if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) \ + || defined(__SYSTYPE_SVR4__) +# define IRIX5 /* or IRIX 6.X */ +# else +# define RISCOS /* or IRIX 4.X */ +# endif +# endif +# endif /* !LINUX */ # define mach_type_known # endif # if defined(sequent) && defined(i386) @@ -130,15 +138,22 @@ # define SYSV # define mach_type_known # endif -# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) \ +# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \ || defined(hppa) || defined(__hppa__) # define HP_PA +# ifndef LINUX +# define HPUX +# endif # define mach_type_known # endif # if defined(LINUX) && (defined(i386) || defined(__i386__)) # define I386 # define mach_type_known # endif +# if defined(LINUX) && (defined(__ia64__) || defined(__ia64)) +# define IA64 +# define mach_type_known +# endif # if defined(LINUX) && defined(powerpc) # define POWERPC # define mach_type_known @@ -147,10 +162,14 @@ # define M68K # define mach_type_known # endif -# if defined(LINUX) && defined(sparc) +# if defined(LINUX) && (defined(sparc) || defined(__sparc__)) # define SPARC # define mach_type_known # endif +# if defined(LINUX) && defined(arm) +# define ARM32 +# define mach_type_known +# endif # if defined(__alpha) || defined(__alpha__) # define ALPHA # if !defined(LINUX) @@ -243,6 +262,11 @@ # define CYGWIN32 # define mach_type_known # endif +# if defined(__MINGW32__) +# define I386 +# define MSWIN32 +# define mach_type_known +# endif # if defined(__BORLANDC__) # define I386 # define MSWIN32 @@ -253,6 +277,10 @@ # define UTS4 # define mach_type_known # endif +# if defined(__pj__) +# define PJ +# define mach_type_known +# endif /* Ivan Demakov */ # if defined(__WATCOMC__) && defined(__386__) # define I386 @@ -307,6 +335,9 @@ /* (CX_UX and DGUX) */ /* S370 ==> 370-like machine */ /* running Amdahl UTS4 */ + /* ARM32 ==> Intel StrongARM */ + /* IA64 ==> Intel IA64 */ + /* (e.g. Itanium) */ /* @@ -392,6 +423,15 @@ * * An architecture may define DYNAMIC_LOADING if dynamic_load.c * defined GC_register_dynamic_libraries() for the architecture. + * + * An architecture may define PREFETCH(x) to preload the cache with *x. + * This defaults to a no-op. + * + * PREFETCH_FOR_WRITE(x) is used if *x is about to be written. + * + * An architecture may also define CLEAR_DOUBLE(x) to be a fast way to + * clear the two words at GC_malloc-aligned address x. By default, + * word stores of 0 are used instead. */ @@ -516,7 +556,7 @@ # undef STACK_GRAN # define STACK_GRAN 0x10000000 /* Stack usually starts at 0x80000000 */ -# define DATASTART GC_data_start +# define LINUX_DATA_START extern int _end; # define DATAEND (&_end) # endif @@ -615,8 +655,8 @@ # ifdef LINUX # define OS_TYPE "LINUX" # ifdef __ELF__ -# define DATASTART GC_data_start -# define DYNAMIC_LOADING +# define LINUX_DATA_START +# define DYNAMIC_LOADING # else Linux Sparc non elf ? # endif @@ -684,13 +724,16 @@ # endif # ifdef LINUX # define OS_TYPE "LINUX" -# define HEURISTIC1 -# undef STACK_GRAN -# define STACK_GRAN 0x10000000 - /* STACKBOTTOM is usually 0xc0000000, but this changes with */ - /* different kernel configurations. In particular, systems */ - /* with 2GB physical memory will usually move the user */ - /* address space limit, and hence initial SP to 0x80000000. */ +# define LINUX_STACKBOTTOM +# if 0 +# define HEURISTIC1 +# undef STACK_GRAN +# define STACK_GRAN 0x10000000 + /* STACKBOTTOM is usually 0xc0000000, but this changes with */ + /* different kernel configurations. In particular, systems */ + /* with 2GB physical memory will usually move the user */ + /* address space limit, and hence initial SP to 0x80000000. */ +# endif # if !defined(LINUX_THREADS) || !defined(REDIRECT_MALLOC) # define MPROTECT_VDB # else @@ -706,8 +749,7 @@ # endif # include # if defined(__GLIBC__) && __GLIBC__ >= 2 - extern int __data_start; -# define DATASTART ((ptr_t)(&__data_start)) +# define LINUX_DATA_START # else extern char **__environ; # define DATASTART ((ptr_t)(&__environ)) @@ -726,6 +768,26 @@ extern int etext; # define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) # endif +# ifdef USE_I686_PREFETCH +# define PREFETCH(x) \ + __asm__ __volatile__ (" prefetchnta %0": : "m"(*(char *)(x))) + /* Empirically prefetcht0 is much more effective at reducing */ + /* cache miss stalls for the targetted load instructions. But it */ + /* seems to interfere enough with other cache traffic that the net */ + /* result is worse than prefetchnta. */ +# if 0 + /* Using prefetches for write seems to have a slight negative */ + /* impact on performance, at least for a PIII/500. */ +# define PREFETCH_FOR_WRITE(x) \ + __asm__ __volatile__ (" prefetcht0 %0": : "m"(*(char *)(x))) +# endif +# endif +# ifdef USE_3DNOW_PREFETCH +# define PREFETCH(x) \ + __asm__ __volatile__ (" prefetch %0": : "m"(*(char *)(x))) +# define PREFETCH_FOR_WRITE(x) + __asm__ __volatile__ (" prefetchw %0": : "m"(*(char *)(x))) +# endif # endif # ifdef CYGWIN32 # define OS_TYPE "CYGWIN32" @@ -836,35 +898,48 @@ # ifdef MIPS # define MACH_TYPE "MIPS" -# ifndef IRIX5 -# define DATASTART (ptr_t)0x10000000 - /* Could probably be slightly higher since */ - /* startup code allocates lots of stuff. */ -# else - extern int _fdata; -# define DATASTART ((ptr_t)(&_fdata)) -# ifdef USE_MMAP -# define HEAP_START (ptr_t)0x30000000 -# else -# define HEAP_START DATASTART -# endif - /* Lowest plausible heap address. */ - /* In the MMAP case, we map there. */ - /* In either case it is used to identify */ - /* heap sections so they're not */ - /* considered as roots. */ -# endif /* IRIX5 */ -# define HEURISTIC2 /* # define STACKBOTTOM ((ptr_t)0x7fff8000) sometimes also works. */ +# ifdef LINUX + /* This was developed for a linuxce style platform. Probably */ + /* needs to be tweaked for workstation class machines. */ +# define OS_TYPE "LINUX" + extern int __data_start; +# define DATASTART ((ptr_t)(&__data_start)) +# define ALIGNMENT 4 +# define USE_GENERIC_PUSH_REGS 1 +# define STACKBOTTOM 0x80000000 + /* In many cases, this should probably use LINUX_STACKBOTTOM */ + /* instead. But some kernel versions seem to give the wrong */ + /* value from /proc. */ +# endif /* Linux */ # ifdef ULTRIX +# define HEURISTIC2 +# define DATASTART (ptr_t)0x10000000 + /* Could probably be slightly higher since */ + /* startup code allocates lots of stuff. */ # define OS_TYPE "ULTRIX" # define ALIGNMENT 4 # endif # ifdef RISCOS +# define HEURISTIC2 +# define DATASTART (ptr_t)0x10000000 # define OS_TYPE "RISCOS" # define ALIGNMENT 4 /* Required by hardware */ # endif # ifdef IRIX5 +# define HEURISTIC2 + extern int _fdata; +# define DATASTART ((ptr_t)(&_fdata)) +# ifdef USE_MMAP +# define HEAP_START (ptr_t)0x30000000 +# else +# define HEAP_START DATASTART +# endif + /* Lowest plausible heap address. */ + /* In the MMAP case, we map there. */ + /* In either case it is used to identify */ + /* heap sections so they're not */ + /* considered as roots. */ # define OS_TYPE "IRIX5" # define MPROTECT_VDB # ifdef _MIPS_SZPTR @@ -892,9 +967,17 @@ # endif # ifdef HP_PA + /* OS is assumed to be HP/UX */ # define MACH_TYPE "HP_PA" -# define ALIGNMENT 4 -# define ALIGN_DOUBLE +# define OS_TYPE "HPUX" +# ifdef __LP64__ +# define CPP_WORDSZ 64 +# define ALIGNMENT 8 +# else +# define CPP_WORDSZ 32 +# define ALIGNMENT 4 +# define ALIGN_DOUBLE +# endif extern int __data_start; # define DATASTART ((ptr_t)(&__data_start)) # if 0 @@ -911,14 +994,21 @@ # endif # define STACK_GROWS_UP # define DYNAMIC_LOADING +# ifndef HPUX_THREADS +# define MPROTECT_VDB +# endif # include # define GETPAGESIZE() sysconf(_SC_PAGE_SIZE) - /* They misspelled the Posix macro? */ # endif # ifdef ALPHA # define MACH_TYPE "ALPHA" # define ALIGNMENT 8 +# define USE_GENERIC_PUSH_REGS + /* Gcc and probably the DEC/Compaq compiler spill pointers to preserved */ + /* fp registers in some cases when the target is a 21264. The assembly */ + /* code doesn't handle that yet, and version dependencies make that a */ + /* bit tricky. Do the easy thing for now. */ # ifdef OSF1 # define OS_TYPE "OSF1" # define DATASTART ((ptr_t) 0x140000000) @@ -939,13 +1029,9 @@ # define CPP_WORDSZ 64 # define STACKBOTTOM ((ptr_t) 0x120000000) # ifdef __ELF__ -# if 0 - /* __data_start apparently disappeared in some recent releases. */ - extern int __data_start; -# define DATASTART &__data_start -# endif -# define DATASTART GC_data_start +# define LINUX_DATA_START # define DYNAMIC_LOADING + /* This doesn't work if the collector is in a dynamic library. */ # else # define DATASTART ((ptr_t) 0x140000000) # endif @@ -957,6 +1043,49 @@ # endif # endif +# ifdef IA64 +# define MACH_TYPE "IA64" +# define ALIGN_DOUBLE + /* Requires 16 byte alignment for malloc */ +# define ALIGNMENT 8 +# define USE_GENERIC_PUSH_REGS + /* We need to get preserved registers in addition to register windows. */ + /* That's easiest to do with setjmp. */ +# ifdef HPUX + --> needs work +# endif +# ifdef LINUX +# define OS_TYPE "LINUX" +# define CPP_WORDSZ 64 + /* This should really be done through /proc, but that */ + /* requires we run on an IA64 kernel. */ +# define STACKBOTTOM ((ptr_t) 0xa000000000000000l) + /* We also need the base address of the register stack */ + /* backing store. There is probably a better way to */ + /* get that, too ... */ +# define BACKING_STORE_BASE ((ptr_t) 0x9fffffff80000000l) +# if 1 +# define SEARCH_FOR_DATA_START +# define DATASTART GC_data_start +# else + extern int data_start; +# define DATASTART ((ptr_t)(&data_start)) +# endif +# define DYNAMIC_LOADING +# define MPROTECT_VDB + /* Requires Linux 2.3.47 or later. */ + extern int _end; +# define DATAEND (&_end) + /* PREFETCH appears to have a large performance impact. */ +# define PREFETCH(x) \ + __asm__ (" lfetch [%0]": : "r"((void *)(x))) +# define PREFETCH_FOR_WRITE(x) \ + __asm__ (" lfetch.excl [%0]": : "r"((void *)(x))) +# define CLEAR_DOUBLE(x) \ + __asm__ (" stf.spill [%0]=f0": : "r"((void *)(x))) +# endif +# endif + # ifdef M88K # define MACH_TYPE "M88K" # define ALIGNMENT 4 @@ -987,6 +1116,69 @@ # define HEURISTIC2 # endif +# if defined(PJ) +# define ALIGNMENT 4 + extern int _etext; +# define DATASTART ((ptr_t)(&_etext)) +# define HEURISTIC1 +# endif + +# ifdef ARM32 +# define CPP_WORDSZ 32 +# define MACH_TYPE "ARM32" +# define ALIGNMENT 4 +# ifdef NETBSD +# define OS_TYPE "NETBSD" +# define HEURISTIC2 + extern char etext; +# define DATASTART ((ptr_t)(&etext)) +# define USE_GENERIC_PUSH_REGS +# endif +# ifdef LINUX +# define OS_TYPE "LINUX" +# define HEURISTIC1 +# undef STACK_GRAN +# define STACK_GRAN 0x10000000 +# define USE_GENERIC_PUSH_REGS +# ifdef __ELF__ +# define DYNAMIC_LOADING +# include +# if defined(__GLIBC__) && __GLIBC__ >= 2 +# define LINUX_DATA_START +# else + 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. */ + /* We could use _etext instead, but that */ + /* would include .rodata, which may */ + /* contain large read-only data tables */ + /* that we'd rather not scan. */ +# endif + extern int _end; +# define DATAEND (&_end) +# else + extern int etext; +# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) +# endif +# endif +#endif + +#ifdef LINUX_DATA_START + /* Some Linux distributions arrange to define __data_start. Some */ + /* define data_start as a weak symbol. The latter is technically */ + /* broken, since the user program may define data_start, in which */ + /* case we lose. Nonetheless, we try both, prefering __data_start. */ + /* We assume gcc. */ +# pragma weak __data_start + extern int __data_start; +# pragma weak data_start + extern int data_start; +# define DATASTART ((ptr_t)(&__data_start != 0? &__data_start : &data_start)) +#endif + # ifndef STACK_GROWS_UP # define STACK_GROWS_DOWN # endif @@ -1029,6 +1221,10 @@ # define SUNOS5SIGS # endif +# if defined(HPUX) +# define SUNOS5SIGS +# endif + # if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 -> bad word size # endif @@ -1063,6 +1259,26 @@ # define DEFAULT_VDB # endif +# ifndef PREFETCH +# define PREFETCH(x) +# define NO_PREFETCH +# endif + +# ifndef PREFETCH_FOR_WRITE +# define PREFETCH_FOR_WRITE(x) +# define NO_PREFETCH_FOR_WRITE +# endif + +# ifndef CACHE_LINE_SIZE +# define CACHE_LINE_SIZE 32 /* Wild guess */ +# endif + +# ifndef CLEAR_DOUBLE +# define CLEAR_DOUBLE(x) \ + ((word*)x)[0] = 0; \ + ((word*)x)[1] = 0; +# endif /* CLEAR_DOUBLE */ + # if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS) # define SOLARIS_THREADS # endif @@ -1078,10 +1294,13 @@ # if defined(SOLARIS_THREADS) && !defined(SUNOS5) --> inconsistent configuration # endif +# if defined(HPUX_THREADS) && !defined(HPUX) +--> inconsistent configuration +# endif # if defined(PCR) || defined(SRC_M3) || \ defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \ defined(IRIX_THREADS) || defined(LINUX_THREADS) || \ - defined(IRIX_JDK_THREADS) + defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS) # define THREADS # endif @@ -1096,4 +1315,4 @@ /* include assembly code to do it well. */ # endif -# endif +# endif /* GCCONFIG_H */ diff --git a/boehm-gc/linux_threads.c b/boehm-gc/linux_threads.c index 8287dce647b..7670268ec22 100644 --- a/boehm-gc/linux_threads.c +++ b/boehm-gc/linux_threads.c @@ -36,16 +36,26 @@ # if defined(LINUX_THREADS) # include +# include # include # include # include # include # include # include +# include + +#ifdef USE_LD_WRAP +# define WRAP_FUNC(f) __wrap_##f +# define REAL_FUNC(f) __real_##f +#else +# define WRAP_FUNC(f) GC_##f +# define REAL_FUNC(f) f +# undef pthread_create +# undef pthread_sigmask +# undef pthread_join +#endif -#undef pthread_create -#undef pthread_sigmask -#undef pthread_join void GC_thr_init(); @@ -86,8 +96,12 @@ typedef struct GC_Thread_Rep { # define DETACHED 2 /* Thread is intended to be detached. */ # define MAIN_THREAD 4 /* True for the original thread only. */ - ptr_t stack_end; - ptr_t stack_ptr; /* Valid only when stopped. */ + ptr_t stack_end; /* Cold end of the stack. */ + ptr_t stack_ptr; /* Valid only when stopped. */ +# ifdef IA64 + ptr_t backing_store_end; + ptr_t backing_store_ptr; +# endif int signal; void * status; /* The value returned from the thread. */ /* Used only to avoid premature */ @@ -138,6 +152,10 @@ static inline ptr_t GC_linux_thread_top_of_stack(void) return tos; } +#ifdef IA64 + extern word GC_save_regs_in_stack(); +#endif + void GC_suspend_handler(int sig) { int dummy; @@ -160,7 +178,9 @@ void GC_suspend_handler(int sig) /* to stop the world. Thus concurrent modification of the */ /* data structure is impossible. */ me -> stack_ptr = (ptr_t)(&dummy); - me -> stack_end = GC_linux_thread_top_of_stack(); +# ifdef IA64 + me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack(); +# endif /* Tell the thread that wants to stop the world that this */ /* thread has been stopped. Note that sem_post() is */ @@ -173,6 +193,10 @@ void GC_suspend_handler(int sig) /* is no race. */ if (sigfillset(&mask) != 0) ABORT("sigfillset() failed"); if (sigdelset(&mask, SIG_RESTART) != 0) ABORT("sigdelset() failed"); +# ifdef NO_SIGNALS + if (sigdelset(&mask, SIGINT) != 0) ABORT("sigdelset() failed"); + if (sigdelset(&mask, SIGQUIT) != 0) ABORT("sigdelset() failed"); +# endif do { me->signal = 0; sigsuspend(&mask); /* Wait for signal */ @@ -375,13 +399,21 @@ void GC_start_world() #endif } -/* We hold allocation lock. We assume the world is stopped. */ +# ifdef IA64 +# define IF_IA64(x) x +# else +# define IF_IA64(x) +# endif +/* We hold allocation lock. Should do exactly the right thing if the */ +/* world is stopped. Should not fail if it isn't. */ void GC_push_all_stacks() { - register int i; - register GC_thread p; - register ptr_t sp = GC_approx_sp(); - register ptr_t lo, hi; + int i; + GC_thread p; + ptr_t sp = GC_approx_sp(); + ptr_t lo, hi; + /* On IA64, we also need to scan the register backing store. */ + IF_IA64(ptr_t bs_lo; ptr_t bs_hi;) pthread_t me = pthread_self(); if (!GC_thr_initialized) GC_thr_init(); @@ -393,25 +425,33 @@ void GC_push_all_stacks() if (p -> flags & FINISHED) continue; if (pthread_equal(p -> id, me)) { lo = GC_approx_sp(); + IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();) } else { lo = p -> stack_ptr; + IF_IA64(bs_hi = p -> backing_store_ptr;) } if ((p -> flags & MAIN_THREAD) == 0) { - if (pthread_equal(p -> id, me)) { - hi = GC_linux_thread_top_of_stack(); - } else { - hi = p -> stack_end; - } + hi = p -> stack_end; + IF_IA64(bs_lo = p -> backing_store_end); } else { /* The original stack. */ hi = GC_stackbottom; + IF_IA64(bs_lo = BACKING_STORE_BASE;) } #if DEBUG_THREADS GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n", (unsigned long) p -> id, (unsigned long) lo, (unsigned long) hi); #endif + if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n"); GC_push_all_stack(lo, hi); +# ifdef IA64 + if (pthread_equal(p -> id, me)) { + GC_push_all_eager(bs_lo, bs_hi); + } else { + GC_push_all_stack(bs_lo, bs_hi); + } +# endif } } } @@ -420,6 +460,7 @@ void GC_push_all_stacks() /* We hold the allocation lock. */ void GC_thr_init() { + int dummy; GC_thread t; struct sigaction act; @@ -433,6 +474,13 @@ void GC_thr_init() if (sigfillset(&act.sa_mask) != 0) { ABORT("sigfillset() failed"); } +# ifdef NO_SIGNALS + if (sigdelset(&act.sa_mask, SIGINT) != 0 + || sigdelset(&act.sa_mask, SIGQUIT != 0)) { + ABORT("sigdelset() failed"); + } +# endif + /* SIG_RESTART is unmasked by the handler when necessary. */ act.sa_handler = GC_suspend_handler; if (sigaction(SIG_SUSPEND, &act, NULL) != 0) { @@ -446,11 +494,11 @@ void GC_thr_init() /* Add the initial thread, so we can stop it. */ t = GC_new_thread(pthread_self()); - t -> stack_ptr = 0; + t -> stack_ptr = (ptr_t)(&dummy); t -> flags = DETACHED | MAIN_THREAD; } -int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset) { sigset_t fudged_set; @@ -459,7 +507,7 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) sigdelset(&fudged_set, SIG_SUSPEND); set = &fudged_set; } - return(pthread_sigmask(how, set, oset)); + return(REAL_FUNC(pthread_sigmask)(how, set, oset)); } struct start_info { @@ -483,10 +531,25 @@ void GC_thread_exit_proc(void *arg) } else { me -> flags |= FINISHED; } + if (GC_incremental && GC_collection_in_progress()) { + int old_gc_no = GC_gc_no; + + /* Make sure that no part of our stack is still on the mark stack, */ + /* since it's about to be unmapped. */ + while (GC_incremental && GC_collection_in_progress() + && old_gc_no == GC_gc_no) { + ENTER_GC(); + GC_collect_a_little_inner(1); + EXIT_GC(); + UNLOCK(); + sched_yield(); + LOCK(); + } + } UNLOCK(); } -int GC_pthread_join(pthread_t thread, void **retval) +int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval) { int result; GC_thread thread_gc_id; @@ -496,7 +559,7 @@ int GC_pthread_join(pthread_t thread, void **retval) /* This is guaranteed to be the intended one, since the thread id */ /* cant have been recycled by pthreads. */ UNLOCK(); - result = pthread_join(thread, retval); + result = REAL_FUNC(pthread_join)(thread, retval); LOCK(); /* Here the pthread thread id may have been recycled. */ GC_delete_gc_thread(thread, thread_gc_id); @@ -506,6 +569,7 @@ int GC_pthread_join(pthread_t thread, void **retval) void * GC_start_routine(void * arg) { + int dummy; struct start_info * si = arg; void * result; GC_thread me; @@ -514,22 +578,45 @@ void * GC_start_routine(void * arg) void *start_arg; my_pthread = pthread_self(); +# ifdef DEBUG_THREADS + GC_printf1("Starting thread 0x%lx\n", my_pthread); + GC_printf1("pid = %ld\n", (long) getpid()); + GC_printf1("sp = 0x%lx\n", (long) &arg); +# endif LOCK(); me = GC_new_thread(my_pthread); me -> flags = si -> flags; me -> stack_ptr = 0; - me -> stack_end = 0; + /* me -> stack_end = GC_linux_stack_base(); -- currently (11/99) */ + /* doesn't work because the stack base in /proc/self/stat is the */ + /* one for the main thread. There is a strong argument that that's */ + /* a kernel bug, but a pervasive one. */ +# ifdef STACK_GROWS_DOWN + me -> stack_end = (ptr_t)(((word)(&dummy) + (GC_page_size - 1)) + & ~(GC_page_size - 1)); + me -> stack_ptr = me -> stack_end - 0x10; + /* Needs to be plausible, since an asynchronous stack mark */ + /* should not crash. */ +# else + me -> stack_end = (ptr_t)(((word)(&dummy) & ~(GC_page_size - 1)); + me -> stack_ptr = me -> stack_end + 0x10; +# endif + /* This is dubious, since we may be more than a page into the stack, */ + /* and hence skip some of it, though it's not clear that matters. */ +# ifdef IA64 + me -> backing_store_end = (ptr_t) + (GC_save_regs_in_stack() & ~(GC_page_size - 1)); + /* This is also < 100% convincing. We should also read this */ + /* from /proc, but the hook to do so isn't there yet. */ +# endif /* IA64 */ UNLOCK(); start = si -> start_routine; - start_arg = si -> arg; - sem_post(&(si -> registered)); - pthread_cleanup_push(GC_thread_exit_proc, si); # ifdef DEBUG_THREADS - GC_printf1("Starting thread 0x%lx\n", pthread_self()); - GC_printf1("pid = %ld\n", (long) getpid()); - GC_printf1("sp = 0x%lx\n", (long) &arg); GC_printf1("start_routine = 0x%lx\n", start); # endif + start_arg = si -> arg; + sem_post(&(si -> registered)); + pthread_cleanup_push(GC_thread_exit_proc, si); result = (*start)(start_arg); #if DEBUG_THREADS GC_printf1("Finishing thread 0x%x\n", pthread_self()); @@ -544,7 +631,7 @@ void * GC_start_routine(void * arg) } int -GC_pthread_create(pthread_t *new_thread, +WRAP_FUNC(pthread_create)(pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { @@ -576,7 +663,14 @@ GC_pthread_create(pthread_t *new_thread, if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED; si -> flags = my_flags; UNLOCK(); - result = pthread_create(new_thread, &new_attr, GC_start_routine, si); +# ifdef DEBUG_THREADS + GC_printf1("About to start new thread from thread 0x%X\n", + pthread_self()); +# endif + result = REAL_FUNC(pthread_create)(new_thread, &new_attr, GC_start_routine, si); +# ifdef DEBUG_THREADS + GC_printf1("Started thread 0x%X\n", *new_thread); +# endif /* Wait until child has been added to the thread table. */ /* This also ensures that we hold onto si until the child is done */ /* with it. Thus it doesn't matter whether it is otherwise */ @@ -588,7 +682,9 @@ GC_pthread_create(pthread_t *new_thread, return(result); } -GC_bool GC_collecting = 0; +#if defined(USE_SPIN_LOCK) + +VOLATILE GC_bool GC_collecting = 0; /* A hint that we're in the collector and */ /* holding the allocation lock for an */ /* extended period. */ @@ -661,5 +757,7 @@ yield: } } +#endif /* known architecture */ + # endif /* LINUX_THREADS */ diff --git a/boehm-gc/mach_dep.c b/boehm-gc/mach_dep.c index 52f86346761..12c3f07603f 100644 --- a/boehm-gc/mach_dep.c +++ b/boehm-gc/mach_dep.c @@ -80,6 +80,24 @@ void GC_push_regs() # ifdef RT register long TMP_SP; /* must be bound to r11 */ # endif + +# if defined(MIPS) && defined(LINUX) + /* I'm not sure whether this has actually been tested. */ +# define call_push(x) asm("move $4," x ";"); asm("jal GC_push_one") + call_push("$2"); + call_push("$3"); + call_push("$16"); + call_push("$17"); + call_push("$18"); + call_push("$19"); + call_push("$20"); + call_push("$21"); + call_push("$22"); + call_push("$23"); + call_push("$30"); +# undef call_push +# endif /* MIPS && LINUX */ + # ifdef VAX /* VAX - generic code below does not work under 4.2 */ /* r1 through r5 are caller save, and therefore */ @@ -199,10 +217,11 @@ void GC_push_regs() # endif /* __MWERKS__ */ # endif /* MACOS */ -# if defined(I386) &&!defined(OS2) &&!defined(SVR4) &&!defined(MSWIN32) \ +# if defined(I386) &&!defined(OS2) &&!defined(SVR4) \ + && (defined(__MINGW32__) || !defined(MSWIN32)) \ && !defined(SCO) && !defined(SCO_ELF) \ && !(defined(LINUX) && defined(__ELF__)) \ - && !(defined(__FreeBSD__) && defined(__ELF__)) \ + && !(defined(FREEBSD) && defined(__ELF__)) \ && !defined(DOS4GW) /* I386 code, generic code does not appear to work */ /* It does appear to work under OS2, and asms dont */ @@ -217,20 +236,25 @@ void GC_push_regs() # endif # if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \ - || ( defined(I386) && defined(__FreeBSD__) && defined(__ELF__) ) + || ( defined(I386) && defined(FREEBSD) && defined(__ELF__) ) /* This is modified for Linux with ELF (Note: _ELF_ only) */ /* This section handles FreeBSD with ELF. */ - asm("pushl %eax"); asm("call GC_push_one"); asm("addl $4,%esp"); - asm("pushl %ecx"); asm("call GC_push_one"); asm("addl $4,%esp"); - asm("pushl %edx"); asm("call GC_push_one"); asm("addl $4,%esp"); - asm("pushl %ebp"); asm("call GC_push_one"); asm("addl $4,%esp"); - asm("pushl %esi"); asm("call GC_push_one"); asm("addl $4,%esp"); - asm("pushl %edi"); asm("call GC_push_one"); asm("addl $4,%esp"); - asm("pushl %ebx"); asm("call GC_push_one"); asm("addl $4,%esp"); + /* Eax is caller-save and dead here. Other caller-save */ + /* registers could also be skipped. We assume there are no */ + /* pointers in MMX registers, etc. */ + /* We combine instructions in a single asm to prevent gcc from */ + /* inserting code in the middle. */ + asm("pushl %ecx; call GC_push_one; addl $4,%esp"); + asm("pushl %edx; call GC_push_one; addl $4,%esp"); + asm("pushl %ebp; call GC_push_one; addl $4,%esp"); + asm("pushl %esi; call GC_push_one; addl $4,%esp"); + asm("pushl %edi; call GC_push_one; addl $4,%esp"); + asm("pushl %ebx; call GC_push_one; addl $4,%esp"); # endif -# if defined(I386) && defined(MSWIN32) && !defined(USE_GENERIC) +# if defined(I386) && defined(MSWIN32) && !defined(__MINGW32__) \ + && !defined(USE_GENERIC) /* I386 code, Microsoft variant */ __asm push eax __asm call GC_push_one @@ -274,11 +298,10 @@ void GC_push_regs() asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4"); # endif -# if defined(SPARC) || defined(IA64) +# if defined(SPARC) { word GC_save_regs_in_stack(); - /* generic code will not work */ GC_save_regs_ret_val = GC_save_regs_in_stack(); } # endif @@ -351,8 +374,8 @@ void GC_push_regs() /* other machines... */ # if !(defined M68K) && !(defined VAX) && !(defined RT) # if !(defined SPARC) && !(defined I386) && !(defined NS32K) -# if !defined(POWERPC) && !defined(UTS4) && !defined(IA64) -# if !defined(PJ) +# if !defined(POWERPC) && !defined(UTS4) +# if !defined(PJ) && !(defined(MIPS) && defined(LINUX)) --> bad news <-- # endif # endif @@ -379,11 +402,24 @@ ptr_t cold_gc_frame; for (; (char *)i < lim; i++) { *i = 0; } -# if defined(POWERPC) || defined(MSWIN32) || defined(UTS4) +# if defined(POWERPC) || defined(MSWIN32) || defined(UTS4) || defined(LINUX) (void) setjmp(regs); # else (void) _setjmp(regs); # endif +# if defined(SPARC) || defined(IA64) + /* On a register window machine, we need to save register */ + /* contents on the stack for this to work. The setjmp */ + /* is probably not needed on SPARC, since pointers are */ + /* only stored in windowed or scratch registers. It is */ + /* needed on IA64, since some non-windowed registers are */ + /* preserved. */ + { + word GC_save_regs_in_stack(); + + GC_save_regs_ret_val = GC_save_regs_in_stack(); + } +# endif GC_push_current_stack(cold_gc_frame); } } diff --git a/boehm-gc/malloc.c b/boehm-gc/malloc.c index 66e62d29694..a5a93ad8119 100644 --- a/boehm-gc/malloc.c +++ b/boehm-gc/malloc.c @@ -81,6 +81,10 @@ register ptr_t *opp; /* but that's benign. */ /* Volatile declarations may need to be added */ /* to prevent the compiler from breaking things.*/ + /* If we only execute the second of the */ + /* following assignments, we lose the free */ + /* list, but that should still be OK, at least */ + /* for garbage collected memory. */ *opp = obj_link(op); obj_link(op) = 0; } else { diff --git a/boehm-gc/mallocx.c b/boehm-gc/mallocx.c index 8c07fa98846..c842665237e 100644 --- a/boehm-gc/mallocx.c +++ b/boehm-gc/mallocx.c @@ -134,22 +134,14 @@ void GC_incr_mem_freed(size_t n) /* Analogous to the above, but assumes a small object size, and */ /* bypasses MERGE_SIZES mechanism. Used by gc_inline.h. */ -#ifdef __STDC__ - ptr_t GC_generic_malloc_words_small(size_t lw, int k) -#else - ptr_t GC_generic_malloc_words_small(lw, k) - register word lw; - register int k; -#endif +ptr_t GC_generic_malloc_words_small_inner(lw, k) +register word lw; +register int k; { register ptr_t op; register ptr_t *opp; register struct obj_kind * kind = GC_obj_kinds + k; -DCL_LOCK_STATE; - GC_INVOKE_FINALIZERS(); - DISABLE_SIGNALS(); - LOCK(); opp = &(kind -> ok_freelist[lw]); if( (op = *opp) == 0 ) { if (!GC_is_initialized) { @@ -167,6 +159,26 @@ DCL_LOCK_STATE; *opp = obj_link(op); obj_link(op) = 0; GC_words_allocd += lw; + return((ptr_t)op); +} + +/* Analogous to the above, but assumes a small object size, and */ +/* bypasses MERGE_SIZES mechanism. Used by gc_inline.h. */ +#ifdef __STDC__ + ptr_t GC_generic_malloc_words_small(size_t lw, int k) +#else + ptr_t GC_generic_malloc_words_small(lw, k) + register word lw; + register int k; +#endif +{ +register ptr_t op; +DCL_LOCK_STATE; + + GC_INVOKE_FINALIZERS(); + DISABLE_SIGNALS(); + LOCK(); + op = GC_generic_malloc_words_small_inner(lw, k); UNLOCK(); ENABLE_SIGNALS(); return((ptr_t)op); diff --git a/boehm-gc/mark.c b/boehm-gc/mark.c index 67085fbcc29..827b219018d 100644 --- a/boehm-gc/mark.c +++ b/boehm-gc/mark.c @@ -38,7 +38,7 @@ word x; /* mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0} -- declared in gc_priv.h */ -word GC_n_mark_procs = 0; +word GC_n_mark_procs = GC_RESERVED_MARK_PROCS; /* Initialize GC_obj_kinds properly and standard free lists properly. */ /* This must be done statically since they may be accessed before */ @@ -365,20 +365,20 @@ GC_bool GC_mark_stack_empty() /* with IGNORE_OFF_PAGE set. */ /*ARGSUSED*/ # ifdef PRINT_BLACK_LIST - word GC_find_start(current, hhdr, source) + ptr_t GC_find_start(current, hhdr, source) word source; # else - word GC_find_start(current, hhdr) + ptr_t GC_find_start(current, hhdr) # define source 0 # endif -register word current; +register ptr_t current; register hdr * hhdr; { # ifdef ALL_INTERIOR_POINTERS if (hhdr != 0) { - register word orig = current; + register ptr_t orig = current; - current = (word)HBLKPTR(current) + HDR_BYTES; + current = (ptr_t)HBLKPTR(current) + HDR_BYTES; do { current = current - HBLKSIZE*(word)hhdr; hhdr = HDR(current); @@ -429,6 +429,12 @@ mse * msp; * is never 0. A mark stack entry never has size 0. * We try to traverse on the order of a hblk of memory before we return. * Caller is responsible for calling this until the mark stack is empty. + * Note that this is the most performance critical routine in the + * collector. Hence it contains all sorts of ugly hacks to speed + * things up. In particular, we avoid procedure calls on the common + * path, we take advantage of peculiarities of the mark descriptor + * encoding, we optionally maintain a cache for the block address to + * header mapping, we prefetch when an object is "grayed", etc. */ void GC_mark_from_mark_stack() { @@ -443,9 +449,12 @@ void GC_mark_from_mark_stack() register word descr; register ptr_t greatest_ha = GC_greatest_plausible_heap_addr; register ptr_t least_ha = GC_least_plausible_heap_addr; + DECLARE_HDR_CACHE; + # define SPLIT_RANGE_WORDS 128 /* Must be power of 2. */ GC_objects_are_marked = TRUE; + INIT_HDR_CACHE; # ifdef OS2 /* Use untweaked version to circumvent compiler problem */ while (GC_mark_stack_top_reg >= GC_mark_stack_reg && credit >= 0) { # else @@ -453,8 +462,13 @@ void GC_mark_from_mark_stack() >= 0) { # endif current_p = GC_mark_stack_top_reg -> mse_start; - retry: descr = GC_mark_stack_top_reg -> mse_descr; + retry: + /* current_p and descr describe the current object. */ + /* *GC_mark_stack_top_reg is vacant. */ + /* The following is 0 only for small objects described by a simple */ + /* length descriptor. For many applications this is the common */ + /* case, so we try to detect it quickly. */ if (descr & ((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS) - 1)) | DS_TAGS)) { word tag = descr & DS_TAGS; @@ -465,8 +479,8 @@ void GC_mark_from_mark_stack() /* stack. */ GC_mark_stack_top_reg -> mse_start = limit = current_p + SPLIT_RANGE_WORDS-1; - GC_mark_stack_top_reg -> mse_descr -= - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1); + GC_mark_stack_top_reg -> mse_descr = + descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1); /* Make sure that pointers overlapping the two ranges are */ /* considered. */ limit = (word *)((char *)limit + sizeof(word) - ALIGNMENT); @@ -479,8 +493,8 @@ void GC_mark_from_mark_stack() if ((signed_word)descr < 0) { current = *current_p; if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) { - PUSH_CONTENTS(current, GC_mark_stack_top_reg, mark_stack_limit, - current_p, exit1); + PUSH_CONTENTS((ptr_t)current, GC_mark_stack_top_reg, + mark_stack_limit, current_p, exit1); } } descr <<= 1; @@ -496,24 +510,94 @@ void GC_mark_from_mark_stack() mark_stack_limit, ENV(descr)); continue; case DS_PER_OBJECT: - GC_mark_stack_top_reg -> mse_descr = - *(word *)((ptr_t)current_p + descr - tag); + if ((signed_word)descr >= 0) { + /* Descriptor is in the object. */ + descr = *(word *)((ptr_t)current_p + descr - DS_PER_OBJECT); + } else { + /* Descriptor is in type descriptor pointed to by first */ + /* word in object. */ + ptr_t type_descr = *(ptr_t *)current_p; + /* type_descr is either a valid pointer to the descriptor */ + /* structure, or this object was on a free list. If it */ + /* it was anything but the last object on the free list, */ + /* we will misinterpret the next object on the free list as */ + /* the type descriptor, and get a 0 GC descriptor, which */ + /* is ideal. Unfortunately, we need to check for the last */ + /* object case explicitly. */ + if (0 == type_descr) { + /* Rarely executed. */ + GC_mark_stack_top_reg--; + continue; + } + descr = *(word *)(type_descr + - (descr - (DS_PER_OBJECT - INDIR_PER_OBJ_BIAS))); + } goto retry; } - } else { + } else /* Small object with length descriptor */ { GC_mark_stack_top_reg--; limit = (word *)(((ptr_t)current_p) + (word)descr); } /* The simple case in which we're scanning a range. */ credit -= (ptr_t)limit - (ptr_t)current_p; limit -= 1; - while (current_p <= limit) { - current = *current_p; - if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) { - PUSH_CONTENTS(current, GC_mark_stack_top_reg, - mark_stack_limit, current_p, exit2); + { +# define PREF_DIST 4 + +# ifndef SMALL_CONFIG + word deferred; + + /* Try to prefetch the next pointer to be examined asap. */ + /* Empirically, this also seems to help slightly without */ + /* prefetches, at least on linux/X86. Presumably this loop */ + /* ends up with less register pressure, and gcc thus ends up */ + /* generating slightly better code. Overall gcc code quality */ + /* for this loop is still not great. */ + for(;;) { + PREFETCH((ptr_t)limit - PREF_DIST*CACHE_LINE_SIZE); + deferred = *limit; + limit = (word *)((char *)limit - ALIGNMENT); + if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) { + PREFETCH(deferred); + break; + } + if (current_p > limit) goto next_object; + /* Unroll once, so we don't do too many of the prefetches */ + /* based on limit. */ + deferred = *limit; + limit = (word *)((char *)limit - ALIGNMENT); + if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) { + PREFETCH(deferred); + break; + } + if (current_p > limit) goto next_object; + } +# endif + + while (current_p <= limit) { + /* Empirically, unrolling this loop doesn't help a lot. */ + /* Since HC_PUSH_CONTENTS expands to a lot of code, */ + /* we don't. */ + current = *current_p; + PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE); + if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) { + /* Prefetch the contents of the object we just pushed. It's */ + /* likely we will need them soon. */ + PREFETCH(current); + HC_PUSH_CONTENTS((ptr_t)current, GC_mark_stack_top_reg, + mark_stack_limit, current_p, exit2); + } + current_p = (word *)((char *)current_p + ALIGNMENT); } - current_p = (word *)((char *)current_p + ALIGNMENT); + +# ifndef SMALL_CONFIG + /* We still need to mark the entry we previously prefetched. */ + /* We alrady know that it passes the preliminary pointer */ + /* validity test. */ + HC_PUSH_CONTENTS((ptr_t)deferred, GC_mark_stack_top_reg, + mark_stack_limit, current_p, exit4); + next_object:; +# endif } } GC_mark_stack_top = GC_mark_stack_top_reg; @@ -686,7 +770,7 @@ word p; return; } # endif - GC_PUSH_ONE_STACK(p, 0); + GC_PUSH_ONE_STACK(p, MARKED_FROM_REGISTER); } # ifdef __STDC__ diff --git a/boehm-gc/mark_rts.c b/boehm-gc/mark_rts.c index 0e84f2732fc..5bafd07ed89 100644 --- a/boehm-gc/mark_rts.c +++ b/boehm-gc/mark_rts.c @@ -412,9 +412,8 @@ ptr_t cold_gc_frame; if (0 == cold_gc_frame) return; # ifdef STACK_GROWS_DOWN GC_push_all_eager(GC_approx_sp(), cold_gc_frame); -# ifdef IA64 - --> fix this -# endif + /* For IA64, the register stack backing store is handled */ + /* in the thread-specific code. */ # else GC_push_all_eager( cold_gc_frame, GC_approx_sp() ); # endif @@ -505,6 +504,9 @@ ptr_t cold_gc_frame; /* In the USE_GENERIC_PUSH_REGS case, this is done inside */ /* GC_push_regs, so that we catch callee-save registers saved */ /* inside the GC_push_regs frame. */ + /* In the case of linux threads on Ia64, the hot section of */ + /* the main stack is marked here, but the register stack */ + /* backing store is handled in the threads-specific code. */ # endif if (GC_push_other_roots != 0) (*GC_push_other_roots)(); /* In the threads case, this also pushes thread stacks. */ diff --git a/boehm-gc/misc.c b/boehm-gc/misc.c index 40cbe97de9f..780dc7b5624 100644 --- a/boehm-gc/misc.c +++ b/boehm-gc/misc.c @@ -42,11 +42,12 @@ # ifdef WIN32_THREADS GC_API CRITICAL_SECTION GC_allocate_ml; # else -# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ - || defined(IRIX_JDK_THREADS) +# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS) \ + || (defined(LINUX_THREADS) && defined(USE_SPIN_LOCK)) pthread_t GC_lock_holder = NO_THREAD; # else -# if defined(HPUX_THREADS) +# if defined(HPUX_THREADS) \ + || defined(LINUX_THREADS) && !defined(USE_SPIN_LOCK) pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER; # else --> declare allocator lock here @@ -119,6 +120,15 @@ extern signed_word GC_mem_found; for (i = 8*sizeof(word) + 1; i <= 16 * sizeof(word); i++) { GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 1) & (~1); } +# ifdef GC_GCJ_SUPPORT + /* Make all sizes up to 32 words predictable, so that a */ + /* compiler can statically perform the same computation, */ + /* or at least a computation that results in similar size */ + /* classes. */ + for (i = 16*sizeof(word) + 1; i <= 32 * sizeof(word); i++) { + GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 3) & (~3); + } +# endif /* We leave the rest of the array to be filled in on demand. */ } @@ -439,8 +449,8 @@ void GC_init_inner() # ifdef MSWIN32 GC_init_win32(); # endif -# if defined(LINUX) && \ - (defined(POWERPC) || defined(ALPHA) || defined(SPARC) || defined(IA64)) +# if defined(SEARCH_FOR_DATA_START) + /* This doesn't really work if the collector is in a shared library. */ GC_init_linux_data_start(); # endif # ifdef SOLARIS_THREADS @@ -807,7 +817,8 @@ struct callinfo info[NFRAMES]; #endif /* SAVE_CALL_CHAIN */ -# ifdef SRC_M3 +/* Needed by SRC_M3, gcj, and should perhaps be the official interface */ +/* to GC_dont_gc. */ void GC_enable() { GC_dont_gc--; @@ -817,7 +828,6 @@ void GC_disable() { GC_dont_gc++; } -# endif #if !defined(NO_DEBUGGING) diff --git a/boehm-gc/new_hblk.c b/boehm-gc/new_hblk.c index 9f32ae0dcb4..1e1273f854e 100644 --- a/boehm-gc/new_hblk.c +++ b/boehm-gc/new_hblk.c @@ -103,10 +103,10 @@ ptr_t ofl; p[3] = 0; p += 4; for (; p < lim; p += 4) { + PREFETCH_FOR_WRITE(p+64); p[0] = (word)(p-4); p[1] = 0; - p[2] = 0; - p[3] = 0; + CLEAR_DOUBLE(p+2); }; return((ptr_t)(p-4)); } @@ -141,6 +141,7 @@ ptr_t ofl; p[4] = (word)p; p += 8; for (; p < lim; p += 8) { + PREFETCH_FOR_WRITE(p+64); p[0] = (word)(p-4); p[4] = (word)p; }; @@ -179,6 +180,10 @@ int kind; /* Mark all objects if appropriate. */ if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(HDR(h)); + PREFETCH_FOR_WRITE((char *)h); + PREFETCH_FOR_WRITE((char *)h + 128); + PREFETCH_FOR_WRITE((char *)h + 256); + PREFETCH_FOR_WRITE((char *)h + 378); /* Handle small objects sizes more efficiently. For larger objects */ /* the difference is less significant. */ # ifndef SMALL_CONFIG diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c index e83b5cacd44..6158906e88d 100644 --- a/boehm-gc/os_dep.c +++ b/boehm-gc/os_dep.c @@ -66,7 +66,7 @@ # define NEED_FIND_LIMIT # endif -# if (defined(SUNOS4) & defined(DYNAMIC_LOADING)) && !defined(PCR) +# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR) # define NEED_FIND_LIMIT # endif @@ -75,7 +75,8 @@ # endif # if defined(LINUX) && \ - (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64)) + (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64) \ + || defined(MIPS)) # define NEED_FIND_LIMIT # endif @@ -142,8 +143,8 @@ # define OPT_PROT_EXEC 0 #endif -#if defined(LINUX) && (defined(POWERPC) || defined(SPARC) || defined(ALPHA) \ - || defined(IA64)) +#if defined(SEARCH_FOR_DATA_START) + /* The following doesn't work if the GC is in a dynamic library. */ /* The I386 case can be handled without a search. The Alpha case */ /* used to be handled differently as well, but the rules changed */ /* for recent Linux versions. This seems to be the easiest way to */ @@ -598,19 +599,17 @@ ptr_t GC_get_stack_base() #ifdef LINUX_STACKBOTTOM # define STAT_SKIP 27 /* Number of fields preceding startstack */ - /* field in /proc//stat */ + /* field in /proc/self/stat */ ptr_t GC_linux_stack_base(void) { - char buf[50]; FILE *f; char c; word result = 0; int i; - sprintf(buf, "/proc/%d/stat", getpid()); - f = fopen(buf, "r"); - if (NULL == f) ABORT("Couldn't open /proc//stat"); + f = fopen("/proc/self/stat", "r"); + if (NULL == f) ABORT("Couldn't open /proc/self/stat"); c = getc(f); /* Skip the required number of fields. This number is hopefully */ /* constant across all Linux implementations. */ @@ -1825,6 +1824,9 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # else # ifdef IA64 char * addr = si -> si_addr; + /* I believe this is claimed to work on all platforms for */ + /* Linux 2.3.47 and later. Hopefully we don't have to */ + /* worry about earlier kernels on IA64. */ # else # if defined(POWERPC) char * addr = (char *) (sc.regs->dar); @@ -2129,12 +2131,13 @@ word len; ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE); } -#ifndef MSWIN32 +#if !defined(MSWIN32) && !defined(LINUX_THREADS) /* Replacement for UNIX system call. */ /* Other calls that write to the heap */ /* should be handled similarly. */ # if defined(__STDC__) && !defined(SUNOS4) # include +# include ssize_t read(int fd, void *buf, size_t nbyte) # else # ifndef LINT @@ -2151,10 +2154,12 @@ word len; GC_begin_syscall(); GC_unprotect_range(buf, (word)nbyte); -# ifdef IRIX5 +# if defined(IRIX5) || defined(LINUX_THREADS) /* Indirect system call may not always be easily available. */ /* We could call _read, but that would interfere with the */ /* libpthread interception of read. */ + /* On Linux, we have to be careful with the linuxthreads */ + /* read interception. */ { struct iovec iov; @@ -2168,7 +2173,29 @@ word len; GC_end_syscall(); return(result); } -#endif /* !MSWIN32 */ +#endif /* !MSWIN32 && !LINUX */ + +#ifdef USE_LD_WRAP + /* We use the GNU ld call wrapping facility. */ + /* This requires that the linker be invoked with "--wrap read". */ + /* This can be done by passing -Wl,"--wrap read" to gcc. */ + /* I'm not sure that this actually wraps whatever version of read */ + /* is called by stdio. That code also mentions __read. */ +# include + ssize_t __wrap_read(int fd, void *buf, size_t nbyte) + { + int result; + + GC_begin_syscall(); + GC_unprotect_range(buf, (word)nbyte); + result = __real_read(fd, buf, nbyte); + GC_end_syscall(); + return(result); + } + + /* We should probably also do this for __read, or whatever stdio */ + /* actually calls. */ +#endif /*ARGSUSED*/ GC_bool GC_page_was_ever_dirty(h) diff --git a/boehm-gc/reclaim.c b/boehm-gc/reclaim.c index 6e0f53bb058..1847e590aad 100644 --- a/boehm-gc/reclaim.c +++ b/boehm-gc/reclaim.c @@ -241,9 +241,18 @@ register word sz; /* Clear object, advance p to next object in the process */ q = p + sz; p++; /* Skip link field */ - while (p < q) { +# if defined(SMALL_CONFIG) && defined(ALIGN_DOUBLE) + /* We assert that sz must be even */ + *p++ = 0; + while (p < q) { + CLEAR_DOUBLE(p); + p += 2; + } +# else + while (p < q) { *p++ = 0; - } + } +# endif } word_no += sz; } @@ -321,8 +330,7 @@ register ptr_t list; p[start_displ] = (word)list; \ list = (ptr_t)(p+start_displ); \ p[start_displ+1] = 0; \ - p[start_displ+2] = 0; \ - p[start_displ+3] = 0; \ + CLEAR_DOUBLE(p + start_displ + 2); \ INCR_WORDS(4); \ } @@ -814,6 +822,12 @@ int report_if_found; /* Abort if a GC_reclaimable object is found */ /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */ /* or enqueue the block for later processing. */ GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found); + +# ifdef EAGER_SWEEP + /* This is a very stupid thing to do. We make it possible anyway, */ + /* so that you can convince yourself that it really is very stupid. */ + GC_reclaim_all((GC_stop_func)0, FALSE); +# endif } @@ -847,7 +861,7 @@ int kind; * Abort and return FALSE when/if (*stop_func)() returns TRUE. * If this returns TRUE, then it's safe to restart the world * with incorrectly cleared mark bits. - * If ignore_old is TRUE, then reclain only blocks that have been + * If ignore_old is TRUE, then reclaim only blocks that have been * recently reclaimed, and discard the rest. * Stop_func may be 0. */ diff --git a/boehm-gc/solaris_pthreads.c b/boehm-gc/solaris_pthreads.c index 58424577bca..467de4840bb 100644 --- a/boehm-gc/solaris_pthreads.c +++ b/boehm-gc/solaris_pthreads.c @@ -77,14 +77,16 @@ GC_pthread_create(pthread_t *new_thread, pthread_attr_t attr; word my_flags = 0; int flag; - void * stack; - size_t stack_size; + void * stack = 0; + size_t stack_size = 0; int n; struct sched_param schedparam; - (void)pthread_attr_getstacksize(attr_in, &stack_size); - (void)pthread_attr_getstackaddr(attr_in, &stack); (void)pthread_attr_init(&attr); + if (attr_in != 0) { + (void)pthread_attr_getstacksize(attr_in, &stack_size); + (void)pthread_attr_getstackaddr(attr_in, &stack); + } LOCK(); if (!GC_thr_initialized) { @@ -94,7 +96,11 @@ GC_pthread_create(pthread_t *new_thread, if (stack == 0) { if (stack_size == 0) - stack_size = GC_min_stack_sz; + stack_size = 1048576; + /* ^-- 1 MB (this was GC_min_stack_sz, but that + * violates the pthread_create documentation which + * says the default value if none is supplied is + * 1MB) */ else stack_size += thr_min_stack(); @@ -110,20 +116,22 @@ GC_pthread_create(pthread_t *new_thread, } (void)pthread_attr_setstacksize(&attr, stack_size); (void)pthread_attr_setstackaddr(&attr, stack); - (void)pthread_attr_getscope(attr_in, &n); - (void)pthread_attr_setscope(&attr, n); - (void)pthread_attr_getschedparam(attr_in, &schedparam); - (void)pthread_attr_setschedparam(&attr, &schedparam); - (void)pthread_attr_getschedpolicy(attr_in, &n); - (void)pthread_attr_setschedpolicy(&attr, n); - (void)pthread_attr_getinheritsched(attr_in, &n); - (void)pthread_attr_setinheritsched(&attr, n); - - (void)pthread_attr_getdetachstate(attr_in, &flag); - if (flag == PTHREAD_CREATE_DETACHED) { - my_flags |= DETACHED; + if (attr_in != 0) { + (void)pthread_attr_getscope(attr_in, &n); + (void)pthread_attr_setscope(&attr, n); + (void)pthread_attr_getschedparam(attr_in, &schedparam); + (void)pthread_attr_setschedparam(&attr, &schedparam); + (void)pthread_attr_getschedpolicy(attr_in, &n); + (void)pthread_attr_setschedpolicy(&attr, n); + (void)pthread_attr_getinheritsched(attr_in, &n); + (void)pthread_attr_setinheritsched(&attr, n); + + (void)pthread_attr_getdetachstate(attr_in, &flag); + if (flag == PTHREAD_CREATE_DETACHED) { + my_flags |= DETACHED; + } + (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); } - (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); /* * thr_create can call malloc(), which if redirected will * attempt to acquire the allocation lock. diff --git a/boehm-gc/solaris_threads.c b/boehm-gc/solaris_threads.c index 65b2c6517b1..c3b0b15b97c 100644 --- a/boehm-gc/solaris_threads.c +++ b/boehm-gc/solaris_threads.c @@ -661,7 +661,8 @@ void GC_my_stack_limits() } -/* We hold allocation lock. We assume the world is stopped. */ +/* We hold allocation lock. Should do exactly the right thing if the */ +/* world is stopped. Should not fail if it isn't. */ void GC_push_all_stacks() { register int i; @@ -900,7 +901,7 @@ GC_thr_create(void *stack_base, size_t stack_size, } GC_multithreaded++; if (stack == 0) { - if (stack_size == 0) stack_size = GC_min_stack_sz; + if (stack_size == 0) stack_size = 1024*1024; stack = (void *)GC_stack_alloc(&stack_size); if (stack == 0) { GC_multithreaded--; diff --git a/boehm-gc/threadlibs.c b/boehm-gc/threadlibs.c index df4eb77bb1d..b2e6a10b0b9 100644 --- a/boehm-gc/threadlibs.c +++ b/boehm-gc/threadlibs.c @@ -3,7 +3,16 @@ int main() { -# if defined(IRIX_THREADS) || defined(LINUX_THREADS) +# if defined(LINUX_THREADS) +# ifdef USE_LD_WRAP + printf("-Wl,\"--wrap read\" -Wl,\"--wrap dlopen\" " + "-Wl,\"--wrap pthread_create\" -Wl,\"--wrap pthread_join\" " + "-Wl,\"--wrap pthread_sigmask\" -lpthread\n"); +# else + printf("-lpthread\n"); +# endif +# endif +# if defined(IRIX_THREADS) printf("-lpthread\n"); # endif # if defined(HPUX_THREADS) diff --git a/boehm-gc/typd_mlc.c b/boehm-gc/typd_mlc.c index 74f455d926c..ce769d60fec 100644 --- a/boehm-gc/typd_mlc.c +++ b/boehm-gc/typd_mlc.c @@ -430,7 +430,7 @@ word env; if (bm & 1) { current = *current_p; if ((ptr_t)current >= least_ha && (ptr_t)current <= greatest_ha) { - PUSH_CONTENTS(current, mark_stack_ptr, + PUSH_CONTENTS((ptr_t)current, mark_stack_ptr, mark_stack_limit, current_p, exit1); } } @@ -665,6 +665,7 @@ DCL_LOCK_STATE; # endif } else { *opp = obj_link(op); + obj_link(op) = 0; GC_words_allocd += lw; FASTUNLOCK(); } @@ -708,6 +709,7 @@ DCL_LOCK_STATE; # endif } else { *opp = obj_link(op); + obj_link(op) = 0; GC_words_allocd += lw; FASTUNLOCK(); } @@ -717,7 +719,7 @@ DCL_LOCK_STATE; lw = BYTES_TO_WORDS(GC_size(op)); } if (op != NULL) - ((word *)op)[lw - 1] = d; + ((word *)op)[lw - 1] = d; return((GC_PTR) op); } @@ -772,6 +774,7 @@ DCL_LOCK_STATE; # endif } else { *opp = obj_link(op); + obj_link(op) = 0; GC_words_allocd += lw; FASTUNLOCK(); } diff --git a/boehm-gc/version.h b/boehm-gc/version.h index df0770c9b04..c7095488bd5 100644 --- a/boehm-gc/version.h +++ b/boehm-gc/version.h @@ -1,9 +1,12 @@ #define GC_VERSION_MAJOR 5 #define GC_VERSION_MINOR 0 -#define GC_ALPHA_VERSION 4 +#define GC_ALPHA_VERSION 6 # define GC_NOT_ALPHA 0xff +/* This is really an unreleased version which doesn't have a real version */ +/* number. */ + #ifndef GC_NO_VERSION_VAR unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_ALPHA_VERSION); diff --git a/boehm-gc/win32_threads.c b/boehm-gc/win32_threads.c index f6f74bd1111..469fd232003 100644 --- a/boehm-gc/win32_threads.c +++ b/boehm-gc/win32_threads.c @@ -2,8 +2,10 @@ #include "gc_priv.h" +#if 0 #define STRICT #include +#endif #define MAX_THREADS 64 @@ -61,7 +63,7 @@ ptr_t GC_current_stackbottom() ABORT("no thread table entry for current thread"); } -ptr_t GC_get_lo_stack_addr(ptr_t s) +static ptr_t GC_get_lo_stack_addr(ptr_t s) { ptr_t bottom; MEMORY_BASIC_INFORMATION info; @@ -81,7 +83,7 @@ void GC_push_all_stacks() if (thread_table[i].stack) { ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack); if (thread_table[i].id == thread_id) - GC_push_all(&i, thread_table[i].stack); + GC_push_all_stack(&i, thread_table[i].stack); else { thread_table[i].context.ContextFlags = (CONTEXT_INTEGER|CONTEXT_CONTROL); -- cgit v1.2.3