aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4>2000-04-19 02:29:16 +0000
committerbryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4>2000-04-19 02:29:16 +0000
commit4b6b3b3b1bad96c79817fa99d89b1f9b3551f181 (patch)
tree97fcfdefac13334ccf4a727d31cf49538f4d812c
parent7d39f1e93487526cd808c70e6117ee5adb2ee7e3 (diff)
Imported Boehm GC 5.0alpha6
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/boehm@33244 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--boehm-gc/Makefile47
-rw-r--r--boehm-gc/allchblk.c56
-rw-r--r--boehm-gc/alloc.c10
-rw-r--r--boehm-gc/alpha_mach_dep.s4
-rw-r--r--boehm-gc/cord/cordprnt.c2
-rw-r--r--boehm-gc/dbg_mlc.c107
-rw-r--r--boehm-gc/dyn_load.c58
-rw-r--r--boehm-gc/finalize.c8
-rw-r--r--boehm-gc/headers.c25
-rw-r--r--boehm-gc/include/cord.h2
-rw-r--r--boehm-gc/include/gc.h51
-rw-r--r--boehm-gc/include/gc_cpp.h21
-rw-r--r--boehm-gc/include/gc_typed.h2
-rw-r--r--boehm-gc/include/private/gc_priv.h182
-rw-r--r--boehm-gc/include/private/gcconfig.h329
-rw-r--r--boehm-gc/linux_threads.c160
-rw-r--r--boehm-gc/mach_dep.c68
-rw-r--r--boehm-gc/malloc.c4
-rw-r--r--boehm-gc/mallocx.c34
-rw-r--r--boehm-gc/mark.c126
-rw-r--r--boehm-gc/mark_rts.c8
-rw-r--r--boehm-gc/misc.c24
-rw-r--r--boehm-gc/new_hblk.c9
-rw-r--r--boehm-gc/os_dep.c51
-rw-r--r--boehm-gc/reclaim.c24
-rw-r--r--boehm-gc/solaris_pthreads.c44
-rw-r--r--boehm-gc/solaris_threads.c5
-rw-r--r--boehm-gc/threadlibs.c11
-rw-r--r--boehm-gc/typd_mlc.c7
-rw-r--r--boehm-gc/version.h5
-rw-r--r--boehm-gc/win32_threads.c6
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 <stdio.h>
#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 <thread.h>
-# include <synch.h>
+ /* Should probably happen for other operating systems, too. */
+
+#include <dlfcn.h>
-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 <pthread.h>
# include <signal.h>
@@ -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 <windows.h>
+# include <winbase.h>
+# define CLOCK_TYPE DWORD
+# define GET_TIME(x) x = GetTickCount()
+# define MS_TIME_DIFF(a,b) ((long)((a)-(b)))
+# else /* !MSWIN32, !BSD_TIME */
# include <time.h>
# 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 <pthread.h>
+# 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 <pthread.h>
+ 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 <pthread.h>
@@ -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 <features.h>
# 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 <unistd.h>
# 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 <features.h>
+# 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 <pthread.h>
+# include <sched.h>
# include <time.h>
# include <errno.h>
# include <unistd.h>
# include <sys/mman.h>
# include <sys/time.h>
# include <semaphore.h>
+# include <signal.h>
+
+#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/<pid>/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/<pid>/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 <unistd.h>
+# include <sys/uio.h>
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 <unistd.h>
+ 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 <windows.h>
+#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);