Clean merge -> gc7-branch
authorStefan Ring <stefan@complang.tuwien.ac.at>
Sun, 11 May 2008 10:19:00 +0000 (12:19 +0200)
committerStefan Ring <stefan@complang.tuwien.ac.at>
Sun, 11 May 2008 10:19:00 +0000 (12:19 +0200)
--HG--
branch : gc7-branch
rename : src/threads/native/threads.c => src/threads/posix/thread-posix.c

212 files changed:
configure.ac
src/mm/boehm-gc/AmigaOS.c
src/mm/boehm-gc/BCC_MAKEFILE
src/mm/boehm-gc/ChangeLog [new file with mode: 0644]
src/mm/boehm-gc/EMX_MAKEFILE
src/mm/boehm-gc/MacOS.c
src/mm/boehm-gc/Makefile.am
src/mm/boehm-gc/Makefile.direct
src/mm/boehm-gc/Makefile.dj
src/mm/boehm-gc/NT_MAKEFILE [changed mode: 0644->0755]
src/mm/boehm-gc/NT_STATIC_THREADS_MAKEFILE [new file with mode: 0644]
src/mm/boehm-gc/NT_THREADS_MAKEFILE
src/mm/boehm-gc/NT_X64_STATIC_THREADS_MAKEFILE [new file with mode: 0644]
src/mm/boehm-gc/OS2_MAKEFILE
src/mm/boehm-gc/PCR-Makefile
src/mm/boehm-gc/README.QUICK
src/mm/boehm-gc/SMakefile.amiga
src/mm/boehm-gc/WCC_MAKEFILE
src/mm/boehm-gc/allchblk.c
src/mm/boehm-gc/alloc.c
src/mm/boehm-gc/autogen.sh
src/mm/boehm-gc/backgraph.c
src/mm/boehm-gc/bdw-gc.pc.in [new file with mode: 0644]
src/mm/boehm-gc/blacklst.c
src/mm/boehm-gc/callprocs [changed mode: 0644->0755]
src/mm/boehm-gc/checksums.c
src/mm/boehm-gc/configure.ac [new file with mode: 0644]
src/mm/boehm-gc/configure.in [deleted file]
src/mm/boehm-gc/configure_atomic_ops.sh [new file with mode: 0755]
src/mm/boehm-gc/cord/cord.am [new file with mode: 0644]
src/mm/boehm-gc/cord/de_win.ICO [changed mode: 0644->0755]
src/mm/boehm-gc/cord/de_win.c
src/mm/boehm-gc/darwin_stop_world.c
src/mm/boehm-gc/dbg_mlc.c
src/mm/boehm-gc/digimars.mak
src/mm/boehm-gc/doc/Makefile.am [deleted file]
src/mm/boehm-gc/doc/README
src/mm/boehm-gc/doc/README.Mac
src/mm/boehm-gc/doc/README.changes
src/mm/boehm-gc/doc/README.darwin
src/mm/boehm-gc/doc/README.environment
src/mm/boehm-gc/doc/README.linux
src/mm/boehm-gc/doc/README.macros
src/mm/boehm-gc/doc/README.solaris2
src/mm/boehm-gc/doc/README.win32
src/mm/boehm-gc/doc/README.win64 [new file with mode: 0644]
src/mm/boehm-gc/doc/doc.am [new file with mode: 0644]
src/mm/boehm-gc/doc/gcdescr.html
src/mm/boehm-gc/doc/gcinterface.html
src/mm/boehm-gc/doc/leak.html
src/mm/boehm-gc/doc/overview.html [new file with mode: 0644]
src/mm/boehm-gc/doc/porting.html [new file with mode: 0644]
src/mm/boehm-gc/dyn_load.c
src/mm/boehm-gc/finalize.c
src/mm/boehm-gc/gc.mak
src/mm/boehm-gc/gc_cpp.cc
src/mm/boehm-gc/gc_dlopen.c
src/mm/boehm-gc/gcc_support.c [deleted file]
src/mm/boehm-gc/gcj_mlc.c
src/mm/boehm-gc/headers.c
src/mm/boehm-gc/if_mach.c
src/mm/boehm-gc/if_not_there.c
src/mm/boehm-gc/include/Makefile.am [deleted file]
src/mm/boehm-gc/include/gc.h
src/mm/boehm-gc/include/gc_alloc.h [deleted file]
src/mm/boehm-gc/include/gc_allocator.h
src/mm/boehm-gc/include/gc_config_macros.h
src/mm/boehm-gc/include/gc_cpp.h
src/mm/boehm-gc/include/gc_gcj.h
src/mm/boehm-gc/include/gc_inl.h [deleted file]
src/mm/boehm-gc/include/gc_inline.h
src/mm/boehm-gc/include/gc_local_alloc.h [deleted file]
src/mm/boehm-gc/include/gc_mark.h
src/mm/boehm-gc/include/gc_pthread_redirects.h
src/mm/boehm-gc/include/gc_tiny_fl.h [new file with mode: 0644]
src/mm/boehm-gc/include/gc_typed.h
src/mm/boehm-gc/include/include.am [new file with mode: 0644]
src/mm/boehm-gc/include/new_gc_alloc.h
src/mm/boehm-gc/include/private/dbg_mlc.h
src/mm/boehm-gc/include/private/gc_hdrs.h
src/mm/boehm-gc/include/private/gc_locks.h
src/mm/boehm-gc/include/private/gc_pmark.h
src/mm/boehm-gc/include/private/gc_priv.h
src/mm/boehm-gc/include/private/gcconfig.h
src/mm/boehm-gc/include/private/msvc_dbg.h [new file with mode: 0644]
src/mm/boehm-gc/include/private/pthread_support.h
src/mm/boehm-gc/include/private/solaris_threads.h [deleted file]
src/mm/boehm-gc/include/private/specific.h
src/mm/boehm-gc/include/private/thread_local_alloc.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/AUTHORS [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/COPYING [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/ChangeLog [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/INSTALL [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/Makefile.am [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/NEWS [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/README [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/autogen.sh [new file with mode: 0755]
src/mm/boehm-gc/libatomic_ops-1.2/configure.ac [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/doc/COPYING [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/doc/LICENSING.txt [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/doc/Makefile.am [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/doc/README.txt [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/doc/README_malloc.txt [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/doc/README_stack.txt [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/doc/README_win32.txt [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/mkinstalldirs [new file with mode: 0755]
src/mm/boehm-gc/libatomic_ops-1.2/src/Makefile.am [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/Makefile.msft [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops.c [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops.h [new file with mode: 0755]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/Makefile.am [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize-small.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize-small.template [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/Makefile.am [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/README [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/acquire_release_volatile.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/aligned_atomic_load_store.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/all_acquire_release_volatile.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/all_aligned_atomic_load_store.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/all_atomic_load_store.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ao_t_is_int.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/atomic_load_store.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/char_acquire_release_volatile.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/char_atomic_load_store.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/emul_cas.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/alpha.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/arm.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/cris.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/hppa.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/ia64.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/m68k.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/powerpc.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/s390.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/sparc.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/x86.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/x86_64.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/generic_pthread.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc/hppa.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc/ia64.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ibmc/powerpc.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/icc/ia64.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/int_acquire_release_volatile.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/int_aligned_atomic_load_store.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/int_atomic_load_store.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc/x86.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc/x86_64.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ordered.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ordered_except_wr.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/read_ordered.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/short_acquire_release_volatile.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/short_aligned_atomic_load_store.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/short_atomic_load_store.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/standard_ao_double_t.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc/sparc.S [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc/sparc.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/test_and_set_t_is_ao_t.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/test_and_set_t_is_char.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_malloc.c [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_malloc.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_stack.c [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_stack.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_sysdeps.S [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/tests/Makefile.am [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/tests/list_atomic.c [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/tests/list_atomic.template [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/tests/run_parallel.inc [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/tests/test_atomic.c [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/tests/test_atomic.template [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/tests/test_atomic_include.h [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/tests/test_malloc.c [new file with mode: 0644]
src/mm/boehm-gc/libatomic_ops-1.2/tests/test_stack.c [new file with mode: 0644]
src/mm/boehm-gc/libtool.m4
src/mm/boehm-gc/ltconfig [deleted file]
src/mm/boehm-gc/mach_dep.c
src/mm/boehm-gc/malloc.c
src/mm/boehm-gc/mallocx.c
src/mm/boehm-gc/mark.c
src/mm/boehm-gc/mark_rts.c
src/mm/boehm-gc/misc.c [changed mode: 0644->0755]
src/mm/boehm-gc/mkinstalldirs [new file with mode: 0755]
src/mm/boehm-gc/msvc_dbg.c [new file with mode: 0644]
src/mm/boehm-gc/new_hblk.c
src/mm/boehm-gc/obj_map.c
src/mm/boehm-gc/os_dep.c
src/mm/boehm-gc/pc_excludes [deleted file]
src/mm/boehm-gc/pcr_interface.c
src/mm/boehm-gc/powerpc_darwin_mach_dep.s [deleted file]
src/mm/boehm-gc/pthread_stop_world.c
src/mm/boehm-gc/pthread_support.c
src/mm/boehm-gc/ptr_chck.c
src/mm/boehm-gc/real_malloc.c
src/mm/boehm-gc/reclaim.c
src/mm/boehm-gc/setjmp_t.c
src/mm/boehm-gc/solaris_pthreads.c [deleted file]
src/mm/boehm-gc/solaris_threads.c [deleted file]
src/mm/boehm-gc/sparc_mach_dep.S
src/mm/boehm-gc/specific.c
src/mm/boehm-gc/stubborn.c
src/mm/boehm-gc/tests/leak_test.c
src/mm/boehm-gc/tests/middle.c [new file with mode: 0644]
src/mm/boehm-gc/tests/test.c
src/mm/boehm-gc/tests/test_cpp.cc
src/mm/boehm-gc/tests/tests.am [new file with mode: 0644]
src/mm/boehm-gc/tests/thread_leak_test.c
src/mm/boehm-gc/tests/trace_test.c [deleted file]
src/mm/boehm-gc/thread_local_alloc.c [new file with mode: 0644]
src/mm/boehm-gc/threadlibs.c
src/mm/boehm-gc/typd_mlc.c
src/mm/boehm-gc/version.h
src/mm/boehm-gc/win32_threads.c [changed mode: 0644->0755]
src/threads/posix/thread-posix.c

index 2aa52423d2eb7e7648753edaf7668872ce51239b..7755b008928d3390a57496101493cd31f38e8115 100644 (file)
@@ -934,6 +934,7 @@ AC_CONFIG_FILES([Makefile]
 dnl now configure subpackages with OPT_CFLAGS and ARCH_CFLAGS
 export OPT_CFLAGS
 export ARCH_CFLAGS
+ac_configure_args="$ac_configure_args --disable-shared"
 AC_CONFIG_SUBDIRS(src/mm/boehm-gc)
 
 
index e80247885cf6bd5a5edde4319f39b95c62eb134a..9c3a48455435c750c3eef73298f2094d6138364c 100644 (file)
@@ -41,7 +41,7 @@
    Find the base of the stack.
 ******************************************************************/
 
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base()
 {
     struct Process *proc = (struct Process*)SysBase->ThisTask;
  
index e21bc3d8dfe22efeef43bca48e5b9360c624af8c..b49d6b99a64859bba34093a645c594d3101168f7 100644 (file)
@@ -15,8 +15,7 @@ lib=   $(bcbin)\tlib
 link=   $(bcbin)\ilink32\r
 cflags=  -O2 -R -v- -vi -H -H=gc.csm -I$(bcinclude);$(gcinclude1);$(gcinclude2) -L$(bclib) \\r
         -w-pro -w-aus -w-par -w-ccc -w-rch -a4 -D__STDC__=0\r
-#defines= -DSILENT\r
-defines= -DSILENT -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY\r
+defines= -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY\r
 \r
 .c.obj:\r
        $(cc) @&&|\r
diff --git a/src/mm/boehm-gc/ChangeLog b/src/mm/boehm-gc/ChangeLog
new file mode 100644 (file)
index 0000000..96bf317
--- /dev/null
@@ -0,0 +1,363 @@
+2007-07-02  Hans Boehm <Hans.Boehm@hp.com>
+
+       * gc_config_macros.h: Also check for IA64 when setting
+       GC_HPUX_THREADS.
+       * mallocx.c: Change my_bytes_allocd to signed_word.
+       * include/pthread_redirects.h: Remove obsolete Solaris threads
+       (as opposed to pthreads) support.
+
+2007-07-02  Hans Boehm <Hans.Boehm@hp.com>
+
+       * mach_dep.c (GC_with_callee_saves_pushed): Don't use getcontext()
+       on ARM/Linux.  Check getcontext() return value.
+
+2007-06-29  Hans Boehm <Hans.Boehm@hp.com>
+
+       * backgraph.c (per_object_func): Make argument types consistent.
+       (GC_traverse_back_graph): Mark GC_deepest_obj.
+       
+2007-06-29  Hans Boehm <Hans.Boehm@hp.com>
+
+       * finalize.c (GC_finalize): Change dl_size and fo_size to size_t.
+       * os_dep.c (GC_win32_get_mem): Add GC_mem_top_down option.
+
+2007-06-28  Hans Boehm <Hans.Boehm@hp.com>
+
+       * doc/README.win32, doc/README, README.QUICK: Fix some of the worst
+       anachronisms.
+       * dyn_load.c: Partially support cygwin, but don't enable it yet.
+
+2007-06-28  Hans Boehm <Hans.Boehm@hp.com>
+
+       * Makefile.am: Use -no-undefined for libgc.
+       * Makefile.in: Regenerate.
+       * Makefile.direct: Document USE_PROC_FOR_LIBRARIES.
+       * dyn_load.c (GC_register_map_entries): Rename prot_buf to prot
+       consistently.
+       * misc.c: Fix some WARN calls.  Move GC_is_initialized setting and
+       GC_thr_init() call.
+       * os_dep.c: Consistently use WARN where appropriate.
+       * thread_local_alloc.c: Revert change to GC_WIN32_THREADS test.  Instead
+       remove inappropriate pthread.h include.
+       * doc/README.linux: Remove some anachronisms.
+
+2007-06-23  Hans Boehm <Hans.Boehm@hp.com>
+
+       * alloc.c: Also use GC_check_tls on non-Linux systems.
+       * mallocx.c (GC_reclaim_generic): Remove bogus declaration.
+       * include/private/gc_priv.h (GC_reclaim_generic): Declare correctly
+       with prototype.
+
+2007-06-19  Hans Boehm <Hans.Boehm@hp.com>
+
+       * alloc.c (GC_adj_bytes_allocd): Avoid (long) casts, fix comment.
+       (GC_print_heap_sects): Use size_t instead of unsigned long.
+       * thread_local_alloc.c (GC_lookup_thread): Define in the correct
+       context.
+       * win32_threads.c, include/gc_config_macros.h: The last of Romano
+       Paolo Tenca's patch.  Move stdint.h include to gc_config_macros.h.
+       * include/gc_inline.h: Avoid gc_priv.h dependencies.
+       * tests/test.c (check_heap_stats): Replace unsigned long with size_t.
+
+2007-06-12  Hans Boehm <Hans.Boehm@hp.com>
+
+       * aclocal.m4: Regenerate to update date.
+
+2007-06-10  Hans Boehm <Hans.Boehm@hp.com>
+
+       * NT_X64_STATIC_THREADS_MAKEFILE: Replace obsolete -debugtype:cv.
+       * mark_rts.c (GC_push_roots): Fix kind type.
+
+2007-06-06  Hans Boehm <Hans.Boehm@hp.com>
+
+       * doc/README.win64: New file.
+       * doc/doc.am, Makefile.direct: Add README.win64.
+       * Makefile.in: Regenerate.
+
+2007-06-06  Hans Boehm <Hans.Boehm@hp.com>
+
+       * Makefile.am, Makefile.direct: Add NT_X64_STATIC_THREADS_MAKEFILE.
+       * Makefile.in: Regenerate.
+       * NT_X64_STATIC_THREADS_MAKEFILE: Fix warning flags.
+       * allochblk.c, alloc.c, blacklst.c, dbg_malc.c, dyn_load.c,
+       finalize.c, headers.c, mach_dep.c, malloc.c, mark.c, misc.c,
+       obj_map.c, os_dep.c, ptr_chck.c, reclaim.c, typd_mlc.c,
+       win32_threads.c, cord/de_win.c, include/gc_mark.h,
+       include/private/gc_hdrs.h, include/private/gc_pmark.h,
+       include/private/gc_priv.h, tests/test_cpp.cc:
+       Replace old style function declarations.  Clean up integral types.
+       Remove register declarations.  The change in malloc.c and the
+       "int descr" declaration in mark.c are the most likely to have
+       been real bugs outside of win64.
+       * msvc_dbg.c: Disable on win64.
+       * win32_threads.c: Add AMD64 support.
+       * include/gc.h: no backtrace on AMD64 for now.
+
+2007-06-06  Hans Boehm <Hans.Boehm@hp.com>
+
+       * msvc_dbg.c(GetModuleBase): Replace strcat with strcat_s.
+
+2007-06-06  Hans Boehm <Hans.Boehm@hp.com>
+       
+       * include/gc.h: (GC_word, GC_signed_word): Fix win64 definitions.
+       Don't include windows.h in an extern "C" context.
+       * include/private/gcconfig.h: Fix win64/X86_64 configuration.
+       * tests/test.c: Eliminate more old style function definitions.
+       Cleanup pointer and integer casts for win64.
+       * tests/test_cpp.cc: Don't include gc_priv.h.
+       * NT_STATIC_THREADS_MAKEFILE: Restrict suffixes for VC++ 2005.
+       * NT_X64_STATIC_THREADS_MAKEFILE: New.
+
+2007-06-06  Hans Boehm <Hans.Boehm@hp.com> (Really mostly Romano Paolo Tenca)
+
+       * win32_threads.c: Separate out DEBUG_WIN32_PTHREADS_STACK.  Ignore
+       FINISHED threads for suspension.  (GC_pthread_join): Add
+       pthread_self() cast.  (GC_pthread_start_inner): Execute cleanup
+       handler when popping it.
+       * include/private/gc_locks.h: Inline THREAD_EQUAL for
+       GC_WIN32_PTHREADS.  Define USE_PTHREAD_LOCKS only if we have
+       pthreads.
+
+2007-05-23  Hans Boehm <Hans.Boehm@hp.com> (Really mostly Romano Paolo Tenca)
+
+       * gc_dlopen.c, thread_local_alloc.c, threadlibs.c, win32_threads.c,
+       tests/test.c: Accomodate GC_WIN32_PTHREADS.
+       * include/gc.h: Don't include windows.h for GC_WIN32_PTHREADS.
+       * include/gc_config_macros.h: Define both PTHREADS and
+       GC_WIN32_THREADS.
+       * include/private/gc_locks.h: Nonstandard definitions of
+       NUMERIC_THREAD_ID for GC_WIN32_PTHREADS.
+       * doc/README.win32, Makefile.direct: Include documentation
+       for GC_WIN32_PTHREADS.
+       * Makefile.direct: Remove some anachronisms in the documentation.
+
+2007-05-23  Hans Boehm <Hans.Boehm@hp.com>
+
+       * Makefile.am: Move includes to bottom.  Add better library
+       dependencies.  Increment library version.  Remove "SUBDIRS += .".
+       * cord/cord.am, tests/tests.am: Add better library dependencies.
+       Remove now unnecessary dependencies.
+       * Makefile.in: Regenerate.
+       * include/gc.h (GC_begin_thread_ex, GC_endthreadex, GC_ExitThread):
+       Move to define on all Windows platforms.  (_beginthread): define
+       to generate error if used.
+
+2007-05-22  Hans Boehm <Hans.Boehm@hp.com>
+
+       * include/private/gc_locks.h: Format to 80 columns.
+
+2007-05-22  Hans Boehm <Hans.Boehm@hp.com>
+       
+       * malloc.c(GC_free): Ignore bad frees on MSWIN32 with REDIRECT_MALLOC.
+       * NT_MAKEFILE: msvc_dbg.h is in include/private.  Don't use cvars
+       rc.
+       * misc.c (WIN32 GC_write): Define GC_need_to_lock in single-threaded
+       case.
+       * win32_threads.c: Test for __MINGW32__ in addition to _MINGW_VER.
+       (GC_CreateThread, GC_beginthreadex): Deallocate args even if we fail.
+       * include/gc.h: Add GC_reachable_here().  (GC_WinMain): Add GC_API.
+       (GC_beginthreadex, GC_endthreadex, GC_ExitThread): Declare.
+       * tests/test.c: Add GC_reachable_here() call.
+
+2007-05-21  Hans Boehm <Hans.Boehm@hp.com>
+
+       * alloc.c (GC_try_to_collect): Call GC_init if necessary.
+       * tests/thread_leak_test.c: Don't unconditionally define
+       GC_LINUX_THREADS.
+
+2007-05-21  Andreas Tobler  <a.tobler@schweiz.org>
+
+       * Makefile.am: Remove extra_ldflags_libgc definition.
+       * Makefile.in: Regenerate.
+
+2007-05-17  Hans Boehm <Hans.Boehm@hp.com>
+
+       * include/private/gc_priv.h: Define AO_REQUIRE_CAS.
+
+2007-05-16  Hans Boehm <Hans.Boehm@hp.com>
+
+       * finalize.c (GC_unreachable_finalize_mark_proc): Don't return void
+       value.
+
+2007-05-15  Hans Boehm <Hans.Boehm@hp.com>
+
+       * configure.ac, version.h, doc/README: Change version to 7.0alpha10.
+       * configure: Regenerate.
+
+[7.0alpha9 release]
+
+2007-05-15  Hans Boehm <Hans.Boehm@hp.com>
+
+       * configure.ac, version.h, doc/README: Change version to 7.0alpha9.
+       * configure: Regenerate.
+
+2007-05-15  Hans Boehm <Hans.Boehm@hp.com>
+
+       * Makefile.am: Include NT_STSTIC_THREADS_MAKEFILE in dist.
+       * Makefile.in: Regenerate.
+       * include/private/gc_locks.h: GC_compare_and_exchange, GC_atomic_add:
+       remove. NUMERIC_THREAD_ID, THREAD_EQUAL: New.  GC_lock_holder: now
+       unsigned long.  I_DONT_HOLD_LOCK, I_HOLD_LOCK: Update.
+       * pthread_stop_world.c, pthread_support.c, win32_threads.c: Use
+       NUMERIC_THREAD_ID, THREAD_EQUAL.
+       * include/private/gcconfig.h: GENERIC_COMPARE_AND_SWAP: Remove.
+       * include/private/thread_local_alloc.h: Don't USE_COMPILER_TLS on
+       ARM.
+
+2007-05-11  Hans Boehm <Hans.Boehm@hp.com>
+
+       * dbg_mlc.c, include/gc.h, finalize.c: Merge Alexandre Oliva's
+       GC_debug_register_finalizer_unreachable() patch from gcc tree.
+       * thread_local_alloc.c (GC_malloc, GC_malloc_atomic): Add assertions
+       to check GC has been initialized.
+
+2007-05-10  Hans Boehm <Hans.Boehm@hp.com>
+
+       * include/gc_cpp.h: Documentation updates.
+       * include/gc_config_macros.h: Don't check for __ppc__ to set
+       DARWIN_THREADS.
+       * Makefile.am: Include configure_atomic_ops.sh in dist.
+       * Makefile.in: Regenerate.
+
+2007-05-08  Hans Boehm <Hans.Boehm@hp.com>
+
+       * Makefile.am: Dont distribute copied atomic_ops files.  Include
+       libatomic_ops with "make dist".
+       * Makefile.in: Regenerate.
+       * configure: Regenerate.
+       * configure.ac: Enable THREAD_LOCAL_ALLOC for Cygwin with threads.
+       * win32_threads.c: Report error for Cygwin + GC_DLL.
+
+2007-05-08  Hans Boehm <Hans.Boehm@hp.com>
+
+       * Makefile.direct: Update THREAD_LOCAL_ALLOC documentation.
+       * cord/de_win.c: Rename and move AboutBox.  Call GC_INIT.  Remove
+       MakeProcInstance anachronism.
+       * doc/README.macros: Officially remove elif prohibition.
+       Remove documentation for defunct SRC_M3 support.
+       * include/gc.h: Remove more SRC_M3 references.
+       * include/private/gcconfig.h: Remove still more SRC_M3 references.
+       GC_SOLARIS_THREADS no longer needs to be checked separately.
+       
+2007-05-08  Hans Boehm <Hans.Boehm@hp.com>
+
+       * thread_local_alloc.c, include/private/thread_local_alloc.h:
+       Spell __declspec correctly.
+       * NT_STATIC_THREADS_MAKEFILE: Enable thread-local allocation.
+
+2007-05-07  Hans Boehm <Hans.Boehm@hp.com>
+
+       * doc/README.win32: Adjust GC_win32_dll_threads rules again.
+
+2007-05-07  Hans Boehm <Hans.Boehm@hp.com>
+
+       * mark.c (GC_mark_some wrapper): Restructure for readability, handle
+       GC_started_thread_while_stopped.
+       * misc.c (Win32 GC_write): Lock GC_write_cs only if needed.
+       * win32_threads.c: (client_has_run): remove,
+       GC_started_thread_while_stopped, GC_attached_thread: add.
+       (GC_push_all_stacks): Add verbose output.
+       (DllMain): Avoid initializing collector or the like.
+       Never update both thread tables.
+       * doc/README.win32: Adjust GC_win32_dll_threads rules.
+
+2007-05-07  Hans Boehm <Hans.Boehm@hp.com>
+
+       * pthread_stop_world.c (GC_push_all_stacks): Print thread count with
+       GC_PRINT_VERBOSE_STATS.
+
+2007-05-01  Hans Boehm <Hans.Boehm@hp.com>
+               (and Manuel Serrano, Craig McDaniel)
+
+       * configure.ac: Comment out redundant
+         AC_DEFINE(NO_EXECUTE_PERMISSION).
+       * configure: Regenerate.
+       * sparc_mach_dep.S: Remove single quote in comment.
+       * include/private/gcconfig.h: Fix DATAEND for NONSTOP.
+       * win32_threads.c: Include stdint.h for Mingw.  Add GC_API for DllMain.
+       (GC_use_DllMain): Fix assertion.
+
+2007-02-14  Andreas Tobler  <a.tobler@schweiz.org>
+
+       * configure.ac: Introduce extra_ldflags_libgc. Use it for Darwin.
+       * configure: Regenerate.
+       * Makefile.am (libgc_la_LDFLAGS): Use extra_ldflags_libgc.
+       * Makefile.in: Regenerate.
+       * include/private/gcconfig.h: Enable MPROTECT_VDB for all Darwin
+       targets. Remove comments.
+       Prepare ppc64 support for Darwin.
+
+2007-01-29  Andreas Tobler  <a.tobler@schweiz.org>
+
+       * darwin_stop_world.c: Clean up and reformat code.
+
+2007-01-28  Andreas Tobler  <a.tobler@schweiz.org>
+
+       * darwin_stop_world.c (GC_push_all_stacks): Fix compiler warnings.
+       Make i unsigned.
+       (GC_stop_world): Likewise. Remove unused GC_thread p.
+       (GC_start_world): Likewise.
+
+       * os_dep.c: Define GC_darwin_register_mach_handler_thread extern.
+       Remove double SIG_HNDLR_PTR definition.
+       (GC_forward_exception): Fix compiler warnings, make i unsigned.
+       Initialize thread_state to NULL.
+       (catch_exception_raise): Fix compiler warnings, make i unsigned.
+
+2007-01-25  Petr Salinger and Hans Boehm <Hans.Boehm@hp.com>
+
+       * include/private/gc_priv.h (NEED_FIND_LIMIT, FREEBSD variant):
+       also define for X86_64.
+       * configure.ac: Move generic gnu (Hurd) case to below kfreebsd case.
+       * configure: Regenerate.
+       * README.changes: Point to ChangeLog.
+
+2007-01-25  Andreas Tobler  <a.tobler@schweiz.org>
+
+       * darwin_stop_world.c: Move THREAD_FLD defines to ...
+       * include/private/gc_priv.h: ... here.
+       Fix THREAD_STATE definitions for ppc64.
+       * os_dep.c (catch_exception_raise): Use THREAD_FLD for exc_state member
+       access.
+
+2007-01-18  Andreas Tobler  <a.tobler@schweiz.org>
+
+       * os_dep.c (if defined(MPROTECT_VDB) && defined(DARWIN)): Clean up and
+       reformat code.
+       Correct email reference.
+
+2007-01-11  Andreas Tobler  <a.tobler@schweiz.org>
+
+       * configure.ac (i?86*-*-darwin*): Replaced HAS_I386_THREAD_STATE_* with
+       HAS_X86_THREAD_STATE32_*.
+       (x86_64-*-darwin*): Extended the above check for x86_64-*-darwin* with
+       HAS_X86_THREAD_STATE64_*.
+       Added value 1 in the above AC_DEFINE's. Important for the upcoming
+       Leopard.
+       * configure: Regenerated.
+       * include/private/gcconfig.h: Modified X86_64 define for Darwin.
+       Removed __x86_64__ check in POWERPC section. Added base definitions
+       for the X86_64 Darwin port.
+       * include/private/gc_priv.h: Added GC_MACH_HEADER and GC_MACH_SECTION
+       to distinguish between 32 and 64-bit applications. Added definitions
+       for X86_64 Darwin.
+       * darwin_stop_world.c: Added HAS_X86_THREAD_STATE64___RAX. And
+       replaced HAS_I386_THREAD_STATE___EAX with HAS_X86_THREAD_STATE32___EAX.
+       (GC_push_all_stacks): Added code for X86_64 Darwin. Even for the
+       !DARWIN_DONT_PARSE_STACK. Maybe obsolete.
+       * dyn_load.c (GC_dyld_name_for_hdr): Use GC_MACH_HEADER.
+       (GC_dyld_image_add): Use GC_MACH_HEADER and GC_MACH_SECTION.
+       Distinguish between getsectbynamefromheader_64 and
+       getsectbynamefromheader.
+       * os_dep.c (catch_exception_raise): Introduce exception definition for
+       X86_64 Darwin. Replaced old i386_EXCEPTION_STATE_* definition with
+       x86_EXCEPTION_STATE32_*. Add X86_64 for exc_state.faultvaddr.
+
+2007-01-09  Andreas Tobler  <a.tobler@schweiz.org>
+
+       * libtool.m4: Update to version from libtool-1.5.22.
+       * ltmain.sh: Likewise.
+       * ChangeLog: Created.
+
+See doc/README.changes for earlier changes.
+
index d7674b3a3e9328fca2414b27e56ad9f646ee9efa..c7e5bb806ed0fd4178f91c556197fdf39a88f7d6 100644 (file)
@@ -18,10 +18,9 @@ CC= gcc
 CXX=g++
 # Needed only for "make c++", which adds the c++ interface
 
-CFLAGS= -O -DALL_INTERIOR_POINTERS -DSILENT
+CFLAGS= -O -DALL_INTERIOR_POINTERS
 # Setjmp_test may yield overly optimistic results when compiled
 # without optimization.
-# -DSILENT disables statistics printing, and improves performance.
 # -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
 #   altered stubborn objects, at substantial performance cost.
 # -DFIND_LEAK causes the collector to assume that all inaccessible
@@ -74,7 +73,7 @@ all: gc.a gctest.exe
 $(OBJS) test.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
     $(srcdir)/gcconfig.h $(srcdir)/gc_typed.h
 # The dependency on Makefile is needed.  Changing
-# options such as -DSILENT affects the size of GC_arrays,
+# options affects the size of GC_arrays,
 # invalidating all .o files that rely on gc_priv.h
 
 mark.o typd_mlc.o finalize.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
index 23a428b9b94f23a46ed96beb86169e4a9e68ab95..9fc579f9dafe2f2055fc639c5396487fb77a22a5 100644 (file)
@@ -130,10 +130,12 @@ void GC_MacFreeTemporaryMemory()
        }
        theTemporaryMemory = NULL;
 
-#       if !defined(SILENT) && !defined(SHARED_LIBRARY_BUILD)
-          fprintf(stdout, "[total memory used:  %ld bytes.]\n",
+#       if !defined(SHARED_LIBRARY_BUILD)
+         if (GC_print_stats) {
+            fprintf(stdout, "[total memory used:  %ld bytes.]\n",
                   totalMemoryUsed);
-          fprintf(stdout, "[total collections:  %ld.]\n", GC_gc_no);
+            fprintf(stdout, "[total collections:  %ld.]\n", GC_gc_no);
+         }
 #       endif
     }
 }
index a0ff840d476ed676ce916e80eef729d801555e40..94fa27f8948fa9757bd659b2cbb6c6c6f6463c57 100644 (file)
 # Original author: Tom Tromey
 # Severely truncated by Hans-J. Boehm
 # Modified by: Grzegorz Jakacki <jakacki at acm dot org>
+# Modified by: Petter Urkedal <petter.urkedal@nordita.dk> (2005-04)
 
 ## Process this file with automake to produce Makefile.in.
 
 ## FIXME: `make distcheck' in this directory will not currently work.
 ##     This is most likely to the explicit flags passed to submakes.
 
-AUTOMAKE_OPTIONS = foreign
-
-SUBDIRS = doc include
-
+# We currently use the source files directly from libatomic_ops, if we
+# use the internal version.  This is done since libatomic_ops doesn't
+# use libtool, since it has no real use for it.  But that seems to make
+# it hard to use either the resulting object files or libraries.
+# Thus there seems too be no real reason to recusively build in the
+# libatomic_ops directory.
+# if USE_INTERNAL_LIBATOMICS_OPS
+# SUBDIRS = @maybe_libatomic_ops@
+# else
+# SUBDIRS =
+# endif
+SUBDIRS =
+
+# Initialize variables so that we can declare files locally.
 EXTRA_DIST = 
-    ## more items will be succesively added below
-
-if CPLUSPLUS
-extra = libgccpp.la
-else
-extra = 
+lib_LTLIBRARIES =
+include_HEADERS =
+pkginclude_HEADERS =
+dist_noinst_HEADERS =
+check_PROGRAMS =
+TESTS =
+
+pkgconfigdir = $(libdir)/pkgconfig
+dist_pkgconfig_DATA = bdw-gc.pc
+
+# C Library
+# ---------
+
+lib_LTLIBRARIES += libgc.la
+libgc_la_SOURCES = \
+       allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
+       dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c \
+       malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
+       obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
+       specific.c stubborn.c typd_mlc.c \
+       backgraph.c thread_local_alloc.c
+
+# C Library: Architecture Dependent
+# ---------------------------------
+
+if PTHREADS
+libgc_la_SOURCES += pthread_support.c pthread_stop_world.c
 endif
-noinst_LTLIBRARIES = libgc.la $(extra)
 
-#include_HEADERS = include/gc.h include/gc_local_alloc.h \
-#include/gc_pthread_redirects.h include/gc_config_macros.h \
-#include/leak_detector.h include/gc_typed.h @addincludes@
+if DARWIN_THREADS
+libgc_la_SOURCES += darwin_stop_world.c
+endif
 
-EXTRA_HEADERS = include/gc_cpp.h include/gc_allocator.h
+if WIN32_THREADS
+libgc_la_SOURCES += win32_threads.c
+endif
 
-if POWERPC_DARWIN
-asm_libgc_sources = powerpc_darwin_mach_dep.s
-else
-asm_libgc_sources = 
+if USE_INTERNAL_LIBATOMIC_OPS
+nodist_libgc_la_SOURCES = atomic_ops.c
 endif
 
-libgc_la_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
-dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c \
-malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
-obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
-solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
-backgraph.c win32_threads.c \
-pthread_support.c pthread_stop_world.c darwin_stop_world.c \
-$(asm_libgc_sources)
+if NEED_ATOMIC_OPS_ASM
+nodist_libgc_la_SOURCES = atomic_ops_sysdeps.S
+endif
 
 # Include THREADDLLIBS here to ensure that the correct versions of
 # linuxthread semaphore functions get linked:
 libgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS)
 libgc_la_DEPENDENCIES = @addobjs@
-libgc_la_LDFLAGS = -version-info 1:2:0
+libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info 1:3:0 -no-undefined
 
 EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
-    mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
+    mips_sgi_mach_dep.s mips_ultrix_mach_dep.s \
     rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
     sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
 
-libgccpp_la_SOURCES = gc_cpp.cc
-libgccpp_la_LIBADD = $(THREADDLLIBS) $(UNWINDLIBS)
-libgccpp_la_LDFLAGS = -version-info 1:2:0
 
-EXTRA_DIST += alpha_mach_dep.S mips_sgi_mach_dep.s sparc_mach_dep.S
-
-#AM_CXXFLAGS = @GC_CFLAGS@
-#AM_CFLAGS = @GC_CFLAGS@ -I$(top_builddir)/include
-AM_CPPFLAGS = -I$(top_builddir)/include
+# C++ Interface
+# -------------
 
 if CPLUSPLUS
-extra_checks = test_cpp
-else
-extra_checks = 
+lib_LTLIBRARIES += libgccpp.la
+pkginclude_HEADERS += include/gc_cpp.h include/gc_allocator.h
+libgccpp_la_SOURCES = gc_cpp.cc
+libgccpp_la_LIBADD = $(top_builddir)/libgc.la
+libgccpp_la_LDFLAGS = -version-info 1:3:0 -no-undefined
 endif
 
-#check_PROGRAMS = gctest $(extra_checks)
+# FIXME: If Visual C++ users use Makefile.am, this should go into
+# pkginclude_HEADERS with proper AM_CONDITIONALization.  Otherwise
+# delete this comment.
+EXTRA_DIST += gc_cpp.cpp
 
-test.o:        $(srcdir)/tests/test.c
-       $(COMPILE) -c $(srcdir)/tests/test.c
-#      Using $< in the above seems to fail with the HP/UX on Itanium make.
-test_cpp.o:    $(srcdir)/tests/test_cpp.cc
-       $(CXXCOMPILE) -c $(srcdir)/tests/test_cpp.cc
 
-## FIXME: this is probably the reason why some files from BUILT_SOURCES
-##     are included in the distribution
-# gctest_OBJECTS = test.o
-#gctest_SOURCES = tests/test.c
-#gctest_LDADD = ./libgc.la $(THREADDLLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
-#test_cpp_SOURCES = tests/test_cpp.cc
-#test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADDLLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
+# Misc
+# ----
 
-TESTS = $(check_PROGRAMS)
+#AM_CXXFLAGS = @GC_CFLAGS@
+#AM_CFLAGS = @GC_CFLAGS@
+AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_builddir)/libatomic_ops-1.2/src
 
 ## FIXME: relies on internal code generated by automake.
-all_objs = @addobjs@ $(libgc_la_OBJECTS)
-$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
-include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
-include/gc_pthread_redirects.h include/gc_config_macros.h \
-include/gc_mark.h @addincludes@
+## FIXME: ./configure --enable-dependency-tracking should be used 
+#all_objs = @addobjs@ $(libgc_la_OBJECTS)
+#$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
+#include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
+#include/gc_pthread_redirects.h include/gc_config_macros.h \
+#include/private/thread_local_alloc.h include/private_support.h \
+#include/private/pthread_stop_world.h \
+#include/gc_mark.h @addincludes@
 
 ## FIXME: we shouldn't have to do this, but automake forces us to.
+## We use -Wp,-P to strip #line directives.  Irix `as' chokes on
+## these.
 if COMPILER_XLC
   ## XLC neither requires nor tolerates the unnecessary assembler goop
   ASM_CPP_OPTIONS =
@@ -115,16 +137,10 @@ else
   ASM_CPP_OPTIONS = -Wp,-P -x assembler-with-cpp
 endif
 .s.lo:
-## We use -Wp,-P to strip #line directives.  Irix `as' chokes on
-## these.
        $(LTCOMPILE) $(ASM_CPP_OPTIONS) -c $<
 
-## We have our own definition of LTCOMPILE because we want to use our
-## CFLAGS, not those passed in from the top level make.
-#LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) \
-#      $(AM_CPPFLAGS) $(CPPFLAGS) \
-#      $(AM_CFLAGS) $(MY_CFLAGS) $(GC_CFLAGS) 
-#LINK = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(MY_CFLAGS) $(LDFLAGS) -o $@
+.S.lo:
+       $(LTCOMPILE) $(ASM_CPP_OPTIONS) -c $<
 
 ## We need to add DEFS to assembler flags
 ## :FIXME: what if assembler does not accept -D... ?
@@ -137,9 +153,9 @@ dist_noinst_SCRIPTS = callprocs configure.host
     ## configure.host --- used by Makefile.{am,dj,direct}
 
 # headers which are not installed
-# (see include/Makefile.am for more)
+# (see include/include.am for more)
 #
-dist_noinst_HEADERS = version.h
+dist_noinst_HEADERS += version.h
 
 # documentation which is not installed
 #
@@ -150,31 +166,22 @@ EXTRA_DIST += README.QUICK
 EXTRA_DIST += BCC_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE \
     OS2_MAKEFILE PCR-Makefile digimars.mak EMX_MAKEFILE        \
     Makefile.direct Makefile.dj        Makefile.DLLs SMakefile.amiga \
-    WCC_MAKEFILE
+    WCC_MAKEFILE configure_atomic_ops.sh \
+    NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE
 
 # files used by makefiles other than Makefile.am
 #
 EXTRA_DIST += add_gc_prefix.c gcname.c if_mach.c if_not_there.c \
-    hpux_test_and_clear.s pc_excludes gc.mak MacOS.c \
+    hpux_test_and_clear.s gc.mak MacOS.c \
     MacProjects.sit.hqx mach_dep.c setjmp_t.c \
     threadlibs.c AmigaOS.c \
     Mac_files/datastart.c Mac_files/dataend.c \
-    Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h
+    Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
+    include/private/msvc_dbg.h msvc_dbg.c
 
-# part of C++ interface
-#
-EXTRA_DIST += gc_cpp.cc gc_cpp.cpp
-
-# tests not used by Makefile.am (:FIXME: why?)
-#
-EXTRA_DIST += tests/test_cpp.cc tests/trace_test.c \
-    tests/leak_test.c tests/thread_leak_test.c
-
-# cord package
-#
-EXTRA_DIST += cord/cordbscs.c cord/cordtest.c cord/de.c cord/de_win.c \
-    cord/de_win.ICO cord/cordprnt.c cord/cordxtra.c cord/de_cmds.h \
-    cord/de_win.h cord/de_win.RC
+# The libatomic_ops library.  This is not ideal, since we pick up junk from
+# there.  The hard-coded version number should also go.
+EXTRA_DIST += libatomic_ops-1.2
 
 # this is an auxiliary shell file used by Makefile and Makefile.direct
 #
@@ -189,3 +196,12 @@ EXTRA_DIST += libtool.m4
 # it will not remove dest if building fails
 .S.s:
        if $(CPP) $< >$@ ; then :; else rm -f $@; fi
+
+include include/include.am
+include cord/cord.am
+include tests/tests.am
+include doc/doc.am
+# Putting these at the top causes cord to be built first, and not find libgc.a
+# on HP/UX.  There may be a better fix.
+
+
index 462a54fe70914cf17611eef3f14c83844ac8da34..40195a56255e8fe108dc2c9654ec00d0832f6ab7 100644 (file)
@@ -30,13 +30,22 @@ AS=as $(AS_ABI_FLAG)
 srcdir= .
 VPATH= $(srcdir)
 
-CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_PERMISSION -DSILENT -DALL_INTERIOR_POINTERS
+# Atomic_ops installation directory.  If this doesn't exist, we create
+# it from the included libatomic_ops distribution.
+AO_VERSION=1.2
+AO_SRC_DIR=$(srcdir)/libatomic_ops-$(AO_VERSION)
+AO_INSTALL_DIR=$(srcdir)/libatomic_ops-install
+
+CFLAGS= -O -I$(srcdir)/include -I$(AO_INSTALL_DIR)/include -DATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS
 
 # To build the parallel collector on Linux, add to the above:
 # -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
+# To build the thread-capable preload library that intercepts
+# malloc, add -DGC_USE_DLOPEN_WRAP -DREDIRECT_MALLOC=GC_malloc -fpic
 # To build the parallel collector in a static library on HP/UX,
 # add to the above:
-# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L -mt
+# -DGC_HPUX_THREADS -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L -mt
+# FIXME: PARALLEL_MARK currently broken on HP/UX.
 # To build the thread-safe collector on Tru64, add to the above:
 # -pthread -DGC_OSF1_THREADS
 
@@ -54,33 +63,41 @@ HOSTCFLAGS=$(CFLAGS)
 # without optimization.
 
 # These define arguments influence the collector configuration:
-# -DSILENT disables statistics printing, and improves performance.
 # -DFIND_LEAK causes GC_find_leak to be initially set.
 #   This causes the collector to assume that all inaccessible
 #   objects should have been explicitly deallocated, and reports exceptions.
 #   Finalization and the test program are not usable in this mode.
-# -DGC_SOLARIS_THREADS enables support for Solaris (thr_) threads.
+#
+# IMPORTANT: Any of the _THREADS options must normally also be defined in
+# the client before including gc.h.  This redefines thread primitives to
+# invoke the GC_ versions instead.  Alternatively, linker-based symbol
+# interception can be used on a few platforms.
+# -DGC_THREADS should set the appropriate one of the below macros,
+#   except -DGC_WIN32_PTHREADS, which must be set explicitly.
+# -DGC_SOLARIS_PTHREADS enables support for Solaris pthreads.
 #   (Clients should also define GC_SOLARIS_THREADS and then include
 #   gc.h before performing thr_ or dl* or GC_ operations.)
 #   Must also define -D_REENTRANT.
-# -DGC_SOLARIS_PTHREADS enables support for Solaris pthreads.
-#   (Internally this define GC_SOLARIS_THREADS as well.)
 # -DGC_IRIX_THREADS enables support for Irix pthreads.  See README.irix.
 # -DGC_HPUX_THREADS enables support for HP/UX 11 pthreads.
 #   Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
-# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
-#   see README.linux.  -D_REENTRANT may also be required.
+# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads
+#   or NPTL threads. See README.linux.  -D_REENTRANT may also be required.
 # -DGC_OSF1_THREADS enables support for Tru64 pthreads.
 # -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads.
 #   Appeared to run into some underlying thread problems.
 # -DGC_DARWIN_THREADS enables support for Mac OS X pthreads.
 # -DGC_AIX_THREADS enables support for IBM AIX threads.
 # -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
-#   See README.DGUX386.
+#   See README.DGUX386.  (Probably has not been tested recently.)
 # -DGC_WIN32_THREADS enables support for win32 threads.  That makes sense
 #   for this Makefile only under Cygwin.
-# -DGC_THREADS should set the appropriate one of the above macros.
-#   It assumes pthreads for Solaris.
+# -DGC_WIN32_PTHREADS enables support for Ming32 pthreads.  This cannot be
+#   enabled automatically by GC_THREADS, which would assume Win32 native
+#   threads.
+# -DPTW32_STATIC_LIB causes the static version of the Mingw pthreads library
+#   to be used.  Requires -DGC_WIN32_PTHREADS.
+#   
 # -DALL_INTERIOR_POINTERS allows all pointers to the interior
 #   of objects to be recognized.  (See gc_priv.h for consequences.)
 #   Alternatively, GC_all_interior_pointers can be set at process
@@ -97,13 +114,6 @@ HOSTCFLAGS=$(CFLAGS)
 #   an object can be recognized.  This can be expensive.  (The padding
 #   is normally more than one byte due to alignment constraints.)
 #   -DDONT_ADD_BYTE_AT_END disables the padding.
-# -DNO_SIGNALS does not disable signals during critical parts of
-#   the GC process.  This is no less correct than many malloc 
-#   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
@@ -155,6 +165,14 @@ HOSTCFLAGS=$(CFLAGS)
 # -DATOMIC_UNCOLLECTABLE includes code for GC_malloc_atomic_uncollectable.
 #   This is useful if either the vendor malloc implementation is poor,
 #   or if REDIRECT_MALLOC is used.
+# -DMARK_BIT_PER_GRANULE requests that a mark bit (or often byte)
+#   be allocated for each allocation granule, as opposed to each object.
+#   This often improves speed, possibly at some cost in space and/or
+#   cache footprint.  Normally it is best to let this decision be
+#   made automatically depending on platform.
+# -DMARK_BIT_PER_OBJ requests that a mark bit be allocated for each
+#   object instead of allocation granule.  The opposiet of
+#   MARK_BIT_PER_GRANULE.
 # -DHBLKSIZE=ddd, where ddd is a power of 2 between 512 and 16384, explicitly
 #   sets the heap block size.  Each heap block is devoted to a single size and
 #   kind of object.  For the incremental collector it makes sense to match
@@ -231,11 +249,17 @@ HOSTCFLAGS=$(CFLAGS)
 #   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.
-# -DTHREAD_LOCAL_ALLOC defines GC_local_malloc(), GC_local_malloc_atomic()
-#   and GC_local_gcj_malloc().  Needed for gc_gcj.h interface.  These allocate
-#   in a way that usually does not involve acquisition of a global lock.
-#   Currently works only on platforms such as Linux which use pthread_support.c.
-#   Recommended for multiprocessors.
+# -DGC_USE_DLOPEN_WRAP causes the collector to redefine malloc and intercepted
+#   pthread routines with their real names, and causes it to use dlopen
+#   and dlsym to refer to the original versions.  This makes it possible to
+#   build an LD_PRELOADable malloc replacement library.
+# -DTHREAD_LOCAL_ALLOC defines GC_malloc(), GC_malloc_atomic()
+#   and GC_gcj_malloc() to use a per-thread set of free-lists.
+#   These then allocate  in a way that usually does not involve
+#   acquisition of a global lock.  Currently supported only on platforms
+#   such as Linux that use pthread_support.c.  Recommended for multiprocessors.
+#   Requires explicit GC_INIT() call, unless REDIRECT_MALLOC is
+#   defined and GC_malloc is used first.
 # -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
 #   "__thread" thread-local variables.  This is the default in HP/UX.  It
 #   may help performance on recent Linux installations.  (It failed for
@@ -267,6 +291,10 @@ HOSTCFLAGS=$(CFLAGS)
 #   set and collected heap to grow significantly if malloced memory is
 #   somehow getting traced by the collector.  This has no impact on the
 #   generated library; it only affects the test.
+# -DNO_INCREMENTAL cases the gctest program to not invoke the incremental
+#   collector.  This has no impact on the generated library, only on the
+#   test program.  (This is often useful for debugging failures unrelated
+#   to incremental GC.)
 # -DPOINTER_MASK=0x... causes candidate pointers to be ANDed with the
 #   given mask before being considered.  If either this or the following
 #   macro is defined, it will be assumed that all pointers stored in
@@ -277,10 +305,20 @@ HOSTCFLAGS=$(CFLAGS)
 # -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers
 #   by the indicated amount before trying to interpret them.  Applied
 #   after POINTER_MASK. EXPERIMENTAL.  See also the preceding macro.
+# -DENABLE_TRACE enables the GC_TRACE=addr environment setting to do its
+#   job.  By default this is not supported in order to keep the marker as fast
+#   as possible.
 # -DDARWIN_DONT_PARSE_STACK Causes the Darwin port to discover thread
 #   stack bounds in the same way as other pthread ports, without trying to
 #   walk the frames onthe stack.  This is recommended only as a fallback
 #   for applications that don't support proper stack unwinding.
+# -DUSE_PROC_FOR_LIBRARIES Causes the Linux collector to treat writable
+#   memory mappings (as reported by /proc) as roots, if it doesn't have
+#   otherinformation about them.  It no longer traverses dynamic loader
+#   data structures to find dynamic library static data.  This may be
+#   required for applications that store pointers in mmapped segments without
+#   informaing the collector.  But it typically performs poorly, especially
+#   since it will scan inactive but cached NPTL thread stacks completely.
 #
 
 CXXFLAGS= $(CFLAGS) 
@@ -288,36 +326,47 @@ AR= ar
 RANLIB= ranlib
 
 
-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 pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_threads.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 pthread_support.o pthread_stop_world.o \
+  darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o gcj_mlc.o specific.o \
+  gc_dlopen.o backgraph.o win32_threads.o thread_local_alloc.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 pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.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 pthread_support.c pthread_stop_world.c darwin_stop_world.c \
+  typd_mlc.c ptr_chck.c mallocx.c gcj_mlc.c specific.c gc_dlopen.c \
+  backgraph.c win32_threads.c thread_local_alloc.c
 
 CORD_SRCS=  cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/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_OBJS=  cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
 
 SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.S \
-    sparc_mach_dep.S include/gc.h include/gc_typed.h \
+    sparc_mach_dep.S include/gc.h include/gc_typed.h include/gc_tiny_fl.h \
     include/private/gc_hdrs.h include/private/gc_priv.h \
     include/private/gcconfig.h include/private/gc_pmark.h \
-    include/gc_inl.h include/gc_inline.h include/gc_mark.h \
+    include/gc_inline.h include/gc_mark.h \
     threadlibs.c if_mach.c if_not_there.c gc_cpp.cc include/gc_cpp.h \
     gcname.c include/weakpointer.h include/private/gc_locks.h \
-    gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h \
+    mips_ultrix_mach_dep.s \
     include/new_gc_alloc.h include/gc_allocator.h \
     include/javaxfc.h sparc_sunos4_mach_dep.s sparc_netbsd_mach_dep.s \
-    include/private/solaris_threads.h include/gc_backptr.h \
+    include/gc_backptr.h \
     hpux_test_and_clear.s include/gc_gcj.h \
-    include/gc_local_alloc.h include/private/dbg_mlc.h \
-    include/private/specific.h powerpc_darwin_mach_dep.s \
+    include/private/dbg_mlc.h \
+    include/private/specific.h \
     include/leak_detector.h include/gc_amiga_redirects.h \
     include/gc_pthread_redirects.h ia64_save_regs_in_stack.s \
     include/gc_config_macros.h include/private/pthread_support.h \
     include/private/pthread_stop_world.h include/private/darwin_semaphore.h \
-    include/private/darwin_stop_world.h $(CORD_SRCS)
+    include/private/darwin_stop_world.h include/private/thread_local_alloc.h \
+    $(CORD_SRCS)
 
 DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
        doc/README.amiga doc/README.cords doc/debugging.html \
+       doc/porting.html doc/overview.html \
        doc/README.dj doc/README.hp doc/README.linux doc/README.rs6000 \
        doc/README.sgi doc/README.solaris2 doc/README.uts \
        doc/README.win32 doc/barrett_diagram doc/README \
@@ -326,30 +375,32 @@ DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
        doc/README.autoconf doc/README.macros doc/README.ews4800 \
        doc/README.DGUX386 doc/README.arm.cross doc/leak.html \
        doc/scale.html doc/gcinterface.html doc/README.darwin \
-       doc/simple_example.html
+       doc/simple_example.html doc/README.win64
 
 TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \
        tests/leak_test.c tests/thread_leak_test.c tests/middle.c
 
-GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \
+GNU_BUILD_FILES= configure.ac Makefile.am configure acinclude.m4 \
                 libtool.m4 install-sh configure.host Makefile.in \
                 aclocal.m4 config.sub config.guess \
-                include/Makefile.am include/Makefile.in \
-                doc/Makefile.am doc/Makefile.in \
-                ltmain.sh mkinstalldirs depcomp missing
+                include/include.am doc/doc.am \
+                ltmain.sh mkinstalldirs depcomp missing \
+                cord/cord.am tests/tests.am autogen.sh \
+                bdw-gc.pc.in compile
 
 OTHER_MAKEFILES= OS2_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE gc.mak \
                 BCC_MAKEFILE EMX_MAKEFILE WCC_MAKEFILE Makefile.dj \
                 PCR-Makefile SMakefile.amiga Makefile.DLLs \
-                digimars.mak Makefile.direct NT_STATIC_THREADS_MAKEFILE
+                digimars.mak Makefile.direct NT_STATIC_THREADS_MAKEFILE \
+                NT_X64_STATIC_THREADS_MAKEFILE configure_atomic_ops.sh
 #      Makefile and Makefile.direct are copies of each other.
 
-OTHER_FILES= Makefile setjmp_t.c callprocs pc_excludes \
+OTHER_FILES= Makefile setjmp_t.c callprocs \
            MacProjects.sit.hqx MacOS.c \
            Mac_files/datastart.c Mac_files/dataend.c \
            Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
            add_gc_prefix.c gc_cpp.cpp \
-          version.h AmigaOS.c \
+          version.h AmigaOS.c mscvc_dbg.c include/private/msvc_dbg.h \
           $(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
 
 CORD_INCLUDE_FILES= $(srcdir)/include/gc.h $(srcdir)/include/cord.h \
@@ -365,7 +416,7 @@ CURSES= -lcurses -ltermlib
 # the SHELL environment variable.
 SHELL= /bin/sh
 
-SPECIALCFLAGS = -I$(srcdir)/include
+SPECIALCFLAGS = -I$(srcdir)/include -I$(AO_INSTALL_DIR)/include
 # Alternative flags to the C compiler for mach_dep.c.
 # Mach_dep.c often doesn't like optimization, and it's
 # not time-critical anyway.
@@ -373,6 +424,12 @@ SPECIALCFLAGS = -I$(srcdir)/include
 
 all: gc.a gctest
 
+# if AO_INSTALL_DIR doesn't exist, we assume that it is pointing to
+# the default location, and we need to build
+$(AO_INSTALL_DIR): 
+       CC=$(CC) $(srcdir)/configure_atomic_ops.sh
+       cd $(AO_SRC_DIR); make CC=$(CC) install
+
 LEAKFLAGS=$(CFLAGS) -DFIND_LEAK
 
 BSD-pkg-all: bsd-libgc.a bsd-libleak.a
@@ -402,16 +459,17 @@ $(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
     $(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.h \
     $(srcdir)/include/gc.h $(srcdir)/include/gc_pthread_redirects.h \
     $(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
-    $(srcdir)/include/gc_config_macros.h Makefile
+    $(srcdir)/include/gc_config_macros.h Makefile $(AO_INSTALL_DIR)
 # The dependency on Makefile is needed.  Changing
-# options such as -DSILENT affects the size of GC_arrays,
+# options affects the size of GC_arrays,
 # invalidating all .o files that rely on gc_priv.h
 
-mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
+mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h \
+                                        $(srcdir)/include/private/gc_pmark.h
 
-specific.o pthread_support.o: $(srcdir)/include/private/specific.h
-
-solaris_threads.o solaris_pthreads.o: $(srcdir)/include/private/solaris_threads.h
+specific.o pthread_support.o thread_local_alloc.o win32_threads.o: \
+       $(srcdir)/include/private/specific.h $(srcdir)/include/gc_inline.h \
+       $(srcdir)/include/private/thread_local_alloc.h
 
 dbg_mlc.o gcj_mlc.o: $(srcdir)/include/private/dbg_mlc.h
 
@@ -425,8 +483,9 @@ tests:
 base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
        echo > base_lib
        rm -f dont_ar_1
-       ./if_mach SPARC SUNOS5 touch dont_ar_1
-       ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(OBJS) dyn_load.o
+       cp $(AO_INSTALL_DIR)/lib/libatomic_ops.a gc.a
+       ./if_mach SPARC SOLARIS touch dont_ar_1
+       ./if_mach SPARC SOLARIS $(AR) rus gc.a $(OBJS) dyn_load.o
        ./if_mach M68K AMIGA touch dont_ar_1
        ./if_mach M68K AMIGA $(AR) -vrus gc.a $(OBJS) dyn_load.o
        ./if_not_there dont_ar_1 $(AR) ru gc.a $(OBJS) dyn_load.o
@@ -435,8 +494,8 @@ base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
 
 cords: $(CORD_OBJS) cord/cordtest $(UTILS)
        rm -f dont_ar_3
-       ./if_mach SPARC SUNOS5 touch dont_ar_3
-       ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(CORD_OBJS)
+       ./if_mach SPARC SOLARIS touch dont_ar_3
+       ./if_mach SPARC SOLARIS $(AR) rus gc.a $(CORD_OBJS)
        ./if_mach M68K AMIGA touch dont_ar_3
        ./if_mach M68K AMIGA $(AR) -vrus gc.a $(CORD_OBJS)
        ./if_not_there dont_ar_3 $(AR) ru gc.a $(CORD_OBJS)
@@ -459,8 +518,8 @@ c++-nt: c++
 
 c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp
        rm -f dont_ar_4
-       ./if_mach SPARC SUNOS5 touch dont_ar_4
-       ./if_mach SPARC SUNOS5 $(AR) rus gc.a gc_cpp.o
+       ./if_mach SPARC SOLARIS touch dont_ar_4
+       ./if_mach SPARC SOLARIS $(AR) rus gc.a gc_cpp.o
        ./if_mach M68K AMIGA touch dont_ar_4
        ./if_mach M68K AMIGA $(AR) -vrus gc.a gc_cpp.o
        ./if_not_there dont_ar_4 $(AR) ru gc.a gc_cpp.o
@@ -473,7 +532,7 @@ dyn_load_sunos53.o: dyn_load.c
 
 # SunOS5 shared library version of the collector
 sunos5gc.so: $(OBJS) dyn_load_sunos53.o
-       $(CC) -G -o sunos5gc.so $(OBJS) dyn_load_sunos53.o -ldl
+       $(CC) -G -o sunos5gc.so $(OBJS) dyn_load_sunos53.o $(AO_INSTALL_DIR)/lib/libatomic_ops.a -ldl
        ln sunos5gc.so libgc.so
 
 # Alpha/OSF shared library version of the collector
@@ -491,6 +550,11 @@ liblinuxgc.so: $(OBJS) dyn_load.o
        gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o
        ln liblinuxgc.so libgc.so
 
+# Build gctest with dynamic library
+dyn_test:
+       $(CC) $(CFLAGS) -o gctest tests/test.c libgc.so `./threadlibs`
+       ./gctest
+
 # Alternative Linux rule.  This is preferable, but is likely to break the
 # Makefile for some non-linux platforms.
 # LIBOBJS= $(patsubst %.o, %.lo, $(OBJS))
@@ -506,20 +570,16 @@ liblinuxgc.so: $(OBJS) dyn_load.o
 
 mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s \
            $(srcdir)/mips_ultrix_mach_dep.s \
-            $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s \
+            $(srcdir)/rs6000_mach_dep.s \
            $(srcdir)/sparc_mach_dep.S $(srcdir)/sparc_sunos4_mach_dep.s \
            $(srcdir)/ia64_save_regs_in_stack.s \
            $(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
        rm -f mach_dep.o
-       ./if_mach MIPS IRIX5 $(CC) -c -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
-       ./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 POWERPC DARWIN $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
-       ./if_mach ALPHA LINUX $(CC) -c -o mach_dep.o $(srcdir)/alpha_mach_dep.S
-       ./if_mach SPARC SUNOS5 $(CC) -c -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
-       ./if_mach SPARC NETBSD $(AS) -o mach_dep.o $(srcdir)/sparc_netbsd_mach_dep.s
+       ./if_mach SPARC SOLARIS $(CC) -c -o mach_dep2.o $(srcdir)/sparc_mach_dep.S
+       ./if_mach SPARC OPENBSD $(AS) -o mach_dep2.o $(srcdir)/sparc_sunos4_mach_dep.s
+       ./if_mach SPARC NETBSD $(AS) -o mach_dep2.o $(srcdir)/sparc_netbsd_mach_dep.s
+       ./if_mach SPARC "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
+       ./if_mach SPARC "" ld -r -o mach_dep.o mach_dep1.o mach_dep2.o
        ./if_mach IA64 "" as $(AS_ABI_FLAG) -o ia64_save_regs_in_stack.o $(srcdir)/ia64_save_regs_in_stack.s
        ./if_mach IA64 "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
        ./if_mach IA64 "" ld -r -o mach_dep.o mach_dep1.o ia64_save_regs_in_stack.o
@@ -561,7 +621,7 @@ cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
        rm -f cord/de
        ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
        ./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 POWERPC AIX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
        ./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
        ./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 `./threadlibs`
@@ -594,7 +654,7 @@ gctest: tests/test.o gc.a $(UTILS)
 # If an optimized setjmp_test generates a segmentation fault,
 # odds are your compiler is broken.  Gctest may still work.
 # Try compiling setjmp_t.c unoptimized.
-setjmp_test: $(srcdir)/setjmp_t.c $(srcdir)/include/gc.h $(UTILS)
+setjmp_test: $(srcdir)/setjmp_t.c $(srcdir)/include/gc.h $(UTILS) $(AO_INSTALL_DIR)
        $(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c
 
 test:  KandRtest cord/cordtest
@@ -611,35 +671,27 @@ add_gc_prefix: $(srcdir)/add_gc_prefix.c $(srcdir)/version.h
 gcname: $(srcdir)/gcname.c $(srcdir)/version.h
        $(CC) -o gcname $(srcdir)/gcname.c
 
-gc.tar: $(SRCS) $(DOC_FILES) $(OTHER_FILES) add_gc_prefix gcname
+#We assume this is being done from source directory.
+dist gc.tar: $(SRCS) $(DOC_FILES) $(OTHER_FILES) add_gc_prefix gcname
        cp Makefile Makefile.old
        cp Makefile.direct Makefile
+       CC=$(CC) ./configure_atomic_ops.sh
+       cd $(AO_SRC_DIR); make dist
+       if test $(srcdir)/libatomic_ops-$(AO_VERSION) = $(AO_SRC_DIR); \
+       then \
+         mv $(AO_SRC_DIR) $(AO_SRC_DIR).bak ; \
+         tar xvfz $(AO_SRC_DIR).bak/libatomic_ops-$(AO_VERSION).tar.gz ; \
+       else \
+         tar xvfz $(AO_SRC_DIR)/libatomic_ops-$(AO_VERSION).tar.gz ; \
+       fi
        rm -f `./gcname`
        ln -s . `./gcname`
-       ./add_gc_prefix $(SRCS) $(DOC_FILES) $(OTHER_FILES) > /tmp/gc.tar-files
+       ./add_gc_prefix $(SRCS) $(DOC_FILES) $(OTHER_FILES) libatomic_ops-$(AO_VERSION) > /tmp/gc.tar-files
        tar cvfh gc.tar `cat /tmp/gc.tar-files`
        cp gc.tar `./gcname`.tar
        gzip `./gcname`.tar
        rm `./gcname`
 
-pc_gc.tar: $(SRCS) $(OTHER_FILES)
-       tar cvfX pc_gc.tar pc_excludes $(SRCS) $(OTHER_FILES)
-
-floppy: pc_gc.tar
-       -mmd a:/cord
-       -mmd a:/cord/private
-       -mmd a:/include
-       -mmd a:/include/private
-       mkdir /tmp/pc_gc
-       cat pc_gc.tar | (cd /tmp/pc_gc; tar xvf -)
-       -mcopy -tmn /tmp/pc_gc/* a:
-       -mcopy -tmn /tmp/pc_gc/cord/* a:/cord
-       -mcopy -mn /tmp/pc_gc/cord/de_win.ICO a:/cord
-       -mcopy -tmn /tmp/pc_gc/cord/private/* a:/cord/private
-       -mcopy -tmn /tmp/pc_gc/include/* a:/include
-       -mcopy -tmn /tmp/pc_gc/include/private/* a:/include/private
-       rm -r /tmp/pc_gc
-
 gc.tar.Z: gc.tar
        compress gc.tar
 
index 7757f15133d5117f2d79f61395a640911f2df31e..4618eb84562260a3ff7734cf71a290927de2ecdd 100644 (file)
@@ -29,11 +29,10 @@ EXE_SUFFIX=.exe
 srcdir= .
 VPATH= $(srcdir)
 
-CFLAGS= -gstabs+ -O2 -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION -DSILENT
+CFLAGS= -gstabs+ -O2 -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION
 
 # Setjmp_test may yield overly optimistic results when compiled
 # without optimization.
-# -DSILENT disables statistics printing, and improves performance.
 # -DFIND_LEAK causes GC_find_leak to be initially set.
 #   This causes the collector to assume that all inaccessible
 #   objects should have been explicitly deallocated, and reports exceptions.
@@ -169,7 +168,7 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
     sparc_mach_dep.S include/gc.h include/gc_typed.h \
     include/private/gc_hdrs.h include/private/gc_priv.h \
     include/private/gcconfig.h include/private/gc_mark.h \
-    include/gc_inl.h include/gc_inline.h gc.man \
+    include/gc_inline.h gc.man \
     threadlibs.c if_mach.c if_not_there.c gc_cpp.cc include/gc_cpp.h \
     include/weakpointer.h include/private/gc_locks.h \
     gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h \
@@ -177,7 +176,7 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
     include/private/solaris_threads.h include/gc_backptr.h \
     hpux_test_and_clear.s include/gc_gcj.h \
     include/gc_local_alloc.h include/private/dbg_mlc.h \
-    include/private/specific.h powerpc_darwin_mach_dep.s \
+    include/private/specific.h \
     include/leak_detector.h $(CORD_SRCS)
 
 OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
@@ -221,7 +220,7 @@ $(OBJS) test.o dyn_load.o dyn_load_sunos53.o: \
     $(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
     Makefile
 # The dependency on Makefile is needed.  Changing
-# options such as -DSILENT affects the size of GC_arrays,
+# options affects the size of GC_arrays,
 # invalidating all .o files that rely on gc_priv.h
 
 mark.o typd_mlc.o finalize.o: $(srcdir)/include/gc_mark.h
@@ -229,16 +228,16 @@ mark.o typd_mlc.o finalize.o: $(srcdir)/include/gc_mark.h
 base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
        echo > base_lib
        rm -f on_sparc_sunos5_1
-       ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_1
-       ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(OBJS) dyn_load.o
+       ./if_mach SPARC SOLARIS touch on_sparc_sunos5_1
+       ./if_mach SPARC SOLARIS $(AR) rus gc.a $(OBJS) dyn_load.o
        ./if_not_there on_sparc_sunos5_1 $(AR) ru gc.a $(OBJS) dyn_load.o
        -./if_not_there on_sparc_sunos5_1 $(RANLIB) gc.a
 #      ignore ranlib failure; that usually means it doesn't exist, and isn't needed
 
 cords: $(CORD_OBJS) cord/cordtest$(EXE_SUFFIX) $(UTILS)
        rm -f on_sparc_sunos5_3
-       ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_3
-       ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(CORD_OBJS)
+       ./if_mach SPARC SOLARIS touch on_sparc_sunos5_3
+       ./if_mach SPARC SOLARIS $(AR) rus gc.a $(CORD_OBJS)
        ./if_not_there on_sparc_sunos5_3 $(AR) ru gc.a $(CORD_OBJS)
        -./if_not_there on_sparc_sunos5_3 $(RANLIB) gc.a
 
@@ -254,8 +253,8 @@ base_lib $(UTILS)
 
 c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp$(EXE_SUFFIX)
        rm -f on_sparc_sunos5_4
-       ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_4
-       ./if_mach SPARC SUNOS5 $(AR) rus gc.a gc_cpp.o
+       ./if_mach SPARC SOLARIS touch on_sparc_sunos5_4
+       ./if_mach SPARC SOLARIS $(AR) rus gc.a gc_cpp.o
        ./if_not_there on_sparc_sunos5_4 $(AR) ru gc.a gc_cpp.o
        -./if_not_there on_sparc_sunos5_4 $(RANLIB) gc.a
        ./test_cpp$(EXE_SUFFIX) 1
@@ -285,15 +284,14 @@ liblinuxgc.so: $(OBJS) dyn_load.o
        ln liblinuxgc.so libgc.so
 
 mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S $(srcdir)/mips_ultrix_mach_dep.s \
-            $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s $(UTILS)
+            $(srcdir)/rs6000_mach_dep.s $(UTILS)
        rm -f mach_dep.o
        ./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.S
        ./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 POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
+       ./if_mach POWERPC AIX $(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 SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.S
+       ./if_mach SPARC SOLARIS $(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_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
 
old mode 100644 (file)
new mode 100755 (executable)
index d1b6a5d..c8739ef
@@ -6,17 +6,17 @@ MY_CPU=X86
 CPU=$(MY_CPU)
 !include <ntwin32.mak>
 
-OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj msvc_dbg.obj
 
 all: gctest.exe cord\de.exe test_cpp.exe
 
 .c.obj:
-       $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DSILENT -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_BUILD $*.c /Fo$*.obj
+       $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_BUILD $*.c /Fo$*.obj
 
 .cpp.obj:
-       $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DSILENT -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_BUILD $*.CPP /Fo$*.obj
+       $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_BUILD $*.CPP /Fo$*.obj
 
-$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h
+$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
 
 gc.lib: $(OBJS)
        lib /MACHINE:i386 /out:gc.lib $(OBJS)
@@ -36,7 +36,7 @@ cord\de_win.rbj: cord\de_win.res
 cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
 
 cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
-       $(rc) $(rcvars) -r -fo cord\de_win.res $(cvars) cord\de_win.rc
+       $(rc) $(rcvars) -r -fo cord\de_win.res cord\de_win.rc
 
 # Cord/de is a real win32 gui application.
 cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib
diff --git a/src/mm/boehm-gc/NT_STATIC_THREADS_MAKEFILE b/src/mm/boehm-gc/NT_STATIC_THREADS_MAKEFILE
new file mode 100644 (file)
index 0000000..d0f9127
--- /dev/null
@@ -0,0 +1,74 @@
+# Makefile for Windows NT.  Assumes Microsoft compiler.
+# DLLs are included in the root set under NT, but not under win32S.
+# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
+
+MY_CPU=X86
+CPU=$(MY_CPU)
+!include <ntwin32.mak>
+
+# Make sure that .cc is not viewed as a suffix.  It is for VC++2005, but
+# not earlier versions.  We can deal with either, but not inconsistency.
+.SUFFIXES:
+.SUFFIXES: .obj .cpp .c
+
+# Atomic_ops installation directory.  For win32, the source directory
+# should do, since we only need the headers.
+# We assume this was manually unpacked, since I'm not sure there is
+# a Windows standard command line tool to do this.
+AO_VERSION=1.2
+AO_SRC_DIR=libatomic_ops-$(AO_VERSION)/src
+AO_INCLUDE_DIR=$(AO_SRC_DIR)
+
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj msvc_dbg.obj thread_local_alloc.obj
+
+all: gctest.exe cord\de.exe test_cpp.exe
+
+.c.obj:
+       $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_WIN32_THREADS -DTHREAD_LOCAL_ALLOC $*.c /Fo$*.obj
+
+.cpp.obj:
+       $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL $*.CPP -DGC_WIN32_THREADS -DTHREAD_LOCAL_ALLOC /Fo$*.obj
+
+$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
+
+gc.lib: $(OBJS)
+       lib /MACHINE:i386 /out:gc.lib $(OBJS)
+# The original NT SDK used lib32 instead of lib
+
+gctest.exe: tests\test.obj gc.lib
+#      The following works for win32 debugging.  For win32s debugging use debugtype:coff
+#      and add mapsympe line.
+#  This produces a "GUI" applications that opens no windows and writes to the log file
+#  "gc.log".  This is done to make the result runnable under win32s.
+       $(link) -debug:full -debugtype:cv $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
+#      mapsympe -n -o gctest.sym gctest.exe
+
+cord\de_win.rbj: cord\de_win.res
+       cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
+
+cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
+
+cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
+       $(rc) $(rcvars) -r -fo cord\de_win.res cord\de_win.rc
+
+# Cord/de is a real win32 gui application.
+cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib
+       $(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe  cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
+
+gc_cpp.obj: include\gc_cpp.h include\gc.h
+
+gc_cpp.cpp: gc_cpp.cc
+       copy gc_cpp.cc gc_cpp.cpp
+
+test_cpp.cpp: tests\test_cpp.cc
+       copy tests\test_cpp.cc test_cpp.cpp
+
+# This generates the C++ test executable.  The executable expects
+# a single numeric argument, which is the number of iterations.
+# The output appears in the file "gc.log".
+test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
+       $(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
+
+AO_SCR_DIR:
+               tar xvfz $(AO_SRC_DIR).tar.gz;
+
index 5f0b5462427db7a24abf786c844b8ba97ecb2e29..5c02c9023c5627cfb46d9ebec1db1a507e863362 100644 (file)
@@ -5,6 +5,7 @@
 # TARGTYPE "Win32 (x86) Application" 0x0101
 # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
 
+AO_VERSION=1.2
 !IF "$(CFG)" == ""
 CFG=gctest - Win32 Release
 !MESSAGE No configuration specified.  Defaulting to cord - Win32 Debug.
@@ -108,16 +109,19 @@ CLEAN :
        -@erase ".\Release\typd_mlc.sbr"
        -@erase ".\Release\win32_threads.obj"
        -@erase ".\Release\win32_threads.sbr"
+       -@erase ".\Release\msvc_dbg.obj"
+       -@erase ".\Release\msvc_dbg.sbr"
 
 "$(OUTDIR)" :
     if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
 
 CPP=cl.exe
 # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "SILENT" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
-CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "SILENT" /D "GC_BUILD" /D\
+# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "GC_BUILD" /D\
  "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D\
- "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/" /c 
+ "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" \
+ /Ilibatomic_ops-$(AO_VERSION)/src /YX /Fo"$(INTDIR)/" /c 
 CPP_OBJS=.\Release/
 CPP_SBRS=.\Release/
 
@@ -173,6 +177,7 @@ BSC32_SBRS= \
        ".\Release\reclaim.sbr" \
        ".\Release\stubborn.sbr" \
        ".\Release\typd_mlc.sbr" \
+       ".\Release\msvc_dbg.sbr" \
        ".\Release\win32_threads.sbr"
 
 ".\Release\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
@@ -211,6 +216,7 @@ LINK32_OBJS= \
        ".\Release\reclaim.obj" \
        ".\Release\stubborn.obj" \
        ".\Release\typd_mlc.obj" \
+       ".\Release\msvc_dbg.obj" \
        ".\Release\win32_threads.obj"
 
 ".\Release\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -290,17 +296,20 @@ CLEAN :
        -@erase ".\Debug\vc40.pdb"
        -@erase ".\Debug\win32_threads.obj"
        -@erase ".\Debug\win32_threads.sbr"
+       -@erase ".\Debug\msvc_dbg.obj"
+       -@erase ".\Debug\msvc_dbg.sbr"
 
 "$(OUTDIR)" :
     if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
 
 CPP=cl.exe
 # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "SILENT" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
-CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "SILENT" /D "GC_BUILD"\
- /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D\
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "GC_BUILD"\
+ /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" \
+ /D "GC_ASSERTIONS" /D "__STDC__" /D\
  "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/"\
- /Fd"$(INTDIR)/" /c 
+ /Ilibatomic_ops-$(AO_VERSION)/src /Fd"$(INTDIR)/" /c 
 CPP_OBJS=.\Debug/
 CPP_SBRS=.\Debug/
 
@@ -356,6 +365,7 @@ BSC32_SBRS= \
        ".\Debug\reclaim.sbr" \
        ".\Debug\stubborn.sbr" \
        ".\Debug\typd_mlc.sbr" \
+       ".\Debug\msvc_dbg.sbr" \
        ".\Debug\win32_threads.sbr"
 
 ".\Debug\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
@@ -394,6 +404,7 @@ LINK32_OBJS= \
        ".\Debug\reclaim.obj" \
        ".\Debug\stubborn.obj" \
        ".\Debug\typd_mlc.obj" \
+       ".\Debug\msvc_dbg.obj" \
        ".\Debug\win32_threads.obj"
 
 ".\Debug\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -433,7 +444,8 @@ CPP=cl.exe
 # ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /YX /c
 CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
  "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS"\
- /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /c 
+ /Ilibatomic_ops-$(AO_VERSION)/src /Fp"$(INTDIR)/gctest.pch" \
+ /YX /Fo"$(INTDIR)/" /c 
 CPP_OBJS=.\gctest\Release/
 CPP_SBRS=.\.
 
@@ -519,7 +531,7 @@ CPP=cl.exe
 # ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
 CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
  /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR"$(INTDIR)/"\
- /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
+ /Ilibatomic_ops-$(AO_VERSION)/src /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
 CPP_OBJS=.\gctest\Debug/
 CPP_SBRS=.\gctest\Debug/
 
@@ -609,7 +621,7 @@ CPP=cl.exe
 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
 # ADD CPP /nologo /MD /W3 /GX /O2 /I "." /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
 CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "." /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
- "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c 
/Ilibatomic_ops-$(AO_VERSION)/src "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c 
 CPP_OBJS=.\cord\Release/
 CPP_SBRS=.\.
 
@@ -702,7 +714,7 @@ CPP=cl.exe
 # ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
 CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /I include /D "_DEBUG" /D "WIN32" /D\
  "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX\
- /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
+ /Ilibatomic_ops-$(AO_VERSION)/src /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
 CPP_OBJS=.\cord\Debug/
 CPP_SBRS=.\.
 
@@ -1862,6 +1874,56 @@ NODEP_CPP_WIN32=\
 ".\Debug\win32_threads.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
 
 
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\msvc_dbg.c
+
+!IF  "$(CFG)" == "gc - Win32 Release"
+
+DEP_CPP_WIN32=\
+       ".\include\private\gcconfig.h"\
+       ".\include\gc.h"\
+       ".\include\private\gc_hdrs.h"\
+       ".\include\private\gc_priv.h"\
+       ".\include\private\msvc_dbg.h"\
+       {$(INCLUDE)}"\sys\TYPES.H"\
+       
+NODEP_CPP_WIN32=\
+       ".\th\PCR_Th.h"\
+       ".\th\PCR_ThCrSec.h"\
+       ".\th\PCR_ThCtl.h"\
+       
+
+".\Release\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+".\Release\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "gc - Win32 Debug"
+
+DEP_CPP_WIN32=\
+       ".\include\private\gcconfig.h"\
+       ".\include\gc.h"\
+       ".\include\private\gc_hdrs.h"\
+       ".\include\private\gc_priv.h"\
+       ".\include\private\msvc_dbg.h"\
+       {$(INCLUDE)}"\sys\TYPES.H"\
+       
+NODEP_CPP_WIN32=\
+       ".\th\PCR_Th.h"\
+       ".\th\PCR_ThCrSec.h"\
+       ".\th\PCR_ThCtl.h"\
+       
+
+".\Debug\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+".\Debug\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+
 !ENDIF 
 
 # End Source File
diff --git a/src/mm/boehm-gc/NT_X64_STATIC_THREADS_MAKEFILE b/src/mm/boehm-gc/NT_X64_STATIC_THREADS_MAKEFILE
new file mode 100644 (file)
index 0000000..91a0f60
--- /dev/null
@@ -0,0 +1,74 @@
+# Makefile for Windows NT.  Assumes Microsoft compiler.
+# DLLs are included in the root set under NT, but not under win32S.
+# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
+
+MY_CPU=AMD64
+CPU=$(MY_CPU)
+!include <ntwin32.mak>
+
+# Make sure that .cc is not viewed as a suffix.  It is for VC++2005, but
+# not earlier versions.  We can deal with either, but not inconsistency.
+.SUFFIXES:
+.SUFFIXES: .obj .cpp .c
+
+# Atomic_ops installation directory.  For win32, the source directory
+# should do, since we only need the headers.
+# We assume this was manually unpacked, since I'm not sure there is
+# a Windows standard command line tool to do this.
+AO_VERSION=1.2
+AO_SRC_DIR=libatomic_ops-$(AO_VERSION)/src
+AO_INCLUDE_DIR=$(AO_SRC_DIR)
+
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj msvc_dbg.obj thread_local_alloc.obj
+
+all: gctest.exe cord\de.exe test_cpp.exe
+
+.c.obj:
+       $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_WIN32_THREADS -DTHREAD_LOCAL_ALLOC $*.c /Fo$*.obj /wd4701 -D_CRT_SECURE_NO_DEPRECATE
+# Disable "may not be initialized" warnings.  They're too approximate.
+# Disable crt security warnings, since unfortunately they warn about all sorts
+# of safe uses of strncpy.  It would be nice to leave the rest enabled.
+
+.cpp.obj:
+       $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL $*.CPP -DGC_WIN32_THREADS -DTHREAD_LOCAL_ALLOC /Fo$*.obj -D_CRT_SECURE_NO_DEPRECATE
+
+$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
+
+gc.lib: $(OBJS)
+       lib /MACHINE:X64 /out:gc.lib $(OBJS)
+
+gctest.exe: tests\test.obj gc.lib
+#  This produces a "GUI" applications that opens no windows and writes to the log file
+#  "gc.log".  This was done to make the result runnable under win32s and
+#  should be fixed.
+       $(link) $(ldebug) $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
+
+cord\de_win.rbj: cord\de_win.res
+       cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
+
+cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
+
+cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
+       $(rc) $(rcvars) -r -fo cord\de_win.res cord\de_win.rc
+
+# Cord/de is a real win32 gui application.
+cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib
+       $(link) $(ldebug) $(guiflags) -stack:16384 -out:cord\de.exe  cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
+
+gc_cpp.obj: include\gc_cpp.h include\gc.h
+
+gc_cpp.cpp: gc_cpp.cc
+       copy gc_cpp.cc gc_cpp.cpp
+
+test_cpp.cpp: tests\test_cpp.cc
+       copy tests\test_cpp.cc test_cpp.cpp
+
+# This generates the C++ test executable.  The executable expects
+# a single numeric argument, which is the number of iterations.
+# The output appears in the file "gc.log".
+test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
+       $(link) $(ldebug) $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
+
+AO_SCR_DIR:
+               tar xvfz $(AO_SRC_DIR).tar.gz;
+
index 690598d69d4ad1ba21cdb38e34c65cf9b852b234..c6bad7abcb5b9c16a64ef26a1df4bd62644c98fd 100644 (file)
@@ -10,7 +10,7 @@ OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_r
 CORDOBJS= cord\cordbscs.obj cord\cordxtra.obj cord\cordprnt.obj
 
 CC= icc
-CFLAGS= /O /Q /DSILENT /DSMALL_CONFIG /DALL_INTERIOR_POINTERS
+CFLAGS= /O /Q /DSMALL_CONFIG /DALL_INTERIOR_POINTERS
 # Use /Ti instead of /O for debugging
 # Setjmp_test may yield overly optimistic results when compiled
 # without optimization.
index 1eae36725569152a535fc8574f34eb276269dd82..db4c9f01819d0d8df2b1466c259fa7b6e8439fef 100644 (file)
@@ -13,7 +13,7 @@ include ../config/common.mk
 
 CPPFLAGS = $(INCLUDE) $(CONFIG_CPPFLAGS) \
        -DPCR_NO_RENAME -DPCR_NO_HOSTDEP_ERR
-#CFLAGS        = -DPCR -DSILENT $(CONFIG_CFLAGS)
+#CFLAGS        = -DPCR $(CONFIG_CFLAGS)
 CFLAGS = -DPCR $(CONFIG_CFLAGS)
 SPECIALCFLAGS =        # For code involving asm's
 
@@ -54,9 +54,9 @@ gc.o: $(COBJ) mach_dep.o
 mach_dep.o: mach_dep.c mips_mach_dep.s rs6000_mach_dep.s if_mach if_not_there
        rm -f mach_dep.o
        ./if_mach MIPS "" as -o mach_dep.o mips_mach_dep.s
-       ./if_mach RS6000 "" as -o mach_dep.o rs6000_mach_dep.s
+       ./if_mach POWERPC AIX as -o mach_dep.o rs6000_mach_dep.s
        ./if_mach ALPHA "" as -o mach_dep.o alpha_mach_dep.s
-       ./if_mach SPARC SUNOS5 as -o mach_dep.o sparc_mach_dep.s
+       ./if_mach SPARC SOLARIS as -o mach_dep.o sparc_mach_dep.s
        ./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) mach_dep.c
 
 if_mach: if_mach.c gcconfig.h
index 8294a87d9ea2614a64deb9cc72baf716ff154950..5ffa505c9e8ab0a7cf0d55ca12ce17c7fc6a1491 100644 (file)
@@ -27,34 +27,37 @@ For the version number, see doc/README or version.h.
 INSTALLATION:
 Under UN*X, Linux:
 Alternative 1 (the old way): type "make test" in this directory.
-       Link against gc.a.
+       Link against gc.a.  With the most recent GC distributions
+       you may have to copy Makefile.direct to Makefile first.
 
 Alternative 2 (the new way): type
        "./configure --prefix=<dir>; make; make check; make install".
        Link against <dir>/lib/libgc.a or <dir>/lib/libgc.so.
        See README.autoconf for details
 
-Under OS/2 or Windows 95, 98, Me, NT, or 2000:
+Under Windows 95, 98, Me, NT, or 2000:
 copy the appropriate makefile to MAKEFILE, read it, and type "nmake test".
 (Under Windows, this assumes you have Microsoft command-line tools
-installed, and have DOS configured with enough environment space to run them.)
+installed, and suitably configured.)
 Read the machine specific README in the doc directory if one exists.
-The only way to develop code with the collector for Windows 3.1 is
-to develop under Windows NT or 95+, and then to use win32S.
 
-If you need thread support, you will need to either follow the special
-platform-dependent instructions (win32), or add a suitable define
-option as described in Makefile.
+If you need thread support, you will need to follow the special
+platform-dependent instructions (win32), or define GC_THREADS
+as described in Makefile (Makefile.direct), or possibly use
+--enable-threads=posix when running the configure script.
 
-If you wish to use the cord (structured string) library, type
-"make cords". (This requires an ANSI C compiler.  You may need
-to redefine CC in the Makefile. The CORD_printf implementation in
-cordprnt.c is known to be less than perfectly portable.  The rest
-of the package should still work.)
+If you wish to use the cord (structured string) library with the stand-alone
+Makefile.direct, type "make cords", after copying to "Makefile".
+(This requires an ANSI C compiler.  You may
+need to redefine CC in the Makefile. The CORD_printf implementation in
+cordprnt.c is known to be less than perfectly portable.  The rest of the
+package should still work.)
 
-If you wish to use the collector from C++, type
-"make c++".  These add further files to gc.a and to the include
-subdirectory.  See cord/cord.h and include/gc_cpp.h.
+If you wish to use the collector from C++, type "make c++", or use
+--enable-cplusplus with the configure script.   With Makefile.direct,
+hese add further files to gc.a and to the include subdirectory.  With the
+alternat build process,this generates libgccpp.
+See cord/cord.h and include/gc_cpp.h.
 
 TYPICAL USE:
 Include "gc.h" from the include subdirectory.  Link against the
@@ -67,7 +70,7 @@ Define GC_DEBUG before including gc.h for additional checking.
 
 More documentation on the collector interface can be found at
 http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcinterface.html,
-in doc/README, and in include/gc.h .
+in doc/README and other files in the doc directory, and in include/gc.h .
 
 WARNINGS:
 
index e2085051bbc940ee976e05b8ea1cbc0f07e303d2..94fb723865ca108ce3a54fdfc64746aab819ad10 100644 (file)
@@ -26,7 +26,6 @@ OPTIMIZE=optimize optimizetime optglobal optimizerdepth=100 optimizerpeephole op
 
 OPT= $(OPTIMIZE) CPU=$(CPU) math=$(MATH) NOSTACKCHECK VERBOSE \
 MAPHUNK NOVERSION NOICONS nodebug \
-DEFINE SILENT \
 parm=reg \
 DEFINE __USE_SYSBASE
 
index 32b01df175415432a1d76f1bca8f25045c6779dd..6b1d78baecd7d96b8cd29cc52f63b6afe0110e36 100644 (file)
@@ -25,7 +25,7 @@ CPU=5
 OPTIM=-oneatx -s
 #OPTIM=-ohneatx -s
 
-DEFS=-DALL_INTERIOR_POINTERS -DSILENT -DNO_SIGNALS #-DSMALL_CONFIG #-DGC_DEBUG
+DEFS=-DALL_INTERIOR_POINTERS #-DSMALL_CONFIG #-DGC_DEBUG
 
 
 #####
@@ -98,13 +98,13 @@ gc.dll: $(OBJS) .AUTODEPEND
         @for %i in ($(OBJS)) do @%append $*.lnk file '%i'
 !ifeq CALLING s
       @%append $*.lnk export GC_is_marked
-      @%append $*.lnk export GC_incr_words_allocd
-      @%append $*.lnk export GC_incr_mem_freed
+      @%append $*.lnk export GC_incr_bytes_allocd
+      @%append $*.lnk export GC_incr_bytes_freed
       @%append $*.lnk export GC_generic_malloc_words_small
 !else
       @%append $*.lnk export GC_is_marked_
-      @%append $*.lnk export GC_incr_words_allocd_
-      @%append $*.lnk export GC_incr_mem_freed_
+      @%append $*.lnk export GC_incr_bytes_allocd_
+      @%append $*.lnk export GC_incr_bytes_freed_
       @%append $*.lnk export GC_generic_malloc_words_small_
 !endif
         *wlink @$*.lnk
@@ -156,12 +156,12 @@ test_cpp.exe: test_cpp.obj gc.lib
         @%append $*.lnk library gc.lib
 !ifdef MAKE_AS_DLL
 !ifeq CALLING s
-      @%append $*.lnk import GC_incr_words_allocd gc
-      @%append $*.lnk import GC_incr_mem_freed gc
+      @%append $*.lnk import GC_incr_bytes_allocd gc
+      @%append $*.lnk import GC_incr_bytes_freed gc
       @%append $*.lnk import GC_generic_malloc_words_small gc
 !else
-      @%append $*.lnk import GC_incr_words_allocd_ gc
-      @%append $*.lnk import GC_incr_mem_freed_ gc
+      @%append $*.lnk import GC_incr_bytes_allocd_ gc
+      @%append $*.lnk import GC_incr_bytes_freed_ gc
       @%append $*.lnk import GC_generic_malloc_words_small_ gc
 !endif
 !endif
index aec95dd11d559b5b4977f2caf369fe1d60ca404a..b91806f0c725f9edf603dfb083d9be67240e866b 100644 (file)
@@ -58,9 +58,7 @@ struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
 # ifdef __GNUC__
   __inline__
 # endif
-  static GC_bool GC_enough_large_bytes_left(bytes,n)
-  word bytes;
-  int n;
+  static GC_bool GC_enough_large_bytes_left(word bytes, int n)
   {
     int i;
     for (i = N_HBLK_FLS; i >= n; --i) {
@@ -82,12 +80,11 @@ struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
 #endif /* USE_MUNMAP */
 
 /* Map a number of blocks to the appropriate large block free list index. */
-int GC_hblk_fl_from_blocks(blocks_needed)
-word blocks_needed;
+int GC_hblk_fl_from_blocks(word blocks_needed)
 {
-    if (blocks_needed <= UNIQUE_THRESHOLD) return blocks_needed;
+    if (blocks_needed <= UNIQUE_THRESHOLD) return (int)blocks_needed;
     if (blocks_needed >= HUGE_THRESHOLD) return N_HBLK_FLS;
-    return (blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
+    return (int)(blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
                                        + UNIQUE_THRESHOLD;
     
 }
@@ -108,46 +105,44 @@ void GC_print_hblkfreelist()
     word total_free = 0;
     hdr * hhdr;
     word sz;
-    int i;
+    unsigned i;
     
     for (i = 0; i <= N_HBLK_FLS; ++i) {
       h = GC_hblkfreelist[i];
 #     ifdef USE_MUNMAP
-        if (0 != h) GC_printf1("Free list %ld:\n",
-                              (unsigned long)i);
+        if (0 != h) GC_printf("Free list %ld:\n",
+                             (unsigned long)i);
 #     else
-        if (0 != h) GC_printf2("Free list %ld (Total size %ld):\n",
-                              (unsigned long)i,
-                              (unsigned long)GC_free_bytes[i]);
+        if (0 != h) GC_printf("Free list %lu (Total size %lu):\n",
+                             i, (unsigned long)GC_free_bytes[i]);
 #     endif
       while (h != 0) {
         hhdr = HDR(h);
         sz = hhdr -> hb_sz;
-       GC_printf2("\t0x%lx size %lu ", (unsigned long)h, (unsigned long)sz);
+       GC_printf("\t%p size %lu ", h, (unsigned long)sz);
        total_free += sz;
         if (GC_is_black_listed(h, HBLKSIZE) != 0) {
-             GC_printf0("start black listed\n");
+             GC_printf("start black listed\n");
         } else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0) {
-             GC_printf0("partially black listed\n");
+             GC_printf("partially black listed\n");
         } else {
-             GC_printf0("not black listed\n");
+             GC_printf("not black listed\n");
         }
         h = hhdr -> hb_next;
       }
     }
 #   ifndef USE_MUNMAP
       if (total_free != GC_large_free_bytes) {
-       GC_printf1("GC_large_free_bytes = %lu (INCONSISTENT!!)\n",
-                  (unsigned long) GC_large_free_bytes);
+       GC_printf("GC_large_free_bytes = %lu (INCONSISTENT!!)\n",
+                 (unsigned long) GC_large_free_bytes);
       }
 #   endif
-    GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free);
+    GC_printf("Total of %lu bytes on free list\n", (unsigned long)total_free);
 }
 
 /* Return the free list index on which the block described by the header */
 /* appears, or -1 if it appears nowhere.                                */
-int free_list_index_of(wanted)
-hdr * wanted;
+int free_list_index_of(hdr *wanted)
 {
     struct hblk * h;
     hdr * hhdr;
@@ -180,12 +175,12 @@ void GC_dump_regions()
            ++i;
            end = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
          }
-       GC_printf2("***Section from 0x%lx to 0x%lx\n", start, end);
+       GC_printf("***Section from %p to %p\n", start, end);
        for (p = start; p < end;) {
            hhdr = HDR(p);
-           GC_printf1("\t0x%lx ", (unsigned long)p);
+           GC_printf("\t%p ", p);
            if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
-               GC_printf1("Missing header!!(%ld)\n", hhdr);
+               GC_printf("Missing header!!(%d)\n", hhdr);
                p += HBLKSIZE;
                continue;
            }
@@ -194,25 +189,25 @@ void GC_dump_regions()
                                        divHBLKSZ(hhdr -> hb_sz));
                int actual_index;
                
-               GC_printf1("\tfree block of size 0x%lx bytes",
-                          (unsigned long)(hhdr -> hb_sz));
+               GC_printf("\tfree block of size 0x%lx bytes",
+                         (unsigned long)(hhdr -> hb_sz));
                if (IS_MAPPED(hhdr)) {
-                   GC_printf0("\n");
+                   GC_printf("\n");
                } else {
-                   GC_printf0("(unmapped)\n");
+                   GC_printf("(unmapped)\n");
                }
                actual_index = free_list_index_of(hhdr);
                if (-1 == actual_index) {
-                   GC_printf1("\t\tBlock not on free list %ld!!\n",
-                               correct_index);
+                   GC_printf("\t\tBlock not on free list %d!!\n",
+                             correct_index);
                } else if (correct_index != actual_index) {
-                   GC_printf2("\t\tBlock on list %ld, should be on %ld!!\n",
-                              actual_index, correct_index);
+                   GC_printf("\t\tBlock on list %d, should be on %d!!\n",
+                             actual_index, correct_index);
                }
                p += hhdr -> hb_sz;
            } else {
-               GC_printf1("\tused for blocks of size 0x%lx bytes\n",
-                          (unsigned long)WORDS_TO_BYTES(hhdr -> hb_sz));
+               GC_printf("\tused for blocks of size 0x%lx bytes\n",
+                         (unsigned long)(hhdr -> hb_sz));
                p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
            }
        }
@@ -224,25 +219,56 @@ void GC_dump_regions()
 /* Initialize hdr for a block containing the indicated size and        */
 /* kind of objects.                                                    */
 /* Return FALSE on failure.                                            */
-static GC_bool setup_header(hhdr, sz, kind, flags)
-register hdr * hhdr;
-word sz;       /* object size in words */
-int kind;
-unsigned char flags;
+static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
+                           int kind, unsigned flags)
 {
-    register word descr;
+    word descr;
+    size_t granules;
     
-    /* Add description of valid object pointers */
-      if (!GC_add_map_entry(sz)) return(FALSE);
-      hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
-      
     /* Set size, kind and mark proc fields */
-      hhdr -> hb_sz = sz;
-      hhdr -> hb_obj_kind = kind;
-      hhdr -> hb_flags = flags;
+      hhdr -> hb_sz = byte_sz;
+      hhdr -> hb_obj_kind = (unsigned char)kind;
+      hhdr -> hb_flags = (unsigned char)flags;
+      hhdr -> hb_block = block;
       descr = GC_obj_kinds[kind].ok_descriptor;
-      if (GC_obj_kinds[kind].ok_relocate_descr) descr += WORDS_TO_BYTES(sz);
+      if (GC_obj_kinds[kind].ok_relocate_descr) descr += byte_sz;
       hhdr -> hb_descr = descr;
+    
+#   ifdef MARK_BIT_PER_OBJ
+     /* Set hb_inv_sz as portably as possible.                                 */
+     /* We set it to the smallest value such that sz * inv_sz > 2**32    */
+     /* This may be more precision than necessary.                     */
+      if (byte_sz > MAXOBJBYTES) {
+        hhdr -> hb_inv_sz = LARGE_INV_SZ;
+      } else {
+       word inv_sz;
+
+#       if CPP_WORDSZ == 64
+          inv_sz = ((word)1 << 32)/byte_sz;
+         if (((inv_sz*byte_sz) >> 32) == 0) ++inv_sz;
+#      else  /* 32 bit words */
+         GC_ASSERT(byte_sz >= 4);
+         inv_sz = ((unsigned)1 << 31)/byte_sz;
+         inv_sz *= 2;
+         while (inv_sz*byte_sz > byte_sz) ++inv_sz;
+#      endif
+       hhdr -> hb_inv_sz = inv_sz;
+      }
+#   else /* MARK_BIT_PER_GRANULE */
+      hhdr -> hb_large_block = (unsigned char)(byte_sz > MAXOBJBYTES);
+      granules = BYTES_TO_GRANULES(byte_sz);
+      if (EXPECT(!GC_add_map_entry(granules), FALSE)) {
+        /* Make it look like a valid block. */
+        hhdr -> hb_sz = HBLKSIZE;
+        hhdr -> hb_descr = 0;
+        hhdr -> hb_large_block = TRUE;
+        hhdr -> hb_map = 0;
+        return FALSE;
+      } else {
+        size_t index = (hhdr -> hb_large_block? 0 : granules);
+        hhdr -> hb_map = GC_obj_map[index];
+      }
+#   endif /* MARK_BIT_PER_GRANULE */
       
     /* Clear mark bits */
       GC_clear_hdr_marks(hhdr);
@@ -257,9 +283,7 @@ unsigned char flags;
  * We assume it is on the nth free list, or on the size
  * appropriate free list if n is FL_UNKNOWN.
  */
-void GC_remove_from_fl(hhdr, n)
-hdr * hhdr;
-int n;
+void GC_remove_from_fl(hdr *hhdr, int n)
 {
     int index;
 
@@ -300,8 +324,7 @@ int n;
 /*
  * Return a pointer to the free block ending just before h, if any.
  */
-struct hblk * GC_free_block_ending_at(h)
-struct hblk *h;
+struct hblk * GC_free_block_ending_at(struct hblk *h)
 {
     struct hblk * p = h - 1;
     hdr * phdr;
@@ -332,9 +355,7 @@ struct hblk *h;
  * Add hhdr to the appropriate free list.
  * We maintain individual free lists sorted by address.
  */
-void GC_add_to_fl(h, hhdr)
-struct hblk *h;
-hdr * hhdr;
+void GC_add_to_fl(struct hblk *h, hdr *hhdr)
 {
     int index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
     struct hblk *second = GC_hblkfreelist[index];
@@ -357,7 +378,7 @@ hdr * hhdr;
       GET_HDR(second, second_hdr);
       second_hdr -> hb_prev = h;
     }
-    GC_invalidate_map(hhdr);
+    hhdr -> hb_flags |= FREE_BLK;
 }
 
 #ifdef USE_MUNMAP
@@ -457,11 +478,8 @@ void GC_merge_unmapped(void)
  * The header for the returned block must be set up by the caller.
  * If the return value is not 0, then hhdr is the header for it.
  */
-struct hblk * GC_get_first_part(h, hhdr, bytes, index)
-struct hblk *h;
-hdr * hhdr;
-word bytes;
-int index;
+struct hblk * GC_get_first_part(struct hblk *h, hdr *hhdr,
+                               size_t bytes, int index)
 {
     word total_size = hhdr -> hb_sz;
     struct hblk * rest;
@@ -473,7 +491,7 @@ int index;
     rest = (struct hblk *)((word)h + bytes);
     rest_hdr = GC_install_header(rest);
     if (0 == rest_hdr) {
-       /* This may be very bad news ... */
+       /* FIXME: This is likely to be very bad news ... */
        WARN("Header allocation failed: Dropping block.\n", 0);
        return(0);
     }
@@ -481,7 +499,7 @@ int index;
     rest_hdr -> hb_flags = 0;
 #   ifdef GC_ASSERTIONS
       /* Mark h not free, to avoid assertion about adjacent free blocks. */
-        hhdr -> hb_map = 0;
+        hhdr -> hb_flags &= ~FREE_BLK;
 #   endif
     GC_add_to_fl(rest, rest_hdr);
     return h;
@@ -499,12 +517,8 @@ int index;
  * (Hence adding it to a free list is silly.  But this path is hopefully
  * rare enough that it doesn't matter.  The code is cleaner this way.)
  */
-void GC_split_block(h, hhdr, n, nhdr, index)
-struct hblk *h;
-hdr * hhdr;
-struct hblk *n;
-hdr * nhdr;
-int index;     /* Index of free list */
+void GC_split_block(struct hblk *h, hdr *hhdr, struct hblk *n,
+                   hdr *nhdr, int index /* Index of free list */)
 {
     word total_size = hhdr -> hb_sz;
     word h_size = (word)n - (word)h;
@@ -527,7 +541,8 @@ int index;  /* Index of free list */
       INCR_FREE_BYTES(index, -(signed_word)h_size);
       FREE_ASSERT(GC_free_bytes[index] > 0);
 #     ifdef GC_ASSERTIONS
-       nhdr -> hb_map = 0;     /* Don't fail test for consecutive      */
+       nhdr -> hb_flags &= ~FREE_BLK;
+                               /* Don't fail test for consecutive      */
                                /* free blocks in GC_add_to_fl.         */
 #     endif
 #   ifdef USE_MUNMAP
@@ -535,30 +550,31 @@ int index;        /* Index of free list */
 #   endif
     hhdr -> hb_sz = h_size;
     GC_add_to_fl(h, hhdr);
-    GC_invalidate_map(nhdr);
+    nhdr -> hb_flags |= FREE_BLK;
 }
        
-struct hblk * GC_allochblk_nth();
+struct hblk *
+GC_allochblk_nth(size_t sz/* bytes */, int kind, unsigned flags, int n);
 
 /*
  * Allocate (and return pointer to) a heap block
- *   for objects of size sz words, searching the nth free list.
+ *   for objects of size sz bytes, searching the nth free list.
  *
  * NOTE: We set obj_map field in header correctly.
  *       Caller is responsible for building an object freelist in block.
  *
- * Unlike older versions of the collectors, the client is responsible
- * for clearing the block, if necessary.
+ * The client is responsible for clearing the block, if necessary.
  */
 struct hblk *
-GC_allochblk(sz, kind, flags)
-word sz;
-int kind;
-unsigned flags;  /* IGNORE_OFF_PAGE or 0 */
+GC_allochblk(size_t sz, int kind, unsigned flags/* IGNORE_OFF_PAGE or 0 */)
 {
-    word blocks = OBJ_SZ_TO_BLOCKS(sz);
-    int start_list = GC_hblk_fl_from_blocks(blocks);
+    word blocks;
+    int start_list;
     int i;
+
+    GC_ASSERT((sz & (GRANULE_BYTES - 1)) == 0);
+    blocks = OBJ_SZ_TO_BLOCKS(sz);
+    start_list = GC_hblk_fl_from_blocks(blocks);
     for (i = start_list; i <= N_HBLK_FLS; ++i) {
        struct hblk * result = GC_allochblk_nth(sz, kind, flags, i);
        if (0 != result) {
@@ -569,18 +585,18 @@ unsigned flags;  /* IGNORE_OFF_PAGE or 0 */
 }
 /*
  * The same, but with search restricted to nth free list.
+ * Flags is IGNORE_OFF_PAGE or zero.
+ * Unlike the above, sz is in bytes.
  */
 struct hblk *
-GC_allochblk_nth(sz, kind, flags, n)
-word sz;
-int kind;
-unsigned char flags;  /* IGNORE_OFF_PAGE or 0 */
-int n;
+GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n)
 {
-    register struct hblk *hbp;
-    register hdr * hhdr;               /* Header corr. to hbp */
-    register struct hblk *thishbp;
-    register hdr * thishdr;            /* Header corr. to hbp */
+    struct hblk *hbp;
+    hdr * hhdr;                /* Header corr. to hbp */
+                       /* Initialized after loop if hbp !=0    */
+                       /* Gcc uninitialized use warning is bogus.      */
+    struct hblk *thishbp;
+    hdr * thishdr;             /* Header corr. to hbp */
     signed_word size_needed;    /* number of bytes in requested objects */
     signed_word size_avail;    /* bytes available in this block        */
 
@@ -611,8 +627,7 @@ int n;
                    /* If we are deallocating lots of memory from       */
                    /* finalizers, fail and collect sooner rather       */
                    /* than later.                                      */
-                   if (WORDS_TO_BYTES(GC_finalizer_mem_freed)
-                       > (GC_heapsize >> 4))  {
+                   if (GC_finalizer_bytes_freed > (GC_heapsize >> 4))  {
                      continue;
                    }
 #              endif /* !USE_MUNMAP */
@@ -702,14 +717,13 @@ int n;
                      struct hblk * h;
                      struct hblk * prev = hhdr -> hb_prev;
                      
-                     GC_words_wasted += BYTES_TO_WORDS(total_size);
                      GC_large_free_bytes -= total_size;
                      GC_remove_from_fl(hhdr, n);
                      for (h = hbp; h < limit; h++) {
                        if (h == hbp || 0 != (hhdr = GC_install_header(h))) {
                          (void) setup_header(
-                                 hhdr,
-                                 BYTES_TO_WORDS(HBLKSIZE),
+                                 hhdr, h,
+                                 HBLKSIZE,
                                  PTRFREE, 0); /* Cant fail */
                          if (GC_debugging_started) {
                            BZERO(h, HBLKSIZE);
@@ -747,7 +761,7 @@ int n;
        /* This leaks memory under very rare conditions. */
                
     /* Set up header */
-        if (!setup_header(hhdr, sz, kind, flags)) {
+        if (!setup_header(hhdr, hbp, sz, kind, flags)) {
             GC_remove_counts(hbp, (word)size_needed);
             return(0); /* ditto */
         }
@@ -781,8 +795,7 @@ struct hblk * GC_freehblk_ptr = 0;  /* Search position hint for GC_freehblk */
  * All mark words are assumed to be cleared.
  */
 void
-GC_freehblk(hbp)
-struct hblk *hbp;
+GC_freehblk(struct hblk *hbp)
 {
 struct hblk *next, *prev;
 hdr *hhdr, *prevhdr, *nexthdr;
@@ -800,13 +813,12 @@ signed_word size;
     
     /* Check for duplicate deallocation in the easy case */
       if (HBLK_IS_FREE(hhdr)) {
-        GC_printf1("Duplicate large block deallocation of 0x%lx\n",
-                  (unsigned long) hbp);
+        GC_printf("Duplicate large block deallocation of %p\n", hbp);
        ABORT("Duplicate large block deallocation");
       }
 
     GC_ASSERT(IS_MAPPED(hhdr));
-    GC_invalidate_map(hhdr);
+    hhdr -> hb_flags |= FREE_BLK;
     next = (struct hblk *)((word)hbp + size);
     GET_HDR(next, nexthdr);
     prev = GC_free_block_ending_at(hbp);
index 5cd25cc03058d512ec38140cd7dac832ca93065c..b0808d69c19260634a8b062e97c4c57a7e50ee9f 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1998 by Silicon Graphics.  All rights reserved.
- * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -27,7 +27,7 @@
 
 /*
  * Separate free lists are maintained for different sized objects
- * up to MAXOBJSZ.
+ * up to MAXOBJBYTES.
  * The call GC_allocobj(i,k) ensures that the freelist for
  * kind k objects of size i points to a non-empty
  * free list. It returns a pointer to the first entry on the free list.
@@ -93,19 +93,9 @@ char * GC_copyright[] =
 
 # include "version.h"
 
-#if defined(SAVE_CALL_CHAIN) && \
-       !(defined(REDIRECT_MALLOC) && defined(GC_HAVE_BUILTIN_BACKTRACE))
-#   define SAVE_CALL_CHAIN_IN_GC
-    /* This is only safe if the call chain save mechanism won't end up */
-    /* calling GC_malloc.  The GNU C library documentation suggests    */
-    /* that backtrace doesn't use malloc, but at least the initial     */
-    /* call in some versions does seem to invoke the dynamic linker,   */
-    /* which uses malloc.                                              */
-#endif
-
 /* some more variables */
 
-extern signed_word GC_mem_found;  /* Number of reclaimed longwords     */
+extern signed_word GC_bytes_found; /* Number of reclaimed bytes                */
                                  /* after garbage collection           */
 
 GC_bool GC_dont_expand = 0;
@@ -115,7 +105,7 @@ word GC_free_space_divisor = 3;
 extern GC_bool GC_collection_in_progress();
                /* Collection is in progress, or was abandoned. */
 
-int GC_never_stop_func GC_PROTO((void)) { return(0); }
+int GC_never_stop_func (void) { return(0); }
 
 unsigned long GC_time_limit = TIME_LIMIT;
 
@@ -128,7 +118,7 @@ int GC_n_attempts = 0;              /* Number of attempts at finishing      */
 #if defined(SMALL_CONFIG) || defined(NO_CLOCK)
 #   define GC_timeout_stop_func GC_never_stop_func
 #else
-  int GC_timeout_stop_func GC_PROTO((void))
+  int GC_timeout_stop_func (void)
   {
     CLOCK_TYPE current_time;
     static unsigned count = 0;
@@ -138,13 +128,11 @@ int GC_n_attempts = 0;            /* Number of attempts at finishing      */
     GET_TIME(current_time);
     time_diff = MS_TIME_DIFF(current_time,GC_start_time);
     if (time_diff >= GC_time_limit) {
-#      ifdef CONDPRINT
-         if (GC_print_stats) {
-           GC_printf0("Abandoning stopped marking after ");
-           GC_printf1("%lu msecs", (unsigned long)time_diff);
-           GC_printf1("(attempt %ld)\n", (unsigned long) GC_n_attempts);
-         }
-#      endif
+       if (GC_print_stats) {
+           GC_log_printf("Abandoning stopped marking after ");
+           GC_log_printf("%lu msecs", time_diff);
+           GC_log_printf("(attempt %d)\n", GC_n_attempts);
+       }
        return(1);
     }
     return(0);
@@ -153,14 +141,14 @@ int GC_n_attempts = 0;            /* Number of attempts at finishing      */
 
 /* Return the minimum number of words that must be allocated between   */
 /* collections to amortize the collection cost.                                */
-static word min_words_allocd()
+static word min_bytes_allocd()
 {
 #   ifdef THREADS
        /* We punt, for now. */
-       register signed_word stack_size = 10000;
+       signed_word stack_size = 10000;
 #   else
         int dummy;
-        register signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom;
+        signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom;
 #   endif
     word total_root_size;          /* includes double stack size,      */
                                    /* since the stack is expensive     */
@@ -170,10 +158,8 @@ static word min_words_allocd()
     
     if (stack_size < 0) stack_size = -stack_size;
     total_root_size = 2 * stack_size + GC_root_size;
-    scan_size = BYTES_TO_WORDS(GC_heapsize - GC_large_free_bytes
-                              + (GC_large_free_bytes >> 2)
-                                  /* use a bit more of large empty heap */
-                              + total_root_size);
+    scan_size = 2 * GC_composite_in_use + GC_atomic_in_use
+               + total_root_size;
     if (TRUE_INCREMENTAL) {
         return scan_size / (2 * GC_free_space_divisor);
     } else {
@@ -181,43 +167,39 @@ static word min_words_allocd()
     }
 }
 
-/* Return the number of words allocated, adjusted for explicit storage */
+/* Return the number of bytes allocated, adjusted for explicit storage */
 /* management, etc..  This number is used in deciding when to trigger  */
 /* collections.                                                                */
-word GC_adj_words_allocd()
+word GC_adj_bytes_allocd(void)
 {
-    register signed_word result;
-    register signed_word expl_managed =
-               BYTES_TO_WORDS((long)GC_non_gc_bytes
-                               - (long)GC_non_gc_bytes_at_gc);
+    signed_word result;
+    signed_word expl_managed =
+               (signed_word)GC_non_gc_bytes
+               - (signed_word)GC_non_gc_bytes_at_gc;
     
     /* Don't count what was explicitly freed, or newly allocated for   */
     /* explicit management.  Note that deallocating an explicitly      */
     /* managed object should not alter result, assuming the client     */
     /* is playing by the rules.                                                */
-    result = (signed_word)GC_words_allocd
-            - (signed_word)GC_mem_freed 
-            + (signed_word)GC_finalizer_mem_freed - expl_managed;
-    if (result > (signed_word)GC_words_allocd) {
-        result = GC_words_allocd;
+    result = (signed_word)GC_bytes_allocd
+            - (signed_word)GC_bytes_freed 
+            + (signed_word)GC_finalizer_bytes_freed
+            - expl_managed;
+    if (result > (signed_word)GC_bytes_allocd) {
+        result = GC_bytes_allocd;
        /* probably client bug or unfortunate scheduling */
     }
-    result += GC_words_finalized;
+    result += GC_bytes_finalized;
        /* We count objects enqueued for finalization as though they    */
        /* had been reallocated this round. Finalization is user        */
        /* visible progress.  And if we don't count this, we have       */
        /* stability problems for programs that finalize all objects.   */
-    if ((signed_word)(GC_words_wasted >> 3) < result)
-        result += GC_words_wasted;
-       /* This doesn't reflect useful work.  But if there is lots of   */
-       /* new fragmentation, the same is probably true of the heap,    */
-       /* and the collection will be correspondingly cheaper.          */
-    if (result < (signed_word)(GC_words_allocd >> 3)) {
+    if (result < (signed_word)(GC_bytes_allocd >> 3)) {
        /* Always count at least 1/8 of the allocations.  We don't want */
        /* to collect too infrequently, since that would inhibit        */
        /* coalescing of free storage blocks.                           */
        /* This also makes us partially robust against client bugs.     */
-        return(GC_words_allocd >> 3);
+        return(GC_bytes_allocd >> 3);
     } else {
         return(result);
     }
@@ -233,9 +215,7 @@ void GC_clear_a_few_frames()
 {
 #   define NWORDS 64
     word frames[NWORDS];
-    /* Some compilers will warn that frames was set but never used.    */
-    /* That's the whole idea ...                                       */
-    register int i;
+    int i;
     
     for (i = 0; i < NWORDS; i++) frames[i] = 0;
 }
@@ -245,16 +225,16 @@ void GC_clear_a_few_frames()
 static word GC_collect_at_heapsize = (word)(-1);
 
 /* Have we allocated enough to amortize a collection? */
-GC_bool GC_should_collect()
+GC_bool GC_should_collect(void)
 {
-    return(GC_adj_words_allocd() >= min_words_allocd()
+    return(GC_adj_bytes_allocd() >= min_bytes_allocd()
           || GC_heapsize >= GC_collect_at_heapsize);
 }
 
 
-void GC_notify_full_gc()
+void GC_notify_full_gc(void)
 {
-    if (GC_start_call_back != (void (*) GC_PROTO((void)))0) {
+    if (GC_start_call_back != (void (*) (void))0) {
        (*GC_start_call_back)();
     }
 }
@@ -267,7 +247,7 @@ GC_bool GC_is_full_gc = FALSE;
  * between partial, full, and stop-world collections.
  * Assumes lock held, signals disabled.
  */
-void GC_maybe_gc()
+void GC_maybe_gc(void)
 {
     static int n_partial_gcs = 0;
 
@@ -281,14 +261,12 @@ void GC_maybe_gc()
            GC_wait_for_reclaim();
 #        endif
          if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) {
-#          ifdef CONDPRINT
-             if (GC_print_stats) {
-               GC_printf2(
+           if (GC_print_stats) {
+               GC_log_printf(
                  "***>Full mark for collection %lu after %ld allocd bytes\n",
-                 (unsigned long) GC_gc_no+1,
-                 (long)WORDS_TO_BYTES(GC_words_allocd));
-             }
-#           endif
+                 (unsigned long)GC_gc_no+1,
+                 (long)GC_bytes_allocd);
+           }
            GC_promote_black_lists();
            (void)GC_reclaim_all((GC_stop_func)0, TRUE);
            GC_clear_marks();
@@ -307,7 +285,7 @@ void GC_maybe_gc()
 #      endif
         if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED? 
                            GC_never_stop_func : GC_timeout_stop_func)) {
-#           ifdef SAVE_CALL_CHAIN_IN_GC
+#           ifdef SAVE_CALL_CHAIN
                 GC_save_callers(GC_last_stack);
 #           endif
             GC_finish_collection();
@@ -326,20 +304,15 @@ void GC_maybe_gc()
  * If stop_func is not GC_never_stop_func, then abort if stop_func returns TRUE.
  * Return TRUE if we successfully completed the collection.
  */
-GC_bool GC_try_to_collect_inner(stop_func)
-GC_stop_func stop_func;
+GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
 {
-#   ifdef CONDPRINT
-        CLOCK_TYPE start_time, current_time;
-#   endif
+    CLOCK_TYPE start_time, current_time;
     if (GC_dont_gc) return FALSE;
     if (GC_incremental && GC_collection_in_progress()) {
-#   ifdef CONDPRINT
       if (GC_print_stats) {
-       GC_printf0(
+       GC_log_printf(
            "GC_try_to_collect_inner: finishing collection in progress\n");
       }
-#   endif /* CONDPRINT */
       /* Just finish collection already in progress.   */
        while(GC_collection_in_progress()) {
            if (stop_func()) return(FALSE);
@@ -347,15 +320,12 @@ GC_stop_func stop_func;
        }
     }
     if (stop_func == GC_never_stop_func) GC_notify_full_gc();
-#   ifdef CONDPRINT
-      if (GC_print_stats) {
-        if (GC_print_stats) GET_TIME(start_time);
-       GC_printf2(
+    if (GC_print_stats) {
+        GET_TIME(start_time);
+       GC_log_printf(
           "Initiating full world-stop collection %lu after %ld allocd bytes\n",
-          (unsigned long) GC_gc_no+1,
-          (long)WORDS_TO_BYTES(GC_words_allocd));
-      }
-#   endif
+          (unsigned long)GC_gc_no+1, (long)GC_bytes_allocd);
+    }
     GC_promote_black_lists();
     /* Make sure all blocks have been reclaimed, so sweep routines     */
     /* don't see cleared mark bits.                                    */
@@ -372,7 +342,7 @@ GC_stop_func stop_func;
        }
     GC_invalidate_mark_state();  /* Flush mark stack.  */
     GC_clear_marks();
-#   ifdef SAVE_CALL_CHAIN_IN_GC
+#   ifdef SAVE_CALL_CHAIN
         GC_save_callers(GC_last_stack);
 #   endif
     GC_is_full_gc = TRUE;
@@ -388,13 +358,11 @@ GC_stop_func stop_func;
       return(FALSE);
     }
     GC_finish_collection();
-#   if defined(CONDPRINT)
-      if (GC_print_stats) {
+    if (GC_print_stats) {
         GET_TIME(current_time);
-        GC_printf1("Complete collection took %lu msecs\n",
-                   MS_TIME_DIFF(current_time,start_time));
-      }
-#   endif
+        GC_log_printf("Complete collection took %lu msecs\n",
+                  MS_TIME_DIFF(current_time,start_time));
+    }
     return(TRUE);
 }
 
@@ -417,17 +385,16 @@ GC_stop_func stop_func;
 int GC_deficit = 0;    /* The number of extra calls to GC_mark_some    */
                        /* that we have made.                           */
 
-void GC_collect_a_little_inner(n)
-int n;
+void GC_collect_a_little_inner(int n)
 {
-    register int i;
+    int i;
     
     if (GC_dont_gc) return;
     if (GC_incremental && GC_collection_in_progress()) {
        for (i = GC_deficit; i < GC_RATE*n; i++) {
            if (GC_mark_some((ptr_t)0)) {
                /* Need to finish a collection */
-#              ifdef SAVE_CALL_CHAIN_IN_GC
+#              ifdef SAVE_CALL_CHAIN
                    GC_save_callers(GC_last_stack);
 #              endif
 #              ifdef PARALLEL_MARK
@@ -454,17 +421,15 @@ int n;
     }
 }
 
-int GC_collect_a_little GC_PROTO(())
+int GC_collect_a_little(void)
 {
     int result;
     DCL_LOCK_STATE;
 
-    DISABLE_SIGNALS();
     LOCK();
     GC_collect_a_little_inner(1);
     result = (int)GC_collection_in_progress();
     UNLOCK();
-    ENABLE_SIGNALS();
     if (!result && GC_debugging_started) GC_print_all_smashed();
     return(result);
 }
@@ -475,35 +440,26 @@ int GC_collect_a_little GC_PROTO(())
  * If stop_func() ever returns TRUE, we may fail and return FALSE.
  * Increment GC_gc_no if we succeed.
  */
-GC_bool GC_stopped_mark(stop_func)
-GC_stop_func stop_func;
+GC_bool GC_stopped_mark(GC_stop_func stop_func)
 {
-    register int i;
+    unsigned i;
     int dummy;
-#   if defined(PRINTTIMES) || defined(CONDPRINT)
-       CLOCK_TYPE start_time, current_time;
-#   endif
+    CLOCK_TYPE start_time, current_time;
        
-#   ifdef PRINTTIMES
+    if (GC_print_stats)
        GET_TIME(start_time);
-#   endif
-#   if defined(CONDPRINT) && !defined(PRINTTIMES)
-       if (GC_print_stats) GET_TIME(start_time);
-#   endif
+
 #   if defined(REGISTER_LIBRARIES_EARLY)
         GC_cond_register_dynamic_libraries();
 #   endif
     STOP_WORLD();
     IF_THREADS(GC_world_stopped = TRUE);
-#   ifdef CONDPRINT
-      if (GC_print_stats) {
-       GC_printf1("--> Marking for collection %lu ",
-                  (unsigned long) GC_gc_no + 1);
-       GC_printf2("after %lu allocd bytes + %lu wasted bytes\n",
-                  (unsigned long) WORDS_TO_BYTES(GC_words_allocd),
-                  (unsigned long) WORDS_TO_BYTES(GC_words_wasted));
-      }
-#   endif
+    if (GC_print_stats) {
+       GC_log_printf("--> Marking for collection %lu ",
+                 (unsigned long)GC_gc_no + 1);
+       GC_log_printf("after %lu allocd bytes\n",
+                  (unsigned long) GC_bytes_allocd);
+    }
 #   ifdef MAKE_BACK_GRAPH
       if (GC_print_back_height) {
         GC_build_back_graph();
@@ -517,13 +473,10 @@ GC_stop_func stop_func;
        GC_initiate_gc();
        for(i = 0;;i++) {
            if ((*stop_func)()) {
-#                  ifdef CONDPRINT
-                     if (GC_print_stats) {
-                       GC_printf0("Abandoned stopped marking after ");
-                       GC_printf1("%lu iterations\n",
-                                  (unsigned long)i);
-                     }
-#                  endif
+                   if (GC_print_stats) {
+                       GC_log_printf("Abandoned stopped marking after ");
+                       GC_log_printf("%u iterations\n", i);
+                   }
                    GC_deficit = i; /* Give the mutator a chance. */
                     IF_THREADS(GC_world_stopped = FALSE);
                    START_WORLD();
@@ -533,26 +486,16 @@ GC_stop_func stop_func;
        }
        
     GC_gc_no++;
-#   ifdef PRINTSTATS
-      GC_printf2("Collection %lu reclaimed %ld bytes",
-                 (unsigned long) GC_gc_no - 1,
-                 (long)WORDS_TO_BYTES(GC_mem_found));
-#   else
-#     ifdef CONDPRINT
-        if (GC_print_stats) {
-         GC_printf1("Collection %lu finished", (unsigned long) GC_gc_no - 1);
-       }
-#     endif
-#   endif /* !PRINTSTATS */
-#   ifdef CONDPRINT
-      if (GC_print_stats) {
-        GC_printf1(" ---> heapsize = %lu bytes\n",
-                  (unsigned long) GC_heapsize);
+    if (GC_print_stats) {
+      GC_log_printf("Collection %lu reclaimed %ld bytes",
+                   (unsigned long)GC_gc_no - 1,
+                   (long)GC_bytes_found);
+      GC_log_printf(" ---> heapsize = %lu bytes\n",
+               (unsigned long) GC_heapsize);
         /* Printf arguments may be pushed in funny places.  Clear the  */
         /* space.                                                      */
-        GC_printf0("");
-      }
-#   endif  /* CONDPRINT  */
+      GC_log_printf("");
+    }
 
     /* Check all debugged objects for consistency */
         if (GC_debugging_started) {
@@ -561,90 +504,111 @@ GC_stop_func stop_func;
     
     IF_THREADS(GC_world_stopped = FALSE);
     START_WORLD();
-#   ifdef PRINTTIMES
-       GET_TIME(current_time);
-       GC_printf1("World-stopped marking took %lu msecs\n",
-                  MS_TIME_DIFF(current_time,start_time));
-#   else
-#     ifdef CONDPRINT
-       if (GC_print_stats) {
-         GET_TIME(current_time);
-         GC_printf1("World-stopped marking took %lu msecs\n",
-                    MS_TIME_DIFF(current_time,start_time));
-       }
-#     endif
-#   endif
+    if (GC_print_stats) {
+      GET_TIME(current_time);
+      GC_log_printf("World-stopped marking took %lu msecs\n",
+                   MS_TIME_DIFF(current_time,start_time));
+    }
     return(TRUE);
 }
 
 /* Set all mark bits for the free list whose first entry is q  */
-#ifdef __STDC__
-  void GC_set_fl_marks(ptr_t q)
-#else
-  void GC_set_fl_marks(q)
-  ptr_t q;
-#endif
+void GC_set_fl_marks(ptr_t q)
 {
    ptr_t p;
    struct hblk * h, * last_h = 0;
-   hdr *hhdr;
-   int word_no;
+   hdr *hhdr;  /* gcc "might be uninitialized" warning is bogus. */
+   IF_PER_OBJ(size_t sz;)
+   unsigned bit_no;
 
    for (p = q; p != 0; p = obj_link(p)){
        h = HBLKPTR(p);
        if (h != last_h) {
          last_h = h; 
          hhdr = HDR(h);
+         IF_PER_OBJ(sz = hhdr->hb_sz;)
        }
-       word_no = (((word *)p) - ((word *)h));
-       set_mark_bit_from_hdr(hhdr, word_no);
+       bit_no = MARK_BIT_NO((ptr_t)p - (ptr_t)h, sz);
+       if (!mark_bit_from_hdr(hhdr, bit_no)) {
+         set_mark_bit_from_hdr(hhdr, bit_no);
+          ++hhdr -> hb_n_marks;
+        }
    }
 }
 
-/* Clear all mark bits for the free list whose first entry is q        */
-/* Decrement GC_mem_found by number of words on free list.     */
-#ifdef __STDC__
-  void GC_clear_fl_marks(ptr_t q)
-#else
-  void GC_clear_fl_marks(q)
-  ptr_t q;
+#ifdef GC_ASSERTIONS
+/* Check that all mark bits for the free list whose first entry is q   */
+/* are set.                                                            */
+void GC_check_fl_marks(ptr_t q)
+{
+   ptr_t p;
+
+   for (p = q; p != 0; p = obj_link(p)){
+       if (!GC_is_marked(p)) {
+           GC_err_printf("Unmarked object %p on list %p\n", p, q);
+           ABORT("Unmarked local free list entry.");
+       }
+   }
+}
 #endif
+
+/* Clear all mark bits for the free list whose first entry is q        */
+/* Decrement GC_bytes_found by number of bytes on free list.   */
+void GC_clear_fl_marks(ptr_t q)
 {
    ptr_t p;
    struct hblk * h, * last_h = 0;
    hdr *hhdr;
-   int word_no;
+   size_t sz;
+   unsigned bit_no;
 
    for (p = q; p != 0; p = obj_link(p)){
        h = HBLKPTR(p);
        if (h != last_h) {
          last_h = h; 
          hhdr = HDR(h);
+         sz = hhdr->hb_sz;  /* Normally set only once. */
        }
-       word_no = (((word *)p) - ((word *)h));
-       clear_mark_bit_from_hdr(hhdr, word_no);
-#      ifdef GATHERSTATS
-           GC_mem_found -= hhdr -> hb_sz;
-#      endif
+       bit_no = MARK_BIT_NO((ptr_t)p - (ptr_t)h, sz);
+       if (mark_bit_from_hdr(hhdr, bit_no)) {
+         size_t n_marks = hhdr -> hb_n_marks - 1;
+         clear_mark_bit_from_hdr(hhdr, bit_no);
+#        ifdef PARALLEL_MARK
+           /* Appr. count, don't decrement to zero! */
+           if (0 != n_marks) {
+              hhdr -> hb_n_marks = n_marks;
+           }
+#        else
+            hhdr -> hb_n_marks = n_marks;
+#        endif
+        }
+       GC_bytes_found -= sz;
    }
 }
 
+#if defined(GC_ASSERTIONS) && defined(THREADS) && defined(THREAD_LOCAL_ALLOC)
+extern void GC_check_tls(void);
+#endif
+
 /* Finish up a collection.  Assumes lock is held, signals are disabled,        */
 /* but the world is otherwise running.                                 */
 void GC_finish_collection()
 {
-#   ifdef PRINTTIMES
-       CLOCK_TYPE start_time;
-       CLOCK_TYPE finalize_time;
-       CLOCK_TYPE done_time;
+    CLOCK_TYPE start_time;
+    CLOCK_TYPE finalize_time;
+    CLOCK_TYPE done_time;
        
-       GET_TIME(start_time);
-       finalize_time = start_time;
+#   if defined(GC_ASSERTIONS) && defined(THREADS) \
+       && defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
+       /* Check that we marked some of our own data.           */
+        /* FIXME: Add more checks.                             */
+        GC_check_tls();
 #   endif
 
-#   ifdef GATHERSTATS
-        GC_mem_found = 0;
-#   endif
+    if (GC_print_stats)
+      GET_TIME(start_time);
+
+    GC_bytes_found = 0;
 #   if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
        if (getenv("GC_PRINT_ADDRESS_MAP") != 0) {
          GC_print_address_map();
@@ -655,12 +619,12 @@ void GC_finish_collection()
       /* Mark all objects on the free list.  All objects should be */
       /* marked when we're done.                                  */
        {
-         register word size;           /* current object size          */
-         int kind;
+         word size;            /* current object size          */
+         unsigned kind;
          ptr_t q;
 
          for (kind = 0; kind < GC_n_kinds; kind++) {
-           for (size = 1; size <= MAXOBJSZ; size++) {
+           for (size = 1; size <= MAXOBJGRANULES; size++) {
              q = GC_obj_kinds[kind].ok_freelist[size];
              if (q != 0) GC_set_fl_marks(q);
            }
@@ -675,34 +639,33 @@ void GC_finish_collection()
       GC_clean_changing_list();
 #   endif
 
-#   ifdef PRINTTIMES
+    if (GC_print_stats)
       GET_TIME(finalize_time);
-#   endif
 
     if (GC_print_back_height) {
 #     ifdef MAKE_BACK_GRAPH
        GC_traverse_back_graph();
 #     else
 #      ifndef SMALL_CONFIG
-         GC_err_printf0("Back height not available: "
-                        "Rebuild collector with -DMAKE_BACK_GRAPH\n");
+         GC_err_printf("Back height not available: "
+                       "Rebuild collector with -DMAKE_BACK_GRAPH\n");
 #      endif
 #     endif
     }
 
     /* Clear free list mark bits, in case they got accidentally marked   */
     /* (or GC_find_leak is set and they were intentionally marked).     */
-    /* Also subtract memory remaining from GC_mem_found count.           */
+    /* Also subtract memory remaining from GC_bytes_found count.         */
     /* Note that composite objects on free list are cleared.             */
     /* Thus accidentally marking a free list is not a problem;  only     */
     /* objects on the list itself will be marked, and that's fixed here. */
       {
-       register word size;             /* current object size          */
-       register ptr_t q;       /* pointer to current object    */
-       int kind;
+       word size;              /* current object size          */
+       ptr_t q;        /* pointer to current object    */
+       unsigned kind;
 
        for (kind = 0; kind < GC_n_kinds; kind++) {
-         for (size = 1; size <= MAXOBJSZ; size++) {
+         for (size = 1; size <= MAXOBJGRANULES; size++) {
            q = GC_obj_kinds[kind].ok_freelist[size];
            if (q != 0) GC_clear_fl_marks(q);
          }
@@ -710,70 +673,67 @@ void GC_finish_collection()
       }
 
 
-#   ifdef PRINTSTATS
-       GC_printf1("Bytes recovered before sweep - f.l. count = %ld\n",
-                 (long)WORDS_TO_BYTES(GC_mem_found));
-#   endif
+    if (GC_print_stats == VERBOSE)
+       GC_log_printf("Bytes recovered before sweep - f.l. count = %ld\n",
+                 (long)GC_bytes_found);
+    
     /* Reconstruct free lists to contain everything not marked */
         GC_start_reclaim(FALSE);
+       if (GC_print_stats) {
+         GC_log_printf("Heap contains %lu pointer-containing "
+                       "+ %lu pointer-free reachable bytes\n",
+                       (unsigned long)GC_composite_in_use,
+                       (unsigned long)GC_atomic_in_use);
+       }
         if (GC_is_full_gc)  {
            GC_used_heap_size_after_full = USED_HEAP_SIZE;
            GC_need_full_gc = FALSE;
        } else {
            GC_need_full_gc =
-                BYTES_TO_WORDS(USED_HEAP_SIZE - GC_used_heap_size_after_full)
-                > min_words_allocd();
+                USED_HEAP_SIZE - GC_used_heap_size_after_full
+                > min_bytes_allocd();
        }
 
-#   ifdef PRINTSTATS
-       GC_printf2(
+    if (GC_print_stats == VERBOSE) {
+       GC_log_printf(
                  "Immediately reclaimed %ld bytes in heap of size %lu bytes",
-                 (long)WORDS_TO_BYTES(GC_mem_found),
+                 (long)GC_bytes_found,
                  (unsigned long)GC_heapsize);
 #      ifdef USE_MUNMAP
-         GC_printf1("(%lu unmapped)", GC_unmapped_bytes);
+         GC_log_printf("(%lu unmapped)", (unsigned long)GC_unmapped_bytes);
 #      endif
-       GC_printf2(
-               "\n%lu (atomic) + %lu (composite) collectable bytes in use\n",
-               (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
-               (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
-#   endif
+       GC_log_printf("\n");
+    }
 
+    /* Reset or increment counters for next cycle */
       GC_n_attempts = 0;
       GC_is_full_gc = FALSE;
-    /* Reset or increment counters for next cycle */
-      GC_words_allocd_before_gc += GC_words_allocd;
+      GC_bytes_allocd_before_gc += GC_bytes_allocd;
       GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
-      GC_words_allocd = 0;
-      GC_words_wasted = 0;
-      GC_mem_freed = 0;
-      GC_finalizer_mem_freed = 0;
+      GC_bytes_allocd = 0;
+      GC_bytes_freed = 0;
+      GC_finalizer_bytes_freed = 0;
       
 #   ifdef USE_MUNMAP
       GC_unmap_old();
 #   endif
-#   ifdef PRINTTIMES
+    if (GC_print_stats) {
        GET_TIME(done_time);
-       GC_printf2("Finalize + initiate sweep took %lu + %lu msecs\n",
-                  MS_TIME_DIFF(finalize_time,start_time),
-                  MS_TIME_DIFF(done_time,finalize_time));
-#   endif
+       GC_log_printf("Finalize + initiate sweep took %lu + %lu msecs\n",
+                     MS_TIME_DIFF(finalize_time,start_time),
+                     MS_TIME_DIFF(done_time,finalize_time));
+    }
 }
 
 /* Externally callable routine to invoke full, stop-world collection */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_try_to_collect(GC_stop_func stop_func)
-# else
-    int GC_try_to_collect(stop_func)
-    GC_stop_func stop_func;
-# endif
+int GC_try_to_collect(GC_stop_func stop_func)
 {
     int result;
     DCL_LOCK_STATE;
     
+    if (!GC_is_initialized) GC_init();
     if (GC_debugging_started) GC_print_all_smashed();
     GC_INVOKE_FINALIZERS();
-    DISABLE_SIGNALS();
     LOCK();
     ENTER_GC();
     if (!GC_is_initialized) GC_init_inner();
@@ -782,7 +742,6 @@ void GC_finish_collection()
     result = (int)GC_try_to_collect_inner(stop_func);
     EXIT_GC();
     UNLOCK();
-    ENABLE_SIGNALS();
     if(result) {
         if (GC_debugging_started) GC_print_all_smashed();
         GC_INVOKE_FINALIZERS();
@@ -790,7 +749,7 @@ void GC_finish_collection()
     return(result);
 }
 
-void GC_gcollect GC_PROTO(())
+void GC_gcollect(void)
 {
     (void)GC_try_to_collect(GC_never_stop_func);
     if (GC_have_errors) GC_print_all_errors();
@@ -802,11 +761,8 @@ word GC_n_heap_sects = 0;  /* Number of sections currently in heap. */
  * Use the chunk of memory starting at p of size bytes as part of the heap.
  * Assumes p is HBLKSIZE aligned, and bytes is a multiple of HBLKSIZE.
  */
-void GC_add_to_heap(p, bytes)
-struct hblk *p;
-word bytes;
+void GC_add_to_heap(struct hblk *p, size_t bytes)
 {
-    word words;
     hdr * phdr;
     
     if (GC_n_heap_sects >= MAX_HEAP_SECTS) {
@@ -822,69 +778,60 @@ word bytes;
     GC_heap_sects[GC_n_heap_sects].hs_start = (ptr_t)p;
     GC_heap_sects[GC_n_heap_sects].hs_bytes = bytes;
     GC_n_heap_sects++;
-    words = BYTES_TO_WORDS(bytes);
-    phdr -> hb_sz = words;
-    phdr -> hb_map = (unsigned char *)1;   /* A value != GC_invalid_map        */
+    phdr -> hb_sz = bytes;
     phdr -> hb_flags = 0;
     GC_freehblk(p);
     GC_heapsize += bytes;
     if ((ptr_t)p <= (ptr_t)GC_least_plausible_heap_addr
         || GC_least_plausible_heap_addr == 0) {
-        GC_least_plausible_heap_addr = (GC_PTR)((ptr_t)p - sizeof(word));
+        GC_least_plausible_heap_addr = (void *)((ptr_t)p - sizeof(word));
                /* Making it a little smaller than necessary prevents   */
                /* us from getting a false hit from the variable        */
                /* itself.  There's some unintentional reflection       */
                /* here.                                                */
     }
     if ((ptr_t)p + bytes >= (ptr_t)GC_greatest_plausible_heap_addr) {
-        GC_greatest_plausible_heap_addr = (GC_PTR)((ptr_t)p + bytes);
+        GC_greatest_plausible_heap_addr = (void *)((ptr_t)p + bytes);
     }
 }
 
 # if !defined(NO_DEBUGGING)
-void GC_print_heap_sects()
+void GC_print_heap_sects(void)
 {
-    register unsigned i;
+    unsigned i;
     
-    GC_printf1("Total heap size: %lu\n", (unsigned long) GC_heapsize);
+    GC_printf("Total heap size: %lu\n", (unsigned long) GC_heapsize);
     for (i = 0; i < GC_n_heap_sects; i++) {
-        unsigned long start = (unsigned long) GC_heap_sects[i].hs_start;
-        unsigned long len = (unsigned long) GC_heap_sects[i].hs_bytes;
+        ptr_t start = GC_heap_sects[i].hs_start;
+        size_t len = GC_heap_sects[i].hs_bytes;
         struct hblk *h;
         unsigned nbl = 0;
         
-       GC_printf3("Section %ld from 0x%lx to 0x%lx ", (unsigned long)i,
-                  start, (unsigned long)(start + len));
+       GC_printf("Section %d from %p to %p ", i,
+                  start, start + len);
        for (h = (struct hblk *)start; h < (struct hblk *)(start + len); h++) {
            if (GC_is_black_listed(h, HBLKSIZE)) nbl++;
        }
-       GC_printf2("%lu/%lu blacklisted\n", (unsigned long)nbl,
+       GC_printf("%lu/%lu blacklisted\n", (unsigned long)nbl,
                   (unsigned long)(len/HBLKSIZE));
     }
 }
 # endif
 
-GC_PTR GC_least_plausible_heap_addr = (GC_PTR)ONES;
-GC_PTR GC_greatest_plausible_heap_addr = 0;
+void * GC_least_plausible_heap_addr = (void *)ONES;
+void * GC_greatest_plausible_heap_addr = 0;
 
-ptr_t GC_max(x,y)
-ptr_t x, y;
+static INLINE ptr_t GC_max(ptr_t x, ptr_t y)
 {
     return(x > y? x : y);
 }
 
-ptr_t GC_min(x,y)
-ptr_t x, y;
+static INLINE ptr_t GC_min(ptr_t x, ptr_t y)
 {
     return(x < y? x : y);
 }
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_set_max_heap_size(GC_word n)
-# else
-    void GC_set_max_heap_size(n)
-    GC_word n;
-# endif
+void GC_set_max_heap_size(GC_word n)
 {
     GC_max_heapsize = n;
 }
@@ -903,8 +850,7 @@ GC_word GC_max_retries = 0;
  * Tiny values of n are rounded up.
  * Returns FALSE on failure.
  */
-GC_bool GC_expand_hp_inner(n)
-word n;
+GC_bool GC_expand_hp_inner(word n)
 {
     word bytes;
     struct hblk * space;
@@ -926,37 +872,28 @@ word n;
     }
     space = GET_MEM(bytes);
     if( space == 0 ) {
-#      ifdef CONDPRINT
-         if (GC_print_stats) {
-           GC_printf1("Failed to expand heap by %ld bytes\n",
-                      (unsigned long)bytes);
-         }
-#       endif
+       if (GC_print_stats) {
+           GC_log_printf("Failed to expand heap by %ld bytes\n",
+                         (unsigned long)bytes);
+       }
        return(FALSE);
     }
-#   ifdef CONDPRINT
-      if (GC_print_stats) {
-       GC_printf2("Increasing heap size by %lu after %lu allocated bytes\n",
-                  (unsigned long)bytes,
-                  (unsigned long)WORDS_TO_BYTES(GC_words_allocd));
-#      ifdef UNDEFINED
-         GC_printf1("Root size = %lu\n", GC_root_size);
-         GC_print_block_list(); GC_print_hblkfreelist();
-         GC_printf0("\n");
-#      endif
-      }
-#   endif
-    expansion_slop = WORDS_TO_BYTES(min_words_allocd()) + 4*MAXHINCR*HBLKSIZE;
-    if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
+    if (GC_print_stats) {
+       GC_log_printf("Increasing heap size by %lu after %lu allocated bytes\n",
+                     (unsigned long)bytes,
+                     (unsigned long)GC_bytes_allocd);
+    }
+    expansion_slop = min_bytes_allocd() + 4*MAXHINCR*HBLKSIZE;
+    if ((GC_last_heap_addr == 0 && !((word)space & SIGNB))
         || (GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space)) {
         /* Assume the heap is growing up */
         GC_greatest_plausible_heap_addr =
-            (GC_PTR)GC_max((ptr_t)GC_greatest_plausible_heap_addr,
+            (void *)GC_max((ptr_t)GC_greatest_plausible_heap_addr,
                            (ptr_t)space + bytes + expansion_slop);
     } else {
         /* Heap is growing down */
         GC_least_plausible_heap_addr =
-            (GC_PTR)GC_min((ptr_t)GC_least_plausible_heap_addr,
+            (void *)GC_min((ptr_t)GC_least_plausible_heap_addr,
                            (ptr_t)space - expansion_slop);
     }
 #   if defined(LARGE_CONFIG)
@@ -972,33 +909,26 @@ word n;
     GC_add_to_heap(space, bytes);
     /* Force GC before we are likely to allocate past expansion_slop */
       GC_collect_at_heapsize =
-         GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE;
+         GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE;
 #     if defined(LARGE_CONFIG)
         if (GC_collect_at_heapsize < GC_heapsize /* wrapped */)
-         GC_collect_at_heapsize = (word)(-1);
+         GC_collect_at_heapsize = (word)(-1);
 #     endif
     return(TRUE);
 }
 
 /* Really returns a bool, but it's externally visible, so that's clumsy. */
 /* Arguments is in bytes.                                              */
-# if defined(__STDC__) || defined(__cplusplus)
-  int GC_expand_hp(size_t bytes)
-# else
-  int GC_expand_hp(bytes)
-  size_t bytes;
-# endif
+int GC_expand_hp(size_t bytes)
 {
     int result;
     DCL_LOCK_STATE;
     
-    DISABLE_SIGNALS();
     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);
 }
 
@@ -1006,12 +936,10 @@ unsigned GC_fail_count = 0;
                        /* How many consecutive GC/expansion failures?  */
                        /* Reset by GC_allochblk.                       */
 
-GC_bool GC_collect_or_expand(needed_blocks, ignore_off_page)
-word needed_blocks;
-GC_bool ignore_off_page;
+GC_bool GC_collect_or_expand(word needed_blocks, GC_bool ignore_off_page)
 {
     if (!GC_incremental && !GC_dont_gc &&
-       ((GC_dont_expand && GC_words_allocd > 0) || GC_should_collect())) {
+       ((GC_dont_expand && GC_bytes_allocd > 0) || GC_should_collect())) {
       GC_gcollect_inner();
     } else {
       word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
@@ -1047,41 +975,37 @@ GC_bool ignore_off_page;
            return(FALSE);
        }
       } else {
-#        ifdef CONDPRINT
-            if (GC_fail_count && GC_print_stats) {
-             GC_printf0("Memory available again ...\n");
-           }
-#        endif
+          if (GC_fail_count && GC_print_stats) {
+             GC_printf("Memory available again ...\n");
+         }
       }
     }
     return(TRUE);
 }
 
 /*
- * Make sure the object free list for sz is not empty.
+ * Make sure the object free list for size gran (in granules) is not empty.
  * Return a pointer to the first object on the free list.
  * The object MUST BE REMOVED FROM THE FREE LIST BY THE CALLER.
  * Assumes we hold the allocator lock and signals are disabled.
  *
  */
-ptr_t GC_allocobj(sz, kind)
-word sz;
-int kind;
+ptr_t GC_allocobj(size_t gran, int kind)
 {
-    ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
+    void ** flh = &(GC_obj_kinds[kind].ok_freelist[gran]);
     GC_bool tried_minor = FALSE;
     
-    if (sz == 0) return(0);
+    if (gran == 0) return(0);
 
     while (*flh == 0) {
       ENTER_GC();
       /* Do our share of marking work */
         if(TRUE_INCREMENTAL) GC_collect_a_little_inner(1);
       /* Sweep blocks for objects of this size */
-        GC_continue_reclaim(sz, kind);
+        GC_continue_reclaim(gran, kind);
       EXIT_GC();
       if (*flh == 0) {
-        GC_new_hblk(sz, kind);
+        GC_new_hblk(gran, kind);
       }
       if (*flh == 0) {
         ENTER_GC();
index 6c355f6c9f8c45b4604290d06270b64dc72ec417..fe66cc00706555517622d64f80d931fec21d3e8c 100755 (executable)
@@ -9,3 +9,5 @@ fi
 ${CACAO_AUTOHEADER}
 ${CACAO_AUTOMAKE} --add-missing
 ${CACAO_AUTOCONF}
+
+(cd libatomic_ops-1.2; ./autogen.sh)
index 4c3528f8a1ff1d5f3b8568c751b6c0a8c3aeb70e..9efe42bf63a0a35d54c037afea76a6407f08edb8 100644 (file)
@@ -249,19 +249,19 @@ static void add_edge(ptr_t p,  ptr_t q)
     if (be -> n_edges == 100) {
 #       if 0
          if (GC_print_stats) {
-           GC_err_printf0("The following object has in-degree >= 100:\n");
+           GC_err_printf("The following object has in-degree >= 100:\n");
            GC_print_heap_obj(q);
          }
 #      endif
     }
 }
 
-typedef void (*per_object_func)(ptr_t p, word n_words, word gc_descr);
+typedef void (*per_object_func)(ptr_t p, size_t n_bytes, word gc_descr);
 
 static void per_object_helper(struct hblk *h, word fn)
 {
   hdr * hhdr = HDR(h);
-  word sz = hhdr -> hb_sz;
+  size_t sz = hhdr -> hb_sz;
   word descr = hhdr -> hb_descr;
   per_object_func f = (per_object_func)fn;
   int i = 0;
@@ -277,7 +277,7 @@ void GC_apply_to_each_object(per_object_func f)
   GC_apply_to_all_blocks(per_object_helper, (word)f);
 }
 
-static void reset_back_edge(ptr_t p, word n_words, word gc_descr)
+static void reset_back_edge(ptr_t p, size_t n_bytes, word gc_descr)
 {
   /* Skip any free list links, or dropped blocks */
   if (GC_HAS_DEBUG_INFO(p)) {
@@ -313,20 +313,20 @@ static void reset_back_edge(ptr_t p, word n_words, word gc_descr)
   }
 }
 
-static void add_back_edges(ptr_t p, word n_words, word gc_descr)
+static void add_back_edges(ptr_t p, size_t n_bytes, word gc_descr)
 {
   word *currentp = (word *)(p + sizeof(oh));
 
   /* For now, fix up non-length descriptors conservatively.    */
     if((gc_descr & GC_DS_TAGS) != GC_DS_LENGTH) {
-      gc_descr = WORDS_TO_BYTES(n_words);
+      gc_descr = n_bytes;
     }
   while (currentp < (word *)(p + gc_descr)) {
     word current = *currentp++;
     FIXUP_POINTER(current);
     if (current >= (word)GC_least_plausible_heap_addr && 
        current <= (word)GC_greatest_plausible_heap_addr) {
-       ptr_t target = GC_base((GC_PTR)current);
+       ptr_t target = GC_base((void *)current);
        if (0 != target) {
         add_edge(p, target);
        }
@@ -371,7 +371,7 @@ static word backwards_height(ptr_t p)
     word this_height;
     if (GC_is_marked(q) && !(FLAG_MANY & (word)GET_OH_BG_PTR(p))) {
       if (GC_print_stats)
-         GC_printf2("Found bogus pointer from 0x%lx to 0x%lx\n", q, p);
+         GC_log_printf("Found bogus pointer from 0x%lx to 0x%lx\n", q, p);
        /* Reachable object "points to" unreachable one.                */
        /* Could be caused by our lax treatment of GC descriptors.      */
       this_height = 1;
@@ -394,7 +394,7 @@ ptr_t GC_deepest_obj;
 /* next GC.                                                            */
 /* Set GC_max_height to be the maximum height we encounter, and        */
 /* GC_deepest_obj to be the corresponding object.                      */
-static void update_max_height(ptr_t p, word n_words, word gc_descr)
+static void update_max_height(ptr_t p, size_t n_bytes, word gc_descr)
 {
   if (GC_is_marked(p) && GC_HAS_DEBUG_INFO(p)) {
     int i;
@@ -446,21 +446,23 @@ void GC_traverse_back_graph(void)
 {
   GC_max_height = 0;
   GC_apply_to_each_object(update_max_height);
+  if (0 != GC_deepest_obj)
+    GC_set_mark_bit(GC_deepest_obj);  /* Keep it until we can print it. */
 }
 
 void GC_print_back_graph_stats(void)
 {
-  GC_printf2("Maximum backwards height of reachable objects at GC %lu is %ld\n",
-            (unsigned long) GC_gc_no, GC_max_height);
+  GC_printf("Maximum backwards height of reachable objects at GC %lu is %ld\n",
+           (unsigned long) GC_gc_no, (unsigned long)GC_max_height);
   if (GC_max_height > GC_max_max_height) {
     GC_max_max_height = GC_max_height;
-    GC_printf0("The following unreachable object is last in a longest chain "
-              "of unreachable objects:\n");
+    GC_printf("The following unreachable object is last in a longest chain "
+             "of unreachable objects:\n");
     GC_print_heap_obj(GC_deepest_obj);
   }
   if (GC_print_stats) {
-    GC_printf1("Needed max total of %ld back-edge structs\n",
-              GC_n_back_edge_structs);
+    GC_log_printf("Needed max total of %ld back-edge structs\n",
+                 GC_n_back_edge_structs);
   }
   GC_apply_to_each_object(reset_back_edge);
   GC_deepest_obj = 0;
diff --git a/src/mm/boehm-gc/bdw-gc.pc.in b/src/mm/boehm-gc/bdw-gc.pc.in
new file mode 100644 (file)
index 0000000..ef4c234
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Boehm-Demers-Weiser Conservative Garbage Collector
+Description: A garbage collector for C and C++
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lgc
+Cflags: -I${includedir}
index 24075d30e931d23290c734feefb0c9cb2c40c670..bea0474588ed486680381ec161c1aeb3776cbe69 100644 (file)
@@ -53,40 +53,34 @@ word GC_total_stack_black_listed;
 
 word GC_black_list_spacing = MINHINCR*HBLKSIZE;  /* Initial rough guess */
 
-void GC_clear_bl();
+void GC_clear_bl(word *);
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_default_print_heap_obj_proc(ptr_t p)
-# else
-    void GC_default_print_heap_obj_proc(p)
-    ptr_t p;
-# endif
+void GC_default_print_heap_obj_proc(ptr_t p)
 {
     ptr_t base = GC_base(p);
 
-    GC_err_printf2("start: 0x%lx, appr. length: %ld", base, GC_size(base));
+    GC_err_printf("start: %p, appr. length: %ld", base,
+                 (unsigned long)GC_size(base));
 }
 
-void (*GC_print_heap_obj) GC_PROTO((ptr_t p)) =
-                               GC_default_print_heap_obj_proc;
+void (*GC_print_heap_obj) (ptr_t p) = GC_default_print_heap_obj_proc;
 
-void GC_print_source_ptr(p)
-ptr_t p;
+void GC_print_source_ptr(ptr_t p)
 {
     ptr_t base = GC_base(p);
     if (0 == base) {
        if (0 == p) {
-           GC_err_printf0("in register");
+           GC_err_printf("in register");
        } else {
-           GC_err_printf0("in root set");
+           GC_err_printf("in root set");
        }
     } else {
-       GC_err_printf0("in object at ");
+       GC_err_printf("in object at ");
        (*GC_print_heap_obj)(base);
     }
 }
 
-void GC_bl_init()
+void GC_bl_init(void)
 {
     if (!GC_all_interior_pointers) {
       GC_old_normal_bl = (word *)
@@ -94,7 +88,7 @@ void GC_bl_init()
       GC_incomplete_normal_bl = (word *)GC_scratch_alloc
                                        ((word)(sizeof(page_hash_table)));
       if (GC_old_normal_bl == 0 || GC_incomplete_normal_bl == 0) {
-        GC_err_printf0("Insufficient memory for black list\n");
+        GC_err_printf("Insufficient memory for black list\n");
         EXIT();
       }
       GC_clear_bl(GC_old_normal_bl);
@@ -104,30 +98,28 @@ void GC_bl_init()
     GC_incomplete_stack_bl = (word *)GC_scratch_alloc
                                        ((word)(sizeof(page_hash_table)));
     if (GC_old_stack_bl == 0 || GC_incomplete_stack_bl == 0) {
-        GC_err_printf0("Insufficient memory for black list\n");
+        GC_err_printf("Insufficient memory for black list\n");
         EXIT();
     }
     GC_clear_bl(GC_old_stack_bl);
     GC_clear_bl(GC_incomplete_stack_bl);
 }
                
-void GC_clear_bl(doomed)
-word *doomed;
+void GC_clear_bl(word *doomed)
 {
     BZERO(doomed, sizeof(page_hash_table));
 }
 
-void GC_copy_bl(old, new)
-word *new, *old;
+void GC_copy_bl(word *old, word *new)
 {
     BCOPY(old, new, sizeof(page_hash_table));
 }
 
-static word total_stack_black_listed();
+static word total_stack_black_listed(void);
 
 /* Signal the completion of a collection.  Turn the incomplete black   */
 /* lists into new black lists, etc.                                    */                       
-void GC_promote_black_lists()
+void GC_promote_black_lists(void)
 {
     word * very_old_normal_bl = GC_old_normal_bl;
     word * very_old_stack_bl = GC_old_stack_bl;
@@ -141,10 +133,9 @@ void GC_promote_black_lists()
     GC_incomplete_normal_bl = very_old_normal_bl;
     GC_incomplete_stack_bl = very_old_stack_bl;
     GC_total_stack_black_listed = total_stack_black_listed();
-#   ifdef PRINTSTATS
-       GC_printf1("%ld bytes in heap blacklisted for interior pointers\n",
-                  (unsigned long)GC_total_stack_black_listed);
-#   endif
+    if (GC_print_stats == VERBOSE)
+       GC_log_printf("%ld bytes in heap blacklisted for interior pointers\n",
+                     (unsigned long)GC_total_stack_black_listed);
     if (GC_total_stack_black_listed != 0) {
         GC_black_list_spacing =
                HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
@@ -161,7 +152,7 @@ void GC_promote_black_lists()
     }
 }
 
-void GC_unpromote_black_lists()
+void GC_unpromote_black_lists(void)
 {
     if (!GC_all_interior_pointers) {
       GC_copy_bl(GC_old_normal_bl, GC_incomplete_normal_bl);
@@ -173,23 +164,21 @@ void GC_unpromote_black_lists()
 /* the plausible heap bounds.                                  */
 /* Add it to the normal incomplete black list if appropriate.  */
 #ifdef PRINT_BLACK_LIST
-  void GC_add_to_black_list_normal(p, source)
-  ptr_t source;
+  void GC_add_to_black_list_normal(word p, ptr_t source)
 #else
-  void GC_add_to_black_list_normal(p)
+  void GC_add_to_black_list_normal(word p)
 #endif
-word p;
 {
     if (!(GC_modws_valid_offsets[p & (sizeof(word)-1)])) return;
     {
-        register int index = PHT_HASH(p);
+        word index = PHT_HASH((word)p);
         
         if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_normal_bl, index)) {
 #          ifdef PRINT_BLACK_LIST
                if (!get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
-                 GC_err_printf2(
-                       "Black listing (normal) 0x%lx referenced from 0x%lx ",
-                       (unsigned long) p, (unsigned long) source);
+                 GC_err_printf(
+                       "Black listing (normal) %p referenced from %p ",
+                       (ptr_t) p, source);
                  GC_print_source_ptr(source);
                  GC_err_puts("\n");
                }
@@ -202,21 +191,20 @@ word p;
 
 /* And the same for false pointers from the stack. */
 #ifdef PRINT_BLACK_LIST
-  void GC_add_to_black_list_stack(p, source)
+  void GC_add_to_black_list_stack(word p, ptr_t source)
   ptr_t source;
 #else
-  void GC_add_to_black_list_stack(p)
+  void GC_add_to_black_list_stack(word p)
 #endif
-word p;
 {
-    register int index = PHT_HASH(p);
+    word index = PHT_HASH((word)p);
         
     if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_stack_bl, index)) {
 #      ifdef PRINT_BLACK_LIST
            if (!get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
-                 GC_err_printf2(
-                       "Black listing (stack) 0x%lx referenced from 0x%lx ",
-                       (unsigned long)p, (unsigned long)source);
+                 GC_err_printf(
+                       "Black listing (stack) %p referenced from %p ",
+                       (ptr_t)p, source);
                  GC_print_source_ptr(source);
                  GC_err_puts("\n");
            }
@@ -233,12 +221,10 @@ word p;
  * If (h,len) is not black listed, return 0.
  * Knows about the structure of the black list hash tables.
  */
-struct hblk * GC_is_black_listed(h, len)
-struct hblk * h;
-word len;
+struct hblk * GC_is_black_listed(struct hblk *h, word len)
 {
-    register int index = PHT_HASH((word)h);
-    register word i;
+    word index = PHT_HASH((word)h);
+    word i;
     word nblocks = divHBLKSZ(len);
 
     if (!GC_all_interior_pointers) {
@@ -270,14 +256,13 @@ word len;
 /* Return the number of blacklisted blocks in a given range.   */
 /* Used only for statistical purposes.                         */
 /* Looks only at the GC_incomplete_stack_bl.                   */
-word GC_number_stack_black_listed(start, endp1)
-struct hblk *start, *endp1;
+word GC_number_stack_black_listed(struct hblk *start, struct hblk *endp1)
 {
     register struct hblk * h;
     word result = 0;
     
     for (h = start; h < endp1; h++) {
-        register int index = PHT_HASH((word)h);
+        word index = PHT_HASH((word)h);
         
         if (get_pht_entry_from_index(GC_old_stack_bl, index)) result++;
     }
@@ -286,14 +271,14 @@ struct hblk *start, *endp1;
 
 
 /* Return the total number of (stack) black-listed bytes. */
-static word total_stack_black_listed()
+static word total_stack_black_listed(void)
 {
     register unsigned i;
     word total = 0;
     
     for (i = 0; i < GC_n_heap_sects; i++) {
        struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
-       word len = (word) GC_heap_sects[i].hs_bytes;
+       size_t len = (word) GC_heap_sects[i].hs_bytes;
        struct hblk * endp1 = start + len/HBLKSIZE;
        
        total += GC_number_stack_black_listed(start, endp1);
old mode 100644 (file)
new mode 100755 (executable)
index b1ed5e82f9296cfa62c1bef8b63edb26cba79988..6673f4184831b7c84031a3c380e4bcf482515772 100644 (file)
@@ -53,14 +53,14 @@ struct hblk *h;
 # ifdef STUBBORN_ALLOC
 /* Check whether a stubborn object from the given block appears on     */
 /* the appropriate free list.                                          */
-GC_bool GC_on_free_list(h)
+GC_bool GC_on_free_list(struct hblk *h)
 struct hblk *h;
 {
-    register hdr * hhdr = HDR(h);
-    register int sz = hhdr -> hb_sz;
+    hdr * hhdr = HDR(h);
+    int sz = BYTES_TO_WORDS(hhdr -> hb_sz);
     ptr_t p;
     
-    if (sz > MAXOBJSZ) return(FALSE);
+    if (sz > MAXOBJWORDS) return(FALSE);
     for (p = GC_sobjfreelist[sz]; p != 0; p = obj_link(p)) {
         if (HBLKPTR(p) == h) return(TRUE);
     }
@@ -73,9 +73,7 @@ int GC_n_changed_errors;
 int GC_n_clean;
 int GC_n_dirty;
 
-void GC_update_check_page(h, index)
-struct hblk *h;
-int index;
+void GC_update_check_page(struct hblk *h, int index)
 {
     page_entry *pe = GC_sums + index;
     register hdr * hhdr = HDR(h);
@@ -86,8 +84,7 @@ int index;
     pe -> new_sum = GC_checksum(h);
 #   if !defined(MSWIN32) && !defined(MSWINCE)
         if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) {
-            GC_printf1("GC_page_was_ever_dirty(0x%lx) is wrong\n",
-                      (unsigned long)h);
+            GC_printf("GC_page_was_ever_dirty(%p) is wrong\n", h);
         }
 #   endif
     if (GC_page_was_dirty(h)) {
@@ -107,7 +104,7 @@ int index;
            /* Set breakpoint here */GC_n_dirty_errors++;
        }
 #      ifdef STUBBORN_ALLOC
-         if ( hhdr -> hb_map != GC_invalid_map
+         if (!HBLK_IS_FREE(hhdr)
            && hhdr -> hb_obj_kind == STUBBORN
            && !GC_page_was_changed(h)
            && !GC_on_free_list(h)) {
@@ -121,14 +118,14 @@ int index;
     pe -> block = h + OFFSET;
 }
 
-word GC_bytes_in_used_blocks;
+unsigned long GC_bytes_in_used_blocks;
 
 void GC_add_block(h, dummy)
 struct hblk *h;
 word dummy;
 {
-   register hdr * hhdr = HDR(h);
-   register bytes = WORDS_TO_BYTES(hhdr -> hb_sz);
+   hdr * hhdr = HDR(h);
+   bytes = hhdr -> hb_sz;
    
    bytes += HBLKSIZE-1;
    bytes &= ~(HBLKSIZE-1);
@@ -137,15 +134,15 @@ word dummy;
 
 void GC_check_blocks()
 {
-    word bytes_in_free_blocks = GC_large_free_bytes;
+    unsigned long bytes_in_free_blocks = GC_large_free_bytes;
     
     GC_bytes_in_used_blocks = 0;
     GC_apply_to_all_blocks(GC_add_block, (word)0);
-    GC_printf2("GC_bytes_in_used_blocks = %ld, bytes_in_free_blocks = %ld ",
-               GC_bytes_in_used_blocks, bytes_in_free_blocks);
-    GC_printf1("GC_heapsize = %ld\n", GC_heapsize);
+    GC_printf("GC_bytes_in_used_blocks = %lu, bytes_in_free_blocks = %lu ",
+             GC_bytes_in_used_blocks, bytes_in_free_blocks);
+    GC_printf("GC_heapsize = %lu\n", (unsigned long)GC_heapsize);
     if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) {
-       GC_printf0("LOST SOME BLOCKS!!\n");
+       GC_printf("LOST SOME BLOCKS!!\n");
     }
 }
 
@@ -176,18 +173,18 @@ void GC_check_dirty()
         }
     }
 out:
-    GC_printf2("Checked %lu clean and %lu dirty pages\n",
+    GC_printf("Checked %lu clean and %lu dirty pages\n",
              (unsigned long) GC_n_clean, (unsigned long) GC_n_dirty);
     if (GC_n_dirty_errors > 0) {
-        GC_printf1("Found %lu dirty bit errors\n",
-                  (unsigned long)GC_n_dirty_errors);
+        GC_printf("Found %lu dirty bit errors\n",
+                 (unsigned long)GC_n_dirty_errors);
     }
     if (GC_n_changed_errors > 0) {
-       GC_printf1("Found %lu changed bit errors\n",
-                  (unsigned long)GC_n_changed_errors);
-       GC_printf0("These may be benign (provoked by nonpointer changes)\n");
+       GC_printf("Found %lu changed bit errors\n",
+                 (unsigned long)GC_n_changed_errors);
+       GC_printf("These may be benign (provoked by nonpointer changes)\n");
 #      ifdef THREADS
-           GC_printf0(
+           GC_printf(
            "Also expect 1 per thread currently allocating a stubborn obj.\n");
 #      endif
     }
diff --git a/src/mm/boehm-gc/configure.ac b/src/mm/boehm-gc/configure.ac
new file mode 100644 (file)
index 0000000..4cb639c
--- /dev/null
@@ -0,0 +1,677 @@
+# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
+# 
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+# 
+# Permission is hereby granted to use or copy this program
+# for any purpose,  provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+#
+# Original author: Tom Tromey
+# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
+
+dnl Process this file with autoconf to produce configure.
+
+# Initialization
+# ==============
+
+AC_INIT(gc,7.0,Hans.Boehm@hp.com) 
+    ## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
+AC_CONFIG_SRCDIR(gcj_mlc.c)
+AC_CANONICAL_TARGET 
+AC_PREREQ(2.53)
+AC_REVISION($Revision: 1.25 $)
+GC_SET_VERSION
+AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects nostdinc])
+AM_MAINTAINER_MODE
+
+AM_CONFIG_HEADER([include/config.h])
+
+AC_SUBST(PACKAGE)
+AC_SUBST(GC_VERSION)
+
+AM_PROG_CC_C_O
+AC_PROG_CXX
+
+dnl temporary set the CFLAGS for configure tests (e.g. inline keyword)
+dnl we set it properly later in this file
+CFLAGS="$ARCH_CFLAGS $OPT_CFLAGS"
+AC_C_INLINE
+
+AM_PROG_AS
+## FIXME: really needed? (AC_LIBTOOL already provides this)
+AC_CHECK_TOOL(AR, ar)
+AC_CHECK_TOOL(RANLIB, ranlib, :)  # :)
+
+AC_PROG_LIBTOOL
+AC_PROG_INSTALL
+
+. ${srcdir}/configure.host
+
+GC_CFLAGS=${gc_cflags}
+AC_SUBST(GC_CFLAGS)
+
+AC_ARG_ENABLE(boehm-threads,
+  [AC_HELP_STRING([--enable-boehm-threads=TYPE], [choose threading package])],
+  THREADS=$enableval,
+  [ AC_MSG_CHECKING([for thread model used by GCC])
+    THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
+    if test -z "$THREADS"; then
+      THREADS=no
+    fi
+    AC_MSG_RESULT([$THREADS]) ])
+
+AC_ARG_ENABLE(parallel-mark,
+   [AC_HELP_STRING([--enable-parallel-mark],
+       [parallelize marking and free list construction])],
+   [case "$THREADS" in
+      no | none | single)
+       AC_MSG_ERROR([Parallel mark requires --enable-threads=x spec])
+       ;;
+    esac ]
+)
+
+AC_ARG_ENABLE(cplusplus,
+    [AC_HELP_STRING([--enable-cplusplus], [install C++ support])])
+
+INCLUDES=-I${srcdir}/include
+THREADDLLIBS=
+need_atomic_ops_asm=false
+## Libraries needed to support dynamic loading and/or threads.
+case "$THREADS" in
+ no | none | single)
+    THREADS=none
+    ;;
+ posix | pthreads)
+    THREADS=posix
+    THREADDLLIBS=-lpthread
+    case "$host" in
+     x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
+       AC_DEFINE([GC_LINUX_THREADS], 1, [gc linux threads])
+       AC_DEFINE([_REENTRANT], 1, [reentrant])
+        if test "${enable_parallel_mark}" = yes; then
+         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
+       fi
+       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
+       AC_MSG_WARN("Explict GC_INIT() calls may be required.");
+       ;;
+     *-*-linux*)
+       AC_DEFINE([GC_LINUX_THREADS], 1, [gc linux threads])
+       AC_DEFINE([_REENTRANT], 1, [reentrant])
+       ;;
+     *-*-aix*)
+       AC_DEFINE([GC_AIX_THREADS], 1, [gc aix threads])
+       AC_DEFINE([_REENTRANT], 1, [reentrant])
+       ;;
+     *-*-hpux11*)
+       AC_MSG_WARN("Only HP/UX 11 POSIX threads are supported.")
+       AC_DEFINE([GC_HPUX_THREADS], 1, [gc hpux threads])
+       AC_DEFINE([_POSIX_C_SOURCE], 199506L, [posix c source])
+       if test "${enable_parallel_mark}" = yes; then
+         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
+       fi
+       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
+       AC_MSG_WARN("Explict GC_INIT() calls may be required.");
+       THREADDLLIBS="-lpthread -lrt"
+       # HPUX needs REENTRANT for the _r calls.
+       AC_DEFINE(_REENTRANT, 1, [Required define if using POSIX threads])
+       ;;
+     *-*-hpux10*)
+       AC_MSG_WARN("Only HP-UX 11 POSIX threads are supported.")
+       ;;
+     *-*-freebsd*)
+       AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.")
+       AC_DEFINE([GC_FREEBSD_THREADS], 1, [gc freebsd threads])
+       INCLUDES="$INCLUDES -pthread"
+       ;;
+     *-*-kfreebsd*-gnu)
+       AC_DEFINE([GC_FREEBSD_THREADS], 1, [gc freebsd threads])
+       INCLUDES="$INCLUDES -pthread"
+       THREADDLLIBS=-pthread
+       AC_DEFINE([_REENTRANT], 1, [reentrant])
+        if test "${enable_parallel_mark}" = yes; then
+         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
+       fi
+       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
+       AC_DEFINE([USE_COMPILER_TLS], 1, [use compiler tls])
+       ;;
+     *-*-gnu*)
+       AC_DEFINE([GC_GNU_THREADS], 1, [GC GNU threads])
+       AC_DEFINE(_REENTRANT)
+       AC_DEFINE(THREAD_LOCAL_ALLOC)
+       ;;
+     *-*-netbsd*)
+       AC_MSG_WARN("Only on NetBSD 2.0 or later.")
+       AC_DEFINE([GC_NETBSD_THREADS], 1, [GC NetBSD threads])
+       AC_DEFINE([_REENTRANT], 1, [reentrant])
+       AC_DEFINE([_PTHREADS], 1, [pthreads])
+       THREADDLLIBS="-lpthread -lrt"
+       ;;
+     *-*-solaris*)
+       AC_DEFINE([GC_SOLARIS_THREADS], 1, [gc solaris threads])
+       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
+       THREADDLLIBS="-lpthread -lrt"
+       if test "$GCC" != yes; then
+          CFLAGS="$CFLAGS -O"
+          need_atomic_ops_asm=true
+        fi
+       ;;
+     *-*-irix*)
+       AC_DEFINE([GC_IRIX_THREADS], 1, [gc irix threads])
+       ;;
+     *-*-cygwin*)
+       AC_DEFINE([GC_WIN32_THREADS], 1, [gc win32 threads])
+       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
+       win32_threads=true
+       ;;
+     *-*-darwin*)
+       AC_DEFINE([GC_DARWIN_THREADS], 1, [gc darwin threads])
+       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
+       AC_MSG_WARN("Explict GC_INIT() calls may be required.");
+       if test "${enable_parallel_mark}" = yes; then
+         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
+       fi
+       darwin_threads=true
+       ;;
+     *-*-osf*)
+       AC_DEFINE([GC_OSF1_THREADS], 1, [gc osf1 threads])
+        if test "${enable_parallel_mark}" = yes; then
+         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
+         AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
+         AC_MSG_WARN("Explict GC_INIT() calls may be required.");
+         # May want to enable it in other cases, too.
+         # Measurements havent yet been done.
+       fi
+       INCLUDES="$INCLUDES -pthread"
+       THREADDLLIBS="-lpthread -lrt"
+       ;;
+      *)
+       AC_MSG_ERROR("Pthreads not supported by the GC on this platform.")
+       ;;
+    esac
+    ;;
+ win32)
+    AC_DEFINE([GC_WIN32_THREADS], 1, [gc win32 threads])
+    dnl Wine getenv may not return NULL for missing entry
+    AC_DEFINE([NO_GETENV], 1, [no getenv])
+    ;;
+ dgux386)
+    THREADS=dgux386
+    AC_MSG_RESULT($THREADDLLIBS)
+    # Use pthread GCC  switch
+    THREADDLLIBS=-pthread
+    if test "${enable_parallel_mark}" = yes; then
+        AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
+    fi
+    AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
+    AC_MSG_WARN("Explict GC_INIT() calls may be required.");
+    AC_DEFINE([GC_DGUX386_THREADS], 1, [gc dgux386 threads])
+    AC_DEFINE([DGUX_THREADS], 1, [dgux threads])
+    # Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
+    INCLUDES="-pthread $INCLUDES"
+    ;;
+ aix)
+    THREADS=posix
+    THREADDLLIBS=-lpthread
+    AC_DEFINE([GC_AIX_THREADS], 1, [gc aix threads])
+    AC_DEFINE([_REENTRANT], 1, [reentrant])
+    ;;
+ decosf1 | irix | mach | os2 | solaris | dce | vxworks)
+    AC_MSG_ERROR(thread package $THREADS not yet supported)
+    ;;
+ *)
+    AC_MSG_ERROR($THREADS is an unknown thread package)
+    ;;
+esac
+AC_SUBST(THREADDLLIBS)
+AM_CONDITIONAL(THREADS, test x$THREADS != xnone)
+AM_CONDITIONAL(PTHREADS, test x$THREADS = xposix)
+AM_CONDITIONAL(DARWIN_THREADS, test x$darwin_threads = xtrue)
+AM_CONDITIONAL(WIN32_THREADS, test x$win32_threads = xtrue)
+
+case "$host" in 
+   powerpc-*-darwin*)
+      powerpc_darwin=true
+      dnl CACAO: disable this for now
+      AC_DEFINE([DARWIN_DONT_PARSE_STACK], 1, [don't use FindTopOfStack])
+      ;;
+esac
+
+# Darwin needs a few extra special tests to deal with variation in the
+# system headers.
+case "$host" in
+  powerpc*-*-darwin*)
+    AC_CHECK_MEMBER(ppc_thread_state_t.r0,
+      AC_DEFINE(HAS_PPC_THREAD_STATE_R0,1,
+       [ppc_thread_state_t has field r0]),,
+      [#include <mach/thread_status.h>])
+    AC_CHECK_MEMBER(ppc_thread_state_t.__r0,
+      AC_DEFINE(HAS_PPC_THREAD_STATE___R0,1,dnl
+       [ppc_thread_state_t has field __r0]),,
+      [#include <mach/thread_status.h>])
+    AC_CHECK_MEMBER(ppc_thread_state64_t.r0,
+      AC_DEFINE(HAS_PPC_THREAD_STATE64_R0,1,dnl
+       [ppc_thread_state64_t has field r0]),,
+      [#include <mach/thread_status.h>])
+    AC_CHECK_MEMBER(ppc_thread_state64_t.__r0,
+      AC_DEFINE(HAS_PPC_THREAD_STATE64___R0,1,dnl
+       [ppc_thread_state64_t has field __r0]),,
+      [#include <mach/thread_status.h>])
+    ;;
+  i?86*-*-darwin*)
+    AC_CHECK_MEMBER(x86_thread_state32_t.eax,
+      AC_DEFINE(HAS_X86_THREAD_STATE32_EAX,1,dnl
+       [x86_thread_state32_t has field eax]),,
+      [#include <sys/cdefs.h>
+      #include <mach/thread_status.h>])
+    AC_CHECK_MEMBER(x86_thread_state32_t.__eax,
+      AC_DEFINE(HAS_X86_THREAD_STATE32___EAX,1,dnl
+       [x86_thread_state32_t has field __eax]),,
+      [#include <sys/cdefs.h>
+      #include <mach/thread_status.h>])
+    ;;
+  x86_64-*-darwin*)
+    AC_CHECK_MEMBER(x86_thread_state64_t.rax,
+      AC_DEFINE(HAS_X86_THREAD_STATE64_RAX,1,dnl
+       [x86_thread_state64_t has field rax]),,
+      [#include <sys/cdefs.h>
+      #include <mach/thread_status.h>])
+    AC_CHECK_MEMBER(x86_thread_state64_t.__rax,
+      AC_DEFINE(HAS_X86_THREAD_STATE64___RAX,1,dnl
+       [x86_thread_state64_t has field __rax]),,
+      [#include <sys/cdefs.h>
+      #include <mach/thread_status.h>])
+     ;;
+  *) ;;
+esac
+
+AC_MSG_CHECKING(for xlc)
+AC_TRY_COMPILE([],[
+ #ifndef __xlC__
+ # error
+ #endif
+], [compiler_xlc=yes], [compiler_xlc=no])
+AC_MSG_RESULT($compiler_xlc)
+AM_CONDITIONAL(COMPILER_XLC,test $compiler_xlc = yes)
+if test $compiler_xlc = yes -a "$powerpc_darwin" = true; then
+  # the darwin stack-frame-walking code is completely broken on xlc
+  AC_DEFINE(DARWIN_DONT_PARSE_STACK)
+fi
+
+# We never want libdl on darwin. It is a fake libdl that just ends up making
+# dyld calls anyway
+case "$host" in
+  *-*-darwin*) ;;
+  *)
+    AC_CHECK_LIB(dl, dlopen, THREADDLLIBS="$THREADDLLIBS -ldl")
+    ;;
+esac
+
+# extra LD Flags which are required for targets
+case "${host}" in
+  *-*-darwin*)
+    extra_ldflags_libgc=-Wl,-single_module
+    ;;
+esac
+AC_SUBST(extra_ldflags_libgc)
+
+AC_SUBST(EXTRA_TEST_LIBS)
+
+target_all=libgc.la
+AC_SUBST(target_all)
+
+dnl If the target is an eCos system, use the appropriate eCos
+dnl I/O routines.
+dnl FIXME: this should not be a local option but a global target
+dnl system; at present there is no eCos target.
+TARGET_ECOS="no"
+AC_ARG_WITH(ecos,
+[  --with-ecos             enable runtime eCos target support],
+TARGET_ECOS="$with_ecos"
+)
+
+addobjs=
+addlibs=
+CXXINCLUDES=
+case "$TARGET_ECOS" in
+   no)
+      ;;
+   *)
+      AC_DEFINE([ECOS], 1, [ecos])
+      CXXINCLUDES="-I${TARGET_ECOS}/include"
+      addobjs="$addobjs ecos.lo"
+      ;;
+esac
+
+AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes)
+
+AC_SUBST(CXX)
+
+AC_SUBST(INCLUDES)
+AC_SUBST(CXXINCLUDES)
+
+# Configuration of shared libraries
+#
+AC_MSG_CHECKING(whether to build shared libraries)
+AC_ENABLE_SHARED
+
+case "$host" in
+ alpha-*-openbsd*)
+     enable_shared=no
+     AC_MSG_RESULT(no)
+     ;;
+ *)
+     AC_MSG_RESULT(yes)
+     ;;
+esac
+
+# Configuration of machine-dependent code
+#
+AC_MSG_CHECKING(which machine-dependent code should be used) 
+machdep=
+case "$host" in
+ alpha-*-openbsd*)
+    machdep="mach_dep.lo"
+    if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
+       AC_MSG_WARN(OpenBSD/Alpha without dlopen(). Shared library support is disabled)
+    fi
+    ;;
+ alpha*-*-linux*)
+    machdep="mach_dep.lo"
+    ;;
+ i?86-*-solaris2.[[89]] | i?86-*-solaris2.1?)
+    AC_DEFINE([SOLARIS25_PROC_VDB_BUG_FIXED], 1, [solaris 2.5 proc vdb bug fixed])
+    ;;
+ mipstx39-*-elf*)
+    machdep="mach_dep.lo"
+    AC_DEFINE([STACKBASE], __stackbase, [stackbase])
+    AC_DEFINE([DATASTART_IS_ETEXT], 1, [datastart is etext])
+    ;;
+ mips-dec-ultrix*)
+    machdep="mach-dep.lo"
+    ;;
+ mips-nec-sysv*|mips-unknown-sysv*)
+    ;;
+ mips*-*-linux*) 
+    ;; 
+ mips-*-*)
+    machdep="mach_dep.lo"
+    AC_DEFINE([NO_EXECUTE_PERMISSION], 1, [no execute permission])
+    dnl This is now redundant, but it is also important for incremental GC
+    dnl performance under Irix.
+    ;;
+ sparc-*-netbsd*)
+    machdep="mach_dep.lo sparc_netbsd_mach_dep.lo"
+    ;;
+ sparc-sun-solaris2.3)
+    machdep="mach_dep.lo sparc_mach_dep.lo"
+    AC_DEFINE([SUNOS53_SHARED_LIB], 1, [sun os 5.3 shared lib])
+    ;;
+ sparc*-sun-solaris2.*)
+    machdep="mach_dep.lo sparc_mach_dep.lo"
+    ;;
+ ia64-*-*)
+    machdep="mach_dep.lo ia64_save_regs_in_stack.lo"
+    ;;
+esac
+if test x"$machdep" = x; then
+AC_MSG_RESULT($machdep)
+   machdep="mach_dep.lo"
+fi
+addobjs="$addobjs $machdep"
+AC_SUBST(addobjs)
+AC_SUBST(addlibs)
+
+AC_PROG_LIBTOOL
+
+#
+# Check for AViiON Machines running DGUX
+#
+ac_is_dgux=no
+AC_CHECK_HEADER(sys/dg_sys_info.h,
+[ac_is_dgux=yes;])
+
+    ## :GOTCHA: we do not check anything but sys/dg_sys_info.h
+if test $ac_is_dgux = yes; then
+    if test "$enable_full_debug" = "yes"; then
+      CFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
+      CXXFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
+    else
+      CFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
+      CXXFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
+    fi
+    AC_SUBST(CFLAGS)
+    AC_SUBST(CXXFLAGS)
+fi
+
+dnl We use these options to decide which functions to include.
+AC_ARG_WITH(target-subdir,
+[  --with-target-subdir=SUBDIR
+                          configuring with a cross compiler])
+AC_ARG_WITH(cross-host,
+[  --with-cross-host=HOST  configuring with a cross compiler])
+
+# automake wants to see AC_EXEEXT.  But we don't need it.  And having
+# it is actually a problem, because the compiler we're passed can't
+# necessarily do a full link.  So we fool automake here.
+if false; then
+  # autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
+  # to nothing, so nothing would remain between `then' and `fi' if it
+  # were not for the `:' below.
+  :
+  AC_EXEEXT
+fi
+
+dnl As of 4.13a2, the collector will not properly work on Solaris when
+dnl built with gcc and -O.  So we remove -O in the appropriate case.
+dnl Not needed anymore on Solaris.
+AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
+case "$host" in
+ *aix*)
+    if test "$GCC" = yes; then
+       AC_MSG_RESULT(yes)
+       new_CFLAGS=
+       for i in $CFLAGS; do
+         case "$i" in
+          -O*)
+             ;;
+          *)
+             new_CFLAGS="$new_CFLAGS $i"
+             ;;
+         esac
+       done
+       CFLAGS="$new_CFLAGS"
+    else
+       AC_MSG_RESULT(no)
+    fi
+    ;;
+ *) AC_MSG_RESULT(no) ;;
+esac
+
+dnl We need to override the top-level CFLAGS.  This is how we do it.
+dnl MY_CFLAGS="$CFLAGS"
+dnl AC_SUBST(MY_CFLAGS)
+
+dnl pass CFLAGS to Makefiles via AM_CFLAGS
+CFLAGS=$OPT_CFLAGS
+AM_CFLAGS=$ARCH_CFLAGS
+AC_SUBST(AM_CFLAGS)
+
+dnl Include defines that have become de facto standard.
+dnl ALL_INTERIOR_POINTERS can be overridden in startup code.
+AC_DEFINE([NO_EXECUTE_PERMISSION], 1, [no exceute permission])
+AC_DEFINE([ALL_INTERIOR_POINTERS], 1, [all interior pointers])
+
+
+dnl Interface Selection
+dnl -------------------
+dnl
+dnl By default, make the library as general as possible.
+dnl enable_gcj_support=no
+AC_ARG_ENABLE(gcj-support,
+    [AC_HELP_STRING([--disable-gcj-support],
+       [Disable support for gcj.])])
+AM_CONDITIONAL(ENABLE_GCJ_SUPPORT,
+    [test x"$enable_gcj_support" != xno])
+if test x"$enable_gcj_support" != xno; then
+    AC_DEFINE(GC_GCJ_SUPPORT, 1, [Define to include support for gcj])
+fi
+
+AC_ARG_ENABLE(java-finalization,
+    [AC_HELP_STRING([--disable-java-finalization],
+       [Disable support for java finalization.])])
+if test x"$enable_java_finalization" != xno; then
+    AC_DEFINE([JAVA_FINALIZATION], 1, [java finalization])
+fi
+
+AC_ARG_ENABLE(atomic-uncollectable,
+    [AC_HELP_STRING([--disable-atomic-uncollectible],
+       [Disable support for atomic uncollectible allocation.])])
+if test x"$enable_atomic_uncollectible" != x"no"; then
+    AC_DEFINE(ATOMIC_UNCOLLECTABLE, 1,
+       [Define to enable atomic uncollectible allocation.])
+fi
+
+AC_ARG_ENABLE(redirect-malloc,
+    [AC_HELP_STRING([--enable-redirect-malloc],
+       [Redirect malloc and friends to GC routines])])
+
+if test "${enable_redirect_malloc}" = yes; then
+    if test "${enable_full_debug}" = yes; then
+       AC_DEFINE([REDIRECT_MALLOC], GC_debug_malloc_replacement, [redirect malloc])
+       AC_DEFINE([REDIRECT_REALLOC], GC_debug_realloc_replacement, [redirect realloc])
+       AC_DEFINE([REDIRECT_FREE], GC_debug_free, [redirect free])
+    else
+       AC_DEFINE([REDIRECT_MALLOC], GC_malloc, [redirect malloc])
+    fi
+fi
+
+AC_ARG_ENABLE(large-config,
+    [AC_HELP_STRING([--enable-large-config],
+       [Optimize for large (> 100 MB) heap or root set])])
+
+if test "${enable_large_config}" = yes; then
+    AC_DEFINE(LARGE_CONFIG, 1, [Define to optimize for large heaps or root sets])
+fi
+
+dnl This is something of a hack.  When cross-compiling we turn off
+dnl some functionality.  We also enable the "small" configuration.
+dnl These is only correct when targetting an embedded system.  FIXME.
+if test -n "${with_cross_host}"; then
+   AC_DEFINE([NO_CLOCK], 1, [no clock])
+   AC_DEFINE([SMALL_CONFIG], 1, [small config])
+   AC_DEFINE([NO_DEBUGGING], 1, [no debugging])
+fi
+
+
+dnl Debugging
+dnl ---------
+
+UNWINDLIBS=
+AC_ARG_ENABLE(gc-debug,
+[AC_HELP_STRING([--enable-gc-debug],
+    [include full support for pointer backtracing etc.])],
+[ if test "$enable_gc_debug" = "yes"; then
+    AC_MSG_WARN("Should define GC_DEBUG and use debug alloc. in clients.")
+    AC_DEFINE([KEEP_BACK_PTRS], 1, [keep back ptrs])
+    AC_DEFINE([DBG_HDRS_ALL], 1, [dbg hdrs all])
+    case $host in
+      ia64-*-linux* )
+       AC_DEFINE([MAKE_BACK_GRAPH], 1, [make back graph])
+       AC_DEFINE([SAVE_CALL_COUNT], 8, [save call count])
+        AC_CHECK_LIB(unwind, backtrace, [
+         AC_DEFINE([GC_HAVE_BUILTIN_BACKTRACE], 1, [have builtin backtrace])
+         UNWINDLIBS=-lunwind
+         AC_MSG_WARN("Client code may need to link against libunwind.")
+       ])
+      ;;
+      x86-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
+       AC_DEFINE([MAKE_BACK_GRAPH], 1, [make back graph])
+       AC_MSG_WARN("Client must not use -fomit-frame-pointer.")
+       AC_DEFINE([SAVE_CALL_COUNT], 8, [save call count])
+      ;;
+      i[3456]86-*-dgux*)
+       AC_DEFINE([MAKE_BACK_GRAPH], 1, [make back graph])
+      ;;
+    esac ]
+  fi)
+
+AC_SUBST(UNWINDLIBS)
+
+AC_ARG_ENABLE(gc-assertions,
+    [AC_HELP_STRING([--enable-gc-assertions],
+       [collector-internal assertion checking])])
+if test "${enable_gc_assertions}" = yes; then
+    AC_DEFINE([GC_ASSERTIONS], 1, [gc assertions])
+fi
+
+AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
+
+
+dnl Atomic Ops
+dnl ----------
+
+atomic_ops_libs=-latomic_ops
+AC_CHECK_HEADER(atomic_ops.h,
+  [ AC_MSG_NOTICE([Using pre-installed libatomic_ops]) ],
+  [ ao_dir=
+    for candidate in ${srcdir}/libatomic_ops*; do
+       case $candidate in
+           *.tar.gz)
+               ;;
+           *install)
+               dnl generated by alternate Makefile.
+               ;;
+           *)
+               if test -e "$candidate"; then
+                   ao_dir="$candidate"
+               fi
+               ;;
+       esac
+    done
+    if test -z "$ao_dir"; then
+       AC_MSG_ERROR([Missig libatomic_ops.])
+    fi
+    ao_version="${ao_dir#*libatomic_ops-}"
+    AC_MSG_NOTICE([Using internal version of libatomic_ops])
+
+    dnl Automake does not accept shell variables in AC_CONFIG_SUBDIRS
+    test -e ${srcdir}/libatomic_ops \
+       || ln -s ${ao_dir} ${srcdir}/libatomic_ops
+    AC_CONFIG_SUBDIRS(libatomic_ops)
+
+    dnl Also copy the source files to be linked in.
+    test -e ${srcdir}/atomic_ops.c \
+       || ln -s ${srcdir}/libatomic_ops/src/atomic_ops.c \
+                ${srcdir}/atomic_ops.c
+
+    test -e ${srcdir}/atomic_ops_sysdeps.S \
+       || ln -s ${srcdir}/libatomic_ops/src/atomic_ops_sysdeps.S \
+                ${srcdir}/atomic_ops_sysdeps.S
+
+    dnl This gets the source include files, which is often close enough.
+    dnl It also makes atomic_ops_sysdeps.S assemble.
+    GC_CFLAGS="${GC_CFLAGS} -I \$(top_srcdir)/libatomic_ops/src"
+    maybe_libatomic_ops="libatomic_ops"
+  ])
+
+AM_CONDITIONAL(USE_INTERNAL_LIBATOMIC_OPS,
+               test -n "$maybe_libatomic_ops" -a "$THREADS" != "none")
+AM_CONDITIONAL(NEED_ATOMIC_OPS_ASM, test -n "$maybe_libatomic_ops" -a x$need_atomic_ops_asm = xtrue)
+AC_SUBST(atomic_ops_libs)
+
+dnl Produce the Files
+dnl -----------------
+
+AC_CONFIG_FILES([Makefile bdw-gc.pc])
+
+AC_CONFIG_COMMANDS([default],,
+  [ srcdir=${srcdir}
+    host=${host}
+    CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+    CC="${CC}"
+    DEFS="$DEFS" ])
+
+AC_OUTPUT
diff --git a/src/mm/boehm-gc/configure.in b/src/mm/boehm-gc/configure.in
deleted file mode 100644 (file)
index a429b09..0000000
+++ /dev/null
@@ -1,510 +0,0 @@
-# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
-# 
-# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-# OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
-# 
-# Permission is hereby granted to use or copy this program
-# for any purpose,  provided the above notices are retained on all copies.
-# Permission to modify the code and to distribute modified code is granted,
-# provided the above notices are retained, and a notice that the code was
-# modified is included with the above copyright notice.
-#
-# Original author: Tom Tromey
-# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
-
-dnl Process this file with autoconf to produce configure.
-
-# Initialization
-# ==============
-
-AC_INIT(gc,6.8,Hans.Boehm@hp.com) 
-    ## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
-AC_CONFIG_SRCDIR(gcj_mlc.c)
-AC_CANONICAL_TARGET 
-AC_PREREQ(2.53)
-AC_REVISION($Revision: 5268 $)
-GC_SET_VERSION
-AM_INIT_AUTOMAKE
-
-AM_CONFIG_HEADER([include/config.h])
-
-AC_SUBST(PACKAGE)
-AC_SUBST(GC_VERSION)
-
-AC_PROG_CC
-AC_PROG_CXX
-
-dnl temporary set the CFLAGS for configure tests (e.g. inline keyword)
-dnl we set it properly later in this file
-CFLAGS="$ARCH_CFLAGS $OPT_CFLAGS"
-AC_C_INLINE
-
-AM_PROG_AS
-AC_CHECK_TOOL(AR, ar)
-AC_CHECK_TOOL(RANLIB, ranlib, :)  # :)
-
-AC_PROG_LIBTOOL
-AC_PROG_INSTALL
-
-AM_MAINTAINER_MODE
-
-. [$]{srcdir}/configure.host
-
-GC_CFLAGS=${gc_cflags}
-AC_SUBST(GC_CFLAGS)
-
-AC_ARG_ENABLE(boehm-threads, [  --enable-boehm-threads=TYPE   choose threading package],
-  THREADS=$enableval,
-  [ AC_MSG_CHECKING([for thread model used by GCC])
-    THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
-    if test -z "$THREADS"; then
-      THREADS=no
-    fi
-    AC_MSG_RESULT([$THREADS])])
-
-AC_ARG_ENABLE(parallel-mark,
-[  --enable-parallel-mark      parallelize marking and free list construction],
-   [case "$THREADS" in
-      no | none | single)
-       AC_MSG_ERROR([Parallel mark requires --enable-threads=x spec])
-       ;;
-    esac]
-)
-
-AC_ARG_ENABLE(cplusplus,
-[  --enable-cplusplus          install C++ support],
-)
-
-INCLUDES=-I${srcdir}/include
-THREADDLLIBS=
-## Libraries needed to support dynamic loading and/or threads.
-case "$THREADS" in
- no | none | single)
-    THREADS=none
-    ;;
- posix | pthreads)
-    THREADS=posix
-    THREADDLLIBS=-lpthread
-    case "$host" in
-     x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
-       AC_DEFINE([GC_LINUX_THREADS], 1, [gc linux threads])
-       AC_DEFINE([_REENTRANT], 1, [reentrant])
-        if test "${enable_parallel_mark}" = yes; then
-         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
-       fi
-       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
-       ;;
-     *-*-linux*)
-       AC_DEFINE([GC_LINUX_THREADS], 1, [gc linux threads])
-       AC_DEFINE([_REENTRANT], 1, [reentrant])
-       ;;
-     *-*-aix*)
-       AC_DEFINE([GC_AIX_THREADS], 1, [gc aix threads])
-       AC_DEFINE([_REENTRANT], 1, [reentrant])
-       ;;
-     *-*-hpux11*)
-       AC_MSG_WARN("Only HP/UX 11 POSIX threads are supported.")
-       AC_DEFINE([GC_HPUX_THREADS], 1, [gc hpux threads])
-       AC_DEFINE([_POSIX_C_SOURCE], 199506L, [posix c source])
-       if test "${enable_parallel_mark}" = yes; then
-         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
-       fi
-       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
-       THREADDLLIBS="-lpthread -lrt"
-       # HPUX needs REENTRANT for the _r calls.
-       AC_DEFINE(_REENTRANT, 1, [Required define if using POSIX threads])
-       ;;
-     *-*-hpux10*)
-       AC_MSG_WARN("Only HP-UX 11 POSIX threads are supported.")
-       ;;
-     *-*-freebsd*)
-       AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.")
-       AC_DEFINE([GC_FREEBSD_THREADS], 1, [gc freebsd threads])
-       INCLUDES="$INCLUDES -pthread"
-       THREADDLLIBS=-pthread
-       ;;
-     *-*-kfreebsd*-gnu)
-       AC_DEFINE([GC_FREEBSD_THREADS], 1, [gc freebsd threads])
-       INCLUDES="$INCLUDES -pthread"
-       THREADDLLIBS=-pthread
-       AC_DEFINE([_REENTRANT], 1, [reentrant])
-        if test "${enable_parallel_mark}" = yes; then
-         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
-       fi
-       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
-       AC_DEFINE([USE_COMPILER_TLS], 1, [use compiler tls])
-       ;;
-     *-*-netbsd*)
-       AC_MSG_WARN("Only on NetBSD 2.0 or later.")
-       AC_DEFINE([GC_NETBSD_THREADS], 1, [GC NetBSD threads])
-       AC_DEFINE([_REENTRANT], 1, [reentrant])
-       AC_DEFINE([_PTHREADS], 1, [pthreads])
-       THREADDLLIBS="-lpthread -lrt"
-       ;;
-     *-*-solaris*)
-       AC_DEFINE([GC_SOLARIS_THREADS], 1, [gc solaris threads])
-       AC_DEFINE([GC_SOLARIS_PTHREADS], 1, [gc solaris pthreads])
-       ;;
-     *-*-irix*)
-       AC_DEFINE([GC_IRIX_THREADS], 1, [gc irix threads])
-       ;;
-     *-*-cygwin*)
-       AC_DEFINE([GC_WIN32_THREADS], 1, [gc win32 threads])
-       ;;
-     *-*-darwin*)
-       AC_DEFINE([GC_DARWIN_THREADS], 1, [gc darwin threads])
-       AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
-       if test "${enable_parallel_mark}" = yes; then
-         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
-       fi
-       ;;
-     *-*-osf*)
-       AC_DEFINE([GC_OSF1_THREADS], 1, [gc osf1 threads])
-        if test "${enable_parallel_mark}" = yes; then
-         AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
-         AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
-         # May want to enable it in other cases, too.
-         # Measurements havent yet been done.
-       fi
-       INCLUDES="$INCLUDES -pthread"
-       THREADDLLIBS="-lpthread -lrt"
-       ;;
-      *)
-       AC_MSG_ERROR("Pthreads not supported by the GC on this platform.")
-       ;;
-    esac
-    ;;
- win32)
-    AC_DEFINE([GC_WIN32_THREADS], 1, [gc win32 threads])
-    dnl Wine getenv may not return NULL for missing entry
-    AC_DEFINE([NO_GETENV], 1, [no getenv])
-    ;;
- dgux386)
-    THREADS=dgux386
-    AC_MSG_RESULT($THREADDLLIBS)
-    # Use pthread GCC  switch
-    THREADDLLIBS=-pthread
-    if test "${enable_parallel_mark}" = yes; then
-        AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
-    fi
-    AC_DEFINE([THREAD_LOCAL_ALLOC], 1, [thread local alloc])
-    AC_DEFINE([GC_DGUX386_THREADS], 1, [gc dgux386 threads])
-    AC_DEFINE([DGUX_THREADS], 1, [dgux threads])
-    # Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
-    INCLUDES="-pthread $INCLUDES"
-    ;;
- aix)
-    THREADS=posix
-    THREADDLLIBS=-lpthread
-    AC_DEFINE([GC_AIX_THREADS], 1, [gc aix threads])
-    AC_DEFINE([_REENTRANT], 1, [reentrant])
-    ;;
- decosf1 | irix | mach | os2 | solaris | dce | vxworks)
-    AC_MSG_ERROR(thread package $THREADS not yet supported)
-    ;;
- *)
-    AC_MSG_ERROR($THREADS is an unknown thread package)
-    ;;
-esac
-AC_SUBST(THREADDLLIBS)
-
-case "$host" in 
-   powerpc-*-darwin*)
-      powerpc_darwin=true
-      dnl CACAO: disable this for now
-      AC_DEFINE([DARWIN_DONT_PARSE_STACK], 1, [don't use FindTopOfStack])
-      ;;
-esac
-AM_CONDITIONAL(POWERPC_DARWIN,test x$powerpc_darwin = xtrue)
-
-AC_MSG_CHECKING(for xlc)
-AC_TRY_COMPILE([],[
- #ifndef __xlC__
- # error
- #endif
-], [compiler_xlc=yes], [compiler_xlc=no])
-AC_MSG_RESULT($compiler_xlc)
-AM_CONDITIONAL(COMPILER_XLC,test $compiler_xlc = yes)
-if test $compiler_xlc = yes -a "$powerpc_darwin" = true; then
-  # the darwin stack-frame-walking code is completely broken on xlc
-  AC_DEFINE(DARWIN_DONT_PARSE_STACK)
-fi
-
-# We never want libdl on darwin. It is a fake libdl that just ends up making
-# dyld calls anyway
-case "$host" in
-  *-*-darwin*) ;;
-  *) 
-    AC_CHECK_LIB(dl, dlopen, THREADDLLIBS="$THREADDLLIBS -ldl")
-    ;;
-esac
-
-AC_SUBST(EXTRA_TEST_LIBS)
-
-target_all=libgc.la
-AC_SUBST(target_all)
-
-dnl If the target is an eCos system, use the appropriate eCos
-dnl I/O routines.
-dnl FIXME: this should not be a local option but a global target
-dnl system; at present there is no eCos target.
-TARGET_ECOS="no"
-AC_ARG_WITH(ecos,
-[  --with-ecos             enable runtime eCos target support],
-TARGET_ECOS="$with_ecos"
-)
-
-addobjs=
-addlibs=
-addincludes=
-addtests=
-CXXINCLUDES=
-case "$TARGET_ECOS" in
-   no)
-      ;;
-   *)
-      AC_DEFINE([ECOS], 1, [ecos])
-      CXXINCLUDES="-I${TARGET_ECOS}/include"
-      addobjs="$addobjs ecos.lo"
-      ;;
-esac
-
-if test "${enable_cplusplus}" = yes; then
-      addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
-      addtests="$addtests test_cpp"
-fi
-
-AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes)
-
-AC_SUBST(CXX)
-
-AC_SUBST(INCLUDES)
-AC_SUBST(CXXINCLUDES)
-
-# Configuration of shared libraries
-#
-AC_MSG_CHECKING(whether to build shared libraries)
-AC_ENABLE_SHARED
-
-case "$host" in
- alpha-*-openbsd*)
-     enable_shared=no
-     AC_MSG_RESULT(no)
-     ;;
- *)
-     AC_MSG_RESULT(yes)
-     ;;
-esac
-
-# Configuration of machine-dependent code
-#
-AC_MSG_CHECKING(which machine-dependent code should be used) 
-machdep=
-case "$host" in
- alpha-*-openbsd*)
-    machdep="alpha_mach_dep.lo"
-    if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
-       AC_MSG_WARN(OpenBSD/Alpha without dlopen(). Shared library support is disabled)
-    fi
-    ;;
- alpha*-*-linux*)
-    machdep="alpha_mach_dep.lo"
-    ;;
- i?86-*-solaris2.[[89]] | i?86-*-solaris2.1?)
-    AC_DEFINE([SOLARIS25_PROC_VDB_BUG_FIXED], 1, [solaris 2.5 proc vdb bug fixed])
-    ;;
- mipstx39-*-elf*)
-    machdep="mips_ultrix_mach_dep.lo"
-    AC_DEFINE([STACKBASE], __stackbase, [stackbase])
-    AC_DEFINE([DATASTART_IS_ETEXT], 1, [datastart is etext])
-    ;;
- mips-dec-ultrix*)
-    machdep="mips_ultrix_mach-dep.lo"
-    ;;
- mips-nec-sysv*|mips-unknown-sysv*)
-    ;;
- mips*-*-linux*) 
-    ;; 
- mips-*-*)
-    machdep="mips_sgi_mach_dep.lo"
-    AC_DEFINE([NO_EXECUTE_PERMISSION], 1, [no execute permission])
-    ;;
- sparc-*-netbsd*)
-    machdep="sparc_netbsd_mach_dep.lo"
-    ;;
- sparc-sun-solaris2.3)
-    machdep="sparc_mach_dep.lo"
-    AC_DEFINE([SUNOS53_SHARED_LIB], 1, [sun os 5.3 shared lib])
-    ;;
- sparc*-sun-solaris2.*)
-    machdep="sparc_mach_dep.lo"
-    ;;
- ia64-*-*)
-    machdep="mach_dep.lo ia64_save_regs_in_stack.lo"
-    ;;
-esac
-if test x"$machdep" = x; then
-AC_MSG_RESULT($machdep)
-   machdep="mach_dep.lo"
-fi
-addobjs="$addobjs $machdep"
-AC_SUBST(addobjs)
-AC_SUBST(addincludes)
-AC_SUBST(addlibs)
-AC_SUBST(addtests)
-
-AC_PROG_LIBTOOL
-
-#
-# Check for AViiON Machines running DGUX
-#
-ac_is_dgux=no
-AC_CHECK_HEADER(sys/dg_sys_info.h,
-[ac_is_dgux=yes;])
-
-    ## :GOTCHA: we do not check anything but sys/dg_sys_info.h
-if test $ac_is_dgux = yes; then
-    if test "$enable_full_debug" = "yes"; then
-      CFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
-      CXXFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
-    else
-      CFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
-      CXXFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
-    fi
-    AC_SUBST(CFLAGS)
-    AC_SUBST(CXXFLAGS)
-fi
-
-dnl We use these options to decide which functions to include.
-AC_ARG_WITH(target-subdir,
-[  --with-target-subdir=SUBDIR
-                          configuring with a cross compiler])
-AC_ARG_WITH(cross-host,
-[  --with-cross-host=HOST  configuring with a cross compiler])
-
-# automake wants to see AC_EXEEXT.  But we don't need it.  And having
-# it is actually a problem, because the compiler we're passed can't
-# necessarily do a full link.  So we fool automake here.
-if false; then
-  # autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
-  # to nothing, so nothing would remain between `then' and `fi' if it
-  # were not for the `:' below.
-  :
-  AC_EXEEXT
-fi
-
-dnl As of 4.13a2, the collector will not properly work on Solaris when
-dnl built with gcc and -O.  So we remove -O in the appropriate case.
-dnl Not needed anymore on Solaris.
-AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
-case "$host" in
- *aix*)
-    if test "$GCC" = yes; then
-       AC_MSG_RESULT(yes)
-       new_CFLAGS=
-       for i in $CFLAGS; do
-         case "$i" in
-          -O*)
-             ;;
-          *)
-             new_CFLAGS="$new_CFLAGS $i"
-             ;;
-         esac
-       done
-       CFLAGS="$new_CFLAGS"
-    else
-       AC_MSG_RESULT(no)
-    fi
-    ;;
- *) AC_MSG_RESULT(no) ;;
-esac
-
-dnl We need to override the top-level CFLAGS.  This is how we do it.
-dnl MY_CFLAGS="$CFLAGS"
-dnl AC_SUBST(MY_CFLAGS)
-
-dnl pass CFLAGS to Makefiles via AM_CFLAGS
-CFLAGS=$OPT_CFLAGS
-AM_CFLAGS=$ARCH_CFLAGS
-AC_SUBST(AM_CFLAGS)
-
-dnl Include defines that have become de facto standard.
-dnl ALL_INTERIOR_POINTERS can be overridden in startup code.
-AC_DEFINE([SILENT], 1, [silent])
-AC_DEFINE([NO_SIGNALS], 1, [no signals])
-AC_DEFINE([NO_EXECUTE_PERMISSION], 1, [no exceute permission])
-AC_DEFINE([ALL_INTERIOR_POINTERS], 1, [all interior pointers])
-
-dnl By default, make the library as general as possible.
-AC_DEFINE([JAVA_FINALIZATION], 1, [java finalization])
-AC_DEFINE([GC_GCJ_SUPPORT], 1, [gc gcj support])
-AC_DEFINE([ATOMIC_UNCOLLECTABLE], 1, [atomic uncollectable])
-
-dnl This is something of a hack.  When cross-compiling we turn off
-dnl some functionality.  We also enable the "small" configuration.
-dnl These is only correct when targetting an embedded system.  FIXME.
-if test -n "${with_cross_host}"; then
-   AC_DEFINE([NO_SIGSET], 1, [no sigset])
-   AC_DEFINE([NO_CLOCK], 1, [no clock])
-   AC_DEFINE([SMALL_CONFIG], 1, [small config])
-   AC_DEFINE([NO_DEBUGGING], 1, [no debugging])
-fi
-
-UNWINDLIBS=
-AC_ARG_ENABLE(full-debug,
-[  --enable-full-debug include full support for pointer backtracing etc.],
-[ if test "$enable_full_debug" = "yes"; then
-    AC_MSG_WARN("Should define GC_DEBUG and use debug alloc. in clients.")
-    AC_DEFINE([KEEP_BACK_PTRS], 1, [keep back ptrs])
-    AC_DEFINE([DBG_HDRS_ALL], 1, [dbg hdrs all])
-    case $host in
-      ia64-*-linux* )
-       AC_DEFINE([MAKE_BACK_GRAPH], 1, [make back graph])
-       AC_DEFINE([SAVE_CALL_COUNT], 8, [save call count])
-        AC_CHECK_LIB(unwind, backtrace, [
-         AC_DEFINE([GC_HAVE_BUILTIN_BACKTRACE], 1, [have builtin backtrace])
-         UNWINDLIBS=-lunwind
-         AC_MSG_WARN("Client code may need to link against libunwind.")
-       ])
-      ;;
-      x86-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
-       AC_DEFINE([MAKE_BACK_GRAPH], 1, [make back graph])
-       AC_MSG_WARN("Client must not use -fomit-frame-pointer.")
-       AC_DEFINE([SAVE_CALL_COUNT], 8, [save call count])
-      ;;
-      i[3456]86-*-dgux*)
-       AC_DEFINE([MAKE_BACK_GRAPH], 1, [make back graph])
-      ;;
-    esac ]
-  fi)
-
-AC_SUBST(UNWINDLIBS)
-
-AC_ARG_ENABLE(redirect-malloc,
-[  --enable-redirect-malloc  redirect malloc and friends to GC routines])
-
-if test "${enable_redirect_malloc}" = yes; then
-    if test "${enable_full_debug}" = yes; then
-       AC_DEFINE([REDIRECT_MALLOC], GC_debug_malloc_replacement, [redirect malloc])
-       AC_DEFINE([REDIRECT_REALLOC], GC_debug_realloc_replacement, [redirect realloc])
-       AC_DEFINE([REDIRECT_FREE], GC_debug_free, [redirect free])
-    else
-       AC_DEFINE([REDIRECT_MALLOC], GC_malloc, [redirect malloc])
-    fi
-fi
-
-AC_ARG_ENABLE(gc-assertions,
-[  --enable-gc-assertions  collector-internal assertion checking])
-if test "${enable_gc_assertions}" = yes; then
-    AC_DEFINE([GC_ASSERTIONS], 1, [gc assertions])
-fi
-
-AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
-
-AC_OUTPUT([Makefile doc/Makefile include/Makefile],,
-srcdir=${srcdir}
-host=${host}
-CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
-CC="${CC}"
-DEFS="$DEFS"
-)
diff --git a/src/mm/boehm-gc/configure_atomic_ops.sh b/src/mm/boehm-gc/configure_atomic_ops.sh
new file mode 100755 (executable)
index 0000000..6a0e31a
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+P=`pwd`/libatomic_ops-install
+cd libatomic_ops-*[0-9]
+./configure --prefix=$P
diff --git a/src/mm/boehm-gc/cord/cord.am b/src/mm/boehm-gc/cord/cord.am
new file mode 100644 (file)
index 0000000..fc5e8cc
--- /dev/null
@@ -0,0 +1,17 @@
+
+lib_LTLIBRARIES += libcord.la
+
+libcord_la_LIBADD = $(top_builddir)/libgc.la
+libcord_la_LDFLAGS = -version-info 1:3:0 -no-undefined
+
+libcord_la_SOURCES = \
+       cord/cordbscs.c                         \
+       cord/cordprnt.c                         \
+       cord/cordtest.c                         \
+       cord/cordxtra.c                         
+
+
+EXTRA_DIST += \
+       cord/cordbscs.c cord/cordtest.c cord/de.c \
+       cord/cordprnt.c cord/cordxtra.c cord/de_cmds.h \
+       cord/de_win.h cord/de_win.c cord/de_win.RC cord/de_win.ICO
old mode 100644 (file)
new mode 100755 (executable)
index 0bbd676a3355d226eaf9e3d56895c7b9f6c95340..1871736e393b18e9b2886e722b2dca9e60f44a64 100644 (file)
@@ -51,6 +51,11 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
    WNDCLASS    wndclass;
    HANDLE      hAccel;
 
+#  ifdef THREAD_LOCAL_ALLOC
+     GC_INIT();  /* Required if GC is built with THREAD_LOCAL_ALLOC    */
+                /* Always safe, but this is used as a GC test.         */
+#  endif
+
    if (!hPrevInstance)
    {
       wndclass.style          = CS_HREDRAW | CS_VREDRAW;
@@ -174,10 +179,35 @@ int screen_was_painted = 0;/* Screen has been painted at least once.      */
 
 void update_cursor(void);
 
+INT_PTR CALLBACK AboutBoxCallback( HWND hDlg, UINT message,
+                           WPARAM wParam, LPARAM lParam )
+{
+   switch( message )
+   {
+      case WM_INITDIALOG:
+           SetFocus( GetDlgItem( hDlg, IDOK ) );
+           break;
+
+      case WM_COMMAND:
+           switch( wParam )
+           {
+              case IDOK:
+                   EndDialog( hDlg, TRUE );
+                   break;
+           }
+           break;
+
+      case WM_CLOSE:
+           EndDialog( hDlg, TRUE );
+           return TRUE;
+
+   }
+   return FALSE;
+}
+
 LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
                           WPARAM wParam, LPARAM lParam)
 {
-   static FARPROC lpfnAboutBox;
    static HANDLE  hInstance;
    HDC dc;
    PAINTSTRUCT ps;
@@ -192,7 +222,6 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
    {
       case WM_CREATE:
            hInstance = ( (LPCREATESTRUCT) lParam)->hInstance;
-           lpfnAboutBox = MakeProcInstance( (FARPROC) AboutBox, hInstance );
            dc = GetDC(hwnd);
            SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
            GetTextMetrics(dc, &tm);
@@ -209,7 +238,7 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
           if (wParam == QUIT) {
               SendMessage( hwnd, WM_CLOSE, 0, 0L );
           } else {
-              do_command(wParam);
+              do_command((int)wParam);
           }
           return(0);
       
@@ -249,7 +278,7 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
 
                case IDM_HELPABOUT:
                   if( DialogBox( hInstance, "ABOUTBOX",
-                                 hwnd, lpfnAboutBox ) )
+                                 hwnd, AboutBoxCallback ) )
                      InvalidateRect( hwnd, NULL, TRUE );
                   return( 0 );
               case IDM_HELPCONTENTS:
@@ -294,13 +323,14 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
                   SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
                   
                   TextOut(dc, this_line.left, this_line.top,
-                          plain, len);
-                  TextOut(dc, this_line.left + len * char_width, this_line.top,
-                          blanks, COLS - len);
+                          plain, (int)len);
+                  TextOut(dc, this_line.left + (int)len * char_width,
+                          this_line.top,
+                          blanks, (int)(COLS - len));
                   SetBkMode(dc, TRANSPARENT);
                   SetTextColor(dc, RED);
                   TextOut(dc, this_line.left, this_line.top,
-                          control, strlen(control));
+                          control, (int)strlen(control));
               }
           }
           EndPaint(hwnd, &ps);
@@ -338,29 +368,3 @@ void invalidate_line(int i)
     InvalidateRect(hwnd, &line, FALSE);
 }
 
-LRESULT CALLBACK AboutBox( HWND hDlg, UINT message,
-                           WPARAM wParam, LPARAM lParam )
-{
-   switch( message )
-   {
-      case WM_INITDIALOG:
-           SetFocus( GetDlgItem( hDlg, IDOK ) );
-           break;
-
-      case WM_COMMAND:
-           switch( wParam )
-           {
-              case IDOK:
-                   EndDialog( hDlg, TRUE );
-                   break;
-           }
-           break;
-
-      case WM_CLOSE:
-           EndDialog( hDlg, TRUE );
-           return TRUE;
-
-   }
-   return FALSE;
-}
-
index 3d757b4542ab3124f2862c58fdc372bb2a184c2f..ba792acd5b6a95ae1d9b5d0730a622803418edb4 100644 (file)
@@ -12,7 +12,7 @@
    be allocated, is called the red zone. This area as shown in Figure 3-2 may
    be used for any purpose as long as a new stack frame does not need to be
    added to the stack."
-   
+
    Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
    it must set up a stack frame just like routines that call other routines."
 */
@@ -32,9 +32,10 @@ typedef struct StackFrame {
   unsigned long        savedRTOC;
 } StackFrame;
 
-unsigned long FindTopOfStack(unsigned int stack_start) {
+unsigned long FindTopOfStack(unsigned long stack_start)
+{
   StackFrame   *frame;
-  
+
   if (stack_start == 0) {
 # ifdef POWERPC
 #   if CPP_WORDSZ == 32
@@ -48,234 +49,296 @@ unsigned long FindTopOfStack(unsigned int stack_start) {
   }
 
 # ifdef DEBUG_THREADS
-    /* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
+    /* GC_printf("FindTopOfStack start at sp = %p\n", frame); */
 # endif
   do {
-    if (frame->savedSP == 0) break;
-               /* if there are no more stack frames, stop */
+    if (frame->savedSP == 0)
+      break;
+    /* if there are no more stack frames, stop */
 
     frame = (StackFrame*)frame->savedSP;
 
     /* we do these next two checks after going to the next frame
        because the LR for the first stack frame in the loop
        is not set up on purpose, so we shouldn't check it. */
-    if ((frame->savedLR & ~3) == 0) break; /* if the next LR is bogus, stop */
-    if ((~(frame->savedLR) & ~3) == 0) break; /* ditto */
-  } while (1); 
+    if ((frame->savedLR & ~3) == 0)
+      break; /* if the next LR is bogus, stop */
+    if ((~(frame->savedLR) & ~3) == 0)
+      break; /* ditto */
+  } while (1);
 
 # ifdef DEBUG_THREADS
-    /* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
+    /* GC_printf("FindTopOfStack finish at sp = %p\n", frame); */
 # endif
 
   return (unsigned long)frame;
-}      
+}
 
 #ifdef DARWIN_DONT_PARSE_STACK
-void GC_push_all_stacks() {
+void GC_push_all_stacks()
+{
   int i;
   kern_return_t r;
   GC_thread p;
   pthread_t me;
   ptr_t lo, hi;
-#if defined(POWERPC)
-  ppc_thread_state_t state;
-#elif defined(I386)
-  i386_thread_state_t state;
-#else
-# error FIXME for non-x86 || ppc architectures
-#endif
-  mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
-  
+  GC_THREAD_STATE_T state;
+  /* MACHINE_THREAD_STATE_COUNT doesn't seem to be defined everywhere. */
+  /* Hence we use our own version.                                     */
+  mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT;
+
   me = pthread_self();
-  if (!GC_thr_initialized) GC_thr_init();
-  
-  for(i=0;i<THREAD_TABLE_SZ;i++) {
-    for(p=GC_threads[i];p!=0;p=p->next) {
-      if(p -> flags & FINISHED) continue;
-      if(pthread_equal(p->id,me)) {
+  if (!GC_thr_initialized)
+    GC_thr_init();
+
+  for(i = 0; i < THREAD_TABLE_SZ; i++) {
+    for(p = GC_threads[i]; p != 0; p = p->next) {
+      if(p->flags & FINISHED) continue;
+      if(pthread_equal(p->id, me)) {
        lo = GC_approx_sp();
       } else {
        /* Get the thread state (registers, etc) */
-       r = thread_get_state(
-                            p->stop_info.mach_thread,
-                            MACHINE_THREAD_STATE,
-                            (natural_t*)&state,
-                            &thread_state_count);
-       if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
-       
-#if defined(I386)
-       lo = state.esp;
-
-       GC_push_one(state.eax); 
-       GC_push_one(state.ebx); 
-       GC_push_one(state.ecx); 
-       GC_push_one(state.edx); 
-       GC_push_one(state.edi); 
-       GC_push_one(state.esi); 
-       GC_push_one(state.ebp); 
-#elif defined(POWERPC)
-       lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
-        
-       GC_push_one(state.r0); 
-       GC_push_one(state.r2); 
-       GC_push_one(state.r3); 
-       GC_push_one(state.r4); 
-       GC_push_one(state.r5); 
-       GC_push_one(state.r6); 
-       GC_push_one(state.r7); 
-       GC_push_one(state.r8); 
-       GC_push_one(state.r9); 
-       GC_push_one(state.r10); 
-       GC_push_one(state.r11); 
-       GC_push_one(state.r12); 
-       GC_push_one(state.r13); 
-       GC_push_one(state.r14); 
-       GC_push_one(state.r15); 
-       GC_push_one(state.r16); 
-       GC_push_one(state.r17); 
-       GC_push_one(state.r18); 
-       GC_push_one(state.r19); 
-       GC_push_one(state.r20); 
-       GC_push_one(state.r21); 
-       GC_push_one(state.r22); 
-       GC_push_one(state.r23); 
-       GC_push_one(state.r24); 
-       GC_push_one(state.r25); 
-       GC_push_one(state.r26); 
-       GC_push_one(state.r27); 
-       GC_push_one(state.r28); 
-       GC_push_one(state.r29); 
-       GC_push_one(state.r30); 
-       GC_push_one(state.r31);
-#else
-# error FIXME for non-x86 || ppc architectures
-#endif
+       r = thread_get_state(p->stop_info.mach_thread, GC_MACH_THREAD_STATE,
+                            (natural_t*)&state, &thread_state_count);
+
+#       ifdef DEBUG_THREADS
+         GC_printf("thread_get_state return value = %d\n", r);
+#      endif
+
+       if(r != KERN_SUCCESS)
+         ABORT("thread_get_state failed");
+
+#       if defined(I386)
+         lo = (void*)state . THREAD_FLD (esp);
+         GC_push_one(state . THREAD_FLD (eax));
+         GC_push_one(state . THREAD_FLD (ebx));
+         GC_push_one(state . THREAD_FLD (ecx));
+         GC_push_one(state . THREAD_FLD (edx));
+         GC_push_one(state . THREAD_FLD (edi));
+         GC_push_one(state . THREAD_FLD (esi));
+         GC_push_one(state . THREAD_FLD (ebp));
+
+#       elif defined(X86_64)
+         lo = (void*)state . THREAD_FLD (rsp);
+         GC_push_one(state . THREAD_FLD (rax));
+         GC_push_one(state . THREAD_FLD (rbx));
+         GC_push_one(state . THREAD_FLD (rcx));
+         GC_push_one(state . THREAD_FLD (rdx));
+         GC_push_one(state . THREAD_FLD (rdi));
+         GC_push_one(state . THREAD_FLD (rsi));
+         GC_push_one(state . THREAD_FLD (rbp));
+         GC_push_one(state . THREAD_FLD (rsp));
+         GC_push_one(state . THREAD_FLD (r8));
+         GC_push_one(state . THREAD_FLD (r9));
+         GC_push_one(state . THREAD_FLD (r10));
+         GC_push_one(state . THREAD_FLD (r11));
+         GC_push_one(state . THREAD_FLD (r12));
+         GC_push_one(state . THREAD_FLD (r13));
+         GC_push_one(state . THREAD_FLD (r14));
+         GC_push_one(state . THREAD_FLD (r15));
+         GC_push_one(state . THREAD_FLD (rip));
+         GC_push_one(state . THREAD_FLD (rflags));
+         GC_push_one(state . THREAD_FLD (cs));
+         GC_push_one(state . THREAD_FLD (fs));
+         GC_push_one(state . THREAD_FLD (gs));
+
+#       elif defined(POWERPC)
+         lo = (void*)(state . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
+
+         GC_push_one(state . THREAD_FLD (r0));
+         GC_push_one(state . THREAD_FLD (r2));
+         GC_push_one(state . THREAD_FLD (r3));
+         GC_push_one(state . THREAD_FLD (r4));
+         GC_push_one(state . THREAD_FLD (r5));
+         GC_push_one(state . THREAD_FLD (r6));
+         GC_push_one(state . THREAD_FLD (r7));
+         GC_push_one(state . THREAD_FLD (r8));
+         GC_push_one(state . THREAD_FLD (r9));
+         GC_push_one(state . THREAD_FLD (r10));
+         GC_push_one(state . THREAD_FLD (r11));
+         GC_push_one(state . THREAD_FLD (r12));
+         GC_push_one(state . THREAD_FLD (r13));
+         GC_push_one(state . THREAD_FLD (r14));
+         GC_push_one(state . THREAD_FLD (r15));
+         GC_push_one(state . THREAD_FLD (r16));
+         GC_push_one(state . THREAD_FLD (r17));
+         GC_push_one(state . THREAD_FLD (r18));
+         GC_push_one(state . THREAD_FLD (r19));
+         GC_push_one(state . THREAD_FLD (r20));
+         GC_push_one(state . THREAD_FLD (r21));
+         GC_push_one(state . THREAD_FLD (r22));
+         GC_push_one(state . THREAD_FLD (r23));
+         GC_push_one(state . THREAD_FLD (r24));
+         GC_push_one(state . THREAD_FLD (r25));
+         GC_push_one(state . THREAD_FLD (r26));
+         GC_push_one(state . THREAD_FLD (r27));
+         GC_push_one(state . THREAD_FLD (r28));
+         GC_push_one(state . THREAD_FLD (r29));
+         GC_push_one(state . THREAD_FLD (r30));
+         GC_push_one(state . THREAD_FLD (r31));
+#      else
+#        error FIXME for non-x86 || ppc architectures
+#      endif
       } /* p != me */
       if(p->flags & MAIN_THREAD)
        hi = GC_stackbottom;
       else
        hi = p->stack_end;
-#if DEBUG_THREADS
-      GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
-                (unsigned long) p -> id,
-                (unsigned long) lo,
-                (unsigned long) hi
-                );
-#endif
-      GC_push_all_stack(lo,hi);
+#     if DEBUG_THREADS
+        GC_printf("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
+                 (unsigned long) p -> id, (unsigned long) lo,
+                 (unsigned long) hi);
+#     endif
+      GC_push_all_stack(lo, hi);
     } /* for(p=GC_threads[i]...) */
   } /* for(i=0;i<THREAD_TABLE_SZ...) */
 }
 
 #else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
 
-void GC_push_all_stacks() {
-    int i;
-       task_t my_task;
-    kern_return_t r;
-    mach_port_t me;
-    ptr_t lo, hi;
-    thread_act_array_t act_list = 0;
-    mach_msg_type_number_t listcount = 0;
-
-    me = mach_thread_self();
-    if (!GC_thr_initialized) GC_thr_init();
-    
-       my_task = current_task();
-    r = task_threads(my_task, &act_list, &listcount);
-    if(r != KERN_SUCCESS) ABORT("task_threads failed");
-    for(i = 0; i < listcount; i++) {
-      thread_act_t thread = act_list[i];
-      if (thread == me) {
-       lo = GC_approx_sp();
-       hi = (ptr_t)FindTopOfStack(0);
-      } else {
+void GC_push_all_stacks()
+{
+  unsigned int i;
+  task_t my_task;
+  kern_return_t r;
+  mach_port_t me;
+  ptr_t lo, hi;
+  thread_act_array_t act_list = 0;
+  mach_msg_type_number_t listcount = 0;
+
+  me = mach_thread_self();
+  if (!GC_thr_initialized)
+    GC_thr_init();
+
+  my_task = current_task();
+  r = task_threads(my_task, &act_list, &listcount);
+  if(r != KERN_SUCCESS)
+    ABORT("task_threads failed");
+  for(i = 0; i < listcount; i++) {
+    thread_act_t thread = act_list[i];
+    if (thread == me) {
+      lo = GC_approx_sp();
+      hi = (ptr_t)FindTopOfStack(0);
+    } else {
 #     if defined(POWERPC)
-#      if CPP_WORDSZ == 32
-       ppc_thread_state_t info;
-#      else
-       ppc_thread_state64_t info;
-#      endif
+        GC_THREAD_STATE_T info;
        mach_msg_type_number_t outCount = THREAD_STATE_MAX;
-       r = thread_get_state(thread, MACHINE_THREAD_STATE,
-                            (natural_t *)&info, &outCount);
-       if(r != KERN_SUCCESS) ABORT("task_get_state failed");
-
-       lo = (void*)(info.r1 - PPC_RED_ZONE_SIZE);
-       hi = (ptr_t)FindTopOfStack(info.r1);
-
-       GC_push_one(info.r0); 
-       GC_push_one(info.r2); 
-       GC_push_one(info.r3); 
-       GC_push_one(info.r4); 
-       GC_push_one(info.r5); 
-       GC_push_one(info.r6); 
-       GC_push_one(info.r7); 
-       GC_push_one(info.r8); 
-       GC_push_one(info.r9); 
-       GC_push_one(info.r10); 
-       GC_push_one(info.r11); 
-       GC_push_one(info.r12); 
-       GC_push_one(info.r13); 
-       GC_push_one(info.r14); 
-       GC_push_one(info.r15); 
-       GC_push_one(info.r16); 
-       GC_push_one(info.r17); 
-       GC_push_one(info.r18); 
-       GC_push_one(info.r19); 
-       GC_push_one(info.r20); 
-       GC_push_one(info.r21); 
-       GC_push_one(info.r22); 
-       GC_push_one(info.r23); 
-       GC_push_one(info.r24); 
-       GC_push_one(info.r25); 
-       GC_push_one(info.r26); 
-       GC_push_one(info.r27); 
-       GC_push_one(info.r28); 
-       GC_push_one(info.r29); 
-       GC_push_one(info.r30); 
-       GC_push_one(info.r31);
-#      else
+       r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
+                            &outCount);
+       if(r != KERN_SUCCESS)
+         ABORT("task_get_state failed");
+
+       lo = (void*)(info . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
+       hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (r1));
+
+       GC_push_one(info . THREAD_FLD (r0));
+       GC_push_one(info . THREAD_FLD (r2));
+       GC_push_one(info . THREAD_FLD (r3));
+       GC_push_one(info . THREAD_FLD (r4));
+       GC_push_one(info . THREAD_FLD (r5));
+       GC_push_one(info . THREAD_FLD (r6));
+       GC_push_one(info . THREAD_FLD (r7));
+       GC_push_one(info . THREAD_FLD (r8));
+       GC_push_one(info . THREAD_FLD (r9));
+       GC_push_one(info . THREAD_FLD (r10));
+       GC_push_one(info . THREAD_FLD (r11));
+       GC_push_one(info . THREAD_FLD (r12));
+       GC_push_one(info . THREAD_FLD (r13));
+       GC_push_one(info . THREAD_FLD (r14));
+       GC_push_one(info . THREAD_FLD (r15));
+       GC_push_one(info . THREAD_FLD (r16));
+       GC_push_one(info . THREAD_FLD (r17));
+       GC_push_one(info . THREAD_FLD (r18));
+       GC_push_one(info . THREAD_FLD (r19));
+       GC_push_one(info . THREAD_FLD (r20));
+       GC_push_one(info . THREAD_FLD (r21));
+       GC_push_one(info . THREAD_FLD (r22));
+       GC_push_one(info . THREAD_FLD (r23));
+       GC_push_one(info . THREAD_FLD (r24));
+       GC_push_one(info . THREAD_FLD (r25));
+       GC_push_one(info . THREAD_FLD (r26));
+       GC_push_one(info . THREAD_FLD (r27));
+       GC_push_one(info . THREAD_FLD (r28));
+       GC_push_one(info . THREAD_FLD (r29));
+       GC_push_one(info . THREAD_FLD (r30));
+       GC_push_one(info . THREAD_FLD (r31));
+
+#     elif defined(I386)
        /* FIXME: Remove after testing: */
        WARN("This is completely untested and likely will not work\n", 0);
-       i386_thread_state_t info;
+       GC_THREAD_STATE_T info;
+       mach_msg_type_number_t outCount = THREAD_STATE_MAX;
+       r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
+                            &outCount);
+       if(r != KERN_SUCCESS)
+         ABORT("task_get_state failed");
+
+       lo = (void*)info . THREAD_FLD (esp);
+       hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (esp));
+
+       GC_push_one(info . THREAD_FLD (eax));
+       GC_push_one(info . THREAD_FLD (ebx));
+       GC_push_one(info . THREAD_FLD (ecx));
+       GC_push_one(info . THREAD_FLD (edx));
+       GC_push_one(info . THREAD_FLD (edi));
+       GC_push_one(info . THREAD_FLD (esi));
+       /* GC_push_one(info . THREAD_FLD (ebp));  */
+       /* GC_push_one(info . THREAD_FLD (esp));  */
+       GC_push_one(info . THREAD_FLD (ss));
+       GC_push_one(info . THREAD_FLD (eip));
+       GC_push_one(info . THREAD_FLD (cs));
+       GC_push_one(info . THREAD_FLD (ds));
+       GC_push_one(info . THREAD_FLD (es));
+       GC_push_one(info . THREAD_FLD (fs));
+       GC_push_one(info . THREAD_FLD (gs));
+
+#     elif defined(X86_64)
+       GC_THREAD_STATE_T info;
        mach_msg_type_number_t outCount = THREAD_STATE_MAX;
-       r = thread_get_state(thread, MACHINE_THREAD_STATE,
-                            (natural_t *)&info, &outCount);
-       if(r != KERN_SUCCESS) ABORT("task_get_state failed");
-
-       lo = (void*)info.esp;
-       hi = (ptr_t)FindTopOfStack(info.esp);
-
-       GC_push_one(info.eax); 
-       GC_push_one(info.ebx); 
-       GC_push_one(info.ecx); 
-       GC_push_one(info.edx); 
-       GC_push_one(info.edi); 
-       GC_push_one(info.esi); 
-       /* GC_push_one(info.ebp);  */
-       /* GC_push_one(info.esp);  */
-       GC_push_one(info.ss); 
-       GC_push_one(info.eip); 
-       GC_push_one(info.cs); 
-       GC_push_one(info.ds); 
-       GC_push_one(info.es); 
-       GC_push_one(info.fs); 
-       GC_push_one(info.gs); 
-#      endif /* !POWERPC */
+       r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
+                            &outCount);
+       if(r != KERN_SUCCESS)
+         ABORT("task_get_state failed");
+
+       lo = (void*)info . THREAD_FLD (rsp);
+       hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (rsp));
+
+       GC_push_one(info . THREAD_FLD (rax));
+       GC_push_one(info . THREAD_FLD (rbx));
+       GC_push_one(info . THREAD_FLD (rcx));
+       GC_push_one(info . THREAD_FLD (rdx));
+       GC_push_one(info . THREAD_FLD (rdi));
+       GC_push_one(info . THREAD_FLD (rsi));
+       GC_push_one(info . THREAD_FLD (rbp));
+       GC_push_one(info . THREAD_FLD (rsp));
+       GC_push_one(info . THREAD_FLD (r8));
+       GC_push_one(info . THREAD_FLD (r9));
+       GC_push_one(info . THREAD_FLD (r10));
+       GC_push_one(info . THREAD_FLD (r11));
+       GC_push_one(info . THREAD_FLD (r12));
+       GC_push_one(info . THREAD_FLD (r13));
+       GC_push_one(info . THREAD_FLD (r14));
+       GC_push_one(info . THREAD_FLD (r15));
+       GC_push_one(info . THREAD_FLD (rip));
+       GC_push_one(info . THREAD_FLD (rflags));
+       GC_push_one(info . THREAD_FLD (cs));
+       GC_push_one(info . THREAD_FLD (fs));
+       GC_push_one(info . THREAD_FLD (gs));
+
+#     else
+#      error FIXME for non-x86 || ppc architectures
+#     endif
       }
 #     if DEBUG_THREADS
-       GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
-                 (unsigned long) thread,
-                 (unsigned long) lo,
-                 (unsigned long) hi
-                );
+        GC_printf("Darwin: Stack for thread 0x%lx = [%p,%p)\n",
+                 (unsigned long) thread, lo, hi);
 #     endif
-      GC_push_all_stack(lo, hi); 
-         mach_port_deallocate(my_task, thread);
+      GC_push_all_stack(lo, hi);
+      mach_port_deallocate(my_task, thread);
     } /* for(p=GC_threads[i]...) */
-    vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
-       mach_port_deallocate(my_task, me);
+    vm_deallocate(my_task, (vm_address_t)act_list,
+                 sizeof(thread_t) * listcount);
+    mach_port_deallocate(my_task, me);
 }
 #endif /* !DARWIN_DONT_PARSE_STACK */
 
@@ -285,7 +348,8 @@ static int GC_use_mach_handler_thread = 0;
 static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
 static int GC_mach_threads_count;
 
-void GC_stop_init() {
+void GC_stop_init()
+{
   int i;
 
   for (i = 0; i < THREAD_TABLE_SZ; i++) {
@@ -296,8 +360,9 @@ void GC_stop_init() {
 }
 
 /* returns true if there's a thread in act_list that wasn't in old_list */
-int GC_suspend_thread_list(thread_act_array_t act_list, int count, 
-                          thread_act_array_t old_list, int old_count) {
+int GC_suspend_thread_list(thread_act_array_t act_list, int count,
+                          thread_act_array_t old_list, int old_count)
+{
   mach_port_t my_thread = mach_thread_self();
   int i, j;
 
@@ -305,8 +370,8 @@ int GC_suspend_thread_list(thread_act_array_t act_list, int count,
 
   for(i = 0; i < count; i++) {
     thread_act_t thread = act_list[i];
-#   if DEBUG_THREADS 
-      GC_printf1("Attempting to suspend thread %p\n", thread);
+#   if DEBUG_THREADS
+      GC_printf("Attempting to suspend thread %p\n", thread);
 #   endif
     /* find the current thread in the old list */
     int found = 0;
@@ -323,50 +388,53 @@ int GC_suspend_thread_list(thread_act_array_t act_list, int count,
       /* default is not suspended */
       GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
       changed = 1;
-    }      
+    }
 
-    if (thread != my_thread &&
-       (!GC_use_mach_handler_thread
-        || (GC_use_mach_handler_thread
-            && GC_mach_handler_thread != thread))) {
+    if (thread != my_thread
+       && (!GC_use_mach_handler_thread
+           || (GC_use_mach_handler_thread
+               && GC_mach_handler_thread != thread))) {
       struct thread_basic_info info;
       mach_msg_type_number_t outCount = THREAD_INFO_MAX;
       kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
                                (thread_info_t)&info, &outCount);
       if(kern_result != KERN_SUCCESS) {
-       /* the thread may have quit since the thread_threads () call 
+       /* the thread may have quit since the thread_threads () call
         * we mark already_suspended so it's not dealt with anymore later
         */
-        if (!found) {
+       if (!found) {
          GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
-         GC_mach_threads_count++;
+         GC_mach_threads_count++;
        }
        continue;
       }
 #     if DEBUG_THREADS
-        GC_printf2("Thread state for 0x%lx = %d\n", thread, info.run_state);
+        GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
+                 info.run_state);
 #     endif
       if (!found) {
-       GC_mach_threads[GC_mach_threads_count].already_suspended = info.suspend_count;
+       GC_mach_threads[GC_mach_threads_count].already_suspended
+         = info.suspend_count;
       }
-      if (info.suspend_count) continue;
-      
+      if (info.suspend_count)
+       continue;
+
 #     if DEBUG_THREADS
-        GC_printf1("Suspending 0x%lx\n", thread);
+        GC_printf("Suspending 0x%lx\n", (unsigned long)thread);
 #     endif
       /* Suspend the thread */
       kern_result = thread_suspend(thread);
       if(kern_result != KERN_SUCCESS) {
-       /* the thread may have quit since the thread_threads () call 
+       /* the thread may have quit since the thread_threads () call
         * we mark already_suspended so it's not dealt with anymore later
         */
-        if (!found) {
+       if (!found) {
          GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
-         GC_mach_threads_count++;
+         GC_mach_threads_count++;
        }
        continue;
       }
-    } 
+    }
     if (!found) GC_mach_threads_count++;
   }
   mach_port_deallocate(current_task(), my_thread);
@@ -377,21 +445,21 @@ int GC_suspend_thread_list(thread_act_array_t act_list, int count,
 /* Caller holds allocation lock.       */
 void GC_stop_world()
 {
-  int i, changes;
-    GC_thread p;
-       task_t my_task = current_task();
+    unsigned int i, changes;
+    task_t my_task = current_task();
     mach_port_t my_thread = mach_thread_self();
     kern_return_t kern_result;
     thread_act_array_t act_list, prev_list;
     mach_msg_type_number_t listcount, prevcount;
-    
+
 #   if DEBUG_THREADS
-      GC_printf1("Stopping the world from 0x%lx\n", mach_thread_self());
+      GC_printf("Stopping the world from 0x%lx\n",
+               (unsigned long)mach_thread_self());
 #   endif
 
     /* clear out the mach threads list table */
-    GC_stop_init(); 
-       
+    GC_stop_init();
+
     /* Make sure all free list construction has stopped before we start. */
     /* No new construction can start, since free list construction is  */
     /* required to acquire and release the GC lock before it starts,   */
@@ -402,52 +470,59 @@ void GC_stop_world()
       /* We should have previously waited for it to become zero. */
 #   endif /* PARALLEL_MARK */
 
-      /* Loop stopping threads until you have gone over the whole list
-        twice without a new one appearing. thread_create() won't
-        return (and thus the thread stop) until the new thread
-        exists, so there is no window whereby you could stop a
-        thread, recognise it is stopped, but then have a new thread
-        it created before stopping show up later.
-      */
-      
-      changes = 1;
-      prev_list = NULL;
-      prevcount = 0;
-      do {
-       int result;
-       kern_result = task_threads(my_task, &act_list, &listcount);
-       result = GC_suspend_thread_list(act_list, listcount,
-                                       prev_list, prevcount);
+    /* Loop stopping threads until you have gone over the whole list
+       twice without a new one appearing. thread_create() won't
+       return (and thus the thread stop) until the new thread
+       exists, so there is no window whereby you could stop a
+       thread, recognise it is stopped, but then have a new thread
+       it created before stopping show up later.
+    */
+
+    changes = 1;
+    prev_list = NULL;
+    prevcount = 0;
+    do {
+      int result;
+      kern_result = task_threads(my_task, &act_list, &listcount);
+
+      if(kern_result == KERN_SUCCESS) {
+       result = GC_suspend_thread_list(act_list, listcount, prev_list,
+                                       prevcount);
        changes = result;
+
+       if(prev_list != NULL) {
+         for(i = 0; i < prevcount; i++)
+           mach_port_deallocate(my_task, prev_list[i]);
+
+         vm_deallocate(my_task, (vm_address_t)prev_list,
+                       sizeof(thread_t) * prevcount);
+       }
        prev_list = act_list;
        prevcount = listcount;
-       
-       if(kern_result == KERN_SUCCESS) {
-               int i;
-               
-               for(i = 0; i < listcount; i++)
-                       mach_port_deallocate(my_task, act_list[i]);
-               
-        vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
-       }
-      } while (changes);
-      
+      }
+    } while (changes);
+    GC_ASSERT(prev_list != 0);
+    for(i = 0; i < prevcount; i++)
+      mach_port_deallocate(my_task, prev_list[i]);
+
+    vm_deallocate(my_task, (vm_address_t)act_list,
+                 sizeof(thread_t) * listcount);
+
 #   ifdef MPROTECT_VDB
       if(GC_incremental) {
-        extern void GC_mprotect_stop();
-        GC_mprotect_stop();
+       extern void GC_mprotect_stop();
+       GC_mprotect_stop();
       }
 #   endif
-    
+
 #   ifdef PARALLEL_MARK
       GC_release_mark_lock();
 #   endif
-    #if DEBUG_THREADS
-      GC_printf1("World stopped from 0x%lx\n", my_thread);
-    #endif
-         
-         mach_port_deallocate(my_task, my_thread);
+#   if DEBUG_THREADS
+      GC_printf("World stopped from 0x%lx\n", (unsigned long)my_thread);
+#   endif
+
+    mach_port_deallocate(my_task, my_thread);
 }
 
 /* Caller holds allocation lock, and has held it continuously since    */
@@ -456,65 +531,69 @@ void GC_start_world()
 {
   task_t my_task = current_task();
   mach_port_t my_thread = mach_thread_self();
-  int i, j;
-  GC_thread p;
+  unsigned int i;
+  int j;
   kern_return_t kern_result;
   thread_act_array_t act_list;
   mach_msg_type_number_t listcount;
   struct thread_basic_info info;
   mach_msg_type_number_t outCount = THREAD_INFO_MAX;
-  
+
 #   if DEBUG_THREADS
-      GC_printf0("World starting\n");
+      GC_printf("World starting\n");
 #   endif
 
 #   ifdef MPROTECT_VDB
       if(GC_incremental) {
-        extern void GC_mprotect_resume();
-        GC_mprotect_resume();
+       extern void GC_mprotect_resume();
+       GC_mprotect_resume();
       }
 #   endif
 
     kern_result = task_threads(my_task, &act_list, &listcount);
     for(i = 0; i < listcount; i++) {
       thread_act_t thread = act_list[i];
-      if (thread != my_thread &&
-         (!GC_use_mach_handler_thread ||
-          (GC_use_mach_handler_thread && GC_mach_handler_thread != thread))) {
+      if (thread != my_thread
+         && (!GC_use_mach_handler_thread
+             || (GC_use_mach_handler_thread
+                 && GC_mach_handler_thread != thread))) {
        for(j = 0; j < GC_mach_threads_count; j++) {
          if (thread == GC_mach_threads[j].thread) {
            if (GC_mach_threads[j].already_suspended) {
 #             if DEBUG_THREADS
-               GC_printf1("Not resuming already suspended thread %p\n", thread);
+               GC_printf("Not resuming already suspended thread %p\n", thread);
 #             endif
              continue;
            }
            kern_result = thread_info(thread, THREAD_BASIC_INFO,
                                      (thread_info_t)&info, &outCount);
-           if(kern_result != KERN_SUCCESS) ABORT("thread_info failed");
+           if(kern_result != KERN_SUCCESS)
+             ABORT("thread_info failed");
 #           if DEBUG_THREADS
-             GC_printf2("Thread state for 0x%lx = %d\n", thread,
+             GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
                         info.run_state);
-             GC_printf1("Resuming 0x%lx\n", thread);
+             GC_printf("Resuming 0x%lx\n", (unsigned long)thread);
 #           endif
            /* Resume the thread */
            kern_result = thread_resume(thread);
-           if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
-         } 
+           if(kern_result != KERN_SUCCESS)
+             ABORT("thread_resume failed");
+         }
        }
       }
-         
-         mach_port_deallocate(my_task, thread);
+      mach_port_deallocate(my_task, thread);
     }
-    vm_deallocate(my_task, (vm_address_t)act_list, sizeof(thread_t) * listcount);
-       
-       mach_port_deallocate(my_task, my_thread);
+    vm_deallocate(my_task, (vm_address_t)act_list,
+                 sizeof(thread_t) * listcount);
+
+    mach_port_deallocate(my_task, my_thread);
 #   if DEBUG_THREADS
-     GC_printf0("World started\n");
+      GC_printf("World started\n");
 #   endif
 }
 
-void GC_darwin_register_mach_handler_thread(mach_port_t thread) {
+void GC_darwin_register_mach_handler_thread(mach_port_t thread)
+{
   GC_mach_handler_thread = thread;
   GC_use_mach_handler_thread = 1;
 }
index 18c2f6c9b760f577c94696e5fcc4c429a602cbab..3fbd60aec4d8af6bc02c82dae8abbc36e0cdd4cc 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
  * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2007 Free Software Foundation, Inc
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -22,8 +23,8 @@
 
 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));
+       (void * obj, GC_finalization_proc fn, void * cd,
+        GC_finalization_proc *ofn, void * *ocd);
 
 
 #ifndef SHORT_DBG_HDRS
@@ -36,8 +37,7 @@ GC_API void GC_register_finalizer_no_order
 /* on free lists may not have debug information set.  Thus it's        */
 /* not always safe to return TRUE, even if the client does     */
 /* its part.                                                   */
-GC_bool GC_has_other_debug_info(p)
-ptr_t p;
+GC_bool GC_has_other_debug_info(ptr_t p)
 {
     register oh * ohdr = (oh *)p;
     register ptr_t body = (ptr_t)(ohdr + 1);
@@ -63,7 +63,7 @@ ptr_t p;
 
 # include <stdlib.h>
 
-# if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
+# if defined(LINUX) || defined(SOLARIS) \
      || defined(HPUX) || defined(IRIX5) || defined(OSF1)
 #   define RANDOM() random()
 # else
@@ -148,7 +148,7 @@ ptr_t p;
         /* e.g. RAND_MAX = 1.5* GC_heapsize.  But for typical cases,   */
         /* it's not too bad.                                           */
     for (i = 0; i < GC_n_heap_sects; ++ i) {
-       int size = GC_heap_sects[i].hs_bytes;
+       size_t size = GC_heap_sects[i].hs_bytes;
        if (heap_offset < size) {
            return GC_heap_sects[i].hs_start + heap_offset;
        } else {
@@ -184,34 +184,34 @@ ptr_t p;
     void *base;
 
     GC_print_heap_obj(GC_base(current));
-    GC_err_printf0("\n");
+    GC_err_printf("\n");
     for (i = 0; ; ++i) {
       source = GC_get_back_ptr_info(current, &base, &offset);
       if (GC_UNREFERENCED == source) {
-       GC_err_printf0("Reference could not be found\n");
+       GC_err_printf("Reference could not be found\n");
        goto out;
       }
       if (GC_NO_SPACE == source) {
-       GC_err_printf0("No debug info in object: Can't find reference\n");
+       GC_err_printf("No debug info in object: Can't find reference\n");
        goto out;
       }
-      GC_err_printf1("Reachable via %d levels of pointers from ",
+      GC_err_printf("Reachable via %d levels of pointers from ",
                 (unsigned long)i);
       switch(source) {
        case GC_REFD_FROM_ROOT:
-         GC_err_printf1("root at 0x%lx\n\n", (unsigned long)base);
+         GC_err_printf("root at %p\n\n", base);
          goto out;
        case GC_REFD_FROM_REG:
-         GC_err_printf0("root in register\n\n");
+         GC_err_printf("root in register\n\n");
          goto out;
        case GC_FINALIZER_REFD:
-         GC_err_printf0("list of finalizable objects\n\n");
+         GC_err_printf("list of finalizable objects\n\n");
          goto out;
        case GC_REFD_FROM_HEAP:
-         GC_err_printf1("offset %ld in object:\n", (unsigned long)offset);
+         GC_err_printf("offset %ld in object:\n", (unsigned long)offset);
          /* Take GC_base(base) to get real base, i.e. header. */
          GC_print_heap_obj(GC_base(base));
-         GC_err_printf0("\n");
+         GC_err_printf("\n");
          break;
       }
       current = base;
@@ -225,7 +225,7 @@ ptr_t p;
   {
     void * current;
     current = GC_generate_random_valid_address();
-    GC_printf1("\n****Chose address 0x%lx in object\n", (unsigned long)current);
+    GC_printf("\n****Chose address %p in object\n", current);
     GC_print_backtrace(current);
   }
     
@@ -241,11 +241,7 @@ ptr_t p;
        (((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
 /* Store debugging info into p.  Return displaced pointer. */
 /* Assumes we don't hold allocation lock.                 */
-ptr_t GC_store_debug_info(p, sz, string, integer)
-register ptr_t p;      /* base pointer */
-word sz;       /* bytes */
-GC_CONST char * string;
-word integer;
+ptr_t GC_store_debug_info(ptr_t p, word sz, const char *string, word integer)
 {
     register word * result = (word *)((oh *)p + 1);
     DCL_LOCK_STATE;
@@ -277,11 +273,7 @@ word integer;
 #ifdef DBG_HDRS_ALL
 /* Store debugging info into p.  Return displaced pointer.        */
 /* This version assumes we do hold the allocation lock.                   */
-ptr_t GC_store_debug_info_inner(p, sz, string, integer)
-register ptr_t p;      /* base pointer */
-word sz;       /* bytes */
-char * string;
-word integer;
+ptr_t GC_store_debug_info_inner(ptr_t p, word sz, char *string, word integer)
 {
     register word * result = (word *)((oh *)p + 1);
     
@@ -312,8 +304,7 @@ word integer;
 /* Check the object with debugging info at ohdr                */
 /* return NIL if it's OK.  Else return clobbered       */
 /* address.                                            */
-ptr_t GC_check_annotated_obj(ohdr)
-register oh * ohdr;
+ptr_t GC_check_annotated_obj(oh *ohdr)
 {
     register ptr_t body = (ptr_t)(ohdr + 1);
     register word gc_sz = GC_size((ptr_t)ohdr);
@@ -336,17 +327,14 @@ register oh * ohdr;
 
 static GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
 
-void GC_register_describe_type_fn(kind, fn)
-int kind;
-GC_describe_type_fn fn;
+void GC_register_describe_type_fn(int kind, GC_describe_type_fn fn)
 {
   GC_describe_type_fns[kind] = fn;
 }
 
 /* Print a type description for the object whose client-visible address        */
 /* is p.                                                               */
-void GC_print_type(p)
-ptr_t p;
+void GC_print_type(ptr_t p)
 {
     hdr * hhdr = GC_find_header(p);
     char buffer[GC_TYPE_DESCR_LEN + 1];
@@ -379,25 +367,25 @@ ptr_t p;
            GC_err_puts("STUBBORN");
            break;
          default:
-           GC_err_printf2("kind %ld, descr 0x%lx", kind, hhdr -> hb_descr);
+           GC_err_printf("kind %d, descr 0x%lx", kind,
+                         (unsigned long)(hhdr -> hb_descr));
        }
     }
 }
 
     
 
-void GC_print_obj(p)
-ptr_t p;
+void GC_print_obj(ptr_t p)
 {
     register oh * ohdr = (oh *)GC_base(p);
     
-    GC_ASSERT(!I_HOLD_LOCK());
-    GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
+    GC_ASSERT(I_DONT_HOLD_LOCK());
+    GC_err_printf("%p (", ((ptr_t)ohdr + sizeof(oh)));
     GC_err_puts(ohdr -> oh_string);
 #   ifdef SHORT_DBG_HDRS
-      GC_err_printf1(":%ld, ", (unsigned long)(ohdr -> oh_int));
+      GC_err_printf(":%ld, ", (unsigned long)(ohdr -> oh_int));
 #   else
-      GC_err_printf2(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int),
+      GC_err_printf(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int),
                                        (unsigned long)(ohdr -> oh_sz));
 #   endif
     GC_print_type((ptr_t)(ohdr + 1));
@@ -405,14 +393,9 @@ ptr_t p;
     PRINT_CALL_CHAIN(ohdr);
 }
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_debug_print_heap_obj_proc(ptr_t p)
-# else
-    void GC_debug_print_heap_obj_proc(p)
-    ptr_t p;
-# endif
+void GC_debug_print_heap_obj_proc(ptr_t p)
 {
-    GC_ASSERT(!I_HOLD_LOCK());
+    GC_ASSERT(I_DONT_HOLD_LOCK());
     if (GC_HAS_DEBUG_INFO(p)) {
        GC_print_obj(p);
     } else {
@@ -421,17 +404,15 @@ ptr_t p;
 }
 
 #ifndef SHORT_DBG_HDRS
-void GC_print_smashed_obj(p, clobbered_addr)
-ptr_t p, clobbered_addr;
+void GC_print_smashed_obj(ptr_t p, ptr_t clobbered_addr)
 {
     register oh * ohdr = (oh *)GC_base(p);
     
-    GC_ASSERT(!I_HOLD_LOCK());
-    GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
-                                               (unsigned long)p);
+    GC_ASSERT(I_DONT_HOLD_LOCK());
+    GC_err_printf("%p in object at %p(", clobbered_addr, p);
     if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
         || ohdr -> oh_string == 0) {
-        GC_err_printf1("<smashed>, appr. sz = %ld)\n",
+        GC_err_printf("<smashed>, appr. sz = %ld)\n",
                       (GC_size((ptr_t)ohdr) - DEBUG_BYTES));
     } else {
         if (ohdr -> oh_string[0] == '\0') {
@@ -439,20 +420,20 @@ ptr_t p, clobbered_addr;
         } else {
             GC_err_puts(ohdr -> oh_string);
         }
-        GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
+        GC_err_printf(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
                                          (unsigned long)(ohdr -> oh_sz));
         PRINT_CALL_CHAIN(ohdr);
     }
 }
 #endif
 
-void GC_check_heap_proc GC_PROTO((void));
+void GC_check_heap_proc (void);
 
-void GC_print_all_smashed_proc GC_PROTO((void));
+void GC_print_all_smashed_proc (void);
 
-void GC_do_nothing() {}
+void GC_do_nothing(void) {}
 
-void GC_start_debugging()
+void GC_start_debugging(void)
 {
 #   ifndef SHORT_DBG_HDRS
       GC_check_heap = GC_check_heap_proc;
@@ -468,36 +449,21 @@ void GC_start_debugging()
 
 size_t GC_debug_header_size = sizeof(oh);
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_debug_register_displacement(GC_word offset)
-# else
-    void GC_debug_register_displacement(offset) 
-    GC_word offset;
-# endif
+void GC_debug_register_displacement(size_t offset)
 {
     GC_register_displacement(offset);
     GC_register_displacement((word)sizeof(oh) + offset);
 }
 
-# ifdef __STDC__
-    GC_PTR GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
-# else
-    GC_PTR GC_debug_malloc(lb, s, i)
-    size_t lb;
-    char * s;
-    int i;
-#   ifdef GC_ADD_CALLER
-       --> GC_ADD_CALLER not implemented for K&R C
-#   endif
-# endif
+void * GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
 {
-    GC_PTR result = GC_malloc(lb + DEBUG_BYTES);
+    void * result = GC_malloc(lb + DEBUG_BYTES);
     
     if (result == 0) {
-        GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
-                      (unsigned long) lb);
+        GC_err_printf("GC_debug_malloc(%lu) returning NIL (",
+                     (unsigned long) lb);
         GC_err_puts(s);
-        GC_err_printf1(":%ld)\n", (unsigned long)i);
+        GC_err_printf(":%ld)\n", (unsigned long)i);
         return(0);
     }
     if (!GC_debugging_started) {
@@ -507,25 +473,15 @@ size_t GC_debug_header_size = sizeof(oh);
     return (GC_store_debug_info(result, (word)lb, s, (word)i));
 }
 
-# ifdef __STDC__
-    GC_PTR GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
-# else
-    GC_PTR GC_debug_malloc_ignore_off_page(lb, s, i)
-    size_t lb;
-    char * s;
-    int i;
-#   ifdef GC_ADD_CALLER
-       --> GC_ADD_CALLER not implemented for K&R C
-#   endif
-# endif
+void * GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
 {
-    GC_PTR result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
+    void * result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
     
     if (result == 0) {
-        GC_err_printf1("GC_debug_malloc_ignore_off_page(%ld) returning NIL (",
+        GC_err_printf("GC_debug_malloc_ignore_off_page(%lu) returning NIL (",
                       (unsigned long) lb);
         GC_err_puts(s);
-        GC_err_printf1(":%ld)\n", (unsigned long)i);
+        GC_err_printf(":%lu)\n", (unsigned long)i);
         return(0);
     }
     if (!GC_debugging_started) {
@@ -535,25 +491,15 @@ size_t GC_debug_header_size = sizeof(oh);
     return (GC_store_debug_info(result, (word)lb, s, (word)i));
 }
 
-# ifdef __STDC__
-    GC_PTR GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
-# else
-    GC_PTR GC_debug_malloc_atomic_ignore_off_page(lb, s, i)
-    size_t lb;
-    char * s;
-    int i;
-#   ifdef GC_ADD_CALLER
-       --> GC_ADD_CALLER not implemented for K&R C
-#   endif
-# endif
+void * GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
 {
-    GC_PTR result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
+    void * result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
     
     if (result == 0) {
-        GC_err_printf1("GC_debug_malloc_atomic_ignore_off_page(%ld)"
+        GC_err_printf("GC_debug_malloc_atomic_ignore_off_page(%lu)"
                       " returning NIL (", (unsigned long) lb);
         GC_err_puts(s);
-        GC_err_printf1(":%ld)\n", (unsigned long)i);
+        GC_err_printf(":%lu)\n", (unsigned long)i);
         return(0);
     }
     if (!GC_debugging_started) {
@@ -572,12 +518,12 @@ size_t GC_debug_header_size = sizeof(oh);
  * We assume debugging was started in collector initialization,
  * and we already hold the GC lock.
  */
-  GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k)
+  void * GC_debug_generic_malloc_inner(size_t lb, int k)
   {
-    GC_PTR result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
+    void * result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
     
     if (result == 0) {
-        GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
+        GC_err_printf("GC internal allocation (%lu bytes) returning NIL\n",
                       (unsigned long) lb);
         return(0);
     }
@@ -585,13 +531,13 @@ size_t GC_debug_header_size = sizeof(oh);
     return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
   }
 
-  GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, int k)
+  void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, int k)
   {
-    GC_PTR result = GC_generic_malloc_inner_ignore_off_page(
+    void * result = GC_generic_malloc_inner_ignore_off_page(
                                                lb + DEBUG_BYTES, k);
     
     if (result == 0) {
-        GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
+        GC_err_printf("GC internal allocation (%lu bytes) returning NIL\n",
                       (unsigned long) lb);
         return(0);
     }
@@ -601,22 +547,15 @@ size_t GC_debug_header_size = sizeof(oh);
 # endif
 
 #ifdef STUBBORN_ALLOC
-# ifdef __STDC__
-    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;
-    char * s;
-    int i;
-# endif
+void * GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
 {
-    GC_PTR result = GC_malloc_stubborn(lb + DEBUG_BYTES);
+    void * result = GC_malloc_stubborn(lb + DEBUG_BYTES);
     
     if (result == 0) {
-        GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
-                      (unsigned long) lb);
+        GC_err_printf("GC_debug_malloc(%lu) returning NIL (",
+                     (unsigned long) lb);
         GC_err_puts(s);
-        GC_err_printf1(":%ld)\n", (unsigned long)i);
+        GC_err_printf(":%lu)\n", (unsigned long)i);
         return(0);
     }
     if (!GC_debugging_started) {
@@ -626,41 +565,35 @@ size_t GC_debug_header_size = sizeof(oh);
     return (GC_store_debug_info(result, (word)lb, s, (word)i));
 }
 
-void GC_debug_change_stubborn(p)
-GC_PTR p;
+void GC_debug_change_stubborn(void *p)
 {
-    register GC_PTR q = GC_base(p);
-    register hdr * hhdr;
+    void * q = GC_base(p);
+    hdr * hhdr;
     
     if (q == 0) {
-        GC_err_printf1("Bad argument: 0x%lx to GC_debug_change_stubborn\n",
-                      (unsigned long) p);
+        GC_err_printf("Bad argument: %p to GC_debug_change_stubborn\n", p);
         ABORT("GC_debug_change_stubborn: bad arg");
     }
     hhdr = HDR(q);
     if (hhdr -> hb_obj_kind != STUBBORN) {
-        GC_err_printf1("GC_debug_change_stubborn arg not stubborn: 0x%lx\n",
-                      (unsigned long) p);
+        GC_err_printf("GC_debug_change_stubborn arg not stubborn: %p\n", p);
         ABORT("GC_debug_change_stubborn: arg not stubborn");
     }
     GC_change_stubborn(q);
 }
 
-void GC_debug_end_stubborn_change(p)
-GC_PTR p;
+void GC_debug_end_stubborn_change(void *p)
 {
-    register GC_PTR q = GC_base(p);
+    register void * q = GC_base(p);
     register hdr * hhdr;
     
     if (q == 0) {
-        GC_err_printf1("Bad argument: 0x%lx to GC_debug_end_stubborn_change\n",
-                      (unsigned long) p);
+        GC_err_printf("Bad argument: %p to GC_debug_end_stubborn_change\n", p);
         ABORT("GC_debug_end_stubborn_change: bad arg");
     }
     hhdr = HDR(q);
     if (hhdr -> hb_obj_kind != STUBBORN) {
-        GC_err_printf1("debug_end_stubborn_change arg not stubborn: 0x%lx\n",
-                      (unsigned long) p);
+        GC_err_printf("debug_end_stubborn_change arg not stubborn: %p\n", p);
         ABORT("GC_debug_end_stubborn_change: arg not stubborn");
     }
     GC_end_stubborn_change(q);
@@ -668,46 +601,30 @@ GC_PTR p;
 
 #else /* !STUBBORN_ALLOC */
 
-# ifdef __STDC__
-    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;
-    char * s;
-    int i;
-# endif
+void * GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
 {
     return GC_debug_malloc(lb, OPT_RA s, i);
 }
 
-void GC_debug_change_stubborn(p)
-GC_PTR p;
+void GC_debug_change_stubborn(void *p)
 {
 }
 
-void GC_debug_end_stubborn_change(p)
-GC_PTR p;
+void GC_debug_end_stubborn_change(void *p)
 {
 }
 
 #endif /* !STUBBORN_ALLOC */
 
-# ifdef __STDC__
-    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;
-    char * s;
-    int i;
-# endif
+void * GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
 {
-    GC_PTR result = GC_malloc_atomic(lb + DEBUG_BYTES);
+    void * result = GC_malloc_atomic(lb + DEBUG_BYTES);
     
     if (result == 0) {
-        GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
+        GC_err_printf("GC_debug_malloc_atomic(%lu) returning NIL (",
                      (unsigned long) lb);
         GC_err_puts(s);
-        GC_err_printf1(":%ld)\n", (unsigned long)i);
+        GC_err_printf(":%lu)\n", (unsigned long)i);
         return(0);
     }
     if (!GC_debugging_started) {
@@ -717,14 +634,7 @@ GC_PTR p;
     return (GC_store_debug_info(result, (word)lb, s, (word)i));
 }
 
-# ifdef __STDC__
-    char *GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
-#else
-    char *GC_debug_strdup(str, s, i)
-    char *str;
-    char *s;
-    int i;
-#endif
+char *GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
 {
     char *copy;
     if (str == NULL) return NULL;
@@ -737,22 +647,15 @@ GC_PTR p;
     return copy;
 }
 
-# ifdef __STDC__
-    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;
-    char * s;
-    int i;
-# endif
+void * GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS)
 {
-    GC_PTR result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
+    void * result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
     
     if (result == 0) {
-        GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
+        GC_err_printf("GC_debug_malloc_uncollectable(%lu) returning NIL (",
                      (unsigned long) lb);
         GC_err_puts(s);
-        GC_err_printf1(":%ld)\n", (unsigned long)i);
+        GC_err_printf(":%lu)\n", (unsigned long)i);
         return(0);
     }
     if (!GC_debugging_started) {
@@ -763,24 +666,17 @@ GC_PTR p;
 }
 
 #ifdef ATOMIC_UNCOLLECTABLE
-# ifdef __STDC__
-    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;
-    char * s;
-    int i;
-# endif
+void * GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
 {
-    GC_PTR result =
+    void * result =
        GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
     
     if (result == 0) {
-        GC_err_printf1(
-               "GC_debug_malloc_atomic_uncollectable(%ld) returning NIL (",
+        GC_err_printf(
+               "GC_debug_malloc_atomic_uncollectable(%lu) returning NIL (",
                 (unsigned long) lb);
         GC_err_puts(s);
-        GC_err_printf1(":%ld)\n", (unsigned long)i);
+        GC_err_printf(":%lu)\n", (unsigned long)i);
         return(0);
     }
     if (!GC_debugging_started) {
@@ -791,36 +687,29 @@ GC_PTR p;
 }
 #endif /* ATOMIC_UNCOLLECTABLE */
 
-# ifdef __STDC__
-    void GC_debug_free(GC_PTR p)
-# else
-    void GC_debug_free(p)
-    GC_PTR p;
-# endif
+void GC_debug_free(void * p)
 {
-    register GC_PTR base;
-    register ptr_t clobbered;
+    ptr_t base;
+    ptr_t clobbered;
     
     if (0 == p) return;
     base = GC_base(p);
     if (base == 0) {
-        GC_err_printf1("Attempt to free invalid pointer %lx\n",
-                      (unsigned long)p);
+        GC_err_printf("Attempt to free invalid pointer %p\n", p);
         ABORT("free(invalid pointer)");
     }
     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
-        GC_err_printf1(
-                 "GC_debug_free called on pointer %lx wo debugging info\n",
-                 (unsigned long)p);
+        GC_err_printf(
+                 "GC_debug_free called on pointer %p wo debugging info\n", p);
     } else {
 #     ifndef SHORT_DBG_HDRS
         clobbered = GC_check_annotated_obj((oh *)base);
         if (clobbered != 0) {
           if (((oh *)base) -> oh_sz == GC_size(base)) {
-            GC_err_printf0(
+            GC_err_printf(
                   "GC_debug_free: found previously deallocated (?) object at ");
           } else {
-            GC_err_printf0("GC_debug_free: found smashed location at ");
+            GC_err_printf("GC_debug_free: found smashed location at ");
           }
           GC_print_smashed_obj(p, clobbered);
         }
@@ -831,7 +720,7 @@ GC_PTR p;
     if (GC_find_leak) {
         GC_free(base);
     } else {
-       register hdr * hhdr = HDR(p);
+       hdr * hhdr = HDR(p);
        GC_bool uncollectable = FALSE;
 
         if (hhdr ->  hb_obj_kind == UNCOLLECTABLE) {
@@ -846,52 +735,42 @@ GC_PTR p;
            GC_free(base);
        } else {
            size_t i;
-           size_t obj_sz = hhdr -> hb_sz - BYTES_TO_WORDS(sizeof(oh));
+           size_t obj_sz = BYTES_TO_WORDS(hhdr -> hb_sz - sizeof(oh));
 
            for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = 0xdeadbeef;
-           GC_ASSERT((word *)p + i == (word *)base + hhdr -> hb_sz);
+           GC_ASSERT((word *)p + i == (word *)(base + hhdr -> hb_sz));
        }
     } /* !GC_find_leak */
 }
 
 #ifdef THREADS
 
-extern void GC_free_inner(GC_PTR p);
+extern void GC_free_inner(void * p);
 
 /* Used internally; we assume it's called correctly.   */
-void GC_debug_free_inner(GC_PTR p)
+void GC_debug_free_inner(void * p)
 {
     GC_free_inner(GC_base(p));
 }
 #endif
 
-# ifdef __STDC__
-    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;
-    size_t lb;
-    char *s;
-    int i;
-# endif
+void * GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
 {
-    register GC_PTR base = GC_base(p);
-    register ptr_t clobbered;
-    register GC_PTR result;
-    register size_t copy_sz = lb;
-    register size_t old_sz;
-    register hdr * hhdr;
+    void * base = GC_base(p);
+    ptr_t clobbered;
+    void * result;
+    size_t copy_sz = lb;
+    size_t old_sz;
+    hdr * hhdr;
     
     if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i));
     if (base == 0) {
-        GC_err_printf1(
-              "Attempt to reallocate invalid pointer %lx\n", (unsigned long)p);
+        GC_err_printf("Attempt to reallocate invalid pointer %p\n", p);
         ABORT("realloc(invalid pointer)");
     }
     if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
-        GC_err_printf1(
-               "GC_debug_realloc called on pointer %lx wo debugging info\n",
-               (unsigned long)p);
+        GC_err_printf(
+               "GC_debug_realloc called on pointer %p wo debugging info\n", p);
         return(GC_realloc(p, lb));
     }
     hhdr = HDR(base);
@@ -916,7 +795,7 @@ void GC_debug_free_inner(GC_PTR p)
        break;
 #    endif
       default:
-        GC_err_printf0("GC_debug_realloc: encountered bad kind\n");
+        GC_err_printf("GC_debug_realloc: encountered bad kind\n");
         ABORT("bad kind");
     }
 #   ifdef SHORT_DBG_HDRS
@@ -924,7 +803,7 @@ void GC_debug_free_inner(GC_PTR p)
 #   else
       clobbered = GC_check_annotated_obj((oh *)base);
       if (clobbered != 0) {
-        GC_err_printf0("GC_debug_realloc: found smashed location at ");
+        GC_err_printf("GC_debug_realloc: found smashed location at ");
         GC_print_smashed_obj(p, clobbered);
       }
       old_sz = ((oh *)base) -> oh_sz;
@@ -946,12 +825,7 @@ void GC_debug_free_inner(GC_PTR p)
 ptr_t GC_smashed[MAX_SMASHED];
 unsigned GC_n_smashed = 0;
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_add_smashed(ptr_t smashed)
-# else
-    void GC_add_smashed(smashed)
-    ptr_t smashed;
-#endif
+void GC_add_smashed(ptr_t smashed)
 {
     GC_ASSERT(GC_is_marked(GC_base(smashed)));
     GC_smashed[GC_n_smashed] = smashed;
@@ -962,13 +836,13 @@ unsigned GC_n_smashed = 0;
 }
 
 /* Print all objects on the list.  Clear the list.     */
-void GC_print_all_smashed_proc ()
+void GC_print_all_smashed_proc(void)
 {
     unsigned i;
 
-    GC_ASSERT(!I_HOLD_LOCK());
+    GC_ASSERT(I_DONT_HOLD_LOCK());
     if (GC_n_smashed == 0) return;
-    GC_err_printf0("GC_check_heap_block: found smashed heap objects:\n");
+    GC_err_printf("GC_check_heap_block: found smashed heap objects:\n");
     for (i = 0; i < GC_n_smashed; ++i) {
         GC_print_smashed_obj(GC_base(GC_smashed[i]), GC_smashed[i]);
        GC_smashed[i] = 0;
@@ -976,37 +850,32 @@ void GC_print_all_smashed_proc ()
     GC_n_smashed = 0;
 }
 
-/* Check all marked objects in the given block for validity */
+/* Check all marked objects in the given block for validity    */
+/* Avoid GC_apply_to_each_object for performance reasons.      */
 /*ARGSUSED*/
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_check_heap_block(register struct hblk *hbp, word dummy)
-# else
-    void GC_check_heap_block(hbp, dummy)
-    register struct hblk *hbp; /* ptr to current heap block            */
-    word dummy;
-# endif
+void GC_check_heap_block(struct hblk *hbp, word dummy)
 {
-    register struct hblkhdr * hhdr = HDR(hbp);
-    register word sz = hhdr -> hb_sz;
-    register int word_no;
-    register word *p, *plim;
+    struct hblkhdr * hhdr = HDR(hbp);
+    size_t sz = hhdr -> hb_sz;
+    size_t bit_no;
+    char *p, *plim;
     
-    p = (word *)(hbp->hb_body);
-    word_no = 0;
-    if (sz > MAXOBJSZ) {
+    p = hbp->hb_body;
+    bit_no = 0;
+    if (sz > MAXOBJBYTES) {
        plim = p;
     } else {
-       plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz));
+       plim = hbp->hb_body + HBLKSIZE - sz;
     }
     /* go through all words in block */
        while( p <= plim ) {
-           if( mark_bit_from_hdr(hhdr, word_no)
+           if( mark_bit_from_hdr(hhdr, bit_no)
                && GC_HAS_DEBUG_INFO((ptr_t)p)) {
                ptr_t clobbered = GC_check_annotated_obj((oh *)p);
                
                if (clobbered != 0) GC_add_smashed(clobbered);
            }
-           word_no += sz;
+           bit_no += MARK_BIT_OFFSET(sz);
            p += sz;
        }
 }
@@ -1014,14 +883,12 @@ void GC_print_all_smashed_proc ()
 
 /* This assumes that all accessible objects are marked, and that       */
 /* I hold the allocation lock. Normally called by collector.           */
-void GC_check_heap_proc()
+void GC_check_heap_proc(void)
 {
 #   ifndef SMALL_CONFIG
-#     ifdef ALIGN_DOUBLE
-        GC_STATIC_ASSERT((sizeof(oh) & (2 * sizeof(word) - 1)) == 0);
-#     else
-        GC_STATIC_ASSERT((sizeof(oh) & (sizeof(word) - 1)) == 0);
-#     endif
+      /* Ignore gcc no effect warning on the following.                */
+      GC_STATIC_ASSERT((sizeof(oh) & (GRANULE_BYTES - 1)) == 0);
+      /* FIXME: Should we check for twice that alignment?      */
 #   endif
     GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
 }
@@ -1030,16 +897,10 @@ void GC_check_heap_proc()
 
 struct closure {
     GC_finalization_proc cl_fn;
-    GC_PTR cl_data;
+    void * cl_data;
 };
 
-# ifdef __STDC__
-    void * GC_make_closure(GC_finalization_proc fn, void * data)
-# else
-    GC_PTR GC_make_closure(fn, data)
-    GC_finalization_proc fn;
-    GC_PTR data;
-# endif
+void * GC_make_closure(GC_finalization_proc fn, void * data)
 {
     struct closure * result =
 #   ifdef DBG_HDRS_ALL
@@ -1051,34 +912,25 @@ struct closure {
     
     result -> cl_fn = fn;
     result -> cl_data = data;
-    return((GC_PTR)result);
+    return((void *)result);
 }
 
-# ifdef __STDC__
-    void GC_debug_invoke_finalizer(void * obj, void * data)
-# else
-    void GC_debug_invoke_finalizer(obj, data)
-    char * obj;
-    char * data;
-# endif
+void GC_debug_invoke_finalizer(void * obj, void * data)
 {
     register struct closure * cl = (struct closure *) data;
     
-    (*(cl -> cl_fn))((GC_PTR)((char *)obj + sizeof(oh)), cl -> cl_data);
+    (*(cl -> cl_fn))((void *)((char *)obj + sizeof(oh)), cl -> cl_data);
 } 
 
 /* Set ofn and ocd to reflect the values we got back.  */
-static void store_old (obj, my_old_fn, my_old_cd, ofn, ocd)
-GC_PTR obj;
-GC_finalization_proc my_old_fn;
-struct closure * my_old_cd;
-GC_finalization_proc *ofn;
-GC_PTR *ocd;
+static void store_old (void *obj, GC_finalization_proc my_old_fn,
+                      struct closure *my_old_cd, GC_finalization_proc *ofn,
+                      void **ocd)
 {
     if (0 != my_old_fn) {
       if (my_old_fn != GC_debug_invoke_finalizer) {
-        GC_err_printf1("Debuggable object at 0x%lx had non-debug finalizer.\n",
-                      obj);
+        GC_err_printf("Debuggable object at %p had non-debug finalizer.\n",
+                     obj);
         /* This should probably be fatal. */
       } else {
         if (ofn) *ofn = my_old_cd -> cl_fn;
@@ -1090,26 +942,17 @@ GC_PTR *ocd;
     }
 }
 
-# ifdef __STDC__
-    void GC_debug_register_finalizer(GC_PTR obj, GC_finalization_proc fn,
-                                    GC_PTR cd, GC_finalization_proc *ofn,
-                                    GC_PTR *ocd)
-# else
-    void GC_debug_register_finalizer(obj, fn, cd, ofn, ocd)
-    GC_PTR obj;
-    GC_finalization_proc fn;
-    GC_PTR cd;
-    GC_finalization_proc *ofn;
-    GC_PTR *ocd;
-# endif
+void GC_debug_register_finalizer(void * obj, GC_finalization_proc fn,
+                                void * cd, GC_finalization_proc *ofn,
+                                void * *ocd)
 {
     GC_finalization_proc my_old_fn;
-    GC_PTR my_old_cd;
+    void * my_old_cd;
     ptr_t base = GC_base(obj);
     if (0 == base) return;
     if ((ptr_t)obj - base != sizeof(oh)) {
-        GC_err_printf1(
-           "GC_debug_register_finalizer called with non-base-pointer 0x%lx\n",
+        GC_err_printf(
+           "GC_debug_register_finalizer called with non-base-pointer %p\n",
            obj);
     }
     if (0 == fn) {
@@ -1121,28 +964,19 @@ GC_PTR *ocd;
     store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
 }
 
-# ifdef __STDC__
-    void GC_debug_register_finalizer_no_order
-                                   (GC_PTR obj, GC_finalization_proc fn,
-                                    GC_PTR cd, GC_finalization_proc *ofn,
-                                    GC_PTR *ocd)
-# else
-    void GC_debug_register_finalizer_no_order
-                                   (obj, fn, cd, ofn, ocd)
-    GC_PTR obj;
-    GC_finalization_proc fn;
-    GC_PTR cd;
-    GC_finalization_proc *ofn;
-    GC_PTR *ocd;
-# endif
+void GC_debug_register_finalizer_no_order
+                                   (void * obj, GC_finalization_proc fn,
+                                    void * cd, GC_finalization_proc *ofn,
+                                    void * *ocd)
 {
     GC_finalization_proc my_old_fn;
-    GC_PTR my_old_cd;
+    void * my_old_cd;
     ptr_t base = GC_base(obj);
     if (0 == base) return;
     if ((ptr_t)obj - base != sizeof(oh)) {
-        GC_err_printf1(
-         "GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
+        GC_err_printf(
+         "GC_debug_register_finalizer_no_order called with "
+         "non-base-pointer %p\n",
          obj);
     }
     if (0 == fn) {
@@ -1153,32 +987,47 @@ GC_PTR *ocd;
                                     &my_old_cd);
     }
     store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
- }
+}
 
-# ifdef __STDC__
-    void GC_debug_register_finalizer_ignore_self
-                                   (GC_PTR obj, GC_finalization_proc fn,
-                                    GC_PTR cd, GC_finalization_proc *ofn,
-                                    GC_PTR *ocd)
-# else
-    void GC_debug_register_finalizer_ignore_self
-                                   (obj, fn, cd, ofn, ocd)
-    GC_PTR obj;
-    GC_finalization_proc fn;
-    GC_PTR cd;
-    GC_finalization_proc *ofn;
-    GC_PTR *ocd;
-# endif
+void GC_debug_register_finalizer_unreachable
+                                   (void * obj, GC_finalization_proc fn,
+                                    void * cd, GC_finalization_proc *ofn,
+                                    void * *ocd)
 {
     GC_finalization_proc my_old_fn;
-    GC_PTR my_old_cd;
+    void * my_old_cd;
     ptr_t base = GC_base(obj);
     if (0 == base) return;
     if ((ptr_t)obj - base != sizeof(oh)) {
-        GC_err_printf1(
-           "GC_debug_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
+        GC_err_printf(
+           "GC_debug_register_finalizer_unreachable called with "
+           "non-base-pointer %p\n",
            obj);
     }
+    if (0 == fn) {
+      GC_register_finalizer_unreachable(base, 0, 0, &my_old_fn, &my_old_cd);
+    } else {
+      GC_register_finalizer_unreachable(base, GC_debug_invoke_finalizer,
+                                       GC_make_closure(fn,cd), &my_old_fn,
+                                       &my_old_cd);
+    }
+    store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
+}
+
+void GC_debug_register_finalizer_ignore_self
+                                   (void * obj, GC_finalization_proc fn,
+                                    void * cd, GC_finalization_proc *ofn,
+                                    void * *ocd)
+{
+    GC_finalization_proc my_old_fn;
+    void * my_old_cd;
+    ptr_t base = GC_base(obj);
+    if (0 == base) return;
+    if ((ptr_t)obj - base != sizeof(oh)) {
+        GC_err_printf(
+           "GC_debug_register_finalizer_ignore_self called with "
+           "non-base-pointer %p\n", obj);
+    }
     if (0 == fn) {
       GC_register_finalizer_ignore_self(base, 0, 0, &my_old_fn, &my_old_cd);
     } else {
@@ -1195,15 +1044,12 @@ GC_PTR *ocd;
 # define RA
 #endif
 
-GC_PTR GC_debug_malloc_replacement(lb)
-size_t lb;
+void * GC_debug_malloc_replacement(size_t lb)
 {
     return GC_debug_malloc(lb, RA "unknown", 0);
 }
 
-GC_PTR GC_debug_realloc_replacement(p, lb)
-GC_PTR p;
-size_t lb;
+void * GC_debug_realloc_replacement(void *p, size_t lb)
 {
     return GC_debug_realloc(p, lb, RA "unknown", 0);
 }
index 9778feee97624ea5745e384fe7148259c6a52d27..41178fdce77cfb26fad1560aba3eb461adbd44e8 100644 (file)
@@ -3,7 +3,7 @@
 # Written by Walter Bright\r
 \r
 \r
-DEFINES=-DNDEBUG -DSILENT -DGC_BUILD -D_WINDOWS -DGC_DLL -DALL_INTERIOR_POINTERS -D__STDC__ -DWIN32_THREADS\r
+DEFINES=-DNDEBUG -DGC_BUILD -D_WINDOWS -DGC_DLL -DALL_INTERIOR_POINTERS -D__STDC__ -DWIN32_THREADS\r
 CFLAGS=-Iinclude $(DEFINES) -wx -g\r
 LFLAGS=/ma/implib/co\r
 CC=sc\r
@@ -61,7 +61,7 @@ gctest.exe : gc.lib tests\test.obj
        sc -ogctest.exe tests\test.obj gc.lib\r
 \r
 tests\test.obj : tests\test.c\r
-       $(CC) -c -g -DNDEBUG -DSILENT -DGC_BUILD -D_WINDOWS -DGC_DLL \\r
+       $(CC) -c -g -DNDEBUG -DGC_BUILD -D_WINDOWS -DGC_DLL \\r
        -DALL_INTERIOR_POINTERS -DWIN32_THREADS \\r
        -Iinclude tests\test.c -otests\test.obj\r
 \r
diff --git a/src/mm/boehm-gc/doc/Makefile.am b/src/mm/boehm-gc/doc/Makefile.am
deleted file mode 100644 (file)
index a849aad..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-# 
-# 
-# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-# OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
-# 
-# Permission is hereby granted to use or copy this program
-# for any purpose,  provided the above notices are retained on all copies.
-# Permission to modify the code and to distribute modified code is granted,
-# provided the above notices are retained, and a notice that the code was
-# modified is included with the above copyright notice.
-#
-# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
-
-## Process this file with automake to produce Makefile.in.
-
-# installed documentation
-#
-dist_noinst_DATA = barrett_diagram debugging.html gc.man \
-    gcdescr.html README README.amiga README.arm.cross \
-    README.autoconf README.changes README.contributors \
-    README.cords README.DGUX386 README.dj README.environment \
-    README.ews4800 README.hp README.linux README.Mac \
-    README.MacOSX README.macros README.OS2 README.rs6000 \
-    README.sgi README.solaris2 README.uts README.win32 \
-    tree.html leak.html gcinterface.html scale.html \
-    README.darwin simple_example.html
-
index 7d6659ce3c28aa601f0bfec6c93d0187494e0496..33a6740bcc361f48da5753b617085608b057006f 100644 (file)
@@ -1,7 +1,7 @@
 Copyright (c) 1988, 1989 Hans-J. Boehm, Alan J. Demers
 Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
 Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
-Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
+Copyright (c) 1999-2005 Hewlett-Packard Development Company, L.P.
 
 The file linux_threads.c is also
 Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
@@ -11,7 +11,10 @@ Copyright (c) 2001 by Red Hat Inc. All rights reserved.
 
 Several files supporting GNU-style builds are copyrighted by the Free
 Software Foundation, and carry a different license from that given
-below.
+below.  The files included in the libatomic_ops distribution (included
+here) use either the license below, or a similar MIT-style license,
+or, for some files not actually used by the garbage-collector library, the
+GPL.
 
 THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -28,7 +31,7 @@ are GPL'ed, but with an exception that should cover all uses in the
 collector.  (If you are concerned about such things, I recommend you look
 at the notice in config.guess or ltmain.sh.)
 
-This is version 6.8 of a conservative garbage collector for C and C++.
+This is version 7.0 of a conservative garbage collector for C and C++.
 
 You might find a more recent version of this at
 
@@ -71,7 +74,7 @@ http://www.hpl.hp.com/personal/Hans_Boehm/papers/, among other places.)
   Unlike the collector described in the second reference, this collector
 operates either with the mutator stopped during the entire collection
 (default) or incrementally during allocations.  (The latter is supported
-on only a few machines.)  On the most common platforms, it can be built
+on fewer machines.)  On the most common platforms, it can be built
 with or without thread support.  On a few platforms, it can take advantage
 of a multiprocessor to speed up garbage collection.
 
@@ -117,12 +120,14 @@ from other such accessible objects, or from the registers,
 stack, data, or statically allocated bss segments.  Pointers from
 the stack or registers may point to anywhere inside an object.
 The same is true for heap pointers if the collector is compiled with
- ALL_INTERIOR_POINTERS defined, as is now the default.
+ALL_INTERIOR_POINTERS defined, or GC_all_interior_pointers is otherwise
+set, as is now the default.
 
 Compiling without ALL_INTERIOR_POINTERS may reduce accidental retention
 of garbage objects, by requiring pointers from the heap to to the beginning
 of an object.  But this no longer appears to be a significant
-issue for most programs.
+issue for most programs occupying a small fraction of the possible
+address space.
 
 There are a number of routines which modify the pointer recognition
 algorithm.  GC_register_displacement allows certain interior pointers
@@ -181,25 +186,33 @@ stored on the thread's stack for the duration of their lifetime.
 
 INSTALLATION AND PORTABILITY
 
-  As distributed, the macro SILENT is defined in Makefile.
-In the event of problems, this can be removed to obtain a moderate
-amount of descriptive output for each collection.
+  As distributed, the collector operates silently
+In the event of problems, this can usually be changed by defining the
+GC_PRINT_STATS or GC_PRINT_VERBOSE_STATS environment variables.  This
+will result in a few lines of descriptive output for each collection.
 (The given statistics exhibit a few peculiarities.
 Things don't appear to add up for a variety of reasons, most notably
 fragmentation losses.  These are probably much more significant for the
 contrived program "test.c" than for your application.)
 
-  Note that typing "make test" will automatically build the collector
+  On most Un*x-like platforms, the collector can be built either using a
+GNU autoconf-based build infrastructure (type "configure; make" in the
+simplest case), or with a classic makefile by itself (type
+"cp Makefile.direct Makefile; make").  Here we focus on the latter option.
+On other platforms, typically only the latter option is available, though
+with a different supplied Makefile.)
+
+  Typing "make test" nstead of "make" will automatically build the collector
 and then run setjmp_test and gctest. Setjmp_test will give you information
 about configuring the collector, which is useful primarily if you have
 a machine that's not already supported.  Gctest is a somewhat superficial
 test of collector functionality.  Failure is indicated by a core dump or
 a message to the effect that the collector is broken.  Gctest takes about 
-35 seconds to run on a SPARCstation 2. It may use up to 8 MB of memory.  (The
+a second to two to run on reasonable 2007 vintage desktops.
+It may use up to about 30MB of memory.  (The
 multi-threaded version will use more.  64-bit versions may use more.)
 "Make test" will also, as its last step, attempt to build and test the
-"cord" string library.  This will fail without an ANSI C compiler, but
-the garbage collector itself should still be usable.
+"cord" string library.)
 
   The Makefile will generate a library gc.a which you should link against.
 Typing "make cords" will add the cord library to gc.a.
@@ -220,10 +233,6 @@ machines that use a flat 32-bit or 64-bit address space.
 That includes the vast majority of Workstations and X86 (X >= 3) PCs.
 (The list here was deleted because it was getting too long and constantly
 out of date.)
-  It does NOT run under plain 16-bit DOS or Windows 3.X.  There are however
-various packages (e.g. win32s, djgpp) that allow flat 32-bit address
-applications to run under those systemsif the have at least an 80386 processor,
-and several of those are compatible with the collector.
 
   In a few cases (Amiga, OS/2, Win32, MacOS) a separate makefile
 or equivalent is supplied.  Many of these have separate README.system
@@ -255,77 +264,8 @@ enforce less alignment for pointers.
 or 64 bit addresses will require a major effort.  A port to plain MSDOS
 or win16 is hard.
 
-  For machines not already mentioned, or for nonstandard compilers, the
-following are likely to require change:
-
-1.  The parameters in gcconfig.h.
-      The parameters that will usually require adjustment are
-   STACKBOTTOM,  ALIGNMENT and DATASTART.  Setjmp_test
-   prints its guesses of the first two.
-      DATASTART should be an expression for computing the
-   address of the beginning of the data segment.  This can often be
-   &etext.  But some memory management units require that there be
-   some unmapped space between the text and the data segment.  Thus
-   it may be more complicated.   On UNIX systems, this is rarely
-   documented.  But the adb "$m" command may be helpful.  (Note
-   that DATASTART will usually be a function of &etext.  Thus a
-   single experiment is usually insufficient.)
-     STACKBOTTOM is used to initialize GC_stackbottom, which
-   should be a sufficient approximation to the coldest stack address.
-   On some machines, it is difficult to obtain such a value that is
-   valid across a variety of MMUs, OS releases, etc.  A number of
-   alternatives exist for using the collector in spite of this.  See the
-   discussion in gcconfig.h immediately preceding the various
-   definitions of STACKBOTTOM.
-   
-2.  mach_dep.c.
-      The most important routine here is one to mark from registers.
-    The distributed file includes a generic hack (based on setjmp) that
-    happens to work on many machines, and may work on yours.  Try
-    compiling and running setjmp_t.c to see whether it has a chance of
-    working.  (This is not correct C, so don't blame your compiler if it
-    doesn't work.  Based on limited experience, register window machines
-    are likely to cause trouble.  If your version of setjmp claims that
-    all accessible variables, including registers, have the value they
-    had at the time of the longjmp, it also will not work.  Vanilla 4.2 BSD
-    on Vaxen makes such a claim.  SunOS does not.)
-      If your compiler does not allow in-line assembly code, or if you prefer
-    not to use such a facility, mach_dep.c may be replaced by a .s file
-    (as we did for the MIPS machine and the PC/RT).
-      At this point enough architectures are supported by mach_dep.c
-    that you will rarely need to do more than adjust for assembler
-    syntax.
-
-3.  os_dep.c (and gc_priv.h).
-         Several kinds of operating system dependent routines reside here.
-       Many are optional.  Several are invoked only through corresponding
-       macros in gc_priv.h, which may also be redefined as appropriate.
-      The routine GC_register_data_segments is crucial.  It registers static
-    data areas that must be traversed by the collector. (User calls to
-    GC_add_roots may sometimes be used for similar effect.)
-      Routines to obtain memory from the OS also reside here.
-    Alternatively this can be done entirely by the macro GET_MEM
-    defined in gc_priv.h.  Routines to disable and reenable signals
-    also reside here if they are need by the macros DISABLE_SIGNALS
-    and ENABLE_SIGNALS defined in gc_priv.h.
-      In a multithreaded environment, the macros LOCK and UNLOCK
-    in gc_priv.h will need to be suitably redefined.
-      The incremental collector requires page dirty information, which
-    is acquired through routines defined in os_dep.c.  Unless directed
-    otherwise by gcconfig.h, these are implemented as stubs that simply
-    treat all pages as dirty.  (This of course makes the incremental
-    collector much less useful.)
-
-4.  dyn_load.c
-       This provides a routine that allows the collector to scan data
-       segments associated with dynamic libraries.  Often it is not
-       necessary to provide this routine unless user-written dynamic
-       libraries are used.
-
-  For a different version of UN*X or different machines using the
-Motorola 68000, Vax, SPARC, 80386, NS 32000, PC/RT, or MIPS architecture,
-it should frequently suffice to change definitions in gcconfig.h.
-
+  For machines not already mentioned, or for nonstandard compilers,
+some porting suggestions are provided in the "porting.html" file.
 
 THE C INTERFACE TO THE ALLOCATOR
 
@@ -448,21 +388,10 @@ See gc_cpp.h for the definition of the interface.  This interface
 tries to approximate the Ellis-Detlefs C++ garbage collection
 proposal without compiler changes.
 
-Cautions:
-1. Arrays allocated without new placement syntax are
-allocated as uncollectable objects.  They are traced by the
-collector, but will not be reclaimed.
-
-2. Failure to use "make c++" in combination with (1) will
-result in arrays allocated using the default new operator.
-This is likely to result in disaster without linker warnings.
-
-3. If your compiler supports an overloaded new[] operator,
-then gc_cpp.cc and gc_cpp.h should be suitably modified.
-
-4. Many current C++ compilers have deficiencies that
-break some of the functionality.  See the comments in gc_cpp.h
-for suggested workarounds.
+  Very often it will also be necessary to use gc_allocator.h and the
+allocator declared there to construct STL data structures.  Otherwise
+subobjects of STL data structures wil be allcoated using a system
+allocator, and objects they refer to may be prematurely collected.
 
 USE AS LEAK DETECTOR:
 
@@ -473,19 +402,14 @@ This will cause the collector to invoke the report_leak
 routine defined near the top of reclaim.c whenever an inaccessible
 object is found that has not been explicitly freed.  Such objects will
 also be automatically reclaimed.
-  Productive use of this facility normally involves redefining report_leak
-to do something more intelligent.  This typically requires annotating
-objects with additional information (e.g. creation time stack trace) that
-identifies their origin.  Such code is typically not very portable, and is
-not included here, except on SPARC machines.
-  If all objects are allocated with GC_DEBUG_MALLOC (see next section),
-then the default version of report_leak will report the source file
-and line number at which the leaked object was allocated.  This may
-sometimes be sufficient.  (On SPARC/SUNOS4 machines, it will also report
-a cryptic stack trace.  This can often be turned into a sympolic stack
-trace by invoking program "foo" with "callprocs foo".  Callprocs is
-a short shell script that invokes adb to expand program counter values
-to symbolic addresses.  It was largely supplied by Scott Schwartz.)
+  If all objects are allocated with GC_DEBUG_MALLOC (see next section), then
+the default version of report_leak will report at least the source file and
+line number at which the leaked object was allocated.  This may sometimes be
+sufficient.  (On a few machines, it will also report a cryptic stack trace.
+If this is not symbolic, it can somethimes be called into a sympolic stack
+trace by invoking program "foo" with "callprocs foo".  Callprocs is a short
+shell script that invokes adb to expand program counter values to symbolic
+addresses.  It was largely supplied by Scott Schwartz.)
   Note that the debugging facilities described in the next section can
 sometimes be slightly LESS effective in leak finding mode, since in
 leak finding mode, GC_debug_free actually results in reuse of the object.
@@ -612,10 +536,12 @@ for suggestions on how to fix your compiler.
   This is not a real-time collector.  In the standard configuration,
 percentage of time required for collection should be constant across
 heap sizes.  But collection pauses will increase for larger heaps.
-(On SPARCstation 2s collection times will be on the order of 300 msecs
-per MB of accessible memory that needs to be scanned.  Your mileage
-may vary.)  The incremental/generational collection facility helps,
-but is portable only if "stubborn" allocation is used.
+They will decrease with the number of processors if parallel marking
+is enabled.
+(On 2007 vintage machines, GC times may be on the order of 5 msecs
+per MB of accessible memory that needs to be scanned and processor.
+Your mileage may vary.)  The incremental/generational collection facility
+may help in some cases.
   Please address bug reports to boehm@acm.org.  If you are
 contemplating a major addition, you might also send mail to ask whether
 it's already been done (or whether we tried and discarded it).
index 04f468251a1e5f4b94181f9e6ad085b96e8ff442..ae9c1d5e597f5a62084d4c9f2d38a3f7055ee8b7 100644 (file)
@@ -1,3 +1,8 @@
+The contents of this file are old and pertain to pre-MacOSX versions.
+You probably really wanted README.darwin.
+
+---------------------------------------------
+
 Patrick Beard's Notes for building GC v4.12 with CodeWarrior Pro 2:
 ----------------------------------------------------------------------------
 The current build environment for the collector is CodeWarrior Pro 2.
index 37849303398de6a34e6b24e8b7d5fe9a9f990bff..27bf33eaaa976fc715d8be6fc091b4c7d7241582 100644 (file)
@@ -5,6 +5,9 @@ This has been maintained with varying diligence over the years.
 I made an attempt to include recent contributors here.  I apologize for any
 omissions.
 
+RECENT UPDATES ARE RECORDED IN ../ChangeLog FILE INSTEAD TO CONFORM TO
+MORE COMMON CONVENTIONS.
+
 -------------------------
 
   Version 1.3 and immediately preceding versions contained spurious
@@ -2077,16 +2080,13 @@ Since 6.3alpha5:
    Adrian Bunk for the patches).
  - Integrated NetBSD/OpenBSD patches from Marc Recht and Matthias Drochner.
 
-Since gc6.3alpha6:
+Since 6.3alpha6:
  - Compile test_cpp.cc with CXXCOMPILE instead of COMPILE.
  - Very large allocations could cause a collector hang.  Correct
    calculation of GC_collect_at_heapsize.
  - GC_print_hblkfreelist printed some bogus results if USE_MUNMAP
    was defined.
- - The generic GC_THREADS macro didn't work correctly on Solaris,
-   since the implementation failed to include gc_config_macros.h
-   before deciding whether or not to compile the rest of the file.
- - Threadlibs.c failed to expand the generic GC_THREADS macro.
+ - Include gc_config_macros.h in threadlibs.c.
  - Correct MacOSX thread stop code. (Thanks to Dick Porter.)
  - SMALL_OBJ definition was off by one.  This could cause crashes
    at startup.  (Thanks to Zoltan Varga for narrowing this down to
@@ -2096,12 +2096,12 @@ Since gc6.3alpha6:
  - Changed X86_64 implementation to use SA_SIGINFO in the MPROTECT_VDB
    implementation.  The old approach appears to have been broken by
    recent kernels.
- - Add GC_ATTR_UNUSED to eliminate a warning in gc_allocator.h.  (Thanks
+ - Added GC_ATTR_UNUSED to eliminate a warning in gc_allocator.h (Thanks
    to Andrew Begel.)
  - Fix GC_task_self declaration in os_dep.c.  (Thanks to Andrew Pinski.)
  - Increase INITIAL_BUF_SZ in os_dep.c for Solaris /proc reads.
 
-Since 6.3:
+Since gc6.3:
  - Merge gcconfig.h changes from gcc tree.
  - Unconditionally include gc_priv.h in solaris_pthreads.c, win32_threads.h,
    aix_irix_threads.c, and solaris_threads.c to get thread definitions.
@@ -2139,8 +2139,6 @@ Since 6.3:
    risk change for win32.  (Thanks to Ashley Bone for the crucial
    experimental data behind this, and to Rutger Ovidus for
    some further experiments.)
- - Fixed print_block_list to print the correct kind number for
-   STUBBORN.  (Thanks to Rutger Ovidus.)
  - GC_allochblk_nth incremented GC_words_wasted by bytes rather than
    words.
  - Consider GC_words_wasted in GC_adj_words_allocd only if it is within
@@ -2167,8 +2165,8 @@ Since 6.3:
  - Ignore GC_enable_incremental() requests when KEEP_BACK_PTRS is set.
    The GC itself will dirty lots of pages in this cases, probably making
    it counterproductive on all platforms.  And the DARWIN port crashes.
-
-Since GC6.4:
+Since gc6.4:
  - Integrated Paolo Molaro's patch to deal with EINTR in sem_wait.
  - Make GC_approx_sp() write to dummy location to ensure that stack
    is grown here, when sp looks reasonable, rather than later, when
@@ -2220,8 +2218,8 @@ Since GC6.4:
    in GC_remove_from_fl.
  - Fix stack_size assertion in GC_pthread_create.
  - Fix assertion in GC_steal_mark_stack.
-  
-Since 6.5
+
+Since gc6.5:
  - Fix CPU count detection for Irix and FreeBSD. (Thanks to Dan Bonachea.)
  - Integrate Dan Bonachea's patch for the IBM XLC compiler on Darwin.
  - Integrated Andreas Tobler's FreeBSD/PowerPC patch.
@@ -2260,11 +2258,9 @@ Since 6.6:
  - Remove spurious gc:: qualifier for operator delete[] in gc_cpp.h.
    (Thanks to Hanno Boeck.)
  - Changed a test for LINUX in config_macros.h to one for __linux__.
- - Fix ppc 64 test_and_set code by removing it.  (Thanks to Christian
-   Thalinger.)
  - Add prototypes for GC_finalizer_notifier and GC_thr_init.  (Thanks to
    David Ayers.)
- - Use ld instead of nonexistent ldz instruction in Darwin FindTopOfStack.
+ - Use ld instead of nonexitent ldz instruction in Darwin FindTopOfStack.
    (Thanks to Andreas Tobler.)
  - Add support for Darwin/X86.  (Thanks to Geoff Norton and the Mono
    developers.)
@@ -2277,30 +2273,294 @@ Since 6.6:
    for both stack and heap references.)  Thanks to Andrew McKinlay for the
    critical test case.
  - Integrated Tatsuya Bizenn's NETBSD threads support, with some
-   minimally tested changes.
+   untested changes.
  - Added GC_strdup and friends to make leak detection work correctly
    for strdup clients.  (Thanks to Jon Moore.)  Fixed the existing strdup
    with malloc redirection to handle a null malloc return correctly.
- - Fix Makefile.am, so it handles exe extensions under Cygwin correctly
-   for gctest.
 
-Since 6.7:
+Since gc6.7:
  - Added some support for Dragonfly BSD.  (Thanks to Joerg Sonnenberger and
    Thomas Klausner.)
- - Improvements to the HP/UX section of configure.in.
-   (Thanks to Andreas Tobler.)
+ - Improvements to the HP/UX section of configure.in/configure.ac.
+   (Thanks to Andreas Tobler)
  - GC_unix_get_mem could neglect to release the malloc lock on Irix, under
    extremely unlikely circumstances.  Thanks to Jean-Baptiste Nivois for
    some careful code reading.
  - Added support for kFreeBSD + glibc (Thanks to Petr Salinger)
  - Fix more MacOS threads memory leaks (Thanks to Allan Hsu)
  - Added initial Solaris/X86-64 support (Thanks to Rainer Orth)
- - Applied a long-lost MINGW patch from Gerard Allan for malloc redirection
-   with threads.  This one probably makes no sense for 7.0, and was not applied
-   there.
- - The Solaris/SPARC definition of GC_INIT() in gc.h wasn't C++-compilable.
 
+Since gc6.8:
+ - Fix typo in PREFETCH implementation for X86_64.  (Thanks to Peter Wang.)
+ - Fix M68K LINUX port. (Thanks to Debian packagers.)
+ - __GNUC__ was misspelled as __GNUC in new_gc_alloc.h. (Thanks to Peter Wang.)
+ - Integrated Allan Hsu's patch for OS X VM deallocation problems.
+ - Applied FreeBSD/X86_64 patch.
+
+Since gc6.9:
+ - Remove GC_PROTO, VOLATILE, GC_PTR, and GC_CONST.  Assume ANSI C compiler
+   and use ANSI constructs unconditionally.
+ - Introduce #elif and #error in some of the appropriate places.
+ - Remove GC_printf cruft. Use stdargs.
+ - Remove separate Solaris threads support.  Use the more generic Posix
+   implementation.
+ - Use atomic_ops for atomic operations and memory barriers.
+ - Clean up MPROTECT_VDB implementation.  Use SA_SIGINFO wherever
+   possible.
+ - Remove broken SIGNALS stuff.
+ - Use size_t instead of word, where appropriate.
+ - Add .S.o rule to Makefile.am.
+ - Officially unsupport SunOS4, several old flavors of M68K (SunOS4,
+   A/UX, HP), IBM PC/RTs and RISCOS/Irix4.  (I doubt the old code worked.
+   If anyone cares, these should be easy to resurrect.)
+ - Add EXPECT() in some critical places.
+ - Redefined hb_sz and hb_body to deal with bytes rather than words.
+   This affected a great deal of code.  I would like to consistently use
+   byte offsets and sizes where there's not a convincing reason to do
+   otherwise.
+ - Redefined several other variables (GC_mem_found, GC_words_allocd)
+   etc. to use units of bytes.  Most of these were also renamed to
+   reflect that fact.
+ - Killed as many "register" declarations as possible.
+ - Partially replaced stubborn allocation with manual write barrier.
+   It's currently broken.
+ - Restructured mark code, to allow mark bits to be kept either on
+   a per allocation granule or per object basis.  The emphasis is
+   now on the -DUSE_MARK_BYTES option, since individual bits perform
+   quite badly on hyperthreaded P4s, and are probably suboptimal on
+   other architectures.  -DUSE_MARK_BITS is currently broken, and may
+   be resurrected only for the single-threaded case.  This significantly
+   reduced the cache footprint required by auxiliary GC data structures.
+   It also reduces space overhead for small heaps.  It probably slows
+   things down slightly if interior pointers are very common.
+ - As part of the above, we now maintain an approximate count of set
+   mark bits in each heap block.
+ - As part of the above, the semantics of hb_map changed drastically.
+   For MARK_BIT_PER_OBJ, it doesn't exist.  For MARK_BIT_PER_GRANULE,
+   it is purely a way to replace a mod instruction with a table lookup.
+   (Somewhat to my surprise, this still wins on modern hardware.)
+ - Removed PRINTSTATS, GATHERSTATS, and SILENT macros.  Everything is
+   now controlled by GC_print_stats variable and GC_PRINT_STATS
+   and new GC_PRINT_VERBOSE_STATS environment variables.
+ - Add GC_log_printf and use it consistently for logging output.
+ - Unconditionally count the objects we reclaim in the sweep phase.
+   For thread local allocation, we need that anyway, and we expect
+   that's increasingly the only case that matters.  And it simplifies
+   the code.  In general expect minor performance hacks that benefit
+   only the single-threaded case to disappear.
+ - Remove GC_quiet from gc.h and elsewhere.
+ - Changed the heap expansion heuristic, and the definition of
+   GC_free_space_divisor, to refer to live data size, instead of total
+   heap size.  I believe this is much more robust.  It wasn't previously
+   possible, because we didn't have access to live data size.
+ - Thread local allocation added the extra byte in twice: Once in
+   thread_local_alloc, and once in malloc_many.
+ - Removed GC_malloc_words_small and GC_gcj_fast_malloc.  A new
+   mechanism based on the thread local allocation data structures
+   is expected to be added instead.  This should allow inlined code
+   that is both fast and doesn't rely on collector internals.
+ - Changed both free lists and reclaim lists to be indexed by granules
+   instead of words, norming halving their size.
+ - MERGE_SIZE is now the only option, and the macro was removed.
+   (Without it, we need a memory reference to GC_all_interior_pointers
+   anyway.  Thus it costs us nothing.)
+ - Change GC_size_map to map to granules instead of words.  Make sure
+   that every possible size up to TINY_FREELISTS is present.
+ - Split of macros need for fast inline allocation into gc_tiny_fl.h
+   in anticipation of a new inline allocator that doesn't rely on GC
+   internals.
+ - Changed thread local allocation to use GRANULE_BYTES and TINY_FREELISTS
+   in anticipation of a merge with the inline allocation code.
+ - Removed ALIGN_DOUBLE.  This is mostly handled by GRANULE_BYTES.
+ - Make locking on most platforms conditional on GC_need_to_lock.
+
+Since gc7.0alpha1:
+ - GC_bytes_allocd was incremented by a possibly uninitialized variable
+   in GC_generic_malloc_inner.  (Bug introduced in gc7.0alpha1.  Thanks
+   to Ben Hutchings for tracking it down.)
+ - Win32 fixes.  (Thanks to Ben Hutchings and Maurizio Vairani.)
+ - Integrated Ben Hutchings' GetWriteWatch-based virtual dirty bit
+   implementation for win32.
+ - Removed pc_gc.tar and floppy targets in Makefile.direct.  Removed
+   pc_excludes file.
+ - No longer include GC_bytes_wasted when evaluating allocation progress.
+   Since we are now counting live memory, it no longer makes sense.
+ - Applied Davide Angelocola's configury patch.  There are now separate
+   Makefile.am's in the cord and tests subdirectory, more tests, etc.
+ - Renamed configure.in to configure.ac.
+ - Merged a very small number of Nathanael Nerode's configure.ac
+   cleanups from the gcc tree.  Unfortunately, that file is a bit
+   different from ours.
+ - Changed EINTR handling in sem_wait slightly.
+ - Restructure the root marking code.  Remove all traces of
+   USE_GENERIC_PUSH_REGS, and effectively make it the default.
+   Make it easier to pass a context pointer to the mark routine, in
+   case we ever want to do precise stack marking.
+ - Replace GC_start_blocking() and GC_end_blocking() with GC_do_blocking().
+   This remains undocumented, and only implemented for pthreads.  But it
+   removes an otherwise unavoidable race with stores of callee-save
+   registers.
+ - Fix GC_n_mark_bits for the default MARK_BIT_PER_GRANULE case.  This
+   resulted in bogus complaints in heap dumps.
+ - Upgrade to libatomic_ops-1.0, and update build structure to match.
+ - Remove SRC_M3 support. Clean up lock initialization code in misc.c.
+ - Removed gc_local_alloc.h.  If THREAD_LOCAL_ALLOC is defined, the
+   thread local allocation routines are now called automatically.
+ - Renamed gc_inl.h back to gc_inline.h.  Changed the interface appreciably
+   since locking has turned into a dominant issue, and in-line allocation
+   only makes sense if it's no worse than thread-local allocation.
+   Gc_inline.h is now also used to implement thread-local allocation.
+ - Finished replacing stubborn allocation with manual write barrier.
+   Untested.
+ - Use thread-local allocation code by default.
+ - Added GC_register_my_thread and friends for Posix and win32.
+ - Patch for GWW_VDB from Ben Hutchings.
+ - Removed explicit THREAD_LOCAL_ALLOC tests, since that now always
+   redefines GC_malloc.
+ - Removed now unused AIX memory allocation code.
+ - Various minor fixes for bugs introduced in 7.0alpha1.
+
+Since gc7.0alpha2
+ - Added support for dlopen-based interception of pthread functions.
+   This is only half done.  The gc.h redefinitions currently interfere.
+ - Integrated major automake overhaul from Petter Urkedal.
+
+Since gc7.0alpha3
+   (various 6.5, 6.6 changes)
+ - Removed GC_brief_async_signal_safe_sleep and used atomic_ops instead.
+   (Thanks to Ben Maurer.)
+ - Integrated build patches from David Angelocola and Petter Urkedal.
+ - Fix dynamic-linker-based pthread call redirection.
+ - Renamed RS6000 to POWERPC/AIX.
+ - Allow recovery from SIGSEGV in marker on Linux.  This works around
+   a race in thread stack marking if /proc is used to find roots.  We do
+   that by default with malloc redirection and threads.  This involved
+   moving some GC_find_limit and SETJMP related declarations to gc_priv.h.
+ - Added doc/porting.html file.
+ - Added ADD_HEAP_GUARD_PAGES for sbrk/*nix platforms to debug extreme
+   memory overwrite errors.
+ - Added trivial NO_INCREMENTAL flag to facilitate debugging.
+ - Added GC_getattr_np-based GC_get_stack_base (untested).
+ - Separated thread local allocation into a separate file and added the
+   beginning of win32 support for that.
+
+Since gc7.0alpha4
+   (more 6.6, 6.7 changes)
+ - Some Solaris fixes, including some more general changes in how
+   the assembly pieces of mach_dep.c are handled.
+ - Removed a lot of SOLARIS_THREADS-specific code that was only
+   needed with the old implementation.  This included many (mostly no-op)
+   versions of GC_is_fresh.
+ - Don't use atomic_ops in gc_locks.h unless we need threads.
+ - Fixed USE_MARK_BITS, which is once againthe default without PARALLEL_MARK.
+ - Removed Solaris GC_INIT hack.  It's a workaround for a long dead bug,
+   and it seemed to be wrong anyway.
+ - Changed win32_threads.c to require preprocessor-based interception
+   of thread routines by default.  A client call to GC_use_DllMain is
+   now required to get the old behavior in which DllMain is used to implicitly
+   register threads.  This was doen for uniformity with other platforms, and
+   because the DllMain solution seemed to require very tricky code which,
+   at least in the past, imposed hard bounds onthe number of threads.
+ - Many small changes to make thread support work again on Cygwin.
+ - Moved definition of allocator lock etc. to pthread_support.c and
+   win32_threads.c for those two cases.
+ - Got rid of the FASTLOCK() machinery.  It doesn't seem useful on modern
+   platforms.
+ - Cleaned up the uncollectable allocation routines, speeding up the
+   slower paths.  The code did enough unnecessary work off the critical path
+   that the underlying logic was getting hard to extract.
+ - No longer turn off THREAD_LOCAL_ALLOC with DBG_HDRS_ALL.  Indications
+   are it just works, and I think the reasons for it not working disappeared
+   a while ago.
+ - Fixed bugs in hb_n_marks calculation and assertion.
+ - Don't use __builtin_expect for pre-3.0 gcc.
+ - Define GWW_VDB only for recent Microsoft tool chains.
+ - Add overview.html to doc directory.
+ - Fix NT_STATIC_THREADS_MAKEFILE, various compiler warnings.
+ - Made thread local allocation sort of work with Cygwin.  The code should
+   be there to deal with other Windows variants, But non-Cygwin Windows
+   threads need more bug fixes.
+
+Since gc7.0alpha5
+   (more 6.7 changes)
+ - Declare GC_dump() in gc.h.
+ - Add --enable-large-config, which just defines the LARGE_CONFIG macro.
+ - Make GlobalAlloc address alignment a bit more intuitive.  (Thanks to
+   Charles Mills.)
+ - Use #elif in the definitions of GET_MEM.
+ - Overhaul porting.html.  Remove corresponding text from README.
+ - Fix typo in DARWIN section of gcconfig.h.
+ - Fix Darwin thread memory leak.  (Thanks to Bruce Mitchener.)
+ - Update x86 AO_test_and_set implementation to use "=q".
+ - Add $(EXEEXT) to many tests in tests/tests.am.  (Corresponds to a
+   6.7 fix, which no longer applied.)
+ - Fix Darwin/PPC port.
+ - Fix Cygwin/threads port.
+ - Fix gcj malloc support.
+ - For GNU-style make, don't build libatomic_ops unless threads are requested.
+   This should allow single-threaded builds on platforms which do not
+   currently support libatomic_ops.
+ - Clean up and hopefully fix the CFLAGS calculation for GNU build.
+   (Substantially improves things on HP/UX.)
+ - Integrated Andrei Polushin's Visual C++ patches.  These provide for
+   stack traces, better C++ debug support, and better log file handling.
+   Note that these change the location of the log file to a the path of the
+   executable with a .log extension.  To get the old behavior back, define
+   OLD_WIN32_LOG_FILE.  For the time being, I'm checking his project
+   files and the like into a windows-untested subdirectory.  They
+   are almost certainly already out of date, but better than what we had
+   before.
+ - Fixed some win32 threads bugs, and added support for _beginthreadex.
+ - Fix zero size thread local allocation so that explicit deallocation
+   works correctly.
+ - Removed serious bug in GC_malloc_uncollectable(large size).
+ - Do not try to do thread-local gcj allocation in incremental mode.  There
+   are races in setting up the descriptor.
+ - Add GC_INIT() to middle.c, fix some more GC_printfn calls.
+ - Some assertions erroneously used I_HOLD_LOCK() negatively, eventhough
+   it can now spuriously return TRUE.
+ - Rename SUNOS5 macro and OS name to SOLARIS and SUNOS5DL to SOLARISDL.
+ - On Linux and some Un*x variants, allocate memory by first trying sbrk,
+   and then switching to mmap if that fails.
+ - Fixed /proc/x/maps reading to deal with asynchronous deletions.
+ - Fix REDIRECT_MALLOC with threads on Linux.  It now usually seems to work
+   with ugly hacks that include having calloc behave differently when it is
+   called from ld.so or the pthreads library.  A reasonable amount of
+   infrastructure was added to support some of this.  Thanks to Roland McGrath
+   for ideas and information.
+ - Import various updated build scripts.
+ - Add GC_register_has_static_roots_callback.  (Thanks to Andrew Haley.)
+ - Fix serious bugs in GC_malloc_atomic_uncollectable().
+ - Return GC_SUCCESS form GC_get_stack_base().
+ - Fix several atomic_ops problems on IA64 with HP Compiler.
+ - Update to atomic_ops-1.2.
+ - Fix hb_n_marks description and reclaim.c assertion.
+ - Various additional win32 threads fixes.
+ - Enable GC_ASSERTIONS for Debug build with NT_THREADS_MAKEFILE.
+
+[gc7.0alpha7 was released and version bumped to gc7.0alpha8]
+
+Since first gc7.0alpha8 version:
+ [ Some gc6.9 changes ]
+ - Change FindTopOfStack decl in darwin_stop_world.c.
+ - Move some static tests from misc.c to gcconfig.h.  Use #error.
+ - Add GC_print_free_list() function.  (Thanks to Bruce Hoult.)
+ - Add GC_GNU_THREADS support on HURD. (Thanks to Aleksey Demakov,
+   Barry DeFreese, and possibly other Debian maintainers.)
+ - __GNUC__ was misspelled as __GNUC in thread_local_alloc.h.
+   (Thanks to Peter Wang.)
+ - Integrated various MacOSX patches and tried to reconcile them.
+   Thanks to Allan Hsu, several contributers at Apple, and probably
+   others.
+ - Added some casts to powerpc.h in libatomic_ops to silence warnings.
+
+FOR FURTHER UPDATES SEE ../ChangeLog FILE.
+  
 To do:
+ - REDIRECT_MALLOC and threads combination should work on more platforms,
+   and needs more testing on Linux.
+ - Clone marker inner loop to support arch-dependent prefetching,
+   and counting of objects marked for finalization.
  - The USE_MUNMAP code should really use a separate data structure
    indexed by physical page to keep track of time since last use of
    a page.  Using hblk headers means we lose track of ages when
@@ -2331,3 +2591,4 @@ To do:
    it looks like the whole object is treated as dirty if any part of it
    is.
  
+FOR FURTHER UPDATES SEE ../ChangeLog FILE.
index 70954971fc05abc9f234ca1af16bc344609516b6..b413ff3385305aaec203d19f1344d74dbd733daa 100644 (file)
@@ -1,16 +1,3 @@
-6.5 update:
-I disabled incremental GC on Darwin in this version, since I couldn't
-get gctest to pass when the GC was built as a dynamic library.  Building
-with -DMPROTECT_VDB (and threads) on the command line should get you
-back to the old state.                 - HB
-
-./configure --enable-cplusplus results in a "make check" failure, probably
-because the ::delete override ends up in a separate dl, and Darwin dynamic
-loader semantics appear to be such that this is not really visible to the
-main program, unlike on ELF systems.  Someone who understands dynamic
-loading needs to lookat this.  For now, gc_cpp.o needs to be linked
-statically, if needed.                 - HB
-
 Darwin/MacOSX Support - December 16, 2003
 =========================================
 
@@ -95,6 +82,20 @@ Darwin/OS X port.
 -Brian Alliet
 brian@brianweb.net
 
+gc_cpp.h usage
+==============
+
+Replacement of operator new and delete is apparently not supported with
+dynamic libraries.  This means that applications using gc_cpp.h
+(including the built-in test) will probably not work correctly with
+the collector in a dynamic library, unless special care is taken.
+
+See
+http://article.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/1421
+for some details.
+
+- Hans Boehm (based on information from Andrew Begel)
+
 
 Older Information (Most of this no longer applies to the current code)
 ======================================================================
index 686e948250b6332c89b452ee703d86e19b5d50f2..d50d37094c79ceedeb62db891375607d5fd4cc0f 100644 (file)
@@ -15,11 +15,11 @@ GC_LOOP_ON_ABORT - Causes the collector abort routine to enter a tight loop.
                   result in an infinite loop in a handler, allowing
                   similar debugging techniques.
 
-GC_PRINT_STATS - Turn on as much logging as is easily feasible without
-                adding signifcant runtime overhead.  Doesn't work if
-                the collector is built with SMALL_CONFIG.  Overridden
-                by setting GC_quiet.  On by default if the collector
-                was built without -DSILENT.
+GC_PRINT_STATS - Turn on GC logging.  Not functional with -DSMALL_CONFIG.
+
+GC_LOG_FILE - The name of the log file.  Stderr by default.
+
+GC_PRINT_VERBOSE_STATS - Turn on even more logging.
 
 GC_DUMP_REGULARLY - Generate a GC debugging dump GC_dump() on startup
                    and during every collection.  Very verbose.  Useful
@@ -47,7 +47,7 @@ GC_NPROCS=<n> - Linux w/threads only.  Explicitly sets the number of processors
                first spinning.
 
 GC_MARKERS=<n> - Linux w/threads and parallel marker only.  Set the number
-               of marker threads.  This is normaly set to the number of
+               of marker threads.  This is normally set to the number of
                processors.  It is safer to adjust GC_MARKERS than GC_NPROCS,
                since GC_MARKERS has no impact on the lock implementation.
 
@@ -94,29 +94,6 @@ GC_RETRY_SIGNALS, GC_NO_RETRY_SIGNALS - Try to compensate for lost
                     was turned into a runtime flag to enable last-minute
                     work-arounds.
 
-GC_IGNORE_FB[=<n>] -  (Win32 only.) Try to avoid treating a mapped
-               frame buffer as part of the root set.  Certain (higher end?)
-               graphics cards seems to result in the graphics memory mapped
-               into the user address space as writable memory.
-               Unfortunately, there seems to be no systematic way to
-               identify such memory.  Setting the environment variable to n
-               causes the collector to ignore mappings longer than n MB.
-               The default value of n is currently 15.  (This should cover
-               a 16 MB graphics card, since the mapping appears to be slightly
-               shorter than all of graphics memory.  It will fail if a dll
-               writes pointers to collectable objects into a data segment
-               whose length is >= 15MB.  Empirically that's rare, but
-               certainly possible.)  WARNING: Security sensitive applications
-               should probably disable this feature by setting
-               GC_disallow_ignore_fb, or by building with -DNO_GETENV,
-               since small values could force collection of reachable
-               objects, which is conceivably a (difficult to exploit)
-               security hole.  GC_IGNORE_FB values less than 3 MB
-               are never honored, eliminating this risk for most,
-               but not all, applications.  This feature is likely to disappear
-               if/when we find a less disgusting "solution".
-               IN VERSION 6.4 AND LATER, THIS SHOULD BE UNNECESSARY.
-
 The following turn on runtime flags that are also program settable.  Checked
 only during initialization.  We expect that they will usually be set through
 other means, but this may help with debugging and testing:
@@ -149,3 +126,10 @@ GC_ALL_INTERIOR_POINTERS - Turns on GC_all_interior_pointers and thus interior
                           pointer recognition.
 
 GC_DONT_GC - Turns off garbage collection.  Use cautiously.
+
+GC_TRACE=addr - Intended for collector debugging.  Requires that the collector
+               have been built with ENABLE_TRACE defined.  Causes the debugger
+               to log information about the tracing of address ranges containing
+               addr.  Typically addr is the address that contains a pointer to
+               an object that mysteriously failed to get marked.  Addr must be
+               specified as a hexadecimal integer.
index ec4e7e641a067bfa6e46a6b2475ddf4fff57060c..3c501814872bc1668a0d4a4d7770596a57d3ca91 100644 (file)
@@ -26,8 +26,8 @@ To use threads, you need to abide by the following requirements:
    pthread implementations (in particular it will *not* work with
    MIT pthreads).
 
-2) You must compile the collector with -DGC_LINUX_THREADS and -D_REENTRANT
-   specified in the Makefile.
+2) You must compile the collector with -DGC_LINUX_THREADS (or
+   just -DGC_THREADS) and -D_REENTRANT specified in the Makefile.
 
 3a) Every file that makes thread calls should define GC_LINUX_THREADS and 
    _REENTRANT and then include gc.h.  Gc.h redefines some of the
@@ -55,17 +55,16 @@ To use threads, you need to abide by the following requirements:
    conditions, this may cause unexpected heap growth.
 
 5) The combination of GC_LINUX_THREADS, REDIRECT_MALLOC, and incremental
-   collection fails in seemingly random places.  This hasn't been tracked
-   down yet, but is perhaps not completely astonishing.  The thread package
-   uses malloc, and thus can presumably get SIGSEGVs while inside the
-   package.  There is no real guarantee that signals are handled properly
-   at that point.
+   collection is probably not fully reliable, though it now seems to work
+   in simple cases.
 
 6) Thread local storage may not be viewed as part of the root set by the
    collector.  This probably depends on the linuxthreads version.  For the
    time being, any collectable memory referenced by thread local storage should
    also be referenced from elsewhere, or be allocated as uncollectable.
-   (This is really a bug that should be fixed somehow.)
+   (This is really a bug that should be fixed somehow.  The current GC
+   version probably gets things right if there are not too many tls locations
+   and if dlopen is not used.)
 
 
 M68K LINUX:
index df0ef2cda933f68b5f2b37552a000182d38b1a5d..6a9a1fdcb372f092179f5cf139f2fff200415acc 100644 (file)
@@ -19,12 +19,6 @@ relatively easy to adapt to new compilers with a different set of predefined
 macros.  Currently these macros generally identify platforms instead of
 features.  In many cases, this is a mistake.
 
-3) The code currently avoids #elif, eventhough that would make it more
-readable.  This was done since #elif would need to be understood by ALL
-compilers used to build the collector, and that hasn't always been the case.
-It makes sense to reconsider this decision at some point, since #elif has been
-standardized at least since 1989.
-
 Many of the tested configuration macros are at least somewhat defined in
 either include/private/gcconfig.h or in Makefile.direct.  Here is an attempt
 at defining some of the remainder:  (Thanks to Walter Bright for suggesting
@@ -79,12 +73,6 @@ SUNOS5SIGS   Solaris-like signal handling.  This is probably misnamed,
 PCR            Set if the collector is being built as part of the Xerox
                Portable Common Runtime.
 
-SRC_M3         Set if the collector is being built as a replacement of the
-               one in the DEC/Compaq SRC Modula-3 runtime.  I suspect this
-               was last used around 1994, and no doubt broke a long time ago.
-               It's there primarily incase someone wants to port to a similar
-               system.
-
 USE_COMPILER_TLS  Assume the existence of __thread-style thread-local
                storage.  Set automatically for thread-local allocation with
                the HP/UX vendor compiler.  Usable with gcc on sufficiently
index 31e7500382dd6984fea151583664902d20abcf52..73620342f397fac556c6e33f26dccd7f8232cb6e 100644 (file)
@@ -21,7 +21,9 @@ You may want to reverse this decisions if you use -DREDIRECT_MALLOC=...
 SOLARIS THREADS:
 
 The collector must be compiled with -DGC_SOLARIS_THREADS (thr_ functions)
-or -DGC_SOLARIS_PTHREADS (pthread_ functions) to be thread safe.
+or -DGC_THREADS to be thread safe.  This assumes use of the pthread_
+interface.  Old style Solaris threads are no longer supported.
+
 It is also essential that gc.h be included in files that call thr_create,
 thr_join, thr_suspend, thr_continue, or dlopen.  Gc.h macro defines
 these to also do GC bookkeeping, etc.  Gc.h must be included with
@@ -30,20 +32,15 @@ these replacements are not visible.
 A collector built in this way way only be used by programs that are
 linked with the threads library.
 
-In this mode, the collector contains various workarounds for older Solaris
-bugs.  Mostly, these should not be noticeable unless you look at system
-call traces.  However, it cannot protect a guard page at the end of
-a thread stack.  If you know that you will only be running Solaris2.5
-or later, it should be possible to fix this by compiling the collector
-with -DSOLARIS23_MPROTECT_BUG_FIXED.
-
 Since 5.0 alpha5, dlopen disables collection temporarily,
 unless USE_PROC_FOR_LIBRARIES is defined.  In some unlikely cases, this
 can result in unpleasant heap growth.  But it seems better than the
 race/deadlock issues we had before.
 
 If solaris_threads are used on an X86 processor with malloc redirected to
-GC_malloc a deadlock is likely to result.
+GC_malloc, it is necessary to call GC_thr_init explicitly before forking the
+first thread.  (This avoids a deadlock arising from calling GC_thr_init
+with the allocation lock held.)
 
 It appears that there is a problem in using gc_cpp.h in conjunction with
 Solaris threads and Sun's C++ runtime.  Apparently the overloaded new operator
@@ -55,6 +52,13 @@ have it invoke the garbage-collector's allocators only after main has started.
 (Note that the latter requires a moderately expensive test in operator
 delete.)
 
+I encountered "symbol <unknown>: offet .... is non-aligned" errors.  These
+appear to be traceable to the use of the GNU assembler with the Sun linker.
+The former appears to generate a relocation not understood by the latter.
+The fix appears to be to use a consistent tool chain.  (As a non-Solaris-expert
+my solution involved hacking the libtool script, but I'm sure you can
+do something less ugly.)
+
 Hans-J. Boehm
 (The above contains my personal opinions, which are probably not shared
 by anyone else.)
index 6f57db117647407369b0059a8a91dc12c4454821..1dce2b9e78fdde024f1376274344b1fd2c369738 100644 (file)
@@ -6,8 +6,8 @@ broken in the meantime.  Patches are appreciated.
 
 For historical reasons,
 the collector test program "gctest" is linked as a GUI application,
-but does not open any windows.  Its output appears in the file
-"gc.log".  It may be started from the file manager.  The hour glass
+but does not open any windows.  Its output normally appears in the file
+"gctest.exe.log".  It may be started from the file manager.  The hour glass
 cursor may appear as long as it's running.  If it is started from the
 command line, it will usually run in the background.  Wait a few
 minutes (a few seconds on a modern machine) before you check the output.
@@ -37,6 +37,8 @@ This is currently incompatible with -DUSE_MUNMAP.  (Thanks to Jonathan
 Clark for tracking this down.  There's some chance this may be fixed
 in 6.1alpha4, since we now separate heap sections with an unused page.)
 
+[Threads and incremental collection are discussed near the end, below.]
+
 Microsoft Tools
 ---------------
 For Microsoft development tools, rename NT_MAKEFILE as
@@ -66,6 +68,19 @@ absence of thread support).
 
 GNU Tools
 ---------
+The collector should be buildable under Cygwin with either the old standard
+Makefile, or possibly with the "configure --diable-shared;make" machinery.
+(For the latter use --enable-threads=posix for thread support.) The major issue
+here seems to be that dynamic library support is not currently enabled for
+Cygwin.  (This is probably fixable without a great deal of difficulty by
+reusing the standard WIN32 code.  But it requires some tweaking.)  As a result
+of this, "configure; make; make check" currently does not completely succeed,
+though the static library appears to be OK when used only from the main
+programs, and correspondingly the Makefile.direct self tests succeed.
+
+Mingw32 builds are not regularly tested, and may or may not work.
+The following paragraph is probably obsolete:
+
 For GNU-win32, use the regular makefile, possibly after uncommenting
 the line "include Makefile.DLLs".  The latter should be necessary only
 if you want to package the collector as a DLL.
@@ -74,9 +89,6 @@ believed to work only for b18, not b19, probably due to linker changes
 in b19.  This is probably fixable with a different definition of
 DATASTART and DATAEND in gcconfig.h.
 
-The collector should also be buildable under Cygwin with either the
-old standard Makefile, or with the "configure;make" machinery.
-
 Borland Tools
 -------------
 [Rarely tested.]
@@ -95,15 +107,54 @@ version, change the line near the top.  By default, it does not
 require the assembler.  If you do have the assembler, I recommend
 removing the -DUSE_GENERIC.
 
+
+Watcom compiler
+---------------
+
+Ivan V. Demakov's README for the Watcom port:
+
+The collector has been compiled with Watcom C 10.6 and 11.0.
+It runs under win32, win32s, and even under msdos with dos4gw
+dos-extender. It should also run under OS/2, though this isn't
+tested. Under win32 the collector can be built either as dll
+or as static library.
+
+Note that all compilations were done under Windows 95 or NT.
+For unknown reason compiling under Windows 3.11 for NT (one
+attempt has been made) leads to broken executables.
+
+Incremental collection is not supported.
+
+cord is not ported.
+
+Before compiling you may need to edit WCC_MAKEFILE to set target
+platform, library type (dynamic or static), calling conventions, and
+optimization options.
+
+To compile the collector and testing programs use the command:
+    wmake -f WCC_MAKEFILE
+
+All programs using gc should be compiled with 4-byte alignment.
+For further explanations on this see comments about Borland.
+
+If the gc is compiled as dll, the macro ``GC_DLL'' should be defined before
+including "gc.h" (for example, with -DGC_DLL compiler option). It's
+important, otherwise resulting programs will not run.
+
+Ivan Demakov (email: ivan@tgrad.nsk.su)
+
 Incremental Collection
 ----------------------
-There is some support for incremental collection.  This is
-currently pretty simple-minded.  Pages are protected.  Protection
-faults are caught by a handler installed at the bottom of the handler
-stack.  This is both slow and interacts poorly with a debugger.
-Whenever possible, I recommend adding a call to
+There is some support for incremental collection.  By default, the
+collector chooses between explicit page protection, anf GetWriteWatch-based
+write tracking automatically, depending on the platform.
+
+The former is slow and interacts poorly with a debugger.
+Pages are protected.  Protection faults are caught by a handler
+installed at the bottom of the handler
+stack.  Whenever possible, I recommend adding a call to
 GC_enable_incremental at the last possible moment, after most
-debugging is complete.  Unlike the UNIX versions, no system
+debugging is complete.  No system
 calls are wrapped by the collector itself.  It may be necessary
 to wrap ReadFile calls that use a buffer in the heap, so that the
 call does not encounter a protection fault while it's running.
@@ -115,12 +166,18 @@ Note that incremental collection is disabled with -DSMALL_CONFIG.
 Threads
 -------
 
-James Clark has contributed the necessary code to support win32 threads
-with the collector in a DLL.
+This version of the collector by default handles threads similarly
+to other platforms.  James Clark's code which tracks threads attached
+to the collector DLL still exists, but requires that both
+- the collector is built in a DLL with GC_DLL defined, and
+- GC_use_DllMain() is called before GC initialization, which
+  in turn must happen before creating additional threads.
+We generally recommend avoiding this if possible, since it seems to
+be less than 100% reliable.
+
 Use NT_THREADS_MAKEFILE (a.k.a gc.mak) instead of NT_MAKEFILE
-to build this version.  Note that this requires some files whose names
-are more than 8 + 3 characters long.  Thus you should unpack the tar file
-so that long file names are preserved.  To build the garbage collector
+to build a version that supports both kinds of thread tracking.
+To build the garbage collector
 test with VC++ from the command line, use
 
 nmake /F ".\gc.mak" CFG="gctest - Win32 Release"
@@ -128,8 +185,6 @@ nmake /F ".\gc.mak" CFG="gctest - Win32 Release"
 This requires that the subdirectory gctest\Release exist.
 The test program and DLL will reside in the Release directory.
 
-This version relies on the collector residing in a dll.
-
 This version currently supports incremental collection only if it is
 enabled before any additional threads are created.
 
@@ -138,78 +193,29 @@ with Microsoft tools (use NT_STATIC_THREADS_MAKEFILE) and with the GNU
 tools.  In all cases,the collector must be built with GC_WIN32_THREADS
 defined, even if the Cygwin pthreads interface is used.
 (NT_STATIC_THREADS_MAKEFILE does this implicitly.  Under Cygwin,
-./configure --enable-threads=posix defines GC_WIN32_THREADS.)  Threads must be
-created with GC_CreateThread.  This can be accomplished by
-including gc.h and then calling CreateThread, which is redefined
-by gc.h.
+./configure --enable-threads=posix defines GC_WIN32_THREADS.)
+
+For the normal, non-dll-based thread tracking to work properly,
+threads should be created with GC_CreateThread or GC_beginthreadex,
+and exit normally or call GC_endthreadex or GC_ExitThread.  (For
+Cygwin, use standard pthread calls instead.)  As in the pthread
+case, including gc.h will redefine CreateThread, _beginthreadex,
+_endthreadex, and ExitThread to call the GC_ versions instead.
 
-For the statically linked versions, it is required that GC_init()
-be called before other GC calls, since there seems to be no implicit way
-to initialize the allocation lock.  The easiest way to ensure this in
-portable code is to call GC_INIT() from the main executable (not
-a dynamic library) before calling any other GC_ routines.
+Note that, as usual, GC_CreateThread tends to introduce resource leaks
+that are avoided by GC_beginthreadex.  There is currently no equivalent of
+_beginthread, and it should not be used.
+
+GC_INIT should be called from the main executable before other GC calls.
 
 We strongly advise against using the TerminateThread() win32 API call,
 especially with the garbage collector.  Any use is likely to provoke a
 crash in the GC, since it makes it impossible for the collector to
 correctly track threads.
 
-
-Watcom compiler
----------------
-
-Ivan V. Demakov's README for the Watcom port:
-
-The collector has been compiled with Watcom C 10.6 and 11.0.
-It runs under win32, win32s, and even under msdos with dos4gw
-dos-extender. It should also run under OS/2, though this isn't
-tested. Under win32 the collector can be built either as dll
-or as static library.
-
-Note that all compilations were done under Windows 95 or NT.
-For unknown reason compiling under Windows 3.11 for NT (one
-attempt has been made) leads to broken executables.
-
-Incremental collection is not supported.
-
-cord is not ported.
-
-Before compiling you may need to edit WCC_MAKEFILE to set target
-platform, library type (dynamic or static), calling conventions, and
-optimization options.
-
-To compile the collector and testing programs use the command:
-    wmake -f WCC_MAKEFILE
-
-All programs using gc should be compiled with 4-byte alignment.
-For further explanations on this see comments about Borland.
-
-If the gc is compiled as dll, the macro ``GC_DLL'' should be defined before
-including "gc.h" (for example, with -DGC_DLL compiler option). It's
-important, otherwise resulting programs will not run.
-
-Ivan Demakov (email: ivan@tgrad.nsk.su)
-
-Win32S
-------
-
-[The following is probably obsolete.  The win32s support is still in the
-collector, but I doubt anyone cares, or has tested it recently.]
-
-The collector runs under both win32s and win32, but with different semantics.
-Under win32, all writable pages outside of the heaps and stack are
-scanned for roots.  Thus the collector sees pointers in DLL data
-segments.  Under win32s, only the main data segment is scanned.
-(The main data segment should always be scanned.  Under some
-versions of win32s, other regions may also be scanned.)
-Thus all accessible objects should be accessible from local variables
-or variables in the main data segment.  Alternatively, other data
-segments (e.g. in DLLs) may be registered with the collector by
-calling GC_init() and then GC_register_root_section(a), where
-a is the address of some variable inside the data segment.  (Duplicate
-registrations are ignored, but not terribly quickly.)
-
-(There are two reasons for this.  We didn't want to see many 16:16
-pointers.  And the VirtualQuery call has different semantics under
-the two systems, and under different versions of win32s.)
+To build the collector for Mingw32 Pthreads, use Makefile.direct and
+explicitly set GC_WIN32_PTHREADS.  Use -DPTW32_STATIC_LIB for the static
+threads library.  Note that the DEBUG_WIN32_PTHREADS support in
+win32_threads.c is currently broken and looking for someone to debug it.
+(This information and the port came from Romano Paolo Tenca).
 
diff --git a/src/mm/boehm-gc/doc/README.win64 b/src/mm/boehm-gc/doc/README.win64
new file mode 100644 (file)
index 0000000..9db0e78
--- /dev/null
@@ -0,0 +1,17 @@
+64-bit Windows on AMD64/Intel EM64T is somewhat supported in the 7.0
+release.  A collector can be built with Microsoft Visual C++ 2005.
+The resulting test programs have been known to work at least once.
+More testing would clearly be helpful.
+
+Currently only NT_X64_STATIC_THREADS_MAKEFILE has been used in
+this environment.  Copy this file to MAKEFILE, and then type "nmake"
+in a Visual C++ command line window to build the static library
+and the usual test programs.  To verify that the colllector is
+at least somewhat functional, run gctest.exe.  This should create
+gctest.exe.log after a few seconds.
+
+This process is completely analogous to NT_STATIC_THREADS_MAKEFILE
+for the 32-bit version.
+
+Note that currently a few warnings are still generated by default,
+and a number of others have been explicitly turned off in the makefile.
diff --git a/src/mm/boehm-gc/doc/doc.am b/src/mm/boehm-gc/doc/doc.am
new file mode 100644 (file)
index 0000000..b546fa4
--- /dev/null
@@ -0,0 +1,55 @@
+# 
+# 
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+# 
+# Permission is hereby granted to use or copy this program
+# for any purpose,  provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+#
+# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
+# Modified by: Petter Urkedal <petter.urkedal@nordita.dk>
+
+## Process this file with automake to produce Makefile.in.
+
+# installed documentation
+#
+dist_noinst_DATA = \
+       doc/barrett_diagram \
+       doc/debugging.html \
+       doc/gc.man \
+       doc/gcdescr.html \
+       doc/README \
+       doc/README.amiga \
+       doc/README.arm.cross \
+       doc/README.autoconf \
+       doc/README.changes \
+       doc/README.contributors \
+       doc/README.cords \
+       doc/README.DGUX386 \
+       doc/README.dj \
+       doc/README.environment \
+       doc/README.ews4800 \
+       doc/README.hp \
+       doc/README.linux \
+       doc/README.Mac \
+       doc/README.MacOSX \
+       doc/README.macros \
+       doc/README.OS2 \
+       doc/README.rs6000 \
+       doc/README.sgi \
+       doc/README.solaris2 \
+       doc/README.uts \
+       doc/README.win32 \
+       doc/README.win64 \
+       doc/overview.html \
+       doc/tree.html \
+       doc/leak.html \
+       doc/gcinterface.html \
+       doc/scale.html \
+       doc/README.darwin \
+       doc/simple_example.html \
+       doc/porting.html
+
index cab6bde4fbab9682471022bca6b098a69af86486..dc08470e401a690e9a1fb02f9160a813e2317794 100644 (file)
@@ -1,7 +1,7 @@
 <HTML>
 <HEAD>
     <TITLE> Conservative GC Algorithmic Overview </TITLE>
-    <AUTHOR> Hans-J. Boehm, HP Labs (Much of this was written at SGI)</author>
+    <AUTHOR> Hans-J. Boehm, HP Labs (Some of this was written at SGI)</author>
 </HEAD>
 <BODY>
 <H1> <I>This is under construction, and may always be.</i> </h1>
@@ -549,6 +549,67 @@ by using ld's function call wrapping mechanism under Linux.
 Recent versions of the collector support several facilites to enhance
 the processor-scalability and thread performance of the collector.
 These are discussed in more detail <A HREF="scale.html">here</a>.
+We briefly outline the data approach to thread-local allocation in the
+next section.
+<H2>Thread-local allocation</h2>
+If thread-local allocation is enabled, the collector keeps separate
+arrays of free lists for each thread.  Thread-local allocation
+is currently only supported on a few platforms.
+<P>
+The free list arrays associated
+with each thread are only used to satisfy requests for objects that
+are  both very small, and belong to one of a small number of well-known
+kinds.  These currently include "normal" and pointer-free objects.
+Depending onthe configuration, "gcj" objects may also be included.
+<P>
+Thread-local free list entries contain either a pointer to the first
+element of a free list, or they contain a counter of the number of
+allocation "granules" allocated so far.  Initially they contain the
+value one, i.e. a small counter value.
+<P>
+Thread-local allocation allocates directly through the global
+allocator, if the object is of a size or kind not covered by the
+local free lists.
+<P>
+If there is an appropriate local free list, the allocator checks whether it
+contains a sufficiently small counter value.  If so, the counter is simply
+incremented by the counter value, and the global allocator is used.
+In this way, the initial few allocations of a given size bypass the local
+allocator.  A thread that only allocates a handful of objects of a given
+size will not build up its own free list for that size.  This avoids
+wasting space for unpopular objects sizes or kinds.
+<P>
+Once the counter passes a threshold, <TT>GC_malloc_many</tt> is called
+to allocate roughly <TT>HBLKSIZE</tt> space and put it on the corresponding
+local free list.  Further allocations of that size and kind then use
+this free list, and no longer need to acquire the allocation lock.
+The allocation procedure is otherwise similar to the global free lists.
+The local free lists are also linked using the first word in the object.
+In most cases this means they require considerably less time.
+<P>
+Local free lists are treated buy most of the rest of the collector
+as though they were in-use reachable data.  This requires some care,
+since pointer-free objects are not normally traced, and hence a special
+tracing procedure is required to mark all objects on pointer-free and
+gcj local free lists.
+<P>
+On thread exit, any remaining thread-local free list entries are
+transferred back to the global free list.
+<P>
+Note that if the collector is configured for thread-local allocation,
+GC versions before 7 do not invoke the thread-local allocator by default.
+<TT>GC_malloc</tt> only uses thread-local allocation in version 7 and later.
+In earlier versions, <TT>GC_MALLOC</tt> (all caps) may be directed
+to use thread-local allocation by defining <TT>GC_REDIRECT_TO_LOCAL</tt>
+and then include <TT>gc_local_alloc.h</tt>.
+<P>
+For some more details see <A HREF="scale.html">here</a>, and the
+technical report entitled
+<A HREF="http://www.hpl.hp.com/techreports/2000/HPL-2000-165.html">
+``Fast Multiprocessor Memory Allocation and Garbage Collection''
+</a>
+<P>
+<HR>
 <P>
 Comments are appreciated.  Please send mail to
 <A HREF="mailto:boehm@acm.org"><TT>boehm@acm.org</tt></a> or
index ed16950e2f0b342676eb3cc0f670794bb022378f..74230aa6caee465d4e677511eaa4b6a557585834 100644 (file)
@@ -106,7 +106,9 @@ On some platforms, it is necessary to invoke this
 <I>from the main executable, not from a dynamic library,</i> before
 the initial invocation of a GC routine.  It is recommended that this be done
 in portable code, though we try to ensure that it expands to a no-op
-on as many platforms as possible.
+on as many platforms as possible.  As of GC 7.0, it is required if
+thread-local allocation is enabled in the collector build, and <TT>malloc</tt>
+is not redirected to <TT>GC_malloc</tt>.
 <DT> <B> void GC_gcollect(void) </b>
 <DD>
 Explicitly force a garbage collection.
@@ -165,7 +167,17 @@ advantage of the collector.  For details see
 <A HREF="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/cordh.txt">cord.h</a>
 
 <H1>C++ Interface</h1>
-Usage of the collector from C++ is complicated by the fact that there
+The C++ interface is implemented as a thin layer on the C interface.
+Unfortunately, this thin layer appears to be very sensitive to variations
+in C++ implementations, particularly since it tries to replace the global
+::new operator, something that appears to not be well-standardized.
+Your platform may need minor adjustments in this layer (gc_cpp.cc, gc_cpp.h,
+and possibly gc_allocator.h).  Such changes do not require understanding
+of collector internals, though they may require a good understanding of
+your platform.  (Patches enhancing portability are welcome.
+But it's easy to break one platform by fixing another.)
+<P>
+Usage of the collector from C++ is also complicated by the fact that there
 are many "standard" ways to allocate memory in C++.  The default ::new
 operator, default malloc, and default STL allocators allocate memory
 that is not garbage collected, and is not normally "traced" by the
@@ -183,7 +195,7 @@ memory is referenced by pointers stored in one of
 </ul>
 "Traceable" objects are not necessarily reclaimed by the collector,
 but are scanned for pointers to collectable objects.
-They are allocated by <TT>GC_MALLOC_UNCOLLECTABLE</tt>, as described
+They are usually allocated by <TT>GC_MALLOC_UNCOLLECTABLE</tt>, as described
 above, and through some interfaces described below.
 <P>
 (On most platforms, the collector may not trace correctly from in-flight
@@ -198,11 +210,28 @@ which replaces a standard C++ allocation mechanism:
 <DL>
 <DT> <B> STL allocators </b>
 <DD>
+<P>
+Recent versions of the collector also include a more standard-conforming
+allocator implementation in <TT>gc_allocator.h</tt>.  It defines
+<UL>
+<LI> traceable_allocator
+<LI> gc_allocator
+</ul>
+which may be used either directly to allocate memory or to instantiate
+container templates. 
+The former allocates uncollectable but traced memory.
+The latter allocates garbage-collected memory.
+<P>
+These should work with any fully standard-conforming C++ compiler.
+<P>
 Users of the <A HREF="http://www.sgi.com/tech/stl">SGI extended STL</a>
-can include <TT>new_gc_alloc.h</tt> before including
+or its derivatives (including most g++ versions)
+can alternatively include <TT>new_gc_alloc.h</tt> before including
 STL header files.
 (<TT>gc_alloc.h</tt> corresponds to now obsolete versions of the
-SGI STL.)
+SGI STL.)  This interface is no longer recommended, but it has existed
+for much longer.
+<P>
 This defines SGI-style allocators
 <UL>
 <LI> alloc
@@ -210,22 +239,12 @@ This defines SGI-style allocators
 <LI> gc_alloc
 <LI> single_client_gc_alloc
 </ul>
-which may be used either directly to allocate memory or to instantiate
-container templates.  The first two allocate uncollectable but traced
+The first two allocate uncollectable but traced
 memory, while the second two allocate collectable memory.
 The single_client versions are not safe for concurrent access by
 multiple threads, but are faster.
 <P>
 For an example, click <A HREF="http://hpl.hp.com/personal/Hans_Boehm/gc/gc_alloc_exC.txt">here</a>.
-<P>
-Recent versions of the collector also include a more standard-conforming
-allocator implementation in <TT>gc_allocator.h</tt>.  It defines
-<UL>
-<LI> traceable_allocator
-<LI> gc_allocator
-</ul>
-Again the former allocates uncollectable but traced memory.
-This should work with any fully standard-conforming C++ compiler.
 <DT> <B> Class inheritance based interface </b>
 <DD>
 Users may include gc_cpp.h and then cause members of classes to
index 91fa8ea840236fa3f6b76e2ba9dbf25f78cbda0b..8f460c9f68c9635165b46aafa3bff55174a937e4 100644 (file)
@@ -161,8 +161,10 @@ Linux/X86, but not on most other platforms.
 Since version 6.1, it should be possible to run the collector in leak
 detection mode on a program a.out under Linux/X86 as follows:
 <OL>
-<LI> Ensure that a.out is a single-threaded executable.  This doesn't yet work
-for multithreaded programs.
+<LI> <I>Ensure that a.out is a single-threaded executable, or you are using
+a very recent (7.0alpha7+) collector version on Linux.</i>
+On most platforms this does not
+work at all for multithreaded programs.
 <LI> If possible, ensure that the addr2line program is installed in
 /usr/bin.  (It comes with RedHat Linux.)
 <LI> If possible, compile a.out with full debug information.
@@ -171,11 +173,12 @@ no longer necessary to call GC_ routines explicitly, though that can also
 improve the quality of the leak reports.
 <LI> Build the collector and install it in directory <I>foo</i> as follows:
 <UL>
-<LI> configure --prefix=<I>foo</i> --enable-full-debug --enable-redirect-malloc
---disable-threads
-<LI> make
-<LI> make install
+<LI> <TT>configure --prefix=<I>foo</i> --enable-full-debug --enable-redirect-malloc
+--disable-threads</tt>
+<LI> <TT>make</tt>
+<LI> <TT>make install</tt>
 </ul>
+With a very recent collector on Linux, it may be safe to omit the <TT>--disable-threads</tt>.
 <LI> Set environment variables as follows:
 <UL>
 <LI> LD_PRELOAD=<I>foo</i>/lib/libgc.so
@@ -191,7 +194,7 @@ embarrassing.  It can generate
 mountains of leak reports if the application wasn't designed to avoid leaks,
 <I>e.g.</i> because it's always short-lived.
 </ol>
-This has not yet been thropughly tested on large applications, but it's known
+This has not yet been thoroughly tested on large applications, but it's known
 to do the right thing on at least some small ones.
 </body>
 </html>
diff --git a/src/mm/boehm-gc/doc/overview.html b/src/mm/boehm-gc/doc/overview.html
new file mode 100644 (file)
index 0000000..d31f937
--- /dev/null
@@ -0,0 +1,446 @@
+<!DOCTYPE HTML>
+<html><head><title>A garbage collector for C and C++</title></head>
+<body>
+<table bgcolor="#f0f0ff" cellpadding="10%">
+  <tbody><tr>
+  <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcinterface.html">Interface Overview</a></td>
+  <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/04tutorial.pdf">Tutorial Slides</a></td>
+  <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/faq.html">FAQ</a></td>
+  <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/simple_example.html">Example</a></td>
+  <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source">Download</a></td>
+  <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/license.txt">License</a></td>
+  </tr>
+</tbody></table>
+<h1>A garbage collector for C and C++</h1>
+<ul>
+<li><a href="#platforms">Platforms</a>
+</li><li><a href="#multiprocessors">Scalable multiprocessor versions</a>
+</li><li><a href="#details">Some collector details</a>
+</li><li><a href="#further">Further reading</a>
+</li><li><a href="#users">Current users</a>
+</li><li><a href="#collector">Local Links for this collector</a>
+</li><li><a href="#background">Local Background Links</a>
+</li><li><a href="#contacts">Contacts and Mailing List</a>
+</li></ul>
+[ This is an updated version of the page formerly at
+<tt>http://reality.sgi.com/boehm/gc.html</tt>
+and before that at
+<a href="ftp://parcftp.xerox.com/pub/gc/gc.html">
+<tt>ftp://parcftp.xerox.com/pub/gc/gc.html</tt></a>.]
+<p>
+The <a href="http://www.hpl.hp.com/personal/Hans_Boehm">Boehm</a>-<a href="http://www.cs.cornell.edu/annual_report/00-01/bios.htm#demers">Demers</a>-<a href="http://www-sul.stanford.edu/weiser/">Weiser</a>
+conservative garbage collector can
+be used as a garbage collecting
+replacement for C <tt>malloc</tt> or C++ <tt>new</tt>.
+It allows you to allocate memory basically as you normally would,
+without explicitly deallocating memory that is no longer useful.
+The collector automatically recycles memory when it determines
+that it can no longer be otherwise accessed.
+A simple example of such a use is given
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/simple_example.html">here</a>.
+</p><p>
+The collector is also used by a number of programming language
+implementations that either use C as intermediate code, want
+to facilitate easier interoperation with C libraries, or
+just prefer the simple collector interface.
+For a more detailed description of the interface, see
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcinterface.html">here</a>.
+</p><p>
+Alternatively, the garbage collector  may be used as
+a <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html">leak detector</a>
+for C or C++ programs, though that is not its primary goal.
+</p><p>
+Typically several versions will be available.
+Usually you should first try to use
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/gc.tar.gz"><tt>gc_source/gc.tar.gz</tt></a>,
+which is normally an older, more stable version.
+</p><p>
+If that fails, try the latest explicitly numbered version
+in <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/">
+<tt>gc_source/</tt></a>.
+Later versions may contain additional features, platform support,
+or bug fixes, but are likely to be less well tested.
+Note that versions containing the letters <tt>alpha</tt> are even less
+well tested than others, especially on non-HP platforms.
+</p><p>
+A slightly older version of the garbage collector is now also
+included as part of the
+<a href="http://gcc.gnu.org/">GNU compiler</a>
+distribution.  The source
+code for that version is available for browsing
+<a href="http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/boehm-gc/">here</a>.
+</p><p>
+The arguments for and against conservative garbage collection
+in C and C++ are briefly
+discussed in
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/issues.html">issues.html</a>.  The beginnings of
+a frequently-asked-questions list are <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/faq.html">here</a>.
+</p><p>
+The garbage collector code is copyrighted by
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm">Hans-J. Boehm</a>,
+Alan J. Demers,
+<a href="http://www.xerox.com/">Xerox Corporation</a>,
+<a href="http://www.sgi.com/">Silicon Graphics</a>,
+and
+<a href="http://www.hp.com/">Hewlett-Packard Company</a>.
+It may be used and copied without payment of a fee under minimal restrictions.
+See the README file in the distribution  or the
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/license.txt">license</a> for more details.
+<b>IT IS PROVIDED AS IS,
+WITH ABSOLUTELY NO WARRANTY EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK</b>.
+</p><p>
+Empirically, this collector works with most unmodified C programs,
+simply by replacing
+<tt>malloc</tt> with <tt>GC_malloc</tt> calls,
+replacing <tt>realloc</tt> with <tt>GC_realloc</tt> calls, and removing
+free calls.  Exceptions are discussed
+in <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/issues.html">issues.html</a>. 
+</p><h2><a name="platforms">Platforms</a></h2>
+The collector is not completely portable, but the distribution
+includes ports to most standard PC and UNIX/Linux platforms.
+The collector should work on Linux, *BSD, recent Windows versions,
+MacOS X, HP/UX, Solaris,
+Tru64, Irix and a few other operating systems.
+Some ports are more polished than others.
+<p>
+Irix pthreads, Linux threads, Win32 threads, Solaris threads
+(old style and pthreads),
+HP/UX 11 pthreads, Tru64 pthreads, and MacOS X threads are supported
+in recent versions.
+</p><h3>Separately distributed ports</h3>
+For MacOS 9/Classic use, Patrick Beard's latest port is available from
+<a href="http://homepage.mac.com/pcbeard/gc/">
+<tt>http://homepage.mac.com/pcbeard/gc/</tt></a>.
+(Unfortunately, that's now quite dated.
+I'm not in a position to test under MacOS.  Although I try to
+incorporate changes, it is impossible for
+me to update the project file.)
+<p>
+Precompiled versions of the collector for NetBSD are available
+<a href="ftp://ftp.netbsd.org/pub/NetBSD/packages/pkgsrc/devel/boehm-gc/README.html">here</a>
+or
+<a href="http://www.netbsd.org/packages/devel/boehm-gc/README.html">here</a>.
+</p><p>
+<a href="http://www.debian.org/">Debian Linux</a> includes prepackaged
+versions of the collector.
+</p><h2><a name="multiprocessors">Scalable multiprocessor versions</a></h2>
+Kenjiro Taura, Toshio Endo, and Akinori Yonezawa have made available
+a <a href="http://www.yl.is.s.u-tokyo.ac.jp/gc/">parallel collector</a>
+based on this one.  Their collector takes advantage of multiple processors
+during a collection.  Starting with collector version 6.0alpha1
+we also do this, though with more modest processor scalability goals.
+Our approach is discussed briefly in
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/scale.html"><tt>scale.html</tt></a>.
+<h2><a name="details">Some Collector Details</a></h2>
+The collector uses a <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/complexity.html">mark-sweep</a> algorithm.
+It provides incremental and generational
+collection under operating systems which provide the right kind of
+virtual memory support.  (Currently this includes SunOS[45], IRIX,
+OSF/1, Linux, and Windows, with varying restrictions.)
+It allows <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/finalization.html"><i>finalization</i></a> code
+to be invoked when an object is collected.
+It can take advantage of type information to locate pointers if such
+information is provided, but it is usually used without such information.
+ee the README and
+<tt>gc.h</tt> files in the distribution for more details.
+<p>
+For an overview of the implementation, see <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcdescr.html">here</a>.
+</p><p>
+The garbage collector distribution includes a C string
+(<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/cordh.txt"><i>cord</i></a>) package that provides
+for fast concatenation and substring operations on long strings.
+A simple curses- and win32-based editor that represents the entire file
+as a cord is included as a
+sample application.
+</p><p>
+Performance of the nonincremental collector is typically competitive
+with malloc/free implementations.  Both space and time overhead are
+likely to be only slightly higher
+for programs written for malloc/free
+(see Detlefs, Dosser and Zorn's
+<a href="ftp://ftp.cs.colorado.edu/pub/techreports/zorn/CU-CS-665-93.ps.Z">Memory Allocation Costs in Large C and C++ Programs</a>.)
+For programs allocating primarily very small objects, the collector
+may be faster; for programs allocating primarily large objects it will
+be slower.  If the collector is used in a multithreaded environment
+and configured for thread-local allocation, it may in some cases
+significantly outperform malloc/free allocation in time.
+</p><p>
+We also expect that in many cases any additional overhead
+will be more than compensated for by decreased copying etc.
+if programs are written
+and tuned for garbage collection.
+</p><h1><a name="further">Further Reading:</a></h1>
+<b>The beginnings of a frequently asked questions list for this
+collector are <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/faq.html">here</a></b>.
+<p>
+<b>The following provide information on garbage collection in general</b>:
+</p><p>
+Paul Wilson's <a href="ftp://ftp.cs.utexas.edu/pub/garbage">garbage collection ftp archive</a> and <a href="ftp://ftp.cs.utexas.edu/pub/garbage/gcsurvey.ps">GC survey</a>.
+</p><p>
+The Ravenbrook <a href="http://www.memorymanagement.org/">
+Memory Management Reference</a>.
+</p><p>
+David Chase's
+<a href="http://www.iecc.com/gclist/GC-faq.html">GC FAQ</a>.
+</p><p>
+Richard Jones'
+<a href="http://www.ukc.ac.uk/computer_science/Html/Jones/gc.html">
+GC page</a> and
+<a href="http://www.cs.kent.ac.uk/people/staff/rej/gcbook/gcbook.html">
+his book</a>.
+</p><p>
+<b>The following papers describe the collector algorithms we use
+and the underlying design decisions at
+a higher level.</b>
+</p><p>
+(Some of the lower level details can be found
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcdescr.html">here</a>.)
+</p><p>
+The first one is not available
+electronically due to copyright considerations.  Most of the others are
+subject to ACM copyright.
+</p><p>
+Boehm, H., "Dynamic Memory Allocation and Garbage Collection", <i>Computers in Physics
+9</i>, 3, May/June 1995, pp. 297-303.  This is directed at an otherwise sophisticated
+audience unfamiliar with memory allocation issues.  The algorithmic details differ
+from those in the implementation.  There is a related letter to the editor and a minor
+correction in the next issue.
+</p><p>
+Boehm, H., and <a href="http://www.ubiq.com/hypertext/weiser/weiser.html">M. Weiser</a>,
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/spe_gc_paper">"Garbage Collection in an Uncooperative Environment"</a>,
+<i>Software Practice &amp; Experience</i>, September 1988, pp. 807-820.
+</p><p>
+Boehm, H., A. Demers, and S. Shenker, <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi91.ps.Z">"Mostly Parallel Garbage Collection"</a>, Proceedings
+of the ACM SIGPLAN '91 Conference on Programming Language Design and Implementation,
+<i>SIGPLAN Notices 26</i>, 6 (June 1991), pp. 157-164.
+</p><p>
+Boehm, H., <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi93.ps.Z">"Space Efficient Conservative Garbage Collection"</a>, Proceedings of the ACM
+SIGPLAN '93 Conference on Programming Language Design and Implementation, <i>SIGPLAN
+Notices 28</i>, 6 (June 1993), pp. 197-206.
+</p><p>
+Boehm, H., "Reducing Garbage Collector Cache Misses",
+<i> Proceedings of the 2000 International Symposium on Memory Management </i>.
+<a href="http://portal.acm.org/citation.cfm?doid=362422.362438">
+Official version.</a>
+<a href="http://www.hpl.hp.com/techreports/2000/HPL-2000-99.html">
+Technical report version.</a>  Describes the prefetch strategy
+incorporated into the collector for some platforms.  Explains why
+the sweep phase of a "mark-sweep" collector should not really be
+a distinct phase.
+</p><p>
+M. Serrano, H. Boehm,
+"Understanding Memory Allocation of Scheme Programs",
+<i>Proceedings of the Fifth ACM SIGPLAN International Conference on
+Functional Programming</i>, 2000, Montreal, Canada, pp. 245-256.
+<a href="http://www.acm.org/pubs/citations/proceedings/fp/351240/p245-serrano/">
+Official version.</a>
+<a href="http://www.hpl.hp.com/techreports/2000/HPL-2000-62.html">
+Earlier Technical Report version.</a>  Includes some discussion of the
+collector debugging facilities for identifying causes of memory retention.
+</p><p>
+Boehm, H.,
+"Fast Multiprocessor Memory Allocation and Garbage Collection",
+<a href="http://www.hpl.hp.com/techreports/2000/HPL-2000-165.html">
+HP Labs Technical Report HPL 2000-165</a>.  Discusses the parallel
+collection algorithms, and presents some performance results.
+</p><p>
+Boehm, H., "Bounding Space Usage of Conservative Garbage Collectors",
+<i>Proceeedings of the 2002 ACM SIGPLAN-SIGACT Symposium on Principles of
+Programming Languages</i>, Jan. 2002, pp. 93-100.
+<a href="http://portal.acm.org/citation.cfm?doid=503272.503282">
+Official version.</a>
+<a href="http://www.hpl.hp.com/techreports/2001/HPL-2001-251.html">
+Technical report version.</a>
+Includes a discussion of a collector facility to much more reliably test for
+the potential of unbounded heap growth.
+</p><p>
+<b>The following papers discuss language and compiler restrictions necessary to guaranteed
+safety of conservative garbage collection.</b>
+</p><p>
+We thank John Levine and JCLT for allowing
+us to make the second paper available electronically, and providing PostScript for the final
+version.
+</p><p>
+Boehm, H., <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi96.ps.gz">``Simple
+Garbage-Collector-Safety''</a>, Proceedings
+of the ACM SIGPLAN '96 Conference on Programming Language Design
+and Implementation.
+</p><p>
+Boehm, H., and D. Chase,  <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/boecha.ps.gz">
+``A Proposal for Garbage-Collector-Safe C Compilation''</a>,
+<i>Journal of C  Language Translation 4</i>, 2 (Decemeber 1992), pp. 126-141.
+</p><p>
+<b>Other related information: </b>
+</p><p>
+The Detlefs, Dosser and Zorn's <a href="ftp://ftp.cs.colorado.edu/pub/techreports/zorn/CU-CS-665-93.ps.Z">Memory Allocation Costs in Large C and C++ Programs</a>.
+ This is a performance comparison of the Boehm-Demers-Weiser collector to malloc/free,
+using programs written for malloc/free.
+</p><p>
+Joel Bartlett's <a href="ftp://ftp.digital.com/pub/DEC/CCgc">mostly copying conservative garbage collector for C++</a>.
+</p><p>
+John Ellis and David Detlef's <a href="ftp://parcftp.xerox.com/pub/ellis/gc/gc.ps">Safe Efficient Garbage Collection for C++</a> proposal.
+</p><p>
+Henry Baker's <a href="http://home.pipeline.com/%7Ehbaker1/">paper collection</a>.
+</p><p>
+Slides for Hans Boehm's <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/myths.ps">Allocation and GC Myths</a> talk.
+</p><h1><a name="users">Current users:</a></h1>
+Known current users of some variant of this collector include:
+<p>
+The runtime system for <a href="http://gcc.gnu.org/java">GCJ</a>,
+the static GNU java compiler.
+</p><p>
+<a href="http://w3m.sourceforge.net/">W3m</a>, a text-based web browser.
+</p><p>
+Some versions of the Xerox DocuPrint printer software.
+</p><p>
+The <a href="http://www.mozilla.org/">Mozilla</a> project, as leak
+detector.
+</p><p>
+The <a href="http://www.go-mono.com/">Mono</a> project,
+an open source implementation of the .NET development framework.
+</p><p>
+The <a href="http://www.gnu.org/projects/dotgnu/">DotGNU Portable.NET
+project</a>, another open source .NET implementation.
+</p><p>
+The <a href="http://irssi.org/">Irssi IRC client</a>.
+</p><p>
+<a href="http://titanium.cs.berkeley.edu/">The Berkeley Titanium project</a>.
+</p><p>
+<a href="http://www.nag.co.uk/nagware_fortran_compilers.asp">The NAGWare f90 Fortran 90 compiler</a>.
+</p><p>
+Elwood Corporation's <a href="http://www.elwood.com/eclipse-info/index.htm">
+Eclipse</a> Common Lisp system, C library, and translator.
+</p><p>
+The <a href="http://www-sop.inria.fr/mimosa/fp/Bigloo/">Bigloo
+Scheme</a>
+and <a href="http://kaolin.unice.fr/%7Eserrano/camloo.html">Camloo ML
+compilers</a>
+written by Manuel Serrano and others.
+</p><p>
+Brent Benson's <a href="http://ftp.cs.indiana.edu/pub/scheme-repository/imp/">libscheme</a>.
+</p><p>
+The <a href="http://www.cs.rice.edu/CS/PLT/packages/mzscheme/index.html">MzScheme</a> scheme implementation.
+</p><p>
+The <a href="http://www.cs.washington.edu/research/projects/cecil/www/cecil-home.html">University of Washington Cecil Implementation</a>.
+</p><p>
+<a href="http://www.icsi.berkeley.edu/Sather/">The Berkeley Sather implementation</a>.
+</p><p>
+<a href="http://www.cs.berkeley.edu/%7Eharmonia/">The Berkeley Harmonia Project</a>.
+</p><p>
+The <a href="http://www.cs.arizona.edu/sumatra/toba/">Toba</a> Java Virtual
+Machine to C translator.
+</p><p>
+The <a href="http://www.gwydiondylan.org/">Gwydion Dylan compiler</a>.
+</p><p>
+The <a href="http://gcc.gnu.org/onlinedocs/gcc/Objective-C.html">
+GNU Objective C runtime</a>.
+</p><p>
+<a href="http://www.math.uiuc.edu/Macaulay2">Macaulay 2</a>, a system to support
+research in algebraic geometry and commutative algebra.
+</p><p>
+The <a href="http://www.vestasys.org/">Vesta</a> configuration management
+system.
+</p><p>
+<a href="http://www.visual-prolog.com/vip6">Visual Prolog 6</a>.
+</p><p>
+<a href="http://asymptote.sf.net/">Asymptote LaTeX-compatible
+vector graphics language.</a>
+
+</p><h1><a name="collector">More collector information at this site</a></h1>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/simple_example.html">A simple illustration of how to build and
+use the collector.</a>.
+<p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcinterface.html">Description of alternate interfaces to the
+garbage collector.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/04tutorial.pdf">Slides from an ISMM 2004  tutorial about the GC.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/faq.html">A FAQ (frequently asked questions) list.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html">How to use the garbage collector as a leak detector.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/debugging.html">Some hints on debugging garbage collected
+applications.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcdescr.html">An overview of the implementation of the
+garbage collector.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/tree.html">The data structure used for fast pointer lookups.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/scale.html">Scalability of the collector to multiprocessors.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source">Directory containing garbage collector source.</a>
+
+</p><h1><a name="background">More background information at this site</a></h1>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/bounds.html">An attempt to establish a bound on space usage of
+conservative garbage collectors.</a>
+<p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/complexity.html">Mark-sweep versus copying garbage collectors
+and their complexity.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/conservative.html">Pros and cons of conservative garbage collectors,
+in comparison to other collectors.
+</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/issues.html">Issues related to garbage collection vs.
+manual memory management in C/C++.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/example.html">An example of a case in which garbage collection
+results in a much faster implementation as a result of reduced
+synchronization.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/nonmoving">Slide set discussing performance of nonmoving
+garbage collectors.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/popl03/web">
+Slide set discussing <i>Destructors, Finalizers, and Synchronization</i>
+(POPL 2003).</a>
+</p><p>
+<a href="http://portal.acm.org/citation.cfm?doid=604131.604153">
+Paper corresponding to above slide set.</a>
+(<a href="http://www.hpl.hp.com/techreports/2002/HPL-2002-335.html">
+Technical Report version</a>.)
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_bench.html">A Java/Scheme/C/C++ garbage collection benchmark.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/myths.ps">Slides for talk on memory allocation myths.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gctalk.ps">Slides for OOPSLA 98 garbage collection talk.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers">Related papers.</a>
+</p><h1><a name="contacts">Contacts and Mailing List</a><a></a></h1>
+<a>We have recently set up two mailing list for collector announcements
+and discussions:
+</a><ul>
+<li><a href="mailto:gc-announce@linux.hpl.hp.com">gc-announce@linux.hpl.hp.com</a>
+is used for announcements of new versions.  Postings are restricted.
+We expect this to always remain a very low volume list.
+</li><li><a href="mailto:gc@linux.hpl.hp.com">gc@linux.hpl.hp.com</a> is used for
+discussions, bug reports, and the like.  Subscribers may post.
+On-topic posts by nonsubscribers will usually also be accepted, but
+it may take some time to review them.
+</li></ul>
+To subscribe to these lists, send a mail message containing the
+word "subscribe" to
+<a href="mailto:gc-announce-request@linux.hpl.hp.com?subject=subscribe">gc-announce-request@linux.hpl.hp.com</a>
+or to
+<a href="mailto:gc-request@linux.hpl.hp.com?subject=subscribe">gc-request@linux.hpl.hp.com</a>.
+(Please ignore the instructions about web-based subscription.
+The listed web site is behind the HP firewall.)
+<p>
+The archives for these lists appear
+<a href="http://www.hpl.hp.com/hosted/linux/mail-archives">here</a>.
+The gc list archive may also be read at
+<a href="http://dir.gmane.org/gmane.comp.programming.garbage-collection.boehmgc">gmane.org</a>.
+</p><p>
+Some prior discussion of the collector has taken place on the gcc
+java mailing list, whose archives appear
+<a href="http://gcc.gnu.org/ml/java/">here</a>, and also on
+<a href="http://lists.tunes.org/mailman/listinfo/gclist">gclist@iecc.com</a>.
+</p><p>
+Comments and bug reports may also be sent to
+(<a href="mailto:Hans_Boehm@hp.com">Hans.Boehm@hp.com</a>) or
+(<a href="mailto:boehm@acm.org">boehm@acm.org</a>), but the gc
+mailing list is usually preferred.
+</p></body></html>
diff --git a/src/mm/boehm-gc/doc/porting.html b/src/mm/boehm-gc/doc/porting.html
new file mode 100644 (file)
index 0000000..5a06c22
--- /dev/null
@@ -0,0 +1,333 @@
+<HTML>
+<HEAD>
+    <TITLE>Conservative GC Porting Directions</TITLE>
+</HEAD>
+<BODY>
+<H1>Conservative GC Porting Directions</h1>
+The collector is designed to be relatively easy to port, but is not
+portable code per se.  The collector inherently has to perform operations,
+such as scanning the stack(s), that are not possible in portable C code.
+<P>
+All of the following assumes that the collector is being ported to a
+byte-addressable 32- or 64-bit machine.  Currently all successful ports
+to 64-bit machines involve LP64 targets.  The code base includes some
+provisions for P64 targets (notably win64), but that has not been tested.
+You are hereby discouraged from attempting a port to non-byte-addressable,
+or 8-bit, or 16-bit machines.
+<P>
+The difficulty of porting the collector varies greatly depending on the needed
+functionality.  In the simplest case, only some small additions are needed
+for the <TT>include/private/gcconfig.h</tt> file.  This is described in the
+following section.  Later sections discuss some of the optional features,
+which typically involve more porting effort.
+<P>
+Note that the collector makes heavy use of <TT>ifdef</tt>s.  Unlike
+some other software projects, we have concluded repeatedly that this is preferable
+to system dependent files, with code duplicated between the files.
+However, to keep this manageable, we do strongly believe in indenting
+<TT>ifdef</tt>s correctly (for historical reasons usually without the leading
+sharp sign).  (Separate source files are of course fine if they don't result in
+code duplication.)
+<H2>Adding Platforms to <TT>gcconfig.h</tt></h2>
+If neither thread support, nor tracing of dynamic library data is required,
+these are often the only changes you will need to make.
+<P>
+The <TT>gcconfig.h</tt> file consists of three sections:
+<OL>
+<LI> A section that defines GC-internal macros
+that identify the architecture (e.g. <TT>IA64</tt> or <TT>I386</tt>)
+and operating system (e.g. <TT>LINUX</tt> or <TT>MSWIN32</tt>).
+This is usually done by testing predefined macros.  By defining
+our own macros instead of using the predefined ones directly, we can
+impose a bit more consistency, and somewhat isolate ourselves from
+compiler differences.
+<P>
+It is relatively straightforward to add a new entry here.  But please try
+to be consistent with the existing code.  In particular, 64-bit variants
+of 32-bit architectures general are <I>not</i> treated as a new architecture.
+Instead we explicitly test for 64-bit-ness in the few places in which it
+matters.  (The notable exception here is <TT>I386</tt> and <TT>X86_64</tt>.
+This is partially historical, and partially justified by the fact that there
+are arguably more substantial architecture and ABI differences here than
+for RISC variants.)
+<P>
+on GNU-based systems, <TT>cpp -dM empty_source_file.c</tt> seems to generate
+a set of predefined macros.  On some other systems, the "verbose"
+compiler option may do so, or the manual page may list them.
+<LI>
+A section that defines a small number of platform-specific macros, which are
+then used directly by the collector.  For simple ports, this is where most of
+the effort is required.  We describe the macros below.
+<P>
+This section contains a subsection for each architecture (enclosed in a
+suitable <TT>ifdef</tt>.  Each subsection usually contains some
+architecture-dependent defines, followed by several sets of OS-dependent
+defines, again enclosed in <TT>ifdef</tt>s.
+<LI>
+A section that fills in defaults for some macros left undefined in the preceding
+section, and defines some other macros that rarely need adjustment for
+new platforms.  You will typically not have to touch these.
+If you are porting to an OS that
+was previously completely unsupported, it is likely that you will
+need to add another clause to the definition of <TT>GET_MEM</tt>.
+</ol>
+The following macros must be defined correctly for each architecture and operating
+system:
+<DL>
+<DT><TT>MACH_TYPE</tt>
+<DD>
+Defined to a string that represents the machine architecture.  Usually
+just the macro name used to identify the architecture, but enclosed in quotes.
+<DT><TT>OS_TYPE</tt>
+<DD>
+Defined to a string that represents the operating system name.  Usually
+just the macro name used to identify the operating system, but enclosed in quotes.
+<DT><TT>CPP_WORDSZ</tt>
+<DD>
+The word size in bits as a constant suitable for preprocessor tests,
+i.e. without casts or sizeof expressions.  Currently always defined as
+either 64 or 32.  For platforms supporting both 32- and 64-bit ABIs,
+this should be conditionally defined depending on the current ABI.
+There is a default of 32.
+<DT><TT>ALIGNMENT</tt>
+<DD>
+Defined to be the largest <TT>N</tt>, such that
+all pointer are guaranteed to be aligned on <TT>N</tt>-byte boundaries.
+defining it to be 1 will always work, but perform poorly.
+For all modern 32-bit platforms, this is 4.  For all modern 64-bit
+platforms, this is 8.  Whether or not X86 qualifies as a modern
+architecture here is compiler- and OS-dependent.
+<DT><TT>DATASTART</tt>
+<DD>
+The beginning of the main data segment.  The collector will trace all
+memory between <TT>DATASTART</tt> and <TT>DATAEND</tt> for root pointers.
+On some platforms,this can be defined to a constant address,
+though experience has shown that to be risky.  Ideally the linker will
+define a symbol (e.g. <TT>_data</tt> whose address is the beginning
+of the data segment.  Sometimes the value can be computed using
+the <TT>GC_SysVGetDataStart</tt> function.  Not used if either
+the next macro is defined, or if dynamic loading is supported, and the
+dynamic loading support defines a function
+<TT>GC_register_main_static_data()</tt> which returns false.
+<DT><TT>SEARCH_FOR_DATA_START</tt>
+<DD>
+If this is defined <TT>DATASTART</tt> will be defined to a dynamically
+computed value which is obtained by starting with the address of
+<TT>_end</tt> and walking backwards until non-addressable memory is found.
+This often works on Posix-like platforms.  It makes it harder to debug
+client programs, since startup involves generating and catching a
+segmentation fault, which tends to confuse users.
+<DT><TT>DATAEND</tt>
+<DD>
+Set to the end of the main data segment.  Defaults to <TT>end</tt>,
+where that is declared as an array.  This works in some cases, since
+the linker introduces a suitable symbol.
+<DT><TT>DATASTART2, DATAEND2</tt>
+<DD>
+Some platforms have two discontiguous main data segments, e.g.
+for initialized and uninitialized data.  If so, these two macros
+should be defined to the limits of the second main data segment.
+<DT><TT>STACK_GROWS_UP</tt>
+<DD>
+Should be defined if the stack (or thread stacks) grow towards higher
+addresses.  (This appears to be true only on PA-RISC.  If your architecture
+has more than one stack per thread, and is not already supported, you will
+need to do more work.  Grep for "IA64" in the source for an example.)
+<DT><TT>STACKBOTTOM</tt>
+<DD>
+Defined to be the cool end of the stack, which is usually the
+highest address in the stack.  It must bound the region of the
+stack that contains pointers into the GC heap.  With thread support,
+this must be the cold end of the main stack, which typically
+cannot be found in the same way as the other thread stacks.
+If this is not defined and none of the following three macros
+is defined, client code must explicitly set
+<TT>GC_stackbottom</tt> to an appropriate value before calling
+<TT>GC_INIT()</tt> or any other <TT>GC_</tt> routine.
+<DT><TT>LINUX_STACKBOTTOM</tt>
+<DD>
+May be defined instead of <TT>STACKBOTTOM</tt>.
+If defined, then the cold end of the stack will be determined
+Currently we usually read it from /proc.
+<DT><TT>HEURISTIC1</tt>
+<DD>
+May be defined instead of <TT>STACKBOTTOM</tt>.
+<TT>STACK_GRAN</tt> should generally also be undefined and defined.
+The cold end of the stack is determined by taking an address inside
+<TT>GC_init's frame</tt>, and rounding it up to
+the next multiple of <TT>STACK_GRAN</tt>.  This works well if the stack base is
+always aligned to a large power of two.
+(<TT>STACK_GRAN</tt> is predefined to 0x1000000, which is
+rarely optimal.)
+<DT><TT>HEURISTIC2</tt>
+<DD>
+May be defined instead of <TT>STACKBOTTOM</tt>.
+The cold end of the stack is determined by taking an address inside
+GC_init's frame, incrementing it repeatedly
+in small steps (decrement if <TT>STACK_GROWS_UP</tt>), and reading the value
+at each location.  We remember the value when the first
+Segmentation violation or Bus error is signalled, round that
+to the nearest plausible page boundary, and use that as the
+stack base.
+<DT><TT>DYNAMIC_LOADING</tt>
+<DD>
+Should be defined if <TT>dyn_load.c</tt> has been updated for this
+platform and tracing of dynamic library roots is supported.
+<DT><TT>MPROTECT_VDB, PROC_VDB</tt>
+<DD>
+May be defined if the corresponding "virtual dirty bit"
+implementation in os_dep.c is usable on this platform.  This
+allows incremental/generational garbage collection.
+<TT>MPROTECT_VDB</tt> identifies modified pages by
+write protecting the heap and catching faults.
+<TT>PROC_VDB</tt> uses the /proc primitives to read dirty bits.
+<DT><TT>PREFETCH, PREFETCH_FOR_WRITE</tt>
+<DD>
+The collector uses <TT>PREFETCH</tt>(<I>x</i>) to preload the cache
+with *<I>x</i>.
+This defaults to a no-op.
+<DT><TT>CLEAR_DOUBLE</tt>
+<DD>
+If <TT>CLEAR_DOUBLE</tt> is defined, then
+<TT>CLEAR_DOUBLE</tt>(x) is used as a fast way to
+clear the two words at GC_malloc-aligned address x.  By default,
+word stores of 0 are used instead.
+<DT><TT>HEAP_START</tt>
+<DD>
+<TT>HEAP_START</tt> may be defined as the initial address hint for mmap-based
+allocation.
+<DT><TT>ALIGN_DOUBLE</tt>
+<DD>
+Should be defined if the architecture requires double-word alignment
+of <TT>GC_malloc</tt>ed memory, e.g. 8-byte alignment with a
+32-bit ABI.  Most modern machines are likely to require this.
+This is no longer needed for GC7 and later.
+</dl>
+<H2>Additional requirements for a basic port</h2>
+In some cases, you may have to add additional platform-specific code
+to other files.  A likely candidate is the implementation of
+<TT>GC_with_callee_saves_pushed</tt> in </tt>mach_dep.c</tt>.
+This ensure that register contents that the collector must trace
+from are copied to the stack.  Typically this can be done portably,
+but on some platforms it may require assembly code, or just
+tweaking of conditional compilation tests.
+<P>
+For GC7, if your platform supports <TT>getcontext()</tt>, then definining
+the macro <TT>UNIX_LIKE</tt> for your OS in <TT>gcconfig.h</tt>
+(if it isn't defined there already) is likely to solve the problem.
+otherwise, if you are using gcc, <TT>_builtin_unwind_init()</tt>
+will be used, and should work fine.  If that is not applicable either,
+the implementation will try to use <TT>setjmp()</tt>.  This will work if your
+<TT>setjmp</tt> implementation saves all possibly pointer-valued registers
+into the buffer, as opposed to trying to unwind the stack at
+<TT>longjmp</tt> time.  The <TT>setjmp_test</tt> test tries to determine this,
+but often doesn't get it right.
+<P>
+In GC6.x versions of the collector, tracing of registers
+was more commonly handled
+with assembly code.  In GC7, this is generally to be avoided.
+<P>
+Most commonly <TT>os_dep.c</tt> will not require attention, but see below.
+<H2>Thread support</h2>
+Supporting threads requires that the collector be able to find and suspend
+all threads potentially accessing the garbage-collected heap, and locate
+any state associated with each thread that must be traced.
+<P>
+The functionality needed for thread support is generally implemented
+in one or more files specific to the particular thread interface.
+For example, somewhat portable pthread support is implemented
+in <TT>pthread_support.c</tt> and <TT>pthread_stop_world.c</tt>.
+The essential functionality consists of
+<DL>
+<DT><TT>GC_stop_world()</tt>
+<DD>
+Stops all threads which may access the garbage collected heap, other
+than the caller.
+<DT><TT>GC_start_world()</tt>
+<DD>
+Restart other threads.
+<DT><TT>GC_push_all_stacks()</tt>
+<DD>
+Push the contents of all thread stacks (or at least of pointer-containing
+regions in the thread stacks) onto the mark stack.
+</dl>
+These very often require that the garbage collector maintain its
+own data structures to track active threads.
+<P>
+In addition, <TT>LOCK</tt> and <TT>UNLOCK</tt> must be implemented
+in <TT>gc_locks.h</tt>
+<P>
+The easiest case is probably a new pthreads platform
+on which threads can be stopped
+with signals.  In this case, the changes involve:
+<OL>
+<LI>Introducing a suitable <TT>GC_</tt><I>X</i><TT>_THREADS</tt> macro, which should
+be automatically defined by <TT>gc_config_macros.h</tt> in the right cases.
+It should also result in a definition of <TT>GC_PTHREADS</tt>, as for the
+existing cases.
+<LI>For GC7+, ensuring that the <TT>atomic_ops</tt> package at least
+minimally supports the platform.
+If incremental GC is needed, or if pthread locks don't
+perform adequately as the allocation lock, you will probably need to
+ensure that a sufficient <TT>atomic_ops</tt> port
+exists for the platform to provided an atomic test and set
+operation.  (Current GC7 versions require more<TT>atomic_ops</tt>
+asupport than necessary.  This is a bug.)  For earlier versions define
+<TT>GC_test_and_set</tt> in <TT>gc_locks.h</tt>.
+<LI>Making any needed adjustments to <TT>pthread_stop_world.c</tt> and
+<TT>pthread_support.c</tt>.  Ideally none should be needed.  In fact,
+not all of this is as well standardized as one would like, and outright
+bugs requiring workarounds are common.
+</ol>
+Non-preemptive threads packages will probably require further work.  Similarly
+thread-local allocation and parallel marking requires further work
+in <TT>pthread_support.c</tt>, and may require better <TT>atomic_ops</tt>
+support.
+<H2>Dynamic library support</h2>
+So long as <TT>DATASTART</tt> and <TT>DATAEND</tt> are defined correctly,
+the collector will trace memory reachable from file scope or <TT>static</tt>
+variables defined as part of the main executable.  This is sufficient
+if either the program is statically linked, or if pointers to the
+garbage-collected heap are never stored in non-stack variables
+defined in dynamic libraries.
+<P>
+If dynamic library data sections must also be traced, then
+<UL>
+<LI><TT>DYNAMIC_LOADING</tt> must be defined in the appropriate section
+of <TT>gcconfig.h</tt>.
+<LI>An appropriate versions of the functions
+<TT>GC_register_dynamic_libraries()</tt> should be defined in
+<TT>dyn_load.c</tt>.  This function should invoke
+<TT>GC_cond_add_roots(</tt><I>region_start, region_end</i><TT>, TRUE)</tt>
+on each dynamic library data section.
+</ul>
+<P>
+Implementations that scan for writable data segments are error prone, particularly
+in the presence of threads.  They frequently result in race conditions
+when threads exit and stacks disappear.  They may also accidentally trace
+large regions of graphics memory, or mapped files.  On at least
+one occasion they have been known to try to trace device memory that
+could not safely be read in the manner the GC wanted to read it.
+<P>
+It is usually safer to walk the dynamic linker data structure, especially
+if the linker exports an interface to do so.  But beware of poorly documented
+locking behavior in this case.
+<H2>Incremental GC support</h2>
+For incremental and generational collection to work, <TT>os_dep.c</tt>
+must contain a suitable "virtual dirty bit" implementation, which
+allows the collector to track which heap pages (assumed to be
+a multiple of the collectors block size) have been written during
+a certain time interval.  The collector provides several
+implementations, which might be adapted.  The default
+(<TT>DEFAULT_VDB</tt>) is a placeholder which treats all pages
+as having been written.  This ensures correctness, but renders
+incremental and generational collection essentially useless.
+<H2>Stack traces for debug support</h2>
+If stack traces in objects are need for debug support,
+<TT>GC_dave_callers</tt> and <TT>GC_print_callers</tt> must be
+implemented.
+<H2>Disclaimer</h2>
+This is an initial pass at porting guidelines.  Some things
+have no doubt been overlooked.
+</body>
+</html>
index e73886e9630554581f0eed45b463f98f1bab6921..70fd0e0bc015fd40f98214138ff8fac9807e87a1 100644 (file)
@@ -29,8 +29,9 @@
 
 #include "config.h"
 
-#if (defined(__linux__) || defined(__GLIBC__)) && !defined(_GNU_SOURCE)
-    /* Can't test LINUX, since this must be define before other includes */
+#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \
+     && !defined(_GNU_SOURCE)
+    /* Can't test LINUX, since this must be defined before other includes */
 #   define _GNU_SOURCE
 #endif
 #if !defined(MACOS) && !defined(_WIN32_WCE)
 #   undef GC_must_restore_redefined_dlopen
 # endif
 
+/* A user-supplied routine that is called to determine if a DSO must
+   be scanned by the gc.  */
+static int (*GC_has_static_roots)(const char *, void *, size_t);
+
+
 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
     && !defined(PCR)
-#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
+#if !defined(SOLARISDL) && !defined(IRIX5) && \
     !defined(MSWIN32) && !defined(MSWINCE) && \
     !(defined(ALPHA) && defined(OSF1)) && \
     !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
-    !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
+    !defined(AIX) && !defined(SCO_ELF) && !defined(DGUX) && \
     !(defined(FREEBSD) && defined(__ELF__)) && \
     !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
-    !defined(DARWIN)
+    !defined(DARWIN) && !defined(CYGWIN32)
  --> We only know how to find data segments of dynamic libraries for the
  --> above.  Additional SVR4 variants might not be too
  --> hard to add.
 #endif
 
 #include <stdio.h>
-#ifdef SUNOS5DL
+#ifdef SOLARISDL
 #   include <sys/elf.h>
 #   include <dlfcn.h>
 #   include <link.h>
 #endif
-#ifdef SUNOS4
-#   include <dlfcn.h>
-#   include <link.h>
-#   include <a.out.h>
-  /* struct link_map field overrides */
-#   define l_next      lm_next
-#   define l_addr      lm_addr
-#   define l_name      lm_name
-#endif
 
 #if defined(NETBSD)
 #   include <machine/elf_machdep.h>
 #      else
 #        define ElfW(type) Elf64_##type
 #      endif
+#    elif defined(NETBSD)
+#      if ELFSIZE == 32
+#        define ElfW(type) Elf32_##type
+#      else
+#        define ElfW(type) Elf64_##type
+#      endif
 #    else
-#      ifdef NETBSD
-#        if ELFSIZE == 32
-#          define ElfW(type) Elf32_##type
-#        else
-#          define ElfW(type) Elf64_##type
-#        endif
+#      if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
+#        define ElfW(type) Elf32_##type
 #      else
-#        if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
-#          define ElfW(type) Elf32_##type
-#        else
-#          define ElfW(type) Elf64_##type
-#       endif
+#        define ElfW(type) Elf64_##type
 #      endif
 #    endif
 #  endif
 
-#if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
+#if defined(SOLARISDL) && !defined(USE_PROC_FOR_LIBRARIES)
 
 #ifdef LINT
     Elf32_Dyn _DYNAMIC;
@@ -168,59 +163,17 @@ GC_FirstDLOpenedLinkMap()
     return cachedResult;
 }
 
-#endif /* SUNOS5DL ... */
+#endif /* SOLARISDL ... */
 
 /* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
 # if defined(GC_must_restore_redefined_dlopen)
 #   define dlopen GC_dlopen
 # endif
 
-#if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
-
-#ifdef LINT
-    struct link_dynamic _DYNAMIC;
-#endif
-
-static struct link_map *
-GC_FirstDLOpenedLinkMap()
-{
-    extern struct link_dynamic _DYNAMIC;
-
-    if( &_DYNAMIC == 0) {
-        return(0);
-    }
-    return(_DYNAMIC.ld_un.ld_1->ld_loaded);
-}
-
-/* Return the address of the ld.so allocated common symbol     */
-/* with the least address, or 0 if none.                       */
-static ptr_t GC_first_common()
-{
-    ptr_t result = 0;
-    extern struct link_dynamic _DYNAMIC;
-    struct rtc_symb * curr_symbol;
-    
-    if( &_DYNAMIC == 0) {
-        return(0);
-    }
-    curr_symbol = _DYNAMIC.ldd -> ldd_cp;
-    for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) {
-        if (result == 0
-            || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) {
-            result = (ptr_t)(curr_symbol -> rtc_sp -> n_value);
-        }
-    }
-    return(result);
-}
-
-#endif  /* SUNOS4 ... */
-
-# if defined(SUNOS4) || defined(SUNOS5DL)
+# if defined(SOLARISDL)
 /* Add dynamic library data sections to the root set.          */
 # if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
-#   ifndef SRC_M3
        --> fix mutual exclusion with dlopen
-#   endif  /* We assume M3 programs don't call dlopen for now */
 # endif
 
 # ifndef USE_PROC_FOR_LIBRARIES
@@ -232,16 +185,6 @@ void GC_register_dynamic_libraries()
   for (lm = GC_FirstDLOpenedLinkMap();
        lm != (struct link_map *) 0;  lm = lm->l_next)
     {
-#     ifdef SUNOS4
-       struct exec *e;
-        
-        e = (struct exec *) lm->lm_addr;
-        GC_add_roots_inner(
-                   ((char *) (N_DATOFF(*e) + lm->lm_addr)),
-                   ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)),
-                   TRUE);
-#     endif
-#     ifdef SUNOS5DL
        ElfW(Ehdr) * e;
         ElfW(Phdr) * p;
         unsigned long offset;
@@ -268,25 +211,11 @@ void GC_register_dynamic_libraries()
               break;
           }
        }
-#     endif
     }
-#   ifdef SUNOS4
-      {
-       static ptr_t common_start = 0;
-       ptr_t common_end;
-       extern ptr_t GC_find_limit();
-       
-       if (common_start == 0) common_start = GC_first_common();
-       if (common_start != 0) {
-           common_end = GC_find_limit(common_start, TRUE);
-           GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE);
-       }
-      }
-#   endif
 }
 
 # endif /* !USE_PROC ... */
-# endif /* SUNOS */
+# endif /* SOLARISDL */
 
 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
     (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
@@ -307,47 +236,62 @@ extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
        /* Repeatedly read until buffer is filled, or EOF is encountered */
        /* Defined in os_dep.c.                                          */
 
-char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
-                         char *prot_buf, unsigned int *maj_dev);
-word GC_apply_to_maps(word (*fn)(char *));
+char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
+                         char **prot, unsigned int *maj_dev,
+                        char **mapping_name);
+char *GC_get_maps(void);
        /* From os_dep.c        */
 
 word GC_register_map_entries(char *maps)
 {
-    char prot_buf[5];
+    char *prot;
     char *buf_ptr = maps;
     int count;
-    word start, end;
+    ptr_t start, end;
     unsigned int maj_dev;
-    word least_ha, greatest_ha;
+    ptr_t least_ha, greatest_ha;
     unsigned i;
-    word datastart = (word)(DATASTART);
+    ptr_t datastart = (ptr_t)(DATASTART);
 
-    /* Compute heap bounds. FIXME: Should be done by add_to_heap?      */
-       least_ha = (word)(-1);
+    /* Compute heap bounds. FIXME: Should work if heap and roots are   */
+    /* interleaved?                                                    */
+       least_ha = (ptr_t)(word)(-1);
        greatest_ha = 0;
        for (i = 0; i < GC_n_heap_sects; ++i) {
-           word sect_start = (word)GC_heap_sects[i].hs_start;
-           word sect_end = sect_start + GC_heap_sects[i].hs_bytes;
+           ptr_t sect_start = GC_heap_sects[i].hs_start;
+           ptr_t sect_end = sect_start + GC_heap_sects[i].hs_bytes;
            if (sect_start < least_ha) least_ha = sect_start;
            if (sect_end > greatest_ha) greatest_ha = sect_end;
         }
-       if (greatest_ha < (word)GC_scratch_last_end_ptr)
-           greatest_ha = (word)GC_scratch_last_end_ptr; 
+       if (greatest_ha < (ptr_t)GC_scratch_last_end_ptr)
+           greatest_ha = (ptr_t)GC_scratch_last_end_ptr; 
 
     for (;;) {
-        buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
+        buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot, &maj_dev, 0);
        if (buf_ptr == NULL) return 1;
-       if (prot_buf[1] == 'w') {
+       if (prot[1] == 'w') {
            /* This is a writable mapping.  Add it to           */
            /* the root set unless it is already otherwise      */
            /* accounted for.                                   */
-           if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) {
+           if (start <= GC_stackbottom && end >= GC_stackbottom) {
                /* Stack mapping; discard       */
                continue;
            }
 #          ifdef THREADS
+             /* This may fail, since a thread may already be           */
+             /* unregistered, but its thread stack may still be there. */
+             /* That can fail because the stack may disappear while    */
+             /* we're marking.  Thus the marker is, and has to be      */
+             /* prepared to recover from segmentation faults.          */
              if (GC_segment_is_thread_stack(start, end)) continue;
+             /* FIXME: REDIRECT_MALLOC actually works with threads on  */
+             /* LINUX/IA64 if we omit this check.  The problem is that */
+             /* thread stacks contain pointers to dynamic thread       */
+             /* vectors, which may be reused due to thread caching.    */
+             /* Currently they may not be marked if the thread is      */
+             /* still live.                                            */
+             /* For dead threads, we trace the whole stack, which is   */
+             /* very suboptimal for performance reasons.               */
 #          endif
            /* We no longer exclude the main data segment.              */
            if (start < least_ha && end > least_ha) {
@@ -365,14 +309,14 @@ word GC_register_map_entries(char *maps)
 
 void GC_register_dynamic_libraries()
 {
-   if (!GC_apply_to_maps(GC_register_map_entries))
-       ABORT("Failed to read /proc for library registration.");
+    if (!GC_register_map_entries(GC_get_maps()))
+        ABORT("Failed to read /proc for library registration.");
 }
 
 /* We now take care of the main data segment ourselves: */
 GC_bool GC_register_main_static_data()
 {
-  return FALSE;
+    return FALSE;
 }
   
 # define HAVE_REGISTER_MAIN_STATIC_DATA
@@ -414,6 +358,11 @@ static int GC_register_dynlib_callback(info, size, ptr)
        {
          if( !(p->p_flags & PF_W) ) break;
          start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
+
+         if (GC_has_static_roots
+             && !GC_has_static_roots(info->dlpi_name, start, p->p_memsz))
+           break;
+
          GC_add_roots_inner(start, start + p->p_memsz, TRUE);
        }
       break;
@@ -504,12 +453,6 @@ GC_FirstDLOpenedLinkMap()
     if( cachedResult == 0 ) {
         int tag;
         for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
-           /* FIXME: The DT_DEBUG header is not mandated by the        */
-           /* ELF spec.  This code appears to be dependent on          */
-           /* idiosynchracies of older GNU tool chains.  If this code  */
-           /* fails for you, the real problem is probably that it is   */
-           /* being used at all.  You should be getting the            */
-           /* dl_iterate_phdr version.                                 */
             if( tag == DT_DEBUG ) {
                 struct link_map *lm
                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
@@ -592,16 +535,16 @@ void GC_register_dynamic_libraries()
     static prmap_t * addr_map = 0;
     static int current_sz = 0; /* Number of records currently in addr_map */
     static int needed_sz;      /* Required size of addr_map            */
-    register int i;
-    register long flags;
-    register ptr_t start;
-    register ptr_t limit;
+    int i;
+    long flags;
+    ptr_t start;
+    ptr_t limit;
     ptr_t heap_start = (ptr_t)HEAP_START;
     ptr_t heap_end = heap_start;
 
-#   ifdef SUNOS5DL
+#   ifdef SOLARISDL
 #     define MA_PHYS 0
-#   endif /* SUNOS5DL */
+#   endif /* SOLARISDL */
 
     if (fd < 0) {
       sprintf(buf, "/proc/%d", getpid());
@@ -613,7 +556,7 @@ void GC_register_dynamic_libraries()
       }
     }
     if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
-       GC_err_printf2("fd = %d, errno = %d\n", fd, errno);
+       GC_err_printf("fd = %d, errno = %d\n", fd, errno);
        ABORT("/proc PIOCNMAP ioctl failed");
     }
     if (needed_sz >= current_sz) {
@@ -623,7 +566,7 @@ void GC_register_dynamic_libraries()
                                                (current_sz * sizeof(prmap_t)));
     }
     if (ioctl(fd, PIOCMAP, addr_map) < 0) {
-        GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
+        GC_err_printf("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
                         fd, errno, needed_sz, addr_map);
        ABORT("/proc PIOCMAP ioctl failed");
     };
@@ -634,7 +577,7 @@ void GC_register_dynamic_libraries()
     }
     for (i = 0; i < needed_sz; i++) {
         flags = addr_map[i].pr_mflags;
-        if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
+       if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
                      | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
         if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
             goto irrelevant;
@@ -696,7 +639,7 @@ void GC_register_dynamic_libraries()
 
 # endif /* USE_PROC || IRIX5 */
 
-# if defined(MSWIN32) || defined(MSWINCE)
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
 
 # define WIN32_LEAN_AND_MEAN
 # define NOSERVICE
@@ -757,90 +700,13 @@ void GC_register_dynamic_libraries()
   
 # define HAVE_REGISTER_MAIN_STATIC_DATA
 
-  /* The frame buffer testing code is dead in this version.    */
-  /* We leave it here temporarily in case the switch to just   */
-  /* testing for MEM_IMAGE sections causes un expected                 */
-  /* problems.                                                 */
-  GC_bool GC_warn_fb = TRUE;   /* Warn about traced likely     */
-                               /* graphics memory.             */
-  GC_bool GC_disallow_ignore_fb = FALSE;
-  int GC_ignore_fb_mb; /* Ignore mappings bigger than the      */
-                       /* specified number of MB.              */
-  GC_bool GC_ignore_fb = FALSE; /* Enable frame buffer         */
-                               /* checking.            */
-  
-  /* Issue warning if tracing apparent framebuffer.            */
-  /* This limits us to one warning, and it's a back door to    */
-  /* disable that.                                             */
-  /* Should [start, start+len) be treated as a frame buffer    */
-  /* and ignored?                                              */
-  /* Unfortunately, we currently are not quite sure how to tell        */
-  /* this automatically, and rely largely on user input.       */
-  /* We expect that any mapping with type MEM_MAPPED (which    */
-  /* apparently excludes library data sections) can be safely  */
-  /* ignored.  But we're too completely remove this code in    */
-  /* this version.                                             */
-  /* Based on a very limited sample, it appears that:          */
-  /*   - Frame buffer mappings appear as mappings of large     */
-  /*     length, usually a bit less than a power of two.       */
-  /*   - The definition of "a bit less" in the above cannot    */
-  /*     be made more precise.                                 */
-  /*   - Have a starting address at best 64K aligned.          */
-  /*   - Have type == MEM_MAPPED.                              */
-  static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp)
-  {
-    static GC_bool initialized = FALSE;
-#   define MB (1024*1024)
-#   define DEFAULT_FB_MB 15
-#   define MIN_FB_MB 3
-
-    if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
-    if (!initialized) {
-      char * ignore_fb_string =  GETENV("GC_IGNORE_FB");
-
-      if (0 != ignore_fb_string) {
-       while (*ignore_fb_string == ' ' || *ignore_fb_string == '\t')
-         ++ignore_fb_string;
-       if (*ignore_fb_string == '\0') {
-         GC_ignore_fb_mb = DEFAULT_FB_MB;
-       } else {
-         GC_ignore_fb_mb = atoi(ignore_fb_string);
-         if (GC_ignore_fb_mb < MIN_FB_MB) {
-           WARN("Bad GC_IGNORE_FB value.  Using %ld\n", DEFAULT_FB_MB);
-           GC_ignore_fb_mb = DEFAULT_FB_MB;
-         }
-       }
-       GC_ignore_fb = TRUE;
-      } else {
-       GC_ignore_fb_mb = DEFAULT_FB_MB;  /* For warning */
-      }
-      initialized = TRUE;
-    }
-    if (len >= ((size_t)GC_ignore_fb_mb << 20)) {
-      if (GC_ignore_fb) {
-       return TRUE;
-      } else {
-       if (GC_warn_fb) {
-         WARN("Possible frame buffer mapping at 0x%lx: \n"
-              "\tConsider setting GC_IGNORE_FB to improve performance.\n",
-              start);
-         GC_warn_fb = FALSE;
-       }
-       return FALSE;
-      }
-    } else {
-      return FALSE;
-    }
-  }
-
 # ifdef DEBUG_VIRTUALQUERY
   void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
   {
-    GC_printf4("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
+    GC_printf("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
               buf -> BaseAddress, buf -> AllocationBase, buf -> RegionSize,
               buf -> RegionSize);
-    GC_printf4("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
+    GC_printf("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
               "Type = %lx\n",
               buf -> AllocationProtect, buf -> State, buf -> Protect,
               buf -> Type);
@@ -853,7 +719,7 @@ void GC_register_dynamic_libraries()
   void GC_register_dynamic_libraries()
   {
     MEMORY_BASIC_INFORMATION buf;
-    DWORD result;
+    size_t result;
     DWORD protect;
     LPVOID p;
     char * base;
@@ -864,8 +730,8 @@ void GC_register_dynamic_libraries()
 #   endif
     base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
 #   if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
-    /* Only the first 32 MB of address space belongs to the current process */
-    while (p < (LPVOID)0x02000000) {
+      /* Only the first 32 MB of address space belongs to the current process */
+      while (p < (LPVOID)0x02000000) {
         result = VirtualQuery(p, &buf, sizeof(buf));
        if (result == 0) {
            /* Page is free; advance to the next possible allocation base */
@@ -874,7 +740,7 @@ void GC_register_dynamic_libraries()
                 & ~(GC_sysinfo.dwAllocationGranularity-1));
        } else
 #   else
-    while (p < GC_sysinfo.lpMaximumApplicationAddress) {
+      while (p < GC_sysinfo.lpMaximumApplicationAddress) {
         result = VirtualQuery(p, &buf, sizeof(buf));
 #   endif
        {
@@ -887,16 +753,12 @@ void GC_register_dynamic_libraries()
                && (protect == PAGE_EXECUTE_READWRITE
                    || protect == PAGE_READWRITE)
                && !GC_is_heap_base(buf.AllocationBase)
-               /* This used to check for
-                * !is_frame_buffer(p, buf.RegionSize, buf.Type)
-                * instead of just checking for MEM_IMAGE.
-                * If something breaks, change it back. */
-               /* There is some evidence that we cannot always
-                * ignore MEM_PRIVATE sections under Windows ME
-                * and predecessors.  Hence we now also check for
-                * that case.   */
-               && (buf.Type == MEM_IMAGE ||
-                   !GC_wnt && buf.Type == MEM_PRIVATE)) {  
+               /* There is some evidence that we cannot always
+                * ignore MEM_PRIVATE sections under Windows ME
+                * and predecessors.  Hence we now also check for
+                * that case.   */
+               && (buf.Type == MEM_IMAGE ||
+                   !GC_wnt && buf.Type == MEM_PRIVATE)) {
 #              ifdef DEBUG_VIRTUALQUERY
                  GC_dump_meminfo(&buf);
 #              endif
@@ -913,7 +775,7 @@ void GC_register_dynamic_libraries()
     GC_cond_add_roots(base, limit);
   }
 
-#endif /* MSWIN32 || MSWINCE */
+#endif /* MSWIN32 || MSWINCE || CYGWIN32 */
   
 #if defined(ALPHA) && defined(OSF1)
 
@@ -952,15 +814,15 @@ void GC_register_dynamic_libraries()
       /* Check status AFTER checking moduleid because */
       /* of a bug in the non-shared ldr_next_module stub */
         if (status != 0 ) {
-            GC_printf1("dynamic_load: status = %ld\n", (long)status);
+            GC_printf("dynamic_load: status = %d\n", status);
             {
                 extern char *sys_errlist[];
                 extern int sys_nerr;
                 extern int errno;
                 if (errno <= sys_nerr) {
-                    GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
+                    GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
                } else {
-                    GC_printf1("dynamic_load: %d\n", (long)errno);
+                    GC_printf("dynamic_load: %d\n", errno);
                 }
         }
             ABORT("ldr_next_module failed");
@@ -976,7 +838,7 @@ void GC_register_dynamic_libraries()
           if (moduleinfo.lmi_flags & LDR_MAIN)
               continue;    /* skip the main module */
 
-#     ifdef VERBOSE
+#     ifdef DL_VERBOSE
           GC_printf("---Module---\n");
           GC_printf("Module ID            = %16ld\n", moduleinfo.lmi_modid);
           GC_printf("Count of regions     = %16d\n", moduleinfo.lmi_nregion);
@@ -997,7 +859,7 @@ void GC_register_dynamic_libraries()
             if (! (regioninfo.lri_prot & LDR_W))
                 continue;
 
-#         ifdef VERBOSE
+#         ifdef DL_VERBOSE
               GC_printf("--- Region ---\n");
               GC_printf("Region number    = %16ld\n",
                        regioninfo.lri_region_no);
@@ -1024,7 +886,6 @@ void GC_register_dynamic_libraries()
 #include <errno.h>
 #include <dl.h>
 
-extern int errno;
 extern char *sys_errlist[];
 extern int sys_nerr;
 
@@ -1051,26 +912,26 @@ void GC_register_dynamic_libraries()
               break; /* Moved past end of shared library list --> finished */
           } else {
               if (errno <= sys_nerr) {
-                    GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
+                    GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
               } else {
-                    GC_printf1("dynamic_load: %d\n", (long) errno);
+                    GC_printf("dynamic_load: %d\n", errno);
              }
               ABORT("shl_get failed");
           }
 #       endif
         }
 
-#     ifdef VERBOSE
-          GC_printf0("---Shared library---\n");
-          GC_printf1("\tfilename        = \"%s\"\n", shl_desc->filename);
-          GC_printf1("\tindex           = %d\n", index);
-          GC_printf1("\thandle          = %08x\n",
+#     ifdef DL_VERBOSE
+          GC_printf("---Shared library---\n");
+          GC_printf("\tfilename        = \"%s\"\n", shl_desc->filename);
+          GC_printf("\tindex           = %d\n", index);
+          GC_printf("\thandle          = %08x\n",
                                        (unsigned long) shl_desc->handle);
-          GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
-          GC_printf1("\ttext seg. end   = %08x\n", shl_desc->tend);
-          GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
-          GC_printf1("\tdata seg. end   = %08x\n", shl_desc->dend);
-          GC_printf1("\tref. count      = %lu\n", shl_desc->ref_count);
+          GC_printf("\ttext seg. start = %08x\n", shl_desc->tstart);
+          GC_printf("\ttext seg. end   = %08x\n", shl_desc->tend);
+          GC_printf("\tdata seg. start = %08x\n", shl_desc->dstart);
+          GC_printf("\tdata seg. end   = %08x\n", shl_desc->dend);
+          GC_printf("\tref. count      = %lu\n", shl_desc->ref_count);
 #     endif
 
       /* register shared library's data segment as a garbage collection root */
@@ -1082,7 +943,7 @@ void GC_register_dynamic_libraries()
 }
 #endif /* HPUX */
 
-#ifdef RS6000
+#ifdef AIX
 #pragma alloca
 #include <sys/ldr.h>
 #include <sys/errno.h>
@@ -1113,7 +974,7 @@ void GC_register_dynamic_libraries()
                ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
        }
 }
-#endif /* RS6000 */
+#endif /* AIX */
 
 #ifdef DARWIN
 
@@ -1139,7 +1000,7 @@ const static struct {
 };
     
 #ifdef DARWIN_DEBUG
-static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
+static const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr) {
     unsigned long i,c;
     c = _dyld_image_count();
     for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
@@ -1149,45 +1010,58 @@ static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
 #endif
         
 /* This should never be called by a thread holding the lock */
-static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
+static void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr, intptr_t slide)
+{
     unsigned long start,end,i;
-    const struct section *sec;
+    const struct GC_MACH_SECTION *sec;
     if (GC_no_dls) return;
     for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
-        sec = getsectbynamefromheader(
-            hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
-        if(sec == NULL || sec->size == 0) continue;
-        start = slide + sec->addr;
-        end = start + sec->size;
-#      ifdef DARWIN_DEBUG
-            GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
-                start,end,sec->size,GC_dyld_name_for_hdr(hdr));
-#       endif
-        GC_add_roots((char*)start,(char*)end);
+#   if defined (__LP64__)
+      sec = getsectbynamefromheader_64(
+#   else
+      sec = getsectbynamefromheader(
+#   endif
+                                   hdr, GC_dyld_sections[i].seg,
+                                   GC_dyld_sections[i].sect);
+      if(sec == NULL || sec->size == 0) continue;
+      start = slide + sec->addr;
+      end = start + sec->size;
+#   ifdef DARWIN_DEBUG
+      GC_printf("Adding section at %p-%p (%lu bytes) from image %s\n",
+               start,end,sec->size,GC_dyld_name_for_hdr(hdr));
+#   endif
+      GC_add_roots((char*)start,(char*)end);
     }
 #   ifdef DARWIN_DEBUG
-        GC_print_static_roots();
+       GC_print_static_roots();
 #   endif
 }
 
 /* This should never be called by a thread holding the lock */
-static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
+static void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
+                                intptr_t slide)
+{
     unsigned long start,end,i;
-    const struct section *sec;
+    const struct GC_MACH_SECTION *sec;
     for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
-        sec = getsectbynamefromheader(
-            hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
-        if(sec == NULL || sec->size == 0) continue;
-        start = slide + sec->addr;
-        end = start + sec->size;
-#      ifdef DARWIN_DEBUG
-            GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
-                start,end,sec->size,GC_dyld_name_for_hdr(hdr));
-#              endif
-        GC_remove_roots((char*)start,(char*)end);
+#   if defined (__LP64__)
+      sec = getsectbynamefromheader_64(
+#   else
+      sec = getsectbynamefromheader(
+#   endif
+                                   hdr, GC_dyld_sections[i].seg,
+                                   GC_dyld_sections[i].sect);
+      if(sec == NULL || sec->size == 0) continue;
+      start = slide + sec->addr;
+      end = start + sec->size;
+#   ifdef DARWIN_DEBUG
+      GC_printf("Removing section at %p-%p (%lu bytes) from image %s\n",
+               start,end,sec->size,GC_dyld_name_for_hdr(hdr));
+#   endif
+      GC_remove_roots((char*)start,(char*)end);
     }
 #   ifdef DARWIN_DEBUG
-        GC_print_static_roots();
+       GC_print_static_roots();
 #   endif
 }
 
@@ -1209,7 +1083,7 @@ void GC_init_dyld() {
   if(initialized) return;
   
 #   ifdef DARWIN_DEBUG
-  GC_printf0("Registering dyld callbacks...\n");
+      GC_printf("Registering dyld callbacks...\n");
 #   endif
   
   /* Apple's Documentation:
@@ -1233,7 +1107,7 @@ void GC_init_dyld() {
     
     if (bind_fully_env == NULL) {
 #   ifdef DARWIN_DEBUG
-      GC_printf0("Forcing full bind of GC code...\n");
+      GC_printf("Forcing full bind of GC code...\n");
 #   endif
       
       if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
@@ -1307,5 +1181,13 @@ GC_bool GC_register_main_static_data()
 {
   return TRUE;
 }
+
+/* Register a routine to filter dynamic library registration.  */
+void
+GC_register_has_static_roots_callback
+  (int (*callback)(const char *, void *, size_t)) {
+  GC_has_static_roots = callback;
+}
+
 #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
 
index d99123db492e53470efffa9c282a560b6531163e..fc11eaa9f78544d1506c8e0873c6d9f2d24e844f 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (C) 2007 Free Software Foundation, Inc
 
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -88,7 +89,7 @@ static signed_word log_fo_table_size = -1;
 
 word GC_fo_entries = 0;
 
-void GC_push_finalizer_structures GC_PROTO((void))
+void GC_push_finalizer_structures(void)
 {
     GC_push_all((ptr_t)(&dl_head), (ptr_t)(&dl_head) + sizeof(word));
     GC_push_all((ptr_t)(&fo_head), (ptr_t)(&fo_head) + sizeof(word));
@@ -101,16 +102,16 @@ void GC_push_finalizer_structures GC_PROTO((void))
 /* *table is a pointer to an array of hash headers.  If we succeed, we */
 /* update both *table and *log_size_ptr.                               */
 /* Lock is held.  Signals are disabled.                                        */
-void GC_grow_table(table, log_size_ptr)
-struct hash_chain_entry ***table;
-signed_word * log_size_ptr;
+void GC_grow_table(struct hash_chain_entry ***table,
+                  signed_word *log_size_ptr)
 {
     register word i;
     register struct hash_chain_entry *p;
-    int log_old_size = *log_size_ptr;
-    register int log_new_size = log_old_size + 1;
+    signed_word log_old_size = *log_size_ptr;
+    signed_word log_new_size = log_old_size + 1;
     word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
-    register word new_size = 1 << log_new_size;
+    word new_size = (word)1 << log_new_size;
+    /* FIXME: Power of 2 size often gets rounded up to one more page. */
     struct hash_chain_entry **new_table = (struct hash_chain_entry **)
        GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
                (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
@@ -125,9 +126,9 @@ signed_word * log_size_ptr;
     for (i = 0; i < old_size; i++) {
       p = (*table)[i];
       while (p != 0) {
-        register ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
-        register struct hash_chain_entry *next = p -> next;
-        register int new_hash = HASH3(real_key, new_size, log_new_size);
+        ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
+        struct hash_chain_entry *next = p -> next;
+        size_t new_hash = HASH3(real_key, new_size, log_new_size);
         
         p -> next = new_table[new_hash];
         new_table[new_hash] = p;
@@ -138,58 +139,36 @@ signed_word * log_size_ptr;
     *table = new_table;
 }
 
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_register_disappearing_link(GC_PTR * link)
-# else
-    int GC_register_disappearing_link(link)
-    GC_PTR * link;
-# endif
+int GC_register_disappearing_link(void * * link)
 {
     ptr_t base;
     
-    base = (ptr_t)GC_base((GC_PTR)link);
+    base = (ptr_t)GC_base((void *)link);
     if (base == 0)
        ABORT("Bad arg to GC_register_disappearing_link");
     return(GC_general_register_disappearing_link(link, base));
 }
 
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_general_register_disappearing_link(GC_PTR * link,
-                                             GC_PTR obj)
-# else
-    int GC_general_register_disappearing_link(link, obj)
-    GC_PTR * link;
-    GC_PTR obj;
-# endif
-
+int GC_general_register_disappearing_link(void * * link, void * obj)
 {
     struct disappearing_link *curr_dl;
-    int index;
+    size_t index;
     struct disappearing_link * new_dl;
     DCL_LOCK_STATE;
     
     if ((word)link & (ALIGNMENT-1))
        ABORT("Bad arg to GC_general_register_disappearing_link");
 #   ifdef THREADS
-       DISABLE_SIGNALS();
        LOCK();
 #   endif
     if (log_dl_table_size == -1
         || GC_dl_entries > ((word)1 << log_dl_table_size)) {
-#      ifndef THREADS
-           DISABLE_SIGNALS();
-#      endif
        GC_grow_table((struct hash_chain_entry ***)(&dl_head),
                      &log_dl_table_size);
-#      ifdef CONDPRINT
-         if (GC_print_stats) {
-           GC_printf1("Grew dl table to %lu entries\n",
-                       (unsigned long)(1 << log_dl_table_size));
-         }
-#      endif
-#      ifndef THREADS
-           ENABLE_SIGNALS();
-#      endif
+       if (GC_print_stats) {
+           GC_log_printf("Grew dl table to %u entries\n",
+                     (1 << log_dl_table_size));
+       }
     }
     index = HASH2(link, log_dl_table_size);
     curr_dl = dl_head[index];
@@ -198,7 +177,6 @@ signed_word * log_size_ptr;
             curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
 #          ifdef THREADS
                 UNLOCK();
-               ENABLE_SIGNALS();
 #          endif
             return(1);
         }
@@ -208,7 +186,6 @@ signed_word * log_size_ptr;
     if (0 == new_dl) {
 #     ifdef THREADS
        UNLOCK();
-       ENABLE_SIGNALS();
 #     endif
       new_dl = (struct disappearing_link *)
              GC_oom_fn(sizeof(struct disappearing_link));
@@ -218,7 +195,6 @@ signed_word * log_size_ptr;
       }
       /* It's not likely we'll make it here, but ... */
 #     ifdef THREADS
-        DISABLE_SIGNALS();
        LOCK();
 #     endif
     }
@@ -229,26 +205,19 @@ signed_word * log_size_ptr;
     GC_dl_entries++;
 #   ifdef THREADS
         UNLOCK();
-        ENABLE_SIGNALS();
 #   endif
     return(0);
 }
 
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_unregister_disappearing_link(GC_PTR * link)
-# else
-    int GC_unregister_disappearing_link(link)
-    GC_PTR * link;
-# endif
+int GC_unregister_disappearing_link(void * * link)
 {
     struct disappearing_link *curr_dl, *prev_dl;
-    int index;
+    size_t index;
     DCL_LOCK_STATE;
     
-    DISABLE_SIGNALS();
     LOCK();
     index = HASH2(link, log_dl_table_size);
-    if (((unsigned long)link & (ALIGNMENT-1))) goto out;
+    if (((word)link & (ALIGNMENT-1))) goto out;
     prev_dl = 0; curr_dl = dl_head[index];
     while (curr_dl != 0) {
         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
@@ -259,11 +228,10 @@ signed_word * log_size_ptr;
             }
             GC_dl_entries--;
             UNLOCK();
-           ENABLE_SIGNALS();
 #          ifdef DBG_HDRS_ALL
              dl_set_next(curr_dl, 0);
 #          else
-              GC_free((GC_PTR)curr_dl);
+              GC_free((void *)curr_dl);
 #          endif
             return(1);
         }
@@ -272,32 +240,29 @@ signed_word * log_size_ptr;
     }
 out:
     UNLOCK();
-    ENABLE_SIGNALS();
     return(0);
 }
 
 /* Possible finalization_marker procedures.  Note that mark stack      */
 /* overflow is handled by the caller, and is not a disaster.           */
-GC_API void GC_normal_finalize_mark_proc(p)
-ptr_t p;
+GC_API void GC_normal_finalize_mark_proc(ptr_t p)
 {
     hdr * hhdr = HDR(p);
     
-    PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
+    PUSH_OBJ(p, hhdr, GC_mark_stack_top,
             &(GC_mark_stack[GC_mark_stack_size]));
 }
 
 /* This only pays very partial attention to the mark descriptor.       */
 /* It does the right thing for normal and atomic objects, and treats   */
 /* most others as normal.                                              */
-GC_API void GC_ignore_self_finalize_mark_proc(p)
-ptr_t p;
+GC_API void GC_ignore_self_finalize_mark_proc(ptr_t p)
 {
     hdr * hhdr = HDR(p);
     word descr = hhdr -> hb_descr;
     ptr_t q, r;
     ptr_t scan_limit;
-    ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
+    ptr_t target_limit = p + hhdr -> hb_sz - 1;
     
     if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
        scan_limit = p + descr - sizeof(word);
@@ -307,17 +272,29 @@ ptr_t p;
     for (q = p; q <= scan_limit; q += ALIGNMENT) {
        r = *(ptr_t *)q;
        if (r < p || r > target_limit) {
-           GC_PUSH_ONE_HEAP((word)r, q);
+           GC_PUSH_ONE_HEAP(r, q);
        }
     }
 }
 
 /*ARGSUSED*/
-GC_API void GC_null_finalize_mark_proc(p)
-ptr_t p;
+GC_API void GC_null_finalize_mark_proc(ptr_t p)
 {
 }
 
+/* Possible finalization_marker procedures.  Note that mark stack      */
+/* overflow is handled by the caller, and is not a disaster.           */
+
+/* GC_unreachable_finalize_mark_proc is an alias for normal marking,   */
+/* but it is explicitly tested for, and triggers different             */
+/* behavior.  Objects registered in this way are not finalized         */
+/* if they are reachable by other finalizable objects, eve if those    */
+/* other objects specify no ordering.                                  */
+GC_API void GC_unreachable_finalize_mark_proc(ptr_t p)
+{
+    GC_normal_finalize_mark_proc(p);
+}
+
 
 
 /* Register a finalization function.  See gc.h for details.    */
@@ -328,41 +305,29 @@ ptr_t p;
 /* marking for finalization ordering.  Any objects marked      */
 /* by that procedure will be guaranteed to not have been       */
 /* finalized when this finalizer is invoked.                   */
-GC_API void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
-GC_PTR obj;
-GC_finalization_proc fn;
-GC_PTR cd;
-GC_finalization_proc * ofn;
-GC_PTR * ocd;
-finalization_mark_proc * mp;
+GC_API void GC_register_finalizer_inner(void * obj,
+                                       GC_finalization_proc fn, void *cd,
+                                       GC_finalization_proc *ofn, void **ocd,
+                                       finalization_mark_proc mp)
 {
     ptr_t base;
     struct finalizable_object * curr_fo, * prev_fo;
-    int index;
+    size_t index;
     struct finalizable_object *new_fo;
     hdr *hhdr;
     DCL_LOCK_STATE;
 
 #   ifdef THREADS
-       DISABLE_SIGNALS();
        LOCK();
 #   endif
     if (log_fo_table_size == -1
         || GC_fo_entries > ((word)1 << log_fo_table_size)) {
-#      ifndef THREADS
-           DISABLE_SIGNALS();
-#      endif
        GC_grow_table((struct hash_chain_entry ***)(&fo_head),
                      &log_fo_table_size);
-#      ifdef CONDPRINT
-         if (GC_print_stats) {
-           GC_printf1("Grew fo table to %lu entries\n",
-                       (unsigned long)(1 << log_fo_table_size));
-         }
-#      endif
-#      ifndef THREADS
-           ENABLE_SIGNALS();
-#      endif
+       if (GC_print_stats) {
+           GC_log_printf("Grew fo table to %u entries\n",
+                         (1 << log_fo_table_size));
+       }
     }
     /* in the THREADS case signals are disabled and we hold allocation */
     /* lock; otherwise neither is true.  Proceed carefully.            */
@@ -370,12 +335,13 @@ finalization_mark_proc * mp;
     index = HASH2(base, log_fo_table_size);
     prev_fo = 0; curr_fo = fo_head[index];
     while (curr_fo != 0) {
+        GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
         if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
             /* Interruption by a signal in the middle of this  */
             /* should be safe.  The client may see only *ocd   */
             /* updated, but we'll declare that to be his       */
             /* problem.                                                */
-            if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
+            if (ocd) *ocd = (void *) (curr_fo -> fo_client_data);
             if (ofn) *ofn = curr_fo -> fo_fn;
             /* Delete the structure for base. */
                 if (prev_fo == 0) {
@@ -389,7 +355,7 @@ finalization_mark_proc * mp;
                   /* estimate will only make the table larger than     */
                   /* necessary.                                                */
 #              if !defined(THREADS) && !defined(DBG_HDRS_ALL)
-                  GC_free((GC_PTR)curr_fo);
+                  GC_free((void *)curr_fo);
 #              endif
             } else {
                 curr_fo -> fo_fn = fn;
@@ -405,7 +371,6 @@ finalization_mark_proc * mp;
             }
 #          ifdef THREADS
                 UNLOCK();
-               ENABLE_SIGNALS();
 #          endif
             return;
         }
@@ -417,7 +382,6 @@ finalization_mark_proc * mp;
     if (fn == 0) {
 #      ifdef THREADS
             UNLOCK();
-           ENABLE_SIGNALS();
 #      endif
         return;
     }
@@ -426,16 +390,15 @@ finalization_mark_proc * mp;
       /* We won't collect it, hence finalizer wouldn't be run. */
 #     ifdef THREADS
           UNLOCK();
-         ENABLE_SIGNALS();
 #     endif
       return;
     }
     new_fo = (struct finalizable_object *)
        GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
-    if (0 == new_fo) {
+    GC_ASSERT(GC_size(new_fo) >= sizeof(struct finalizable_object));
+    if (EXPECT(0 == new_fo, FALSE)) {
 #     ifdef THREADS
        UNLOCK();
-       ENABLE_SIGNALS();
 #     endif
       new_fo = (struct finalizable_object *)
              GC_oom_fn(sizeof(struct finalizable_object));
@@ -445,7 +408,6 @@ finalization_mark_proc * mp;
       }
       /* It's not likely we'll make it here, but ... */
 #     ifdef THREADS
-        DISABLE_SIGNALS();
        LOCK();
 #     endif
     }
@@ -459,63 +421,48 @@ finalization_mark_proc * mp;
     fo_head[index] = new_fo;
 #   ifdef THREADS
         UNLOCK();
-       ENABLE_SIGNALS();
 #   endif
 }
 
-# if defined(__STDC__)
-    void GC_register_finalizer(void * obj,
+void GC_register_finalizer(void * obj,
                               GC_finalization_proc fn, void * cd,
                               GC_finalization_proc *ofn, void ** ocd)
-# else
-    void GC_register_finalizer(obj, fn, cd, ofn, ocd)
-    GC_PTR obj;
-    GC_finalization_proc fn;
-    GC_PTR cd;
-    GC_finalization_proc * ofn;
-    GC_PTR * ocd;
-# endif
 {
     GC_register_finalizer_inner(obj, fn, cd, ofn,
                                ocd, GC_normal_finalize_mark_proc);
 }
 
-# if defined(__STDC__)
-    void GC_register_finalizer_ignore_self(void * obj,
+void GC_register_finalizer_ignore_self(void * obj,
                               GC_finalization_proc fn, void * cd,
                               GC_finalization_proc *ofn, void ** ocd)
-# else
-    void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
-    GC_PTR obj;
-    GC_finalization_proc fn;
-    GC_PTR cd;
-    GC_finalization_proc * ofn;
-    GC_PTR * ocd;
-# endif
 {
     GC_register_finalizer_inner(obj, fn, cd, ofn,
                                ocd, GC_ignore_self_finalize_mark_proc);
 }
 
-# if defined(__STDC__)
-    void GC_register_finalizer_no_order(void * obj,
+void GC_register_finalizer_no_order(void * obj,
                               GC_finalization_proc fn, void * cd,
                               GC_finalization_proc *ofn, void ** ocd)
-# else
-    void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
-    GC_PTR obj;
-    GC_finalization_proc fn;
-    GC_PTR cd;
-    GC_finalization_proc * ofn;
-    GC_PTR * ocd;
-# endif
 {
     GC_register_finalizer_inner(obj, fn, cd, ofn,
                                ocd, GC_null_finalize_mark_proc);
 }
 
+static GC_bool need_unreachable_finalization = FALSE;
+       /* Avoid the work if this isn't used.   */
+
+void GC_register_finalizer_unreachable(void * obj,
+                              GC_finalization_proc fn, void * cd,
+                              GC_finalization_proc *ofn, void ** ocd)
+{
+    need_unreachable_finalization = TRUE;
+    GC_ASSERT(GC_java_finalization);
+    GC_register_finalizer_inner(obj, fn, cd, ofn,
+                               ocd, GC_unreachable_finalize_mark_proc);
+}
+
 #ifndef NO_DEBUGGING
-void GC_dump_finalization()
+void GC_dump_finalization(void)
 {
     struct disappearing_link * curr_dl;
     struct finalizable_object * curr_fo;
@@ -524,19 +471,19 @@ void GC_dump_finalization()
     int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
     int i;
 
-    GC_printf0("Disappearing links:\n");
+    GC_printf("Disappearing links:\n");
     for (i = 0; i < dl_size; i++) {
       for (curr_dl = dl_head[i]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
         real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
         real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
-        GC_printf2("Object: 0x%lx, Link:0x%lx\n", real_ptr, real_link);
+        GC_printf("Object: %p, Link:%p\n", real_ptr, real_link);
       }
     }
-    GC_printf0("Finalizers:\n");
+    GC_printf("Finalizers:\n");
     for (i = 0; i < fo_size; i++) {
       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
-        GC_printf1("Finalizable object: 0x%lx\n", real_ptr);
+        GC_printf("Finalizable object: %p\n", real_ptr);
       }
     }
 }
@@ -544,14 +491,14 @@ void GC_dump_finalization()
 
 /* Called with world stopped.  Cause disappearing links to disappear,  */
 /* and invoke finalizers.                                              */
-void GC_finalize()
+void GC_finalize(void)
 {
     struct disappearing_link * curr_dl, * prev_dl, * next_dl;
     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
     ptr_t real_ptr, real_link;
-    register int i;
-    int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
-    int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
+    size_t i;
+    size_t dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
+    size_t fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
     
   /* Make disappearing links disappear */
     for (i = 0; i < dl_size; i++) {
@@ -582,6 +529,7 @@ void GC_finalize()
     GC_ASSERT(GC_mark_state == MS_NONE);
     for (i = 0; i < fo_size; i++) {
       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
+        GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
         if (!GC_is_marked(real_ptr)) {
            GC_MARKED_FOR_FINALIZATION(real_ptr);
@@ -594,7 +542,7 @@ void GC_finalize()
     }
   /* Enqueue for finalization all objects that are still               */
   /* unreachable.                                                      */
-    GC_words_finalized = 0;
+    GC_bytes_finalized = 0;
     for (i = 0; i < fo_size; i++) {
       curr_fo = fo_head[i];
       prev_fo = 0;
@@ -619,9 +567,9 @@ void GC_finalize()
               /* see it.                                               */
               curr_fo -> fo_hidden_base = 
                        (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
-              GC_words_finalized +=
-                       ALIGNED_WORDS(curr_fo -> fo_object_size)
-                       + ALIGNED_WORDS(sizeof(struct finalizable_object));
+              GC_bytes_finalized +=
+                       curr_fo -> fo_object_size
+                       + sizeof(struct finalizable_object);
            GC_ASSERT(GC_is_marked(GC_base((ptr_t)curr_fo)));
             curr_fo = next_fo;
         } else {
@@ -641,9 +589,45 @@ void GC_finalize()
            if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
                GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
            }
-           GC_set_mark_bit(real_ptr);
+           if (curr_fo -> fo_mark_proc != GC_unreachable_finalize_mark_proc) {
+               GC_set_mark_bit(real_ptr);
+           }
        }
       }
+
+    /* now revive finalize-when-unreachable objects reachable from
+       other finalizable objects */
+      if (need_unreachable_finalization) {
+        curr_fo = GC_finalize_now;
+        prev_fo = 0;
+        while (curr_fo != 0) {
+         next_fo = fo_next(curr_fo);
+         if (curr_fo -> fo_mark_proc == GC_unreachable_finalize_mark_proc) {
+           real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
+           if (!GC_is_marked(real_ptr)) {
+             GC_set_mark_bit(real_ptr);
+           } else {
+             if (prev_fo == 0)
+               GC_finalize_now = next_fo;
+             else
+               fo_set_next(prev_fo, next_fo);
+
+              curr_fo -> fo_hidden_base =
+                       (word) HIDE_POINTER(curr_fo -> fo_hidden_base);
+              GC_bytes_finalized -=
+                       curr_fo -> fo_object_size + sizeof(struct finalizable_object);
+
+             i = HASH2(real_ptr, log_fo_table_size);
+             fo_set_next (curr_fo, fo_head[i]);
+             GC_fo_entries++;
+             fo_head[i] = curr_fo;
+             curr_fo = prev_fo;
+           }
+         }
+         prev_fo = curr_fo;
+         curr_fo = next_fo;
+        }
+      }
   }
 
   /* Remove dangling disappearing links. */
@@ -674,7 +658,7 @@ void GC_finalize()
 
 /* Enqueue all remaining finalizers to be run - Assumes lock is
  * held, and signals are disabled */
-void GC_enqueue_all_finalizers()
+void GC_enqueue_all_finalizers(void)
 {
     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
     ptr_t real_ptr;
@@ -682,7 +666,7 @@ void GC_enqueue_all_finalizers()
     int fo_size;
     
     fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
-    GC_words_finalized = 0;
+    GC_bytes_finalized = 0;
     for (i = 0; i < fo_size; i++) {
         curr_fo = fo_head[i];
         prev_fo = 0;
@@ -709,9 +693,8 @@ void GC_enqueue_all_finalizers()
           curr_fo -> fo_hidden_base = 
                        (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
 
-          GC_words_finalized +=
-               ALIGNED_WORDS(curr_fo -> fo_object_size)
-                       + ALIGNED_WORDS(sizeof(struct finalizable_object));
+          GC_bytes_finalized +=
+               curr_fo -> fo_object_size + sizeof(struct finalizable_object);
           curr_fo = next_fo;
         }
     }
@@ -733,55 +716,50 @@ void GC_enqueue_all_finalizers()
  * This routine is externally callable, so is called without 
  * the allocation lock. 
  */
-GC_API void GC_finalize_all()
+GC_API void GC_finalize_all(void)
 {
     DCL_LOCK_STATE;
 
-    DISABLE_SIGNALS();
     LOCK();
     while (GC_fo_entries > 0) {
       GC_enqueue_all_finalizers();
       UNLOCK();
-      ENABLE_SIGNALS();
       GC_INVOKE_FINALIZERS();
-      DISABLE_SIGNALS();
       LOCK();
     }
     UNLOCK();
-    ENABLE_SIGNALS();
 }
 #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))
+int GC_should_invoke_finalizers(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()
+int GC_invoke_finalizers(void)
 {
     struct finalizable_object * curr_fo;
     int count = 0;
-    word mem_freed_before;
+    word bytes_freed_before;
     DCL_LOCK_STATE;
     
     while (GC_finalize_now != 0) {
 #      ifdef THREADS
-           DISABLE_SIGNALS();
            LOCK();
 #      endif
        if (count == 0) {
-           mem_freed_before = GC_mem_freed;
+           bytes_freed_before = GC_bytes_freed;
+           /* Don't do this outside, since we need the lock. */
        }
        curr_fo = GC_finalize_now;
 #      ifdef THREADS
            if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
            UNLOCK();
-           ENABLE_SIGNALS();
            if (curr_fo == 0) break;
 #      else
            GC_finalize_now = fo_next(curr_fo);
@@ -795,22 +773,23 @@ int GC_invoke_finalizers()
            /* This is probably a bad idea.  It throws off accounting if */
            /* nearly all objects are finalizable.  O.w. it shouldn't    */
            /* matter.                                                   */
-           GC_free((GC_PTR)curr_fo);
+           GC_free((void *)curr_fo);
 #      endif
     }
-    if (count != 0 && mem_freed_before != GC_mem_freed) {
+    /* bytes_freed_before is initialized whenever count != 0 */
+    if (count != 0 && bytes_freed_before != GC_bytes_freed) {
         LOCK();
-       GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
+       GC_finalizer_bytes_freed += (GC_bytes_freed - bytes_freed_before);
        UNLOCK();
     }
     return count;
 }
 
-void (* GC_finalizer_notifier)() = (void (*) GC_PROTO((void)))0;
+void (* GC_finalizer_notifier)() = (void (*) (void))0;
 
 static GC_word last_finalizer_notification = 0;
 
-void GC_notify_or_invoke_finalizers GC_PROTO((void))
+void GC_notify_or_invoke_finalizers(void)
 {
     /* This is a convenient place to generate backtraces if appropriate, */
     /* since that code is not callable with the allocation lock.        */
@@ -819,10 +798,10 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void))
 
       if (GC_gc_no > last_back_trace_gc_no) {
        word i;
-
+  
 #      ifdef KEEP_BACK_PTRS
          LOCK();
-         /* Stops when GC_gc_no wraps; that's OK.      */
+         /* Stops when GC_gc_no wraps; that's OK.      */
          last_back_trace_gc_no = (word)(-1);  /* disable others. */
          for (i = 0; i < GC_backtraces; ++i) {
              /* FIXME: This tolerates concurrent heap mutation,        */
@@ -850,28 +829,21 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void))
 #      endif   /* Otherwise GC can run concurrently and add more */
        return;
     }
-    if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
+    if (GC_finalizer_notifier != (void (*) (void))0
        && last_finalizer_notification != GC_gc_no) {
        last_finalizer_notification = GC_gc_no;
        GC_finalizer_notifier();
     }
 }
 
-# ifdef __STDC__
-    GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
-                                        GC_PTR client_data)
-# else
-    GC_PTR GC_call_with_alloc_lock(fn, client_data)
-    GC_fn_type fn;
-    GC_PTR client_data;
-# endif
+void * GC_call_with_alloc_lock(GC_fn_type fn, void * client_data)
 {
-    GC_PTR result;
+    void * result;
     DCL_LOCK_STATE;
     
 #   ifdef THREADS
-      DISABLE_SIGNALS();
       LOCK();
+      /* FIXME - This looks wrong!! */
       SET_LOCK_HOLDER();
 #   endif
     result = (*fn)(client_data);
@@ -880,22 +852,21 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void))
         UNSET_LOCK_HOLDER();
 #     endif /* o.w. UNLOCK() does it implicitly */
       UNLOCK();
-      ENABLE_SIGNALS();
 #   endif
     return(result);
 }
 
 #if !defined(NO_DEBUGGING)
 
-void GC_print_finalization_stats()
+void GC_print_finalization_stats(void)
 {
     struct finalizable_object *fo = GC_finalize_now;
     size_t ready = 0;
 
-    GC_printf2("%lu finalization table entries; %lu disappearing links\n",
+    GC_printf("%u finalization table entries; %u disappearing links\n",
               GC_fo_entries, GC_dl_entries);
     for (; 0 != fo; fo = fo_next(fo)) ++ready;
-    GC_printf1("%lu objects are eligible for immediate finalization\n", ready);
+    GC_printf("%u objects are eligible for immediate finalization\n", ready);
 }
 
 #endif /* NO_DEBUGGING */
index 5f0b5462427db7a24abf786c844b8ba97ecb2e29..5c02c9023c5627cfb46d9ebec1db1a507e863362 100644 (file)
@@ -5,6 +5,7 @@
 # TARGTYPE "Win32 (x86) Application" 0x0101
 # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
 
+AO_VERSION=1.2
 !IF "$(CFG)" == ""
 CFG=gctest - Win32 Release
 !MESSAGE No configuration specified.  Defaulting to cord - Win32 Debug.
@@ -108,16 +109,19 @@ CLEAN :
        -@erase ".\Release\typd_mlc.sbr"
        -@erase ".\Release\win32_threads.obj"
        -@erase ".\Release\win32_threads.sbr"
+       -@erase ".\Release\msvc_dbg.obj"
+       -@erase ".\Release\msvc_dbg.sbr"
 
 "$(OUTDIR)" :
     if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
 
 CPP=cl.exe
 # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "SILENT" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
-CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "SILENT" /D "GC_BUILD" /D\
+# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "GC_BUILD" /D\
  "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D\
- "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/" /c 
+ "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" \
+ /Ilibatomic_ops-$(AO_VERSION)/src /YX /Fo"$(INTDIR)/" /c 
 CPP_OBJS=.\Release/
 CPP_SBRS=.\Release/
 
@@ -173,6 +177,7 @@ BSC32_SBRS= \
        ".\Release\reclaim.sbr" \
        ".\Release\stubborn.sbr" \
        ".\Release\typd_mlc.sbr" \
+       ".\Release\msvc_dbg.sbr" \
        ".\Release\win32_threads.sbr"
 
 ".\Release\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
@@ -211,6 +216,7 @@ LINK32_OBJS= \
        ".\Release\reclaim.obj" \
        ".\Release\stubborn.obj" \
        ".\Release\typd_mlc.obj" \
+       ".\Release\msvc_dbg.obj" \
        ".\Release\win32_threads.obj"
 
 ".\Release\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -290,17 +296,20 @@ CLEAN :
        -@erase ".\Debug\vc40.pdb"
        -@erase ".\Debug\win32_threads.obj"
        -@erase ".\Debug\win32_threads.sbr"
+       -@erase ".\Debug\msvc_dbg.obj"
+       -@erase ".\Debug\msvc_dbg.sbr"
 
 "$(OUTDIR)" :
     if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
 
 CPP=cl.exe
 # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "SILENT" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
-CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "SILENT" /D "GC_BUILD"\
- /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D\
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "GC_BUILD"\
+ /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" \
+ /D "GC_ASSERTIONS" /D "__STDC__" /D\
  "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/"\
- /Fd"$(INTDIR)/" /c 
+ /Ilibatomic_ops-$(AO_VERSION)/src /Fd"$(INTDIR)/" /c 
 CPP_OBJS=.\Debug/
 CPP_SBRS=.\Debug/
 
@@ -356,6 +365,7 @@ BSC32_SBRS= \
        ".\Debug\reclaim.sbr" \
        ".\Debug\stubborn.sbr" \
        ".\Debug\typd_mlc.sbr" \
+       ".\Debug\msvc_dbg.sbr" \
        ".\Debug\win32_threads.sbr"
 
 ".\Debug\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
@@ -394,6 +404,7 @@ LINK32_OBJS= \
        ".\Debug\reclaim.obj" \
        ".\Debug\stubborn.obj" \
        ".\Debug\typd_mlc.obj" \
+       ".\Debug\msvc_dbg.obj" \
        ".\Debug\win32_threads.obj"
 
 ".\Debug\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -433,7 +444,8 @@ CPP=cl.exe
 # ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /YX /c
 CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
  "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS"\
- /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /c 
+ /Ilibatomic_ops-$(AO_VERSION)/src /Fp"$(INTDIR)/gctest.pch" \
+ /YX /Fo"$(INTDIR)/" /c 
 CPP_OBJS=.\gctest\Release/
 CPP_SBRS=.\.
 
@@ -519,7 +531,7 @@ CPP=cl.exe
 # ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
 CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
  /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR"$(INTDIR)/"\
- /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
+ /Ilibatomic_ops-$(AO_VERSION)/src /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
 CPP_OBJS=.\gctest\Debug/
 CPP_SBRS=.\gctest\Debug/
 
@@ -609,7 +621,7 @@ CPP=cl.exe
 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
 # ADD CPP /nologo /MD /W3 /GX /O2 /I "." /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
 CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "." /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
- "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c 
/Ilibatomic_ops-$(AO_VERSION)/src "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c 
 CPP_OBJS=.\cord\Release/
 CPP_SBRS=.\.
 
@@ -702,7 +714,7 @@ CPP=cl.exe
 # ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
 CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /I include /D "_DEBUG" /D "WIN32" /D\
  "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX\
- /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
+ /Ilibatomic_ops-$(AO_VERSION)/src /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
 CPP_OBJS=.\cord\Debug/
 CPP_SBRS=.\.
 
@@ -1862,6 +1874,56 @@ NODEP_CPP_WIN32=\
 ".\Debug\win32_threads.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
 
 
+!ENDIF 
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\msvc_dbg.c
+
+!IF  "$(CFG)" == "gc - Win32 Release"
+
+DEP_CPP_WIN32=\
+       ".\include\private\gcconfig.h"\
+       ".\include\gc.h"\
+       ".\include\private\gc_hdrs.h"\
+       ".\include\private\gc_priv.h"\
+       ".\include\private\msvc_dbg.h"\
+       {$(INCLUDE)}"\sys\TYPES.H"\
+       
+NODEP_CPP_WIN32=\
+       ".\th\PCR_Th.h"\
+       ".\th\PCR_ThCrSec.h"\
+       ".\th\PCR_ThCtl.h"\
+       
+
+".\Release\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+".\Release\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+
+!ELSEIF  "$(CFG)" == "gc - Win32 Debug"
+
+DEP_CPP_WIN32=\
+       ".\include\private\gcconfig.h"\
+       ".\include\gc.h"\
+       ".\include\private\gc_hdrs.h"\
+       ".\include\private\gc_priv.h"\
+       ".\include\private\msvc_dbg.h"\
+       {$(INCLUDE)}"\sys\TYPES.H"\
+       
+NODEP_CPP_WIN32=\
+       ".\th\PCR_Th.h"\
+       ".\th\PCR_ThCrSec.h"\
+       ".\th\PCR_ThCtl.h"\
+       
+
+".\Debug\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+".\Debug\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+
 !ENDIF 
 
 # End Source File
index f8b803a8baa42a1f59583e48cd7120866be31090..c4dc4cd2562647f3d0549d3432f42180c512f138 100644 (file)
@@ -57,5 +57,11 @@ void* operator new( size_t size,
 #endif
 }
 
+// This new operator is used by VC++ 7.0 and later in Debug builds.
+void* operator new[](size_t size, int nBlockUse, const char* szFileName, int nLine)
+{
+    return operator new(size, nBlockUse, szFileName, nLine);
+}
+
 #endif /* _MSC_VER */
 
index 75616b9692ea3bf37b8d779dae4aed5932c5140b..a069a041d45c1217f787128972cd740f7cdf03da 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "private/gc_priv.h"
 
-# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) \
+# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) && !defined(GC_WIN32_PTHREADS)\
       || defined(GC_SOLARIS_THREADS)
 
 # if defined(dlopen) && !defined(GC_USE_LD_WRAP)
@@ -67,9 +67,7 @@
 #ifdef GC_USE_LD_WRAP
   void * __wrap_dlopen(const char *path, int mode)
 #else
-  void * GC_dlopen(path, mode)
-  GC_CONST char * path;
-  int mode;
+  void * GC_dlopen(const char *path, int mode)
 #endif
 {
     void * result;
diff --git a/src/mm/boehm-gc/gcc_support.c b/src/mm/boehm-gc/gcc_support.c
deleted file mode 100644 (file)
index 2ab0e7e..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-/***************************************************************************
-
-Interface between g++ and Boehm GC
-
-    Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
-
-    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-    OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
-
-    Permission is hereby granted to copy this code for any purpose,
-    provided the above notices are retained on all copies.
-
-    Last modified on Sun Jul 16 23:21:14 PDT 1995 by ellis
-
-This module provides runtime support for implementing the
-Ellis/Detlefs GC proposal, "Safe, Efficient Garbage Collection for
-C++", within g++, using its -fgc-keyword extension.  It defines
-versions of __builtin_new, __builtin_new_gc, __builtin_vec_new,
-__builtin_vec_new_gc, __builtin_delete, and __builtin_vec_delete that
-invoke the Bohem GC.  It also implements the WeakPointer.h interface.
-
-This module assumes the following configuration options of the Boehm GC:
-
-    -DALL_INTERIOR_POINTERS
-    -DDONT_ADD_BYTE_AT_END   
-
-This module adds its own required padding to the end of objects to
-support C/C++ "one-past-the-object" pointer semantics.
-
-****************************************************************************/
-
-#include "config.h"
-
-#include <stddef.h>
-#include "gc.h"
-
-#if defined(__STDC__) 
-#   define PROTO( args ) args
-#else
-#    define PROTO( args ) ()
-#    endif
-
-#define BITSPERBYTE 8     
-    /* What's the portable way to do this? */
-
-
-typedef void (*vfp) PROTO(( void ));
-extern vfp __new_handler;
-extern void __default_new_handler PROTO(( void ));
-
-
-/* A destructor_proc is the compiler generated procedure representing a 
-C++ destructor.  The "flag" argument is a hidden argument following some
-compiler convention. */
-
-typedef (*destructor_proc) PROTO(( void* this, int flag ));
-
-
-/***************************************************************************
-
-A BI_header is the header the compiler adds to the front of
-new-allocated arrays of objects with destructors.  The header is
-padded out to a double, because that's what the compiler does to
-ensure proper alignment of array elements on some architectures.  
-
-int NUM_ARRAY_ELEMENTS (void* o)
-    returns the number of array elements for array object o.
-
-char* FIRST_ELEMENT_P (void* o)
-    returns the address of the first element of array object o.
-
-***************************************************************************/
-
-typedef struct BI_header {
-    int nelts;
-    char padding [sizeof( double ) - sizeof( int )]; 
-        /* Better way to do this? */
-} BI_header;
-
-#define NUM_ARRAY_ELEMENTS( o ) \
-  (((BI_header*) o)->nelts)
-
-#define FIRST_ELEMENT_P( o ) \
-  ((char*) o + sizeof( BI_header ))
-
-
-/***************************************************************************
-
-The __builtin_new routines add a descriptor word to the end of each
-object.   The descriptor serves two purposes.  
-
-First, the descriptor acts as padding, implementing C/C++ pointer
-semantics.  C and C++ allow a valid array pointer to be incremented
-one past the end of an object.  The extra padding ensures that the
-collector will recognize that such a pointer points to the object and
-not the next object in memory.
-
-Second, the descriptor stores three extra pieces of information,
-whether an object has a registered finalizer (destructor), whether it
-may have any weak pointers referencing it, and for collectible arrays,
-the element size of the array.  The element size is required for the
-array's finalizer to iterate through the elements of the array.  (An
-alternative design would have the compiler generate a finalizer
-procedure for each different array type.  But given the overhead of
-finalization, there isn't any efficiency to be gained by that.)
-
-The descriptor must be added to non-collectible as well as collectible
-objects, since the Ellis/Detlefs proposal allows "pointer to gc T" to
-be assigned to a "pointer to T", which could then be deleted.  Thus,
-__builtin_delete must determine at runtime whether an object is
-collectible, whether it has weak pointers referencing it, and whether
-it may have a finalizer that needs unregistering.  Though
-GC_REGISTER_FINALIZER doesn't care if you ask it to unregister a
-finalizer for an object that doesn't have one, it is a non-trivial
-procedure that does a hash look-up, etc.  The descriptor trades a
-little extra space for a significant increase in time on the fast path
-through delete.  (A similar argument applies to
-GC_UNREGISTER_DISAPPEARING_LINK).
-
-For non-array types, the space for the descriptor could be shrunk to a
-single byte for storing the "has finalizer" flag.  But this would save
-space only on arrays of char (whose size is not a multiple of the word
-size) and structs whose largest member is less than a word in size
-(very infrequent).  And it would require that programmers actually
-remember to call "delete[]" instead of "delete" (which they should,
-but there are probably lots of buggy programs out there).  For the
-moment, the space savings seems not worthwhile, especially considering
-that the Boehm GC is already quite space competitive with other
-malloc's.
-
-
-Given a pointer o to the base of an object:
-
-Descriptor* DESCRIPTOR (void* o) 
-     returns a pointer to the descriptor for o.
-
-The implementation of descriptors relies on the fact that the GC
-implementation allocates objects in units of the machine's natural
-word size (e.g. 32 bits on a SPARC, 64 bits on an Alpha).
-
-**************************************************************************/
-
-typedef struct Descriptor {
-    unsigned has_weak_pointers: 1;
-    unsigned has_finalizer: 1;
-    unsigned element_size: BITSPERBYTE * sizeof( unsigned ) - 2; 
-} Descriptor;
-
-#define DESCRIPTOR( o ) \
-  ((Descriptor*) ((char*)(o) + GC_size( o ) - sizeof( Descriptor )))
-
-
-/**************************************************************************
-
-Implementations of global operator new() and operator delete()
-
-***************************************************************************/
-
-
-void* __builtin_new( size ) 
-    size_t size;
-    /* 
-    For non-gc non-array types, the compiler generates calls to
-    __builtin_new, which allocates non-collected storage via
-    GC_MALLOC_UNCOLLECTABLE.  This ensures that the non-collected
-    storage will be part of the collector's root set, required by the
-    Ellis/Detlefs semantics. */
-{
-    vfp handler = __new_handler ? __new_handler : __default_new_handler;
-
-    while (1) {
-        void* o = GC_MALLOC_UNCOLLECTABLE( size + sizeof( Descriptor ) );
-        if (o != 0) return o;
-        (*handler) ();}}
-
-
-void* __builtin_vec_new( size ) 
-    size_t size;
-    /* 
-    For non-gc array types, the compiler generates calls to
-    __builtin_vec_new. */
-{
-    return __builtin_new( size );}
-
-
-void* __builtin_new_gc( size )
-    size_t size;
-    /* 
-    For gc non-array types, the compiler generates calls to
-    __builtin_new_gc, which allocates collected storage via
-    GC_MALLOC. */
-{
-    vfp handler = __new_handler ? __new_handler : __default_new_handler;
-
-    while (1) {
-        void* o = GC_MALLOC( size + sizeof( Descriptor ) );
-        if (o != 0) return o;
-        (*handler) ();}}
-
-
-void* __builtin_new_gc_a( size )
-    size_t size;
-    /* 
-    For non-pointer-containing gc non-array types, the compiler
-    generates calls to __builtin_new_gc_a, which allocates collected
-    storage via GC_MALLOC_ATOMIC. */
-{
-    vfp handler = __new_handler ? __new_handler : __default_new_handler;
-
-    while (1) {
-        void* o = GC_MALLOC_ATOMIC( size + sizeof( Descriptor ) );
-        if (o != 0) return o;
-        (*handler) ();}}
-
-
-void* __builtin_vec_new_gc( size )
-    size_t size;
-    /*
-    For gc array types, the compiler generates calls to
-    __builtin_vec_new_gc. */
-{
-    return __builtin_new_gc( size );}
-
-
-void* __builtin_vec_new_gc_a( size )
-    size_t size;
-    /*
-    For non-pointer-containing gc array types, the compiler generates
-    calls to __builtin_vec_new_gc_a. */
-{
-    return __builtin_new_gc_a( size );}
-
-
-static void call_destructor( o, data )
-    void* o;
-    void* data;
-    /* 
-    call_destructor is the GC finalizer proc registered for non-array
-    gc objects with destructors.  Its client data is the destructor
-    proc, which it calls with the magic integer 2, a special flag
-    obeying the compiler convention for destructors. */
-{
-    ((destructor_proc) data)( o, 2 );}
-
-
-void* __builtin_new_gc_dtor( o, d )
-    void* o;
-    destructor_proc d;
-    /* 
-    The compiler generates a call to __builtin_new_gc_dtor to register
-    the destructor "d" of a non-array gc object "o" as a GC finalizer.
-    The destructor is registered via
-    GC_REGISTER_FINALIZER_IGNORE_SELF, which causes the collector to
-    ignore pointers from the object to itself when determining when
-    the object can be finalized.  This is necessary due to the self
-    pointers used in the internal representation of multiply-inherited
-    objects. */
-{
-    Descriptor* desc = DESCRIPTOR( o );
-
-    GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_destructor, d, 0, 0 );
-    desc->has_finalizer = 1;}
-
-
-static void call_array_destructor( o, data )
-    void* o;
-    void* data;
-    /*
-    call_array_destructor is the GC finalizer proc registered for gc
-    array objects whose elements have destructors. Its client data is
-    the destructor proc.  It iterates through the elements of the
-    array in reverse order, calling the destructor on each. */
-{
-    int num = NUM_ARRAY_ELEMENTS( o );
-    Descriptor* desc = DESCRIPTOR( o );
-    size_t size = desc->element_size;
-    char* first_p = FIRST_ELEMENT_P( o );
-    char* p = first_p + (num - 1) * size;
-
-    if (num > 0) {
-        while (1) {
-            ((destructor_proc) data)( p, 2 );
-            if (p == first_p) break;
-            p -= size;}}}
-
-
-void* __builtin_vec_new_gc_dtor( first_elem, d, element_size )
-    void* first_elem;
-    destructor_proc d;
-    size_t element_size;
-    /* 
-    The compiler generates a call to __builtin_vec_new_gc_dtor to
-    register the destructor "d" of a gc array object as a GC
-    finalizer.  "first_elem" points to the first element of the array,
-    *not* the beginning of the object (this makes the generated call
-    to this function smaller).  The elements of the array are of size
-    "element_size".  The destructor is registered as in
-    _builtin_new_gc_dtor. */
-{
-    void* o = (char*) first_elem - sizeof( BI_header );
-    Descriptor* desc = DESCRIPTOR( o );
-
-    GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_array_destructor, d, 0, 0 );
-    desc->element_size = element_size;
-    desc->has_finalizer = 1;}
-
-
-void __builtin_delete( o )
-    void* o;
-    /* 
-    The compiler generates calls to __builtin_delete for operator
-    delete().  The GC currently requires that any registered
-    finalizers be unregistered before explicitly freeing an object.
-    If the object has any weak pointers referencing it, we can't
-    actually free it now. */
-{
-  if (o != 0) { 
-      Descriptor* desc = DESCRIPTOR( o );
-      if (desc->has_finalizer) GC_REGISTER_FINALIZER( o, 0, 0, 0, 0 );
-      if (! desc->has_weak_pointers) GC_FREE( o );}}
-
-
-void __builtin_vec_delete( o )
-    void* o;
-    /* 
-    The compiler generates calls to __builitn_vec_delete for operator
-    delete[](). */
-{
-  __builtin_delete( o );}
-
-
-/**************************************************************************
-
-Implementations of the template class WeakPointer from WeakPointer.h
-
-***************************************************************************/
-
-typedef struct WeakPointer {
-    void* pointer; 
-} WeakPointer;
-
-
-void* _WeakPointer_New( t )
-    void* t;
-{
-    if (t == 0) {
-        return 0;}
-    else {
-        void* base = GC_base( t );
-        WeakPointer* wp = 
-            (WeakPointer*) GC_MALLOC_ATOMIC( sizeof( WeakPointer ) );
-        Descriptor* desc = DESCRIPTOR( base );
-
-        wp->pointer = t;
-        desc->has_weak_pointers = 1;
-        GC_general_register_disappearing_link( &wp->pointer, base );
-        return wp;}}
-
-
-static void* PointerWithLock( wp ) 
-    WeakPointer* wp;
-{
-    if (wp == 0 || wp->pointer == 0) {
-      return 0;}
-    else {
-        return (void*) wp->pointer;}}
-
-
-void* _WeakPointer_Pointer( wp )
-    WeakPointer* wp;
-{
-    return (void*) GC_call_with_alloc_lock( PointerWithLock, wp );}
-
-
-typedef struct EqualClosure {
-    WeakPointer* wp1;
-    WeakPointer* wp2;
-} EqualClosure;
-
-
-static void* EqualWithLock( ec )
-    EqualClosure* ec;
-{
-    if (ec->wp1 == 0 || ec->wp2 == 0) {
-        return (void*) (ec->wp1 == ec->wp2);}
-    else {
-      return (void*) (ec->wp1->pointer == ec->wp2->pointer);}}
-
-
-int _WeakPointer_Equal( wp1,  wp2 )
-    WeakPointer* wp1;
-    WeakPointer* wp2;
-{
-    EqualClosure ec;
-
-    ec.wp1 = wp1;
-    ec.wp2 = wp2;
-    return (int) GC_call_with_alloc_lock( EqualWithLock, &ec );}
-
-
-int _WeakPointer_Hash( wp )
-    WeakPointer* wp;
-{
-    return (int) _WeakPointer_Pointer( wp );}
-
-
-/**************************************************************************
-
-Implementations of the template class CleanUp from WeakPointer.h
-
-***************************************************************************/
-
-typedef struct Closure {
-    void (*c) PROTO(( void* d, void* t ));
-    ptrdiff_t t_offset; 
-    void* d;
-} Closure;
-
-
-static void _CleanUp_CallClosure( obj, data ) 
-    void* obj;
-    void* data;
-{
-    Closure* closure = (Closure*) data;
-    closure->c( closure->d, (char*) obj + closure->t_offset );}
-
-
-void _CleanUp_Set( t, c, d ) 
-    void* t;
-    void (*c) PROTO(( void* d, void* t ));
-    void* d;
-{
-    void* base = GC_base( t );
-    Descriptor* desc = DESCRIPTOR( t );
-
-    if (c == 0) {
-        GC_REGISTER_FINALIZER_IGNORE_SELF( base, 0, 0, 0, 0 );
-        desc->has_finalizer = 0;}
-    else {
-        Closure* closure = (Closure*) GC_MALLOC( sizeof( Closure ) );
-        closure->c = c;
-        closure->t_offset = (char*) t - (char*) base;
-        closure->d = d;
-        GC_REGISTER_FINALIZER_IGNORE_SELF( base, _CleanUp_CallClosure, 
-                                           closure, 0, 0 );
-        desc->has_finalizer = 1;}}
-
-
-void _CleanUp_Call( t ) 
-    void* t;
-{
-      /* ? Aren't we supposed to deactivate weak pointers to t too? 
-         Why? */
-    void* base = GC_base( t );
-    void* d;
-    GC_finalization_proc f;
-
-    GC_REGISTER_FINALIZER( base, 0, 0, &f, &d );
-    f( base, d );}
-
-
-typedef struct QueueElem {
-    void* o;
-    GC_finalization_proc f;
-    void* d;
-    struct QueueElem* next; 
-} QueueElem;
-
-
-void* _CleanUp_Queue_NewHead()
-{
-    return GC_MALLOC( sizeof( QueueElem ) );}
-    
-     
-static void _CleanUp_Queue_Enqueue( obj, data )
-    void* obj; 
-    void* data;
-{
-    QueueElem* q = (QueueElem*) data;
-    QueueElem* head = q->next;
-
-    q->o = obj;
-    q->next = head->next;
-    head->next = q;}
-    
-    
-void _CleanUp_Queue_Set( h, t ) 
-    void* h;
-    void* t;
-{
-    QueueElem* head = (QueueElem*) h;
-    void* base = GC_base( t );
-    void* d;
-    GC_finalization_proc f;
-    QueueElem* q = (QueueElem*) GC_MALLOC( sizeof( QueueElem ) );
-     
-    GC_REGISTER_FINALIZER( base, _CleanUp_Queue_Enqueue, q, &f, &d );
-    q->f = f;
-    q->d = d;
-    q->next = head;}
-    
-
-int _CleanUp_Queue_Call( h ) 
-    void* h;
-{
-    QueueElem* head = (QueueElem*) h;
-    QueueElem* q = head->next;
-
-    if (q == 0) {
-        return 0;}
-    else {
-        head->next = q->next;
-        q->next = 0;
-        if (q->f != 0) q->f( q->o, q->d );
-        return 1;}}
-
-
-
index 45ffa4831532ae666e8ae2718080f76a4679a762..ff950e5c2cbaace0ff69571d3de6ecbb8c72b33e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
- * Copyright (c) 1999 by Hewlett-Packard Company.  All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -60,20 +60,16 @@ void GC_init_gcj_malloc(int mp_index, void * /* really GC_mark_proc */mp)
     DCL_LOCK_STATE;
 
     GC_init(); /* In case it's not already done.       */
-    DISABLE_SIGNALS();
     LOCK();
     if (GC_gcj_malloc_initialized) {
       UNLOCK();
-      ENABLE_SIGNALS();
       return;
     }
     GC_gcj_malloc_initialized = TRUE;
     ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO"));
-#   ifdef CONDPRINT
-      if (GC_print_stats && ignore_gcj_info) {
-        GC_printf0("Gcj-style type information is disabled!\n");
-      }
-#   endif
+    if (GC_print_stats && ignore_gcj_info) {
+        GC_log_printf("Gcj-style type information is disabled!\n");
+    }
     GC_ASSERT(GC_mark_procs[mp_index] == (GC_mark_proc)0); /* unused */
     GC_mark_procs[mp_index] = (GC_mark_proc)mp;
     if (mp_index >= GC_n_mark_procs) ABORT("GC_init_gcj_malloc: bad index");
@@ -105,16 +101,15 @@ void GC_init_gcj_malloc(int mp_index, void * /* really GC_mark_proc */mp)
                                FALSE, TRUE);
       }
     UNLOCK();
-    ENABLE_SIGNALS();
 }
 
-ptr_t GC_clear_stack();
+void * GC_clear_stack(void *);
 
 #define GENERAL_MALLOC(lb,k) \
-    (GC_PTR)GC_clear_stack(GC_generic_malloc_inner((word)lb, k))
+    GC_clear_stack(GC_generic_malloc_inner((word)lb, k))
     
 #define GENERAL_MALLOC_IOP(lb,k) \
-    (GC_PTR)GC_clear_stack(GC_generic_malloc_inner_ignore_off_page(lb, k))
+    GC_clear_stack(GC_generic_malloc_inner_ignore_off_page(lb, k))
 
 /* We need a mechanism to release the lock and invoke finalizers.      */
 /* We don't really have an opportunity to do this on a rarely executed */
@@ -138,20 +133,20 @@ static void maybe_finalize()
 /* Allocate an object, clear it, and store the pointer to the  */
 /* type structure (vtable in gcj).                             */
 /* This adds a byte at the end of the object if GC_malloc would.*/
-void * GC_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr)
+#ifdef THREAD_LOCAL_ALLOC
+  void * GC_core_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr)
+#else
+  void * GC_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr)
+#endif
 {
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-DCL_LOCK_STATE;
+    ptr_t op;
+    ptr_t * opp;
+    word lg;
+    DCL_LOCK_STATE;
 
-    if( EXPECT(SMALL_OBJ(lb), 1) ) {
-#       ifdef MERGE_SIZES
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_gcjobjfreelist[lw]);
+    if(SMALL_OBJ(lb)) {
+       lg = GC_size_map[lb];
+       opp = &(GC_gcjobjfreelist[lg]);
        LOCK();
        op = *opp;
         if(EXPECT(op == 0, 0)) {
@@ -161,12 +156,9 @@ DCL_LOCK_STATE;
                UNLOCK();
                return(GC_oom_fn(lb));
            }
-#          ifdef MERGE_SIZES
-               lw = GC_size_map[lb];   /* May have been uninitialized. */
-#          endif
         } else {
             *opp = obj_link(op);
-            GC_words_allocd += lw;
+            GC_bytes_allocd += GRANULES_TO_BYTES(lg);
         }
        *(void **)op = ptr_to_struct_containing_descr;
        GC_ASSERT(((void **)op)[1] == 0);
@@ -182,15 +174,15 @@ DCL_LOCK_STATE;
        *(void **)op = ptr_to_struct_containing_descr;
        UNLOCK();
     }
-    return((GC_PTR) op);
+    return((void *) op);
 }
 
 /* Similar to GC_gcj_malloc, but add debug info.  This is allocated    */
 /* with GC_gcj_debug_kind.                                             */
-GC_PTR GC_debug_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr,
+void * GC_debug_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr,
                           GC_EXTRA_PARAMS)
 {
-    GC_PTR result;
+    void * result;
 
     /* We're careful to avoid extra calls, which could          */
     /* confuse the backtrace.                                  */
@@ -199,11 +191,10 @@ GC_PTR GC_debug_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr,
     result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
     if (result == 0) {
        UNLOCK();
-        GC_err_printf2("GC_debug_gcj_malloc(%ld, 0x%lx) returning NIL (",
-                      (unsigned long) lb,
-                      (unsigned long) ptr_to_struct_containing_descr);
+        GC_err_printf("GC_debug_gcj_malloc(%ld, %p) returning NIL (",
+                     (unsigned long)lb, ptr_to_struct_containing_descr);
         GC_err_puts(s);
-        GC_err_printf1(":%ld)\n", (unsigned long)i);
+        GC_err_printf(":%d)\n", i);
         return(GC_oom_fn(lb));
     }
     *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr;
@@ -215,92 +206,25 @@ GC_PTR GC_debug_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr,
     return (GC_store_debug_info(result, (word)lb, s, (word)i));
 }
 
-/* Similar to GC_gcj_malloc, but the size is in words, and we don't    */
-/* adjust it.  The size is assumed to be such that it can be   */
-/* allocated as a small object.                                        */
-void * GC_gcj_fast_malloc(size_t lw, void * ptr_to_struct_containing_descr)
-{
-ptr_t op;
-ptr_t * opp;
-DCL_LOCK_STATE;
-
-    opp = &(GC_gcjobjfreelist[lw]);
-    LOCK();
-    op = *opp;
-    if( EXPECT(op == 0, 0) ) {
-       maybe_finalize();
-        op = (ptr_t)GC_clear_stack(
-               GC_generic_malloc_words_small_inner(lw, GC_gcj_kind));
-       if (0 == op) {
-           UNLOCK();
-           return GC_oom_fn(WORDS_TO_BYTES(lw));
-       }
-    } else {
-        *opp = obj_link(op);
-        GC_words_allocd += lw;
-    }
-    *(void **)op = ptr_to_struct_containing_descr;
-    UNLOCK();
-    return((GC_PTR) op);
-}
-
-/* And a debugging version of the above:       */
-void * GC_debug_gcj_fast_malloc(size_t lw,
-                               void * ptr_to_struct_containing_descr,
-                               GC_EXTRA_PARAMS)
-{
-    GC_PTR result;
-    size_t lb = WORDS_TO_BYTES(lw);
-
-    /* We clone the code from GC_debug_gcj_malloc, so that we  */
-    /* dont end up with extra frames on the stack, which could */
-    /* confuse the backtrace.                                  */
-    LOCK();
-    maybe_finalize();
-    result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
-    if (result == 0) {
-       UNLOCK();
-        GC_err_printf2("GC_debug_gcj_fast_malloc(%ld, 0x%lx) returning NIL (",
-                      (unsigned long) lw,
-                      (unsigned long) ptr_to_struct_containing_descr);
-        GC_err_puts(s);
-        GC_err_printf1(":%ld)\n", (unsigned long)i);
-        return GC_oom_fn(WORDS_TO_BYTES(lw));
-    }
-    *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr;
-    UNLOCK();
-    if (!GC_debugging_started) {
-       GC_start_debugging();
-    }
-    ADD_CALL_CHAIN(result, ra);
-    return (GC_store_debug_info(result, (word)lb, s, (word)i));
-}
-
 void * GC_gcj_malloc_ignore_off_page(size_t lb,
                                     void * ptr_to_struct_containing_descr) 
 {
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-DCL_LOCK_STATE;
+    ptr_t op;
+    ptr_t * opp;
+    word lg;
+    DCL_LOCK_STATE;
 
-    if( SMALL_OBJ(lb) ) {
-#       ifdef MERGE_SIZES
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_gcjobjfreelist[lw]);
+    if(SMALL_OBJ(lb)) {
+       lg = GC_size_map[lb];
+       opp = &(GC_gcjobjfreelist[lg]);
        LOCK();
         if( (op = *opp) == 0 ) {
            maybe_finalize();
             op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind);
-#          ifdef MERGE_SIZES
-               lw = GC_size_map[lb];   /* May have been uninitialized. */
-#          endif
+           lg = GC_size_map[lb];       /* May have been uninitialized. */
         } else {
             *opp = obj_link(op);
-            GC_words_allocd += lw;
+            GC_bytes_allocd += GRANULES_TO_BYTES(lg);
         }
        *(void **)op = ptr_to_struct_containing_descr;
        UNLOCK();
@@ -313,7 +237,7 @@ DCL_LOCK_STATE;
        }
         UNLOCK();
     }
-    return((GC_PTR) op);
+    return((void *) op);
 }
 
 #else
index 533b59d1037dd630c48bbe9d6bbef31844bb5705..c9930d3a5483b21bec8eed0f55883dfbe1e31194 100644 (file)
@@ -35,17 +35,75 @@ bottom_index * GC_all_bottom_indices_end = 0;
                                /* bottom_index.                  */
  
 /* Non-macro version of header location routine */
-hdr * GC_find_header(h)
-ptr_t h;
+hdr * GC_find_header(ptr_t h)
 {
 #   ifdef HASH_TL
-       register hdr * result;
+       hdr * result;
        GET_HDR(h, result);
        return(result);
 #   else
        return(HDR_INNER(h));
 #   endif
 }
+
+/* Handle a header cache miss.  Returns a pointer to the       */
+/* header corresponding to p, if p can possibly be a valid     */
+/* object pointer, and 0 otherwise.                            */
+/* GUARANTEED to return 0 for a pointer past the first page    */
+/* of an object unless both GC_all_interior_pointers is set    */
+/* and p is in fact a valid object pointer.                    */
+#ifdef PRINT_BLACK_LIST
+  hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce, ptr_t source)
+#else
+  hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce)
+#endif
+{
+  hdr *hhdr;
+  HC_MISS();
+  GET_HDR(p, hhdr);
+  if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+    if (GC_all_interior_pointers) {
+      if (hhdr != 0) {
+       ptr_t current = p;
+           
+       current = (ptr_t)HBLKPTR(current);
+       do {
+           current = current - HBLKSIZE*(word)hhdr;
+           hhdr = HDR(current);
+       } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
+       /* current points to near the start of the large object */
+       if (hhdr -> hb_flags & IGNORE_OFF_PAGE
+           || HBLK_IS_FREE(hhdr))
+           return 0;
+       if (p - current >= (ptrdiff_t)(hhdr->hb_sz)) {
+           GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
+           /* Pointer past the end of the block */
+           return 0;
+       }
+      } else {
+       GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
+      }
+      return hhdr;
+      /* Pointers past the first page are probably too rare    */
+      /* to add them to the cache.  We don't.                  */
+      /* And correctness relies on the fact that we don't.     */
+    } else {
+      if (hhdr == 0) {
+       GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
+      }
+      return 0;
+    }
+  } else {
+    if (HBLK_IS_FREE(hhdr)) {
+      GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
+      return 0;
+    } else {
+      hce -> block_addr = (word)(p) >> LOG_HBLKSIZE;
+      hce -> hce_hdr = hhdr; 
+      return hhdr;
+    }
+  } 
+}
  
 /* Routines to dynamically allocate collector data structures that will */
 /* never be freed.                                                      */
@@ -55,18 +113,12 @@ static ptr_t scratch_free_ptr = 0;
 /* 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;
+ptr_t GC_scratch_alloc(size_t bytes)
 {
     register ptr_t result = scratch_free_ptr;
 
-#   ifdef ALIGN_DOUBLE
-#      define GRANULARITY (2 * sizeof(word))
-#   else
-#      define GRANULARITY sizeof(word)
-#   endif
-    bytes += GRANULARITY-1;
-    bytes &= ~(GRANULARITY-1);
+    bytes += GRANULE_BYTES-1;
+    bytes &= ~(GRANULE_BYTES-1);
     scratch_free_ptr += bytes;
     if (scratch_free_ptr <= GC_scratch_end_ptr) {
         return(result);
@@ -88,9 +140,8 @@ register word bytes;
         }
         result = (ptr_t)GET_MEM(bytes_to_get);
         if (result == 0) {
-#          ifdef PRINTSTATS
-                GC_printf0("Out of memory - trying to allocate less\n");
-#          endif
+           if (GC_print_stats)
+                GC_printf("Out of memory - trying to allocate less\n");
             scratch_free_ptr -= bytes;
            bytes_to_get = bytes;
 #          ifdef USE_MMAP
@@ -109,7 +160,7 @@ register word bytes;
 static hdr * hdr_free_list = 0;
 
 /* Return an uninitialized header */
-static hdr * alloc_hdr()
+static hdr * alloc_hdr(void)
 {
     register hdr * result;
     
@@ -122,21 +173,18 @@ static hdr * alloc_hdr()
     return(result);
 }
 
-static void free_hdr(hhdr)
-hdr * hhdr;
+static void free_hdr(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()
+void GC_init_headers(void)
 {
     register unsigned i;
     
@@ -145,14 +193,11 @@ 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  */
 /* Return FALSE on failure.                                            */
-static GC_bool get_index(addr)
-word addr;
+static GC_bool get_index(word addr)
 {
     word hi = (word)(addr) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
     bottom_index * r;
@@ -161,7 +206,7 @@ word addr;
     bottom_index *pi;
     
 #   ifdef HASH_TL
-      unsigned i = TL_HASH(hi);
+      word i = TL_HASH(hi);
       bottom_index * old;
       
       old = p = GC_top_index[i];
@@ -203,8 +248,7 @@ word addr;
 /* 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;
+struct hblkhdr * GC_install_header(struct hblk *h)
 {
     hdr * result;
     
@@ -218,12 +262,10 @@ register struct hblk * h;
 }
 
 /* Set up forwarding counts for block h of size sz */
-GC_bool GC_install_counts(h, sz)
-register struct hblk * h;
-register word sz; /* bytes */
+GC_bool GC_install_counts(struct hblk *h, size_t sz/* bytes */)
 {
-    register struct hblk * hbp;
-    register int i;
+    struct hblk * hbp;
+    word i;
     
     for (hbp = h; (char *)hbp < (char *)h + sz; hbp += BOTTOM_SZ) {
         if (!get_index((word) hbp)) return(FALSE);
@@ -237,8 +279,7 @@ register word sz; /* bytes */
 }
 
 /* Remove the header for block h */
-void GC_remove_header(h)
-register struct hblk * h;
+void GC_remove_header(struct hblk *h)
 {
     hdr ** ha;
     
@@ -248,9 +289,7 @@ register struct hblk * h;
 }
 
 /* Remove forwarding counts for h */
-void GC_remove_counts(h, sz)
-register struct hblk * h;
-register word sz; /* bytes */
+void GC_remove_counts(struct hblk *h, size_t sz/* bytes */)
 {
     register struct hblk * hbp;
     
@@ -261,18 +300,17 @@ register word sz; /* bytes */
 
 /* Apply fn to all allocated blocks */
 /*VARARGS1*/
-void GC_apply_to_all_blocks(fn, client_data)
-void (*fn) GC_PROTO((struct hblk *h, word client_data));
-word client_data;
+void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data),
+                           word client_data)
 {
-    register int j;
-    register bottom_index * index_p;
+    signed_word j;
+    bottom_index * index_p;
     
     for (index_p = GC_all_bottom_indices; index_p != 0;
          index_p = index_p -> asc_link) {
         for (j = BOTTOM_SZ-1; j >= 0;) {
             if (!IS_FORWARDING_ADDR_OR_NIL(index_p->index[j])) {
-                if (index_p->index[j]->hb_map != GC_invalid_map) {
+                if (!HBLK_IS_FREE(index_p->index[j])) {
                     (*fn)(((struct hblk *)
                              (((index_p->key << LOG_BOTTOM_SZ) + (word)j)
                               << LOG_HBLKSIZE)),
@@ -282,7 +320,7 @@ word client_data;
              } else if (index_p->index[j] == 0) {
                 j--;
              } else {
-                j -= (word)(index_p->index[j]);
+                j -= (signed_word)(index_p->index[j]);
              }
          }
      }
@@ -290,8 +328,7 @@ word client_data;
 
 /* Get the next valid block whose address is at least h        */
 /* Return 0 if there is none.                          */
-struct hblk * GC_next_used_block(h)
-struct hblk * h;
+struct hblk * GC_next_used_block(struct hblk *h)
 {
     register bottom_index * bi;
     register word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
@@ -309,7 +346,7 @@ struct hblk * h;
             if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
                 j++;
             } else {
-                if (hhdr->hb_map != GC_invalid_map) {
+                if (!HBLK_IS_FREE(hhdr)) {
                     return((struct hblk *)
                              (((bi -> key << LOG_BOTTOM_SZ) + j)
                               << LOG_HBLKSIZE));
@@ -327,8 +364,7 @@ struct hblk * h;
 /* Get the last (highest address) block whose address is       */
 /* at most h.  Return 0 if there is none.                      */
 /* Unlike the above, this may return a free block.             */
-struct hblk * GC_prev_block(h)
-struct hblk * h;
+struct hblk * GC_prev_block(struct hblk *h)
 {
     register bottom_index * bi;
     register signed_word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
index 3dcccf21f5a86099e809475d5cd3303c9a61f2b0..d6e0a70d74095160f4cd566b9435b9d2cd938f7a 100644 (file)
@@ -5,10 +5,7 @@
 # include <string.h>
 # include <unistd.h>
 
-int main(argc, argv, envp)
-int argc;
-char ** argv;
-char ** envp;
+int main(int argc, char **argv, char **envp)
 {
     if (argc < 4) goto Usage;
     if (strcmp(MACH_TYPE, argv[1]) != 0) return(0);
index 8691e925920eabc542710ca22c9dc9247485cf69..7af6fba4e033b8bcb536a4f66fbfee10fce1732f 100644 (file)
@@ -8,10 +8,7 @@
 #include <dirent.h>
 #endif /* __DJGPP__ */
 
-int main(argc, argv, envp)
-int argc;
-char ** argv;
-char ** envp;
+int main(int argc, char **argv, char **envp)
 {
     FILE * f;
 #ifdef __DJGPP__
diff --git a/src/mm/boehm-gc/include/Makefile.am b/src/mm/boehm-gc/include/Makefile.am
deleted file mode 100644 (file)
index 4224ba4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# 
-# 
-# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-# OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
-# 
-# Permission is hereby granted to use or copy this program
-# for any purpose,  provided the above notices are retained on all copies.
-# Permission to modify the code and to distribute modified code is granted,
-# provided the above notices are retained, and a notice that the code was
-# modified is included with the above copyright notice.
-#
-# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
-
-## Process this file with automake to produce Makefile.in.
-
-# installed headers
-#
-dist_noinst_HEADERS = gc.h gc_typed.h gc_inl.h \
-    gc_inline.h gc_mark.h gc_cpp.h \
-    weakpointer.h gc_alloc.h new_gc_alloc.h \
-    gc_allocator.h gc_backptr.h \
-    gc_gcj.h gc_local_alloc.h leak_detector.h \
-    gc_amiga_redirects.h gc_pthread_redirects.h \
-    gc_config_macros.h
-
-# headers which are not installed
-#
-dist_noinst_HEADERS += private/gc_hdrs.h \
-    private/gc_priv.h private/gcconfig.h \
-    private/gc_pmark.h private/gc_locks.h \
-    private/solaris_threads.h private/dbg_mlc.h \
-    private/specific.h private/cord_pos.h \
-    private/pthread_support.h private/pthread_stop_world.h \
-    private/darwin_semaphore.h private/darwin_stop_world.h \
-    cord.h ec.h javaxfc.h 
index b80b568ba4f6953f738e3770ba83e98184d7e82a..f4e5b5c50b1b710516ed71584ed8e82a55749f94 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
  * Copyright 1996-1999 by Silicon Graphics.  All rights reserved.
  * Copyright 1999 by Hewlett-Packard Company.  All rights reserved.
+ * Copyright (C) 2007 Free Software Foundation, Inc
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 
 # include "gc_config_macros.h"
 
-# if defined(__STDC__) || defined(__cplusplus) || defined(_AIX)
-#   define GC_PROTO(args) args
-    typedef void * GC_PTR;
-#   define GC_CONST const
-# else
-#   define GC_PROTO(args) ()
-    typedef char * GC_PTR;
-#   define GC_CONST
-#  endif
-
 # ifdef __cplusplus
     extern "C" {
 # endif
@@ -61,8 +52,8 @@
   /* Win64 isn't really supported yet, but this is the first step. And */
   /* it might cause error messages to show up in more plausible places.        */
   /* This needs basetsd.h, which is included by windows.h.             */
-  typedef ULONG_PTR GC_word;
-  typedef LONG_PTR GC_word;
+  typedef unsigned long long GC_word;
+  typedef long long GC_signed_word;
 #endif
 
 /* Public read-only variables */
@@ -83,7 +74,7 @@ GC_API int GC_parallel;       /* GC is parallelized for performance on        */
 
 /* Public R/W variables */
 
-GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
+GC_API void * (*GC_oom_fn) (size_t bytes_requested);
                        /* When there is insufficient memory to satisfy */
                        /* an allocation request, we return             */
                        /* (*GC_oom_fn)().  By default this just        */
@@ -110,11 +101,6 @@ GC_API int GC_all_interior_pointers;
                        /* pointer recognition.                         */
                        /* MUST BE 0 or 1.                              */
 
-GC_API int GC_quiet;   /* Disable statistics output.  Only matters if  */
-                       /* collector has been compiled with statistics  */
-                       /* enabled.  This involves a performance cost,  */
-                       /* and is thus not the default.                 */
-
 GC_API int GC_finalize_on_demand;
                        /* If nonzero, finalizers will only be run in   */
                        /* response to an explicit GC_invoke_finalizers */
@@ -128,8 +114,10 @@ GC_API int GC_java_finalization;
                        /* it a bit safer to use non-topologically-     */
                        /* ordered finalization.  Default value is      */
                        /* determined by JAVA_FINALIZATION macro.       */
+                       /* Enables register_finalizer_unreachable to    */
+                       /* work correctly.                              */
 
-GC_API void (* GC_finalizer_notifier) GC_PROTO((void));
+GC_API void (* GC_finalizer_notifier)(void);
                        /* Invoked by the collector when there are      */
                        /* objects to be finalized.  Invoked at most    */
                        /* once per GC cycle.  Never invoked unless     */
@@ -189,15 +177,16 @@ GC_API int GC_no_dls;
 GC_API GC_word GC_free_space_divisor;
                        /* We try to make sure that we allocate at      */
                        /* least N/GC_free_space_divisor bytes between  */
-                       /* collections, where N is the heap size plus   */
+                       /* collections, where N is twice the number     */
+                       /* of traced bytes, plus the number of untraced */
+                       /* bytes (bytes in "atomic" objects), plus      */
                        /* a rough estimate of the root set size.       */
+                       /* N approximates GC tracing work per GC.       */
                        /* Initially, GC_free_space_divisor = 3.        */
                        /* Increasing its value will use less space     */
                        /* but more collection time.  Decreasing it     */
                        /* will appreciably decrease collection time    */
                        /* at the expense of space.                     */
-                       /* GC_free_space_divisor = 1 will effectively   */
-                       /* disable collections.                         */
 
 GC_API GC_word GC_max_retries;
                        /* The maximum number of GCs attempted before   */
@@ -205,7 +194,7 @@ GC_API GC_word GC_max_retries;
                        /* expansion fails.  Initially 0.               */
                        
 
-GC_API char *GC_stackbottom;   /* Cool end of user stack.              */
+GC_API char *GC_stackbottom;    /* Cool end of user stack.             */
                                /* May be set in the client prior to    */
                                /* calling any GC_ routines.  This      */
                                /* avoids some overhead, and            */
@@ -247,7 +236,7 @@ GC_API unsigned long GC_time_limit;
  * to call this somehow (e.g. from a constructor) before doing any allocation.
  * For win32 threads, it needs to be called explicitly.
  */
-GC_API void GC_init GC_PROTO((void));
+GC_API void GC_init(void);
 
 /* Added for cacao */
 int GC_signum1();   
@@ -270,15 +259,15 @@ int GC_signum2();
  * starting in 6.0.  GC_malloc_stubborn is an alias for GC_malloc unless
  * the collector is built with STUBBORN_ALLOC defined.
  */
-GC_API GC_PTR GC_malloc GC_PROTO((size_t size_in_bytes));
-GC_API GC_PTR GC_malloc_atomic GC_PROTO((size_t size_in_bytes));
-GC_API char *GC_strdup GC_PROTO((const char *str));
-GC_API GC_PTR GC_malloc_uncollectable GC_PROTO((size_t size_in_bytes));
-GC_API GC_PTR GC_malloc_stubborn GC_PROTO((size_t size_in_bytes));
+GC_API void * GC_malloc(size_t size_in_bytes);
+GC_API void * GC_malloc_atomic(size_t size_in_bytes);
+GC_API char * GC_strdup (const char *str);
+GC_API void * GC_malloc_uncollectable(size_t size_in_bytes);
+GC_API void * GC_malloc_stubborn(size_t size_in_bytes);
 
 /* The following is only defined if the library has been suitably      */
 /* compiled:                                                           */
-GC_API GC_PTR GC_malloc_atomic_uncollectable GC_PROTO((size_t size_in_bytes));
+GC_API void * GC_malloc_atomic_uncollectable(size_t size_in_bytes);
 
 /* Explicitly deallocate an object.  Dangerous if used incorrectly.     */
 /* Requires a pointer to the base of an object.                                */
@@ -286,7 +275,7 @@ GC_API GC_PTR GC_malloc_atomic_uncollectable GC_PROTO((size_t size_in_bytes));
 /* An object should not be enable for finalization when it is          */
 /* explicitly deallocated.                                             */
 /* GC_free(0) is a no-op, as required by ANSI C for free.              */
-GC_API void GC_free GC_PROTO((GC_PTR object_addr));
+GC_API void GC_free(void * object_addr);
 
 /*
  * Stubborn objects may be changed only if the collector is explicitly informed.
@@ -303,8 +292,8 @@ GC_API void GC_free GC_PROTO((GC_PTR object_addr));
  * do so.  The same applies to dropping stubborn objects that are still
  * changeable.
  */
-GC_API void GC_change_stubborn GC_PROTO((GC_PTR));
-GC_API void GC_end_stubborn_change GC_PROTO((GC_PTR));
+GC_API void GC_change_stubborn(void *);
+GC_API void GC_end_stubborn_change(void *);
 
 /* Return a pointer to the base (lowest address) of an object given    */
 /* a pointer to a location within the object.                          */
@@ -316,13 +305,13 @@ GC_API void GC_end_stubborn_change GC_PROTO((GC_PTR));
 /* object.                                                             */
 /* Note that a deallocated object in the garbage collected heap                */
 /* may be considered valid, even if it has been deallocated with       */
-/* GC_free.                                                            */
-GC_API GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
+/* GC_free.                                                            */
+GC_API void * GC_base(void * displaced_pointer);
 
 /* Given a pointer to the base of an object, return its size in bytes. */
 /* The returned size may be slightly larger than what was originally   */
 /* requested.                                                          */
-GC_API size_t GC_size GC_PROTO((GC_PTR object_addr));
+GC_API size_t GC_size(void * object_addr);
 
 /* For compatibility with C library.  This is occasionally faster than */
 /* a malloc followed by a bcopy.  But if you rely on that, either here */
@@ -332,37 +321,35 @@ GC_API size_t GC_size GC_PROTO((GC_PTR object_addr));
 /* If the argument is stubborn, the result will have changes enabled.  */
 /* It is an error to have changes enabled for the original object.     */
 /* Follows ANSI comventions for NULL old_object.                       */
-GC_API GC_PTR GC_realloc
-       GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes));
+GC_API void * GC_realloc(void * old_object, size_t new_size_in_bytes);
                                   
 /* Explicitly increase the heap size.  */
 /* Returns 0 on failure, 1 on success.  */
-GC_API int GC_expand_hp GC_PROTO((size_t number_of_bytes));
+GC_API int GC_expand_hp(size_t number_of_bytes);
 
 /* Limit the heap size to n bytes.  Useful when you're debugging,      */
 /* especially on systems that don't handle running out of memory well. */
 /* n == 0 ==> unbounded.  This is the default.                         */
-GC_API void GC_set_max_heap_size GC_PROTO((GC_word n));
+GC_API void GC_set_max_heap_size(GC_word n);
 
-GC_API GC_word GC_get_max_heap_size GC_PROTO((void));
+GC_API GC_word GC_get_max_heap_size(void);
 
 /* Inform the collector that a certain section of statically allocated */
 /* memory contains no pointers to garbage collected memory.  Thus it   */
 /* need not be scanned.  This is sometimes important if the application */
 /* maps large read/write files into the address space, which could be  */
 /* mistaken for dynamic library data segments on some systems.         */
-GC_API void GC_exclude_static_roots GC_PROTO((GC_PTR start, GC_PTR finish));
+GC_API void GC_exclude_static_roots(void * low_address,
+                                   void * high_address_plus_1);
 
 /* Clear the set of root segments.  Wizards only. */
-GC_API void GC_clear_roots GC_PROTO((void));
+GC_API void GC_clear_roots(void);
 
 /* Add a root segment.  Wizards only. */
-GC_API void GC_add_roots GC_PROTO((char * low_address,
-                                  char * high_address_plus_1));
+GC_API void GC_add_roots(void * low_address, void * high_address_plus_1);
 
 /* Remove a root segment.  Wizards only. */
-GC_API void GC_remove_roots GC_PROTO((char * low_address, 
-    char * high_address_plus_1));
+GC_API void GC_remove_roots(void * low_address, void * high_address_plus_1);
 
 /* Add a displacement to the set of those considered valid by the      */
 /* collector.  GC_register_displacement(n) means that if p was returned */
@@ -376,14 +363,14 @@ GC_API void GC_remove_roots GC_PROTO((char * low_address,
 /* retention.                                                          */
 /* This is a no-op if the collector has recognition of                 */
 /* arbitrary interior pointers enabled, which is now the default.      */
-GC_API void GC_register_displacement GC_PROTO((GC_word n));
+GC_API void GC_register_displacement(size_t n);
 
 /* The following version should be used if any debugging allocation is */
 /* being done.                                                         */
-GC_API void GC_debug_register_displacement GC_PROTO((GC_word n));
+GC_API void GC_debug_register_displacement(size_t n);
 
 /* Explicitly trigger a full, world-stop collection.   */
-GC_API void GC_gcollect GC_PROTO((void));
+GC_API void GC_gcollect(void);
 
 /* Trigger a full world-stopped collection.  Abort the collection if   */
 /* and when stop_func returns a nonzero value.  Stop_func will be      */
@@ -394,32 +381,32 @@ GC_API void GC_gcollect GC_PROTO((void));
 /* aborted collections do no useful work; the next collection needs    */
 /* to start from the beginning.                                                */
 /* Return 0 if the collection was aborted, 1 if it succeeded.          */
-typedef int (* GC_stop_func) GC_PROTO((void));
-GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
+typedef int (* GC_stop_func)(void);
+GC_API int GC_try_to_collect(GC_stop_func stop_func);
 
 /* Return the number of bytes in the heap.  Excludes collector private */
 /* data structures.  Includes empty blocks and fragmentation loss.     */
 /* Includes some pages that were allocated but never written.          */
-GC_API size_t GC_get_heap_size GC_PROTO((void));
+GC_API size_t GC_get_heap_size(void);
 
 /* Return a lower bound on the number of free bytes in the heap.       */
-GC_API size_t GC_get_free_bytes GC_PROTO((void));
+GC_API size_t GC_get_free_bytes(void);
 
 /* Return the number of bytes allocated since the last collection.     */
-GC_API size_t GC_get_bytes_since_gc GC_PROTO((void));
+GC_API size_t GC_get_bytes_since_gc(void);
 
 /* Return the total number of bytes allocated in this process.         */
 /* Never decreases, except due to wrapping.                            */
-GC_API size_t GC_get_total_bytes GC_PROTO((void));
+GC_API size_t GC_get_total_bytes(void);
 
 /* Disable garbage collection.  Even GC_gcollect calls will be                 */
 /* ineffective.                                                                */
-GC_API void GC_disable GC_PROTO((void));
+GC_API void GC_disable(void);
 
 /* Reenable garbage collection.  GC_disable() and GC_enable() calls    */
 /* nest.  Garbage collection is enabled if the number of calls to both */
 /* both functions is equal.                                            */
-GC_API void GC_enable GC_PROTO((void));
+GC_API void GC_enable(void);
 
 /* Enable incremental/generational collection. */
 /* Not advisable unless dirty bits are                 */
@@ -433,17 +420,20 @@ GC_API void GC_enable GC_PROTO((void));
 /* Causes GC_local_gcj_malloc() to revert to   */
 /* locked allocation.  Must be called          */
 /* before any GC_local_gcj_malloc() calls.     */
-GC_API void GC_enable_incremental GC_PROTO((void));
+/* For best performance, should be called as early as possible.        */
+/* On some platforms, calling it later may have adverse effects.*/
+/* Safe to call before GC_INIT().  Includes a GC_init() call.  */
+GC_API void GC_enable_incremental(void);
 
 /* Does incremental mode write-protect pages?  Returns zero or */
 /* more of the following, or'ed together:                      */
 #define GC_PROTECTS_POINTER_HEAP  1 /* May protect non-atomic objs.    */
 #define GC_PROTECTS_PTRFREE_HEAP  2
-#define GC_PROTECTS_STATIC_DATA   4 /* Curently never.                 */
+#define GC_PROTECTS_STATIC_DATA   4 /* Currently never.                        */
 #define GC_PROTECTS_STACK        8 /* Probably impractical.            */
 
 #define GC_PROTECTS_NONE 0
-GC_API int GC_incremental_protection_needs GC_PROTO((void));
+GC_API int GC_incremental_protection_needs(void);
 
 /* Perform some garbage collection work, if appropriate.       */
 /* Return 0 if there is no more work to be done.               */
@@ -452,7 +442,7 @@ GC_API int GC_incremental_protection_needs GC_PROTO((void));
 /* progress requires it, e.g. if incremental collection is     */
 /* disabled.  It is reasonable to call this in a wait loop     */
 /* until it returns 0.                                         */
-GC_API int GC_collect_a_little GC_PROTO((void));
+GC_API int GC_collect_a_little(void);
 
 /* Allocate an object of size lb bytes.  The client guarantees that    */
 /* as long as the object is live, it will be referenced by a pointer   */
@@ -468,8 +458,8 @@ GC_API int GC_collect_a_little GC_PROTO((void));
 /* for arrays likely to be larger than 100K or so.  For other systems, */
 /* or if the collector is not configured to recognize all interior     */
 /* pointers, the threshold is normally much higher.                    */
-GC_API GC_PTR GC_malloc_ignore_off_page GC_PROTO((size_t lb));
-GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
+GC_API void * GC_malloc_ignore_off_page(size_t lb);
+GC_API void * GC_malloc_atomic_ignore_off_page(size_t lb);
 
 #if defined(__sgi) && !defined(__GNUC__) && _COMPILER_VERSION >= 720
 #   define GC_ADD_CALLER
@@ -489,6 +479,13 @@ GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
 # endif
 #endif
 
+#if defined(_MSC_VER) && _MSC_VER >= 1200 /* version 12.0+ (MSVC 6.0+)  */ \
+    && !defined(_AMD64_)
+# ifndef GC_HAVE_NO_BUILTIN_BACKTRACE
+#   define GC_HAVE_BUILTIN_BACKTRACE
+# endif
+#endif
+
 #if defined(GC_HAVE_BUILTIN_BACKTRACE) && !defined(GC_CAN_SAVE_CALL_STACKS)
 # define GC_CAN_SAVE_CALL_STACKS
 #endif
@@ -519,34 +516,30 @@ 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 * s, int i
+#  define GC_EXTRA_PARAMS GC_word ra, const char * s, int i
 #else
 #  define GC_EXTRAS __FILE__, __LINE__
-#  define GC_EXTRA_PARAMS GC_CONST char * s, int i
+#  define GC_EXTRA_PARAMS const char * s, int i
 #endif
 
 /* Debugging (annotated) allocation.  GC_gcollect will check           */
 /* objects allocated in this way for overwrites, etc.                  */
-GC_API GC_PTR GC_debug_malloc
-       GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_atomic
-       GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API char *GC_debug_strdup
-       GC_PROTO((const char *str, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_uncollectable
-       GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_stubborn
-       GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_ignore_off_page
-       GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_atomic_ignore_off_page
-       GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API void GC_debug_free GC_PROTO((GC_PTR object_addr));
-GC_API GC_PTR GC_debug_realloc
-       GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
-                 GC_EXTRA_PARAMS));
-GC_API void GC_debug_change_stubborn GC_PROTO((GC_PTR));
-GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
+GC_API void * GC_debug_malloc(size_t size_in_bytes, GC_EXTRA_PARAMS);
+GC_API void * GC_debug_malloc_atomic(size_t size_in_bytes, GC_EXTRA_PARAMS);
+GC_API char * GC_debug_strdup(const char *str, GC_EXTRA_PARAMS);
+GC_API void * GC_debug_malloc_uncollectable
+       (size_t size_in_bytes, GC_EXTRA_PARAMS);
+GC_API void * GC_debug_malloc_stubborn
+       (size_t size_in_bytes, GC_EXTRA_PARAMS);
+GC_API void * GC_debug_malloc_ignore_off_page
+       (size_t size_in_bytes, GC_EXTRA_PARAMS);
+GC_API void * GC_debug_malloc_atomic_ignore_off_page
+       (size_t size_in_bytes, GC_EXTRA_PARAMS);
+GC_API void GC_debug_free (void * object_addr);
+GC_API void * GC_debug_realloc
+       (void * old_object, size_t new_size_in_bytes, GC_EXTRA_PARAMS);
+GC_API void GC_debug_change_stubborn(void *);
+GC_API void GC_debug_end_stubborn_change(void *);
 
 /* Routines that allocate objects with debug information (like the     */
 /* above), but just fill in dummy file and line number information.    */
@@ -560,9 +553,9 @@ GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
 /*    platforms it may be more convenient not to recompile, e.g. for   */
 /*    leak detection.  This can be accomplished by instructing the     */
 /*    linker to replace malloc/realloc with these.                     */
-GC_API GC_PTR GC_debug_malloc_replacement GC_PROTO((size_t size_in_bytes));
-GC_API GC_PTR GC_debug_realloc_replacement
-             GC_PROTO((GC_PTR object_addr, size_t size_in_bytes));
+GC_API void * GC_debug_malloc_replacement (size_t size_in_bytes);
+GC_API void * GC_debug_realloc_replacement
+             (void * object_addr, size_t size_in_bytes);
                                 
 # ifdef GC_DEBUG
 #   define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
@@ -582,6 +575,8 @@ GC_API GC_PTR GC_debug_realloc_replacement
        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_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
+       GC_debug_register_finalizer_unreachable(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)
@@ -605,6 +600,8 @@ GC_API GC_PTR GC_debug_realloc_replacement
        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_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
+       GC_register_finalizer_unreachable(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)
@@ -628,15 +625,14 @@ GC_API GC_PTR GC_debug_realloc_replacement
 /* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes,             */
 /* Christian Jacobi, and Russ Atkinson.  It's not perfect, and         */
 /* probably nobody else agrees with it.            Hans-J. Boehm  3/13/92      */
-typedef void (*GC_finalization_proc)
-       GC_PROTO((GC_PTR obj, GC_PTR client_data));
+typedef void (*GC_finalization_proc) (void * obj, void * client_data);
 
-GC_API void GC_register_finalizer
-       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
-                 GC_finalization_proc *ofn, GC_PTR *ocd));
+GC_API void GC_register_finalizer(void * obj, GC_finalization_proc fn,
+                                 void * cd, GC_finalization_proc *ofn,
+                                 void * *ocd);
 GC_API void GC_debug_register_finalizer
-       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
-                 GC_finalization_proc *ofn, GC_PTR *ocd));
+                (void * obj, GC_finalization_proc fn, void * cd,
+                 GC_finalization_proc *ofn, void * *ocd);
        /* When obj is no longer accessible, invoke             */
        /* (*fn)(obj, cd).  If a and b are inaccessible, and    */
        /* a points to b (after disappearing links have been    */
@@ -680,23 +676,45 @@ GC_API void GC_debug_register_finalizer
 /* Note that cd will still be viewed as accessible, even if it */
 /* refers to the object itself.                                        */
 GC_API void GC_register_finalizer_ignore_self
-       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
-                 GC_finalization_proc *ofn, GC_PTR *ocd));
+               (void * obj, GC_finalization_proc fn, void * cd,
+                GC_finalization_proc *ofn, void * *ocd);
 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));
+               (void * obj, GC_finalization_proc fn, void * cd,
+                GC_finalization_proc *ofn, void * *ocd);
 
 /* Another version of the above.  It ignores all cycles.        */
 /* It should probably only be used by Java implementations.     */
 /* Note that cd will still be viewed as accessible, even if it */
 /* refers to the object itself.                                        */
 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));
+               (void * obj, GC_finalization_proc fn, void * cd,
+                GC_finalization_proc *ofn, void * *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));
-
+               (void * obj, GC_finalization_proc fn, void * cd,
+                GC_finalization_proc *ofn, void * *ocd);
+
+/* This is a special finalizer that is useful when an object's  */
+/* finalizer must be run when the object is known to be no      */
+/* longer reachable, not even from other finalizable objects.   */
+/* It behaves like "normal" finalization, except that the      */
+/* finalizer is not run while the object is reachable from     */
+/* other objects specifying unordered finalization.            */
+/* Effectively it allows an object referenced, possibly                */
+/* indirectly, from an unordered finalizable object to override */
+/* the unordered finalization request.                         */
+/* This can be used in combination with finalizer_no_order so   */
+/* as to release resources that must not be released while an   */
+/* object can still be brought back to life by other            */
+/* finalizers.                                                  */
+/* Only works if GC_java_finalization is set.  Probably only   */
+/* of interest when implementing a language that requires      */
+/* unordered finalization (e.g. Java, C#).                     */
+GC_API void GC_register_finalizer_unreachable
+                (void * obj, GC_finalization_proc fn, void * cd,
+                 GC_finalization_proc *ofn, void * *ocd);
+GC_API void GC_debug_register_finalizer_unreachable
+                (void * obj, GC_finalization_proc fn, void * cd,
+                 GC_finalization_proc *ofn, void * *ocd);
 
 /* The following routine may be used to break cycles between   */
 /* finalizable objects, thus causing cyclic finalizable                */
@@ -705,7 +723,7 @@ GC_API void GC_debug_register_finalizer_no_order
 /* where p is a pointer that is not followed by finalization   */
 /* code, and should not be considered in determining           */
 /* finalization order.                                         */
-GC_API int GC_register_disappearing_link GC_PROTO((GC_PTR * /* link */));
+GC_API int GC_register_disappearing_link(void * * link );
        /* Link should point to a field of a heap allocated     */
        /* object obj.  *link will be cleared when obj is       */
        /* found to be inaccessible.  This happens BEFORE any   */
@@ -725,8 +743,7 @@ GC_API int GC_register_disappearing_link GC_PROTO((GC_PTR * /* link */));
        /* otherwise.                                           */
        /* Only exists for backward compatibility.  See below:  */
        
-GC_API int GC_general_register_disappearing_link
-       GC_PROTO((GC_PTR * /* link */, GC_PTR obj));
+GC_API int GC_general_register_disappearing_link (void * * link, void * obj);
        /* A slight generalization of the above. *link is       */
        /* cleared when obj first becomes inaccessible.  This   */
        /* can be used to implement weak pointers easily and    */
@@ -744,7 +761,16 @@ GC_API int GC_general_register_disappearing_link
        /* the object containing link.  Explicitly deallocating */
        /* obj may or may not cause link to eventually be       */
        /* cleared.                                             */
-GC_API int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
+       /* This can be used to implement certain types of       */
+       /* weak pointers.  Note however that this generally     */
+       /* requires that thje allocation lock is held (see      */
+       /* GC_call_with_allock_lock() below) when the disguised */
+       /* pointer is accessed.  Otherwise a strong pointer     */
+       /* could be recreated between the time the collector    */
+       /* decides to reclaim the object and the link is        */
+       /* cleared.                                             */
+
+GC_API int GC_unregister_disappearing_link (void * * link);
        /* Returns 0 if link was not actually registered.       */
        /* Undoes a registration by either of the above two     */
        /* routines.                                            */
@@ -752,23 +778,40 @@ GC_API int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
 GC_API void GC_finalize_all();
 
 /* Returns !=0  if GC_invoke_finalizers has something to do.           */
-GC_API int GC_should_invoke_finalizers GC_PROTO((void));
+GC_API int GC_should_invoke_finalizers(void);
 
-GC_API int GC_invoke_finalizers GC_PROTO((void));
+GC_API int GC_invoke_finalizers(void);
        /* Run finalizers for all objects that are ready to     */
        /* be finalized.  Return the number of finalizers       */
        /* that were run.  Normally this is also called         */
        /* implicitly during some allocations.  If              */
-       /* GC_finalize_on_demand is nonzero, it must be called  */
+       /* GC-finalize_on_demand is nonzero, it must be called  */
        /* explicitly.                                          */
 
+/* Explicitly tell the collector that an object is reachable   */
+/* at a particular program point.  This prevents the argument  */
+/* pointer from being optimized away, even it is otherwise no  */
+/* longer needed.  It should have no visible effect in the     */
+/* absence of finalizers or disappearing links.  But it may be */
+/* needed to prevent finalizers from running while the         */
+/* associated external resource is still in use.               */
+/* The function is sometimes called keep_alive in other                */
+/* settings.                                                   */
+# if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+#   define GC_reachable_here(ptr) \
+    __asm__ volatile(" " : : "X"(ptr) : "memory");
+# else
+    GC_API void GC_noop1(GC_word x);
+#   define GC_reachable_here(ptr) GC_noop1((GC_word)(ptr));
+#endif
+
 /* GC_set_warn_proc can be used to redirect or filter warning messages.        */
 /* p may not be a NULL pointer.                                                */
-typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
-GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
+typedef void (*GC_warn_proc) (char *msg, GC_word arg);
+GC_API GC_warn_proc GC_set_warn_proc(GC_warn_proc p);
     /* Returns old warning procedure.  */
 
-GC_API GC_word GC_set_free_space_divisor GC_PROTO((GC_word value));
+GC_API GC_word GC_set_free_space_divisor(GC_word value);
     /* Set free_space_divisor.  See above for definition.      */
     /* Returns old value.                                      */
        
@@ -783,15 +826,71 @@ GC_API GC_word GC_set_free_space_divisor GC_PROTO((GC_word value));
 # if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
     typedef GC_word GC_hidden_pointer;
 #   define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
-#   define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p)))
+#   define REVEAL_POINTER(p) ((void *)(HIDE_POINTER(p)))
     /* Converting a hidden pointer to a real pointer requires verifying        */
     /* that the object still exists.  This involves acquiring the      */
     /* allocator lock to avoid a race with the collector.              */
 # endif /* I_HIDE_POINTERS */
 
-typedef GC_PTR (*GC_fn_type) GC_PROTO((GC_PTR client_data));
-GC_API GC_PTR GC_call_with_alloc_lock
-               GC_PROTO((GC_fn_type fn, GC_PTR client_data));
+typedef void * (*GC_fn_type) (void * client_data);
+GC_API void * GC_call_with_alloc_lock (GC_fn_type fn, void * client_data);
+
+/* These routines are intended to explicitly notify the collector      */
+/* of new threads.  Often this is unnecessary because thread creation  */
+/* is implicitly intercepted by the collector, using header-file       */
+/* defines, or linker-based interception.  In the long run the intent  */
+/* is to always make redundant registration safe.  In the short run,   */
+/* this is being implemented a platform at a time.                     */
+/* The interface is complicated by the fact that we probably will not  */
+/* ever be able to automatically determine the stack base for thread   */
+/* stacks on all platforms.                                            */
+
+/* Structure representing the base of a thread stack.  On most         */
+/* platforms this contains just a single address.                      */
+struct GC_stack_base {
+       void * mem_base;        /* Base of memory stack.        */
+#      if defined(__ia64) || defined(__ia64__)
+         void * reg_base;      /* Base of separate register stack.     */
+#      endif
+};
+
+typedef void * (*GC_stack_base_func)(struct GC_stack_base *sb, void *arg);
+
+/* Call a function with a stack base structure corresponding to                */
+/* somewhere in the GC_call_with_stack_base frame.  This often can     */
+/* be used to provide a sufficiently accurate stack base.  And we      */
+/* implement it everywhere.                                            */
+void * GC_call_with_stack_base(GC_stack_base_func fn, void *arg);
+
+/* Register the current thread, with the indicated stack base, as      */
+/* a new thread whose stack(s) should be traced by the GC.  If a       */
+/* platform does not implicitly do so, this must be called before a    */
+/* thread can allocate garbage collected memory, or assign pointers    */
+/* to the garbage collected heap.  Once registered, a thread will be   */
+/* stopped during garbage collections.                                 */
+/* Return codes:       */
+#define GC_SUCCESS 0
+#define GC_DUPLICATE 1 /* Was already registered.      */
+#define GC_NO_THREADS 2        /* No thread support in GC.     */
+#define GC_UNIMPLEMENTED 3     /* Not yet implemented on this platform. */
+int GC_register_my_thread(struct GC_stack_base *);
+
+/* Unregister the current thread.  The thread may no longer allocate   */
+/* garbage collected memory or manipulate pointers to the              */
+/* garbage collected heap after making this call.                      */
+/* Specifically, if it wants to return or otherwise communicate a      */
+/* pointer to the garbage-collected heap to another thread, it must    */
+/* do this before calling GC_unregister_my_thread, most probably       */
+/* by saving it in a global data structure.                            */
+int GC_unregister_my_thread(void);
+
+/* Attempt to fill in the GC_stack_base structure with the stack base  */
+/* for this thread.  This appears to be required to implement anything */
+/* like the JNI AttachCurrentThread in an environment in which new     */
+/* threads are not automatically registered with the collector.                */
+/* It is also unfortunately hard to implement well on many platforms.  */
+/* Returns GC_SUCCESS or GC_UNIMPLEMENTED.                             */
+int GC_get_stack_base(struct GC_stack_base *);
 
 /* The following routines are primarily intended for use with a        */
 /* preprocessor which inserts calls to check C pointer arithmetic.     */
@@ -802,14 +901,14 @@ GC_API GC_PTR GC_call_with_alloc_lock
 /* Returns the first argument.                                 */
 /* Succeeds if neither p nor q points to the heap.             */
 /* May succeed if both p and q point to between heap objects.  */
-GC_API GC_PTR GC_same_obj GC_PROTO((GC_PTR p, GC_PTR q));
+GC_API void * GC_same_obj (void * p, void * q);
 
 /* Checked pointer pre- and post- increment operations.  Note that     */
 /* the second argument is in units of bytes, not multiples of the      */
 /* object size.  This should either be invoked from a macro, or the    */
 /* call should be automatically generated.                             */
-GC_API GC_PTR GC_pre_incr GC_PROTO((GC_PTR *p, size_t how_much));
-GC_API GC_PTR GC_post_incr GC_PROTO((GC_PTR *p, size_t how_much));
+GC_API void * GC_pre_incr (void * *p, size_t how_much);
+GC_API void * GC_post_incr (void * *p, size_t how_much);
 
 /* Check that p is visible                                             */
 /* to the collector as a possibly pointer containing location.         */
@@ -819,14 +918,19 @@ GC_API GC_PTR GC_post_incr GC_PROTO((GC_PTR *p, size_t how_much));
 /* untyped allocations.  The idea is that it should be possible, though        */
 /* slow, to add such a call to all indirect pointer stores.)           */
 /* Currently useless for multithreaded worlds.                         */
-GC_API GC_PTR GC_is_visible GC_PROTO((GC_PTR p));
+GC_API void * GC_is_visible (void * p);
 
 /* Check that if p is a pointer to a heap page, then it points to      */
 /* a valid displacement within a heap object.                          */
 /* Fail conspicuously if this property does not hold.                  */
 /* Uninteresting with GC_all_interior_pointers.                                */
 /* Always returns its argument.                                                */
-GC_API GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR        p));
+GC_API void * GC_is_valid_displacement (void * p);
+
+/* Explicitly dump the GC state.  This is most often called from the   */
+/* debugger, or by setting the GC_DUMP_REGULARLY environment variable, */
+/* but it may be useful to call it from client code during debugging.  */
+void GC_dump(void);
 
 /* Safer, but slow, pointer addition.  Probably useful mainly with     */
 /* a preprocessor.  Useful only for heap pointers.                     */
@@ -862,25 +966,18 @@ GC_API GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR   p));
 
 /* Safer assignment of a pointer to a nonstack location.       */
 #ifdef GC_DEBUG
-# if defined(__STDC__) || defined(_AIX)
 #   define GC_PTR_STORE(p, q) \
        (*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
-# else
-#   define GC_PTR_STORE(p, q) \
-       (*(char **)GC_is_visible(p) = GC_is_valid_displacement(q))
-# endif
 #else /* !GC_DEBUG */
 #   define GC_PTR_STORE(p, q) *((p) = (q))
 #endif
 
 /* Functions called to report pointer checking errors */
-GC_API void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR p, GC_PTR q));
+GC_API void (*GC_same_obj_print_proc) (void * p, void * q);
 
-GC_API void (*GC_is_valid_displacement_print_proc)
-       GC_PROTO((GC_PTR p));
+GC_API void (*GC_is_valid_displacement_print_proc) (void * p);
 
-GC_API void (*GC_is_visible_print_proc)
-       GC_PROTO((GC_PTR p));
+GC_API void (*GC_is_visible_print_proc) (void * p);
 
 
 /* For pthread support, we generally need to intercept a number of     */
@@ -893,52 +990,98 @@ GC_API void (*GC_is_visible_print_proc)
 
 # if defined(PCR) || defined(GC_SOLARIS_THREADS) || \
      defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
-       /* Any flavor of threads except SRC_M3. */
+       /* Any flavor of threads.       */
 /* This returns a list of objects, linked through their first          */
 /* word.  Its use can greatly reduce lock contention problems, since   */
 /* the allocation lock can be acquired and released many fewer times.  */
-/* lb must be large enough to hold the pointer field.                  */
 /* It is used internally by gc_local_alloc.h, which provides a simpler */
 /* programming interface on Linux.                                     */
-GC_PTR GC_malloc_many(size_t lb);
-#define GC_NEXT(p) (*(GC_PTR *)(p))    /* Retrieve the next element    */
+void * GC_malloc_many(size_t lb);
+#define GC_NEXT(p) (*(void * *)(p))    /* Retrieve the next element    */
                                        /* in returned list.            */
-extern void GC_thr_init GC_PROTO((void));/* Needed for Solaris/X86     */
+extern void GC_thr_init(void); /* Needed for Solaris/X86 ??    */
+
+#endif /* THREADS */
+
+/* Register a callback to control the scanning of dynamic libraries.
+   When the GC scans the static data of a dynamic library, it will
+   first call a user-supplied routine with filename of the library and
+   the address and length of the memory region.  This routine should
+   return nonzero if that region should be scanned.  */
+GC_API void 
+GC_register_has_static_roots_callback
+  (int (*callback)(const char *, void *, size_t));
+
+
+#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) \
+       && !defined(__CYGWIN__) \
+       && !defined(GC_PTHREADS)
 
-#endif /* THREADS && !SRC_M3 */
+#ifdef __cplusplus
+    }  /* Including windows.h in an extern "C" context no longer works. */
+#endif
 
-#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
 # include <windows.h>
 
+#ifdef __cplusplus
+    extern "C" {
+#endif
   /*
-   * All threads must be created using GC_CreateThread, so that they will be
-   * recorded in the thread table.  For backwards compatibility, this is not
-   * technically true if the GC is built as a dynamic library, since it can
-   * and does then use DllMain to keep track of thread creations.  But new code
-   * should be built to call GC_CreateThread.
+   * All threads must be created using GC_CreateThread or GC_beginthreadex,
+   * or must explicitly call GC_register_my_thread,
+   * so that they will be recorded in the thread table.
+   * For backwards compatibility, it is possible to build the GC
+   * with GC_DLL defined, and to call GC_use_DllMain().
+   * This implicitly registers all created threads, but appears to be
+   * less robust.
+   *
+   * Currently the collector expects all threads to fall through and
+   * terminate normally, or call GC_endthreadex() or GC_ExitThread,
+   * so that the thread is properly unregistered.  (An explicit call
+   * to GC_unregister_my_thread() should also work, but risks unregistering
+   * the thread twice.)
    */
    GC_API HANDLE WINAPI GC_CreateThread(
       LPSECURITY_ATTRIBUTES lpThreadAttributes,
       DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
       LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
 
+
+   GC_API uintptr_t GC_beginthreadex(
+     void *security, unsigned stack_size,
+     unsigned ( __stdcall *start_address )( void * ),
+     void *arglist, unsigned initflag, unsigned *thrdaddr);
+
+   GC_API void GC_endthreadex(unsigned retval);
+
+   GC_API void WINAPI GC_ExitThread(DWORD dwExitCode);
+
 # if defined(_WIN32_WCE)
   /*
    * win32_threads.c implements the real WinMain, which will start a new thread
    * to call GC_WinMain after initializing the garbage collector.
    */
-  int WINAPI GC_WinMain(
+  GC_API int WINAPI GC_WinMain(
       HINSTANCE hInstance,
       HINSTANCE hPrevInstance,
       LPWSTR lpCmdLine,
       int nCmdShow );
-
 #  ifndef GC_BUILD
 #    define WinMain GC_WinMain
-#    define CreateThread GC_CreateThread
 #  endif
 # endif /* defined(_WIN32_WCE) */
 
+  /*
+   * Use implicit thread registration via DllMain.
+   */
+GC_API void GC_use_DllMain(void);
+
+# define CreateThread GC_CreateThread
+# define ExitThread GC_ExitThread
+# define _beginthreadex GC_beginthreadex
+# define _endthreadex GC_endthreadex
+# define _beginthread { > "Please use _beginthreadex instead of _beginthread" < }
+
 #endif /* defined(GC_WIN32_THREADS)  && !cygwin */
 
  /*
@@ -946,24 +1089,10 @@ extern void GC_thr_init GC_PROTO((void));/* Needed for Solaris/X86       */
   * before making any other GC_ calls.  On most platforms this is a
   * no-op and the collector self-initializes.  But a number of platforms
   * make that too hard.
+  * A GC_INIT call is required if the collector is built with THREAD_LOCAL_ALLOC
+  * defined and the initial allocation call is not to GC_malloc().
   */
-#if (defined(sparc) || defined(__sparc)) && defined(sun)
-    /*
-     * If you are planning on putting
-     * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
-     * from the statically loaded program section.
-     * This circumvents a Solaris 2.X (X<=4) linker bug.
-     */
-    extern int _end[], _etext[];
-#   ifdef __cplusplus
-      extern "C" void GC_noop1(GC_word);
-#   else
-      void GC_noop1();
-#   endif /* !__cplusplus */
-#   define GC_INIT() { GC_noop1((GC_word)_end); \
-                      GC_noop1((GC_word)_etext); }
-#else
-# if defined(__CYGWIN32__) || defined (_AIX)
+#if defined(__CYGWIN32__) || defined (_AIX)
     /*
      * Similarly gnu-win32 DLLs need explicit initialization from
      * the main program, as does AIX.
@@ -975,28 +1104,25 @@ extern void GC_thr_init GC_PROTO((void));/* Needed for Solaris/X86       */
       extern int _bss_end__[];
 #     define GC_MAX(x,y) ((x) > (y) ? (x) : (y))
 #     define GC_MIN(x,y) ((x) < (y) ? (x) : (y))
-#     define GC_DATASTART ((GC_PTR) GC_MIN(_data_start__, _bss_start__))
-#     define GC_DATAEND         ((GC_PTR) GC_MAX(_data_end__, _bss_end__))
-#     ifdef GC_DLL
-#       define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); }
+#     define GC_DATASTART ((void *) GC_MIN(_data_start__, _bss_start__))
+#     define GC_DATAEND         ((void *) GC_MAX(_data_end__, _bss_end__))
+#     if defined(GC_DLL)
+#       define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); \
+                          GC_gcollect(); /* For blacklisting. */}
 #     else
-#       define GC_INIT()
+       /* Main program init not required  */
+#       define GC_INIT() { GC_init(); }
 #     endif
 #   endif
 #   if defined(_AIX)
       extern int _data[], _end[];
-#     define GC_DATASTART ((GC_PTR)((ulong)_data))
-#     define GC_DATAEND ((GC_PTR)((ulong)_end))
+#     define GC_DATASTART ((void *)((ulong)_data))
+#     define GC_DATAEND ((void *)((ulong)_end))
 #     define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); }
 #   endif
-# else
-#  if defined(__APPLE__) && defined(__MACH__) || defined(GC_WIN32_THREADS)
+#else
 #   define GC_INIT() { GC_init(); }
-#  else
-#   define GC_INIT()
-#  endif /* !__MACH && !GC_WIN32_THREADS */
-# endif /* !AIX && !cygwin */
-#endif /* !sparc */
+#endif
 
 #if !defined(_WIN32_WCE) \
     && ((defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
diff --git a/src/mm/boehm-gc/include/gc_alloc.h b/src/mm/boehm-gc/include/gc_alloc.h
deleted file mode 100644 (file)
index c50a758..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Copyright (c) 1996-1998 by Silicon Graphics.  All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose,  provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-
-//
-// This is a C++ header file that is intended to replace the SGI STL
-// alloc.h.  This assumes SGI STL version < 3.0.
-//
-// This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE
-// and -DALL_INTERIOR_POINTERS.  We also recommend
-// -DREDIRECT_MALLOC=GC_uncollectable_malloc.
-//
-// Some of this could be faster in the explicit deallocation case.  In particular,
-// we spend too much time clearing objects on the free lists.  That could be avoided.
-//
-// This uses template classes with static members, and hence does not work
-// with g++ 2.7.2 and earlier.
-//
-// This code assumes that the collector itself has been compiled with a
-// compiler that defines __STDC__ .
-//
-
-#include "gc.h"
-
-#ifndef GC_ALLOC_H
-
-#define GC_ALLOC_H
-#define __ALLOC_H      // Prevent inclusion of the default version.  Ugly.
-#define __SGI_STL_ALLOC_H
-#define __SGI_STL_INTERNAL_ALLOC_H
-
-#ifndef __ALLOC
-#   define __ALLOC alloc
-#endif
-
-#include <stddef.h>
-#include <string.h>
-
-// The following is just replicated from the conventional SGI alloc.h:
-
-template<class T, class alloc>
-class simple_alloc {
-
-public:
-    static T *allocate(size_t n)
-                { return 0 == n? 0 : (T*) alloc::allocate(n * sizeof (T)); }
-    static T *allocate(void)
-                { return (T*) alloc::allocate(sizeof (T)); }
-    static void deallocate(T *p, size_t n)
-                { if (0 != n) alloc::deallocate(p, n * sizeof (T)); }
-    static void deallocate(T *p)
-                { alloc::deallocate(p, sizeof (T)); }
-};
-
-#include "gc.h"
-
-// The following need to match collector data structures.
-// We can't include gc_priv.h, since that pulls in way too much stuff.
-// This should eventually be factored out into another include file.
-
-extern "C" {
-    extern void ** const GC_objfreelist_ptr;
-    extern void ** const GC_aobjfreelist_ptr;
-    extern void ** const GC_uobjfreelist_ptr;
-    extern void ** const GC_auobjfreelist_ptr;
-
-    extern void GC_incr_words_allocd(size_t words);
-    extern void GC_incr_mem_freed(size_t words);
-
-    extern char * GC_generic_malloc_words_small(size_t word, int kind);
-}
-
-// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
-// AUNCOLLECTABLE in gc_priv.h.
-
-enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
-       GC_AUNCOLLECTABLE = 3 };
-
-enum { GC_max_fast_bytes = 255 };
-
-enum { GC_bytes_per_word = sizeof(char *) };
-
-enum { GC_byte_alignment = 8 };
-
-enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
-
-inline void * &GC_obj_link(void * p)
-{   return *(void **)p;  }
-
-// Compute a number of words >= n+1 bytes.
-// The +1 allows for pointers one past the end.
-inline size_t GC_round_up(size_t n)
-{
-    return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
-}
-
-// The same but don't allow for extra byte.
-inline size_t GC_round_up_uncollectable(size_t n)
-{
-    return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
-}
-
-template <int dummy>
-class GC_aux_template {
-public:
-  // File local count of allocated words.  Occasionally this is
-  // added into the global count.  A separate count is necessary since the
-  // real one must be updated with a procedure call.
-  static size_t GC_words_recently_allocd;
-
-  // Same for uncollectable mmory.  Not yet reflected in either
-  // GC_words_recently_allocd or GC_non_gc_bytes.
-  static size_t GC_uncollectable_words_recently_allocd;
-
-  // Similar counter for explicitly deallocated memory.
-  static size_t GC_mem_recently_freed;
-
-  // Again for uncollectable memory.
-  static size_t GC_uncollectable_mem_recently_freed;
-
-  static void * GC_out_of_line_malloc(size_t nwords, int kind);
-};
-
-template <int dummy>
-size_t GC_aux_template<dummy>::GC_words_recently_allocd = 0;
-
-template <int dummy>
-size_t GC_aux_template<dummy>::GC_uncollectable_words_recently_allocd = 0;
-
-template <int dummy>
-size_t GC_aux_template<dummy>::GC_mem_recently_freed = 0;
-
-template <int dummy>
-size_t GC_aux_template<dummy>::GC_uncollectable_mem_recently_freed = 0;
-
-template <int dummy>
-void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
-{
-    GC_words_recently_allocd += GC_uncollectable_words_recently_allocd;
-    GC_non_gc_bytes +=
-                GC_bytes_per_word * GC_uncollectable_words_recently_allocd;
-    GC_uncollectable_words_recently_allocd = 0;
-
-    GC_mem_recently_freed += GC_uncollectable_mem_recently_freed;
-    GC_non_gc_bytes -= 
-                GC_bytes_per_word * GC_uncollectable_mem_recently_freed;
-    GC_uncollectable_mem_recently_freed = 0;
-
-    GC_incr_words_allocd(GC_words_recently_allocd);
-    GC_words_recently_allocd = 0;
-
-    GC_incr_mem_freed(GC_mem_recently_freed);
-    GC_mem_recently_freed = 0;
-
-    return GC_generic_malloc_words_small(nwords, kind);
-}
-
-typedef GC_aux_template<0> GC_aux;
-
-// A fast, single-threaded, garbage-collected allocator
-// We assume the first word will be immediately overwritten.
-// In this version, deallocation is not a noop, and explicit
-// deallocation is likely to help performance.
-template <int dummy>
-class single_client_gc_alloc_template {
-    public:
-       static void * allocate(size_t n)
-        {
-           size_t nwords = GC_round_up(n);
-           void ** flh;
-           void * op;
-
-           if (n > GC_max_fast_bytes) return GC_malloc(n);
-           flh = GC_objfreelist_ptr + nwords;
-           if (0 == (op = *flh)) {
-               return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
-           }
-           *flh = GC_obj_link(op);
-           GC_aux::GC_words_recently_allocd += nwords;
-           return op;
-        }
-       static void * ptr_free_allocate(size_t n)
-        {
-           size_t nwords = GC_round_up(n);
-           void ** flh;
-           void * op;
-
-           if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
-           flh = GC_aobjfreelist_ptr + nwords;
-           if (0 == (op = *flh)) {
-               return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
-           }
-           *flh = GC_obj_link(op);
-           GC_aux::GC_words_recently_allocd += nwords;
-           return op;
-        }
-       static void deallocate(void *p, size_t n)
-       {
-            size_t nwords = GC_round_up(n);
-            void ** flh;
-          
-           if (n > GC_max_fast_bytes)  {
-               GC_free(p);
-           } else {
-               flh = GC_objfreelist_ptr + nwords;
-               GC_obj_link(p) = *flh;
-               memset((char *)p + GC_bytes_per_word, 0,
-                      GC_bytes_per_word * (nwords - 1));
-               *flh = p;
-               GC_aux::GC_mem_recently_freed += nwords;
-           }
-       }
-       static void ptr_free_deallocate(void *p, size_t n)
-       {
-            size_t nwords = GC_round_up(n);
-            void ** flh;
-          
-           if (n > GC_max_fast_bytes) {
-               GC_free(p);
-           } else {
-               flh = GC_aobjfreelist_ptr + nwords;
-               GC_obj_link(p) = *flh;
-               *flh = p;
-               GC_aux::GC_mem_recently_freed += nwords;
-           }
-       }
-};
-
-typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
-
-// Once more, for uncollectable objects.
-template <int dummy>
-class single_client_alloc_template {
-    public:
-       static void * allocate(size_t n)
-        {
-           size_t nwords = GC_round_up_uncollectable(n);
-           void ** flh;
-           void * op;
-
-           if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
-           flh = GC_uobjfreelist_ptr + nwords;
-           if (0 == (op = *flh)) {
-               return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
-           }
-           *flh = GC_obj_link(op);
-           GC_aux::GC_uncollectable_words_recently_allocd += nwords;
-           return op;
-        }
-       static void * ptr_free_allocate(size_t n)
-        {
-           size_t nwords = GC_round_up_uncollectable(n);
-           void ** flh;
-           void * op;
-
-           if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
-           flh = GC_auobjfreelist_ptr + nwords;
-           if (0 == (op = *flh)) {
-               return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
-           }
-           *flh = GC_obj_link(op);
-           GC_aux::GC_uncollectable_words_recently_allocd += nwords;
-           return op;
-        }
-       static void deallocate(void *p, size_t n)
-       {
-            size_t nwords = GC_round_up_uncollectable(n);
-            void ** flh;
-          
-           if (n > GC_max_fast_bytes)  {
-               GC_free(p);
-           } else {
-               flh = GC_uobjfreelist_ptr + nwords;
-               GC_obj_link(p) = *flh;
-               *flh = p;
-               GC_aux::GC_uncollectable_mem_recently_freed += nwords;
-           }
-       }
-       static void ptr_free_deallocate(void *p, size_t n)
-       {
-            size_t nwords = GC_round_up_uncollectable(n);
-            void ** flh;
-          
-           if (n > GC_max_fast_bytes) {
-               GC_free(p);
-           } else {
-               flh = GC_auobjfreelist_ptr + nwords;
-               GC_obj_link(p) = *flh;
-               *flh = p;
-               GC_aux::GC_uncollectable_mem_recently_freed += nwords;
-           }
-       }
-};
-
-typedef single_client_alloc_template<0> single_client_alloc;
-
-template < int dummy >
-class gc_alloc_template {
-    public:
-       static void * allocate(size_t n) { return GC_malloc(n); }
-       static void * ptr_free_allocate(size_t n)
-               { return GC_malloc_atomic(n); }
-       static void deallocate(void *, size_t) { }
-       static void ptr_free_deallocate(void *, size_t) { }
-};
-
-typedef gc_alloc_template < 0 > gc_alloc;
-
-template < int dummy >
-class alloc_template {
-    public:
-       static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
-       static void * ptr_free_allocate(size_t n)
-               { return GC_malloc_atomic_uncollectable(n); }
-       static void deallocate(void *p, size_t) { GC_free(p); }
-       static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
-};
-
-typedef alloc_template < 0 > alloc;
-
-#ifdef _SGI_SOURCE
-
-// We want to specialize simple_alloc so that it does the right thing
-// for all pointerfree types.  At the moment there is no portable way to
-// even approximate that.  The following approximation should work for
-// SGI compilers, and perhaps some others.
-
-# define __GC_SPECIALIZE(T,alloc) \
-class simple_alloc<T, alloc> { \
-public: \
-    static T *allocate(size_t n) \
-       { return 0 == n? 0 : \
-                        (T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
-    static T *allocate(void) \
-       { return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
-    static void deallocate(T *p, size_t n) \
-       { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
-    static void deallocate(T *p) \
-       { alloc::ptr_free_deallocate(p, sizeof (T)); } \
-};
-
-__GC_SPECIALIZE(char, gc_alloc)
-__GC_SPECIALIZE(int, gc_alloc)
-__GC_SPECIALIZE(unsigned, gc_alloc)
-__GC_SPECIALIZE(float, gc_alloc)
-__GC_SPECIALIZE(double, gc_alloc)
-
-__GC_SPECIALIZE(char, alloc)
-__GC_SPECIALIZE(int, alloc)
-__GC_SPECIALIZE(unsigned, alloc)
-__GC_SPECIALIZE(float, alloc)
-__GC_SPECIALIZE(double, alloc)
-
-__GC_SPECIALIZE(char, single_client_gc_alloc)
-__GC_SPECIALIZE(int, single_client_gc_alloc)
-__GC_SPECIALIZE(unsigned, single_client_gc_alloc)
-__GC_SPECIALIZE(float, single_client_gc_alloc)
-__GC_SPECIALIZE(double, single_client_gc_alloc)
-
-__GC_SPECIALIZE(char, single_client_alloc)
-__GC_SPECIALIZE(int, single_client_alloc)
-__GC_SPECIALIZE(unsigned, single_client_alloc)
-__GC_SPECIALIZE(float, single_client_alloc)
-__GC_SPECIALIZE(double, single_client_alloc)
-
-#ifdef __STL_USE_STD_ALLOCATORS
-
-???copy stuff from stl_alloc.h or remove it to a different file ???
-
-#endif /* __STL_USE_STD_ALLOCATORS */
-
-#endif /* _SGI_SOURCE */
-
-#endif /* GC_ALLOC_H */
index 200f181efa6f17261b8187570389c50c96ae2814..4f3117b3bd4c9e4adf7e82f53d932fbba3e40fa9 100644 (file)
@@ -40,6 +40,7 @@
 #define GC_ALLOCATOR_H
 
 #include "gc.h"
+#include <new> // for placement new
 
 #if defined(__GNUC__)
 #  define GC_ATTR_UNUSED __attribute__((unused))
@@ -64,6 +65,7 @@ struct GC_type_traits {
 # define GC_DECLARE_PTRFREE(T) \
 template<> struct GC_type_traits<T> { GC_true_type GC_is_ptr_free; }
 
+GC_DECLARE_PTRFREE(char);
 GC_DECLARE_PTRFREE(signed char);
 GC_DECLARE_PTRFREE(unsigned char);
 GC_DECLARE_PTRFREE(signed short);
@@ -74,6 +76,7 @@ GC_DECLARE_PTRFREE(signed long);
 GC_DECLARE_PTRFREE(unsigned long);
 GC_DECLARE_PTRFREE(float);
 GC_DECLARE_PTRFREE(double);
+GC_DECLARE_PTRFREE(long double);
 /* The client may want to add others.  */
 
 // In the following GC_Tp is GC_true_type iff we are allocating a
@@ -106,13 +109,11 @@ public:
   };
 
   gc_allocator()  {}
-# ifndef _MSC_VER
-    // I'm not sure why this is needed here in addition to the following.
-    // The standard specifies it for the standard allocator, but VC++ rejects
-    // it.     -HB
     gc_allocator(const gc_allocator&) throw() {}
-# endif
+# if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
+  // MSVC++ 6.0 do not support member templates
   template <class GC_Tp1> gc_allocator(const gc_allocator<GC_Tp1>&) throw() {}
+# endif
   ~gc_allocator() throw() {}
 
   pointer address(reference GC_x) const { return &GC_x; }
@@ -187,11 +188,12 @@ public:
   };
 
   traceable_allocator() throw() {}
-# ifndef _MSC_VER
     traceable_allocator(const traceable_allocator&) throw() {}
-# endif
+# if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
+  // MSVC++ 6.0 do not support member templates
   template <class GC_Tp1> traceable_allocator
          (const traceable_allocator<GC_Tp1>&) throw() {}
+# endif
   ~traceable_allocator() throw() {}
 
   pointer address(reference GC_x) const { return &GC_x; }
index 1d1a2daace4d48d9682188aa83ecef12b998a828..66abf0b1e3e371d0e5aa16b4c7c186a8d9ef9811 100644 (file)
@@ -5,11 +5,13 @@
  * Some tests for old macros.  These violate our namespace rules and will
  * disappear shortly.  Use the GC_ names.
  */
-#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS)
-# define GC_SOLARIS_THREADS
-#endif
-#if defined(_SOLARIS_PTHREADS)
-# define GC_SOLARIS_PTHREADS
+#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS) \
+    || defined(_SOLARIS_PTHREADS) || defined(GC_SOLARIS_PTHREADS)
+  /* We no longer support old style Solaris threads.           */
+  /* GC_SOLARIS_THREADS now means pthreads.                    */
+# ifndef GC_SOLARIS_THREADS
+#   define GC_SOLARIS_THREADS
+# endif
 #endif
 #if defined(IRIX_THREADS)
 # define GC_IRIX_THREADS
 #endif
 
 #if !defined(_REENTRANT) && (defined(GC_SOLARIS_THREADS) \
-                            || defined(GC_SOLARIS_PTHREADS) \
                             || defined(GC_HPUX_THREADS) \
                             || defined(GC_AIX_THREADS) \
                             || defined(GC_LINUX_THREADS) \
-                            || defined(GC_NETBSD_THREADS))
+                            || defined(GC_NETBSD_THREADS) \
+                            || defined(GC_GNU_THREADS))
 # define _REENTRANT
        /* Better late than never.  This fails if system headers that   */
        /* depend on this were previously included.                     */
 # define _POSIX4A_DRAFT10_SOURCE 1
 #endif
 
-# if defined(GC_SOLARIS_PTHREADS) || defined(GC_FREEBSD_THREADS) || \
+# if defined(GC_SOLARIS_THREADS) || defined(GC_FREEBSD_THREADS) || \
        defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \
        defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \
        defined(GC_DGUX386_THREADS) || defined(GC_DARWIN_THREADS) || \
         defined(GC_AIX_THREADS) || defined(GC_NETBSD_THREADS) || \
-        (defined(GC_WIN32_THREADS) && defined(__CYGWIN32__))
+        (defined(GC_WIN32_THREADS) && defined(__CYGWIN32__)) || \
+       defined(GC_GNU_THREADS)
 #   define GC_PTHREADS
 # endif
 
+#if defined(GC_WIN32_PTHREADS)
+#   define GC_WIN32_THREADS
+#   define GC_PTHREADS
+#endif
+
 #if defined(GC_THREADS) && !defined(GC_PTHREADS)
 # if defined(__linux__)
 #   define GC_LINUX_THREADS
 #   define GC_PTHREADS
 # endif
 # if !defined(__linux__) && (defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
-                         || defined(hppa) || defined(__HPPA))
+                         || defined(hppa) || defined(__HPPA)) \
+                        || (defined(__ia64) && defined(_HPUX_SOURCE))
 #   define GC_HPUX_THREADS
 #   define GC_PTHREADS
 # endif
 #   define GC_IRIX_THREADS
 #   define GC_PTHREADS
 # endif
-# if defined(__sparc) && !defined(__linux__)
-#   define GC_SOLARIS_PTHREADS
+# if defined(__sparc) && !defined(__linux__) \
+     || defined(sun) && (defined(i386) || defined(__i386__))
+#   define GC_SOLARIS_THREADS
 #   define GC_PTHREADS
 # endif
-# if defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
+# if defined(__APPLE__) && defined(__MACH__)
 #   define GC_DARWIN_THREADS
 #   define GC_PTHREADS
 # endif
 # endif
 #endif /* GC_THREADS */
 
-#if defined(GC_THREADS) && !defined(GC_PTHREADS) && \
-    (defined(_WIN32) || defined(_MSC_VER) || defined(__CYGWIN__) \
+#if defined(GC_THREADS) && !defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) \
+    && (defined(_WIN32) || defined(_MSC_VER) || defined(__CYGWIN__) \
      || defined(__MINGW32__) || defined(__BORLANDC__) \
      || defined(_WIN32_WCE))
 # define GC_WIN32_THREADS
-#endif
-
-#if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS)
-#   define GC_SOLARIS_THREADS
+# if defined(__CYGWIN__)
+#   define GC_PTHREADS
+# endif
 #endif
 
 # define __GC
 # ifndef _WIN32_WCE
 #   include <stddef.h>
+#   if defined(__MINGW32__)
+#     include <stdint.h>
+      /* We mention uintptr_t.                                     */
+      /* Perhaps this should be included in pure msft environments  */
+      /* as well?                                                  */
+#   endif
 # else /* ! _WIN32_WCE */
 /* Yet more kluges for WinCE */
 #   include <stdlib.h>         /* size_t is defined here */
index da2fac025ae86c79d32c5d551c1a08006cf842e4..d3df21121038b4b6e66000f49a475d98ab2c67ea 100644 (file)
@@ -48,6 +48,12 @@ using the NoGC placement:
     class A: public gc {...};
     A* a = new (NoGC) A;   // a is uncollectable.
 
+The new(PointerFreeGC) syntax allows the allocation of collectable
+objects that are not scanned by the collector.  This useful if you
+are allocating compressed data, bitmaps, or network packets.  (In
+the latter case, it may remove danger of unfriendly network packets
+intentionally containing values that cause spurious memory retention.)
+
 Both uncollectable and collectable objects can be explicitly deleted
 with "delete", which invokes an object's destructors and frees its
 storage immediately.
@@ -80,7 +86,8 @@ objects.  In practice, it finds almost all of them.
 
 Cautions:
 
-1. Be sure the collector has been augmented with "make c++".
+1. Be sure the collector has been augmented with "make c++" or
+"--enable-cplusplus".
 
 2.  If your compiler supports the new "operator new[]" syntax, then
 add -DGC_OPERATOR_NEW_ARRAY to the Makefile.
@@ -111,7 +118,7 @@ clean-up function:
 that preserves the correct exception semantics requires a language
 extension, e.g. the "gc" keyword.)
 
-4. Compiler bugs:
+4. Compiler bugs (now hopefully history):
 
 * Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
 destructors of classes derived from gc_cleanup won't be invoked.
index 5e79e27b821606f267944e7da5df840fe56cd0be..699ddf5d48bd42429e56857dff5b103d9bf7c1cd 100644 (file)
@@ -71,18 +71,6 @@ extern void * GC_debug_gcj_malloc(size_t lb,
                                  void * ptr_to_struct_containing_descr,
                                  GC_EXTRA_PARAMS);
 
-/* Similar to the above, but the size is in words, and we don't        */
-/* adjust it.  The size is assumed to be such that it can be   */
-/* allocated as a small object.                                        */
-/* Unless it is known that the collector is not configured     */
-/* with USE_MARK_BYTES and unless it is known that the object  */
-/* has weak alignment requirements, lw must be even.           */
-extern void * GC_gcj_fast_malloc(size_t lw,
-                                void * ptr_to_struct_containing_descr);
-extern void * GC_debug_gcj_fast_malloc(size_t lw,
-                                void * ptr_to_struct_containing_descr,
-                                GC_EXTRA_PARAMS);
-
 /* Similar to GC_gcj_malloc, but assumes that a pointer to near the    */
 /* beginning of the resulting object is always maintained.             */
 extern void * GC_gcj_malloc_ignore_off_page(size_t lb,
@@ -94,18 +82,11 @@ extern int GC_gcj_kind;
 
 extern int GC_gcj_debug_kind;
 
-# if defined(GC_LOCAL_ALLOC_H) && defined(GC_REDIRECT_TO_LOCAL)
-    --> gc_local_alloc.h should be included after this.  Otherwise
-    --> we undo the redirection.
-# endif
-
 # ifdef GC_DEBUG
 #   define GC_GCJ_MALLOC(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
-#   define GC_GCJ_FAST_MALLOC(s,d) GC_debug_gcj_fast_malloc(s,d,GC_EXTRAS)
 #   define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
 # else
 #   define GC_GCJ_MALLOC(s,d) GC_gcj_malloc(s,d)
-#   define GC_GCJ_FAST_MALLOC(s,d) GC_gcj_fast_malloc(s,d)
 #   define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) \
        GC_gcj_malloc_ignore_off_page(s,d)
 # endif
diff --git a/src/mm/boehm-gc/include/gc_inl.h b/src/mm/boehm-gc/include/gc_inl.h
deleted file mode 100644 (file)
index c535cfd..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* 
- * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
- * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose,  provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/* Boehm, October 3, 1995 2:07 pm PDT */
-# ifndef GC_PRIVATE_H
-#   include "private/gc_priv.h"
-# endif
-
-/* USE OF THIS FILE IS NOT RECOMMENDED unless GC_all_interior_pointers */
-/* is always set, or the collector has been built with                 */
-/* -DDONT_ADD_BYTE_AT_END, or the specified size includes a pointerfree        */
-/* word at the end.  In the standard collector configuration,          */
-/* the final word of each object may not be scanned.                   */
-/* This iinterface is most useful for compilers that generate C.       */
-/* Manual use is hereby discouraged.                                   */
-
-/* Allocate n words (NOT BYTES).  X is made to point to the result.    */
-/* It is assumed that n < MAXOBJSZ, and                                        */
-/* that n > 0.  On machines requiring double word alignment of some    */
-/* data, we also assume that n is 1 or even.                           */
-/* If the collector is built with -DUSE_MARK_BYTES or -DPARALLEL_MARK, */
-/* the n = 1 case is also disallowed.                                  */
-/* Effectively this means that portable code should make sure n is even.*/
-/* This bypasses the                                                   */
-/* MERGE_SIZES mechanism.  In order to minimize the number of distinct */
-/* free lists that are maintained, the caller should ensure that a     */
-/* small number of distinct values of n are used.  (The MERGE_SIZES    */
-/* mechanism normally does this by ensuring that only the leading three        */
-/* bits of n may be nonzero.  See misc.c for details.)  We really      */
-/* recommend this only in cases in which n is a constant, and no       */
-/* locking is required.                                                        */
-/* In that case it may allow the compiler to perform substantial       */
-/* additional optimizations.                                           */
-# define GC_MALLOC_WORDS(result,n) \
-{      \
-    register ptr_t op; \
-    register ptr_t *opp;       \
-    DCL_LOCK_STATE;    \
-       \
-    opp = &(GC_objfreelist[n]);        \
-    FASTLOCK();        \
-    if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {  \
-        FASTUNLOCK();  \
-        (result) = GC_generic_malloc_words_small((n), NORMAL); \
-    } else {   \
-        *opp = obj_link(op);   \
-        obj_link(op) = 0;      \
-        GC_words_allocd += (n);        \
-        FASTUNLOCK();  \
-        (result) = (GC_PTR) op;        \
-    }  \
-}
-
-
-/* The same for atomic objects:        */
-# define GC_MALLOC_ATOMIC_WORDS(result,n) \
-{      \
-    register ptr_t op; \
-    register ptr_t *opp;       \
-    DCL_LOCK_STATE;    \
-       \
-    opp = &(GC_aobjfreelist[n]);       \
-    FASTLOCK();        \
-    if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {  \
-        FASTUNLOCK();  \
-        (result) = GC_generic_malloc_words_small((n), PTRFREE);        \
-    } else {   \
-        *opp = obj_link(op);   \
-        obj_link(op) = 0;      \
-        GC_words_allocd += (n);        \
-        FASTUNLOCK();  \
-        (result) = (GC_PTR) op;        \
-    }  \
-}
-
-/* And once more for two word initialized objects: */
-# define GC_CONS(result, first, second) \
-{      \
-    register ptr_t op; \
-    register ptr_t *opp;       \
-    DCL_LOCK_STATE;    \
-       \
-    opp = &(GC_objfreelist[2]);        \
-    FASTLOCK();        \
-    if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {  \
-        FASTUNLOCK();  \
-        op = GC_generic_malloc_words_small(2, NORMAL); \
-    } else {   \
-        *opp = obj_link(op);   \
-        GC_words_allocd += 2;  \
-        FASTUNLOCK();  \
-    } \
-    ((word *)op)[0] = (word)(first);   \
-    ((word *)op)[1] = (word)(second);  \
-    (result) = (GC_PTR) op;    \
-}
index db62d1d58a815eaef9a376d0627873eacaf938d8..da7e2e91f020e8d120506f42c5493cf1e6f1734b 100644 (file)
@@ -1 +1,128 @@
-# include "gc_inl.h"
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* USE OF THIS FILE IS NOT RECOMMENDED unless GC_all_interior_pointers */
+/* is not set, or the collector has been built with                    */
+/* -DDONT_ADD_BYTE_AT_END, or the specified size includes a pointerfree        */
+/* word at the end.  In the standard collector configuration,          */
+/* the final word of each object may not be scanned.                   */
+/* This interface is most useful for compilers that generate C.                */
+/* It is also used internally for thread-local allocation, in which    */
+/* case, the size is suitably adjusted by the caller.                  */
+/* Manual use is hereby discouraged.                                   */
+
+#include "gc.h"
+#include "gc_tiny_fl.h"
+
+#if __GNUC__ >= 3
+# define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome)
+  /* Equivalent to (expr), but predict that usually (expr)==outcome. */
+#else
+# define GC_EXPECT(expr, outcome) (expr)
+#endif /* __GNUC__ */
+
+/* The ultimately general inline allocation macro.  Allocate an object */
+/* of size bytes, putting the resulting pointer in result.  Tiny_fl is */
+/* a "tiny" free list array, which will be used first, if the size     */
+/* is appropriate.  If bytes is too large, we allocate with            */
+/* default_expr instead.  If we need to refill the free list, we use   */
+/* GC_generic_malloc_many with the indicated kind.                     */
+/* Tiny_fl should be an array of GC_TINY_FREELISTS void * pointers.    */
+/* If num_direct is nonzero, and the individual free list pointers     */
+/* are initialized to (void *)1, then we allocate numdirect granules   */
+/* directly using gmalloc before putting multiple objects into the     */
+/* tiny_fl entry.  If num_direct is zero, then the free lists may also */
+/* be initialized to (void *)0.                                                */
+/* We rely on much of this hopefully getting optimized away in the     */
+/* num_direct = 0 case.                                                        */
+/* Particularly if bytes is constant, this should generate a small     */
+/* amount of code.                                                     */
+# define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct,\
+                             kind,default_expr,init) \
+{ \
+    if (GC_EXPECT(granules >= GC_TINY_FREELISTS,0)) { \
+        result = default_expr; \
+    } else { \
+       void **my_fl = tiny_fl + granules; \
+        void *my_entry=*my_fl; \
+       void *next; \
+ \
+       while (GC_EXPECT((GC_word)my_entry \
+                               <= num_direct + GC_TINY_FREELISTS + 1, 0)) { \
+           /* Entry contains counter or NULL */ \
+           if ((GC_word)my_entry - 1 < num_direct) { \
+               /* Small counter value, not NULL */ \
+                *my_fl = (ptr_t)my_entry + granules + 1; \
+                result = default_expr; \
+               goto out; \
+            } else { \
+               /* Large counter or NULL */ \
+                GC_generic_malloc_many(((granules) == 0? GC_GRANULE_BYTES : \
+                                         RAW_BYTES_FROM_INDEX(granules)), \
+                                      kind, my_fl); \
+               my_entry = *my_fl; \
+                if (my_entry == 0) { \
+                   result = GC_oom_fn(bytes); \
+                   goto out; \
+               } \
+           } \
+        } \
+        next = *(void **)(my_entry); \
+        result = (void *)my_entry; \
+        *my_fl = next; \
+       init; \
+        PREFETCH_FOR_WRITE(next); \
+        GC_ASSERT(GC_size(result) >= bytes + EXTRA_BYTES); \
+        GC_ASSERT((kind) == PTRFREE || ((GC_word *)result)[1] == 0); \
+      out: ; \
+   } \
+}
+
+# define GC_WORDS_TO_WHOLE_GRANULES(n) \
+       GC_WORDS_TO_GRANULES((n) + GC_GRANULE_WORDS - 1)
+
+/* Allocate n words (NOT BYTES).  X is made to point to the result.    */
+/* This should really only be used if GC_all_interior_pointers is      */
+/* not set, or DONT_ADD_BYTE_AT_END is set.  See above.                        */
+/* The semantics changed in version 7.0; we no longer lock, and                */
+/* the caller is responsible for supplying a cleared tiny_fl           */
+/* free list array.  For single-threaded applications, this may be     */
+/* a global array.                                                     */
+# define GC_MALLOC_WORDS(result,n,tiny_fl) \
+{      \
+    size_t grans = WORDS_TO_WHOLE_GRANULES(n); \
+    GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
+                        NORMAL, GC_malloc(grans*GRANULE_BYTES), \
+                        *(void **)result = 0); \
+}
+
+# define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
+{      \
+    size_t grans = WORDS_TO_WHOLE_GRANULES(n); \
+    GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
+                        PTRFREE, GC_malloc_atomic(grans*GRANULE_BYTES), \
+                        /* no initialization */); \
+}
+
+
+/* And once more for two word initialized objects: */
+# define GC_CONS(result, first, second, tiny_fl) \
+{      \
+    size_t grans = WORDS_TO_WHOLE_GRANULES(2); \
+    GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
+                        NORMAL, GC_malloc(grans*GRANULE_BYTES), \
+                        *(void **)result = (void *)(first)); \
+    ((void **)(result))[1] = (void *)(second); \
+}
diff --git a/src/mm/boehm-gc/include/gc_local_alloc.h b/src/mm/boehm-gc/include/gc_local_alloc.h
deleted file mode 100644 (file)
index 1874c7b..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* 
- * Copyright (c) 2000 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.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose,  provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-
-/*
- * Interface for thread local allocation.  Memory obtained
- * this way can be used by all threads, as though it were obtained
- * from an allocator like GC_malloc.  The difference is that GC_local_malloc
- * counts the number of allocations of a given size from the current thread,
- * and uses GC_malloc_many to perform the allocations once a threashold
- * is exceeded.  Thus far less synchronization may be needed.
- * Allocation of known large objects should not use this interface.
- * This interface is designed primarily for fast allocation of small
- * objects on multiprocessors, e.g. for a JVM running on an MP server.
- *
- * If this file is included with GC_GCJ_SUPPORT defined, GCJ-style
- * bitmap allocation primitives will also be included.
- *
- * If this file is included with GC_REDIRECT_TO_LOCAL defined, then
- * GC_MALLOC, GC_MALLOC_ATOMIC, and possibly GC_GCJ_MALLOC will
- * be redefined to use the thread local allocatoor.
- *
- * The interface is available only if the collector is built with
- * -DTHREAD_LOCAL_ALLOC, which is currently supported only on Linux.
- *
- * The debugging allocators use standard, not thread-local allocation.
- *
- * These routines normally require an explicit call to GC_init(), though
- * that may be done from a constructor function.
- */
-
-#ifndef GC_LOCAL_ALLOC_H
-#define GC_LOCAL_ALLOC_H
-
-#ifndef _GC_H
-#   include "gc.h"
-#endif
-
-#if defined(GC_GCJ_SUPPORT) && !defined(GC_GCJ_H)
-#   include "gc_gcj.h"
-#endif
-
-/* We assume ANSI C for this interface.        */
-
-GC_PTR GC_local_malloc(size_t bytes);
-
-GC_PTR GC_local_malloc_atomic(size_t bytes);
-
-#if defined(GC_GCJ_SUPPORT)
-  GC_PTR GC_local_gcj_malloc(size_t bytes,
-                            void * ptr_to_struct_containing_descr);
-#endif
-
-# ifdef GC_DEBUG
-    /* We don't really use local allocation in this case.      */
-#   define GC_LOCAL_MALLOC(s) GC_debug_malloc(s,GC_EXTRAS)
-#   define GC_LOCAL_MALLOC_ATOMIC(s) GC_debug_malloc_atomic(s,GC_EXTRAS)
-#   ifdef GC_GCJ_SUPPORT
-#      define GC_LOCAL_GCJ_MALLOC(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
-#   endif
-# else
-#   define GC_LOCAL_MALLOC(s) GC_local_malloc(s)
-#   define GC_LOCAL_MALLOC_ATOMIC(s) GC_local_malloc_atomic(s)
-#   ifdef GC_GCJ_SUPPORT
-#      define GC_LOCAL_GCJ_MALLOC(s,d) GC_local_gcj_malloc(s,d)
-#   endif
-# endif
-
-# ifdef GC_REDIRECT_TO_LOCAL
-#   undef GC_MALLOC
-#   define GC_MALLOC(s) GC_LOCAL_MALLOC(s)
-#   undef GC_MALLOC_ATOMIC
-#   define GC_MALLOC_ATOMIC(s) GC_LOCAL_MALLOC_ATOMIC(s)
-#   ifdef GC_GCJ_SUPPORT
-#      undef GC_GCJ_MALLOC
-#      define GC_GCJ_MALLOC(s,d) GC_LOCAL_GCJ_MALLOC(s,d)
-#   endif
-# endif
-
-#endif /* GC_LOCAL_ALLOC_H */
index 953bb74dc084c0e1870c05d203a5a3493ffebc73..8ee50b5d4deb8b36afc0ad6016be13fe33a013a3 100644 (file)
@@ -53,9 +53,9 @@
 /* case correctly somehow.                                             */
 # define GC_PROC_BYTES 100
 struct GC_ms_entry;
-typedef struct GC_ms_entry * (*GC_mark_proc) GC_PROTO((
+typedef struct GC_ms_entry * (*GC_mark_proc) (
                GC_word * addr, struct GC_ms_entry * mark_stack_ptr,
-               struct GC_ms_entry * mark_stack_limit, GC_word env));
+               struct GC_ms_entry * mark_stack_limit, GC_word env);
 
 # define GC_LOG_MAX_MARK_PROCS 6
 # define GC_MAX_MARK_PROCS (1 << GC_LOG_MAX_MARK_PROCS)
@@ -106,8 +106,8 @@ typedef struct GC_ms_entry * (*GC_mark_proc) GC_PROTO((
                        /* held.                                        */
 #define GC_INDIR_PER_OBJ_BIAS 0x10
                        
-extern GC_PTR GC_least_plausible_heap_addr;
-extern GC_PTR GC_greatest_plausible_heap_addr;
+extern void * GC_least_plausible_heap_addr;
+extern void * GC_greatest_plausible_heap_addr;
                        /* Bounds on the heap.  Guaranteed valid        */
                        /* Likely to include future heap expansion.     */
 
@@ -130,10 +130,10 @@ extern GC_PTR GC_greatest_plausible_heap_addr;
 /* which would tie the client code to a fixed collector version.)      */
 /* Note that mark procedures should explicitly call FIXUP_POINTER()    */
 /* if required.                                                                */
-struct GC_ms_entry *GC_mark_and_push
-               GC_PROTO((GC_PTR obj,
-                         struct GC_ms_entry * mark_stack_ptr,
-                         struct GC_ms_entry * mark_stack_limit, GC_PTR *src));
+struct GC_ms_entry *GC_mark_and_push(void * obj,
+                                    struct GC_ms_entry * mark_stack_ptr,
+                                    struct GC_ms_entry * mark_stack_limit,
+                                    void * *src);
 
 #define GC_MARK_AND_PUSH(obj, msp, lim, src) \
        (((GC_word)obj >= (GC_word)GC_least_plausible_heap_addr && \
@@ -146,29 +146,29 @@ extern size_t GC_debug_header_size;
        /* the GC_debug routines.                                       */
        /* Defined as a variable so that client mark procedures don't   */
        /* need to be recompiled for collector version changes.         */
-#define GC_USR_PTR_FROM_BASE(p) ((GC_PTR)((char *)(p) + GC_debug_header_size))
+#define GC_USR_PTR_FROM_BASE(p) ((void *)((char *)(p) + GC_debug_header_size))
 
 /* And some routines to support creation of new "kinds", e.g. with     */
 /* custom mark procedures, by language runtimes.                       */
 /* The _inner versions assume the caller holds the allocation lock.    */
 
 /* Return a new free list array.       */
-void ** GC_new_free_list GC_PROTO((void));
-void ** GC_new_free_list_inner GC_PROTO((void));
+void ** GC_new_free_list(void);
+void ** GC_new_free_list_inner(void);
 
 /* Return a new kind, as specified. */
-int GC_new_kind GC_PROTO((void **free_list, GC_word mark_descriptor_template,
-                         int add_size_to_descriptor, int clear_new_objects));
+unsigned GC_new_kind(void **free_list, GC_word mark_descriptor_template,
+               int add_size_to_descriptor, int clear_new_objects);
                /* The last two parameters must be zero or one. */
-int GC_new_kind_inner GC_PROTO((void **free_list,
-                               GC_word mark_descriptor_template,
-                               int add_size_to_descriptor,
-                               int clear_new_objects));
+unsigned GC_new_kind_inner(void **free_list,
+                     GC_word mark_descriptor_template,
+                     int add_size_to_descriptor,
+                     int clear_new_objects);
 
 /* Return a new mark procedure identifier, suitable for use as */
 /* the first argument in GC_MAKE_PROC.                         */
-int GC_new_proc GC_PROTO((GC_mark_proc));
-int GC_new_proc_inner GC_PROTO((GC_mark_proc));
+unsigned GC_new_proc(GC_mark_proc);
+unsigned GC_new_proc_inner(GC_mark_proc);
 
 /* Allocate an object of a given kind.  Note that in multithreaded     */
 /* contexts, this is usually unsafe for kinds that have the descriptor */
@@ -176,11 +176,9 @@ int GC_new_proc_inner GC_PROTO((GC_mark_proc));
 /* the descriptor is not correct.  Even in the single-threaded case,   */
 /* we need to be sure that cleared objects on a free list don't                */
 /* cause a GC crash if they are accidentally traced.                   */
-/* ptr_t */char * GC_generic_malloc GC_PROTO((GC_word lb, int k));
+void * GC_generic_malloc(size_t lb, int k);
 
-/* FIXME - Should return void *, but that requires other changes.      */
-
-typedef void (*GC_describe_type_fn) GC_PROTO((void *p, char *out_buf));
+typedef void (*GC_describe_type_fn) (void *p, char *out_buf);
                                /* A procedure which                    */
                                /* produces a human-readable            */
                                /* description of the "type" of object  */
@@ -194,7 +192,7 @@ typedef void (*GC_describe_type_fn) GC_PROTO((void *p, char *out_buf));
                                /* global free list.                    */
 #      define GC_TYPE_DESCR_LEN 40
 
-void GC_register_describe_type_fn GC_PROTO((int kind, GC_describe_type_fn knd));
+void GC_register_describe_type_fn(int kind, GC_describe_type_fn knd);
                                /* Register a describe_type function    */
                                /* to be used when printing objects     */
                                /* of a particular kind.                */
index 21e9c9fa605fc15e4f3c29ce7a21861c226aa7fd..b567f63e14f0efd1b6a140162df4e694369ce976 100644 (file)
@@ -5,47 +5,16 @@
 
 #define GC_PTHREAD_REDIRECTS_H
 
-#if defined(GC_SOLARIS_THREADS)
-/* We need to intercept calls to many of the threads primitives, so    */
-/* that we can locate thread stacks and stop the world.                        */
-/* Note also that the collector cannot see thread specific data.       */
-/* Thread specific data should generally consist of pointers to                */
-/* uncollectable objects (allocated with GC_malloc_uncollectable,      */
-/* not the system malloc), which are deallocated using the destructor  */
-/* facility in thr_keycreate.  Alternatively, keep a redundant pointer */
-/* to thread specific data on the thread stack.                                */
-# include <thread.h>
-  int GC_thr_create(void *stack_base, size_t stack_size,
-                    void *(*start_routine)(void *), void *arg, long flags,
-                    thread_t *new_thread);
-  int GC_thr_join(thread_t wait_for, thread_t *departed, void **status);
-  int GC_thr_suspend(thread_t target_thread);
-  int GC_thr_continue(thread_t target_thread);
-  void * GC_dlopen(const char *path, int mode);
-# define thr_create GC_thr_create
-# define thr_join GC_thr_join
-# define thr_suspend GC_thr_suspend
-# define thr_continue GC_thr_continue
-#endif /* GC_SOLARIS_THREADS */
+#if !defined(GC_USE_LD_WRAP) && defined(GC_PTHREADS)
+/* We need to intercept calls to many of the threads primitives, so     */
+/* that we can locate thread stacks and stop the world.                  */
+/* Note also that the collector cannot always see thread specific data.  */
+/* Thread specific data should generally consist of pointers to          */
+/* uncollectable objects (allocated with GC_malloc_uncollectable,        */
+/* not the system malloc), which are deallocated using the destructor    */
+/* facility in thr_keycreate.  Alternatively, keep a redundant pointer   */
+/* to thread specific data on the thread stack.                         */
 
-#if defined(GC_SOLARIS_PTHREADS)
-# include <pthread.h>
-# include <signal.h>
-  extern int GC_pthread_create(pthread_t *new_thread,
-                                const pthread_attr_t *attr,
-                                void * (*thread_execp)(void *), void *arg);
-  extern int GC_pthread_join(pthread_t wait_for, void **status);
-# define pthread_join GC_pthread_join
-# define pthread_create GC_pthread_create
-#endif
-
-#if defined(GC_SOLARIS_PTHREADS) || defined(GC_SOLARIS_THREADS)
-# define dlopen GC_dlopen
-#endif /* SOLARIS_THREADS || SOLARIS_PTHREADS */
-
-
-#if !defined(GC_USE_LD_WRAP) && defined(GC_PTHREADS) && !defined(GC_SOLARIS_PTHREADS)
-/* We treat these similarly. */
 # include <pthread.h>
 # include <signal.h>
 
diff --git a/src/mm/boehm-gc/include/gc_tiny_fl.h b/src/mm/boehm-gc/include/gc_tiny_fl.h
new file mode 100644 (file)
index 0000000..52b6864
--- /dev/null
@@ -0,0 +1,89 @@
+/* 
+ * Copyright (c) 1999-2005 Hewlett-Packard Development Company, L.P.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef GC_TINY_FL_H
+#define GC_TINY_FL_H
+/*
+ * Constants and data structures for "tiny" free lists.
+ * These are used for thread-local allocation or in-lined allocators.
+ * Each global free list also essentially starts with one of these.
+ * However, global free lists are known to the GC.  "Tiny" free lists
+ * are basically private to the client.  Their contents are viewed as
+ * "in use" and marked accordingly by the core of the GC.
+ * 
+ * Note that inlined code might know about the layout of these and the constants
+ * involved.  Thus any change here may invalidate clients, and such changes should
+ * be avoided.  Hence we keep this as simple as possible.
+ */
+
+/*
+ * We always set GRANULE_BYTES to twice the length of a pointer.
+ * This means that all allocation requests are rounded up to the next
+ * multiple of 16 on 64-bit architectures or 8 on 32-bit architectures.
+ * This appears to be a reasonable compromise between fragmentation overhead
+ * and space usage for mark bits (usually mark bytes).
+ * On many 64-bit architectures some memory references require 16-byte
+ * alignment, making this necessary anyway.
+ * For a few 32-bit architecture (e.g. x86), we may also need 16-byte alignment
+ * for certain memory references.  But currently that does not seem to be the
+ * default for all conventional malloc implementations, so we ignore that
+ * problem.
+ * It would always be safe, and often useful, to be able to allocate very
+ * small objects with smaller alignment.  But that would cost us mark bit
+ * space, so we no longer do so.
+ */
+#ifndef GC_GRANULE_BYTES
+  /* GC_GRANULE_BYTES should not be overridden in any instances of the GC */
+  /* library that may be shared between applications, since it affects   */
+  /* the binary interface to the library.                                */
+# if defined(__LP64__) || defined (_LP64) || defined(_WIN64) \
+       || defined(__s390x__) || defined(__x86_64__) \
+       || defined(__alpha__) || defined(__powerpc64__) \
+       || defined(__arch64__)
+#  define GC_GRANULE_BYTES 16
+#  define GC_GRANULE_WORDS 2
+# else
+#  define GC_GRANULE_BYTES 8
+#  define GC_GRANULE_WORDS 2
+# endif
+#endif /* !GC_GRANULE_BYTES */
+
+#if GC_GRANULE_WORDS == 2
+#  define GC_WORDS_TO_GRANULES(n) ((n)>>1)
+#else
+#  define GC_WORDS_TO_GRANULES(n) ((n)*sizeof(void *)/GRANULE_BYTES)
+#endif
+
+/* A "tiny" free list header contains TINY_FREELISTS pointers to       */
+/* singly linked lists of objects of different sizes, the ith one      */
+/* containing objects i granules in size.  Note that there is a list   */
+/* of size zero objects.                                               */
+#ifndef GC_TINY_FREELISTS
+# if GC_GRANULE_BYTES == 16
+#   define GC_TINY_FREELISTS 25
+# else
+#   define GC_TINY_FREELISTS 33        /* Up to and including 256 bytes */
+# endif
+#endif /* !GC_TINY_FREELISTS */
+
+/* The ith free list corresponds to size i*GRANULE_BYTES       */
+/* Internally to the collector, the index can be computed with */
+/* ROUNDED_UP_GRANULES.  Externally, we don't know whether     */
+/* DONT_ADD_BYTE_AT_END is set, but the client should know.    */
+
+/* Convert a free list index to the actual size of objects     */
+/* on that list, including extra space we added.  Not an       */
+/* inverse of the above.                                       */
+#define RAW_BYTES_FROM_INDEX(i) ((i) * GC_GRANULE_BYTES)
+
+#endif /* GC_TINY_FL_H */
index 905734b8da0f550c3833c8dd21f09b7c23828bb2..1086acdd12f9cd4442d714de4d9da7871fad3484 100644 (file)
@@ -47,7 +47,7 @@ typedef GC_word * GC_bitmap;
 
 typedef GC_word GC_descr;
 
-GC_API GC_descr GC_make_descriptor GC_PROTO((GC_bitmap bm, size_t len));
+GC_API GC_descr GC_make_descriptor(GC_bitmap bm, size_t len);
                /* Return a type descriptor for the object whose layout */
                /* is described by the argument.                        */
                /* The least significant bit of the first word is one   */
@@ -74,19 +74,17 @@ GC_API GC_descr GC_make_descriptor GC_PROTO((GC_bitmap bm, size_t len));
 /* ...                                                                 */
 /* T_descr = GC_make_descriptor(T_bitmap, GC_WORD_LEN(T));             */
 
-GC_API GC_PTR GC_malloc_explicitly_typed
-                       GC_PROTO((size_t size_in_bytes, GC_descr d));
+GC_API void * GC_malloc_explicitly_typed(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));
+GC_API void * GC_malloc_explicitly_typed_ignore_off_page
+                        (size_t size_in_bytes, GC_descr d);
                
-GC_API GC_PTR GC_calloc_explicitly_typed
-                       GC_PROTO((size_t nelements,
-                                 size_t element_size_in_bytes,
-                                 GC_descr d));
+GC_API void * GC_calloc_explicitly_typed(size_t nelements,
+                                        size_t element_size_in_bytes,
+                                        GC_descr d);
        /* Allocate an array of nelements elements, each of the */
        /* given size, and with the given descriptor.           */
        /* The elemnt size must be a multiple of the byte       */
diff --git a/src/mm/boehm-gc/include/include.am b/src/mm/boehm-gc/include/include.am
new file mode 100644 (file)
index 0000000..c0f2841
--- /dev/null
@@ -0,0 +1,54 @@
+# 
+# 
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+# 
+# Permission is hereby granted to use or copy this program
+# for any purpose,  provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+#
+# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
+# Modified by: Petter Urkedal <petter.urkedal@nordita.dk>
+
+## Process this file with automake to produce part of Makefile.in.
+
+# installed headers
+#
+dist_noinst_HEADERS += \
+       include/gc.h \
+       include/gc_typed.h \
+       include/gc_inline.h \
+       include/gc_mark.h \
+       include/gc_cpp.h \
+       include/weakpointer.h \
+       include/new_gc_alloc.h \
+       include/gc_allocator.h \
+       include/gc_backptr.h \
+       include/gc_gcj.h \
+       include/leak_detector.h \
+       include/gc_amiga_redirects.h \
+       include/gc_pthread_redirects.h \
+       include/gc_config_macros.h \
+       include/gc_tiny_fl.h
+
+# headers which are not installed
+#
+dist_noinst_HEADERS += \
+       include/private/gc_hdrs.h \
+       include/private/gc_priv.h \
+       include/private/gcconfig.h \
+       include/private/gc_pmark.h \
+       include/private/gc_locks.h \
+       include/private/dbg_mlc.h \
+       include/private/specific.h \
+       include/private/cord_pos.h \
+       include/private/pthread_support.h \
+       include/private/pthread_stop_world.h \
+       include/private/darwin_semaphore.h \
+       include/private/darwin_stop_world.h \
+       include/private/thread_local_alloc.h \
+       include/cord.h \
+       include/ec.h \
+       include/javaxfc.h 
index 7546638c981a5060523cd6bafc5a52cc956aaf96..b4906af548ba0c00044be20dc9bd796b97a35dd8 100644 (file)
@@ -67,7 +67,7 @@
 /* A hack to deal with gcc 3.1.  If you are using gcc3.1 and later,    */
 /* you should probably really use gc_allocator.h instead.              */
 #if defined (__GNUC__) && \
-    (__GNUC > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
+    (__GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
 # define simple_alloc __simple_alloc
 #endif
 
@@ -88,10 +88,11 @@ extern "C" {
     extern void ** const GC_uobjfreelist_ptr;
     extern void ** const GC_auobjfreelist_ptr;
 
-    extern void GC_incr_words_allocd(size_t words);
-    extern void GC_incr_mem_freed(size_t words);
+    extern void GC_incr_bytes_allocd(size_t bytes);
+    extern void GC_incr_mem_freed(size_t words); /* FIXME: use bytes */
 
     extern char * GC_generic_malloc_words_small(size_t word, int kind);
+               /* FIXME: Doesn't exist anymore.        */
 }
 
 // Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
@@ -130,51 +131,50 @@ public:
   // File local count of allocated words.  Occasionally this is
   // added into the global count.  A separate count is necessary since the
   // real one must be updated with a procedure call.
-  static size_t GC_words_recently_allocd;
+  static size_t GC_bytes_recently_allocd;
 
   // Same for uncollectable mmory.  Not yet reflected in either
-  // GC_words_recently_allocd or GC_non_gc_bytes.
-  static size_t GC_uncollectable_words_recently_allocd;
+  // GC_bytes_recently_allocd or GC_non_gc_bytes.
+  static size_t GC_uncollectable_bytes_recently_allocd;
 
   // Similar counter for explicitly deallocated memory.
-  static size_t GC_mem_recently_freed;
+  static size_t GC_bytes_recently_freed;
 
   // Again for uncollectable memory.
-  static size_t GC_uncollectable_mem_recently_freed;
+  static size_t GC_uncollectable_bytes_recently_freed;
 
   static void * GC_out_of_line_malloc(size_t nwords, int kind);
 };
 
 template <int dummy>
-size_t GC_aux_template<dummy>::GC_words_recently_allocd = 0;
+size_t GC_aux_template<dummy>::GC_bytes_recently_allocd = 0;
 
 template <int dummy>
-size_t GC_aux_template<dummy>::GC_uncollectable_words_recently_allocd = 0;
+size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_allocd = 0;
 
 template <int dummy>
-size_t GC_aux_template<dummy>::GC_mem_recently_freed = 0;
+size_t GC_aux_template<dummy>::GC_bytes_recently_freed = 0;
 
 template <int dummy>
-size_t GC_aux_template<dummy>::GC_uncollectable_mem_recently_freed = 0;
+size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_freed = 0;
 
 template <int dummy>
 void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
 {
-    GC_words_recently_allocd += GC_uncollectable_words_recently_allocd;
+    GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd;
     GC_non_gc_bytes +=
-                GC_bytes_per_word * GC_uncollectable_words_recently_allocd;
-    GC_uncollectable_words_recently_allocd = 0;
+                GC_uncollectable_bytes_recently_allocd;
+    GC_uncollectable_bytes_recently_allocd = 0;
 
-    GC_mem_recently_freed += GC_uncollectable_mem_recently_freed;
-    GC_non_gc_bytes -= 
-                GC_bytes_per_word * GC_uncollectable_mem_recently_freed;
-    GC_uncollectable_mem_recently_freed = 0;
+    GC_bytes_recently_freed += GC_uncollectable_bytes_recently_freed;
+    GC_non_gc_bytes -= GC_uncollectable_bytes_recently_freed;
+    GC_uncollectable_bytes_recently_freed = 0;
 
-    GC_incr_words_allocd(GC_words_recently_allocd);
-    GC_words_recently_allocd = 0;
+    GC_incr_bytes_allocd(GC_bytes_recently_allocd);
+    GC_bytes_recently_allocd = 0;
 
-    GC_incr_mem_freed(GC_mem_recently_freed);
-    GC_mem_recently_freed = 0;
+    GC_incr_mem_freed(GC_bytes_per_word(GC_bytes_recently_freed));
+    GC_bytes_recently_freed = 0;
 
     return GC_generic_malloc_words_small(nwords, kind);
 }
@@ -200,7 +200,7 @@ class single_client_gc_alloc_template {
                return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
            }
            *flh = GC_obj_link(op);
-           GC_aux::GC_words_recently_allocd += nwords;
+           GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
            return op;
         }
        static void * ptr_free_allocate(size_t n)
@@ -215,7 +215,7 @@ class single_client_gc_alloc_template {
                return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
            }
            *flh = GC_obj_link(op);
-           GC_aux::GC_words_recently_allocd += nwords;
+           GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
            return op;
         }
        static void deallocate(void *p, size_t n)
@@ -231,7 +231,7 @@ class single_client_gc_alloc_template {
                memset(reinterpret_cast<char *>(p) + GC_bytes_per_word, 0,
                       GC_bytes_per_word * (nwords - 1));
                *flh = p;
-               GC_aux::GC_mem_recently_freed += nwords;
+               GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
            }
        }
        static void ptr_free_deallocate(void *p, size_t n)
@@ -245,7 +245,7 @@ class single_client_gc_alloc_template {
                flh = GC_aobjfreelist_ptr + nwords;
                GC_obj_link(p) = *flh;
                *flh = p;
-               GC_aux::GC_mem_recently_freed += nwords;
+               GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
            }
        }
 };
@@ -268,7 +268,8 @@ class single_client_traceable_alloc_template {
                return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
            }
            *flh = GC_obj_link(op);
-           GC_aux::GC_uncollectable_words_recently_allocd += nwords;
+           GC_aux::GC_uncollectable_bytes_recently_allocd +=
+                                       nwords * GC_bytes_per_word;
            return op;
         }
        static void * ptr_free_allocate(size_t n)
@@ -283,7 +284,8 @@ class single_client_traceable_alloc_template {
                return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
            }
            *flh = GC_obj_link(op);
-           GC_aux::GC_uncollectable_words_recently_allocd += nwords;
+           GC_aux::GC_uncollectable_bytes_recently_allocd +=
+                                       nwords * GC_bytes_per_word;
            return op;
         }
        static void deallocate(void *p, size_t n)
@@ -297,7 +299,8 @@ class single_client_traceable_alloc_template {
                flh = GC_uobjfreelist_ptr + nwords;
                GC_obj_link(p) = *flh;
                *flh = p;
-               GC_aux::GC_uncollectable_mem_recently_freed += nwords;
+               GC_aux::GC_uncollectable_bytes_recently_freed +=
+                               nwords * GC_bytes_per_word;
            }
        }
        static void ptr_free_deallocate(void *p, size_t n)
@@ -311,7 +314,8 @@ class single_client_traceable_alloc_template {
                flh = GC_auobjfreelist_ptr + nwords;
                GC_obj_link(p) = *flh;
                *flh = p;
-               GC_aux::GC_uncollectable_mem_recently_freed += nwords;
+               GC_aux::GC_uncollectable_bytes_recently_freed +=
+                               nwords * GC_bytes_per_word;
            }
        }
 };
index e0a994de5e2a64c1d095cc7e2c3b4d1a2fea9b34..fcd027c4fed97473ea99e7f0bffa15cb60d1c772 100644 (file)
@@ -38,7 +38,7 @@
   /* get them anyway.                                                  */
     typedef GC_word GC_hidden_pointer;
 #   define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
-#   define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p)))
+#   define REVEAL_POINTER(p) ((void *)(HIDE_POINTER(p)))
 #endif /* HIDE_POINTER */
 
 # define START_FLAG ((word)0xfedcedcb)
@@ -95,12 +95,12 @@ typedef struct {
 #      ifdef MAKE_BACK_GRAPH
          GC_hidden_pointer oh_bg_ptr;
 #      endif
-#      if defined(ALIGN_DOUBLE) && \
-           (defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH))
+#      if defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH)
+         /* Keep double-pointer-sized alignment.       */
          word oh_dummy;
 #      endif
 #   endif
-    GC_CONST char * oh_string; /* object descriptor string     */
+    const char * oh_string;    /* object descriptor string     */
     word oh_int;               /* object descriptor integers   */
 #   ifdef NEED_CALLINFO
       struct callinfo oh_ci[NFRAMES];
@@ -132,17 +132,20 @@ typedef struct {
 /* lock.                                                       */
 /* PRINT_CALL_CHAIN prints the call chain stored in an object  */
 /* to stderr.  It requires that we do not hold the lock.       */
-#ifdef SAVE_CALL_CHAIN
+#if defined(SAVE_CALL_CHAIN)
+    struct callinfo;
+    void GC_save_callers(struct callinfo info[NFRAMES]);
+    void GC_print_callers(struct callinfo info[NFRAMES]);
 #   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
+#elif defined(GC_ADD_CALLER)
+    struct callinfo;
+    void GC_print_callers(struct callinfo info[NFRAMES]);
 #   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
+#else
 #   define ADD_CALL_CHAIN(base, ra)
 #   define PRINT_CALL_CHAIN(base)
-# endif
 #endif
 
 # ifdef GC_ADD_CALLER
index 70dfefe8fa7dc2725d2b14a409abe2fd7447a507..559556ca78a226409b1d7c8c1c1c1596569b27fa 100644 (file)
@@ -28,7 +28,7 @@ typedef struct hblkhdr hdr;
  * This defines HDR, GET_HDR, and SET_HDR, the main macros used to
  * retrieve and set object headers.
  *
- * Since 5.0 alpha 5, we can also take advantage of a header lookup
+ * We take advantage of a header lookup
  * cache.  This is a locally declared direct mapped cache, used inside
  * the marker.  The HC_GET_HDR macro uses and maintains this
  * cache.  Assuming we get reasonable hit rates, this shaves a few
@@ -60,22 +60,6 @@ typedef struct hblkhdr hdr;
 
 /* #define COUNT_HDR_CACHE_HITS  */
 
-extern hdr * GC_invalid_header; /* header for an imaginary block       */
-                               /* containing no objects.               */
-
-
-/* Check whether p and corresponding hhdr point to long or invalid     */
-/* object.  If so, advance hhdr        to                                      */
-/* beginning of        block, or set hhdr to GC_invalid_header.                */
-#define ADVANCE(p, hhdr, source) \
-           { \
-             hdr * new_hdr = GC_invalid_header; \
-              p = GC_find_start(p, hhdr, &new_hdr); \
-             hhdr = new_hdr; \
-           }
-
-#ifdef USE_HDR_CACHE
-
 # ifdef COUNT_HDR_CACHE_HITS
     extern word GC_hdr_cache_hits;
     extern word GC_hdr_cache_misses;
@@ -96,7 +80,7 @@ extern hdr * GC_invalid_header; /* header for an imaginary block      */
 # define DECLARE_HDR_CACHE \
        hdr_cache_entry hdr_cache[HDR_CACHE_SIZE]
 
-# define INIT_HDR_CACHE BZERO(hdr_cache, sizeof(hdr_cache));
+# define INIT_HDR_CACHE BZERO(hdr_cache, sizeof(hdr_cache))
 
 # define HCE(h) hdr_cache + (((word)(h) >> LOG_HBLKSIZE) & (HDR_CACHE_SIZE-1))
 
@@ -105,44 +89,33 @@ extern hdr * GC_invalid_header; /* header for an imaginary block   */
 
 # define HCE_HDR(h) ((hce) -> hce_hdr)
 
+#ifdef PRINT_BLACK_LIST
+  hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce, ptr_t source);
+# define HEADER_CACHE_MISS(p, hce, source) \
+         GC_header_cache_miss(p, hce, source)
+#else
+  hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce);
+# define HEADER_CACHE_MISS(p, hce, source) GC_header_cache_miss(p, hce)
+#endif
 
-/* Analogous to GET_HDR, except that in the case of large objects, it  */
-/* Returns the header for the object beginning, and updates p.         */
-/* Returns GC_invalid_header instead of 0.  All of this saves a branch */
-/* in the fast path.                                                   */
-# define HC_GET_HDR(p, hhdr, source) \
+/* Set hhdr to the header for p.  Analogous to GET_HDR below,          */
+/* except that in the case of large objects, it                                */
+/* gets the header for the object beginning, if GC_all_interior_ptrs   */
+/* is set.                                                             */
+/* Returns zero if p points to somewhere other than the first page     */
+/* of an object, and it is not a valid pointer to the object.          */
+# define HC_GET_HDR(p, hhdr, source, exit_label) \
        { \
          hdr_cache_entry * hce = HCE(p); \
-         if (HCE_VALID_FOR(hce, p)) { \
+         if (EXPECT(HCE_VALID_FOR(hce, p), 1)) { \
            HC_HIT(); \
            hhdr = hce -> hce_hdr; \
          } else { \
-           HC_MISS(); \
-           GET_HDR(p, hhdr); \
-            if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \
-             ADVANCE(p, hhdr, source); \
-           } else { \
-             hce -> block_addr = (word)(p) >> LOG_HBLKSIZE; \
-             hce -> hce_hdr = hhdr; \
-           } \
+           hhdr = HEADER_CACHE_MISS(p, hce, source); \
+           if (0 == hhdr) goto exit_label; \
          } \
        }
 
-#else /* !USE_HDR_CACHE */
-
-# define DECLARE_HDR_CACHE
-
-# define INIT_HDR_CACHE
-
-# define HC_GET_HDR(p, hhdr, source) \
-       { \
-         GET_HDR(p, hhdr); \
-          if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \
-           ADVANCE(p, hhdr, source); \
-         } \
-       }
-#endif
-
 typedef struct bi {
     hdr * index[BOTTOM_SZ];
        /*
@@ -225,9 +198,9 @@ typedef struct bi {
                            
 /* Is the result a forwarding address to someplace closer to the       */
 /* beginning of the block or NIL?                                      */
-# define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((unsigned long) (hhdr) <= MAX_JUMP)
+# define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((size_t) (hhdr) <= MAX_JUMP)
 
 /* Get an HBLKSIZE aligned address closer to the beginning of the block */
 /* h.  Assumes hhdr == HDR(h) and IS_FORWARDING_ADDR(hhdr).            */
-# define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (unsigned long)(hhdr))
+# define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (size_t)(hhdr))
 # endif /*  GC_HEADERS_H */
index aba1b46b6910ece97cb2d13d93b2af932e970c79..d7c83b07b9129ea6ab604a456df04a83479a867c 100644 (file)
 /*
  * Mutual exclusion between allocator/collector routines.
  * Needed if there is more than one allocator thread.
- * FASTLOCK() is assumed to try to acquire the lock in a cheap and
- * dirty way that is acceptable for a few instructions, e.g. by
- * inhibiting preemption.  This is assumed to have succeeded only
- * if a subsequent call to FASTLOCK_SUCCEEDED() returns TRUE.
- * FASTUNLOCK() is called whether or not FASTLOCK_SUCCEEDED().
- * If signals cannot be tolerated with the FASTLOCK held, then
- * FASTLOCK should disable signals.  The code executed under
- * FASTLOCK is otherwise immune to interruption, provided it is
- * not restarted.
- * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK
- * and/or DISABLE_SIGNALS and ENABLE_SIGNALS and/or FASTLOCK.
- * (There is currently no equivalent for FASTLOCK.)
+ * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK.
  *
- * In the PARALLEL_MARK case, we also need to define a number of
- * other inline finctions here:
- *   GC_bool GC_compare_and_exchange( volatile GC_word *addr,
- *                                   GC_word old, GC_word new )
- *   GC_word GC_atomic_add( volatile GC_word *addr, GC_word how_much )
- *   void GC_memory_barrier( )
- *   
+ * Note that I_HOLD_LOCK and I_DONT_HOLD_LOCK are used only positively
+ * in assertions, and may return TRUE in the "dont know" case.
  */  
 # ifdef THREADS
-   void GC_noop1 GC_PROTO((word));
-#  ifdef PCR_OBSOLETE  /* Faster, but broken with multiple lwp's       */
-#    include  "th/PCR_Th.h"
-#    include  "th/PCR_ThCrSec.h"
-     extern struct PCR_Th_MLRep GC_allocate_ml;
-#    define DCL_LOCK_STATE  PCR_sigset_t GC_old_sig_mask
-#    define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) 
-#    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
-#    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
-#    define FASTLOCK() PCR_ThCrSec_EnterSys()
-     /* Here we cheat (a lot): */
-#        define FASTLOCK_SUCCEEDED() (*(int *)(&GC_allocate_ml) == 0)
-               /* TRUE if nobody currently holds the lock */
-#    define FASTUNLOCK() PCR_ThCrSec_ExitSys()
-#  endif
+#  include <atomic_ops.h>
+
+   void GC_noop1(word);
 #  ifdef PCR
 #    include <base/PCR_Base.h>
 #    include <th/PCR_Th.h>
         PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
 #    define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
 #    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
-#    define FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml))
-#    define FASTLOCK_SUCCEEDED() (GC_fastLockRes == PCR_ERes_okay)
-#    define FASTUNLOCK()  {\
-        if( FASTLOCK_SUCCEEDED() ) PCR_Th_ML_Release(&GC_allocate_ml); }
 #  endif
-#  ifdef SRC_M3
-     extern GC_word RT0u__inCritical;
-#    define LOCK() RT0u__inCritical++
-#    define UNLOCK() RT0u__inCritical--
-#  endif
-#  ifdef GC_SOLARIS_THREADS
-#    include <thread.h>
-#    include <signal.h>
-     extern mutex_t GC_allocate_ml;
-#    define LOCK() mutex_lock(&GC_allocate_ml);
-#    define UNLOCK() mutex_unlock(&GC_allocate_ml);
-#  endif
-
-/* Try to define GC_TEST_AND_SET and a matching GC_CLEAR for spin lock */
-/* acquisition and release.  We need this for correct operation of the */
-/* incremental GC.                                                     */
-#  ifdef __GNUC__
-#    if defined(I386)
-       inline static int GC_test_and_set(volatile unsigned int *addr) {
-         int oldval;
-         /* Note: the "xchg" instruction does not need a "lock" prefix */
-         __asm__ __volatile__("xchgl %0, %1"
-               : "=r"(oldval), "=m"(*(addr))
-               : "0"(1), "m"(*(addr)) : "memory");
-         return oldval;
-       }
-#      define GC_TEST_AND_SET_DEFINED
-#    endif
-#    if defined(IA64)
-#      if defined(__INTEL_COMPILER)
-#        include <ia64intrin.h>
-#      endif
-       inline static int GC_test_and_set(volatile unsigned int *addr) {
-         long oldval, n = 1;
-#      ifndef __INTEL_COMPILER
-         __asm__ __volatile__("xchg4 %0=%1,%2"
-               : "=r"(oldval), "=m"(*addr)
-               : "r"(n), "1"(*addr) : "memory");
-#      else
-         oldval = _InterlockedExchange(addr, n);
-#      endif
-         return oldval;
-       }
-#      define GC_TEST_AND_SET_DEFINED
-       /* Should this handle post-increment addressing?? */
-       inline static void GC_clear(volatile unsigned int *addr) {
-#      ifndef __INTEL_COMPILER
-        __asm__ __volatile__("st4.rel %0=r0" : "=m" (*addr) : : "memory");
-#      else
-         /* there is no st4 but I can use xchg I hope */
-        _InterlockedExchange(addr, 0);
-#      endif
-       }
-#      define GC_CLEAR_DEFINED
-#    endif
-#    ifdef SPARC
-       inline static int GC_test_and_set(volatile unsigned int *addr) {
-        int oldval;
-
-        __asm__ __volatile__("ldstub %1,%0"
-        : "=r"(oldval), "=m"(*addr)
-        : "m"(*addr) : "memory");
-        return oldval;
-       }
-#      define GC_TEST_AND_SET_DEFINED
-#    endif
-/* tbfg */
-#if 0          
-#    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) : "memory");
-          return oldval;
-       }
-#      define GC_TEST_AND_SET_DEFINED
-#    endif
-#endif
-#    if defined(POWERPC)
-        inline static int GC_test_and_set(volatile unsigned int *addr) {
-          int oldval;
-          int temp = 1; /* locked value */
-
-          __asm__ __volatile__(
-               "1:\tlwarx %0,0,%3\n"   /* load and reserve               */
-               "\tcmpwi %0, 0\n"       /* if load is                     */
-               "\tbne 2f\n"            /*   non-zero, return already set */
-               "\tstwcx. %2,0,%1\n"    /* else store conditional         */
-               "\tbne- 1b\n"           /* retry if lost reservation      */
-               "\tsync\n"              /* import barrier                 */
-               "2:\t\n"                /* oldval is zero if we set       */
-              : "=&r"(oldval), "=p"(addr)
-              : "r"(temp), "1"(addr)
-              : "cr0","memory");
-          return oldval;
-        }
-#     define GC_TEST_AND_SET_DEFINED
-      inline static void GC_clear(volatile unsigned int *addr) {
-       __asm__ __volatile__("lwsync" : : : "memory");
-        *(addr) = 0;
-      }
-#     define GC_CLEAR_DEFINED
-#    endif
-#    if defined(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"
-#      ifdef __ELF__
-                             "       beq %0,3f\n"
-#      else
-                             "       beq %0,1b\n"
-#      endif
-                             "       mb\n"
-                             "2:\n"
-#      ifdef __ELF__
-                             ".section .text2,\"ax\"\n"
-                             "3:     br 1b\n"
-                             ".previous"
-#      endif
-                             :"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
-                             :"Ir" (1), "m" (*addr)
-                            :"memory");
-
-          return oldvalue;
-        }
-#       define GC_TEST_AND_SET_DEFINED
-        inline static void GC_clear(volatile unsigned int *addr) {
-          __asm__ __volatile__("mb" : : : "memory");
-          *(addr) = 0;
-        }
-#       define GC_CLEAR_DEFINED
-#    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.                */
-         /* The first operand is the result, the second the value      */
-         /* to be stored.  Both registers must be different from addr. */
-         /* Make the address operand an early clobber output so it     */
-         /* doesn't overlap with the other operands.  The early clobber*/
-         /* on oldval is neccessary to prevent the compiler allocating */
-         /* them to the same register if they are both unused.         */
-          __asm__ __volatile__("swp %0, %2, [%3]"
-                             : "=&r"(oldval), "=&r"(addr)
-                             : "r"(1), "1"(addr)
-                             : "memory");
-          return oldval;
-        }
-#       define GC_TEST_AND_SET_DEFINED
-#    endif /* ARM32 */
-#    ifdef CRIS
-        inline static int GC_test_and_set(volatile unsigned int *addr) {
-         /* Ripped from linuxthreads/sysdeps/cris/pt-machine.h.        */
-         /* Included with Hans-Peter Nilsson's permission.             */
-         register unsigned long int ret;
-
-         /* Note the use of a dummy output of *addr to expose the write.
-          * The memory barrier is to stop *other* writes being moved past
-          * this code.
-          */
-           __asm__ __volatile__("clearf\n"
-                                "0:\n\t"
-                                "movu.b [%2],%0\n\t"
-                                "ax\n\t"
-                                "move.b %3,[%2]\n\t"
-                                "bwf 0b\n\t"
-                                "clearf"
-                                : "=&r" (ret), "=m" (*addr)
-                                : "r" (addr), "r" ((int) 1), "m" (*addr)
-                                : "memory");
-           return ret;
-        }
-#       define GC_TEST_AND_SET_DEFINED
-#    endif /* CRIS */
-#    ifdef S390
-       inline static int GC_test_and_set(volatile unsigned int *addr) {
-         int ret;
-         __asm__ __volatile__ (
-          "     l     %0,0(%2)\n"
-          "0:   cs    %0,%1,0(%2)\n"
-          "     jl    0b"
-          : "=&d" (ret)
-          : "d" (1), "a" (addr)
-          : "cc", "memory");
-         return ret;
-       }
-#    endif
-#  endif /* __GNUC__ */
-#  if (defined(ALPHA) && !defined(__GNUC__))
-#    ifndef OSF1
-       --> We currently assume that if gcc is not used, we are
-       --> running under Tru64.
-#    endif
-#    include <machine/builtins.h>
-#    include <c_asm.h>
-#    define GC_test_and_set(addr) __ATOMIC_EXCH_LONG(addr, 1)
-#    define GC_TEST_AND_SET_DEFINED
-#    define GC_clear(addr) { asm("mb"); *(volatile unsigned *)addr = 0; }
-#    define GC_CLEAR_DEFINED
-#  endif
-#  if defined(MSWIN32)
-#    define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
-#    define GC_TEST_AND_SET_DEFINED
-#  endif
-#  ifdef MIPS
-#    ifdef LINUX
-#      include <sys/tas.h>
-#      define GC_test_and_set(addr) _test_and_set((int *) addr,1)
-#      define GC_TEST_AND_SET_DEFINED
-#    elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
-       || !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
-#       ifdef __GNUC__
-#          define GC_test_and_set(addr) _test_and_set((void *)addr,1)
-#       else
-#          define GC_test_and_set(addr) test_and_set((void *)addr,1)
-#       endif
-#    else
-#       include <sgidefs.h>
-#       include <mutex.h>
-#       define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
-#       define GC_clear(addr) __lock_release(addr);
-#       define GC_CLEAR_DEFINED
-#    endif
-#    define GC_TEST_AND_SET_DEFINED
-#  endif /* MIPS */
-#  if defined(_AIX)
-#    include <sys/atomic_op.h>
-#    if (defined(_POWER) || defined(_POWERPC)) 
-#      if defined(__GNUC__)  
-         inline static void GC_memsync() {
-           __asm__ __volatile__ ("sync" : : : "memory");
-         }
-#      else
-#        ifndef inline
-#          define inline __inline
-#        endif
-#        pragma mc_func GC_memsync { \
-           "7c0004ac" /* sync (same opcode used for dcs)*/ \
-         }
-#      endif
-#    else 
-#    error dont know how to memsync
-#    endif
-     inline static int GC_test_and_set(volatile unsigned int * addr) {
-          int oldvalue = 0;
-          if (compare_and_swap((void *)addr, &oldvalue, 1)) {
-            GC_memsync();
-            return 0;
-          } else return 1;
-     }
-#    define GC_TEST_AND_SET_DEFINED
-     inline static void GC_clear(volatile unsigned int *addr) {
-          GC_memsync();
-          *(addr) = 0;
-     }
-#    define GC_CLEAR_DEFINED
-
-#  endif
-#  if 0 /* defined(HP_PA) */
-     /* The official recommendation seems to be to not use ldcw from   */
-     /* user mode.  Since multithreaded incremental collection doesn't */
-     /* work anyway on HP_PA, this shouldn't be a major loss.          */
-
-     /* "set" means 0 and "clear" means 1 here.                */
-#    define GC_test_and_set(addr) !GC_test_and_clear(addr);
-#    define GC_TEST_AND_SET_DEFINED
-#    define GC_clear(addr) GC_noop1((word)(addr)); *(volatile unsigned int *)addr = 1;
-       /* The above needs a memory barrier! */
-#    define GC_CLEAR_DEFINED
+#  if !defined(AO_HAVE_test_and_set_acquire) && defined(GC_PTHREADS)
+#    define USE_PTHREAD_LOCKS
 #  endif
-#  if defined(GC_TEST_AND_SET_DEFINED) && !defined(GC_CLEAR_DEFINED)
-#    ifdef __GNUC__
-       inline static void GC_clear(volatile unsigned int *addr) {
-         /* Try to discourage gcc from moving anything past this. */
-         __asm__ __volatile__(" " : : : "memory");
-         *(addr) = 0;
-       }
-#    else
-           /* The function call in the following should prevent the    */
-           /* compiler from moving assignments to below the UNLOCK.    */
-#      define GC_clear(addr) GC_noop1((word)(addr)); \
-                            *((volatile unsigned int *)(addr)) = 0;
-#    endif
-#    define GC_CLEAR_DEFINED
-#  endif /* !GC_CLEAR_DEFINED */
 
-#  if !defined(GC_TEST_AND_SET_DEFINED)
+#  if defined(GC_WIN32_THREADS) && defined(GC_PTHREADS)
 #    define USE_PTHREAD_LOCKS
 #  endif
 
-#  if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
-      && !defined(GC_WIN32_THREADS)
-#    define NO_THREAD (pthread_t)(-1)
+#  if defined(GC_WIN32_THREADS) && !defined(USE_PTHREAD_LOCKS)
+#    include <windows.h>
+#    define NO_THREAD (DWORD)(-1)
+     extern DWORD GC_lock_holder;
+     GC_API CRITICAL_SECTION GC_allocate_ml;
+#    ifdef GC_ASSERTIONS
+#        define UNCOND_LOCK() \
+               { EnterCriticalSection(&GC_allocate_ml); \
+                 SET_LOCK_HOLDER(); }
+#        define UNCOND_UNLOCK() \
+               { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
+                 LeaveCriticalSection(&GC_allocate_ml); }
+#    else
+#      define UNCOND_LOCK() EnterCriticalSection(&GC_allocate_ml);
+#      define UNCOND_UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
+#    endif /* !GC_ASSERTIONS */
+#    define SET_LOCK_HOLDER() GC_lock_holder = GetCurrentThreadId()
+#    define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
+#    define I_HOLD_LOCK() (!GC_need_to_lock \
+                          || GC_lock_holder == GetCurrentThreadId())
+#    define I_DONT_HOLD_LOCK() (!GC_need_to_lock \
+                          || GC_lock_holder != GetCurrentThreadId())
+#  elif defined(GC_PTHREADS)
 #    include <pthread.h>
-#    if defined(PARALLEL_MARK) 
-      /* We need compare-and-swap to update mark bits, where it's      */
-      /* performance critical.  If USE_MARK_BYTES is defined, it is    */
-      /* no longer needed for this purpose.  However we use it in      */
-      /* either case to implement atomic fetch-and-add, though that's  */
-      /* less performance critical, and could perhaps be done with     */
-      /* a lock.                                                       */
-#     if defined(GENERIC_COMPARE_AND_SWAP)
-       /* Probably not useful, except for debugging.   */
-       /* We do use GENERIC_COMPARE_AND_SWAP on PA_RISC, but we        */
-       /* minimize its use.                                            */
-       extern pthread_mutex_t GC_compare_and_swap_lock;
-
-       /* Note that if GC_word updates are not atomic, a concurrent    */
-       /* reader should acquire GC_compare_and_swap_lock.  On          */
-       /* currently supported platforms, such updates are atomic.      */
-       extern GC_bool GC_compare_and_exchange(volatile GC_word *addr,
-                                              GC_word old, GC_word new_val);
-#     endif /* GENERIC_COMPARE_AND_SWAP */
-#     if defined(I386)
-#      if !defined(GENERIC_COMPARE_AND_SWAP)
-         /* Returns TRUE if the comparison succeeded. */
-         inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
-                                                      GC_word old,
-                                                      GC_word new_val) 
-         {
-          char result;
-          __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
-               : "+m"(*(addr)), "=r"(result)
-               : "r" (new_val), "a"(old) : "memory");
-          return (GC_bool) result;
-         }
-#      endif /* !GENERIC_COMPARE_AND_SWAP */
-       inline static void GC_memory_barrier()
-       {
-        /* We believe the processor ensures at least processor */
-        /* consistent ordering.  Thus a compiler barrier       */
-        /* should suffice.                                     */
-         __asm__ __volatile__("" : : : "memory");
-       }
-#     endif /* I386 */
-
-#     if defined(POWERPC)
-#      if !defined(GENERIC_COMPARE_AND_SWAP)
-#       if CPP_WORDSZ == 64
-        /* Returns TRUE if the comparison succeeded. */
-        inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
-            GC_word old, GC_word new_val) 
-        {
-            unsigned long result, dummy;
-            __asm__ __volatile__(
-                "1:\tldarx %0,0,%5\n"
-                  "\tcmpd %0,%4\n"
-                  "\tbne  2f\n"
-                  "\tstdcx. %3,0,%2\n"
-                  "\tbne- 1b\n"
-                  "\tsync\n"
-                  "\tli %1, 1\n"
-                  "\tb 3f\n"
-                "2:\tli %1, 0\n"
-                "3:\t\n"
-                :  "=&r" (dummy), "=r" (result), "=p" (addr)
-                :  "r" (new_val), "r" (old), "2"(addr)
-                : "cr0","memory");
-            return (GC_bool) result;
-        }
-#       else
-        /* Returns TRUE if the comparison succeeded. */
-        inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
-            GC_word old, GC_word new_val) 
-        {
-            int result, dummy;
-            __asm__ __volatile__(
-                "1:\tlwarx %0,0,%5\n"
-                  "\tcmpw %0,%4\n"
-                  "\tbne  2f\n"
-                  "\tstwcx. %3,0,%2\n"
-                  "\tbne- 1b\n"
-                  "\tsync\n"
-                  "\tli %1, 1\n"
-                  "\tb 3f\n"
-                "2:\tli %1, 0\n"
-                "3:\t\n"
-                :  "=&r" (dummy), "=r" (result), "=p" (addr)
-                :  "r" (new_val), "r" (old), "2"(addr)
-                : "cr0","memory");
-            return (GC_bool) result;
-        }
-#       endif
-#      endif /* !GENERIC_COMPARE_AND_SWAP */
-        inline static void GC_memory_barrier()
-        {
-            __asm__ __volatile__("sync" : : : "memory");
-        }
-#     endif /* POWERPC */
-
-#     if defined(IA64)
-#      if !defined(GENERIC_COMPARE_AND_SWAP)
-         inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
-                                                      GC_word old, GC_word new_val) 
-        {
-         unsigned long oldval;
-#        if CPP_WORDSZ == 32
-            __asm__ __volatile__(
-                 "addp4 %0=0,%1\n"
-                 "mov ar.ccv=%3 ;; cmpxchg4.rel %0=[%0],%2,ar.ccv"
-                 : "=&r"(oldval)
-                 : "r"(addr), "r"(new_val), "r"(old) : "memory");
-#        else
-           __asm__ __volatile__(
-                 "mov ar.ccv=%3 ;; cmpxchg8.rel %0=[%1],%2,ar.ccv"
-                 : "=r"(oldval)
-                 : "r"(addr), "r"(new_val), "r"(old) : "memory");
-#        endif
-         return (oldval == old);
-         }
-#      endif /* !GENERIC_COMPARE_AND_SWAP */
-#      if 0
-       /* Shouldn't be needed; we use volatile stores instead. */
-        inline static void GC_memory_barrier()
-        {
-          __asm__ __volatile__("mf" : : : "memory");
-        }
-#      endif /* 0 */
-#     endif /* IA64 */
-#     if defined(ALPHA)
-#      if !defined(GENERIC_COMPARE_AND_SWAP)
-#        if defined(__GNUC__)
-           inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
-                                                        GC_word old, GC_word new_val) 
-          {
-            unsigned long was_equal;
-             unsigned long temp;
-
-             __asm__ __volatile__(
-                             "1:     ldq_l %0,%1\n"
-                             "       cmpeq %0,%4,%2\n"
-                            "       mov %3,%0\n"
-                             "       beq %2,2f\n"
-                             "       stq_c %0,%1\n"
-                             "       beq %0,1b\n"
-                             "2:\n"
-                             "       mb\n"
-                             :"=&r" (temp), "=m" (*addr), "=&r" (was_equal)
-                             : "r" (new_val), "Ir" (old)
-                            :"memory");
-             return was_equal;
-           }
-#        else /* !__GNUC__ */
-           inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
-                                                        GC_word old, GC_word new_val) 
-         {
-           return __CMP_STORE_QUAD(addr, old, new_val, addr);
-          }
-#        endif /* !__GNUC__ */
-#      endif /* !GENERIC_COMPARE_AND_SWAP */
-#      ifdef __GNUC__
-         inline static void GC_memory_barrier()
-         {
-           __asm__ __volatile__("mb" : : : "memory");
-         }
+     
+     /* Posix allows pthread_t to be a struct, though it rarely is.    */
+     /* Unfortunately, we need to use a pthread_t to index a data      */
+     /* structure.  It also helps if comparisons don't involve a       */
+     /* function call.  Hence we introduce platform-dependent macros   */
+     /* to compare pthread_t ids and to map them to integers.          */
+     /* the mapping to integers does not need to result in different   */
+     /* integers for each thread, though that should be true as much   */
+     /* as possible.                                                   */
+     /* Refine to exclude platforms on which pthread_t is struct */
+#    if !defined(GC_WIN32_PTHREADS)
+#      define NUMERIC_THREAD_ID(id) ((unsigned long)(id))
+#      define THREAD_EQUAL(id1, id2) ((id1) == (id2))
+#      define NUMERIC_THREAD_ID_UNIQUE
+#    else
+#      if defined(GC_WIN32_PTHREADS)
+#       define NUMERIC_THREAD_ID(id) ((unsigned long)(id.p))
+        /* Using documented internal details of win32_pthread library. */
+        /* Faster than pthread_equal(). Should not change with         */
+        /* future versions of win32_pthread library.                   */
+#       define THREAD_EQUAL(id1, id2) ((id1.p == id2.p) && (id1.x == id2.x))
+#        undef NUMERIC_THREAD_ID_UNIQUE
 #      else
-#       define GC_memory_barrier() asm("mb")
-#      endif /* !__GNUC__ */
-#     endif /* ALPHA */
-#     if defined(S390)
-#      if !defined(GENERIC_COMPARE_AND_SWAP)
-         inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
-                                         GC_word old, GC_word new_val)
-         {
-           int retval;
-           __asm__ __volatile__ (
-#            ifndef __s390x__
-               "     cs  %1,%2,0(%3)\n"
-#            else
-               "     csg %1,%2,0(%3)\n"
-#            endif
-             "     ipm %0\n"
-             "     srl %0,28\n"
-             : "=&d" (retval), "+d" (old)
-             : "d" (new_val), "a" (addr)
-             : "cc", "memory");
-           return retval == 0;
-         }
+        /* Generic definitions that always work, but will result in    */
+        /* poor performance and weak assertion checking.               */
+#       define NUMERIC_THREAD_ID(id) 1l
+#       define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2)
+#        undef NUMERIC_THREAD_ID_UNIQUE
 #      endif
-#     endif
-#     if !defined(GENERIC_COMPARE_AND_SWAP)
-        /* Returns the original value of *addr.        */
-        inline static GC_word GC_atomic_add(volatile GC_word *addr,
-                                           GC_word how_much)
-        {
-         GC_word old;
-         do {
-           old = *addr;
-         } while (!GC_compare_and_exchange(addr, old, old+how_much));
-          return old;
-        }
-#     else /* GENERIC_COMPARE_AND_SWAP */
-       /* So long as a GC_word can be atomically updated, it should    */
-       /* be OK to read *addr without a lock.                          */
-       extern GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much);
-#     endif /* GENERIC_COMPARE_AND_SWAP */
-
-#    endif /* PARALLEL_MARK */
+#    endif
+#    define NO_THREAD (-1l)
+               /* != NUMERIC_THREAD_ID(pthread_self()) for any thread */
 
 #    if !defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_LOCKS)
       /* In the THREAD_LOCAL_ALLOC case, the allocation lock tends to  */
       /* and sleeping for fixed periods are likely to result in        */
       /* significant wasted time.  We thus rely mostly on queued locks. */
 #     define USE_SPIN_LOCK
-      extern volatile unsigned int GC_allocate_lock;
+      extern volatile AO_TS_t GC_allocate_lock;
       extern void GC_lock(void);
        /* Allocation lock holder.  Only set if acquired by client through */
        /* GC_call_with_alloc_lock.                                        */
 #     ifdef GC_ASSERTIONS
-#        define LOCK() \
-               { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); \
+#        define UNCOND_LOCK() \
+               { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
+                       GC_lock(); \
                  SET_LOCK_HOLDER(); }
-#        define UNLOCK() \
+#        define UNCOND_UNLOCK() \
                { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
-                 GC_clear(&GC_allocate_lock); }
+                 AO_CLEAR(&GC_allocate_lock); }
 #     else
-#        define LOCK() \
-               { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
-#        define UNLOCK() \
-               GC_clear(&GC_allocate_lock)
+#        define UNCOND_LOCK() \
+               { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
+                       GC_lock(); }
+#        define UNCOND_UNLOCK() \
+               AO_CLEAR(&GC_allocate_lock)
 #     endif /* !GC_ASSERTIONS */
-#     if 0
-       /* Another alternative for OSF1 might be:               */
-#       include <sys/mman.h>
-        extern msemaphore GC_allocate_semaphore;
-#       define LOCK() { if (msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) \
-                           != 0) GC_lock(); else GC_allocate_lock = 1; }
-        /* The following is INCORRECT, since the memory model is too weak. */
-       /* Is this true?  Presumably msem_unlock has the right semantics?  */
-       /*              - HB                                               */
-#       define UNLOCK() { GC_allocate_lock = 0; \
-                          msem_unlock(&GC_allocate_semaphore, 0); }
-#     endif /* 0 */
 #    else /* THREAD_LOCAL_ALLOC  || USE_PTHREAD_LOCKS */
 #      ifndef USE_PTHREAD_LOCKS
 #        define USE_PTHREAD_LOCKS
 #      endif
-#    endif /* THREAD_LOCAL_ALLOC */
-#   ifdef USE_PTHREAD_LOCKS
+#    endif /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCK */
+#    ifdef USE_PTHREAD_LOCKS
 #      include <pthread.h>
        extern pthread_mutex_t GC_allocate_ml;
 #      ifdef GC_ASSERTIONS
-#        define LOCK() \
+#        define UNCOND_LOCK() \
                { GC_lock(); \
                  SET_LOCK_HOLDER(); }
-#        define UNLOCK() \
+#        define UNCOND_UNLOCK() \
                { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
                  pthread_mutex_unlock(&GC_allocate_ml); }
 #      else /* !GC_ASSERTIONS */
 #        if defined(NO_PTHREAD_TRYLOCK)
-#          define LOCK() GC_lock();
+#          define UNCOND_LOCK() GC_lock();
 #        else /* !defined(NO_PTHREAD_TRYLOCK) */
-#        define LOCK() \
+#        define UNCOND_LOCK() \
           { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
 #        endif
-#        define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
+#        define UNCOND_UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
 #      endif /* !GC_ASSERTIONS */
-#   endif /* USE_PTHREAD_LOCKS */
-#   define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
-#   define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
-#   define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
-    extern VOLATILE GC_bool GC_collecting;
-#   define ENTER_GC() GC_collecting = 1;
-#   define EXIT_GC() GC_collecting = 0;
-    extern void GC_lock(void);
-    extern pthread_t GC_lock_holder;
-#   ifdef GC_ASSERTIONS
-      extern pthread_t GC_mark_lock_holder;
-#   endif
-#  endif /* GC_PTHREADS with linux_threads.c implementation */
-#  if defined(GC_WIN32_THREADS)
-#    if defined(GC_PTHREADS)
-#      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 /* USE_PTHREAD_LOCKS */
+#    define SET_LOCK_HOLDER() \
+               GC_lock_holder = NUMERIC_THREAD_ID(pthread_self())
+#    define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
+#    define I_HOLD_LOCK() \
+               (!GC_need_to_lock || \
+                GC_lock_holder == NUMERIC_THREAD_ID(pthread_self()))
+#    ifndef NUMERIC_THREAD_ID_UNIQUE
+#      define I_DONT_HOLD_LOCK() 1  /* Conservatively say yes */
 #    else
-#      include <windows.h>
-       GC_API CRITICAL_SECTION GC_allocate_ml;
-#      define LOCK() EnterCriticalSection(&GC_allocate_ml);
-#      define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
+#      define I_DONT_HOLD_LOCK() \
+               (!GC_need_to_lock \
+                || GC_lock_holder != NUMERIC_THREAD_ID(pthread_self()))
 #    endif
-#  endif
-#  ifndef SET_LOCK_HOLDER
-#      define SET_LOCK_HOLDER()
-#      define UNSET_LOCK_HOLDER()
-#      define I_HOLD_LOCK() FALSE
-               /* Used on platforms were locks can be reacquired,      */
-               /* so it doesn't matter if we lie.                      */
-#  endif
+     extern volatile GC_bool GC_collecting;
+#    define ENTER_GC() GC_collecting = 1;
+#    define EXIT_GC() GC_collecting = 0;
+     extern void GC_lock(void);
+     extern unsigned long GC_lock_holder;
+#    ifdef GC_ASSERTIONS
+      extern unsigned long GC_mark_lock_holder;
+#    endif
+#  endif /* GC_PTHREADS with linux_threads.c implementation */
+
+
 # else /* !THREADS */
-#    define LOCK()
-#    define UNLOCK()
-# endif /* !THREADS */
-# ifndef SET_LOCK_HOLDER
+#   define LOCK()
+#   define UNLOCK()
 #   define SET_LOCK_HOLDER()
 #   define UNSET_LOCK_HOLDER()
-#   define I_HOLD_LOCK() FALSE
-               /* Used on platforms were locks can be reacquired,      */
-               /* so it doesn't matter if we lie.                      */
-# endif
+#   define I_HOLD_LOCK() TRUE
+#   define I_DONT_HOLD_LOCK() TRUE
+                       /* Used only in positive assertions or to test whether  */
+                       /* we still need to acaquire the lock.  TRUE works in   */
+                       /* either case.                                         */
+# endif /* !THREADS */
+
+#if defined(UNCOND_LOCK) && !defined(LOCK) 
+     GC_API GC_bool GC_need_to_lock;
+               /* At least two thread running; need to lock.   */
+#    define LOCK() if (GC_need_to_lock) { UNCOND_LOCK(); }
+#    define UNLOCK() if (GC_need_to_lock) { UNCOND_UNLOCK(); }
+#endif
+
 # ifndef ENTER_GC
 #   define ENTER_GC()
 #   define EXIT_GC()
 # ifndef DCL_LOCK_STATE
 #   define DCL_LOCK_STATE
 # endif
-# ifndef FASTLOCK
-#   define FASTLOCK() LOCK()
-#   define FASTLOCK_SUCCEEDED() TRUE
-#   define FASTUNLOCK() UNLOCK()
-# endif
 
 #endif /* GC_LOCKS_H */
index 714fc428ee8aa32d160df816297dd67cb88922ff..36083970acdcba98cd3a03d2943d8bd68085f4ce 100644 (file)
@@ -54,24 +54,24 @@ extern mark_proc GC_mark_procs[MAX_MARK_PROCS];
        (((word)1 << (WORDSZ - GC_DS_TAG_BITS - GC_LOG_MAX_MARK_PROCS)) - 1)
 
 
-extern word GC_n_mark_procs;
+extern unsigned GC_n_mark_procs;
 
 /* Number of mark stack entries to discard on overflow.        */
 #define GC_MARK_STACK_DISCARDS (INITIAL_MARK_STACK_SIZE/8)
 
 typedef struct GC_ms_entry {
-    GC_word * mse_start;   /* First word of object */
+    ptr_t mse_start;   /* First word of object */
     GC_word mse_descr; /* Descriptor; low order two bits are tags,     */
                        /* identifying the upper 30 bits as one of the  */
                        /* following:                                   */
 } mse;
 
-extern word GC_mark_stack_size;
+extern size_t GC_mark_stack_size;
 
 extern mse * GC_mark_stack_limit;
 
 #ifdef PARALLEL_MARK
-  extern mse * VOLATILE GC_mark_stack_top;
+  extern mse * volatile GC_mark_stack_top;
 #else
   extern mse * GC_mark_stack_top;
 #endif
@@ -117,11 +117,6 @@ extern mse * GC_mark_stack;
                                        /* once it returns to 0, it     */
                                        /* stays zero for the cycle.    */
     /* GC_mark_stack_top is also protected by mark lock.       */
-    extern mse * VOLATILE GC_first_nonempty;
-                                       /* Lowest entry on mark stack   */
-                                       /* that may be nonempty.        */
-                                       /* Updated only by initiating   */
-                                       /* thread.                      */
     /*
      * GC_notify_all_marker() is used when GC_help_wanted is first set,
      * when the last helper becomes inactive,
@@ -134,21 +129,9 @@ extern mse * GC_mark_stack;
 
 /* Return a pointer to within 1st page of object.      */
 /* Set *new_hdr_p to corr. hdr.                                */
-#ifdef __STDC__
-  ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
-#else
-  ptr_t GC_find_start();
-#endif
-
-mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp));
+ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
 
-# ifdef GATHERSTATS
-#   define ADD_TO_ATOMIC(sz) GC_atomic_in_use += (sz)
-#   define ADD_TO_COMPOSITE(sz) GC_composite_in_use += (sz)
-# else
-#   define ADD_TO_ATOMIC(sz)
-#   define ADD_TO_COMPOSITE(sz)
-# endif
+mse * GC_signal_mark_stack_overflow(mse *msp);
 
 /* Push the object obj with corresponding heap block header hhdr onto  */
 /* the mark stack.                                                     */
@@ -156,10 +139,7 @@ mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp));
 { \
     register word _descr = (hhdr) -> hb_descr; \
         \
-    if (_descr == 0) { \
-       ADD_TO_ATOMIC((hhdr) -> hb_sz); \
-    } else { \
-        ADD_TO_COMPOSITE((hhdr) -> hb_sz); \
+    if (_descr != 0) { \
         mark_stack_top++; \
         if (mark_stack_top >= mark_stack_limit) { \
           mark_stack_top = GC_signal_mark_stack_overflow(mark_stack_top); \
@@ -177,95 +157,212 @@ mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp));
                       source, exit_label) \
 { \
     hdr * my_hhdr; \
-    ptr_t my_current = current; \
- \
-    GET_HDR(my_current, my_hhdr); \
-    if (IS_FORWARDING_ADDR_OR_NIL(my_hhdr)) { \
-        hdr * new_hdr = GC_invalid_header; \
-         my_current = GC_find_start(my_current, my_hhdr, &new_hdr); \
-         my_hhdr = new_hdr; \
-    } \
-    PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \
-                 source, exit_label, my_hhdr); \
-exit_label: ; \
-}
-
-/* As above, but use header cache for header lookup.   */
-# define HC_PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, \
-                      source, exit_label) \
-{ \
-    hdr * my_hhdr; \
-    ptr_t my_current = current; \
  \
-    HC_GET_HDR(my_current, my_hhdr, source); \
-    PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \
-                 source, exit_label, my_hhdr); \
+    HC_GET_HDR(current, my_hhdr, source, exit_label); \
+    PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
+                 source, exit_label, my_hhdr, TRUE);   \
 exit_label: ; \
 }
 
 /* Set mark bit, exit if it was already set.   */
 
-# ifdef USE_MARK_BYTES
-    /* Unlike the mark bit case, there is a race here, and we may set  */
-    /* the bit twice in the concurrent case.  This can result in the   */
-    /* object being pushed twice.  But that's only a performance issue.        */
-#   define SET_MARK_BIT_EXIT_IF_SET(hhdr,displ,exit_label) \
+# ifdef USE_MARK_BITS
+#   ifdef PARALLEL_MARK
+      /* The following may fail to exit even if the bit was already set.    */
+      /* For our uses, that's benign:                                       */
+#     define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
+        { \
+          if (!(*(addr) & (mask))) { \
+            AO_or((AO_t *)(addr), (mask); \
+          } else { \
+            goto label; \
+          } \
+        }
+#   else
+#     define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
+        { \
+           word old = *(addr); \
+           word my_bits = (bits); \
+           if (old & my_bits) goto exit_label; \
+           *(addr) = (old | my_bits); \
+         }
+#   endif /* !PARALLEL_MARK */
+#   define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
     { \
-        register VOLATILE char * mark_byte_addr = \
-                               hhdr -> hb_marks + ((displ) >> 1); \
-        register char mark_byte = *mark_byte_addr; \
+        word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(bit_no); \
+      \
+        OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(bit_no), \
+                            exit_label); \
+    }
+# endif
+
+
+#ifdef USE_MARK_BYTES
+# if defined(I386) && defined(__GNUC__)
+#  define LONG_MULT(hprod, lprod, x, y) { \
+       asm("mull %2" : "=a"(lprod), "=d"(hprod) : "g"(y), "0"(x)); \
+   }
+# else /* No in-line X86 assembly code */
+#  define LONG_MULT(hprod, lprod, x, y) { \
+       unsigned long long prod = (unsigned long long)x \
+                                 * (unsigned long long)y; \
+       hprod = prod >> 32;  \
+       lprod = (unsigned32)prod;  \
+   }
+# endif
+
+  /* There is a race here, and we may set                              */
+  /* the bit twice in the concurrent case.  This can result in the     */
+  /* object being pushed twice.  But that's only a performance issue.  */
+# define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
+    { \
+        char * mark_byte_addr = (char *)hhdr -> hb_marks + (bit_no); \
+        char mark_byte = *mark_byte_addr; \
           \
        if (mark_byte) goto exit_label; \
        *mark_byte_addr = 1;  \
     } 
-# else
-#   define SET_MARK_BIT_EXIT_IF_SET(hhdr,displ,exit_label) \
-    { \
-        register word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(displ); \
-          \
-        OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(displ), \
-                           exit_label); \
-    } 
-# endif /* USE_MARK_BYTES */
+#endif /* USE_MARK_BYTES */
 
+#ifdef PARALLEL_MARK
+# define INCR_MARKS(hhdr) \
+       AO_store(&(hhdr -> hb_n_marks), AO_load(&(hhdr -> hb_n_marks))+1);
+#else
+# define INCR_MARKS(hhdr) ++(hhdr -> hb_n_marks)
+#endif
+
+#ifdef ENABLE_TRACE
+# define TRACE(source, cmd) \
+       if (GC_trace_addr != 0 && (ptr_t)(source) == GC_trace_addr) cmd
+# define TRACE_TARGET(target, cmd) \
+       if (GC_trace_addr != 0 && (target) == *(ptr_t *)GC_trace_addr) cmd
+#else
+# define TRACE(source, cmd)
+# define TRACE_TARGET(source, cmd)
+#endif
 /* If the mark bit corresponding to current is not set, set it, and    */
-/* push the contents of the object on the mark stack.  For a small     */
-/* object we assume that current is the (possibly interior) pointer    */
-/* to the object.  For large objects we assume that current points     */
-/* to somewhere inside the first page of the object.  If               */
-/* GC_all_interior_pointers is set, it may have been previously        */
-/* adjusted to make that true.                                         */
+/* push the contents of the object on the mark stack.  Current points  */
+/* to the bginning of the object.  We rely on the fact that the        */
+/* preceding header calculation will succeed for a pointer past the    */
+/* forst page of an object, only if it is in fact a valid pointer      */
+/* to the object.  Thus we can omit the otherwise necessary tests      */
+/* here.  Note in particular tha the "displ" value is the displacement */
+/* from the beggining of the heap block, which may itself be in the    */
+/* interior of a large object.                                         */
+#ifdef MARK_BIT_PER_GRANULE
 # define PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
-                          source, exit_label, hhdr) \
+                          source, exit_label, hhdr, do_offset_check) \
 { \
-    int displ;  /* Displacement in block; first bytes, then words */ \
-    int map_entry; \
-    \
-    displ = HBLKDISPL(current); \
-    map_entry = MAP_ENTRY((hhdr -> hb_map), displ); \
-    displ = BYTES_TO_WORDS(displ); \
-    if (map_entry > CPP_MAX_OFFSET) { \
-       if (map_entry == OFFSET_TOO_BIG) { \
-         map_entry = displ % (hhdr -> hb_sz); \
-         displ -= map_entry; \
-         if (displ + (hhdr -> hb_sz) > BYTES_TO_WORDS(HBLKSIZE) \
-             && displ != 0) { \
-           GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); \
+    size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
+    /* displ is always within range.  If current doesn't point to      */ \
+    /* first block, then we are in the all_interior_pointers case, and */ \
+    /* it is safe to use any displacement value.                       */ \
+    size_t gran_displ = BYTES_TO_GRANULES(displ); \
+    size_t gran_offset = hhdr -> hb_map[gran_displ];   \
+    size_t byte_offset = displ & (GRANULE_BYTES - 1); \
+    ptr_t base = current;  \
+    /* The following always fails for large block references. */ \
+    if (EXPECT((gran_offset | byte_offset) != 0, FALSE))  { \
+       if (hhdr -> hb_large_block) { \
+         /* gran_offset is bogus.      */ \
+         size_t obj_displ; \
+         base = (ptr_t)(hhdr -> hb_block); \
+         obj_displ = (ptr_t)(current) - base;  \
+         if (obj_displ != displ) { \
+           GC_ASSERT(obj_displ < hhdr -> hb_sz); \
+           /* Must be in all_interior_pointer case, not first block */ \
+           /* already did validity check on cache miss.             */ \
+           ; \
+         } else { \
+           if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
+             GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
+             goto exit_label; \
+           } \
+         } \
+         gran_displ = 0; \
+         GC_ASSERT(hhdr -> hb_sz > HBLKSIZE || \
+                   hhdr -> hb_block == HBLKPTR(current)); \
+         GC_ASSERT((ptr_t)(hhdr -> hb_block) <= (ptr_t) current); \
+       } else { \
+         size_t obj_displ = GRANULES_TO_BYTES(gran_offset) \
+                            + byte_offset; \
+         if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
+           GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
            goto exit_label; \
          } \
+         gran_displ -= gran_offset; \
+         base -= obj_displ; \
+       } \
+    } \
+    GC_ASSERT(hhdr == GC_find_header(base)); \
+    GC_ASSERT(gran_displ % BYTES_TO_GRANULES(hhdr -> hb_sz) == 0); \
+    TRACE(source, GC_log_printf("GC:%d: passed validity tests\n",GC_gc_no)); \
+    SET_MARK_BIT_EXIT_IF_SET(hhdr, gran_displ, exit_label); \
+    TRACE(source, GC_log_printf("GC:%d: previously unmarked\n",GC_gc_no)); \
+    TRACE_TARGET(base, \
+       GC_log_printf("GC:%d: marking %p from %p instead\n", GC_gc_no, \
+                     base, source)); \
+    INCR_MARKS(hhdr); \
+    GC_STORE_BACK_PTR((ptr_t)source, base); \
+    PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
+}
+#endif /* MARK_BIT_PER_GRANULE */
+
+#ifdef MARK_BIT_PER_OBJ
+# define PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
+                          source, exit_label, hhdr, do_offset_check) \
+{ \
+    size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
+    unsigned32 low_prod, high_prod, offset_fraction; \
+    unsigned32 inv_sz = hhdr -> hb_inv_sz; \
+    ptr_t base = current;  \
+    LONG_MULT(high_prod, low_prod, displ, inv_sz); \
+    /* product is > and within sz_in_bytes of displ * sz_in_bytes * 2**32 */ \
+    if (EXPECT(low_prod >> 16 != 0, FALSE))  { \
+           FIXME: fails if offset is a multiple of HBLKSIZE which becomes 0 \
+       if (inv_sz == LARGE_INV_SZ) { \
+         size_t obj_displ; \
+         base = (ptr_t)(hhdr -> hb_block); \
+         obj_displ = (ptr_t)(current) - base;  \
+         if (obj_displ != displ) { \
+           GC_ASSERT(obj_displ < hhdr -> hb_sz); \
+           /* Must be in all_interior_pointer case, not first block */ \
+           /* already did validity check on cache miss.             */ \
+           ; \
+         } else { \
+           if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
+             GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
+             goto exit_label; \
+           } \
+         } \
+         GC_ASSERT(hhdr -> hb_sz > HBLKSIZE || \
+                   hhdr -> hb_block == HBLKPTR(current)); \
+         GC_ASSERT((ptr_t)(hhdr -> hb_block) < (ptr_t) current); \
        } else { \
-          GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); goto exit_label; \
+         /* Accurate enough if HBLKSIZE <= 2**15.      */ \
+         GC_ASSERT(HBLKSIZE <= (1 << 15)); \
+         size_t obj_displ = (((low_prod >> 16) + 1) * (hhdr -> hb_sz)) >> 16; \
+         if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
+           GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
+           goto exit_label; \
+         } \
+         base -= obj_displ; \
        } \
-    } else { \
-        displ -= map_entry; \
     } \
-    GC_ASSERT(displ >= 0 && displ < MARK_BITS_PER_HBLK); \
-    SET_MARK_BIT_EXIT_IF_SET(hhdr, displ, exit_label); \
-    GC_STORE_BACK_PTR((ptr_t)source, (ptr_t)HBLKPTR(current) \
-                                     + WORDS_TO_BYTES(displ)); \
-    PUSH_OBJ(((word *)(HBLKPTR(current)) + displ), hhdr, \
-            mark_stack_top, mark_stack_limit) \
+    /* May get here for pointer to start of block not at       */ \
+    /* beginning of object.  If so, it's valid, and we're fine. */ \
+    GC_ASSERT(high_prod >= 0 && high_prod <= HBLK_OBJS(hhdr -> hb_sz)); \
+    TRACE(source, GC_log_printf("GC:%d: passed validity tests\n",GC_gc_no)); \
+    SET_MARK_BIT_EXIT_IF_SET(hhdr, high_prod, exit_label); \
+    TRACE(source, GC_log_printf("GC:%d: previously unmarked\n",GC_gc_no)); \
+    TRACE_TARGET(base, \
+       GC_log_printf("GC:%d: marking %p from %p instead\n", GC_gc_no, \
+                     base, source)); \
+    INCR_MARKS(hhdr); \
+    GC_STORE_BACK_PTR((ptr_t)source, base); \
+    PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
 }
+#endif /* MARK_BIT_PER_OBJ */
 
 #if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
 #   define PUSH_ONE_CHECKED_STACK(p, source) \
@@ -286,13 +383,13 @@ exit_label: ; \
 # if NEED_FIXUP_POINTER
     /* Try both the raw version and the fixed up one.  */
 #   define GC_PUSH_ONE_STACK(p, source) \
-      if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr    \
-        && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) {      \
+      if ((p) >= (ptr_t)GC_least_plausible_heap_addr   \
+        && (p) < (ptr_t)GC_greatest_plausible_heap_addr) {     \
         PUSH_ONE_CHECKED_STACK(p, source);     \
       } \
       FIXUP_POINTER(p); \
-      if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr    \
-        && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) {      \
+      if ((p) >= (ptr_t)GC_least_plausible_heap_addr   \
+        && (p) < (ptr_t)GC_greatest_plausible_heap_addr) {     \
         PUSH_ONE_CHECKED_STACK(p, source);     \
       }
 # else /* !NEED_FIXUP_POINTER */
@@ -306,22 +403,22 @@ exit_label: ; \
 
 /*
  * As above, but interior pointer recognition as for
- * normal for heap pointers.
+ * normal heap pointers.
  */
 # define GC_PUSH_ONE_HEAP(p,source) \
     FIXUP_POINTER(p); \
-    if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr      \
-        && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) {      \
+    if ((p) >= (ptr_t)GC_least_plausible_heap_addr     \
+        && (p) < (ptr_t)GC_greatest_plausible_heap_addr) {     \
            GC_mark_stack_top = GC_mark_and_push( \
-                           (GC_PTR)(p), GC_mark_stack_top, \
-                           GC_mark_stack_limit, (GC_PTR *)(source)); \
+                           (void *)(p), GC_mark_stack_top, \
+                           GC_mark_stack_limit, (void * *)(source)); \
     }
 
 /* Mark starting at mark stack entry top (incl.) down to       */
 /* mark stack entry bottom (incl.).  Stop after performing     */
 /* about one page worth of work.  Return the new mark stack    */
 /* top entry.                                                  */
-mse * GC_mark_from GC_PROTO((mse * top, mse * bottom, mse *limit));
+mse * GC_mark_from(mse * top, mse * bottom, mse *limit);
 
 #define MARK_FROM_MARK_STACK() \
        GC_mark_stack_top = GC_mark_from(GC_mark_stack_top, \
@@ -331,7 +428,11 @@ mse * GC_mark_from GC_PROTO((mse * top, mse * bottom, mse *limit));
 /*
  * Mark from one finalizable object using the specified
  * mark proc. May not mark the object pointed to by 
- * real_ptr. That is the job of the caller, if appropriate
+ * real_ptr. That is the job of the caller, if appropriate.
+ * Note that this is called with the mutator running, but
+ * with us holding the allocation lock.  This is safe only if the
+ * mutator needs tha allocation lock to reveal hidden pointers.
+ * FIXME: Why do we need the GC_mark_state test below?
  */
 # define GC_MARK_FO(real_ptr, mark_proc) \
 { \
index 2abd27dd7054268d9b5a61adc6bf944fbb3bae9c..ec93ffea9c979ce1d104be22bf9e60d38e401b7f 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
- * Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
  *
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 # ifndef GC_PRIVATE_H
 # define GC_PRIVATE_H
 
-#if defined(mips) && defined(SYSTYPE_BSD) && defined(sony_news)
-    /* sony RISC NEWS, NEWSOS 4 */
-#   define BSD_TIME
-/*    typedef long ptrdiff_t;   -- necessary on some really old systems        */
-#endif
-
-#if defined(mips) && defined(SYSTYPE_BSD43)
-    /* MIPS RISCOS 4 */
-#   define BSD_TIME
-#endif
+# include <stdlib.h>
+# if !(defined( sony_news ) )
+#   include <stddef.h>
+# endif
 
 #ifdef DGUX
 #   include <sys/types.h>
 #   include <sys/resource.h>
 #endif /* BSD_TIME */
 
-# ifndef _GC_H
+#ifdef PARALLEL_MARK
+#   define AO_REQUIRE_CAS
+#endif
+
+#ifndef _GC_H
 #   include "../gc.h"
-# endif
+#endif
+
+#ifndef GC_TINY_FL_H
+#   include "../gc_tiny_fl.h"
+#endif
 
-# ifndef GC_MARK_H
+#ifndef GC_MARK_H
 #   include "../gc_mark.h"
-# endif
+#endif
 
 typedef GC_word word;
 typedef GC_signed_word signed_word;
+typedef unsigned int unsigned32;
 
 typedef int GC_bool;
 # define TRUE 1
 # define FALSE 0
 
 typedef char * ptr_t;  /* A generic pointer to which we can add        */
-                       /* byte displacements.                          */
-                       /* Preferably identical to caddr_t, if it       */
-                       /* exists.                                      */
-                       
+                       /* byte displacements and which can be used     */
+                       /* for address comparisons.                     */
+
 # ifndef GCCONFIG_H
 #   include "gcconfig.h"
 # endif
@@ -70,24 +72,13 @@ typedef char * ptr_t;       /* A generic pointer to which we can add        */
 #   include "gc_hdrs.h"
 # endif
 
-#if defined(__STDC__)
-#   include <stdlib.h>
-#   if !(defined( sony_news ) )
-#       include <stddef.h>
-#   endif
-#   define VOLATILE volatile
-#else
-#   ifdef MSWIN32
-#      include <stdlib.h>
-#   endif
-#   define VOLATILE
-#endif
-
-#if 0 /* defined(__GNUC__) doesn't work yet */
+#if __GNUC__ >= 3
 # define EXPECT(expr, outcome) __builtin_expect(expr,outcome)
   /* Equivalent to (expr), but predict that usually (expr)==outcome. */
+# define INLINE inline
 #else
 # define EXPECT(expr, outcome) (expr)
+# define INLINE
 #endif /* __GNUC__ */
 
 # ifndef GC_LOCKS_H
@@ -97,13 +88,13 @@ typedef char * ptr_t;       /* A generic pointer to which we can add        */
 # ifdef STACK_GROWS_DOWN
 #   define COOLER_THAN >
 #   define HOTTER_THAN <
-#   define MAKE_COOLER(x,y) if ((word)(x)+(y) > (word)(x)) {(x) += (y);} \
-                           else {(x) = (word)ONES;}
+#   define MAKE_COOLER(x,y) if ((x)+(y) > (x)) {(x) += (y);} \
+                           else {(x) = (ptr_t)ONES;}
 #   define MAKE_HOTTER(x,y) (x) -= (y)
 # else
 #   define COOLER_THAN <
 #   define HOTTER_THAN >
-#   define MAKE_COOLER(x,y) if ((word)(x)-(y) < (word)(x)) {(x) -= (y);} else {(x) = 0;}
+#   define MAKE_COOLER(x,y) if ((x)-(y) < (x)) {(x) -= (y);} else {(x) = 0;}
 #   define MAKE_HOTTER(x,y) (x) += (y)
 # endif
 
@@ -159,72 +150,15 @@ typedef char * ptr_t;     /* A generic pointer to which we can add        */
                    /* This is now really controlled at startup,        */
                    /* through GC_all_interior_pointers.                */
                    
-#define PRINTSTATS  /* Print garbage collection statistics             */
-                   /* For less verbose output, undefine in reclaim.c   */
-
-#define PRINTTIMES  /* Print the amount of time consumed by each garbage   */
-                   /* collection.                                         */
-
-#define PRINTBLOCKS /* Print object sizes associated with heap blocks,     */
-                   /* whether the objects are atomic or composite, and    */
-                   /* whether or not the block was found to be empty      */
-                   /* during the reclaim phase.  Typically generates       */
-                   /* about one screenful per garbage collection.         */
-#undef PRINTBLOCKS
-
-#ifdef SILENT
-#  ifdef PRINTSTATS
-#    undef PRINTSTATS
-#  endif
-#  ifdef PRINTTIMES
-#    undef PRINTTIMES
-#  endif
-#  ifdef PRINTNBLOCKS
-#    undef PRINTNBLOCKS
-#  endif
-#endif
-
-#if defined(PRINTSTATS) && !defined(GATHERSTATS)
-#   define GATHERSTATS
-#endif
-
-#if defined(PRINTSTATS) || !defined(SMALL_CONFIG)
-#   define CONDPRINT  /* Print some things if GC_print_stats is set */
-#endif
 
 #define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
 
-#define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */
-                   /* free lists are actually maintained.  This applies  */
-                   /* only to the top level routines in misc.c, not to   */
-                   /* user generated code that calls GC_allocobj and     */
-                   /* GC_allocaobj directly.                             */
-                   /* Slows down average programs slightly.  May however */
-                   /* substantially reduce fragmentation if allocation   */
-                   /* request sizes are widely scattered.                */
-                   /* May save significant amounts of space for obj_map  */
-                   /* entries.                                           */
-
-#if defined(USE_MARK_BYTES) && !defined(ALIGN_DOUBLE)
-#  define ALIGN_DOUBLE
-   /* We use one byte for every 2 words, which doesn't allow for       */
-   /* odd numbered words to have mark bits.                            */
-#endif
-
-#if defined(GC_GCJ_SUPPORT) && ALIGNMENT < 8 && !defined(ALIGN_DOUBLE)
-   /* GCJ's Hashtable synchronization code requires 64-bit alignment.  */
-#  define ALIGN_DOUBLE
-#endif
-
-/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
-# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
-#   define MERGE_SIZES
-# endif
-
 #if !defined(DONT_ADD_BYTE_AT_END)
 # define EXTRA_BYTES GC_all_interior_pointers
+# define MAX_EXTRA_BYTES 1
 #else
 # define EXTRA_BYTES 0
+# define MAX_EXTRA_BYTES 0
 #endif
 
 
@@ -264,7 +198,7 @@ typedef char * ptr_t;       /* A generic pointer to which we can add        */
 #      if NARGS > 0
            word ci_arg[NARGS]; /* bit-wise complement to avoid retention */
 #      endif
-#      if defined(ALIGN_DOUBLE) && (NFRAMES * (NARGS + 1)) % 2 == 1
+#      if (NFRAMES * (NARGS + 1)) % 2 == 1
            /* Likely alignment problem. */
            word ci_dummy;
 #      endif
@@ -275,9 +209,9 @@ typedef char * ptr_t;       /* A generic pointer to which we can add        */
 
 /* Fill in the pc and argument information for up to NFRAMES of my     */
 /* callers.  Ignore my frame and my callers frame.                     */
-void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES]));
+void GC_save_callers(struct callinfo info[NFRAMES]);
   
-void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
+void GC_print_callers(struct callinfo info[NFRAMES]);
 
 #endif
 
@@ -361,39 +295,8 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
 #   define BCOPY(x,y,n) memcpy(y, x, (size_t)(n))
 #   define BZERO(x,n)  memset(x, 0, (size_t)(n))
 # else
-#   define BCOPY(x,y,n) bcopy((char *)(x),(char *)(y),(int)(n))
-#   define BZERO(x,n) bzero((char *)(x),(int)(n))
-# endif
-
-/* Delay any interrupts or signals that may abort this thread.  Data   */
-/* structures are in a consistent state outside this pair of calls.    */
-/* ANSI C allows both to be empty (though the standard isn't very      */
-/* clear on that point).  Standard malloc implementations are usually  */
-/* neither interruptable nor thread-safe, and thus correspond to       */
-/* empty definitions.                                                  */
-/* It probably doesn't make any sense to declare these to be nonempty  */
-/* if the code is being optimized, since signal safety relies on some  */
-/* ordering constraints that are typically not obeyed by optimizing    */
-/* compilers.                                                          */
-# ifdef PCR
-#   define DISABLE_SIGNALS() \
-                PCR_Th_SetSigMask(PCR_allSigsBlocked,&GC_old_sig_mask)
-#   define ENABLE_SIGNALS() \
-               PCR_Th_SetSigMask(&GC_old_sig_mask, NIL)
-# else
-#   if defined(THREADS) || defined(AMIGA)  \
-       || defined(MSWIN32) || defined(MSWINCE) || defined(MACOS) \
-       || defined(DJGPP) || defined(NO_SIGNALS) 
-                       /* Also useful for debugging.           */
-       /* Should probably use thr_sigsetmask for GC_SOLARIS_THREADS. */
-#     define DISABLE_SIGNALS()
-#     define ENABLE_SIGNALS()
-#   else
-#     define DISABLE_SIGNALS() GC_disable_signals()
-       void GC_disable_signals();
-#     define ENABLE_SIGNALS() GC_enable_signals()
-       void GC_enable_signals();
-#   endif
+#   define BCOPY(x,y,n) bcopy((void *)(x),(void *)(y),(size_t)(n))
+#   define BZERO(x,n) bzero((void *)(x),(size_t)(n))
 # endif
 
 /*
@@ -427,10 +330,10 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
 #   define ABORT(s) PCR_Base_Panic(s)
 # else
 #   ifdef SMALL_CONFIG
-#      define ABORT(msg) abort();
+#      define ABORT(msg) abort()
 #   else
-       GC_API void GC_abort GC_PROTO((GC_CONST char * msg));
-#       define ABORT(msg) GC_abort(msg);
+       GC_API void GC_abort(const char * msg);
+#       define ABORT(msg) GC_abort(msg)
 #   endif
 # endif
 
@@ -464,6 +367,54 @@ extern GC_warn_proc GC_current_warn_proc;
 #   define GETENV(name) 0
 #endif
 
+#if defined(DARWIN)
+#      if defined(POWERPC)
+#              if CPP_WORDSZ == 32
+#                 define GC_THREAD_STATE_T ppc_thread_state_t
+#                define GC_MACH_THREAD_STATE PPC_THREAD_STATE
+#                define GC_MACH_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
+#                define GC_MACH_HEADER mach_header
+#                define GC_MACH_SECTION section
+#              else
+#                 define GC_THREAD_STATE_T ppc_thread_state64_t
+#                define GC_MACH_THREAD_STATE PPC_THREAD_STATE64
+#                define GC_MACH_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT
+#                define GC_MACH_HEADER mach_header_64
+#                define GC_MACH_SECTION section_64
+#              endif
+#      elif defined(I386) || defined(X86_64)
+#               if CPP_WORDSZ == 32
+#                define GC_THREAD_STATE_T x86_thread_state32_t
+#                define GC_MACH_THREAD_STATE x86_THREAD_STATE32
+#                define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
+#                define GC_MACH_HEADER mach_header
+#                define GC_MACH_SECTION section
+#               else
+#                define GC_THREAD_STATE_T x86_thread_state64_t
+#                define GC_MACH_THREAD_STATE x86_THREAD_STATE64
+#                define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
+#                define GC_MACH_HEADER mach_header_64
+#                define GC_MACH_SECTION section_64
+#               endif
+#      else
+#              error define GC_THREAD_STATE_T
+#              define GC_MACH_THREAD_STATE MACHINE_THREAD_STATE
+#              define GC_MACH_THREAD_STATE_COUNT MACHINE_THREAD_STATE_COUNT
+#      endif
+/* Try to work out the right way to access thread state structure members.
+   The structure has changed its definition in different Darwin versions.
+   This now defaults to the (older) names without __, thus hopefully,
+   not breaking any existing Makefile.direct builds.  */
+#       if defined (HAS_PPC_THREAD_STATE___R0) \
+         || defined (HAS_PPC_THREAD_STATE64___R0) \
+         || defined (HAS_X86_THREAD_STATE32___EAX) \
+         || defined (HAS_X86_THREAD_STATE64___RAX)
+#         define THREAD_FLD(x) __ ## x
+#       else
+#         define THREAD_FLD(x) x
+#       endif
+#endif
+
 /*********************************/
 /*                               */
 /* Word-size-dependent defines   */
@@ -490,12 +441,45 @@ extern GC_warn_proc GC_current_warn_proc;
 #  endif
 #endif
 
+/* The first TINY_FREELISTS free lists correspond to the first */
+/* TINY_FREELISTS multiples of GRANULE_BYTES, i.e. we keep     */
+/* separate free lists for each multiple of GRANULE_BYTES      */
+/* up to (TINY_FREELISTS-1) * GRANULE_BYTES.  After that they  */
+/* may be spread out further.                                  */
+#include "../gc_tiny_fl.h"
+#define GRANULE_BYTES GC_GRANULE_BYTES
+#define TINY_FREELISTS GC_TINY_FREELISTS
+
 #define WORDSZ ((word)CPP_WORDSZ)
 #define SIGNB  ((word)1 << (WORDSZ-1))
 #define BYTES_PER_WORD      ((word)(sizeof (word)))
 #define ONES                ((word)(signed_word)(-1))
 #define divWORDSZ(n) ((n) >> LOGWL)       /* divide n by size of word      */
 
+#if GRANULE_BYTES == 8
+# define BYTES_TO_GRANULES(n) ((n)>>3)
+# define GRANULES_TO_BYTES(n) ((n)<<3)
+# if CPP_WORDSZ == 64
+#   define GRANULES_TO_WORDS(n) (n)
+# elif CPP_WORDSZ == 32
+#   define GRANULES_TO_WORDS(n) ((n)<<1)
+# else
+#   define GRANULES_TO_WORDS(n) BYTES_TO_WORDS(GRANULES_TO_BYTES(n))
+# endif
+#elif GRANULE_BYTES == 16
+# define BYTES_TO_GRANULES(n) ((n)>>4)
+# define GRANULES_TO_BYTES(n) ((n)<<4)
+# if CPP_WORDSZ == 64
+#   define GRANULES_TO_WORDS(n) ((n)<<1)
+# elif CPP_WORDSZ == 32
+#   define GRANULES_TO_WORDS(n) ((n)<<2)
+# else
+#   define GRANULES_TO_WORDS(n) BYTES_TO_WORDS(GRANULES_TO_BYTES(n))
+# endif
+#else
+# error Bad GRANULE_BYTES value
+#endif
+
 /*********************/
 /*                   */
 /*  Size Parameters  */
@@ -540,17 +524,20 @@ extern GC_warn_proc GC_current_warn_proc;
 # undef HBLKSIZE
 #endif
 # define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
-# define LOG_HBLKSIZE   ((word)CPP_LOG_HBLKSIZE)
-# define HBLKSIZE ((word)CPP_HBLKSIZE)
+# define LOG_HBLKSIZE   ((size_t)CPP_LOG_HBLKSIZE)
+# define HBLKSIZE ((size_t)CPP_HBLKSIZE)
 
 
-/*  max size objects supported by freelist (larger objects may be   */
-/*  allocated, but less efficiently)                                */
+/*  max size objects supported by freelist (larger objects are */
+/*  allocated directly with allchblk(), by rounding to the next */
+/*  multiple of HBLKSIZE.                                      */
 
 #define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2)
-#define MAXOBJBYTES ((word)CPP_MAXOBJBYTES)
-#define CPP_MAXOBJSZ    BYTES_TO_WORDS(CPP_MAXOBJBYTES)
-#define MAXOBJSZ ((word)CPP_MAXOBJSZ)
+#define MAXOBJBYTES ((size_t)CPP_MAXOBJBYTES)
+#define CPP_MAXOBJWORDS BYTES_TO_WORDS(CPP_MAXOBJBYTES)
+#define MAXOBJWORDS ((size_t)CPP_MAXOBJWORDS)
+#define CPP_MAXOBJGRANULES BYTES_TO_GRANULES(CPP_MAXOBJBYTES)
+#define MAXOBJGRANULES ((size_t)CPP_MAXOBJGRANULES)
                
 # define divHBLKSZ(n) ((n) >> LOG_HBLKSIZE)
 
@@ -566,37 +553,34 @@ extern GC_warn_proc GC_current_warn_proc;
  
 # define HBLKPTR(objptr) ((struct hblk *)(((word) (objptr)) & ~(HBLKSIZE-1)))
 
-# define HBLKDISPL(objptr) (((word) (objptr)) & (HBLKSIZE-1))
+# define HBLKDISPL(objptr) (((size_t) (objptr)) & (HBLKSIZE-1))
 
 /* Round up byte allocation requests to integral number of words, etc. */
 # define ROUNDED_UP_WORDS(n) \
        BYTES_TO_WORDS((n) + (WORDS_TO_BYTES(1) - 1 + EXTRA_BYTES))
-# ifdef ALIGN_DOUBLE
-#       define ALIGNED_WORDS(n) \
-           (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1 + EXTRA_BYTES) & ~1)
+# define ROUNDED_UP_GRANULES(n) \
+       BYTES_TO_GRANULES((n) + (GRANULE_BYTES - 1 + EXTRA_BYTES))
+# if MAX_EXTRA_BYTES == 0
+#  define SMALL_OBJ(bytes) EXPECT((bytes) <= (MAXOBJBYTES), 1)
 # else
-#       define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n)
+#  define SMALL_OBJ(bytes) \
+           (EXPECT((bytes) <= (MAXOBJBYTES - MAX_EXTRA_BYTES), 1) || \
+            (bytes) <= (MAXOBJBYTES - EXTRA_BYTES))
+       /* This really just tests bytes <= MAXOBJBYTES - EXTRA_BYTES.   */
+       /* But we try to avoid looking up EXTRA_BYTES.                  */
 # endif
-# define SMALL_OBJ(bytes) ((bytes) <= (MAXOBJBYTES - EXTRA_BYTES))
 # define ADD_SLOP(bytes) ((bytes) + EXTRA_BYTES)
 # ifndef MIN_WORDS
-    /* MIN_WORDS is the size of the smallest allocated object. */
-    /* 1 and 2 are the only valid values.                      */
-    /* 2 must be used if:                                      */
-    /* - GC_gcj_malloc can be used for objects of requested    */
-    /*   size  smaller than 2 words, or                                */
-    /* - USE_MARK_BYTES is defined.                            */
-#   if defined(USE_MARK_BYTES) || defined(GC_GCJ_SUPPORT)
-#     define MIN_WORDS 2       /* Smallest allocated object.   */
-#   else
-#     define MIN_WORDS 1
-#   endif
+#  define MIN_WORDS 2  /* FIXME: obsolete */
 # endif
 
 
 /*
- * Hash table representation of sets of pages.  This assumes it is
- * OK to add spurious entries to sets.
+ * Hash table representation of sets of pages.
+ * Implements a map from aligned HBLKSIZE chunks of the address space to one
+ * bit each.
+ * This assumes it is OK to spuriously set bits, e.g. because multiple
+ * addresses are represented by a single location.
  * Used by black-listing code, and perhaps by dirty bit maintenance code.
  */
  
@@ -648,43 +632,43 @@ typedef word page_hash_table[PHT_SIZE];
 /*  heap block header */
 #define HBLKMASK   (HBLKSIZE-1)
 
-#define BITS_PER_HBLK (CPP_HBLKSIZE * 8)
-
-#define MARK_BITS_PER_HBLK (BITS_PER_HBLK/CPP_WORDSZ)
+#define MARK_BITS_PER_HBLK (HBLKSIZE/GRANULE_BYTES)
           /* upper bound                                    */
-          /* We allocate 1 bit/word, unless USE_MARK_BYTES  */
-          /* is defined.  Only the first word               */
-          /* in each object is actually marked.             */
+          /* We allocate 1 bit per allocation granule.      */
+          /* If MARK_BIT_PER_GRANULE is defined, we use     */
+          /* every nth bit, where n is the number of        */
+          /* allocation granules per object.  If            */
+          /* MARK_BIT_PER_OBJ is defined, we only use the   */
+          /* initial group of mark bits, and it is safe     */
+          /* to allocate smaller header for large objects.  */
 
 # ifdef USE_MARK_BYTES
-#   define MARK_BITS_SZ (MARK_BITS_PER_HBLK/2)
+#   define MARK_BITS_SZ (MARK_BITS_PER_HBLK + 1)
        /* Unlike the other case, this is in units of bytes.            */
-       /* We actually allocate only every second mark bit, since we    */
-       /* force all objects to be doubleword aligned.                  */
-       /* However, each mark bit is allocated as a byte.               */
+       /* Since we force doubleword alignment, we need at most one     */
+       /* mark bit per 2 words.  But we do allocate and set one        */
+       /* extra mark bit to avoid an explicit check for the            */
+       /* partial object at the end of each block.                     */
 # else
-#   define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ)
+#   define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ + 1)
 # endif
 
+#ifdef PARALLEL_MARK
+# include <atomic_ops.h>
+  typedef AO_t counter_t;
+#else
+  typedef size_t counter_t;
+#endif
+
 /* We maintain layout maps for heap blocks containing objects of a given */
 /* size.  Each entry in this map describes a byte offset and has the    */
 /* following type.                                                      */
-typedef unsigned char map_entry_type;
-
 struct hblkhdr {
-    word hb_sz;  /* If in use, size in words, of objects in the block. */
-                /* if free, the size in bytes of the whole block      */
     struct hblk * hb_next;     /* Link field for hblk free list         */
                                /* and for lists of chunks waiting to be */
                                /* reclaimed.                            */
     struct hblk * hb_prev;     /* Backwards link for free list.        */
-    word hb_descr;             /* object descriptor for marking.  See  */
-                               /* mark.h.                              */
-    map_entry_type * hb_map;   
-                       /* A pointer to a pointer validity map of the block. */
-                       /* See GC_obj_map.                                   */
-                       /* Valid for all blocks with headers.                */
-                       /* Free blocks point to GC_invalid_map.              */
+    struct hblk * hb_block;    /* The corresponding block.             */
     unsigned char hb_obj_kind;
                         /* Kind of objects in the block.  Each kind    */
                         /* identifies a mark procedure and a set of    */
@@ -699,6 +683,7 @@ struct hblkhdr {
                                /* GC_remap must be invoked on it       */
                                /* before it can be reallocated.        */
                                /* Only set with USE_MUNMAP.            */
+#      define FREE_BLK 4       /* Block is free, i.e. not in use.      */
     unsigned short hb_last_reclaimed;
                                /* Value of GC_gc_no when block was     */
                                /* last allocated or swept. May wrap.   */
@@ -707,43 +692,81 @@ struct hblkhdr {
                                /* when the header was allocated, or    */
                                /* when the size of the block last      */
                                /* changed.                             */
+    size_t hb_sz;  /* If in use, size in bytes, of objects in the block. */
+                  /* if free, the size in bytes of the whole block      */
+    word hb_descr;             /* object descriptor for marking.  See  */
+                               /* mark.h.                              */
+#   ifdef MARK_BIT_PER_OBJ
+      unsigned32 hb_inv_sz;    /* A good upper bound for 2**32/hb_sz.  */
+                               /* For large objects, we use            */
+                               /* LARGE_INV_SZ.                        */
+#     define LARGE_INV_SZ (1 << 16)
+#   else
+      unsigned char hb_large_block;
+      short * hb_map;          /* Essentially a table of remainders    */
+                               /* mod BYTES_TO_GRANULES(hb_sz), except */
+                               /* for large blocks.  See GC_obj_map.   */
+#   endif
+    counter_t hb_n_marks;      /* Number of set mark bits, excluding   */
+                               /* the one always set at the end.       */
+                               /* Currently it is concurrently         */
+                               /* updated and hence only approximate.  */
+                               /* But a zero value does guarantee that */
+                               /* the block contains no marked         */
+                               /* objects.                             */
+                               /* Ensuring this property means that we */
+                               /* never decrement it to zero during a  */
+                               /* collection, and hence the count may  */
+                               /* be one too high.  Due to concurrent  */
+                               /* updates, an arbitrary number of      */
+                               /* increments, but not all of them (!)  */
+                               /* may be lost, hence it may in theory  */
+                               /* be much too low.                     */
+                               /* The count may also be too high if    */
+                               /* multiple mark threads mark the       */
+                               /* same object due to a race.           */
+                               /* Without parallel marking, the count  */
+                               /* is accurate.                         */
 #   ifdef USE_MARK_BYTES
       union {
         char _hb_marks[MARK_BITS_SZ];
                            /* The i'th byte is 1 if the object         */
-                           /* starting at word 2i is marked, 0 o.w.    */
+                           /* starting at granule i or object i is     */
+                           /* marked, 0 o.w.                           */
+                           /* The mark bit for the "one past the       */
+                           /* end" object is always set to avoid a     */
+                           /* special case test in the marker.         */
        word dummy;     /* Force word alignment of mark bytes. */
       } _mark_byte_union;
 #     define hb_marks _mark_byte_union._hb_marks
 #   else
       word hb_marks[MARK_BITS_SZ];
-                           /* Bit i in the array refers to the             */
-                           /* object starting at the ith word (header      */
-                           /* INCLUDED) in the heap block.                 */
-                           /* The lsb of word 0 is numbered 0.             */
-                           /* Unused bits are invalid, and are             */
-                           /* occasionally set, e.g for uncollectable      */
-                           /* objects.                                     */
 #   endif /* !USE_MARK_BYTES */
 };
 
+# define ANY_INDEX 23  /* "Random" mark bit index for assertions */
+
 /*  heap block body */
 
-# define BODY_SZ (HBLKSIZE/sizeof(word))
+# define HBLK_WORDS (HBLKSIZE/sizeof(word))
+# define HBLK_GRANULES (HBLKSIZE/GRANULE_BYTES)
+
+/* The number of objects in a block dedicated to a certain size.       */
+/* may erroneously yield zero (instead of one) for large objects.      */
+# define HBLK_OBJS(sz_in_bytes) (HBLKSIZE/(sz_in_bytes))
 
 struct hblk {
-    word hb_body[BODY_SZ];
+    char hb_body[HBLKSIZE];
 };
 
-# define HBLK_IS_FREE(hdr) ((hdr) -> hb_map == GC_invalid_map)
+# define HBLK_IS_FREE(hdr) (((hdr) -> hb_flags & FREE_BLK) != 0)
 
-# define OBJ_SZ_TO_BLOCKS(sz) \
-    divHBLKSZ(WORDS_TO_BYTES(sz) + HBLKSIZE-1)
+# define OBJ_SZ_TO_BLOCKS(sz) divHBLKSZ(sz + HBLKSIZE-1)
     /* Size of block (in units of HBLKSIZE) needed to hold objects of  */
-    /* given sz (in words).                                            */
+    /* given sz (in bytes).                                            */
 
 /* Object free list link */
-# define obj_link(p) (*(ptr_t *)(p))
+# define obj_link(p) (*(void  **)(p))
 
 # define LOG_MAX_MARK_PROCS 6
 # define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS)
@@ -811,7 +834,7 @@ struct roots {
 /* compiled.                                   */
 
 struct _GC_arrays {
-  word _heapsize;
+  word _heapsize;              /* Heap size in bytes.                  */
   word _max_heapsize;
   word _requested_heapsize;    /* Heap size due to explicit expansion */
   ptr_t _last_heap_addr;
@@ -828,29 +851,25 @@ struct _GC_arrays {
        /* Maximum number of bytes that were ever allocated in          */
        /* large object blocks.  This is used to help decide when it    */
        /* is safe to split up a large block.                           */
-  word _words_allocd_before_gc;
+  word _bytes_allocd_before_gc;
                /* Number of words allocated before this        */
                /* collection cycle.                            */
 # ifndef SEPARATE_GLOBALS
-    word _words_allocd;
+    word _bytes_allocd;
        /* Number of words allocated during this collection cycle */
 # endif
-  word _words_wasted;
-       /* Number of words wasted due to internal fragmentation */
-       /* in large objects, or due to dropping blacklisted     */
-       /* blocks, since last gc.  Approximate.                 */
-  word _words_finalized;
-       /* Approximate number of words in objects (and headers) */
+  word _bytes_finalized;
+       /* Approximate number of bytes in objects (and headers) */
        /* That became ready for finalization in the last       */
        /* collection.                                          */
   word _non_gc_bytes_at_gc;
        /* Number of explicitly managed bytes of storage        */
        /* at last collection.                                  */
-  word _mem_freed;
-       /* Number of explicitly deallocated words of memory     */
+  word _bytes_freed;
+       /* Number of explicitly deallocated bytes of memory     */
        /* since last collection.                               */
-  word _finalizer_mem_freed;
-       /* Words of memory explicitly deallocated while         */
+  word _finalizer_bytes_freed;
+       /* Bytes of memory explicitly deallocated while         */
        /* finalizers were running.  Used to approximate mem.   */
        /* explicitly deallocated by finalizers.                */
   ptr_t _scratch_end_ptr;
@@ -863,77 +882,61 @@ struct _GC_arrays {
        /* by DS_PROC mark descriptors.  See gc_mark.h.         */
 
 # ifndef SEPARATE_GLOBALS
-    ptr_t _objfreelist[MAXOBJSZ+1];
+    void *_objfreelist[MAXOBJGRANULES+1];
                          /* free list for objects */
-    ptr_t _aobjfreelist[MAXOBJSZ+1];
+    void *_aobjfreelist[MAXOBJGRANULES+1];
                          /* free list for atomic objs  */
 # endif
 
-  ptr_t _uobjfreelist[MAXOBJSZ+1];
+  void *_uobjfreelist[MAXOBJGRANULES+1];
                          /* uncollectable but traced objs      */
                          /* objects on this and auobjfreelist  */
                          /* are always marked, except during   */
                          /* garbage collections.               */
 # ifdef ATOMIC_UNCOLLECTABLE
-    ptr_t _auobjfreelist[MAXOBJSZ+1];
+    void *_auobjfreelist[MAXOBJGRANULES+1];
 # endif
                          /* uncollectable but traced objs      */
 
-# ifdef GATHERSTATS
     word _composite_in_use;
                /* Number of words in accessible composite      */
                /* objects.                                     */
     word _atomic_in_use;
                /* Number of words in accessible atomic         */
                /* objects.                                     */
-# endif
 # ifdef USE_MUNMAP
     word _unmapped_bytes;
 # endif
-# ifdef MERGE_SIZES
-    unsigned _size_map[WORDS_TO_BYTES(MAXOBJSZ+1)];
+
+    size_t _size_map[MAXOBJBYTES+1];
        /* Number of words to allocate for a given allocation request in */
        /* bytes.                                                        */
-# endif 
 
 # ifdef STUBBORN_ALLOC
-    ptr_t _sobjfreelist[MAXOBJSZ+1];
+    ptr_t _sobjfreelist[MAXOBJGRANULES+1];
 # endif
                          /* free list for immutable objects    */
-  map_entry_type * _obj_map[MAXOBJSZ+1];
+# ifdef MARK_BIT_PER_GRANULE
+    short * _obj_map[MAXOBJGRANULES+1];
                        /* If not NIL, then a pointer to a map of valid  */
-                      /* object addresses. _obj_map[sz][i] is j if the */
-                      /* address block_start+i is a valid pointer      */
-                      /* to an object at block_start +                 */
-                      /* WORDS_TO_BYTES(BYTES_TO_WORDS(i) - j)         */
-                      /* I.e. j is a word displacement from the        */
-                      /* object beginning.                             */
-                      /* The entry is OBJ_INVALID if the corresponding */
-                      /* address is not a valid pointer.  It is        */
-                      /* OFFSET_TOO_BIG if the value j would be too    */
-                      /* large to fit in the entry.  (Note that the    */
-                      /* size of these entries matters, both for       */
-                      /* space consumption and for cache utilization.) */
-#   define OFFSET_TOO_BIG 0xfe
-#   define OBJ_INVALID 0xff
-#   define MAP_ENTRY(map, bytes) (map)[bytes]
-#   define MAP_ENTRIES HBLKSIZE
-#   define MAP_SIZE MAP_ENTRIES
-#   define CPP_MAX_OFFSET (OFFSET_TOO_BIG - 1) 
-#   define MAX_OFFSET ((word)CPP_MAX_OFFSET)
-    /* The following are used only if GC_all_interior_ptrs != 0 */
-#      define VALID_OFFSET_SZ \
-         (CPP_MAX_OFFSET > WORDS_TO_BYTES(CPP_MAXOBJSZ)? \
-          CPP_MAX_OFFSET+1 \
-          : WORDS_TO_BYTES(CPP_MAXOBJSZ)+1)
-       char _valid_offsets[VALID_OFFSET_SZ];
+                      /* object addresses.                             */
+                      /* _obj_map[sz_in_granules][i] is                */
+                      /* i % sz_in_granules.                           */
+                      /* This is now used purely to replace a          */
+                      /* division in the marker by a table lookup.     */
+                      /* _obj_map[0] is used for large objects and     */
+                      /* contains all nonzero entries.  This gets us   */
+                      /* out of the marker fast path without an extra  */
+                      /* test.                                         */
+#   define MAP_LEN BYTES_TO_GRANULES(HBLKSIZE)
+# endif
+#   define VALID_OFFSET_SZ HBLKSIZE
+  char _valid_offsets[VALID_OFFSET_SZ];
                                /* GC_valid_offsets[i] == TRUE ==> i    */
                                /* is registered as a displacement.     */
-       char _modws_valid_offsets[sizeof(word)];
+  char _modws_valid_offsets[sizeof(word)];
                                /* GC_valid_offsets[i] ==>                */
                                /* GC_modws_valid_offsets[i%sizeof(word)] */
-#   define OFFSET_VALID(displ) \
-         (GC_all_interior_pointers || GC_valid_offsets[displ])
 # ifdef STUBBORN_ALLOC
     page_hash_table _changed_pages;
         /* Stubborn object pages that were changes since last call to  */
@@ -942,15 +945,16 @@ struct _GC_arrays {
         /* Stubborn object pages that were changes before last call to */
        /* GC_read_changed.                                             */
 # endif
-# if defined(PROC_VDB) || defined(MPROTECT_VDB)
+# if defined(PROC_VDB) || defined(MPROTECT_VDB) || \
+     defined(GWW_VDB) || defined(MANUAL_VDB)
     page_hash_table _grungy_pages; /* Pages that were dirty at last       */
                                     /* GC_read_dirty.                     */
 # endif
-# ifdef MPROTECT_VDB
-    VOLATILE page_hash_table _dirty_pages;     
+# if defined(MPROTECT_VDB) || defined(MANUAL_VDB)
+    volatile page_hash_table _dirty_pages;     
                        /* Pages dirtied since last GC_read_dirty. */
 # endif
-# ifdef PROC_VDB
+# if defined(PROC_VDB) || defined(GWW_VDB)
     page_hash_table _written_pages;    /* Pages ever dirtied   */
 # endif
 # ifdef LARGE_CONFIG
@@ -967,7 +971,7 @@ struct _GC_arrays {
 #   endif
 # endif
   struct HeapSect {
-      ptr_t hs_start; word hs_bytes;
+      ptr_t hs_start; size_t hs_bytes;
   } _heap_sects[MAX_HEAP_SECTS];
 # if defined(MSWIN32) || defined(MSWINCE)
     ptr_t _heap_bases[MAX_HEAP_SECTS];
@@ -985,6 +989,9 @@ struct _GC_arrays {
   /* Block header index; see gc_headers.h */
   bottom_index * _all_nils;
   bottom_index * _top_index [TOP_SZ];
+#ifdef ENABLE_TRACE
+  ptr_t _trace_addr;
+#endif
 #ifdef SAVE_CALL_CHAIN
   struct callinfo _last_stack[NFRAMES];        /* Stack at last garbage collection.*/
                                        /* Useful for debugging mysterious  */
@@ -1000,7 +1007,7 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
 # ifndef SEPARATE_GLOBALS
 #   define GC_objfreelist GC_arrays._objfreelist
 #   define GC_aobjfreelist GC_arrays._aobjfreelist
-#   define GC_words_allocd GC_arrays._words_allocd
+#   define GC_bytes_allocd GC_arrays._bytes_allocd
 # endif
 # define GC_uobjfreelist GC_arrays._uobjfreelist
 # ifdef ATOMIC_UNCOLLECTABLE
@@ -1013,26 +1020,30 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
 #    define GC_changed_pages GC_arrays._changed_pages
 #    define GC_prev_changed_pages GC_arrays._prev_changed_pages
 # endif
-# define GC_obj_map GC_arrays._obj_map
+# ifdef MARK_BIT_PER_GRANULE
+#   define GC_obj_map GC_arrays._obj_map
+# endif
 # define GC_last_heap_addr GC_arrays._last_heap_addr
 # define GC_prev_heap_addr GC_arrays._prev_heap_addr
-# define GC_words_wasted GC_arrays._words_wasted
 # define GC_large_free_bytes GC_arrays._large_free_bytes
 # define GC_large_allocd_bytes GC_arrays._large_allocd_bytes
 # define GC_max_large_allocd_bytes GC_arrays._max_large_allocd_bytes
-# define GC_words_finalized GC_arrays._words_finalized
+# define GC_bytes_finalized GC_arrays._bytes_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_finalizer_mem_freed GC_arrays._finalizer_mem_freed
+# define GC_bytes_freed GC_arrays._bytes_freed
+# define GC_finalizer_bytes_freed GC_arrays._finalizer_bytes_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_bytes_allocd_before_gc GC_arrays._bytes_allocd_before_gc
 # define GC_heap_sects GC_arrays._heap_sects
 # define GC_last_stack GC_arrays._last_stack
+#ifdef ENABLE_TRACE
+#define GC_trace_addr GC_arrays._trace_addr
+#endif
 # ifdef USE_MUNMAP
 #   define GC_unmapped_bytes GC_arrays._unmapped_bytes
 # endif
@@ -1047,22 +1058,19 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
 # define GC_excl_table GC_arrays._excl_table
 # define GC_all_nils GC_arrays._all_nils
 # define GC_top_index GC_arrays._top_index
-# if defined(PROC_VDB) || defined(MPROTECT_VDB)
+# if defined(PROC_VDB) || defined(MPROTECT_VDB) || \
+     defined(GWW_VDB) || defined(MANUAL_VDB)
 #   define GC_grungy_pages GC_arrays._grungy_pages
 # endif
-# ifdef MPROTECT_VDB
+# if defined(MPROTECT_VDB) || defined(MANUAL_VDB)
 #   define GC_dirty_pages GC_arrays._dirty_pages
 # endif
-# ifdef PROC_VDB
+# if defined(PROC_VDB) || defined(GWW_VDB)
 #   define GC_written_pages GC_arrays._written_pages
 # endif
-# ifdef GATHERSTATS
-#   define GC_composite_in_use GC_arrays._composite_in_use
-#   define GC_atomic_in_use GC_arrays._atomic_in_use
-# endif
-# ifdef MERGE_SIZES
-#   define GC_size_map GC_arrays._size_map
-# endif
+# define GC_composite_in_use GC_arrays._composite_in_use
+# define GC_atomic_in_use GC_arrays._atomic_in_use
+# define GC_size_map GC_arrays._size_map
 
 # define beginGC_arrays ((ptr_t)(&GC_arrays))
 # define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays))
@@ -1073,12 +1081,13 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
 # define MAXOBJKINDS 16
 
 extern struct obj_kind {
-   ptr_t *ok_freelist; /* Array of free listheaders for this kind of object */
+   void **ok_freelist; /* Array of free listheaders for this kind of object */
                        /* Point either to GC_arrays or to storage allocated */
                        /* with GC_scratch_alloc.                            */
    struct hblk **ok_reclaim_list;
                        /* List headers for lists of blocks waiting to be */
                        /* swept.                                         */
+                       /* Indexed by object size in granules.            */
    word ok_descriptor;  /* Descriptor template for objects in this     */
                        /* block.                                       */
    GC_bool ok_relocate_descr;
@@ -1097,14 +1106,14 @@ extern struct obj_kind {
 /* introduce maintenance problems.                                     */
 
 #ifdef SEPARATE_GLOBALS
-  word GC_words_allocd;
+  word GC_bytes_allocd;
        /* Number of words allocated during this collection cycle */
-  ptr_t GC_objfreelist[MAXOBJSZ+1];
+  ptr_t GC_objfreelist[MAXOBJGRANULES+1];
                          /* free list for NORMAL objects */
 # define beginGC_objfreelist ((ptr_t)(&GC_objfreelist))
 # define endGC_objfreelist (beginGC_objfreelist + sizeof(GC_objfreelist))
 
-  ptr_t GC_aobjfreelist[MAXOBJSZ+1];
+  ptr_t GC_aobjfreelist[MAXOBJGRANULES+1];
                          /* free list for atomic (PTRFREE) objs        */
 # define beginGC_aobjfreelist ((ptr_t)(&GC_aobjfreelist))
 # define endGC_aobjfreelist (beginGC_aobjfreelist + sizeof(GC_aobjfreelist))
@@ -1123,7 +1132,7 @@ extern struct obj_kind {
 #   define IS_UNCOLLECTABLE(k) ((k) == UNCOLLECTABLE)
 # endif
 
-extern int GC_n_kinds;
+extern unsigned GC_n_kinds;
 
 GC_API word GC_fo_entries;
 
@@ -1148,10 +1157,6 @@ extern word GC_black_list_spacing;
                        /* "stack-blacklisted", i.e. that are           */
                        /* problematic in the interior of an object.    */
 
-extern map_entry_type * GC_invalid_map;
-                       /* Pointer to the nowhere valid hblk map */
-                       /* Blocks pointing to this map are free. */
-
 extern struct hblk * GC_hblkfreelist[];
                                /* List of completely empty heap blocks */
                                /* Linked through hb_next field of      */
@@ -1207,44 +1212,24 @@ extern long GC_large_alloc_warn_suppressed;
 /* accessed.                                                           */
 #ifdef PARALLEL_MARK
 # define OR_WORD(addr, bits) \
-       { word old; \
-         do { \
-           old = *((volatile word *)addr); \
-         } while (!GC_compare_and_exchange((addr), old, old | (bits))); \
-       }
-# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
-       { word old; \
-         word my_bits = (bits); \
-         do { \
-           old = *((volatile word *)addr); \
-           if (old & my_bits) goto exit_label; \
-         } while (!GC_compare_and_exchange((addr), old, old | my_bits)); \
-       }
+       { AO_or((volatile AO_t *)(addr), (AO_t)bits); }
 #else
 # define OR_WORD(addr, bits) *(addr) |= (bits)
-# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
-       { \
-         word old = *(addr); \
-         word my_bits = (bits); \
-         if (old & my_bits) goto exit_label; \
-         *(addr) = (old | my_bits); \
-       }
 #endif
 
 /* Mark bit operations */
 
 /*
- * Retrieve, set, clear the mark bit corresponding
- * to the nth word in a given heap block.
+ * Retrieve, set, clear the nth mark bit in a given heap block.
  *
- * (Recall that bit n corresponds to object beginning at word n
+ * (Recall that bit n corresponds to nth object or allocation granule
  * relative to the beginning of the block, including unused words)
  */
 
 #ifdef USE_MARK_BYTES
-# define mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n) >> 1])
-# define set_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n)>>1]) = 1
-# define clear_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n)>>1]) = 0
+# define mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n])
+# define set_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n]) = 1
+# define clear_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n]) = 0
 #else /* !USE_MARK_BYTES */
 # define mark_bit_from_hdr(hhdr,n) (((hhdr)->hb_marks[divWORDSZ(n)] \
                            >> (modWORDSZ(n))) & (word)1)
@@ -1255,70 +1240,85 @@ extern long GC_large_alloc_warn_suppressed;
                                &= ~((word)1 << modWORDSZ(n))
 #endif /* !USE_MARK_BYTES */
 
+#ifdef MARK_BIT_PER_OBJ
+#  define MARK_BIT_NO(offset, sz) (((unsigned)(offset))/(sz))
+       /* Get the mark bit index corresponding to the given byte       */
+       /* offset and size (in bytes).                                  */
+#  define MARK_BIT_OFFSET(sz) 1
+       /* Spacing between useful mark bits.                            */
+#  define IF_PER_OBJ(x) x
+#  define FINAL_MARK_BIT(sz) ((sz) > MAXOBJBYTES? 1 : HBLK_OBJS(sz))
+       /* Position of final, always set, mark bit.                     */
+#else /* MARK_BIT_PER_GRANULE */
+#  define MARK_BIT_NO(offset, sz) BYTES_TO_GRANULES((unsigned)(offset))
+#  define MARK_BIT_OFFSET(sz) BYTES_TO_GRANULES(sz)
+#  define IF_PER_OBJ(x)
+#  define FINAL_MARK_BIT(sz) \
+       ((sz) > MAXOBJBYTES? MARK_BITS_PER_HBLK \
+                       : BYTES_TO_GRANULES(sz * HBLK_OBJS(sz)))
+#endif
+
 /* Important internal collector routines */
 
-ptr_t GC_approx_sp GC_PROTO((void));
+ptr_t GC_approx_sp(void);
   
-GC_bool GC_should_collect GC_PROTO((void));
+GC_bool GC_should_collect(void);
   
-void GC_apply_to_all_blocks GC_PROTO(( \
-    void (*fn) GC_PROTO((struct hblk *h, word client_data)), \
-    word client_data));
+void GC_apply_to_all_blocks(void (*fn) (struct hblk *h, word client_data),
+                           word client_data);
                        /* Invoke fn(hbp, client_data) for each         */
                        /* allocated heap block.                        */
-struct hblk * GC_next_used_block GC_PROTO((struct hblk * h));
+struct hblk * GC_next_used_block(struct hblk * h);
                        /* Return first in-use block >= h       */
-struct hblk * GC_prev_block GC_PROTO((struct hblk * h));
+struct hblk * GC_prev_block(struct hblk * h);
                        /* Return last block <= h.  Returned block      */
                        /* is managed by GC, but may or may not be in   */
                        /* use.                                         */
-void GC_mark_init GC_PROTO((void));
-void GC_clear_marks GC_PROTO((void));  /* Clear mark bits for all heap objects. */
-void GC_invalidate_mark_state GC_PROTO((void));
+void GC_mark_init(void);
+void GC_clear_marks(void);     /* Clear mark bits for all heap objects. */
+void GC_invalidate_mark_state(void);
                                        /* Tell the marker that marked     */
                                        /* objects may point to unmarked   */
                                        /* ones, and roots may point to    */
                                        /* unmarked objects.               */
                                        /* Reset mark stack.               */
-GC_bool GC_mark_stack_empty GC_PROTO((void));
-GC_bool GC_mark_some GC_PROTO((ptr_t cold_gc_frame));
+GC_bool GC_mark_stack_empty(void);
+GC_bool GC_mark_some(ptr_t cold_gc_frame);
                        /* Perform about one pages worth of marking     */
                        /* work of whatever kind is needed.  Returns    */
                        /* quickly if no collection is in progress.     */
                        /* Return TRUE if mark phase finished.          */
-void GC_initiate_gc GC_PROTO((void));
+void GC_initiate_gc(void);
                                /* initiate collection.                 */
                                /* If the mark state is invalid, this   */
                                /* becomes full colleection.  Otherwise */
                                /* it's partial.                        */
-void GC_push_all GC_PROTO((ptr_t bottom, ptr_t top));
+void GC_push_all(ptr_t bottom, ptr_t top);
                                /* Push everything in a range           */
                                /* onto mark stack.                     */
-void GC_push_selected GC_PROTO(( \
-    ptr_t bottom, \
-    ptr_t top, \
-    int (*dirty_fn) GC_PROTO((struct hblk *h)), \
-    void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top)) ));
+void GC_push_selected(ptr_t bottom, ptr_t top,
+                     int (*dirty_fn) (struct hblk *h),
+                     void (*push_fn) (ptr_t bottom, ptr_t top) );
                                  /* Push all pages h in [b,t) s.t.     */
                                  /* select_fn(h) != 0 onto mark stack. */
 #ifndef SMALL_CONFIG
-  void GC_push_conditional GC_PROTO((ptr_t b, ptr_t t, GC_bool all));
+  void GC_push_conditional (ptr_t b, ptr_t t, GC_bool all);
 #else
 # define GC_push_conditional(b, t, all) GC_push_all(b, t)
 #endif
                                 /* Do either of the above, depending   */
                                /* on the third arg.                    */
-void GC_push_all_stack GC_PROTO((ptr_t b, ptr_t t));
+void GC_push_all_stack (ptr_t b, ptr_t t);
                                    /* As above, but consider           */
                                    /*  interior pointers as valid      */
-void GC_push_all_eager GC_PROTO((ptr_t b, ptr_t t));
+void GC_push_all_eager (ptr_t b, ptr_t t);
                                    /* Same as GC_push_all_stack, but   */
                                    /* ensures that stack is scanned    */
                                    /* immediately, not just scheduled  */
                                    /* for scanning.                    */
 #ifndef THREADS
-  void GC_push_all_stack_partially_eager GC_PROTO(( \
-      ptr_t bottom, ptr_t top, ptr_t cold_gc_frame ));
+  void GC_push_all_stack_partially_eager(ptr_t bottom, ptr_t top,
+                                        ptr_t cold_gc_frame);
                        /* Similar to GC_push_all_eager, but only the   */
                        /* part hotter than cold_gc_frame is scanned    */
                        /* immediately.  Needed to ensure that callee-  */
@@ -1330,46 +1330,52 @@ void GC_push_all_eager GC_PROTO((ptr_t b, ptr_t t));
   /* stacks are scheduled for scanning in *GC_push_other_roots, which  */
   /* is thread-package-specific.                                       */
 #endif
-void GC_push_current_stack GC_PROTO((ptr_t cold_gc_frame));
+void GC_push_current_stack(ptr_t cold_gc_frame, void *context);
                        /* Push enough of the current stack eagerly to  */
                        /* ensure that callee-save registers saved in   */
                        /* GC frames are scanned.                       */
                        /* In the non-threads case, schedule entire     */
                        /* stack for scanning.                          */
-void GC_push_roots GC_PROTO((GC_bool all, ptr_t cold_gc_frame));
+                       /* The second argument is a pointer to the      */
+                       /* (possibly null) thread context, for          */
+                       /* (currently hypothetical) more precise        */
+                       /* stack scanning.                              */
+void GC_push_roots(GC_bool all, ptr_t cold_gc_frame);
                        /* Push all or dirty roots.     */
-extern void (*GC_push_other_roots) GC_PROTO((void));
+extern void (*GC_push_other_roots)(void);
                        /* Push system or application specific roots    */
                        /* onto the mark stack.  In some environments   */
                        /* (e.g. threads environments) this is          */
                        /* predfined to be non-zero.  A client supplied */
                        /* replacement should also call the original    */
                        /* function.                                    */
-extern void GC_push_gc_structures GC_PROTO((void));
+extern void GC_push_gc_structures(void);
                        /* Push GC internal roots.  These are normally  */
                        /* included in the static data segment, and     */
                        /* Thus implicitly pushed.  But we must do this */
                        /* explicitly if normal root processing is      */
                        /* disabled.  Calls the following:              */
-       extern void GC_push_finalizer_structures GC_PROTO((void));
-       extern void GC_push_stubborn_structures GC_PROTO((void));
+       extern void GC_push_finalizer_structures(void);
+       extern void GC_push_stubborn_structures (void);
 #      ifdef THREADS
-         extern void GC_push_thread_structures GC_PROTO((void));
+         extern void GC_push_thread_structures (void);
 #      endif
-extern void (*GC_start_call_back) GC_PROTO((void));
+extern void (*GC_start_call_back) (void);
                        /* Called at start of full collections.         */
                        /* Not called if 0.  Called with allocation     */
                        /* lock held.                                   */
                        /* 0 by default.                                */
-# if defined(USE_GENERIC_PUSH_REGS)
-  void GC_generic_push_regs GC_PROTO((ptr_t cold_gc_frame));
-# else
-  void GC_push_regs GC_PROTO((void));
-# endif
+void GC_push_regs_and_stack(ptr_t cold_gc_frame);
+
+void GC_push_regs(void);
+
+void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
+                                ptr_t arg);
+
 # if defined(SPARC) || defined(IA64)
   /* Cause all stacked registers to be saved in memory.  Return a      */
   /* pointer to the top of the corresponding memory stack.             */
-  word GC_save_regs_in_stack GC_PROTO((void));
+  ptr_t GC_save_regs_in_stack(void);
 # endif
                        /* Push register contents onto mark stack.      */
                        /* If NURSERY is defined, the default push      */
@@ -1379,9 +1385,9 @@ extern void (*GC_start_call_back) GC_PROTO((void));
     extern void (*GC_push_proc)(ptr_t);
 # endif
 # if defined(MSWIN32) || defined(MSWINCE)
-  void __cdecl GC_push_one GC_PROTO((word p));
+  void __cdecl GC_push_one(word p);
 # else
-  void GC_push_one GC_PROTO((word p));
+  void GC_push_one(word p);
                              /* If p points to an object, mark it    */
                               /* and push contents on the mark stack  */
                              /* Pointer recognition test always      */
@@ -1390,133 +1396,144 @@ extern void (*GC_start_call_back) GC_PROTO((void));
                              /* stack.                               */
 # endif
 # if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
-  void GC_mark_and_push_stack GC_PROTO((word p, ptr_t source));
+  void GC_mark_and_push_stack(ptr_t p, ptr_t source);
                                /* Ditto, omits plausibility test       */
 # else
-  void GC_mark_and_push_stack GC_PROTO((word p));
+  void GC_mark_and_push_stack(ptr_t p);
 # endif
-void GC_push_marked GC_PROTO((struct hblk * h, hdr * hhdr));
+void GC_push_marked(struct hblk * h, hdr * hhdr);
                /* Push contents of all marked objects in h onto        */
                /* mark stack.                                          */
 #ifdef SMALL_CONFIG
 # define GC_push_next_marked_dirty(h) GC_push_next_marked(h)
 #else
-  struct hblk * GC_push_next_marked_dirty GC_PROTO((struct hblk * h));
+  struct hblk * GC_push_next_marked_dirty(struct hblk * h);
                /* Invoke GC_push_marked on next dirty block above h.   */
                /* Return a pointer just past the end of this block.    */
 #endif /* !SMALL_CONFIG */
-struct hblk * GC_push_next_marked GC_PROTO((struct hblk * h));
+struct hblk * GC_push_next_marked(struct hblk * h);
                /* Ditto, but also mark from clean pages.       */
-struct hblk * GC_push_next_marked_uncollectable GC_PROTO((struct hblk * h));
+struct hblk * GC_push_next_marked_uncollectable(struct hblk * h);
                /* Ditto, but mark only from uncollectable pages.       */
-GC_bool GC_stopped_mark GC_PROTO((GC_stop_func stop_func));
+GC_bool GC_stopped_mark(GC_stop_func stop_func);
                        /* Stop world and mark from all roots   */
                        /* and rescuers.                        */
-void GC_clear_hdr_marks GC_PROTO((hdr * hhdr));
+void GC_clear_hdr_marks(hdr * hhdr);
                                    /* Clear the mark bits in a header */
-void GC_set_hdr_marks GC_PROTO((hdr * hhdr));
+void GC_set_hdr_marks(hdr * hhdr);
                                    /* Set the mark bits in a header */
-void GC_set_fl_marks GC_PROTO((ptr_t p));
+void GC_set_fl_marks(ptr_t p);
                                    /* Set all mark bits associated with */
                                    /* a free list.                      */
-void GC_add_roots_inner GC_PROTO((char * b, char * e, GC_bool tmp));
-void GC_remove_roots_inner GC_PROTO((char * b, char * e));
-GC_bool GC_is_static_root GC_PROTO((ptr_t p));
+#ifdef GC_ASSERTIONS
+  void GC_check_fl_marks(ptr_t p);
+                                   /* Check that  all mark bits        */
+                                   /* associated with a free list are  */
+                                   /* set.  Abort if not.              */
+#endif
+void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp);
+void GC_remove_roots_inner(ptr_t b, ptr_t e);
+GC_bool GC_is_static_root(ptr_t p);
                /* Is the address p in one of the registered static     */
                /* root sections?                                       */
 # if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
-GC_bool GC_is_tmp_root GC_PROTO((ptr_t p));
+GC_bool GC_is_tmp_root(ptr_t p);
                /* Is the address p in one of the temporary static      */
                /* root sections?                                       */
 # endif
-void GC_register_dynamic_libraries GC_PROTO((void));
+void GC_register_dynamic_libraries(void);
                /* Add dynamic library data sections to the root set. */
+void GC_cond_register_dynamic_libraries(void);
+               /* Remove and reregister dynamic libraries if we're     */
+               /* configured to do that at each GC.                    */
 
-GC_bool GC_register_main_static_data GC_PROTO((void));
+GC_bool GC_register_main_static_data(void);
                /* We need to register the main data segment.  Returns  */
                /* TRUE unless this is done implicitly as part of       */
                /* dynamic library registration.                        */
   
 /* Machine dependent startup routines */
-ptr_t GC_get_stack_base GC_PROTO((void));      /* Cold end of stack */
+ptr_t GC_get_main_stack_base(void);    /* Cold end of stack */
 #ifdef IA64
-  ptr_t GC_get_register_stack_base GC_PROTO((void));
+  ptr_t GC_get_register_stack_base(void);
                                        /* Cold end of register stack.  */
 #endif
-void GC_register_data_segments GC_PROTO((void));
+void GC_register_data_segments(void);
   
 /* Black listing: */
-void GC_bl_init GC_PROTO((void));
+void GC_bl_init(void);
 # ifdef PRINT_BLACK_LIST
-      void GC_add_to_black_list_normal GC_PROTO((word p, ptr_t source));
+      void GC_add_to_black_list_normal(word p, ptr_t source);
                        /* Register bits as a possible future false     */
                        /* reference from the heap or static data       */
 #     define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
                if (GC_all_interior_pointers) { \
-                 GC_add_to_black_list_stack(bits, (ptr_t)(source)); \
+                 GC_add_to_black_list_stack((word)(bits), (source)); \
                } else { \
-                 GC_add_to_black_list_normal(bits, (ptr_t)(source)); \
+                 GC_add_to_black_list_normal((word)(bits), (source)); \
                }
 # else
-      void GC_add_to_black_list_normal GC_PROTO((word p));
+      void GC_add_to_black_list_normal(word p);
 #     define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
                if (GC_all_interior_pointers) { \
-                 GC_add_to_black_list_stack(bits); \
+                 GC_add_to_black_list_stack((word)(bits)); \
                } else { \
-                 GC_add_to_black_list_normal(bits); \
+                 GC_add_to_black_list_normal((word)(bits)); \
                }
 # endif
 
 # ifdef PRINT_BLACK_LIST
-    void GC_add_to_black_list_stack GC_PROTO((word p, ptr_t source));
+    void GC_add_to_black_list_stack(word p, ptr_t source);
+#   define GC_ADD_TO_BLACK_LIST_STACK(bits, source) \
+           GC_add_to_black_list_stack((word)(bits), (source))
 # else
-    void GC_add_to_black_list_stack GC_PROTO((word p));
+    void GC_add_to_black_list_stack(word p);
+#   define GC_ADD_TO_BLACK_LIST_STACK(bits, source) \
+           GC_add_to_black_list_stack((word)(bits))
 # endif
-struct hblk * GC_is_black_listed GC_PROTO((struct hblk * h, word len));
+struct hblk * GC_is_black_listed(struct hblk * h, word len);
                        /* If there are likely to be false references   */
                        /* to a block starting at h of the indicated    */
                        /* length, then return the next plausible       */
                        /* starting location for h that might avoid     */
                        /* these false references.                      */
-void GC_promote_black_lists GC_PROTO((void));
+void GC_promote_black_lists(void);
                        /* Declare an end to a black listing phase.     */
-void GC_unpromote_black_lists GC_PROTO((void));
+void GC_unpromote_black_lists(void);
                        /* Approximately undo the effect of the above.  */
                        /* This actually loses some information, but    */
                        /* only in a reasonably safe way.               */
-word GC_number_stack_black_listed GC_PROTO(( \
-       struct hblk *start, struct hblk *endp1));
+word GC_number_stack_black_listed(struct hblk *start, struct hblk *endp1);
                        /* Return the number of (stack) blacklisted     */
                        /* blocks in the range for statistical          */
                        /* purposes.                                    */
                        
-ptr_t GC_scratch_alloc GC_PROTO((word bytes));
+ptr_t GC_scratch_alloc(size_t bytes);
                                /* GC internal memory allocation for    */
                                /* small objects.  Deallocation is not  */
                                /* possible.                            */
        
 /* Heap block layout maps: */                  
-void GC_invalidate_map GC_PROTO((hdr * hhdr));
-                               /* Remove the object map associated     */
-                               /* with the block.  This identifies     */
-                               /* the block as invalid to the mark     */
-                               /* routines.                            */
-GC_bool GC_add_map_entry GC_PROTO((word sz));
+GC_bool GC_add_map_entry(size_t sz);
                                /* Add a heap block map for objects of  */
                                /* size sz to obj_map.                  */
                                /* Return FALSE on failure.             */
-void GC_register_displacement_inner GC_PROTO((word offset));
+void GC_register_displacement_inner(size_t offset);
                                /* Version of GC_register_displacement  */
                                /* that assumes lock is already held    */
                                /* and signals are already disabled.    */
+
+void GC_initialize_offsets(void);
+                               /* Initialize GC_valid_offsets,         */
+                               /* depending on current                 */
+                               /* GC_all_interior_pointers settings.   */
   
 /*  hblk allocation: */                
-void GC_new_hblk GC_PROTO((word size_in_words, int kind));
+void GC_new_hblk(size_t size_in_granules, int kind);
                                /* Allocate a new heap block, and build */
                                /* a free list in it.                   */                              
 
-ptr_t GC_build_fl GC_PROTO((struct hblk *h, word sz,
-                          GC_bool clear,  ptr_t list));
+ptr_t GC_build_fl(struct hblk *h, size_t words, GC_bool clear, ptr_t list);
                                /* Build a free list for objects of     */
                                /* size sz in block h.  Append list to  */
                                /* end of the free lists.  Possibly     */
@@ -1524,56 +1541,63 @@ ptr_t GC_build_fl GC_PROTO((struct hblk *h, word sz,
                                /* called by GC_new_hblk, but also      */
                                /* called explicitly without GC lock.   */
 
-struct hblk * GC_allochblk GC_PROTO(( \
-       word size_in_words, int kind, unsigned flags));
+struct hblk * GC_allochblk (size_t size_in_bytes, int kind,
+                           unsigned flags);
                                /* Allocate a heap block, inform        */
                                /* the marker that block is valid       */
                                /* for objects of indicated size.       */
 
-ptr_t GC_alloc_large GC_PROTO((word lw, int k, unsigned flags));
-                       /* Allocate a large block of size lw words.     */
+ptr_t GC_alloc_large (size_t lb, int k, unsigned flags);
+                       /* Allocate a large block of size lb bytes.     */
                        /* The block is not cleared.                    */
                        /* Flags is 0 or IGNORE_OFF_PAGE.               */
                        /* Calls GC_allchblk to do the actual           */
                        /* allocation, but also triggers GC and/or      */
                        /* heap expansion as appropriate.               */
-                       /* Does not update GC_words_allocd, but does    */
+                       /* Does not update GC_bytes_allocd, but does    */
                        /* other accounting.                            */
 
-ptr_t GC_alloc_large_and_clear GC_PROTO((word lw, int k, unsigned flags));
+ptr_t GC_alloc_large_and_clear(size_t lb, int k, unsigned flags);
                        /* As above, but clear block if appropriate     */
                        /* for kind k.                                  */
 
-void GC_freehblk GC_PROTO((struct hblk * p));
+void GC_freehblk(struct hblk * p);
                                /* Deallocate a heap block and mark it  */
                                /* as invalid.                          */
                                
 /*  Misc GC: */
-void GC_init_inner GC_PROTO((void));
-GC_bool GC_expand_hp_inner GC_PROTO((word n));
-void GC_start_reclaim GC_PROTO((int abort_if_found));
+void GC_init_inner(void);
+GC_bool GC_expand_hp_inner(word n);
+void GC_start_reclaim(int abort_if_found);
                                /* Restore unmarked objects to free     */
                                /* lists, or (if abort_if_found is      */
                                /* TRUE) report them.                   */
                                /* Sweeping of small object pages is    */
                                /* largely deferred.                    */
-void GC_continue_reclaim GC_PROTO((word sz, int kind));
+void GC_continue_reclaim(size_t sz, int kind);
                                /* Sweep pages of the given size and    */
                                /* kind, as long as possible, and       */
                                /* as long as the corr. free list is    */
-                               /* empty.                               */
-void GC_reclaim_or_delete_all GC_PROTO((void));
+                               /* empty.  Sz is in granules.           */
+void GC_reclaim_or_delete_all(void);
                                /* Arrange for all reclaim lists to be  */
                                /* empty.  Judiciously choose between   */
                                /* sweeping and discarding each page.   */
-GC_bool GC_reclaim_all GC_PROTO((GC_stop_func stop_func, GC_bool ignore_old));
+GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old);
                                /* Reclaim all blocks.  Abort (in a     */
                                /* consistent state) if f returns TRUE. */
-GC_bool GC_block_empty GC_PROTO((hdr * hhdr));
+ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
+                        GC_bool init, ptr_t list, signed_word *count);
+                               /* Rebuild free list in hbp with        */
+                               /* header hhdr, with objects of size sz */
+                               /* bytes.  Add list to the end of the   */
+                               /* free list.  Add the number of        */
+                               /* reclaimed bytes to *count.           */
+GC_bool GC_block_empty(hdr * hhdr);
                                /* Block completely unmarked?   */
-GC_bool GC_never_stop_func GC_PROTO((void));
+GC_bool GC_never_stop_func(void);
                                /* Returns FALSE.               */
-GC_bool GC_try_to_collect_inner GC_PROTO((GC_stop_func f));
+GC_bool GC_try_to_collect_inner(GC_stop_func f);
 
                                /* Collect; caller must have acquired   */
                                /* lock and disabled signals.           */
@@ -1582,11 +1606,10 @@ GC_bool GC_try_to_collect_inner GC_PROTO((GC_stop_func f));
                                /* successfully.                        */
 # define GC_gcollect_inner() \
        (void) GC_try_to_collect_inner(GC_never_stop_func)
-void GC_finish_collection GC_PROTO((void));
+void GC_finish_collection(void);
                                /* Finish collection.  Mark bits are    */
                                /* consistent and lock is still held.   */
-GC_bool GC_collect_or_expand GC_PROTO(( \
-       word needed_blocks, GC_bool ignore_off_page));
+GC_bool GC_collect_or_expand(word needed_blocks, GC_bool ignore_off_page);
                                /* Collect or expand heap in an attempt */
                                /* make the indicated number of free    */
                                /* blocks available.  Should be called  */
@@ -1596,17 +1619,17 @@ GC_bool GC_collect_or_expand GC_PROTO(( \
 extern GC_bool GC_is_initialized;      /* GC_init() has been run.      */
 
 #if defined(MSWIN32) || defined(MSWINCE)
-  void GC_deinit GC_PROTO((void));
+  void GC_deinit(void);
                                 /* Free any resources allocated by      */
                                 /* GC_init                              */
 #endif
 
-void GC_collect_a_little_inner GC_PROTO((int n));
+void GC_collect_a_little_inner(int n);
                                /* Do n units worth of garbage          */
                                /* collection work, if appropriate.     */
                                /* A unit is an amount appropriate for  */
                                /* HBLKSIZE bytes of allocation.        */
-/* ptr_t GC_generic_malloc GC_PROTO((word lb, int k)); */
+/* void * GC_generic_malloc(size_t lb, int k); */
                                /* Allocate an object of the given      */
                                /* kind.  By default, there are only    */
                                /* a few kinds: composite(pointerfree), */
@@ -1617,99 +1640,116 @@ void GC_collect_a_little_inner GC_PROTO((int n));
                                /* communicate object layout info       */
                                /* to the collector.                    */
                                /* The actual decl is in gc_mark.h.     */
-ptr_t GC_generic_malloc_ignore_off_page GC_PROTO((size_t b, int k));
+void * GC_generic_malloc_ignore_off_page(size_t b, int k);
                                /* As above, but pointers past the      */
                                /* first page of the resulting object   */
                                /* are ignored.                         */
-ptr_t GC_generic_malloc_inner GC_PROTO((word lb, int k));
+void * GC_generic_malloc_inner(size_t lb, int k);
                                /* Ditto, but I already hold lock, etc. */
-ptr_t GC_generic_malloc_words_small_inner GC_PROTO((word lw, int k));
-                               /* Analogous to the above, but assumes  */
-                               /* a small object size, and bypasses    */
-                               /* MERGE_SIZES mechanism.               */
-ptr_t GC_generic_malloc_words_small GC_PROTO((size_t lw, int k));
-                               /* As above, but size in units of words */
-                               /* Bypasses MERGE_SIZES.  Assumes       */
-                               /* words <= MAXOBJSZ.                   */
-ptr_t GC_generic_malloc_inner_ignore_off_page GC_PROTO((size_t lb, int k));
+void * GC_generic_malloc_inner_ignore_off_page(size_t lb, int k);
                                /* Allocate an object, where            */
                                /* the client guarantees that there     */
                                /* will always be a pointer to the      */
                                /* beginning of the object while the    */
                                /* object is live.                      */
-ptr_t GC_allocobj GC_PROTO((word sz, int kind));
+void GC_generic_malloc_many(size_t lb, int k, void **result);
+                               /* Store a pointer to a list of newly   */
+                               /* allocated objects of kind k and size */
+                               /* lb in *result.                       */
+                               /* Caler must make sure that *result is */
+                               /* traced even if objects are ptrfree.  */
+ptr_t GC_allocobj(size_t sz, int kind);
                                /* Make the indicated                   */
                                /* free list nonempty, and return its   */
-                               /* head.                                */
+                               /* head.  Sz is in granules.            */
 
-void GC_free_inner(GC_PTR p);
+/* Allocation routines that bypass the thread local cache.     */
+/* Used internally.                                            */
+#ifdef THREAD_LOCAL_ALLOC
+  void * GC_core_malloc(size_t);
+  void * GC_core_malloc_atomic(size_t);
+# ifdef GC_GCJ_SUPPORT
+    void *GC_core_gcj_malloc(size_t, void *); 
+# endif
+#endif /* THREAD_LOCAL_ALLOC */
+
+void GC_free_inner(void * p);
+void GC_debug_free_inner(void * p);
   
-void GC_init_headers GC_PROTO((void));
-struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h));
+void GC_init_headers(void);
+struct hblkhdr * GC_install_header(struct hblk *h);
                                /* Install a header for block h.        */
                                /* Return 0 on failure, or the header   */
                                /* otherwise.                           */
-GC_bool GC_install_counts GC_PROTO((struct hblk * h, word sz));
+GC_bool GC_install_counts(struct hblk * h, size_t sz);
                                /* Set up forwarding counts for block   */
                                /* h of size sz.                        */
                                /* Return FALSE on failure.             */
-void GC_remove_header GC_PROTO((struct hblk * h));
+void GC_remove_header(struct hblk * h);
                                /* Remove the header for block h.       */
-void GC_remove_counts GC_PROTO((struct hblk * h, word sz));
+void GC_remove_counts(struct hblk * h, size_t sz);
                                /* Remove forwarding counts for h.      */
-hdr * GC_find_header GC_PROTO((ptr_t h)); /* Debugging only.           */
+hdr * GC_find_header(ptr_t h); /* Debugging only.              */
   
-void GC_finalize GC_PROTO((void));
+void GC_finalize(void);
                        /* Perform all indicated finalization actions   */
                        /* on unmarked objects.                         */
                        /* Unreachable finalizable objects are enqueued */
                        /* for processing by GC_invoke_finalizers.      */
                        /* Invoked with lock.                           */
 
-void GC_notify_or_invoke_finalizers GC_PROTO((void));
+void GC_notify_or_invoke_finalizers(void);
                        /* If GC_finalize_on_demand is not set, invoke  */
                        /* eligible finalizers. Otherwise:              */
                        /* Call *GC_finalizer_notifier if there are     */
                        /* finalizers to be run, and we haven't called  */
                        /* this procedure yet this GC cycle.            */
 
-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));
+GC_API void * GC_make_closure(GC_finalization_proc fn, void * data);
+GC_API void GC_debug_invoke_finalizer(void * obj, void * data);
                        /* Auxiliary fns to make finalization work      */
                        /* correctly with displaced pointers introduced */
                        /* by the debugging allocators.                 */
                        
-void GC_add_to_heap GC_PROTO((struct hblk *p, word bytes));
+void GC_add_to_heap(struct hblk *p, size_t bytes);
                        /* Add a HBLKSIZE aligned chunk to the heap.    */
   
-void GC_print_obj GC_PROTO((ptr_t p));
+void GC_print_obj(ptr_t p);
                        /* P points to somewhere inside an object with  */
                        /* debugging info.  Print a human readable      */
                        /* description of the object to stderr.         */
-extern void (*GC_check_heap) GC_PROTO((void));
+extern void (*GC_check_heap)(void);
                        /* Check that all objects in the heap with      */
                        /* debugging info are intact.                   */
                        /* Add any that are not to GC_smashed list.     */
-extern void (*GC_print_all_smashed) GC_PROTO((void));
+extern void (*GC_print_all_smashed) (void);
                        /* Print GC_smashed if it's not empty.          */
                        /* Clear GC_smashed list.                       */
-extern void GC_print_all_errors GC_PROTO((void));
+extern void GC_print_all_errors (void);
                        /* Print smashed and leaked objects, if any.    */
                        /* Clear the lists of such objects.             */
-extern void (*GC_print_heap_obj) GC_PROTO((ptr_t p));
+extern void (*GC_print_heap_obj) (ptr_t p);
                        /* If possible print s followed by a more       */
                        /* detailed description of the object           */
                        /* referred to by p.                            */
 #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
-  void GC_print_address_map GC_PROTO((void));
+  void GC_print_address_map (void);
                        /* Print an address map of the process.         */
 #endif
 
 extern GC_bool GC_have_errors;  /* We saw a smashed or leaked object.  */
                                /* Call error printing routine          */
                                /* occasionally.                        */
-extern GC_bool GC_print_stats; /* Produce at least some logging output */
-                               /* Set from environment variable.       */
+
+#ifndef SMALL_CONFIG
+  extern int GC_print_stats;   /* Nonzero generates basic GC log.      */
+                               /* VERBOSE generates add'l messages.    */
+#else
+# define GC_print_stats 0
+       /* Will this keep the message character strings from the executable? */
+       /* It should ...                                                     */
+#endif
+#define VERBOSE 2
 
 #ifndef NO_DEBUGGING
   extern GC_bool GC_dump_regularly;  /* Generate regular debugging dumps. */
@@ -1732,8 +1772,8 @@ extern GC_bool GC_print_back_height;
 /* Macros used for collector internal allocation.      */
 /* These assume the collector lock is held.            */
 #ifdef DBG_HDRS_ALL
-    extern GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k);
-    extern GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
+    extern void * GC_debug_generic_malloc_inner(size_t lb, int k);
+    extern void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
                                                                int k);
 #   define GC_INTERNAL_MALLOC GC_debug_generic_malloc_inner
 #   define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \
@@ -1758,50 +1798,47 @@ extern GC_bool GC_print_back_height;
 #ifdef USE_MUNMAP
   void GC_unmap_old(void);
   void GC_merge_unmapped(void);
-  void GC_unmap(ptr_t start, word bytes);
-  void GC_remap(ptr_t start, word bytes);
-  void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2);
+  void GC_unmap(ptr_t start, size_t bytes);
+  void GC_remap(ptr_t start, size_t bytes);
+  void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, size_t bytes2);
 #endif
 
 /* Virtual dirty bit implementation:           */
 /* Each implementation exports the following:  */
-void GC_read_dirty GC_PROTO((void));
+void GC_read_dirty(void);
                        /* Retrieve dirty bits. */
-GC_bool GC_page_was_dirty GC_PROTO((struct hblk *h));
+GC_bool GC_page_was_dirty(struct hblk *h);
                        /* Read retrieved dirty bits.   */
-GC_bool GC_page_was_ever_dirty GC_PROTO((struct hblk *h));
+GC_bool GC_page_was_ever_dirty(struct hblk *h);
                        /* Could the page contain valid heap pointers?  */
-void GC_is_fresh GC_PROTO((struct hblk *h, word n));
-                       /* Assert the region currently contains no      */
-                       /* valid pointers.                              */
-void GC_remove_protection GC_PROTO((struct hblk *h, word nblocks,
-                                   GC_bool pointerfree));
+void GC_remove_protection(struct hblk *h, word nblocks,
+                         GC_bool pointerfree);
                        /* h is about to be writteni or allocated.  Ensure  */
                        /* that it's not write protected by the virtual     */
                        /* dirty bit implementation.                        */
                        
-void GC_dirty_init GC_PROTO((void));
+void GC_dirty_init(void);
   
 /* Slow/general mark bit manipulation: */
-GC_API GC_bool GC_is_marked GC_PROTO((ptr_t p));
-void GC_clear_mark_bit GC_PROTO((ptr_t p));
-void GC_set_mark_bit GC_PROTO((ptr_t p));
+GC_API GC_bool GC_is_marked(ptr_t p);
+void GC_clear_mark_bit(ptr_t p);
+void GC_set_mark_bit(ptr_t p);
   
 /* Stubborn objects: */
-void GC_read_changed GC_PROTO((void)); /* Analogous to GC_read_dirty */
-GC_bool GC_page_was_changed GC_PROTO((struct hblk * h));
+void GC_read_changed(void);    /* Analogous to GC_read_dirty */
+GC_bool GC_page_was_changed(struct hblk * h);
                                /* Analogous to GC_page_was_dirty */
-void GC_clean_changing_list GC_PROTO((void));
+void GC_clean_changing_list(void);
                                /* Collect obsolete changing list entries */
-void GC_stubborn_init GC_PROTO((void));
+void GC_stubborn_init(void);
   
 /* Debugging print routines: */
-void GC_print_block_list GC_PROTO((void));
-void GC_print_hblkfreelist GC_PROTO((void));
-void GC_print_heap_sects GC_PROTO((void));
-void GC_print_static_roots GC_PROTO((void));
-void GC_print_finalization_stats GC_PROTO((void));
-void GC_dump GC_PROTO((void));
+void GC_print_block_list(void);
+void GC_print_hblkfreelist(void);
+void GC_print_heap_sects(void);
+void GC_print_static_roots(void);
+void GC_print_finalization_stats(void);
+/* void GC_dump(void); - declared in gc.h */
 
 #ifdef KEEP_BACK_PTRS
    void GC_store_back_pointer(ptr_t source, ptr_t dest);
@@ -1824,50 +1861,22 @@ void GC_dump GC_PROTO((void));
 #   endif
 # endif
 
-void GC_noop1 GC_PROTO((word));
+void GC_noop1(word);
 
 /* Logging and diagnostic output:      */
-GC_API void GC_printf GC_PROTO((GC_CONST char * format, long, long, long, long, long, long));
+GC_API void GC_printf (const char * format, ...);
                        /* A version of printf that doesn't allocate,   */
-                       /* is restricted to long arguments, and         */
-                       /* (unfortunately) doesn't use varargs for      */
-                       /* portability.  Restricted to 6 args and       */
                        /* 1K total output length.                      */
                        /* (We use sprintf.  Hopefully that doesn't     */
                        /* allocate for long arguments.)                */
-# define GC_printf0(f) GC_printf(f, 0l, 0l, 0l, 0l, 0l, 0l)
-# define GC_printf1(f,a) GC_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l)
-# define GC_printf2(f,a,b) GC_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l)
-# define GC_printf3(f,a,b,c) GC_printf(f, (long)a, (long)b, (long)c, 0l, 0l, 0l)
-# define GC_printf4(f,a,b,c,d) GC_printf(f, (long)a, (long)b, (long)c, \
-                                           (long)d, 0l, 0l)
-# define GC_printf5(f,a,b,c,d,e) GC_printf(f, (long)a, (long)b, (long)c, \
-                                             (long)d, (long)e, 0l)
-# define GC_printf6(f,a,b,c,d,e,g) GC_printf(f, (long)a, (long)b, (long)c, \
-                                               (long)d, (long)e, (long)g)
-
-GC_API void GC_err_printf GC_PROTO((GC_CONST char * format, long, long, long, long, long, long));
-# define GC_err_printf0(f) GC_err_puts(f)
-# define GC_err_printf1(f,a) GC_err_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l)
-# define GC_err_printf2(f,a,b) GC_err_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l)
-# define GC_err_printf3(f,a,b,c) GC_err_printf(f, (long)a, (long)b, (long)c, \
-                                                 0l, 0l, 0l)
-# define GC_err_printf4(f,a,b,c,d) GC_err_printf(f, (long)a, (long)b, \
-                                                   (long)c, (long)d, 0l, 0l)
-# define GC_err_printf5(f,a,b,c,d,e) GC_err_printf(f, (long)a, (long)b, \
-                                                     (long)c, (long)d, \
-                                                     (long)e, 0l)
-# define GC_err_printf6(f,a,b,c,d,e,g) GC_err_printf(f, (long)a, (long)b, \
-                                                       (long)c, (long)d, \
-                                                       (long)e, (long)g)
-                       /* Ditto, writes to stderr.                     */
-                       
-void GC_err_puts GC_PROTO((GC_CONST char *s));
+GC_API void GC_err_printf(const char * format, ...);
+GC_API void GC_log_printf(const char * format, ...);
+void GC_err_puts(const char *s);
                        /* Write s to stderr, don't buffer, don't add   */
                        /* newlines, don't ...                          */
 
 #if defined(LINUX) && !defined(SMALL_CONFIG)
-  void GC_err_write GC_PROTO((GC_CONST char *buf, size_t len));
+  void GC_err_write(const char *buf, size_t len);
                        /* Write buf to stderr, don't buffer, don't add */
                        /* newlines, don't ...                          */
 #endif
@@ -1875,7 +1884,7 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
 
 # ifdef GC_ASSERTIONS
 #      define GC_ASSERT(expr) if(!(expr)) {\
-               GC_err_printf2("Assertion failure: %s:%ld\n", \
+               GC_err_printf("Assertion failure: %s:%ld\n", \
                                __FILE__, (unsigned long)__LINE__); \
                ABORT("assertion failure"); }
 # else 
@@ -1929,7 +1938,7 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
                /* some other reason.                                   */
 # endif /* PARALLEL_MARK */
 
-# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS)
+# if defined(GC_PTHREADS)
   /* We define the thread suspension signal here, so that we can refer */
   /* to it in the dirty bit implementation, if necessary.  Ideally we  */
   /* would allocate a (real-time ?) signal using the standard mechanism.*/
@@ -1956,5 +1965,76 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
 #  endif /* !SIG_SUSPEND */
   
 # endif
+     
+/* Some macros for setjmp that works across signal handlers    */
+/* were possible, and a couple of routines to facilitate       */
+/* catching accesses to bad addresses when that's              */
+/* possible/needed.                                            */
+#ifdef UNIX_LIKE
+# include <setjmp.h>
+# if defined(SUNOS5SIGS) && !defined(FREEBSD)
+#  include <sys/siginfo.h>
+# endif
+  /* Define SETJMP and friends to be the version that restores */
+  /* the signal mask.                                          */
+# define SETJMP(env) sigsetjmp(env, 1)
+# define LONGJMP(env, val) siglongjmp(env, val)
+# define JMP_BUF sigjmp_buf
+#else
+# ifdef ECOS
+#   define SETJMP(env)  hal_setjmp(env)
+# else
+#   define SETJMP(env) setjmp(env)
+# endif
+# define LONGJMP(env, val) longjmp(env, val)
+# define JMP_BUF jmp_buf
+#endif
+
+/* Do we need the GC_find_limit machinery to find the end of a         */
+/* data segment.                                               */
+# if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)
+#   define NEED_FIND_LIMIT
+# endif
+
+# if !defined(STACKBOTTOM) && defined(HEURISTIC2)
+#   define NEED_FIND_LIMIT
+# endif
+
+# if (defined(SVR4) || defined(AUX) || defined(DGUX) \
+      || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
+#   define NEED_FIND_LIMIT
+# endif
+
+#if defined(FREEBSD) && (defined(I386) || defined(X86_64) || defined(powerpc) \
+    || defined(__powerpc__))
+#  include <machine/trap.h>
+#  if !defined(PCR)
+#    define NEED_FIND_LIMIT
+#  endif
+#endif
+
+#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \
+    && !defined(NEED_FIND_LIMIT)
+   /* Used by GC_init_netbsd_elf() in os_dep.c.        */
+#  define NEED_FIND_LIMIT
+#endif
+
+#if defined(IA64) && !defined(NEED_FIND_LIMIT)
+#  define NEED_FIND_LIMIT
+     /* May be needed for register backing store base. */
+#endif
+
+# if defined(NEED_FIND_LIMIT) || \
+     defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS)
+JMP_BUF GC_jmp_buf;
+
+/* Set up a handler for address faults which will longjmp to   */
+/* GC_jmp_buf;                                                 */
+extern void GC_setup_temporary_fault_handler(void);
+
+/* Undo the effect of GC_setup_temporary_fault_handler.                */
+extern void GC_reset_fault_handler(void);
+
+# endif /* Need to handle address faults.      */
 
 # endif /* GC_PRIVATE_H */
index 8f76f0b62be2347f15e8c144a27343459ecc93ae..532ff8c7119a34fcb7c59d18c9e6a9d2bc117d03 100644 (file)
@@ -30,6 +30,7 @@
     /* Fake ptr_t declaration, just to avoid compilation errors.       */
     /* This avoids many instances if "ifndef GC_PRIVATE_H" below.      */
     typedef struct GC_undefined_struct * ptr_t;
+#   include <stddef.h> /* For size_t etc. */
 # endif
 
 /* Machine dependent parameters.  Some tuning parameters can be found  */
@@ -56,7 +57,7 @@
 
 /* And one for FreeBSD: */
 # if (defined(__FreeBSD__) || defined(__DragonFly__) || \
-       defined(__FreeBSD_kernel__)) && !defined(FREEBSD)
+      defined(__FreeBSD_kernel__)) && !defined(FREEBSD)
 #    define FREEBSD
 # endif
 
 #    endif
 # endif
 # if defined(sun) && defined(mc68000)
-#    define M68K
-#    define SUNOS4
-#    define mach_type_known
+#    error SUNOS4 no longer supported
 # endif
 # if defined(hp9000s300)
-#    define M68K
-#    define HP
-#    define mach_type_known
+#    error M68K based HP machines no longer supported.
 # endif
 # if defined(OPENBSD) && defined(m68k)
 #    define M68K
 #      if defined(ultrix) || defined(__ultrix)
 #       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
+#       define IRIX5   /* or IRIX 6.X */
 #      endif
 #    endif /* !LINUX */
 #    if defined(__NetBSD__) && defined(__MIPSEL__)
 # endif
 # if defined(sun) && (defined(i386) || defined(__i386__))
 #    define I386
-#    define SUNOS5
+#    define SOLARIS
 #    define mach_type_known
 # endif
 # if defined(sun) && defined(__amd64)
 #    define mach_type_known
 # endif
 # if defined(ibm032)
-#   define RT
-#   define mach_type_known
+#   error IBM PC/RT no longer supported.
 # endif
 # if defined(sun) && (defined(sparc) || defined(__sparc))
 #   define SPARC
     /* Test for SunOS 5.x */
 #     include <errno.h>
-#     ifdef ECHRNG
-#       define SUNOS5
-#     else
-#      define SUNOS4
-#     endif
+#     define SOLARIS
 #   define mach_type_known
 # endif
 # if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
 #   define mach_type_known
 # endif
 # if defined(_IBMR2)
-#   define RS6000
+#   define POWERPC
+#   define AIX
 #   define mach_type_known
 # endif
 # if defined(__NetBSD__) && defined(__sparc__)
 #   define mach_type_known
 # endif
 # if defined(_AUX_SOURCE)
-#   define M68K
-#   define SYSV
-#   define mach_type_known
+#   error A/UX no longer supported
 # endif
 # if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
      || defined(hppa) || defined(__hppa__)
 #   if defined(__ppc__)  || defined(__ppc64__)
 #    define POWERPC
 #    define mach_type_known
-#   endif
-#   if defined(__i386__)
+#   elif defined(__x86_64__)
+#    define X86_64
+#    define mach_type_known
+#   elif defined(__i386__)
 #    define I386
 #    define mach_type_known
 #   endif
 #   define I386
 #   define mach_type_known
 # endif
+# if defined(FREEBSD) && defined(__x86_64__)
+#   define X86_64
+#   define mach_type_known
+# endif
 # if defined(__NetBSD__) && (defined(i386) || defined(__i386__))
 #   define I386
 #   define mach_type_known
 # if defined(FREEBSD) && defined(__sparc__)
 #    define SPARC
 #    define mach_type_known
-#endif
+# endif
 # if defined(bsdi) && (defined(i386) || defined(__i386__))
 #    define I386
 #    define BSDI
 # else
 #   if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
         || defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
-#     define I386
-#     define MSWIN32   /* or Win32s */
+#     if defined(__LP64__) || defined(_WIN64)
+#      define X86_64
+#     else
+#       define I386
+#     endif
+#     define MSWIN32   /* or Win64 */
 #     define mach_type_known
 #   endif
 #   if defined(_MSC_VER) && defined(_M_IA64)
 #   define mach_type_known
 # endif
 # if defined(__pj__)
-#   define PJ
-#   define mach_type_known
+#   error PicoJava no longer supported
+    /* The implementation had problems, and I haven't heard of users   */
+    /* in ages.  If you want it resurrected, let me know.              */
 # endif
 # if defined(__embedded__) && defined(PPC)
 #   define POWERPC
 /* Or manually define the machine type here.  A machine type is        */
 /* characterized by the architecture.  Some                            */
 /* machine types are further subdivided by OS.                         */
-/* the macros ULTRIX, RISCOS, and BSD to distinguish.                  */
-/* Note that SGI IRIX is treated identically to RISCOS.                        */
+/* Macros such as LINUX, FREEBSD, etc. distinguish them.               */
 /* SYSV on an M68K actually means A/UX.                                        */
 /* The distinction in these cases is usually the stack starting address */
 # ifndef mach_type_known
-       --> unknown machine type
+#   error "The collector has not been ported to this machine/OS combination."
 # endif
                    /* Mapping is: M68K       ==> Motorola 680X0        */
-                   /*             (SUNOS4,HP,NEXT, and SYSV (A/UX),    */
+                   /*             (NEXT, and SYSV (A/UX),              */
                    /*             MACOS and AMIGA variants)            */
                    /*             I386       ==> Intel 386             */
                    /*              (SEQUENT, OS2, SCO, LINUX, NETBSD,  */
                    /*               FREEBSD, THREE86BSD, MSWIN32,      */
-                   /*               BSDI,SUNOS5, NEXT, other variants) */
+                   /*               BSDI,SOLARIS, NEXT, other variants)        */
                     /*             NS32K      ==> Encore Multimax      */
-                   /*             MIPS       ==> R2000 through R14K    */
+                    /*             MIPS       ==> R2000 through R14K   */
                     /*                 (many variants)                 */
                     /*            VAX        ==> DEC VAX               */
                     /*                 (BSD, ULTRIX variants)          */
-                    /*            RS6000     ==> IBM RS/6000 AIX3.X    */
-                    /*            RT         ==> IBM PC/RT             */
                     /*            HP_PA      ==> HP9000/700 & /800     */
                     /*                           HP/UX, LINUX          */
                    /*             SPARC      ==> SPARC v7/v8/v9        */
-                   /*                  (SUNOS4, SUNOS5, LINUX,         */
-                   /*                   DRSNX variants)                */
+                   /*                  (SOLARIS, LINUX, DRSNX variants)        */
                    /*             ALPHA      ==> DEC Alpha             */
                    /*                  (OSF1 and LINUX variants)       */
                    /*             M88K       ==> Motorola 88XX0        */
                    /*             X86_64     ==> AMD x86-64            */
                    /*             POWERPC    ==> IBM/Apple PowerPC     */
                    /*                  (MACOS(<=9),DARWIN(incl.MACOSX),*/
-                   /*                   LINUX, NETBSD, NOSYS variants) */
+                   /*                   LINUX, NETBSD, AIX, NOSYS      */
+                   /*                   variants)                      */
                    /*                  Handles 32 and 64-bit variants. */
-                   /*                  AIX should be handled here, but */
-                   /*                  that's called an RS6000.        */
                    /*             CRIS       ==> Axis Etrax            */
                    /*             M32R       ==> Renesas M32R          */
 
  * cause failures on alpha*-*-* with ``-msmall-data or -fpic'' or mips-*-*
  * without any special options.
  *
- * ALIGN_DOUBLE of GC_malloc should return blocks aligned to twice
- * the pointer size.
- *
  * STACKBOTTOM is the cool end of the stack, which is usually the
  * highest address in the stack.
  * Under PCR or OS/2, we have other ways of finding thread stacks.
  * Each architecture may also define the style of virtual dirty bit
  * implementation to be used:
  *   MPROTECT_VDB: Write protect the heap and catch faults.
+ *   GWW_VDB: Use win32 GetWriteWatch primitive.
  *   PROC_VDB: Use the SVR4 /proc primitives to read dirty bits.
  *
+ * The first and second one may be combined, in which case a runtime
+ * selection will be made, based on GetWriteWatch availability.
+ *
  * An architecture may define DYNAMIC_LOADING if dynamic_load.c
  * defined GC_register_dynamic_libraries() for the architecture.
  *
  */
 
 /* If we are using a recent version of gcc, we can use __builtin_unwind_init()
- * to push the relevant registers onto the stack.  This generally makes
- * USE_GENERIC_PUSH_REGS the preferred approach for marking from registers.
+ * to push the relevant registers onto the stack.
  */
 # if defined(__GNUC__) && ((__GNUC__ >= 3) || \
                           (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
-                      && !defined(__INTEL_COMPILER) \
-                      && !defined(__PATHCC__)
+                      && !defined(__INTEL_COMPILER) && !defined(__PATHCC__)
 #   define HAVE_BUILTIN_UNWIND_INIT
 # endif
 
          extern char etext[];
 #        define DATASTART ((ptr_t)(etext))
 #       endif
-#       define USE_GENERIC_PUSH_REGS
 #   endif
 #   ifdef NETBSD
 #      define OS_TYPE "NETBSD"
          extern char etext[];
 #        define DATASTART ((ptr_t)(etext))
 #       endif
-#      define USE_GENERIC_PUSH_REGS
 #   endif
 #   ifdef LINUX
 #       define OS_TYPE "LINUX"
-#       define STACKBOTTOM ((ptr_t)0xf0000000)
-#       define USE_GENERIC_PUSH_REGS
-               /* We never got around to the assembly version. */
-/* #       define MPROTECT_VDB - Reported to not work  9/17/01 */
+#       define LINUX_STACKBOTTOM
+#       define MPROTECT_VDB
 #       ifdef __ELF__
 #            define DYNAMIC_LOADING
 #           include <features.h>
 #            define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
 #       endif
 #   endif
-#   ifdef SUNOS4
-#      define OS_TYPE "SUNOS4"
-       extern char etext[];
-#      define DATASTART ((ptr_t)((((word) (etext)) + 0x1ffff) & ~0x1ffff))
-#      define HEURISTIC1       /* differs      */
-#      define DYNAMIC_LOADING
-#   endif
-#   ifdef HP
-#      define OS_TYPE "HP"
-       extern char etext[];
-#       define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
-#       define STACKBOTTOM ((ptr_t) 0xffeffffc)
-                             /* empirically determined.  seems to work. */
-#      include <unistd.h>
-#      define GETPAGESIZE() sysconf(_SC_PAGE_SIZE)
-#   endif
-#   ifdef SYSV
-#      define OS_TYPE "SYSV"
-       extern etext[];
-#      define DATASTART ((ptr_t)((((word) (etext)) + 0x3fffff) \
-                                  & ~0x3fffff) \
-                                 +((word)etext & 0x1fff))
-       /* This only works for shared-text binaries with magic number 0413.
-          The other sorts of SysV binaries put the data at the end of the text,
-          in which case the default of etext would work.  Unfortunately,
-          handling both would require having the magic-number available.
-                               -- Parag
-          */
-#      define STACKBOTTOM ((ptr_t)0xFFFFFFFE)
-                       /* The stack starts at the top of memory, but   */
-                       /* 0x0 cannot be used as setjump_test complains */
-                       /* that the stack direction is incorrect.  Two  */
-                       /* bytes down from 0x0 should be safe enough.   */
-                       /*              --Parag                         */
-#      include <sys/mmu.h>
-#      define GETPAGESIZE() PAGESIZE   /* Is this still right? */
-#   endif
 #   ifdef AMIGA
 #      define OS_TYPE "AMIGA"
                /* STACKBOTTOM and DATASTART handled specially  */
 #     define DATAEND (_end)
 #   endif
 #   ifdef DARWIN
-#     ifdef __ppc64__
+#     define OS_TYPE "DARWIN"
+#     define DYNAMIC_LOADING
+#     if defined(__ppc64__)
 #       define ALIGNMENT 8
 #       define CPP_WORDSZ 64
+#       define STACKBOTTOM ((ptr_t) 0x7fff5fc00000)
+#       define CACHE_LINE_SIZE 64
+#       ifndef HBLKSIZE
+#         define HBLKSIZE 4096
+#       endif
 #     else
 #       define ALIGNMENT 4
+#       define STACKBOTTOM ((ptr_t) 0xc0000000)
 #     endif
-#     define OS_TYPE "DARWIN"
-#     define DYNAMIC_LOADING
       /* XXX: see get_end(3), get_etext() and get_end() should not be used.
-         These aren't used when dyld support is enabled (it is by default) */
+        These aren't used when dyld support is enabled (it is by default) */
 #     define DATASTART ((ptr_t) get_etext())
 #     define DATAEND   ((ptr_t) get_end())
-#     define STACKBOTTOM ((ptr_t) 0xc0000000)
 #     define USE_MMAP
 #     define USE_MMAP_ANON
-#     define USE_ASM_PUSH_REGS
-      /* This is potentially buggy. It needs more testing. See the comments in
-         os_dep.c.  It relies on threads to track writes. */
 #     ifdef GC_DARWIN_THREADS
-/* #       define MPROTECT_VDB -- diabled for now.  May work for some apps. */
+#       define MPROTECT_VDB
 #     endif
 #     include <unistd.h>
 #     define GETPAGESIZE() getpagesize()
          __asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
 #     endif
       /* There seems to be some issues with trylock hanging on darwin. This
-         should be looked into some more */
+        should be looked into some more */
 #     define NO_PTHREAD_TRYLOCK
 #   endif
 #   ifdef FREEBSD
 #     define DATASTART GC_data_start
 #     define DYNAMIC_LOADING
 #   endif
+#   ifdef AIX
+#     define OS_TYPE "AIX"
+#     undef ALIGNMENT /* in case it's defined  */
+#     ifdef IA64
+#       undef IA64
+          /* DOB: some AIX installs stupidly define IA64 in */
+          /* /usr/include/sys/systemcfg.h                  */
+#     endif
+#     ifdef __64BIT__
+#       define ALIGNMENT 8
+#       define CPP_WORDSZ 64
+#       define STACKBOTTOM ((ptr_t)0x1000000000000000)
+#     else
+#       define ALIGNMENT 4
+#       define CPP_WORDSZ 32
+#       define STACKBOTTOM ((ptr_t)((ulong)&errno))
+#     endif
+#     define USE_MMAP
+#     define USE_MMAP_ANON
+       /* From AIX linker man page:
+       _text Specifies the first location of the program.
+       _etext Specifies the first location after the program.
+       _data Specifies the first location of the data.
+       _edata Specifies the first location after the initialized data
+       _end or end Specifies the first location after all data.
+       */
+      extern int _data[], _end[];
+#     define DATASTART ((ptr_t)((ulong)_data))
+#     define DATAEND ((ptr_t)((ulong)_end))
+      extern int errno;
+#     define DYNAMIC_LOADING
+       /* For really old versions of AIX, this may have to be removed. */
+#   endif
+
 #   ifdef NOSYS
 #     define ALIGNMENT 4
 #     define OS_TYPE "NOSYS"
 #   endif
 # endif
 
-# ifdef RT
-#   define MACH_TYPE "RT"
-#   define ALIGNMENT 4
-#   define DATASTART ((ptr_t) 0x10000000)
-#   define STACKBOTTOM ((ptr_t) 0x1fffd800)
-# endif
-
 # ifdef SPARC
 #   define MACH_TYPE "SPARC"
 #   if defined(__arch64__) || defined(__sparcv9)
 #     define ALIGNMENT 4       /* Required by hardware */
 #     define CPP_WORDSZ 32
 #   endif
-#   define ALIGN_DOUBLE
-#   ifdef SUNOS5
-#      define OS_TYPE "SUNOS5"
+    /* Don't define USE_ASM_PUSH_REGS.  We do use an asm helper, but   */
+    /* not to push the registers on the mark stack.                    */
+#   ifdef SOLARIS
+#      define OS_TYPE "SOLARIS"
        extern int _etext[];
        extern int _end[];
-       extern ptr_t GC_SysVGetDataStart();
-#       define DATASTART GC_SysVGetDataStart(0x10000, _etext)
+       extern ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+#       define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext)
 #      define DATAEND (_end)
 #      if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
 #          define USE_MMAP
                /* Solaris 5.4 installation.  Weird.                      */
 #      define DYNAMIC_LOADING
 #   endif
-#   ifdef SUNOS4
-#      define OS_TYPE "SUNOS4"
-       /* [If you have a weak stomach, don't read this.]               */
-       /* We would like to use:                                        */
-/* #       define DATASTART ((ptr_t)((((word) (etext)) + 0x1fff) & ~0x1fff)) */
-       /* This fails occasionally, due to an ancient, but very         */
-       /* persistent ld bug.  etext is set 32 bytes too high.          */
-       /* We instead read the text segment size from the a.out         */
-       /* header, which happens to be mapped into our address space    */
-       /* at the start of the text segment.  The detective work here   */
-       /* was done by Robert Ehrlich, Manuel Serrano, and Bernard      */
-       /* Serpette of INRIA.                                           */
-       /* This assumes ZMAGIC, i.e. demand-loadable executables.       */
-#      define TEXTSTART 0x2000
-#       define DATASTART ((ptr_t)(*(int *)(TEXTSTART+0x4)+TEXTSTART))
-#      define MPROTECT_VDB
-#      define HEURISTIC1
-#      define DYNAMIC_LOADING
-#   endif
 #   ifdef DRSNX
 #      define OS_TYPE "DRSNX"
-       extern ptr_t GC_SysVGetDataStart();
+       extern ptr_t GC_SysVGetDataStart(size_t, ptr_t);
        extern int etext[];
-#       define DATASTART GC_SysVGetDataStart(0x10000, etext)
+#       define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)etext)
 #      define MPROTECT_VDB
 #       define STACKBOTTOM ((ptr_t) 0xdfff0000)
 #      define DYNAMIC_LOADING
       extern int _etext[];
 #     define DATAEND (_end)
 #     define SVR4
-      extern ptr_t GC_SysVGetDataStart();
+      extern ptr_t GC_SysVGetDataStart(size_t, ptr_t);
 #     ifdef __arch64__
-#      define DATASTART GC_SysVGetDataStart(0x100000, _etext)
+#      define DATASTART GC_SysVGetDataStart(0x100000, (ptr_t)_etext)
 #     else
-#       define DATASTART GC_SysVGetDataStart(0x10000, _etext)
+#       define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext)
 #     endif
 #     define LINUX_STACKBOTTOM
 #   endif
 # ifdef I386
 #   define MACH_TYPE "I386"
 #   if defined(__LP64__) || defined(_WIN64)
-#     define CPP_WORDSZ 64
-#     define ALIGNMENT 8
+#     error This should be handled as X86_64
 #   else
 #     define CPP_WORDSZ 32
 #     define ALIGNMENT 4
                        /* Borland.                                     */
                         /* Ivan Demakov: For Watcom the option is -zp4. */
 #   endif
-#   ifndef SMALL_CONFIG
-#     define ALIGN_DOUBLE /* Not strictly necessary, but may give speed   */
-                         /* improvement on Pentiums.                     */
-#   endif
-#   ifdef HAVE_BUILTIN_UNWIND_INIT
-#      define USE_GENERIC_PUSH_REGS
-#   endif
 #   ifdef SEQUENT
 #      define OS_TYPE "SEQUENT"
        extern int etext[];
       extern int etext[];
 #     define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
 #   endif
-#   ifdef SUNOS5
-#      define OS_TYPE "SUNOS5"
+#   ifdef SOLARIS
+#      define OS_TYPE "SOLARIS"
         extern int _etext[], _end[];
-       extern ptr_t GC_SysVGetDataStart();
-#       define DATASTART GC_SysVGetDataStart(0x1000, _etext)
+       extern ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+#       define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext)
 #      define DATAEND (_end)
 /*     # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7,      */
 /*      but reportedly breaks under 2.8.  It appears that the stack    */
 #   ifdef DGUX
 #      define OS_TYPE "DGUX"
        extern int _etext, _end;
-       extern ptr_t GC_SysVGetDataStart();
-#      define DATASTART GC_SysVGetDataStart(0x1000, &_etext)
+       extern ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+#      define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)(&_etext))
 #      define DATAEND (&_end)
 #      define STACK_GROWS_DOWN
 #      define HEURISTIC2
 #   endif /* DGUX */
 
 #   ifdef LINUX
-#      ifndef __GNUC__
-         /* The Intel compiler doesn't like inline assembly */
-#        define USE_GENERIC_PUSH_REGS
-#      endif
 #      define OS_TYPE "LINUX"
 #       define LINUX_STACKBOTTOM
 #      if 0
                /* os_dep.c. OS2 actually has the right                 */
                /* system call!                                         */
 #      define DATAEND  /* not needed */
-#      define USE_GENERIC_PUSH_REGS
 #   endif
 #   ifdef MSWIN32
 #      define OS_TYPE "MSWIN32"
                /* STACKBOTTOM and DATASTART are handled specially in   */
                /* os_dep.c.                                            */
-#       ifndef __WATCOMC__
+#       if !defined(__WATCOMC__)
 #        define MPROTECT_VDB
+         /* We also avoided doing this in the past with GC_WIN32_THREADS */
+         /* Hopefully that's fixed.                                      */
+#      endif
+#      if _MSC_VER >= 1300  /* .NET, i.e. > VisualStudio 6     */
+#         define GWW_VDB
 #      endif
 #       define DATAEND  /* not needed */
 #   endif
 #          define DYNAMIC_LOADING
 #      endif
        extern char etext[];
-       extern char * GC_FreeBSDGetDataStart();
-#      define DATASTART GC_FreeBSDGetDataStart(0x1000, &etext)
+       extern char * GC_FreeBSDGetDataStart(size_t, ptr_t);
+#      define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
 #   endif
 #   ifdef NETBSD
 #      define OS_TYPE "NETBSD"
 #     define OS_TYPE "HURD"
 #     define STACK_GROWS_DOWN
 #     define HEURISTIC2
-      extern int  __data_start[];
-#     define DATASTART ( (ptr_t) (__data_start))
-      extern int   _end[];
-#     define DATAEND ( (ptr_t) (_end))
+#     define SIG_SUSPEND SIGUSR1
+#     define SIG_THR_RESTART SIGUSR2
+#     define SEARCH_FOR_DATA_START
+      extern int _end[];
+#     define DATAEND ((ptr_t) (_end))
 /* #     define MPROTECT_VDB  Not quite working yet? */
 #     define DYNAMIC_LOADING
 #   endif
 #     define DARWIN_DONT_PARSE_STACK
 #     define DYNAMIC_LOADING
       /* XXX: see get_end(3), get_etext() and get_end() should not be used.
-        These aren't used when dyld support is enabled (it is by default) */
+        These aren't used when dyld support is enabled (it is by default) */
 #     define DATASTART ((ptr_t) get_etext())
 #     define DATAEND   ((ptr_t) get_end())
 #     define STACKBOTTOM ((ptr_t) 0xc0000000)
 #     define USE_MMAP
 #     define USE_MMAP_ANON
-#     define USE_ASM_PUSH_REGS
-      /* This is potentially buggy. It needs more testing. See the comments in
-        os_dep.c.  It relies on threads to track writes. */
 #     ifdef GC_DARWIN_THREADS
-/* #       define MPROTECT_VDB -- disabled for now.  May work for some apps. */
+#       define MPROTECT_VDB
 #     endif
 #     include <unistd.h>
 #     define GETPAGESIZE() getpagesize()
       /* There seems to be some issues with trylock hanging on darwin. This
-         should be looked into some more */
+        should be looked into some more */
 #      define NO_PTHREAD_TRYLOCK
 #   endif /* DARWIN */
 # endif
       extern int __data_start[];
 #     define DATASTART ((ptr_t)(__data_start))
 #     define ALIGNMENT 4
-#     define USE_GENERIC_PUSH_REGS
 #     if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2
 #        define LINUX_STACKBOTTOM
 #     else
 #        define ALIGNMENT 4
 #      endif
 #      define OS_TYPE "EWS4800"
-#      define USE_GENERIC_PUSH_REGS 1
 #   endif
 #   ifdef ULTRIX
 #      define HEURISTIC2
 #      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[];
 #       ifdef _MIPS_SZPTR
 #        define CPP_WORDSZ _MIPS_SZPTR
 #        define ALIGNMENT (_MIPS_SZPTR/8)
-#        if CPP_WORDSZ != 64
-#          define ALIGN_DOUBLE
-#        endif
 #      else
 #         define ALIGNMENT 4
-#        define ALIGN_DOUBLE
 #      endif
 #      define DYNAMIC_LOADING
 #   endif
 #     define OS_TYPE "NETBSD"
 #     define ALIGNMENT 4
 #     define HEURISTIC2
-#     define USE_GENERIC_PUSH_REGS
 #     ifdef __ELF__
         extern int etext[];
 #       define DATASTART GC_data_start
 #    define OS_TYPE "NONSTOP"
 #    define ALIGNMENT 4
 #    define DATASTART ((ptr_t) 0x08000000)
-     extern int _end[];
-#    define DATAEND (_end)
+     extern char **environ;
+#    define DATAEND ((ptr_t)(environ - 0x10))
 #    define STACKBOTTOM ((ptr_t) 0x4fffffff)
-#    define USE_GENERIC_PUSH_REGS
 #   endif
 # endif
 
-# ifdef RS6000
-#   define MACH_TYPE "RS6000"
-#   ifdef ALIGNMENT
-#     undef ALIGNMENT
-#   endif
-#   ifdef IA64
-#     undef IA64 /* DOB: some AIX installs stupidly define IA64 in /usr/include/sys/systemcfg.h */
-#   endif
-#   ifdef __64BIT__
-#     define ALIGNMENT 8
-#     define CPP_WORDSZ 64
-#     define STACKBOTTOM ((ptr_t)0x1000000000000000)
-#   else
-#     define ALIGNMENT 4
-#     define CPP_WORDSZ 32
-#     define STACKBOTTOM ((ptr_t)((ulong)&errno))
-#   endif
-#   define USE_MMAP
-#   define USE_MMAP_ANON
- /* From AIX linker man page:
- _text Specifies the first location of the program.
- _etext Specifies the first location after the program.
- _data Specifies the first location of the data.
- _edata Specifies the first location after the initialized data
- _end or end Specifies the first location after all data.
- */
-    extern int _data[], _end[];
-#   define DATASTART ((ptr_t)((ulong)_data))
-#   define DATAEND ((ptr_t)((ulong)_end))
-    extern int errno;
-#   define USE_GENERIC_PUSH_REGS
-#   define DYNAMIC_LOADING
-       /* For really old versions of AIX, this may have to be removed. */
-# endif
-
 # ifdef HP_PA
 #   define MACH_TYPE "HP_PA"
 #   ifdef __LP64__
 #   else
 #     define CPP_WORDSZ 32
 #     define ALIGNMENT 4
-#     define ALIGN_DOUBLE
 #   endif
 #   if !defined(GC_HPUX_THREADS) && !defined(GC_LINUX_THREADS)
 #     ifndef LINUX /* For now. */
 #       define MPROTECT_VDB
 #     endif
 #   else
-#     define GENERIC_COMPARE_AND_SWAP
-       /* No compare-and-swap instruction.  Use pthread mutexes        */
-       /* when we absolutely have to.                                  */
 #     ifdef PARALLEL_MARK
 #      define USE_MARK_BYTES
                /* Minimize compare-and-swap usage.             */
 #   define MACH_TYPE "ALPHA"
 #   define ALIGNMENT 8
 #   define CPP_WORDSZ 64
-#   ifndef LINUX
-#     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.                                   */
-#   endif
 #   ifdef NETBSD
 #      define OS_TYPE "NETBSD"
 #      define HEURISTIC2
 
 # ifdef IA64
 #   define MACH_TYPE "IA64"
-#   define USE_GENERIC_PUSH_REGS
-       /* We need to get preserved registers in addition to register   */
-       /* windows.   That's easiest to do with setjmp.                 */
-#   ifdef PARALLEL_MARK
-#      define USE_MARK_BYTES
-           /* Compare-and-exchange is too expensive to use for         */
-           /* setting mark bits.                                       */
-#   endif
 #   ifdef HPUX
 #      ifdef _ILP32
 #        define CPP_WORDSZ 32
-#         define ALIGN_DOUBLE
            /* Requires 8 byte alignment for malloc */
 #        define ALIGNMENT 4
 #       else
                ---> unknown ABI
 #         endif
 #        define CPP_WORDSZ 64
-#        define ALIGN_DOUBLE
            /* Requires 16 byte alignment for malloc */
 #         define ALIGNMENT 8
 #       endif
 #   endif
 #   ifdef LINUX
 #      define CPP_WORDSZ 64
-#      define ALIGN_DOUBLE
-         /* Requires 16 byte alignment for malloc */
 #      define ALIGNMENT 8
 #       define OS_TYPE "LINUX"
        /* The following works on NUE and older kernels:        */
 #       define CPP_WORDSZ 32   /* Is this possible?    */
 #     endif
 #     define ALIGNMENT 8
+#     define STRTOULL _strtoui64
 #   endif
 # endif
 
 # ifdef M88K
 #   define MACH_TYPE "M88K"
 #   define ALIGNMENT 4
-#   define ALIGN_DOUBLE
     extern int etext[];
 #   ifdef CX_UX
 #      define OS_TYPE "CX_UX"
 #   endif
 #   ifdef  DGUX
 #      define OS_TYPE "DGUX"
-       extern ptr_t GC_SysVGetDataStart();
-#       define DATASTART GC_SysVGetDataStart(0x10000, etext)
+       extern ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+#       define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)etext)
 #   endif
 #   define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */
 # endif
     /* be moved to the S390 category.                                  */
 #   define MACH_TYPE "S370"
 #   define ALIGNMENT 4 /* Required by hardware */
-#   define USE_GENERIC_PUSH_REGS
 #   ifdef UTS4
 #       define OS_TYPE "UTS4"
        extern int etext[];
        extern int _etext[];
        extern int _end[];
-       extern ptr_t GC_SysVGetDataStart();
-#       define DATASTART GC_SysVGetDataStart(0x10000, _etext)
+       extern ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+#       define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext)
 #      define DATAEND (_end)
 #      define HEURISTIC2
 #   endif
 
 # ifdef S390
 #   define MACH_TYPE "S390"
-#   define USE_GENERIC_PUSH_REGS
 #   ifndef __s390x__
-#     define ALIGNMENT 4
-#     define CPP_WORDSZ 32
+#   define ALIGNMENT 4
+#   define CPP_WORDSZ 32
 #   else
-#     define ALIGNMENT 8
-#     define CPP_WORDSZ 64
-#   endif
+#   define ALIGNMENT 8
+#   define CPP_WORDSZ 64
 #   ifndef HBLKSIZE
 #     define HBLKSIZE 4096
 #   endif
+#   endif
 #   ifdef LINUX
 #       define OS_TYPE "LINUX"
 #       define LINUX_STACKBOTTOM
 #   endif
 # 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"
            extern char etext[];
 #          define DATASTART ((ptr_t)(etext))
 #      endif
-#       define USE_GENERIC_PUSH_REGS
 #   endif
 #   ifdef LINUX
 #       define OS_TYPE "LINUX"
 #       define LINUX_STACKBOTTOM
 #       undef STACK_GRAN
 #       define STACK_GRAN 0x10000000
-#       define USE_GENERIC_PUSH_REGS
 #       ifdef __ELF__
 #            define DYNAMIC_LOADING
 #           include <features.h>
       /* __data_start is usually defined in the target linker script.  */
       extern int __data_start[];
 #     define DATASTART (ptr_t)(__data_start)
-#     define USE_GENERIC_PUSH_REGS
       /* __stack_base__ is set in newlib/libc/sys/arm/crt0.S  */
       extern void *__stack_base__;
 #     define STACKBOTTOM ((ptr_t) (__stack_base__))
 #   define OS_TYPE "LINUX"
 #   define DYNAMIC_LOADING
 #   define LINUX_STACKBOTTOM
-#   define USE_GENERIC_PUSH_REGS
 #   define SEARCH_FOR_DATA_START
       extern int _end[];
 #   define DATAEND (_end)
 #   ifdef LINUX
 #     define OS_TYPE "LINUX"
 #     define LINUX_STACKBOTTOM
-#     define USE_GENERIC_PUSH_REGS
 #     define DYNAMIC_LOADING
 #     define SEARCH_FOR_DATA_START
       extern int _end[];
 #      define OS_TYPE "NETBSD"
 #      define HEURISTIC2
 #      define DATASTART GC_data_start
-#      define USE_GENERIC_PUSH_REGS
 #      define DYNAMIC_LOADING
 #   endif
 # endif
 #     define LINUX_STACKBOTTOM
 #     undef STACK_GRAN
 #     define STACK_GRAN 0x10000000
-#     define USE_GENERIC_PUSH_REGS
 #     define DYNAMIC_LOADING
 #     define SEARCH_FOR_DATA_START
       extern int _end[];
 #     define HBLKSIZE 4096
 #   endif
 #   define CACHE_LINE_SIZE 64
-#   define USE_GENERIC_PUSH_REGS
 #   ifdef LINUX
 #      define OS_TYPE "LINUX"
 #       define LINUX_STACKBOTTOM
             extern int etext[];
 #            define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
 #       endif
-#       if defined(__GNUC__) && __GNUC >= 3
+#       if defined(__GNUC__) && __GNUC__ >= 3
 #          define PREFETCH(x) __builtin_prefetch((x), 0, 0)
 #          define PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1)
 #      endif
 #   endif
+#   ifdef DARWIN
+#     define OS_TYPE "DARWIN"
+#     define DARWIN_DONT_PARSE_STACK
+#     define DYNAMIC_LOADING
+      /* XXX: see get_end(3), get_etext() and get_end() should not be used.
+        These aren't used when dyld support is enabled (it is by default) */
+#     define DATASTART ((ptr_t) get_etext())
+#     define DATAEND   ((ptr_t) get_end())
+#     define STACKBOTTOM ((ptr_t) 0x7fff5fc00000)
+#     define USE_MMAP
+#     define USE_MMAP_ANON
+#     ifdef GC_DARWIN_THREADS
+#       define MPROTECT_VDB
+#     endif
+#     include <unistd.h>
+#     define GETPAGESIZE() getpagesize()
+      /* There seems to be some issues with trylock hanging on darwin. This
+        should be looked into some more */
+#     define NO_PTHREAD_TRYLOCK
+#   endif
 #   ifdef FREEBSD
 #      define OS_TYPE "FREEBSD"
 #      ifndef GC_FREEBSD_THREADS
 #        define HEAP_START DATAEND
 #       endif
 #   endif
+#   ifdef MSWIN32
+#      define OS_TYPE "MSWIN32"
+               /* STACKBOTTOM and DATASTART are handled specially in   */
+               /* os_dep.c.                                            */
+#       if !defined(__WATCOMC__)
+#        define MPROTECT_VDB
+         /* We also avoided doing this in the past with GC_WIN32_THREADS */
+         /* Hopefully that's fixed.                                      */
+#      endif
+#      if _MSC_VER >= 1300  /* .NET, i.e. > VisualStudio 6     */
+#         define GWW_VDB
+#      endif
+#       define DATAEND  /* not needed */
+#   endif
 # endif
 
 #if defined(LINUX) && defined(USE_MMAP)
 #   define USE_MMAP_ANON
 #endif
 
-#if defined(LINUX) && defined(REDIRECT_MALLOC)
-    /* Rld appears to allocate some memory with its own allocator, and */
-    /* some through malloc, which might be redirected.  To make this   */
-    /* work with collectable memory, we have to scan memory allocated  */
-    /* by rld's internal malloc.                                       */
-#   define USE_PROC_FOR_LIBRARIES
+#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
+    /* Nptl allocates thread stacks with mmap, which is fine.  But it  */
+    /* keeps a cache of thread stacks.  Thread stacks contain the      */
+    /* thread control blocks.  These in turn contain a pointer to      */
+    /* (sizeof (void *) from the beginning of) the dtv for thread-local        */
+    /* storage, which is calloc allocated.  If we don't scan the cached        */
+    /* thread stacks, we appear to lose the dtv.  This tends to                */
+    /* result in something that looks like a bogus dtv count, which    */
+    /* tends to result in a memset call on a block that is way too     */
+    /* large.  Sometimes we're lucky and the process just dies ...     */
+    /* There seems to be a similar issue with some other memory        */
+    /* allocated by the dynamic loader.                                        */
+    /* This can be avoided by either:                                  */
+    /* - Defining USE_PROC_FOR_LIBRARIES here.                         */
+    /*   That performs very poorly, precisely because we end up        */
+    /*   scanning cached stacks.                                       */
+    /* - Have calloc look at its callers.  That is currently what we do.*/
+    /*   In spite of the fact that it is gross and disgusting.         */
+/* #   define USE_PROC_FOR_LIBRARIES */
 #endif
-    
+
 # ifndef STACK_GROWS_UP
 #   define STACK_GROWS_DOWN
 # endif
 # endif
 
 # ifndef GETPAGESIZE
-#   if defined(SUNOS5) || defined(IRIX5)
+#   if defined(SOLARIS) || defined(IRIX5) || defined(LINUX) \
+       || defined(NETBSD) || defined(FREEBSD) || defined(HPUX)
 #      include <unistd.h>
 #   endif
 #   define GETPAGESIZE() getpagesize()
 # endif
 
-# if defined(SUNOS5) || defined(DRSNX) || defined(UTS4)
-           /* OS has SVR4 generic features.  Probably others also qualify.     */
+# if defined(SOLARIS) || defined(DRSNX) || defined(UTS4)
+           /* OS has SVR4 generic features.            */
+           /* Probably others also qualify.            */
 #   define SVR4
 # endif
 
-# if defined(SUNOS5) || defined(DRSNX)
-           /* OS has SUNOS5 style semi-undocumented interface to dynamic       */
-           /* loader.                                                          */
-#   define SUNOS5DL
-           /* OS has SUNOS5 style signal handlers.                             */
+# if defined(SOLARIS) || defined(DRSNX)
+           /* OS has SOLARIS style semi-undocumented interface */
+           /* to dynamic loader.                               */
+#   define SOLARISDL
+           /* OS has SOLARIS style signal handlers.            */
 #   define SUNOS5SIGS
 # endif
 
 
 # if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \
            || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
-           || defined(DGUX) || defined(BSD) || defined(SUNOS4) \
-           || defined(_AIX) || defined(DARWIN) || defined(OSF1)
+           || defined(DGUX) || defined(BSD) \
+           || defined(AIX) || defined(DARWIN) || defined(OSF1) \
+           || defined(HURD)
 #   define UNIX_LIKE   /* Basic Unix-like system calls work.   */
 # endif
 
 #   define PCR_VDB
 # endif
 
-# ifdef SRC_M3
-       /* Postponed for now. */
-#   undef PROC_VDB
-#   undef MPROTECT_VDB
-# endif
-
 # ifdef SMALL_CONFIG
        /* Presumably not worth the space it takes. */
 #   undef PROC_VDB
 #   undef MPROTECT_VDB  /* For now.    */
 # endif
 
-# if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB)
+# if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB) \
+    && !defined(GWW_VDB)
 #   define DEFAULT_VDB
 # endif
 
 #   define CACHE_LINE_SIZE 32  /* Wild guess   */
 # endif
 
-# if defined(LINUX) || defined(__GLIBC__)
+# if defined(LINUX) || defined(HURD) || defined(__GLIBC__)
 #   define REGISTER_LIBRARIES_EARLY
     /* We sometimes use dl_iterate_phdr, which may acquire an internal */
     /* lock.  This isn't safe after the world has stopped.  So we must */
                ((word*)x)[1] = 0;
 # endif /* CLEAR_DOUBLE */
 
-       /* Internally we use GC_SOLARIS_THREADS to test for either old or pthreads. */
-# if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS)
-#   define GC_SOLARIS_THREADS
+# if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
+     && !defined(INCLUDE_LINUX_THREAD_DESCR)
+    /* Will not work, since libc and the dynamic loader use thread     */
+    /* locals, sometimes as the only reference.                                */
+#   define INCLUDE_LINUX_THREAD_DESCR
 # endif
 
 # if defined(GC_IRIX_THREADS) && !defined(IRIX5)
 # if defined(GC_NETBSD_THREADS) && !defined(NETBSD)
        --> inconsistent configuration
 # endif
-# if defined(GC_SOLARIS_THREADS) && !defined(SUNOS5)
+# if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS)
        --> inconsistent configuration
 # endif
 # if defined(GC_HPUX_THREADS) && !defined(HPUX)
 # if defined(GC_AIX_THREADS) && !defined(_AIX)
        --> inconsistent configuration
 # endif
+# if defined(GC_GNU_THREADS) && !defined(HURD)
+       --> inconsistent configuration
+# endif
 # if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32)
        --> inconsistent configuration
 # endif
 
-# if defined(PCR) || defined(SRC_M3) || \
-               defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) || \
-               defined(GC_PTHREADS)
+# if defined(PCR) || defined(GC_WIN32_THREADS) || defined(GC_PTHREADS)
 #   define THREADS
 # endif
 
-# if defined(HP_PA) || defined(M88K) \
-             || defined(POWERPC) && !defined(DARWIN) \
-            || defined(LINT) || defined(MSWINCE) || defined(ARM32) || defined(CRIS) \
-            || (defined(I386) && defined(__LCC__))
-       /* Use setjmp based hack to mark from callee-save registers.    */
-       /* The define should move to the individual platform            */
-       /* descriptions.                                                */
-#      define USE_GENERIC_PUSH_REGS
+# if !defined(USE_MARK_BITS) && !defined(USE_MARK_BYTES)
+#   if defined(THREADS) && defined(PARALLEL_MARK)
+#     define USE_MARK_BYTES
+#   else
+#     define USE_MARK_BITS
+#   endif
 # endif
 
 # if defined(MSWINCE)
 # ifdef SAVE_CALL_CHAIN
 #   ifndef SAVE_CALL_COUNT
 #     define NFRAMES 6 /* Number of frames to save. Even for           */
-                               /* alignment reasons.                           */
+                       /* alignment reasons.                           */
 #   else
 #     define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1)
 #   endif
 #   define FIXUP_POINTER(p)
 # endif
 
+# if !defined(MARK_BIT_PER_GRANULE) && !defined(MARK_BIT_PER_OBJ)
+#   define MARK_BIT_PER_GRANULE        /* Usually faster */
+# endif
+
+/* Some static sanity tests.   */
+# if defined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ)
+#   error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ.
+# endif
+
+# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
+#   error "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd."
+# endif
+# if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
+#   error "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd."
+# endif
+
+# if defined(REDIRECT_MALLOC) && defined(THREADS) && !defined(LINUX)
+#   error "REDIRECT_MALLOC with THREADS works at most on Linux."
+# endif
+
 #ifdef GC_PRIVATE_H
        /* This relies on some type definitions from gc_priv.h, from    */
         /* where it's normally included.                               */
        /* though we should perhaps take advantage of the case in which */
        /* does.                                                        */
        struct hblk;    /* See gc_priv.h.       */
-# ifdef PCR
-           char * real_malloc();
+# if defined(PCR)
+    char * real_malloc();
 #   define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
                                          + GC_page_size-1)
-# else
-#   ifdef OS2
-             void * os2_alloc(size_t bytes);
-#     define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
+# elif defined(OS2)
+    void * os2_alloc(size_t bytes);
+#   define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
                                            + GC_page_size) \
                                            + GC_page_size-1)
-#   else
-#     if defined(NEXT) || defined(DOS4GW) || defined(NONSTOP) || \
+# elif defined(NEXT) || defined(DOS4GW) || defined(NONSTOP) || \
                 (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
-                (defined(SUNOS5) && !defined(USE_MMAP))
-#       define GET_MEM(bytes) HBLKPTR((size_t) \
-                                             calloc(1, (size_t)bytes + GC_page_size) \
-                                             + GC_page_size-1)
-#     else
-#      ifdef MSWIN32
-         extern ptr_t GC_win32_get_mem();
-#         define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
-#      else
-#        ifdef MACOS
-#          if defined(USE_TEMPORARY_MEMORY)
-                       extern Ptr GC_MacTemporaryNewPtr(size_t size,
-                                                        Boolean clearMemory);
-#               define GET_MEM(bytes) HBLKPTR( \
+                (defined(SOLARIS) && !defined(USE_MMAP))
+#   define GET_MEM(bytes) HBLKPTR((size_t) calloc(1, (size_t)bytes + GC_page_size) \
+                                                    + GC_page_size-1)
+# elif defined(MSWIN32)
+    extern ptr_t GC_win32_get_mem();
+#   define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
+# elif defined(MACOS)
+#   if defined(USE_TEMPORARY_MEMORY)
+      extern Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory);
+#     define GET_MEM(bytes) HBLKPTR( \
                            GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
                            + GC_page_size-1)
-#          else
-#                  define GET_MEM(bytes) HBLKPTR( \
+#   else
+#     define GET_MEM(bytes) HBLKPTR( \
                                NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
-#          endif
-#        else
-#          ifdef MSWINCE
-             extern ptr_t GC_wince_get_mem();
-#            define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
-#          else
-#            if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
-                       extern void *GC_amiga_get_mem(size_t size);
-#              define GET_MEM(bytes) HBLKPTR((size_t) \
+#   endif
+# elif defined(MSWINCE)
+    extern ptr_t GC_wince_get_mem();
+#   define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
+# elif defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
+    extern void *GC_amiga_get_mem(size_t size);
+#   define GET_MEM(bytes) HBLKPTR((size_t) \
                          GC_amiga_get_mem((size_t)bytes + GC_page_size) \
                          + GC_page_size-1)
-#            else
-               extern ptr_t GC_unix_get_mem();
-#               define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
-#            endif
-#          endif
-#        endif
-#      endif
-#     endif
-#   endif
+# else
+    extern ptr_t GC_unix_get_mem();
+#   define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
 # endif
 
 #endif /* GC_PRIVATE_H */
 
-#if defined(_AIX) && !defined(__GNUC__) && !defined(__STDC__)
-  /* IBMs xlc compiler doesn't appear to follow the convention of      */
-  /* defining  __STDC__ to be zero in extended mode.                   */
-#   define __STDC__ 0
-#endif
-
 # endif /* GCCONFIG_H */
diff --git a/src/mm/boehm-gc/include/private/msvc_dbg.h b/src/mm/boehm-gc/include/private/msvc_dbg.h
new file mode 100644 (file)
index 0000000..1d3030a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+  Copyright (c) 2004-2005 Andrei Polushin
+
+  Permission is hereby granted, free of charge,  to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction,  including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+#ifndef _MSVC_DBG_H
+#define _MSVC_DBG_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !MSVC_DBG_DLL
+#define MSVC_DBG_EXPORT
+#elif MSVC_DBG_BUILD
+#define MSVC_DBG_EXPORT __declspec(dllexport)
+#else
+#define MSVC_DBG_EXPORT __declspec(dllimport)
+#endif
+
+#ifndef MAX_SYM_NAME
+#define MAX_SYM_NAME 2000
+#endif
+
+typedef void*  HANDLE;
+typedef struct _CONTEXT CONTEXT;
+
+MSVC_DBG_EXPORT size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames);
+MSVC_DBG_EXPORT size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread, CONTEXT* context, size_t skip, void* frames[], size_t maxFrames);
+
+MSVC_DBG_EXPORT size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size);
+MSVC_DBG_EXPORT size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size);
+
+MSVC_DBG_EXPORT size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, size_t* offsetBytes);
+MSVC_DBG_EXPORT size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size, size_t* offsetBytes);
+
+MSVC_DBG_EXPORT size_t GetFileLineFromAddress(void* address, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes);
+MSVC_DBG_EXPORT size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes);
+
+MSVC_DBG_EXPORT size_t GetDescriptionFromAddress(void* address, const char* format, char* description, size_t size);
+MSVC_DBG_EXPORT size_t GetDescriptionFromStack(void*const frames[], size_t count, const char* format, char* description[], size_t size);
+
+/* Compatibility with <execinfo.h> */
+MSVC_DBG_EXPORT int    backtrace(void* addresses[], int count);
+MSVC_DBG_EXPORT char** backtrace_symbols(void*const addresses[], int count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif/*_MSVC_DBG_H*/
index 469021b407105e9805a5527f3b860926f5cec362..77f1ad1a90fadc4686fb55b3fdfa1f39c40b3f8e 100644 (file)
@@ -3,8 +3,7 @@
 
 # include "private/gc_priv.h"
 
-# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
-     && !defined(GC_WIN32_THREADS)
+# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
      
 #if defined(GC_DARWIN_THREADS)
 # include "private/darwin_stop_world.h"
 # include "private/pthread_stop_world.h"
 #endif
 
+#ifdef THREAD_LOCAL_ALLOC
+# include "thread_local_alloc.h"
+#endif /* THREAD_LOCAL_ALLOC */
+
 /* We use the allocation lock to protect thread-related data structures. */
 
 /* The set of all known threads.  We intercept thread creation and     */
@@ -31,7 +34,13 @@ typedef struct GC_Thread_Rep {
     
     short flags;
 #      define FINISHED 1       /* Thread has exited.   */
-#      define DETACHED 2       /* Thread is intended to be detached.   */
+#      define DETACHED 2       /* Thread is treated as detached.       */
+                               /* Thread may really be detached, or    */
+                               /* it may have have been explicitly     */
+                               /* registered, in which case we can     */
+                               /* deallocate its GC_Thread_Rep once    */
+                               /* it unregisters itself, since it      */
+                               /* may not return a GC pointer.         */
 #      define MAIN_THREAD 4    /* True for the original thread only.   */
     short thread_blocked;      /* Protected by GC lock.                */
                                /* Treated as a boolean value.  If set, */
@@ -49,42 +58,15 @@ typedef struct GC_Thread_Rep {
                                /* Used only to avoid premature         */
                                /* reclamation of any data it might     */
                                /* reference.                           */
+                               /* This is unfortunately also the       */
+                               /* reason we need to intercept join     */
+                               /* and detach.                          */
 #   ifdef THREAD_LOCAL_ALLOC
-#      if CPP_WORDSZ == 64 && defined(ALIGN_DOUBLE)
-#          define GRANULARITY 16
-#          define NFREELISTS 49
-#      else
-#          define GRANULARITY 8
-#          define NFREELISTS 65
-#      endif
-       /* The ith free list corresponds to size i*GRANULARITY */
-#      define INDEX_FROM_BYTES(n) ((ADD_SLOP(n) + GRANULARITY - 1)/GRANULARITY)
-#      define BYTES_FROM_INDEX(i) ((i) * GRANULARITY - EXTRA_BYTES)
-#      define SMALL_ENOUGH(bytes) (ADD_SLOP(bytes) <= \
-                                   (NFREELISTS-1)*GRANULARITY)
-       ptr_t ptrfree_freelists[NFREELISTS];
-       ptr_t normal_freelists[NFREELISTS];
-#      ifdef GC_GCJ_SUPPORT
-         ptr_t gcj_freelists[NFREELISTS];
-#      endif
-               /* Free lists contain either a pointer or a small count */
-               /* reflecting the number of granules allocated at that  */
-               /* size.                                                */
-               /* 0 ==> thread-local allocation in use, free list      */
-               /*       empty.                                         */
-               /* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
-               /*       too few objects of this size have been         */
-               /*       allocated by this thread.                      */
-               /* >= HBLKSIZE  => pointer to nonempty free list.       */
-               /* > DIRECT_GRANULES, < HBLKSIZE ==> transition to      */
-               /*    local alloc, equivalent to 0.                     */
-#      define DIRECT_GRANULES (HBLKSIZE/GRANULARITY)
-               /* Don't use local free lists for up to this much       */
-               /* allocation.                                          */
+        struct thread_local_freelists tlfs;
 #   endif
 } * GC_thread;
 
-# define THREAD_TABLE_SZ 128   /* Must be power of 2   */
+# define THREAD_TABLE_SZ 256   /* Must be power of 2   */
 extern volatile GC_thread GC_threads[THREAD_TABLE_SZ];
 
 extern GC_bool GC_thr_initialized;
diff --git a/src/mm/boehm-gc/include/private/solaris_threads.h b/src/mm/boehm-gc/include/private/solaris_threads.h
deleted file mode 100644 (file)
index b1f6262..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifdef GC_SOLARIS_THREADS
-
-/* The set of all known threads.  We intercept thread creation and     */
-/* joins.  We never actually create detached threads.  We allocate all */
-/* new thread stacks ourselves.  These allow us to maintain this       */
-/* data structure.                                                     */
-/* Protected by GC_thr_lock.                                           */
-/* Some of this should be declared volatile, but that's incosnsistent  */
-/* with some library routine declarations.  In particular, the                */
-/* definition of cond_t doesn't mention volatile!                      */
-  typedef struct GC_Thread_Rep {
-    struct GC_Thread_Rep * next;
-    thread_t id;
-    word flags;
-#      define FINISHED 1       /* Thread has exited.   */
-#      define DETACHED 2       /* Thread is intended to be detached.   */
-#      define CLIENT_OWNS_STACK        4
-                               /* Stack was supplied by client.        */
-#      define SUSPNDED 8       /* Currently suspended.                 */
-                              /* SUSPENDED is used insystem header.    */
-    ptr_t stack;
-    size_t stack_size;
-    cond_t join_cv;
-    void * status;
-  } * GC_thread;
-  extern GC_thread GC_new_thread(thread_t id);
-
-  extern GC_bool GC_thr_initialized;
-  extern volatile GC_thread GC_threads[];
-  extern size_t GC_min_stack_sz;
-  extern size_t GC_page_sz;
-  extern void GC_thr_init(void);
-  extern ptr_t GC_stack_alloc(size_t * stack_size);
-  extern void GC_stack_free(ptr_t stack, size_t size);
-
-# endif /* GC_SOLARIS_THREADS */
-
index d04e19f5a4b5dcd9c60f66a24d7ff7e626402250..fc2e8f9e6609802e71670b51267203756eb5a8d1 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <errno.h>
+#include "atomic_ops.h"
 
 /* Called during key creation or setspecific.          */
 /* For the GC we already hold lock.                    */
@@ -34,7 +35,7 @@
 /* value.  This invariant must be preserved at ALL times, since                */
 /* asynchronous reads are allowed.                                     */
 typedef struct thread_specific_entry {
-       unsigned long qtid;     /* quick thread id, only for cache */
+       volatile AO_t qtid;     /* quick thread id, only for cache */
        void * value;
        struct thread_specific_entry *next;
        pthread_t thread;
diff --git a/src/mm/boehm-gc/include/private/thread_local_alloc.h b/src/mm/boehm-gc/include/private/thread_local_alloc.h
new file mode 100644 (file)
index 0000000..4c2c536
--- /dev/null
@@ -0,0 +1,152 @@
+/* 
+ * Copyright (c) 2000-2005 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.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* Included indirectly from a thread-library-specific file.    */
+/* This is the interface for thread-local allocation, whose    */
+/* implementation is mostly thread-library-independent.                */
+/* Here we describe only the interface that needs to be known  */
+/* and invoked from the thread support layer;  the actual      */
+/* implementation also exports GC_malloc and friends, which    */
+/* are declared in gc.h.                                       */
+
+#include "private/gc_priv.h"
+
+#if defined(THREAD_LOCAL_ALLOC)
+
+#include "gc_inline.h"
+
+
+# if defined USE_HPUX_TLS
+#   error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
+# endif
+
+# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC) && \
+     !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) && \
+     !defined(USE_CUSTOM_SPECIFIC)
+#   if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+#     if defined(__GNUC__)  /* Fixed for versions past 2.95? */
+#       define USE_WIN32_SPECIFIC
+#     else
+#       define USE_WIN32_COMPILER_TLS
+#     endif /* !GNU */
+#   elif defined(LINUX) && !defined(ARM32) && \
+                (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >=3))
+#     define USE_COMPILER_TLS
+#   elif (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
+         defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)) || \
+        defined(GC_NETBSD_THREADS)
+#     define USE_PTHREAD_SPECIFIC
+#   elif defined(GC_HPUX_THREADS)
+#     ifdef __GNUC__
+#      define USE_PTHREAD_SPECIFIC
+         /* Empirically, as of gcc 3.3, USE_COMPILER_TLS doesn't work. */
+#     else
+#      define USE_COMPILER_TLS
+#     endif
+#   else
+#     define USE_CUSTOM_SPECIFIC  /* Use our own.      */
+#   endif
+# endif
+
+# include <stdlib.h>
+
+/* One of these should be declared as the tlfs field in the    */
+/* structure pointed to by a GC_thread.                                */
+typedef struct thread_local_freelists {
+#   ifdef THREAD_LOCAL_ALLOC
+       void * ptrfree_freelists[TINY_FREELISTS];
+       void * normal_freelists[TINY_FREELISTS];
+#      ifdef GC_GCJ_SUPPORT
+         void * gcj_freelists[TINY_FREELISTS];
+#        define ERROR_FL (void *)(-1)
+               /* Value used for gcj_freelist[-1]; allocation is       */
+               /* erroneous.                                           */
+#      endif
+               /* Free lists contain either a pointer or a small count */
+               /* reflecting the number of granules allocated at that  */
+               /* size.                                                */
+               /* 0 ==> thread-local allocation in use, free list      */
+               /*       empty.                                         */
+               /* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
+               /*       too few objects of this size have been         */
+               /*       allocated by this thread.                      */
+               /* >= HBLKSIZE  => pointer to nonempty free list.       */
+               /* > DIRECT_GRANULES, < HBLKSIZE ==> transition to      */
+               /*    local alloc, equivalent to 0.                     */
+#      define DIRECT_GRANULES (HBLKSIZE/GRANULE_BYTES)
+               /* Don't use local free lists for up to this much       */
+               /* allocation.                                          */
+
+#   endif
+} *GC_tlfs;
+
+# if defined(USE_PTHREAD_SPECIFIC)
+#   define GC_getspecific pthread_getspecific
+#   define GC_setspecific pthread_setspecific
+#   define GC_key_create pthread_key_create
+#   define GC_remove_specific(key)  /* No need for cleanup on exit. */
+    typedef pthread_key_t GC_key_t;
+# elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
+#   define GC_getspecific(x) (x)
+#   define GC_setspecific(key, v) ((key) = (v), 0)
+#   define GC_key_create(key, d) 0
+#   define GC_remove_specific(key)  /* No need for cleanup on exit. */
+    typedef void * GC_key_t;
+# elif defined(USE_WIN32_SPECIFIC)
+#   include <windows.h>
+#   define GC_getspecific TlsGetValue
+#   define GC_setspecific(key, v) !TlsSetValue(key, v)
+       /* We assume 0 == success, msft does the opposite.      */
+#   define GC_key_create(key, d)  \
+       ((d) != 0? (ABORT("Destructor unsupported by TlsAlloc"),0) \
+                : (*(key) = TlsAlloc(), 0))
+#   define GC_remove_specific(key)  /* No need for cleanup on thread exit. */
+       /* Need TlsFree on process exit/detach ? */
+    typedef DWORD GC_key_t;
+# elif defined(USE_CUSTOM_SPECIFIC)
+#   include "private/specific.h"
+# else
+#   error implement me
+# endif
+
+
+/* Each thread structure must be initialized.  */
+/* This call must be made from the new thread. */
+/* Caller holds allocation lock.               */
+void GC_init_thread_local(GC_tlfs p);
+
+/* Called when a thread is unregistered, or exits.     */
+/* We hold the allocator lock.                         */
+void GC_destroy_thread_local(GC_tlfs p);
+
+/* The thread support layer must arrange to mark thread-local  */
+/* free lists explicitly, since the link field is often        */
+/* invisible to the marker.  It knows hoe to find all threads; */
+/* we take care of an individual thread freelist structure.    */
+void GC_mark_thread_local_fls_for(GC_tlfs p);
+
+extern
+#if defined(USE_COMPILER_TLS)
+  __thread
+#elif defined(USE_WIN32_COMPILER_TLS)
+  __declspec(thread)
+#endif
+GC_key_t GC_thread_key;
+
+/* This is set up by the thread_local_alloc implementation.  But the   */
+/* thread support layer calls GC_remove_specific(GC_thread_key)                */
+/* before a thread exits.                                              */
+/* And the thread support layer makes sure that GC_thread_key is traced,*/
+/* if necessary.                                                       */
+
+#endif /* THREAD_LOCAL_ALLOC */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/AUTHORS b/src/mm/boehm-gc/libatomic_ops-1.2/AUTHORS
new file mode 100644 (file)
index 0000000..b770890
--- /dev/null
@@ -0,0 +1,4 @@
+Originally written by Hans Boehm, with some platform-dependent code
+imported from the Boehm-Demers-Weiser GC, where it was contributed
+by many others.
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/COPYING b/src/mm/boehm-gc/libatomic_ops-1.2/COPYING
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/ChangeLog b/src/mm/boehm-gc/libatomic_ops-1.2/ChangeLog
new file mode 100644 (file)
index 0000000..9ff1087
--- /dev/null
@@ -0,0 +1,162 @@
+2007-06-26 Hans Boehm <Hans.Boehm@hp.com> (really Luca Barbato)
+        * src/atomic_ops/sysdeps/gcc/powerpc.h (AO_load_acquire): Add
+       64-bit version.
+
+2007-06-13 Hans Boehm <Hans.Boehm@hp.com>
+        * src/atomic_ops.h: include stddef.h
+
+2007-06-06 Hans Boehm <Hans.Boehm@hp.com>
+       * src/atomic_ops/sysdeps/msftc/x86_64.h: New file.
+       * src/atomic_ops.h: Add test for msftc/x86_64.h.
+       * src/atomic_ops/sysdeps/msftc/x86.h: Complain for _WIN64.
+       * src/atomic_ops/sysdeps/Makefile.am: Add x86_64.h.
+       * src/atomic_ops/sysdeps/Makefile.in: Regenerate.
+       * src/atomic_ops/sysdeps/aligned_atomic_load_store.h,
+         src/atomic_ops/sysdeps/int_aligned_atomic_load_store.h,
+         src/atomic_ops/sysdeps/short_aligned_atomic_load_store.h:
+         Replace unsigned long cast with size_t.
+
+2007-05-17 Hans Boehm <Hans.Boehm@hp.com>
+       * src/atomic_ops/sysdeps/gcc/hppa.h (AO_test_and_set_full):
+       Add cast for return.
+
+2007-05-14 Hans Boehm <Hans.Boehm@hp.com>
+       doc/README.txt: Update to reflect C++0x effort.
+
+2007-05-07  Hans Boehm <Hans.Boehm@hp.com> (with help from Philipp Zambelli)
+       * src/atomic_ops/sysdeps/msftc/x86.h: Don't just assume that mfence
+       is present.
+       * src/atomic_ops/sysdeps/gcc/arm.h (AO_test_and_set_full): Correct
+       oldval type.
+
+2006-11-09 Earl Chew (Agilent)
+       * msftc/x86.h: Follow Microsoft documentation and include
+       windows.h.
+
+[1.2 release]
+
+2006-07-11 Hans Boehm <Hans.Boehm@hp.com>
+       * src/atomic_ops/sysdeps/hpc/ia64.h: Fix typos.
+       
+2006-03-28 Earl Chew (Agilent)
+       * src/atomic_ops/sysdeps/gcc/powerpc.h: Remove unused variable cr.
+       * src/atomic_ops/sysdeps/msftc/x86.h:
+       Use new intrinsics available in MSVC 2003 and MSVC 2005.
+       Use inline assembler to generate mfence and byte sized xchg
+       Use correct prototype for InterlockedCompareExchange.
+       * src/atomic_ops.h: Add test for __PPC__ .
+       * tests/run_parallel.inc: Add simple VxWorks support. 
+       * tests/test_atomic.c, tests/test_atomic_include.h: Add prototypes
+       to silence compiler warnings.
+
+2006-1-13 Hans Boehm <Hans.Boehm@hp.com>
+       *src/atomic_ops/sysdeps/gcc/powerpc.h: Beginnings of 64 bit support.
+       *src/atomic_ops/sysdeps/gcc/x86.h: Use "=q" for AO_test_and_set_full.
+
+2005-11-4 Hans Boehm <Hans.Boehm@hp.com>
+       *src/atomic_ops/sysdeps/gcc/ia64.h: Include
+       all_acquire_release_volatile.h, instead of just the pointer-sized
+       version.
+       *src/atomic_ops/sysdeps/gcc/ia64.h: Include
+       all_acquire_release_volatile.h and all_atomic_load_store.h,
+       instead of just the pointer-sized versions.
+
+[1.1 release]
+
+2005-09-27 Hans Boehm <Hans.Boehm@hp.com>
+       *src/atomic_ops.h: Define AO_CAN_EMUL_CAS for arm.
+       *src/atomic_ops/sysdeps/read_ordered.h: New file, extracted from
+       ordered_except_wr.h.
+       *src/atomic_ops/sysdeps/ordered_except_wr.h: include read_ordered.h
+       instead of duplicating it.
+       *src/atomic_ops/sysdeps/gcc/arm.h: Include read_ordered.h.
+
+2005-09-16 Hans Boehm <Hans.Boehm@hp.com>
+       *src/atomic_ops/sysdeps/gcc/arm.h: Replace the AO_test_and_set
+       definition with one that might actually work.  (Thanks to Kazu
+       Hirata and Paul Brook.)
+
+2005-08-01 Hans Boehm <Hans.Boehm@hp.com>
+       *src/atomic_ops/Makefile.am: Change function naming from "byte" to
+       "char" (again).
+
+[1.0 release]
+
+2005-03-21 Hans Boehm <Hans.Boehm@hp.com>
+       Fix various acquire_release_volatile.h files to reflect the fact
+       that both icc and gcc seem to reorder ordinary memory accesses around
+       volatile accesses early in the compilation. Modify the acquire
+       release test to catch this problem (with high probablity, and only on
+       a multiprocessor).
+
+2005-03        Hans Boehm <Hans.Boehm@hp.com>
+       Fixes for recently introduced bugs.  Update x86 and x86-64 assembly
+       syntax to deal with complaints by some recent gcc versions.
+       
+2005-02        Hans Boehm <Hans.Boehm@hp.com>
+       Added libatomic_ops_gpl library with support for mostly
+       lock-free stack and malloc().
+
+2005-01 Ian Wienand <ianw@gelato.unsw.edu.au>, Al Stone <ahs3@debian.org>,
+       Hans Boehm <Hans.Boehm@hp.com>
+       Use autoconf, automake, starting with code from Debian package.
+       Don't use libtool.
+
+2005-01        Hans Boehm <Hans.Boehm@hp.com>
+       * test_and_set_t_is_ao_t.h, test_and_set_t_is_char.h, others:
+       Change most platforms to use byte-wide test-and-set locations.
+       
+2005-01        Hans Boehm <Hans.Boehm@hp.com>
+       * ao_t_is_int.h: Add to trivially support int-wide operations
+       on platforms with int-sized pointers.
+
+2004-12        Hans Boehm <Hans.Boehm@hp.com>
+       * gcc/powerpc.h: First serious attempt to support PowerPC (with
+       help from Maged Michael and others).
+
+2004-12        Hans Boehm <Hans.Boehm@hp.com>
+       * sunc/sparc.[hS]: Added minimal supprt for the Sun SPARC compiler.
+       * atomic_ops_sysdeps.S: Add support for platforms that require
+       out-of-line assmebly code.
+
+2004-10 Hans Boehm <Hans.Boehm@hp.com>
+       More work on char, short, int sized data.  Add both
+       compare_double_and_swap_double and compare_and_swap_double.
+       Typically each platform will provide at most one of these.
+
+2004-07-02 Ranko Zivojnovic
+       Replace both instances of AO_HAVE_NOP_FULL with AO_HAVE_nop_full.
+
+2004-06 Hans Boehm <Hans.Boehm@hp.com>
+       Start to add atomic_ops primitives for different sized data.
+
+2003-12-18  Hans Boehm  <Hans.Boehm@hp.com>
+       * atomic_ops/sysdeps/acquire_release_volatile.h, atomic_ops.h:
+       Fix support for ecc on IA64.  Remove compiler_barrier workaround
+       for gcc 3.4 and later.
+
+2003-12-17  Hans Boehm  <Hans.Boehm@hp.com>
+       * atomic_ops/sysdeps/hpc/{ia64.h,hppa.h},
+       atomic_ops/sysdeps/msftc/x86.h, Makefile, Makefile.atomic_ops,
+       Makefile.atomic_ops.msft, atomic_ops.h: Add initial support
+       for atomic_ops for VC++/Windows/X86 and HP/UX with the HP
+       compiler on PA_RISC and IA64.
+
+2003-12-09  Hans Boehm  <Hans.Boehm@hp.com>
+
+       * many: Install under "atomic_ops" instead of "ao".
+       Change atomic_ops include file structure.  Auxiliary include
+       files are all under include/atomic_ops.
+       Fix (hopefully) "make dist" in atomic_ops distribution.
+       Renamed various types to end in _t, though the old versions
+       are still defined for backward compatibility.
+
+2003-12-08  Carlos O'Donell  <carlos@baldric.uwo.ca>
+
+       * ao_sysdeps/gcc/hppa.h: Define AO_CLEAR macro. Change 
+       AO_pa_clearable_loc type. Add __ldcw, and __ldcw_align
+       helper macros. AO_test_and_set_full uses helper macros.
+
+
+Started sometime after version 0.4 release.  Currently the format is
+informal.  Eventually should become more GNU-like.
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/INSTALL b/src/mm/boehm-gc/libatomic_ops-1.2/INSTALL
new file mode 100644 (file)
index 0000000..ab8c872
--- /dev/null
@@ -0,0 +1,14 @@
+The configuration and build scripts for this package were generated by
+automake/autoconf.  "configure --prefix=<install dir>; make; make install"
+in this directory should work.
+
+Note that much of the content of this library is in the header files.
+
+However two small libraries are built and installed:
+
+- libatomic_ops.a is a support library, which is not needed on some platforms.
+  This is intended to be usable, under some mild restrictions, in free or
+  proprietary code, as are all the header files.  See doc/LICENSING.txt.
+- libatomic_ops_gpl.a contains some higher level facilities.  This code is
+  currently covered by the GPL.  The contents currently correspond to
+  the headers atomic_ops_stack.h and atomic_ops_malloc.h.
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/Makefile.am b/src/mm/boehm-gc/libatomic_ops-1.2/Makefile.am
new file mode 100644 (file)
index 0000000..da64dc2
--- /dev/null
@@ -0,0 +1,3 @@
+SUBDIRS = src doc tests
+
+#distclean-local:
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/NEWS b/src/mm/boehm-gc/libatomic_ops-1.2/NEWS
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/README b/src/mm/boehm-gc/libatomic_ops-1.2/README
new file mode 100644 (file)
index 0000000..81aa8b7
--- /dev/null
@@ -0,0 +1,13 @@
+This package provides semi-portable access to hardware provided
+atomic memory operations.  These might allow you to write code:
+
+- That does more interesting things in signal handlers.
+- Makes more effective use of multiprocessors by allowing you to write
+  clever lock-free code.  Note that such code is very difficult to get
+  right, and will unavoidably be less portable than lock-based code.  It
+  ia also not always faster than lock-based code.  But it may occasionally
+  be a large performance win.
+- To experiment with new and much better thread programming paradigms, etc.
+
+For details and licensing restrictions see the files in the doc
+subdirectory.
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/autogen.sh b/src/mm/boehm-gc/libatomic_ops-1.2/autogen.sh
new file mode 100755 (executable)
index 0000000..4b78526
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+if test `uname` = 'FreeBSD'; then
+    ${CACAO_ACLOCAL} -I . -I /usr/local/share/aclocal -I /usr/local/share/aclocal19
+else
+    ${CACAO_ACLOCAL}
+fi
+${CACAO_AUTOHEADER}
+${CACAO_AUTOMAKE} --add-missing
+${CACAO_AUTOCONF}
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/configure.ac b/src/mm/boehm-gc/libatomic_ops-1.2/configure.ac
new file mode 100644 (file)
index 0000000..3d0efe7
--- /dev/null
@@ -0,0 +1,66 @@
+# Process this file with autoconf to produce a configure script.
+AC_INIT([libatomic_ops],[1.2])
+AC_CANONICAL_TARGET([])
+AC_CONFIG_SRCDIR(src/atomic_ops.c)
+AM_INIT_AUTOMAKE
+AC_PROG_RANLIB
+
+AM_CONFIG_HEADER(src/config.h)
+
+# Checks for programs.
+AC_PROG_CC
+AM_PROG_AS
+
+# Checks for functions.
+AC_FUNC_MMAP
+
+# Checks for header files.
+AC_HEADER_STDC
+# AC_CHECK_HEADERS([ ])
+
+# Determine PIC flag, adjust default CFLAGS
+need_asm=false
+PICFLAG=
+AC_MSG_CHECKING(Determining PIC compiler flag)
+if test "$GCC" = yes; then
+  AC_MSG_RESULT(-fPIC)
+  PICFLAG=-fPIC
+else
+  case "$host" in
+    *-*-hpux*)
+      AC_MSG_RESULT("+Z")
+      PICFLAG="+Z"
+      if test "$GCC" != yes; then
+        CFLAGS="$CFLAGS +O2 -mt"
+      fi
+      ;;
+    *-*-solaris*)
+      AC_MSG_RESULT(-Kpic)
+      PICFLAG=-Kpic
+      if test "$GCC" != yes; then
+        CFLAGS="$CFLAGS -O"
+        need_asm=true
+      fi
+      ;;
+    *-*-linux*)
+      AC_MSG_RESULT(-fPIC)
+      PICFLAG=-fPIC
+      # Any Linux compiler had better be gcc compatible.
+      ;;
+    *)
+      AC_MSG_RESULT("<none>")
+      ;;
+  esac
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+
+AC_SUBST(PICFLAG)
+AC_SUBST(DEFS)
+
+AM_CONDITIONAL(NEED_ASM, test x$need_asm = xtrue)
+
+AC_CONFIG_FILES([Makefile src/Makefile src/atomic_ops/Makefile src/atomic_ops/sysdeps/Makefile doc/Makefile tests/Makefile])
+AC_CONFIG_COMMANDS([default],[[]],[[PICFLAG=${PICFLAG}
+CC=${CC}
+DEFS=${DEFS}]])
+AC_OUTPUT
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/doc/COPYING b/src/mm/boehm-gc/libatomic_ops-1.2/doc/COPYING
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/doc/LICENSING.txt b/src/mm/boehm-gc/libatomic_ops-1.2/doc/LICENSING.txt
new file mode 100644 (file)
index 0000000..1ae0e93
--- /dev/null
@@ -0,0 +1,64 @@
+Our intent is to make it easy to use libatomic_ops, in
+both free and proprietary software.  Hence most code that we expect to be
+linked into a client application is covered by an MIT-style license.
+
+A few library routines are covered by the GNU General Public License.
+These are put into a separate library, libatomic_ops_gpl.a .
+
+The low-level part of the library is mostly covered by the following
+license:
+
+----------------------------------------
+
+Copyright (c) ...
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. 
+
+--------------------------------
+
+A few files in the sysdeps directory were inherited in part from the
+Boehm-Demers-Weiser conservative garbage collector, and are covered by
+its license, which is similar in spirit:
+
+--------------------------------
+
+Copyright (c) ...
+
+THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+Permission is hereby granted to use or copy this program
+for any purpose,  provided the above notices are retained on all copies.
+Permission to modify the code and to distribute modified code is granted,
+provided the above notices are retained, and a notice that the code was
+modified is included with the above copyright notice.
+
+----------------------------------
+
+A few files are covered by the GNU General Public License.  (See file
+"COPYING".) This applies only to test code, sample applications,
+and the libatomic_ops_gpl portion of the library.
+Thus libatomic_ops_gpl should generally not be linked into proprietary code.
+(This distinction was motivated by patent considerations.)
+
+It is possible that the license of the GPL pieces may be changed for
+future versions to make them more consistent with the rest of the package.
+If you submit patches, and have strong preferences about licensing, please
+express them.
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/doc/Makefile.am b/src/mm/boehm-gc/libatomic_ops-1.2/doc/Makefile.am
new file mode 100644 (file)
index 0000000..ce212d0
--- /dev/null
@@ -0,0 +1,3 @@
+# installed documentation
+#
+dist_pkgdata_DATA=COPYING LICENSING.txt README.txt COPYING README_stack.txt README_malloc.txt README_win32.txt
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/doc/README.txt b/src/mm/boehm-gc/libatomic_ops-1.2/doc/README.txt
new file mode 100644 (file)
index 0000000..fa8f07e
--- /dev/null
@@ -0,0 +1,239 @@
+Usage:
+
+0) If possible, do this on a multiprocessor, especially if you are planning
+on modifying or enhancing the package.  It will work on a uniprocessor,
+but the tests are much more likely to pass in the presence of serious problems.
+
+1) Type ./configure --prefix=<install dir>; make; make check
+in the directory containing unpacked source.  The usual GNU build machinery
+is used, except that only static, but position-independent, libraries
+are normally built.  On Windows, read README_win32.txt instead.
+
+2) Applications should include atomic_ops.h.  Nearly all operations
+are implemented by header files included from it.  It is sometimes
+necessary, and always recommended to also link against libatomic_ops.a.
+To use the almost non-blocking stack or malloc implementations,
+see the corresponding README files, and also link against libatomic_gpl.a
+before linking against libatomic_ops.a.
+
+OVERVIEW:
+Atomic_ops.h defines a large collection of operations, each one of which is
+a combination of an (optional) atomic memory operation, and a memory barrier.
+Also defines associated feature-test macros to determine whether a particular
+operation is available on the current target hardware (either directly or
+by synthesis).  This is an attempt to replace various existing files with
+similar goals, since they usually do not handle differences in memory
+barrier styles with sufficient generality.
+
+If this is included after defining AO_REQUIRE_CAS, then the package
+will make an attempt to emulate compare-and-swap in a way that (at least
+on Linux) should still be async-signal-safe.  As a result, most other
+atomic operations will then be defined using the compare-and-swap
+emulation.  This emulation is slow, since it needs to disable signals.
+And it needs to block in case of contention.  If you care about performance
+on a platform that can't directly provide compare-and-swap, there are
+probably better alternatives.  But this allows easy ports to some such
+platforms (e.g. PA_RISC).  The option is ignored if compare-and-swap
+can be implemented directly.
+
+If atomic_ops.h is included after defining AO_USE_PTHREAD_DEFS, then all
+atomic operations will be emulated with pthread locking.  This is NOT
+async-signal-safe.  And it is slow.  It is intended primarily for debugging
+of the atomic_ops package itself.
+
+Note that the implementation reflects our understanding of real processor
+behavior.  This occasionally diverges from the documented behavior.  (E.g.
+the documented X86 behavior seems to be weak enough that it is impractical
+to use.  Current real implementations appear to be much better behaved.)
+We of course are in no position to guarantee that future processors
+(even HPs) will continue to behave this way, though we hope they will.
+
+This is a work in progress.  Corrections/additions for other platforms are
+greatly appreciated.  It passes rudimentary tests on X86, Itanium, and
+Alpha.
+
+OPERATIONS:
+
+Most operations operate on values of type AO_t, which are unsigned integers
+whose size matches that of pointers on the given architecture.  Exceptions
+are:
+
+- AO_test_and_set operates on AO_TS_t, which is whatever size the hardware
+supports with good performance.  In some cases this is the length of a cache
+line.  In some cases it is a byte.  In many cases it is equivalent to AO_t.
+
+- A few operations are implemented on smaller or larger size integers.
+Such operations are indicated by the appropriate prefix:
+
+AO_char_... Operates on unsigned char values.
+AO_short_... Operates on unsigned short values.
+AO_int_... Operates on unsigned int values.
+
+(Currently a very limited selection of these is implemented.  We're
+working on it.)
+
+The defined operations are all of the form AO_[<size>_]<op><barrier>(<args>).
+
+The <op> component specifies an atomic memory operation.  It may be
+one of the following, where the corresponding argument and result types
+are also specified:
+
+void nop()
+       No atomic operation.  The barrier may still be useful.
+AO_t load(volatile AO_t * addr)
+       Atomic load of *addr.
+void store(volatile AO_t * addr, AO_t new_val)
+       Atomically store new_val to *addr.
+AO_t fetch_and_add(volatile AO_t *addr, AO_t incr)
+       Atomically add incr to *addr, and return the original value of *addr.
+AO_t fetch_and_add1(volatile AO_t *addr)
+       Equivalent to AO_fetch_and_add(addr, 1).
+AO_t fetch_and_sub1(volatile AO_t *addr)
+       Equivalent to AO_fetch_and_add(addr, (AO_t)(-1)).
+void or(volatile AO_t *addr, AO_t incr)
+       Atomically or incr into *addr.
+int compare_and_swap(volatile AO_t * addr, AO_t old_val, AO_t new_val)
+       Atomically compare *addr to old_val, and replace *addr by new_val
+       if the first comparison succeeds.  Returns nonzero if the comparison
+       succeeded and *addr was updated.
+AO_TS_VAL_t test_and_set(volatile AO_TS_t * addr)
+       Atomically read the binary value at *addr, and set it.  AO_TS_VAL_t
+       is an enumeration type which includes the two values AO_TS_SET and
+       and AO_TS_CLEAR.  An AO_TS_t location is capable of holding an
+       AO_TS_VAL_t, but may be much larger, as dictated by hardware
+       constraints.  Test_and_set logically sets the value to AO_TS_SET.
+       It may be reset to AO_TS_CLEAR with the AO_CLEAR(AO_TS_t *) macro.
+       AO_TS_t locations should be initialized to AO_TS_INITIALIZER.
+       The values of AO_TS_SET and AO_TS_CLEAR are hardware dependent.
+       (On PA-RISC, AO_TS_SET is zero!)
+
+Test_and_set is a more limited version of compare_and_swap.  Its only
+advantage is that it is more easily implementable on some hardware.  It
+should thus be used if only binary test-and-set functionality is needed.
+
+If available, we also provide compare_and_swap operations that operate
+on wider values.  Since standard data types for double width values
+may not be available, these explicitly take pairs of arguments for the
+new and/or old value.  Unfortunately, there are two common variants,
+neither of which can easily and efficiently emulate the other.
+The first performs a comparison against the entire value being replaced,
+where the second replaces a double-width replacement, but performs
+a single-width comparison:
+
+int compare_double_and_swap_double(volatile AO_double_t * addr,
+                                  AO_t old_val1, AO_t old_val2,
+                                  AO_t new_val1, AO_t new_val2);
+
+int compare_and_swap_double(volatile AO_double_t * addr,
+                           AO_t old_val1,
+                           AO_t new_val1, AO_t new_val2);
+
+where AO_double_t is a structure containing AO_val1 and AO_val2 fields,
+both of type AO_t.  For compare_and_swap_double, we compare against
+the val1 field.  AO_double_t exists only if AO_HAVE_double_t
+is defined.
+
+ORDERING CONSTRAINTS:
+
+Each operation name also includes a suffix that specifies the associated
+ordering semantics.  The ordering constraint limits reordering of this
+operation with repsect to other atomic operations and ordinary memory
+references.  The current implementation assumes that all memory references
+are to ordinary cacheable memory; the ordering guarantee is with respect
+to other threads or processes, not I/O devices.  (Whether or not this
+distinction is important is platform-dependent.)
+
+Ordering suffixes are one of the following:
+
+<none>: No memory barrier.  A plain AO_nop() really does nothing.
+_release: Earlier operations must become visible to other threads
+         before the atomic operation.
+_acquire: Later operations must become visible after this operation.
+_read: Subsequent reads must become visible after reads included in
+       the atomic operation or preceding it.  Rarely useful for clients?
+_write: Earlier writes become visible before writes during or after
+        the atomic operation.  Rarely useful for clients?
+_full: Ordered with respect to both earlier and later memops.
+_release_write: Ordered with respect to earlier writes.  This is
+               normally implemented as either a _write or _release
+               barrier.
+_dd_acquire_read: Ordered with respect to later reads that are data
+              dependent on this one.  This is needed on
+              a pointer read, which is later dereferenced to read a
+              second value, with the expectation that the second
+              read is ordered after the first one.  On most architectures,
+              this is equivalent to no barrier.  (This is very
+              hard to define precisely.  It should probably be avoided.)
+_release_read: Ordered with respect to earlier reads.  Useful for
+              implementing read locks.  Can be implemented as _release,
+              but not as _read, since _read groups the current operation
+              with the earlier ones.
+
+We assume that if a store is data-dependent on an a previous load, then
+the two are always implicitly ordered.
+
+It is possible to test whether AO_<op><barrier> is available on the
+current platform by checking whether AO_HAVE_<op>_<barrier> is defined
+as a macro.
+
+Note that we generally don't implement operations that are either
+meaningless (e.g. AO_nop_acquire, AO_nop_release) or which appear to
+have no clear use (e.g. AO_load_release, AO_store_acquire, AO_load_write,
+AO_store_read).  On some platforms (e.g. PA-RISC) many operations
+will remain undefined unless AO_REQUIRE_CAS is defined before including
+the package.
+
+When typed in the package build directory, the following command
+will print operations that are unimplemented on the platform:
+
+make test_atomic; ./test_atomic
+
+The following command generates a file "list_atomic.i" containing the
+macro expansions of all implemented operations on the platform:
+
+make list_atomic.i
+
+Future directions:
+
+It currently appears that something roughly analogous to this is very likely
+to become part of the C++0x standard.  That effort has pointed out a number
+of issues that we expect to address there.  Since some of the solutions
+really require compiler support, they may not be completely addressed here.
+
+Known issues include:
+
+We should be more precise in defining the semantics of the ordering
+constraints, and if and how we can guarantee sequential consistency.
+
+Dd_acquire_read is very hard or impossible to define in a way that cannot
+be invalidated by reasonably standard compiler transformations.
+
+There is probably no good reason to provide operations on standard
+integer types, since those may have the wrong alignment constraints.
+
+
+Example:
+
+If you want to initialize an object, and then "publish" a pointer to it
+in a global location p, such that other threads reading the new value of
+p are guaranteed to see an initialized object, it suffices to use
+AO_release_write(p, ...) to write the pointer to the object, and to
+retrieve it in other threads with AO_acquire_read(p).
+
+Platform notes:
+
+All X86: We quietly assume 486 or better.
+
+Windows:
+Currently AO_REQUIRE_CAS is not supported.
+
+Microsoft compilers:
+Define AO_ASSUME_WINDOWS98 to get access to hardware compare-and-swap
+functionality.  This relies on the InterlockedCompareExchange() function
+which was apparently not supported in Windows95.  (There may be a better
+way to get access to this.)  Currently only X86(32 bit) is supported for
+Windows.
+
+Gcc on x86:
+Define AO_USE_PENTIUM4_INSTRS to use the Pentium 4 mfence instruction.
+Currently this is appears to be of marginal benefit.
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/doc/README_malloc.txt b/src/mm/boehm-gc/libatomic_ops-1.2/doc/README_malloc.txt
new file mode 100644 (file)
index 0000000..680b3e2
--- /dev/null
@@ -0,0 +1,57 @@
+The libatomic_ops_gpl includes a simple almost-lock-free malloc implementation.
+
+This is intended as a safe way to allocate memory from a signal handler,
+or to allocate memory in the context of a library that does not know what
+thread library it will be used with.  In either case locking is impossible.
+
+Note that the operations are only guaranteed to be 1-lock-free, i.e. a
+single blocked thread will not prevent progress, but multiple blocked
+threads may.  To safely use these operations in a signal handler,
+the handler should be non-reentrant, i.e. it should not be interruptable
+by another handler using these operations.  Furthermore use outside
+of signal handlers in a multithreaded application should be protected
+by a lock, so that at most one invocation may be interrupted by a signal.
+The header will define the macro "AO_MALLOC_IS_LOCK_FREE" on platforms
+on which malloc is completely lock-free, and hence these restrictions
+do not apply.
+
+In the presence of threads, but absence of contention, the time performance
+of this package should be as good, or slightly better than, most system
+malloc implementations.  Its space performance
+is theoretically optimal (to within a constant factor), but probably
+quite poor in practice.  In particular, no attempt is made to
+coalesce free small memory blocks.  Something like Doug Lea's malloc is
+likely to use significantly less memory for complex applications.
+
+Perfomance on platforms without an efficient compare-and-swap implementation
+will be poor.
+
+This package was not designed for processor-scalability in the face of
+high allocation rates.  If all threads happen to allocate different-sized
+objects, you might get lucky.  Otherwise expect contention and false-sharing
+problems.  If this is an issue, something like Maged Michael's algorithm
+(PLDI 2004) would be technically a far better choice.  If you are concerned
+only with scalablity, and not signal-safety, you might also consider
+using Hoard instead.  We have seen a factor of 3 to 4 slowdown from the
+standard glibc malloc implementation with contention, even when the
+performance without contention was faster.  (To make the implementation
+more scalable, one would need to replicate at least the free list headers,
+so that concurrent access is possible without cache conflicts.)
+
+Unfortunately there is no portable async-signal-safe way to obtain large
+chunks of memory from the OS.  Based on reading of the source code,
+mmap-based allocation appears safe under Linux, and probably BSD variants.
+It is probably unsafe for operating systems built on Mach, such as
+Apple's Darwin.  Without use of mmap, the allocator is
+limited to a fixed size, statically preallocated heap (2MB by default),
+and will fail to allocate objects above a certain size (just under 64K
+by default).  Use of mmap to circumvent these limitations requires an
+explicit call.
+
+The entire interface to the AO_malloc package currently consists of:
+
+#include <atomic_ops_malloc.h> /* includes atomic_ops.h */
+
+void *AO_malloc(size_t sz);
+void AO_free(void *p);
+void AO_malloc_enable_mmap(void);
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/doc/README_stack.txt b/src/mm/boehm-gc/libatomic_ops-1.2/doc/README_stack.txt
new file mode 100644 (file)
index 0000000..98ff87c
--- /dev/null
@@ -0,0 +1,78 @@
+Note that the AO_stack implementation is licensed under the GPL,
+unlike the lower level routines.
+
+The header file atomic_ops_stack.h defines a linked stack abstraction.
+Stacks may be accessed by multiple concurrent threads.  The implementation
+is 1-lock-free, i.e. it will continue to make progress if at most one
+thread becomes inactive while operating on the data structure.
+
+(The implementation can be built to be N-lock-free for any given N.  But that
+seems to rarely be useful, especially since larger N involve some slowdown.)
+
+This makes it safe to access these data structures from non-reentrant
+signal handlers, provided at most one non-signal-handler thread is
+accessing the data structure at once.  This latter condition can be
+ensured by acquiring an ordinary lock around the non-hndler accesses
+to the data structure.
+
+For details see:
+
+Hans-J. Boehm, "An Almost Non-Blocking Stack", PODC 2004,
+http://portal.acm.org/citation.cfm?doid=1011767.1011774, or
+http://www.hpl.hp.com/techreports/2004/HPL-2004-105.html
+(This is not exactly the implementation described there, since the
+interface was cleaned up in the interim.  But it should perform
+very similarly.)
+
+We use a fully lock-free implementation when the underlying hardware
+makes that less expensive, i.e. when we have a double-wide compare-and-swap
+operation available.  (The fully lock-free implementation uses an AO_t-
+sized version count, and assumes it does not wrap during the time any
+given operation is active.  This seems reasonably safe on 32-bit hardware,
+and very safe on 64-bit hardware.) If a fully lock-free implementation
+is used, the macro AO_STACK_IS_LOCK_FREE will be defined.
+
+The implementation is interesting only because it allows reuse of
+existing nodes.  This is necessary, for example, to implement a memory
+allocator.
+
+Since we want to leave the precise stack node type up to the client,
+we insist only that each stack node contains a link field of type AO_t.
+When a new node is pushed on the stack, the push operation expects to be
+passed the pointer to this link field, which will then be overwritten by
+this link field.  Similarly, the pop operation returns a pointer to the
+link field of the object that previously was on the top of the stack.
+
+The cleanest way to use these routines is probably to define the stack node
+type with an initial AO_t link field, so that the conversion between the
+link-field pointer and the stack element pointer is just a compile-time
+cast.  But other possibilities exist.  (This would be cleaner in C++ with
+templates.)
+
+A stack is represented by an AO_stack_t structure.  (This is normally
+2 or 3 times the size of a pointer.)  It may be statically initialized
+by setting it to AO_STACK_INITIALIZER, or dynamically initialized to
+an empty stack with AO_stack_init.  There are only three operations for
+accessing stacks:
+
+void AO_stack_init(AO_stack_t *list);
+void AO_stack_push_release(AO_stack_t *list, AO_t *new_element);
+AO_t * AO_stack_pop_acquire(volatile AO_stack_t *list);
+
+We require that the objects pushed as list elements remain addressable
+as long as any push or pop operation are in progress.  (It is OK for an object
+to be "pop"ped off a stack and "deallocated" with a concurrent "pop" on
+the same stack still in progress, but only if "deallocation" leaves the
+object addressable.  The second "pop" may still read the object, but
+the value it reads will not matter.)
+
+We require that the headers (AO_stack objects) remain allocated and
+valid as long as any operations on them are still in-flight.
+
+We also provide macros AO_REAL_HEAD_PTR that converts an AO_stack_t
+to a pointer to the link field in the next element, and AO_REAL_NEXT_PTR
+that converts a link field to a real, dereferencable, pointer to the link field
+in the next element.  This is intended only for debugging, or to traverse
+the list after modification has ceased.  There is otherwise no guarantee that
+walking a stack using this macro will produce any kind of consistent
+picture of the data structure.
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/doc/README_win32.txt b/src/mm/boehm-gc/libatomic_ops-1.2/doc/README_win32.txt
new file mode 100644 (file)
index 0000000..0fe6f88
--- /dev/null
@@ -0,0 +1,28 @@
+Most of the atomic_ops functionality is available under Win32 with
+the Microsoft tools, but the build process currently is considerably more
+primitive than on Linux/Unix platforms.
+
+To build:
+
+1) Go to the src directory in the distribution.
+2) Make sure the Microsoft command-line tools (e.g. nmake) are available.
+3) Run "nmake -f Makefile.msft".  This should run some tests, which
+may print warnings about the types of the "Interlocked" functions.
+I haven't been able to make all versions of VC++ happy.  If you know
+how to, please send a patch.
+4) To compile applications, you will need to retain or copy the following
+pieces from the resulting src directory contents:
+       "atomic_ops.h" - Header file defining low-level primitives.  This
+                        includes files from:
+       "atomic_ops"- Subdirectory containing implementation header files.
+       "atomic_ops_stack.h" - Header file describing almost lock-free stack.
+       "atomic_ops_malloc.h" - Header file describing almost lock-free malloc.
+       "libatomic_ops_gpl.lib" - Library containing implementation of the
+                                 above two.  The atomic_ops.h implementation
+                                 is entirely in the header files in Win32.
+
+Most clients of atomic_ops.h will need to define AO_ASSUME_WINDOWS98 before
+including it.  Compare_and_swap is otherwise not available.
+
+Note that the library is covered by the GNU General Public License, while
+the top 2 of these pieces allow use in proprietary code.
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/mkinstalldirs b/src/mm/boehm-gc/libatomic_ops-1.2/mkinstalldirs
new file mode 100755 (executable)
index 0000000..259dbfc
--- /dev/null
@@ -0,0 +1,158 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+
+scriptversion=2005-06-29.22
+
+# Original author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain.
+#
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+errstatus=0
+dirmode=
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ...
+
+Create each directory DIR (with mode MODE, if specified), including all
+leading file name components.
+
+Report bugs to <bug-automake@gnu.org>."
+
+# process command line arguments
+while test $# -gt 0 ; do
+  case $1 in
+    -h | --help | --h*)         # -h for help
+      echo "$usage"
+      exit $?
+      ;;
+    -m)                         # -m PERM arg
+      shift
+      test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
+      dirmode=$1
+      shift
+      ;;
+    --version)
+      echo "$0 $scriptversion"
+      exit $?
+      ;;
+    --)                         # stop option processing
+      shift
+      break
+      ;;
+    -*)                         # unknown option
+      echo "$usage" 1>&2
+      exit 1
+      ;;
+    *)                          # first non-opt arg
+      break
+      ;;
+  esac
+done
+
+for file
+do
+  if test -d "$file"; then
+    shift
+  else
+    break
+  fi
+done
+
+case $# in
+  0) exit 0 ;;
+esac
+
+# Solaris 8's mkdir -p isn't thread-safe.  If you mkdir -p a/b and
+# mkdir -p a/c at the same time, both will detect that a is missing,
+# one will create a, then the other will try to create a and die with
+# a "File exists" error.  This is a problem when calling mkinstalldirs
+# from a parallel make.  We use --version in the probe to restrict
+# ourselves to GNU mkdir, which is thread-safe.
+case $dirmode in
+  '')
+    if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+      echo "mkdir -p -- $*"
+      exec mkdir -p -- "$@"
+    else
+      # On NextStep and OpenStep, the `mkdir' command does not
+      # recognize any option.  It will interpret all options as
+      # directories to create, and then abort because `.' already
+      # exists.
+      test -d ./-p && rmdir ./-p
+      test -d ./--version && rmdir ./--version
+    fi
+    ;;
+  *)
+    if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 &&
+       test ! -d ./--version; then
+      echo "mkdir -m $dirmode -p -- $*"
+      exec mkdir -m "$dirmode" -p -- "$@"
+    else
+      # Clean up after NextStep and OpenStep mkdir.
+      for d in ./-m ./-p ./--version "./$dirmode";
+      do
+        test -d $d && rmdir $d
+      done
+    fi
+    ;;
+esac
+
+for file
+do
+  case $file in
+    /*) pathcomp=/ ;;
+    *)  pathcomp= ;;
+  esac
+  oIFS=$IFS
+  IFS=/
+  set fnord $file
+  shift
+  IFS=$oIFS
+
+  for d
+  do
+    test "x$d" = x && continue
+
+    pathcomp=$pathcomp$d
+    case $pathcomp in
+      -*) pathcomp=./$pathcomp ;;
+    esac
+
+    if test ! -d "$pathcomp"; then
+      echo "mkdir $pathcomp"
+
+      mkdir "$pathcomp" || lasterr=$?
+
+      if test ! -d "$pathcomp"; then
+       errstatus=$lasterr
+      else
+       if test ! -z "$dirmode"; then
+         echo "chmod $dirmode $pathcomp"
+         lasterr=
+         chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+         if test ! -z "$lasterr"; then
+           errstatus=$lasterr
+         fi
+       fi
+      fi
+    fi
+
+    pathcomp=$pathcomp/
+  done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/Makefile.am b/src/mm/boehm-gc/libatomic_ops-1.2/src/Makefile.am
new file mode 100644 (file)
index 0000000..7ca41ff
--- /dev/null
@@ -0,0 +1,16 @@
+SUBDIRS=atomic_ops
+
+AM_CFLAGS=@PICFLAG@
+
+include_HEADERS=atomic_ops.h atomic_ops_stack.h atomic_ops_malloc.h
+lib_LIBRARIES = libatomic_ops.a libatomic_ops_gpl.a
+if NEED_ASM
+libatomic_ops_a_SOURCES = atomic_ops.c atomic_ops_sysdeps.S
+else
+libatomic_ops_a_SOURCES = atomic_ops.c
+endif
+
+libatomic_ops_gpl_a_SOURCES = atomic_ops_stack.c atomic_ops_malloc.c
+
+EXTRA_DIST=Makefile.msft
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/Makefile.msft b/src/mm/boehm-gc/libatomic_ops-1.2/src/Makefile.msft
new file mode 100644 (file)
index 0000000..5b93d27
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2003-2005 Hewlett-Packard Developlment Company, L.P.
+# 
+# The really trivial win32/VC++ Makefile.  Note that atomic_ops.c isn't useful.
+# And we rely on a pre-built test_atomic_include.h and generalize-small.h,
+# since we can't rely on sed.
+# Win32 clients only need to include the header files.
+# To install, copy atomic_ops.h and the atomic_ops/... tree to your favorite
+# include directory.
+
+#MY_CPU=X86
+#CPU=$(MY_CPU)
+#!include <ntwin32.mak>
+
+LIB_OBJS=atomic_ops_stack.obj atomic_ops_malloc.obj
+
+all: check
+
+atomic_ops_stack.obj:
+       cl -O2 -c -DAO_ASSUME_WINDOWS98 atomic_ops_stack.c
+
+atomic_ops_malloc.obj:
+       cl -O2 -c -DAO_ASSUME_WINDOWS98 atomic_ops_malloc.c
+
+test_atomic: ..\tests\test_atomic.c ..\tests\test_atomic_include.h
+       cl -O2 -I. -DAO_ASSUME_WINDOWS98 ..\tests\test_atomic.c -o test_atomic
+
+test_atomic_w95: ..\tests\test_atomic.c ..\tests\test_atomic_include.h
+       cl -O2 -I. ..\tests\test_atomic.c -o test_atomic_w95
+
+test_malloc: ..\tests\test_malloc.c ..\tests\test_atomic_include.h \
+            libatomic_ops_gpl.lib 
+       cl -O2 -DAO_ASSUME_WINDOWS98 -I. ..\tests\test_malloc.c -o test_malloc libatomic_ops_gpl.lib
+
+libatomic_ops_gpl.lib: $(LIB_OBJS)
+       lib /MACHINE:i386 /out:libatomic_ops_gpl.lib $(LIB_OBJS)
+
+check:  test_atomic test_atomic_w95 test_malloc
+       echo The following will print lots of \"Missing ...\" messages.
+       test_atomic_w95
+       echo The following will print some \"Missing ...\" messages.
+       test_atomic
+       test_malloc
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops.c b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops.c
new file mode 100644 (file)
index 0000000..f01b8d2
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * Initialized data and out-of-line functions to support atomic_ops.h
+ * go here.  Currently this is needed only for pthread-based atomics
+ * emulation, or for compare-and-swap emulation.
+ * Pthreads emulation isn't useful on a native Windows platform, and
+ * cas emulation is not needed.  Thus we skip this on Windows.
+ */
+
+#if defined(HAVE_CONFIG_H)
+# include "config.h"
+#endif
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__BORLANDC__)
+
+#undef AO_REQUIRE_CAS
+
+#include <pthread.h>
+#include <signal.h>
+#ifdef _HPUX_SOURCE
+# include <sys/time.h>
+#else
+# include <sys/select.h>
+#endif
+#include "atomic_ops.h"  /* Without cas emulation! */
+
+#ifndef AO_HAVE_double_t
+# include "atomic_ops/sysdeps/standard_ao_double_t.h"
+#endif
+
+/*
+ * Lock for pthreads-based implementation.
+ */
+
+pthread_mutex_t AO_pt_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Out of line compare-and-swap emulation based on test and set.
+ * 
+ * We use a small table of locks for different compare_and_swap locations.
+ * Before we update perform a compare-and-swap, we grap the corresponding
+ * lock.  Different locations may hash to the same lock, but since we
+ * never acquire more than one lock at a time, this can't deadlock.
+ * We explicitly disable signals while we perform this operation.
+ *
+ * FIXME: We should probably also suppport emulation based on Lamport
+ * locks, since we may not have test_and_set either.
+ */
+#define AO_HASH_SIZE 16
+
+#define AO_HASH(x) (((unsigned long)(x) >> 12) & (AO_HASH_SIZE-1))
+
+AO_TS_t AO_locks[AO_HASH_SIZE] = {
+       AO_TS_INITIALIZER, AO_TS_INITIALIZER,
+       AO_TS_INITIALIZER, AO_TS_INITIALIZER,
+       AO_TS_INITIALIZER, AO_TS_INITIALIZER,
+       AO_TS_INITIALIZER, AO_TS_INITIALIZER,
+       AO_TS_INITIALIZER, AO_TS_INITIALIZER,
+       AO_TS_INITIALIZER, AO_TS_INITIALIZER,
+       AO_TS_INITIALIZER, AO_TS_INITIALIZER,
+       AO_TS_INITIALIZER, AO_TS_INITIALIZER,
+};
+
+static AO_T dummy = 1;
+
+/* Spin for 2**n units. */
+void AO_spin(int n)
+{
+  int i;
+  AO_T j = AO_load(&dummy);
+
+  for (i = 0; i < (2 << n); ++i)
+    {
+       j *= 5;
+       j -= 4;
+    }
+  AO_store(&dummy, j);
+}
+
+void AO_pause(int n)
+{
+    if (n < 12)
+      AO_spin(n);
+    else
+      {
+        struct timeval tv;
+
+       /* Short async-signal-safe sleep. */
+       tv.tv_sec = 0;
+       tv.tv_usec = (n > 28? 100000 : (1 << (n - 12)));
+       select(0, 0, 0, 0, &tv);
+      }
+}
+
+static void lock_ool(volatile AO_TS_t *l)
+{
+  int i = 0;
+
+  while (AO_test_and_set_acquire(l) == AO_TS_SET)
+    AO_pause(++i);
+}
+
+AO_INLINE void lock(volatile AO_TS_t *l)
+{
+  if (AO_test_and_set_acquire(l) == AO_TS_SET)
+    lock_ool(l);
+}
+
+AO_INLINE void unlock(volatile AO_TS_t *l)
+{
+  AO_CLEAR(l);
+}
+
+static sigset_t all_sigs;
+
+static volatile AO_t initialized = 0;
+
+static volatile AO_TS_t init_lock = AO_TS_INITIALIZER;
+
+int AO_compare_and_swap_emulation(volatile AO_t *addr, AO_t old,
+                                 AO_t new_val)
+{
+  AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
+  sigset_t old_sigs;
+  int result;
+
+  if (!AO_load_acquire(&initialized))
+    {
+      lock(&init_lock);
+      if (!initialized) sigfillset(&all_sigs);
+      unlock(&init_lock);
+      AO_store_release(&initialized, 1);
+    }
+  sigprocmask(SIG_BLOCK, &all_sigs, &old_sigs);
+       /* Neither sigprocmask nor pthread_sigmask is 100%      */
+       /* guaranteed to work here.  Sigprocmask is not         */
+       /* guaranteed be thread safe, and pthread_sigmask       */
+       /* is not async-signal-safe.  Under linuxthreads,       */
+       /* sigprocmask may block some pthreads-internal         */
+       /* signals.  So long as we do that for short periods,   */
+       /* we should be OK.                                     */
+  lock(my_lock);
+  if (*addr == old)
+    {
+      *addr = new_val;
+      result = 1;
+    }
+  else
+    result = 0;
+  unlock(my_lock);
+  sigprocmask(SIG_SETMASK, &old_sigs, NULL);
+  return result;
+}
+
+int AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,
+                                               AO_t old_val1, AO_t old_val2,
+                                               AO_t new_val1, AO_t new_val2)
+{
+  AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
+  sigset_t old_sigs;
+  int result;
+
+  if (!AO_load_acquire(&initialized))
+    {
+      lock(&init_lock);
+      if (!initialized) sigfillset(&all_sigs);
+      unlock(&init_lock);
+      AO_store_release(&initialized, 1);
+    }
+  sigprocmask(SIG_BLOCK, &all_sigs, &old_sigs);
+       /* Neither sigprocmask nor pthread_sigmask is 100%      */
+       /* guaranteed to work here.  Sigprocmask is not         */
+       /* guaranteed be thread safe, and pthread_sigmask       */
+       /* is not async-signal-safe.  Under linuxthreads,       */
+       /* sigprocmask may block some pthreads-internal         */
+       /* signals.  So long as we do that for short periods,   */
+       /* we should be OK.                                     */
+  lock(my_lock);
+  if (addr -> AO_val1 == old_val1 && addr -> AO_val2 == old_val2)
+    {
+      addr -> AO_val1 = new_val1;
+      addr -> AO_val2 = new_val2;
+      result = 1;
+    }
+  else
+    result = 0;
+  unlock(my_lock);
+  sigprocmask(SIG_SETMASK, &old_sigs, NULL);
+  return result;
+}
+
+void AO_store_full_emulation(volatile AO_t *addr, AO_t val)
+{
+  AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
+  lock(my_lock);
+  *addr = val;
+  unlock(my_lock);
+}
+
+#else /* Non-posix platform */
+
+int AO_non_posix_implementation_is_entirely_in_headers;
+
+#endif
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops.h
new file mode 100755 (executable)
index 0000000..d27ec7b
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+#ifndef ATOMIC_OPS_H
+
+#define ATOMIC_OPS_H
+
+#include <assert.h>
+#include <stddef.h>
+
+/* We define various atomic operations on memory in a          */
+/* machine-specific way.  Unfortunately, this is complicated   */
+/* by the fact that these may or may not be combined with      */
+/* various memory barriers.  Thus the actual operations we     */
+/* define have the form AO_<atomic-op>_<barrier>, for all      */
+/* plausible combinations of <atomic-op> and <barrier>.                */
+/* This of course results in a mild combinatorial explosion.   */
+/* To deal with it, we try to generate derived                 */
+/* definitions for as many of the combinations as we can, as   */
+/* automatically as possible.                                  */
+/*                                                             */
+/* Our assumption throughout is that the programmer will       */
+/* specify the least demanding operation and memory barrier    */
+/* that will guarantee correctness for the implementation.     */
+/* Our job is to find the least expensive way to implement it  */
+/* on the applicable hardware.  In many cases that will        */
+/* involve, for example, a stronger memory barrier, or a       */
+/* combination of hardware primitives.                         */
+/*                                                             */
+/* Conventions:                                                        */
+/* "plain" atomic operations are not guaranteed to include     */
+/* a barrier.  The suffix in the name specifies the barrier    */
+/* type.  Suffixes are:                                                */
+/* _release: Earlier operations may not be delayed past it.    */
+/* _acquire: Later operations may not move ahead of it.                */
+/* _read: Subsequent reads must follow this operation and      */
+/*       preceding reads.                                      */
+/* _write: Earlier writes precede both this operation and      */
+/*       later writes.                                         */
+/* _full: Ordered with respect to both earlier and later memops.*/
+/* _release_write: Ordered with respect to earlier writes.     */
+/* _acquire_read: Ordered with repsect to later reads.         */
+/*                                                             */
+/* Currently we try to define the following atomic memory      */
+/* operations, in combination with the above barriers:         */
+/* AO_nop                                                      */
+/* AO_load                                                     */
+/* AO_store                                                    */
+/* AO_test_and_set (binary)                                    */
+/* AO_fetch_and_add                                            */
+/* AO_fetch_and_add1                                           */
+/* AO_fetch_and_sub1                                           */
+/* AO_or                                                       */
+/* AO_compare_and_swap                                         */
+/*                                                             */
+/* Note that atomicity guarantees are valid only if both       */
+/* readers and writers use AO_ operations to access the        */
+/* shared value, while ordering constraints are intended to    */
+/* apply all memory operations.         If a location can potentially  */
+/* be accessed simultaneously from multiple threads, and one of        */
+/* those accesses may be a write access, then all such         */
+/* accesses to that location should be through AO_ primitives. */
+/* However if AO_ operations enforce sufficient ordering to    */
+/* ensure that a location x cannot be accessed concurrently,   */
+/* or can only be read concurrently, then x can be accessed    */
+/* via ordinary references and assignments.                    */
+/*                                                             */
+/* Compare_and_exchange takes an address and an expected old   */
+/* value and a new value, and returns an int.  Nonzero                 */
+/* indicates that it succeeded.                                        */
+/* Test_and_set takes an address, atomically replaces it by    */
+/* AO_TS_SET, and returns the prior value.                     */
+/* An AO_TS_t location can be reset with the                   */
+/* AO_CLEAR macro, which normally uses AO_store_release.       */
+/* AO_fetch_and_add takes an address and an AO_t increment     */
+/* value.  The AO_fetch_and_add1 and AO_fetch_and_sub1 variants        */
+/* are provided, since they allow faster implementations on    */
+/* some hardware. AO_or atomically ors an AO_t value into a    */
+/* memory location, but does not provide access to the original.*/
+/*                                                             */
+/* We expect this list to grow slowly over time.               */
+/*                                                             */
+/* Note that AO_nop_full is a full memory barrier.             */
+/*                                                             */
+/* Note that if some data is initialized with                  */
+/*     data.x = ...; data.y = ...; ...                         */
+/*     AO_store_release_write(&data_is_initialized, 1)         */
+/* then data is guaranteed to be initialized after the test    */
+/*     if (AO_load_release_read(&data_is_initialized)) ...     */
+/* succeeds.  Furthermore, this should generate near-optimal   */
+/* code on all common platforms.                               */
+/*                                                             */
+/* All operations operate on unsigned AO_t, which              */
+/* is the natural word size, and usually unsigned long.                */
+/* It is possible to check whether a particular operation op   */
+/* is available on a particular platform by checking whether   */
+/* AO_HAVE_op is defined.  We make heavy use of these macros   */
+/* internally.                                                 */
+
+/* The rest of this file basically has three sections:         */
+/*                                                             */
+/* Some utility and default definitions.                       */
+/*                                                             */
+/* The architecture dependent section:                         */
+/* This defines atomic operations that have direct hardware    */
+/* support on a particular platform, mostly by uncluding the   */
+/* appropriate compiler- and hardware-dependent file.                  */
+/*                                                             */
+/* The synthesis section:                                      */
+/* This tries to define other atomic operations in terms of    */
+/* those that are explicitly available on the platform.                */
+/* This section is hardware independent.                       */
+/* We make no attempt to synthesize operations in ways that    */
+/* effectively introduce locks, except for the debugging/demo  */
+/* pthread-based implementation at the beginning.  A more      */
+/* relistic implementation that falls back to locks could be   */
+/* added as a higher layer.  But that would sacrifice          */
+/* usability from signal handlers.                             */
+/* The synthesis section is implemented almost entirely in     */
+/* atomic_ops_generalize.h.                                    */
+
+/* Some common defaults.  Overridden for some architectures.   */
+#define AO_t size_t
+
+/* The test_and_set primitive returns an AO_TS_VAL_t value.    */
+/* AO_TS_t is the type of an in-memory test-and-set location.  */
+
+#define AO_TS_INITIALIZER (AO_t)AO_TS_CLEAR
+
+/* Platform-dependent stuff:                                   */
+#if defined(__GNUC__) || defined(_MSC_VER) || defined(__INTEL_COMPILER)
+# define AO_INLINE static __inline
+#else
+# define AO_INLINE static
+#endif
+
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+# define AO_compiler_barrier() __asm__ __volatile__("" : : : "memory")
+#elif defined(_MSC_VER)
+# if defined(_AMD64_)
+#   pragma intrinsic(_ReadWriteBarrier)
+#   define AO_compiler_barrier() _ReadWriteBarrier()
+       /* We assume this does not generate a fence instruction.        */
+       /* The documentation is a bit unclear.                          */
+# else
+#   define AO_compiler_barrier() __asm { }
+       /* The preceding implementation may be preferable here too.     */
+       /* But the documentation warns about VC++ 2003 and earlier.     */
+# endif
+#elif defined(__INTEL_COMPILER)
+# define AO_compiler_barrier() __memory_barrier() /* Too strong? IA64-only? */
+#elif defined(_HPUX_SOURCE)
+# if defined(__ia64)
+#   include <machine/sys/inline.h>
+#   define AO_compiler_barrier() _Asm_sched_fence()
+# else
+    /* FIXME - We dont know how to do this.  This is a guess.  */
+    /* And probably a bad one.                                 */
+    static volatile int AO_barrier_dummy;
+#   define AO_compiler_barrier() AO_barrier_dummy = AO_barrier_dummy
+# endif
+#else
+  /* We conjecture that the following usually gives us the right       */
+  /* semantics or an error.                                            */
+# define AO_compiler_barrier() asm("")
+#endif
+
+#if defined(AO_USE_PTHREAD_DEFS)
+# include "atomic_ops/sysdeps/generic_pthread.h"
+#endif /* AO_USE_PTHREAD_DEFS */
+
+#if defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS) \
+    && !defined(__INTEL_COMPILER)
+# if defined(__i386__)
+#   include "atomic_ops/sysdeps/gcc/x86.h"
+# endif /* __i386__ */
+# if defined(__x86_64__)
+#   include "atomic_ops/sysdeps/gcc/x86_64.h"
+# endif /* __i386__ */
+# if defined(__ia64__)
+#   include "atomic_ops/sysdeps/gcc/ia64.h"
+#   define AO_GENERALIZE_TWICE
+# endif /* __ia64__ */
+# if defined(__hppa__)
+#   include "atomic_ops/sysdeps/gcc/hppa.h"
+#   define AO_CAN_EMUL_CAS
+# endif /* __hppa__ */
+# if defined(__alpha__)
+#   include "atomic_ops/sysdeps/gcc/alpha.h"
+#   define AO_GENERALIZE_TWICE
+# endif /* __alpha__ */
+# if defined(__s390__)
+#   include "atomic_ops/sysdeps/gcc/s390.h"
+# endif /* __s390__ */
+# if defined(__sparc__)
+#   include "atomic_ops/sysdeps/gcc/sparc.h"
+#   define AO_CAN_EMUL_CAS
+# endif /* __sparc__ */
+# if defined(__m68k__)
+#   include "atomic_ops/sysdeps/gcc/m68k.h"
+# endif /* __m68k__ */
+# if defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)
+#   include "atomic_ops/sysdeps/gcc/powerpc.h"
+# endif /* __powerpc__ */
+# if defined(__arm__) && !defined(AO_USE_PTHREAD_DEFS)
+#   include "atomic_ops/sysdeps/gcc/arm.h"
+#   define AO_CAN_EMUL_CAS
+# endif /* __arm__ */
+# if defined(__cris__) || defined(CRIS)
+#   include "atomic_ops/sysdeps/gcc/cris.h"
+# endif
+#endif /* __GNUC__ && !AO_USE_PTHREAD_DEFS */
+
+#if defined(__INTEL_COMPILER) && !defined(AO_USE_PTHREAD_DEFS)
+# if defined(__ia64__)
+#   include "atomic_ops/sysdeps/icc/ia64.h"
+#   define AO_GENERALIZE_TWICE
+# endif
+#endif
+
+#if defined(_HPUX_SOURCE) && !defined(__GNUC__) && !defined(AO_USE_PTHREAD_DEFS)
+# if defined(__ia64)
+#   include "atomic_ops/sysdeps/hpc/ia64.h"
+#   define AO_GENERALIZE_TWICE
+# else
+#   include "atomic_ops/sysdeps/hpc/hppa.h"
+#   define AO_CAN_EMUL_CAS
+# endif
+#endif
+
+#if !defined(__GNUC__) && (defined(sparc) || defined(__sparc)) \
+    && !defined(AO_USE_PTHREAD_DEFS)
+#   include "atomic_ops/sysdeps/sunc/sparc.h"
+#   define AO_CAN_EMUL_CAS
+#endif
+
+#if defined(_MSC_VER)
+# if defined(_AMD64_)
+#   include "atomic_ops/sysdeps/msftc/x86_64.h"
+# elif _M_IX86 >= 400
+#   include "atomic_ops/sysdeps/msftc/x86.h"
+# endif
+#endif
+
+#if defined(AO_REQUIRE_CAS) && !defined(AO_HAVE_compare_and_swap) \
+    && !defined(AO_HAVE_compare_and_swap_full) \
+    && !defined(AO_HAVE_compare_and_swap_acquire)
+# if defined(AO_CAN_EMUL_CAS)
+#   include "atomic_ops/sysdeps/emul_cas.h"
+# else
+#  error Cannot implement AO_compare_and_swap_full on this architecture.
+# endif
+#endif         /* AO_REQUIRE_CAS && !AO_HAVE_compare_and_swap ... */
+
+/* The most common way to clear a test-and-set location                */
+/* at the end of a critical section.                           */
+#if AO_AO_TS_T && !defined(AO_CLEAR)
+# define AO_CLEAR(addr) AO_store_release((AO_TS_t *)addr, AO_TS_CLEAR)
+#endif
+#if AO_CHAR_TS_T && !defined(AO_CLEAR)
+# define AO_CLEAR(addr) AO_char_store_release((AO_TS_t *)addr, AO_TS_CLEAR)
+#endif
+
+/*
+ * The generalization section.
+ * Theoretically this should repeatedly include atomic_ops_generalize.h.
+ * In fact, we observe that this converges after a small fixed number
+ * of iterations, usually one.
+ */
+#include "atomic_ops/generalize.h"
+#ifdef AO_GENERALIZE_TWICE
+# include "atomic_ops/generalize.h"
+#endif
+
+/* For compatibility with version 0.4 and earlier      */
+#define AO_TS_T AO_TS_t
+#define AO_T AO_t
+#define AO_TS_VAL AO_TS_VAL_t
+
+#endif /* ATOMIC_OPS_H */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/Makefile.am b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/Makefile.am
new file mode 100644 (file)
index 0000000..8000273
--- /dev/null
@@ -0,0 +1,12 @@
+SUBDIRS=sysdeps
+
+EXTRA_DIST=generalize-small.template
+
+#Private Headers
+private_HEADERS=generalize.h generalize-small.h
+privatedir=${includedir}/atomic_ops/
+
+generalize-small.h: generalize-small.template
+       sed -e s:XSIZE:char:g -e s:XCTYPE:char:g $? > $@
+       sed -e s:XSIZE:short:g -e s:XCTYPE:short:g $? >> $@
+       sed -e s:XSIZE:int:g -e s:XCTYPE:int:g $? >> $@
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize-small.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize-small.h
new file mode 100644 (file)
index 0000000..4e45a0d
--- /dev/null
@@ -0,0 +1,1725 @@
+/* char_load */
+#if defined(AO_HAVE_char_load_acquire) && !defined(AO_HAVE_char_load)
+#  define AO_char_load(addr) AO_char_load_acquire(addr)
+#  define AO_HAVE_char_load
+#endif
+
+#if defined(AO_HAVE_char_load_full) && !defined(AO_HAVE_char_load_acquire)
+#  define AO_char_load_acquire(addr) AO_char_load_full(addr)
+#  define AO_HAVE_char_load_acquire
+#endif
+
+#if defined(AO_HAVE_char_load_full) && !defined(AO_HAVE_char_load_read)
+#  define AO_char_load_read(addr) AO_char_load_full(addr)
+#  define AO_HAVE_char_load_read
+#endif
+
+#if !defined(AO_HAVE_char_load_acquire_read) && defined(AO_HAVE_char_load_acquire)
+#  define AO_char_load_acquire_read(addr) AO_char_load_acquire(addr)
+#  define AO_HAVE_char_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_char_load) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_char_load_acquire)
+   AO_INLINE unsigned char
+   AO_char_load_acquire(volatile unsigned char *addr)
+   {
+     unsigned char result = AO_char_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_full();
+     return result;
+   }
+#  define AO_HAVE_char_load_acquire
+#endif
+
+#if defined(AO_HAVE_char_load) && defined(AO_HAVE_nop_read) && \
+    !defined(AO_HAVE_char_load_read)
+   AO_INLINE unsigned char
+   AO_char_load_read(volatile unsigned char *addr)
+   {
+     unsigned char result = AO_char_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_read();
+     return result;
+   }
+#  define AO_HAVE_char_load_read
+#endif
+
+#if defined(AO_HAVE_char_load_acquire) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_char_load_full)
+#  define AO_char_load_full(addr) (AO_nop_full(), AO_char_load_acquire(addr))
+#  define AO_HAVE_char_load_full
+#endif
+#if !defined(AO_HAVE_char_load_acquire_read) && defined(AO_HAVE_char_load_read)
+#  define AO_char_load_acquire_read(addr) AO_char_load_read(addr)
+#  define AO_HAVE_char_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_char_load_acquire_read) && !defined(AO_HAVE_char_load)
+#  define AO_char_load(addr) AO_char_load_acquire_read(addr)
+#  define AO_HAVE_char_load
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_char_load_acquire_read)
+#    define AO_char_load_dd_acquire_read(addr) \
+       AO_char_load_acquire_read(addr)
+#    define AO_HAVE_char_load_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_char_load)
+#    define AO_char_load_dd_acquire_read(addr) \
+       AO_char_load(addr)
+#    define AO_HAVE_char_load_dd_acquire_read
+#  endif
+#endif
+
+
+/* char_store */
+
+#if defined(AO_HAVE_char_store_release) && !defined(AO_HAVE_char_store)
+#  define AO_char_store(addr, val) AO_char_store_release(addr,val)
+#  define AO_HAVE_char_store
+#endif
+
+#if defined(AO_HAVE_char_store_full) && !defined(AO_HAVE_char_store_release)
+#  define AO_char_store_release(addr,val) AO_char_store_full(addr,val)
+#  define AO_HAVE_char_store_release
+#endif
+
+#if defined(AO_HAVE_char_store_full) && !defined(AO_HAVE_char_store_write)
+#  define AO_char_store_write(addr,val) AO_char_store_full(addr,val)
+#  define AO_HAVE_char_store_write
+#endif
+
+#if defined(AO_HAVE_char_store_release) && \
+       !defined(AO_HAVE_char_store_release_write)
+#  define AO_char_store_release_write(addr, val) \
+       AO_char_store_release(addr,val)
+#  define AO_HAVE_char_store_release_write
+#endif
+
+#if defined(AO_HAVE_char_store_write) && !defined(AO_HAVE_char_store)
+#  define AO_char_store(addr, val) AO_char_store_write(addr,val)
+#  define AO_HAVE_char_store
+#endif
+
+#if defined(AO_HAVE_char_store) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_char_store_release)
+#  define AO_char_store_release(addr,val) \
+       (AO_nop_full(), AO_char_store(addr,val))
+#  define AO_HAVE_char_store_release
+#endif
+
+#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_char_store) && \
+     !defined(AO_HAVE_char_store_write)
+#  define AO_char_store_write(addr, val) \
+       (AO_nop_write(), AO_char_store(addr,val))
+#  define AO_HAVE_char_store_write
+#endif
+
+#if defined(AO_HAVE_char_store_write) && \
+     !defined(AO_HAVE_char_store_release_write)
+#  define AO_char_store_release_write(addr, val) AO_char_store_write(addr,val)
+#  define AO_HAVE_char_store_release_write
+#endif
+
+#if defined(AO_HAVE_char_store_release) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_char_store_full)
+#  define AO_char_store_full(addr, val) \
+       (AO_char_store_release(addr, val), AO_nop_full())
+#  define AO_HAVE_char_store_full
+#endif
+
+
+/* char_fetch_and_add */
+#if defined(AO_HAVE_char_compare_and_swap_full) && \
+    !defined(AO_HAVE_char_fetch_and_add_full)
+   AO_INLINE AO_t
+   AO_char_fetch_and_add_full(volatile unsigned char *addr,
+                              unsigned char incr)
+   {
+     unsigned char old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_char_compare_and_swap_full(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_char_fetch_and_add_full
+#endif
+
+#if defined(AO_HAVE_char_compare_and_swap_acquire) && \
+    !defined(AO_HAVE_char_fetch_and_add_acquire)
+   AO_INLINE AO_t
+   AO_char_fetch_and_add_acquire(volatile unsigned char *addr,
+                                 unsigned char incr)
+   {
+     unsigned char old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_char_compare_and_swap_acquire(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_char_fetch_and_add_acquire
+#endif
+
+#if defined(AO_HAVE_char_compare_and_swap_release) && \
+    !defined(AO_HAVE_char_fetch_and_add_release)
+   AO_INLINE AO_t
+   AO_char_fetch_and_add_release(volatile unsigned char *addr,
+                                 unsigned char incr)
+   {
+     unsigned char old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_char_compare_and_swap_release(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_char_fetch_and_add_release
+#endif
+
+#if defined(AO_HAVE_char_fetch_and_add_full)
+#  if !defined(AO_HAVE_char_fetch_and_add_release)
+#    define AO_char_fetch_and_add_release(addr, val) \
+        AO_char_fetch_and_add_full(addr, val)
+#    define AO_HAVE_char_fetch_and_add_release
+#  endif
+#  if !defined(AO_HAVE_char_fetch_and_add_acquire)
+#    define AO_char_fetch_and_add_acquire(addr, val) \
+        AO_char_fetch_and_add_full(addr, val)
+#    define AO_HAVE_char_fetch_and_add_acquire
+#  endif
+#  if !defined(AO_HAVE_char_fetch_and_add_write)
+#    define AO_char_fetch_and_add_write(addr, val) \
+        AO_char_fetch_and_add_full(addr, val)
+#    define AO_HAVE_char_fetch_and_add_write
+#  endif
+#  if !defined(AO_HAVE_char_fetch_and_add_read)
+#    define AO_char_fetch_and_add_read(addr, val) \
+        AO_char_fetch_and_add_full(addr, val)
+#    define AO_HAVE_char_fetch_and_add_read
+#  endif
+#endif /* AO_HAVE_char_fetch_and_add_full */
+
+#if !defined(AO_HAVE_char_fetch_and_add) && \
+    defined(AO_HAVE_char_fetch_and_add_release)
+#  define AO_char_fetch_and_add(addr, val) \
+       AO_char_fetch_and_add_release(addr, val)
+#  define AO_HAVE_char_fetch_and_add
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add) && \
+    defined(AO_HAVE_char_fetch_and_add_acquire)
+#  define AO_char_fetch_and_add(addr, val) \
+       AO_char_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_char_fetch_and_add
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add) && \
+    defined(AO_HAVE_char_fetch_and_add_write)
+#  define AO_char_fetch_and_add(addr, val) \
+       AO_char_fetch_and_add_write(addr, val)
+#  define AO_HAVE_char_fetch_and_add
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add) && \
+    defined(AO_HAVE_char_fetch_and_add_read)
+#  define AO_char_fetch_and_add(addr, val) \
+       AO_char_fetch_and_add_read(addr, val)
+#  define AO_HAVE_char_fetch_and_add
+#endif
+
+#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_char_fetch_and_add_full)
+#  define AO_char_fetch_and_add_full(addr, val) \
+       (AO_nop_full(), AO_char_fetch_and_add_acquire(addr, val))
+#endif
+
+#if !defined(AO_HAVE_char_fetch_and_add_release_write) && \
+    defined(AO_HAVE_char_fetch_and_add_write)
+#  define AO_char_fetch_and_add_release_write(addr, val) \
+       AO_char_fetch_and_add_write(addr, val)
+#  define AO_HAVE_char_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add_release_write) && \
+    defined(AO_HAVE_char_fetch_and_add_release)
+#  define AO_char_fetch_and_add_release_write(addr, val) \
+       AO_char_fetch_and_add_release(addr, val)
+#  define AO_HAVE_char_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_char_fetch_and_add_read)
+#  define AO_char_fetch_and_add_acquire_read(addr, val) \
+       AO_char_fetch_and_add_read(addr, val)
+#  define AO_HAVE_char_fetch_and_add_acquire_read
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_char_fetch_and_add_acquire)
+#  define AO_char_fetch_and_add_acquire_read(addr, val) \
+       AO_char_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_char_fetch_and_add_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_char_fetch_and_add_acquire_read)
+#    define AO_char_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_char_fetch_and_add_acquire_read(addr, val)
+#    define AO_HAVE_char_fetch_and_add_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_char_fetch_and_add)
+#    define AO_char_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_char_fetch_and_add(addr, val)
+#    define AO_HAVE_char_fetch_and_add_dd_acquire_read
+#  endif
+#endif
+  
+/* char_fetch_and_add1 */
+
+#if defined(AO_HAVE_char_fetch_and_add_full) &&\
+    !defined(AO_HAVE_char_fetch_and_add1_full)
+#  define AO_char_fetch_and_add1_full(addr) \
+       AO_char_fetch_and_add_full(addr,1)
+#  define AO_HAVE_char_fetch_and_add1_full
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_release) &&\
+    !defined(AO_HAVE_char_fetch_and_add1_release)
+#  define AO_char_fetch_and_add1_release(addr) \
+       AO_char_fetch_and_add_release(addr,1)
+#  define AO_HAVE_char_fetch_and_add1_release
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_char_fetch_and_add1_acquire)
+#  define AO_char_fetch_and_add1_acquire(addr) \
+       AO_char_fetch_and_add_acquire(addr,1)
+#  define AO_HAVE_char_fetch_and_add1_acquire
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_write) &&\
+    !defined(AO_HAVE_char_fetch_and_add1_write)
+#  define AO_char_fetch_and_add1_write(addr) \
+       AO_char_fetch_and_add_write(addr,1)
+#  define AO_HAVE_char_fetch_and_add1_write
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_read) &&\
+    !defined(AO_HAVE_char_fetch_and_add1_read)
+#  define AO_char_fetch_and_add1_read(addr) \
+       AO_char_fetch_and_add_read(addr,1)
+#  define AO_HAVE_char_fetch_and_add1_read
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_char_fetch_and_add1_release_write)
+#  define AO_char_fetch_and_add1_release_write(addr) \
+       AO_char_fetch_and_add_release_write(addr,1)
+#  define AO_HAVE_char_fetch_and_add1_release_write
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_char_fetch_and_add1_acquire_read)
+#  define AO_char_fetch_and_add1_acquire_read(addr) \
+       AO_char_fetch_and_add_acquire_read(addr,1)
+#  define AO_HAVE_char_fetch_and_add1_acquire_read
+#endif
+#if defined(AO_HAVE_char_fetch_and_add) &&\
+    !defined(AO_HAVE_char_fetch_and_add1)
+#  define AO_char_fetch_and_add1(addr) \
+       AO_char_fetch_and_add(addr,1)
+#  define AO_HAVE_char_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_char_fetch_and_add1_full)
+#  if !defined(AO_HAVE_char_fetch_and_add1_release)
+#    define AO_char_fetch_and_add1_release(addr) \
+        AO_char_fetch_and_add1_full(addr)
+#    define AO_HAVE_char_fetch_and_add1_release
+#  endif
+#  if !defined(AO_HAVE_char_fetch_and_add1_acquire)
+#    define AO_char_fetch_and_add1_acquire(addr) \
+        AO_char_fetch_and_add1_full(addr)
+#    define AO_HAVE_char_fetch_and_add1_acquire
+#  endif
+#  if !defined(AO_HAVE_char_fetch_and_add1_write)
+#    define AO_char_fetch_and_add1_write(addr) \
+        AO_char_fetch_and_add1_full(addr)
+#    define AO_HAVE_char_fetch_and_add1_write
+#  endif
+#  if !defined(AO_HAVE_char_fetch_and_add1_read)
+#    define AO_char_fetch_and_add1_read(addr) \
+        AO_char_fetch_and_add1_full(addr)
+#    define AO_HAVE_char_fetch_and_add1_read
+#  endif
+#endif /* AO_HAVE_char_fetch_and_add1_full */
+
+#if !defined(AO_HAVE_char_fetch_and_add1) && \
+    defined(AO_HAVE_char_fetch_and_add1_release)
+#  define AO_char_fetch_and_add1(addr) \
+       AO_char_fetch_and_add1_release(addr)
+#  define AO_HAVE_char_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add1) && \
+    defined(AO_HAVE_char_fetch_and_add1_acquire)
+#  define AO_char_fetch_and_add1(addr) \
+       AO_char_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_char_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add1) && \
+    defined(AO_HAVE_char_fetch_and_add1_write)
+#  define AO_char_fetch_and_add1(addr) \
+       AO_char_fetch_and_add1_write(addr)
+#  define AO_HAVE_char_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add1) && \
+    defined(AO_HAVE_char_fetch_and_add1_read)
+#  define AO_char_fetch_and_add1(addr) \
+       AO_char_fetch_and_add1_read(addr)
+#  define AO_HAVE_char_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_char_fetch_and_add1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_char_fetch_and_add1_full)
+#  define AO_char_fetch_and_add1_full(addr) \
+       (AO_nop_full(), AO_char_fetch_and_add1_acquire(addr))
+#  define AO_HAVE_char_fetch_and_add1_full
+#endif
+
+#if !defined(AO_HAVE_char_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_char_fetch_and_add1_write)
+#  define AO_char_fetch_and_add1_release_write(addr) \
+       AO_char_fetch_and_add1_write(addr)
+#  define AO_HAVE_char_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_char_fetch_and_add1_release)
+#  define AO_char_fetch_and_add1_release_write(addr) \
+       AO_char_fetch_and_add1_release(addr)
+#  define AO_HAVE_char_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_char_fetch_and_add1_read)
+#  define AO_char_fetch_and_add1_acquire_read(addr) \
+       AO_char_fetch_and_add1_read(addr)
+#  define AO_HAVE_char_fetch_and_add1_acquire_read
+#endif
+#if !defined(AO_HAVE_char_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_char_fetch_and_add1_acquire)
+#  define AO_char_fetch_and_add1_acquire_read(addr) \
+       AO_char_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_char_fetch_and_add1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_char_fetch_and_add1_acquire_read)
+#    define AO_char_fetch_and_add1_dd_acquire_read(addr) \
+       AO_char_fetch_and_add1_acquire_read(addr)
+#    define AO_HAVE_char_fetch_and_add1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_char_fetch_and_add1)
+#    define AO_char_fetch_and_add1_dd_acquire_read(addr) \
+       AO_char_fetch_and_add1(addr)
+#    define AO_HAVE_char_fetch_and_add1_dd_acquire_read
+#  endif
+#endif
+
+/* char_fetch_and_sub1 */
+
+#if defined(AO_HAVE_char_fetch_and_add_full) &&\
+    !defined(AO_HAVE_char_fetch_and_sub1_full)
+#  define AO_char_fetch_and_sub1_full(addr) \
+       AO_char_fetch_and_add_full(addr,(unsigned char)(-1))
+#  define AO_HAVE_char_fetch_and_sub1_full
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_release) &&\
+    !defined(AO_HAVE_char_fetch_and_sub1_release)
+#  define AO_char_fetch_and_sub1_release(addr) \
+       AO_char_fetch_and_add_release(addr,(unsigned char)(-1))
+#  define AO_HAVE_char_fetch_and_sub1_release
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_char_fetch_and_sub1_acquire)
+#  define AO_char_fetch_and_sub1_acquire(addr) \
+       AO_char_fetch_and_add_acquire(addr,(unsigned char)(-1))
+#  define AO_HAVE_char_fetch_and_sub1_acquire
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_write) &&\
+    !defined(AO_HAVE_char_fetch_and_sub1_write)
+#  define AO_char_fetch_and_sub1_write(addr) \
+       AO_char_fetch_and_add_write(addr,(unsigned char)(-1))
+#  define AO_HAVE_char_fetch_and_sub1_write
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_read) &&\
+    !defined(AO_HAVE_char_fetch_and_sub1_read)
+#  define AO_char_fetch_and_sub1_read(addr) \
+       AO_char_fetch_and_add_read(addr,(unsigned char)(-1))
+#  define AO_HAVE_char_fetch_and_sub1_read
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_char_fetch_and_sub1_release_write)
+#  define AO_char_fetch_and_sub1_release_write(addr) \
+       AO_char_fetch_and_add_release_write(addr,(unsigned char)(-1))
+#  define AO_HAVE_char_fetch_and_sub1_release_write
+#endif
+#if defined(AO_HAVE_char_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_char_fetch_and_sub1_acquire_read)
+#  define AO_char_fetch_and_sub1_acquire_read(addr) \
+       AO_char_fetch_and_add_acquire_read(addr,(unsigned char)(-1))
+#  define AO_HAVE_char_fetch_and_sub1_acquire_read
+#endif
+#if defined(AO_HAVE_char_fetch_and_add) &&\
+    !defined(AO_HAVE_char_fetch_and_sub1)
+#  define AO_char_fetch_and_sub1(addr) \
+       AO_char_fetch_and_add(addr,(unsigned char)(-1))
+#  define AO_HAVE_char_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_char_fetch_and_sub1_full)
+#  if !defined(AO_HAVE_char_fetch_and_sub1_release)
+#    define AO_char_fetch_and_sub1_release(addr) \
+        AO_char_fetch_and_sub1_full(addr)
+#    define AO_HAVE_char_fetch_and_sub1_release
+#  endif
+#  if !defined(AO_HAVE_char_fetch_and_sub1_acquire)
+#    define AO_char_fetch_and_sub1_acquire(addr) \
+        AO_char_fetch_and_sub1_full(addr)
+#    define AO_HAVE_char_fetch_and_sub1_acquire
+#  endif
+#  if !defined(AO_HAVE_char_fetch_and_sub1_write)
+#    define AO_char_fetch_and_sub1_write(addr) \
+        AO_char_fetch_and_sub1_full(addr)
+#    define AO_HAVE_char_fetch_and_sub1_write
+#  endif
+#  if !defined(AO_HAVE_char_fetch_and_sub1_read)
+#    define AO_char_fetch_and_sub1_read(addr) \
+        AO_char_fetch_and_sub1_full(addr)
+#    define AO_HAVE_char_fetch_and_sub1_read
+#  endif
+#endif /* AO_HAVE_char_fetch_and_sub1_full */
+
+#if !defined(AO_HAVE_char_fetch_and_sub1) && \
+    defined(AO_HAVE_char_fetch_and_sub1_release)
+#  define AO_char_fetch_and_sub1(addr) \
+       AO_char_fetch_and_sub1_release(addr)
+#  define AO_HAVE_char_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_char_fetch_and_sub1) && \
+    defined(AO_HAVE_char_fetch_and_sub1_acquire)
+#  define AO_char_fetch_and_sub1(addr) \
+       AO_char_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_char_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_char_fetch_and_sub1) && \
+    defined(AO_HAVE_char_fetch_and_sub1_write)
+#  define AO_char_fetch_and_sub1(addr) \
+       AO_char_fetch_and_sub1_write(addr)
+#  define AO_HAVE_char_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_char_fetch_and_sub1) && \
+    defined(AO_HAVE_char_fetch_and_sub1_read)
+#  define AO_char_fetch_and_sub1(addr) \
+       AO_char_fetch_and_sub1_read(addr)
+#  define AO_HAVE_char_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_char_fetch_and_sub1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_char_fetch_and_sub1_full)
+#  define AO_char_fetch_and_sub1_full(addr) \
+       (AO_nop_full(), AO_char_fetch_and_sub1_acquire(addr))
+#  define AO_HAVE_char_fetch_and_sub1_full
+#endif
+
+#if !defined(AO_HAVE_char_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_char_fetch_and_sub1_write)
+#  define AO_char_fetch_and_sub1_release_write(addr) \
+       AO_char_fetch_and_sub1_write(addr)
+#  define AO_HAVE_char_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_char_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_char_fetch_and_sub1_release)
+#  define AO_char_fetch_and_sub1_release_write(addr) \
+       AO_char_fetch_and_sub1_release(addr)
+#  define AO_HAVE_char_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_char_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_char_fetch_and_sub1_read)
+#  define AO_char_fetch_and_sub1_acquire_read(addr) \
+       AO_char_fetch_and_sub1_read(addr)
+#  define AO_HAVE_char_fetch_and_sub1_acquire_read
+#endif
+#if !defined(AO_HAVE_char_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_char_fetch_and_sub1_acquire)
+#  define AO_char_fetch_and_sub1_acquire_read(addr) \
+       AO_char_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_char_fetch_and_sub1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_char_fetch_and_sub1_acquire_read)
+#    define AO_char_fetch_and_sub1_dd_acquire_read(addr) \
+       AO_char_fetch_and_sub1_acquire_read(addr)
+#    define AO_HAVE_char_fetch_and_sub1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_char_fetch_and_sub1)
+#    define AO_char_fetch_and_sub1_dd_acquire_read(addr) \
+       AO_char_fetch_and_sub1(addr)
+#    define AO_HAVE_char_fetch_and_sub1_dd_acquire_read
+#  endif
+#endif
+
+/* short_load */
+#if defined(AO_HAVE_short_load_acquire) && !defined(AO_HAVE_short_load)
+#  define AO_short_load(addr) AO_short_load_acquire(addr)
+#  define AO_HAVE_short_load
+#endif
+
+#if defined(AO_HAVE_short_load_full) && !defined(AO_HAVE_short_load_acquire)
+#  define AO_short_load_acquire(addr) AO_short_load_full(addr)
+#  define AO_HAVE_short_load_acquire
+#endif
+
+#if defined(AO_HAVE_short_load_full) && !defined(AO_HAVE_short_load_read)
+#  define AO_short_load_read(addr) AO_short_load_full(addr)
+#  define AO_HAVE_short_load_read
+#endif
+
+#if !defined(AO_HAVE_short_load_acquire_read) && defined(AO_HAVE_short_load_acquire)
+#  define AO_short_load_acquire_read(addr) AO_short_load_acquire(addr)
+#  define AO_HAVE_short_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_short_load) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_short_load_acquire)
+   AO_INLINE unsigned short
+   AO_short_load_acquire(volatile unsigned short *addr)
+   {
+     unsigned short result = AO_short_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_full();
+     return result;
+   }
+#  define AO_HAVE_short_load_acquire
+#endif
+
+#if defined(AO_HAVE_short_load) && defined(AO_HAVE_nop_read) && \
+    !defined(AO_HAVE_short_load_read)
+   AO_INLINE unsigned short
+   AO_short_load_read(volatile unsigned short *addr)
+   {
+     unsigned short result = AO_short_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_read();
+     return result;
+   }
+#  define AO_HAVE_short_load_read
+#endif
+
+#if defined(AO_HAVE_short_load_acquire) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_short_load_full)
+#  define AO_short_load_full(addr) (AO_nop_full(), AO_short_load_acquire(addr))
+#  define AO_HAVE_short_load_full
+#endif
+#if !defined(AO_HAVE_short_load_acquire_read) && defined(AO_HAVE_short_load_read)
+#  define AO_short_load_acquire_read(addr) AO_short_load_read(addr)
+#  define AO_HAVE_short_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_short_load_acquire_read) && !defined(AO_HAVE_short_load)
+#  define AO_short_load(addr) AO_short_load_acquire_read(addr)
+#  define AO_HAVE_short_load
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_short_load_acquire_read)
+#    define AO_short_load_dd_acquire_read(addr) \
+       AO_short_load_acquire_read(addr)
+#    define AO_HAVE_short_load_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_short_load)
+#    define AO_short_load_dd_acquire_read(addr) \
+       AO_short_load(addr)
+#    define AO_HAVE_short_load_dd_acquire_read
+#  endif
+#endif
+
+
+/* short_store */
+
+#if defined(AO_HAVE_short_store_release) && !defined(AO_HAVE_short_store)
+#  define AO_short_store(addr, val) AO_short_store_release(addr,val)
+#  define AO_HAVE_short_store
+#endif
+
+#if defined(AO_HAVE_short_store_full) && !defined(AO_HAVE_short_store_release)
+#  define AO_short_store_release(addr,val) AO_short_store_full(addr,val)
+#  define AO_HAVE_short_store_release
+#endif
+
+#if defined(AO_HAVE_short_store_full) && !defined(AO_HAVE_short_store_write)
+#  define AO_short_store_write(addr,val) AO_short_store_full(addr,val)
+#  define AO_HAVE_short_store_write
+#endif
+
+#if defined(AO_HAVE_short_store_release) && \
+       !defined(AO_HAVE_short_store_release_write)
+#  define AO_short_store_release_write(addr, val) \
+       AO_short_store_release(addr,val)
+#  define AO_HAVE_short_store_release_write
+#endif
+
+#if defined(AO_HAVE_short_store_write) && !defined(AO_HAVE_short_store)
+#  define AO_short_store(addr, val) AO_short_store_write(addr,val)
+#  define AO_HAVE_short_store
+#endif
+
+#if defined(AO_HAVE_short_store) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_short_store_release)
+#  define AO_short_store_release(addr,val) \
+       (AO_nop_full(), AO_short_store(addr,val))
+#  define AO_HAVE_short_store_release
+#endif
+
+#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_short_store) && \
+     !defined(AO_HAVE_short_store_write)
+#  define AO_short_store_write(addr, val) \
+       (AO_nop_write(), AO_short_store(addr,val))
+#  define AO_HAVE_short_store_write
+#endif
+
+#if defined(AO_HAVE_short_store_write) && \
+     !defined(AO_HAVE_short_store_release_write)
+#  define AO_short_store_release_write(addr, val) AO_short_store_write(addr,val)
+#  define AO_HAVE_short_store_release_write
+#endif
+
+#if defined(AO_HAVE_short_store_release) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_short_store_full)
+#  define AO_short_store_full(addr, val) \
+       (AO_short_store_release(addr, val), AO_nop_full())
+#  define AO_HAVE_short_store_full
+#endif
+
+
+/* short_fetch_and_add */
+#if defined(AO_HAVE_short_compare_and_swap_full) && \
+    !defined(AO_HAVE_short_fetch_and_add_full)
+   AO_INLINE AO_t
+   AO_short_fetch_and_add_full(volatile unsigned short *addr,
+                              unsigned short incr)
+   {
+     unsigned short old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_short_compare_and_swap_full(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_short_fetch_and_add_full
+#endif
+
+#if defined(AO_HAVE_short_compare_and_swap_acquire) && \
+    !defined(AO_HAVE_short_fetch_and_add_acquire)
+   AO_INLINE AO_t
+   AO_short_fetch_and_add_acquire(volatile unsigned short *addr,
+                                 unsigned short incr)
+   {
+     unsigned short old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_short_compare_and_swap_acquire(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_short_fetch_and_add_acquire
+#endif
+
+#if defined(AO_HAVE_short_compare_and_swap_release) && \
+    !defined(AO_HAVE_short_fetch_and_add_release)
+   AO_INLINE AO_t
+   AO_short_fetch_and_add_release(volatile unsigned short *addr,
+                                 unsigned short incr)
+   {
+     unsigned short old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_short_compare_and_swap_release(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_short_fetch_and_add_release
+#endif
+
+#if defined(AO_HAVE_short_fetch_and_add_full)
+#  if !defined(AO_HAVE_short_fetch_and_add_release)
+#    define AO_short_fetch_and_add_release(addr, val) \
+        AO_short_fetch_and_add_full(addr, val)
+#    define AO_HAVE_short_fetch_and_add_release
+#  endif
+#  if !defined(AO_HAVE_short_fetch_and_add_acquire)
+#    define AO_short_fetch_and_add_acquire(addr, val) \
+        AO_short_fetch_and_add_full(addr, val)
+#    define AO_HAVE_short_fetch_and_add_acquire
+#  endif
+#  if !defined(AO_HAVE_short_fetch_and_add_write)
+#    define AO_short_fetch_and_add_write(addr, val) \
+        AO_short_fetch_and_add_full(addr, val)
+#    define AO_HAVE_short_fetch_and_add_write
+#  endif
+#  if !defined(AO_HAVE_short_fetch_and_add_read)
+#    define AO_short_fetch_and_add_read(addr, val) \
+        AO_short_fetch_and_add_full(addr, val)
+#    define AO_HAVE_short_fetch_and_add_read
+#  endif
+#endif /* AO_HAVE_short_fetch_and_add_full */
+
+#if !defined(AO_HAVE_short_fetch_and_add) && \
+    defined(AO_HAVE_short_fetch_and_add_release)
+#  define AO_short_fetch_and_add(addr, val) \
+       AO_short_fetch_and_add_release(addr, val)
+#  define AO_HAVE_short_fetch_and_add
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add) && \
+    defined(AO_HAVE_short_fetch_and_add_acquire)
+#  define AO_short_fetch_and_add(addr, val) \
+       AO_short_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_short_fetch_and_add
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add) && \
+    defined(AO_HAVE_short_fetch_and_add_write)
+#  define AO_short_fetch_and_add(addr, val) \
+       AO_short_fetch_and_add_write(addr, val)
+#  define AO_HAVE_short_fetch_and_add
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add) && \
+    defined(AO_HAVE_short_fetch_and_add_read)
+#  define AO_short_fetch_and_add(addr, val) \
+       AO_short_fetch_and_add_read(addr, val)
+#  define AO_HAVE_short_fetch_and_add
+#endif
+
+#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_short_fetch_and_add_full)
+#  define AO_short_fetch_and_add_full(addr, val) \
+       (AO_nop_full(), AO_short_fetch_and_add_acquire(addr, val))
+#endif
+
+#if !defined(AO_HAVE_short_fetch_and_add_release_write) && \
+    defined(AO_HAVE_short_fetch_and_add_write)
+#  define AO_short_fetch_and_add_release_write(addr, val) \
+       AO_short_fetch_and_add_write(addr, val)
+#  define AO_HAVE_short_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add_release_write) && \
+    defined(AO_HAVE_short_fetch_and_add_release)
+#  define AO_short_fetch_and_add_release_write(addr, val) \
+       AO_short_fetch_and_add_release(addr, val)
+#  define AO_HAVE_short_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_short_fetch_and_add_read)
+#  define AO_short_fetch_and_add_acquire_read(addr, val) \
+       AO_short_fetch_and_add_read(addr, val)
+#  define AO_HAVE_short_fetch_and_add_acquire_read
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_short_fetch_and_add_acquire)
+#  define AO_short_fetch_and_add_acquire_read(addr, val) \
+       AO_short_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_short_fetch_and_add_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_short_fetch_and_add_acquire_read)
+#    define AO_short_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_short_fetch_and_add_acquire_read(addr, val)
+#    define AO_HAVE_short_fetch_and_add_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_short_fetch_and_add)
+#    define AO_short_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_short_fetch_and_add(addr, val)
+#    define AO_HAVE_short_fetch_and_add_dd_acquire_read
+#  endif
+#endif
+  
+/* short_fetch_and_add1 */
+
+#if defined(AO_HAVE_short_fetch_and_add_full) &&\
+    !defined(AO_HAVE_short_fetch_and_add1_full)
+#  define AO_short_fetch_and_add1_full(addr) \
+       AO_short_fetch_and_add_full(addr,1)
+#  define AO_HAVE_short_fetch_and_add1_full
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_release) &&\
+    !defined(AO_HAVE_short_fetch_and_add1_release)
+#  define AO_short_fetch_and_add1_release(addr) \
+       AO_short_fetch_and_add_release(addr,1)
+#  define AO_HAVE_short_fetch_and_add1_release
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_short_fetch_and_add1_acquire)
+#  define AO_short_fetch_and_add1_acquire(addr) \
+       AO_short_fetch_and_add_acquire(addr,1)
+#  define AO_HAVE_short_fetch_and_add1_acquire
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_write) &&\
+    !defined(AO_HAVE_short_fetch_and_add1_write)
+#  define AO_short_fetch_and_add1_write(addr) \
+       AO_short_fetch_and_add_write(addr,1)
+#  define AO_HAVE_short_fetch_and_add1_write
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_read) &&\
+    !defined(AO_HAVE_short_fetch_and_add1_read)
+#  define AO_short_fetch_and_add1_read(addr) \
+       AO_short_fetch_and_add_read(addr,1)
+#  define AO_HAVE_short_fetch_and_add1_read
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_short_fetch_and_add1_release_write)
+#  define AO_short_fetch_and_add1_release_write(addr) \
+       AO_short_fetch_and_add_release_write(addr,1)
+#  define AO_HAVE_short_fetch_and_add1_release_write
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_short_fetch_and_add1_acquire_read)
+#  define AO_short_fetch_and_add1_acquire_read(addr) \
+       AO_short_fetch_and_add_acquire_read(addr,1)
+#  define AO_HAVE_short_fetch_and_add1_acquire_read
+#endif
+#if defined(AO_HAVE_short_fetch_and_add) &&\
+    !defined(AO_HAVE_short_fetch_and_add1)
+#  define AO_short_fetch_and_add1(addr) \
+       AO_short_fetch_and_add(addr,1)
+#  define AO_HAVE_short_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_short_fetch_and_add1_full)
+#  if !defined(AO_HAVE_short_fetch_and_add1_release)
+#    define AO_short_fetch_and_add1_release(addr) \
+        AO_short_fetch_and_add1_full(addr)
+#    define AO_HAVE_short_fetch_and_add1_release
+#  endif
+#  if !defined(AO_HAVE_short_fetch_and_add1_acquire)
+#    define AO_short_fetch_and_add1_acquire(addr) \
+        AO_short_fetch_and_add1_full(addr)
+#    define AO_HAVE_short_fetch_and_add1_acquire
+#  endif
+#  if !defined(AO_HAVE_short_fetch_and_add1_write)
+#    define AO_short_fetch_and_add1_write(addr) \
+        AO_short_fetch_and_add1_full(addr)
+#    define AO_HAVE_short_fetch_and_add1_write
+#  endif
+#  if !defined(AO_HAVE_short_fetch_and_add1_read)
+#    define AO_short_fetch_and_add1_read(addr) \
+        AO_short_fetch_and_add1_full(addr)
+#    define AO_HAVE_short_fetch_and_add1_read
+#  endif
+#endif /* AO_HAVE_short_fetch_and_add1_full */
+
+#if !defined(AO_HAVE_short_fetch_and_add1) && \
+    defined(AO_HAVE_short_fetch_and_add1_release)
+#  define AO_short_fetch_and_add1(addr) \
+       AO_short_fetch_and_add1_release(addr)
+#  define AO_HAVE_short_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add1) && \
+    defined(AO_HAVE_short_fetch_and_add1_acquire)
+#  define AO_short_fetch_and_add1(addr) \
+       AO_short_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_short_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add1) && \
+    defined(AO_HAVE_short_fetch_and_add1_write)
+#  define AO_short_fetch_and_add1(addr) \
+       AO_short_fetch_and_add1_write(addr)
+#  define AO_HAVE_short_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add1) && \
+    defined(AO_HAVE_short_fetch_and_add1_read)
+#  define AO_short_fetch_and_add1(addr) \
+       AO_short_fetch_and_add1_read(addr)
+#  define AO_HAVE_short_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_short_fetch_and_add1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_short_fetch_and_add1_full)
+#  define AO_short_fetch_and_add1_full(addr) \
+       (AO_nop_full(), AO_short_fetch_and_add1_acquire(addr))
+#  define AO_HAVE_short_fetch_and_add1_full
+#endif
+
+#if !defined(AO_HAVE_short_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_short_fetch_and_add1_write)
+#  define AO_short_fetch_and_add1_release_write(addr) \
+       AO_short_fetch_and_add1_write(addr)
+#  define AO_HAVE_short_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_short_fetch_and_add1_release)
+#  define AO_short_fetch_and_add1_release_write(addr) \
+       AO_short_fetch_and_add1_release(addr)
+#  define AO_HAVE_short_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_short_fetch_and_add1_read)
+#  define AO_short_fetch_and_add1_acquire_read(addr) \
+       AO_short_fetch_and_add1_read(addr)
+#  define AO_HAVE_short_fetch_and_add1_acquire_read
+#endif
+#if !defined(AO_HAVE_short_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_short_fetch_and_add1_acquire)
+#  define AO_short_fetch_and_add1_acquire_read(addr) \
+       AO_short_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_short_fetch_and_add1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_short_fetch_and_add1_acquire_read)
+#    define AO_short_fetch_and_add1_dd_acquire_read(addr) \
+       AO_short_fetch_and_add1_acquire_read(addr)
+#    define AO_HAVE_short_fetch_and_add1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_short_fetch_and_add1)
+#    define AO_short_fetch_and_add1_dd_acquire_read(addr) \
+       AO_short_fetch_and_add1(addr)
+#    define AO_HAVE_short_fetch_and_add1_dd_acquire_read
+#  endif
+#endif
+
+/* short_fetch_and_sub1 */
+
+#if defined(AO_HAVE_short_fetch_and_add_full) &&\
+    !defined(AO_HAVE_short_fetch_and_sub1_full)
+#  define AO_short_fetch_and_sub1_full(addr) \
+       AO_short_fetch_and_add_full(addr,(unsigned short)(-1))
+#  define AO_HAVE_short_fetch_and_sub1_full
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_release) &&\
+    !defined(AO_HAVE_short_fetch_and_sub1_release)
+#  define AO_short_fetch_and_sub1_release(addr) \
+       AO_short_fetch_and_add_release(addr,(unsigned short)(-1))
+#  define AO_HAVE_short_fetch_and_sub1_release
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_short_fetch_and_sub1_acquire)
+#  define AO_short_fetch_and_sub1_acquire(addr) \
+       AO_short_fetch_and_add_acquire(addr,(unsigned short)(-1))
+#  define AO_HAVE_short_fetch_and_sub1_acquire
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_write) &&\
+    !defined(AO_HAVE_short_fetch_and_sub1_write)
+#  define AO_short_fetch_and_sub1_write(addr) \
+       AO_short_fetch_and_add_write(addr,(unsigned short)(-1))
+#  define AO_HAVE_short_fetch_and_sub1_write
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_read) &&\
+    !defined(AO_HAVE_short_fetch_and_sub1_read)
+#  define AO_short_fetch_and_sub1_read(addr) \
+       AO_short_fetch_and_add_read(addr,(unsigned short)(-1))
+#  define AO_HAVE_short_fetch_and_sub1_read
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_short_fetch_and_sub1_release_write)
+#  define AO_short_fetch_and_sub1_release_write(addr) \
+       AO_short_fetch_and_add_release_write(addr,(unsigned short)(-1))
+#  define AO_HAVE_short_fetch_and_sub1_release_write
+#endif
+#if defined(AO_HAVE_short_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_short_fetch_and_sub1_acquire_read)
+#  define AO_short_fetch_and_sub1_acquire_read(addr) \
+       AO_short_fetch_and_add_acquire_read(addr,(unsigned short)(-1))
+#  define AO_HAVE_short_fetch_and_sub1_acquire_read
+#endif
+#if defined(AO_HAVE_short_fetch_and_add) &&\
+    !defined(AO_HAVE_short_fetch_and_sub1)
+#  define AO_short_fetch_and_sub1(addr) \
+       AO_short_fetch_and_add(addr,(unsigned short)(-1))
+#  define AO_HAVE_short_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_short_fetch_and_sub1_full)
+#  if !defined(AO_HAVE_short_fetch_and_sub1_release)
+#    define AO_short_fetch_and_sub1_release(addr) \
+        AO_short_fetch_and_sub1_full(addr)
+#    define AO_HAVE_short_fetch_and_sub1_release
+#  endif
+#  if !defined(AO_HAVE_short_fetch_and_sub1_acquire)
+#    define AO_short_fetch_and_sub1_acquire(addr) \
+        AO_short_fetch_and_sub1_full(addr)
+#    define AO_HAVE_short_fetch_and_sub1_acquire
+#  endif
+#  if !defined(AO_HAVE_short_fetch_and_sub1_write)
+#    define AO_short_fetch_and_sub1_write(addr) \
+        AO_short_fetch_and_sub1_full(addr)
+#    define AO_HAVE_short_fetch_and_sub1_write
+#  endif
+#  if !defined(AO_HAVE_short_fetch_and_sub1_read)
+#    define AO_short_fetch_and_sub1_read(addr) \
+        AO_short_fetch_and_sub1_full(addr)
+#    define AO_HAVE_short_fetch_and_sub1_read
+#  endif
+#endif /* AO_HAVE_short_fetch_and_sub1_full */
+
+#if !defined(AO_HAVE_short_fetch_and_sub1) && \
+    defined(AO_HAVE_short_fetch_and_sub1_release)
+#  define AO_short_fetch_and_sub1(addr) \
+       AO_short_fetch_and_sub1_release(addr)
+#  define AO_HAVE_short_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_short_fetch_and_sub1) && \
+    defined(AO_HAVE_short_fetch_and_sub1_acquire)
+#  define AO_short_fetch_and_sub1(addr) \
+       AO_short_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_short_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_short_fetch_and_sub1) && \
+    defined(AO_HAVE_short_fetch_and_sub1_write)
+#  define AO_short_fetch_and_sub1(addr) \
+       AO_short_fetch_and_sub1_write(addr)
+#  define AO_HAVE_short_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_short_fetch_and_sub1) && \
+    defined(AO_HAVE_short_fetch_and_sub1_read)
+#  define AO_short_fetch_and_sub1(addr) \
+       AO_short_fetch_and_sub1_read(addr)
+#  define AO_HAVE_short_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_short_fetch_and_sub1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_short_fetch_and_sub1_full)
+#  define AO_short_fetch_and_sub1_full(addr) \
+       (AO_nop_full(), AO_short_fetch_and_sub1_acquire(addr))
+#  define AO_HAVE_short_fetch_and_sub1_full
+#endif
+
+#if !defined(AO_HAVE_short_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_short_fetch_and_sub1_write)
+#  define AO_short_fetch_and_sub1_release_write(addr) \
+       AO_short_fetch_and_sub1_write(addr)
+#  define AO_HAVE_short_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_short_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_short_fetch_and_sub1_release)
+#  define AO_short_fetch_and_sub1_release_write(addr) \
+       AO_short_fetch_and_sub1_release(addr)
+#  define AO_HAVE_short_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_short_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_short_fetch_and_sub1_read)
+#  define AO_short_fetch_and_sub1_acquire_read(addr) \
+       AO_short_fetch_and_sub1_read(addr)
+#  define AO_HAVE_short_fetch_and_sub1_acquire_read
+#endif
+#if !defined(AO_HAVE_short_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_short_fetch_and_sub1_acquire)
+#  define AO_short_fetch_and_sub1_acquire_read(addr) \
+       AO_short_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_short_fetch_and_sub1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_short_fetch_and_sub1_acquire_read)
+#    define AO_short_fetch_and_sub1_dd_acquire_read(addr) \
+       AO_short_fetch_and_sub1_acquire_read(addr)
+#    define AO_HAVE_short_fetch_and_sub1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_short_fetch_and_sub1)
+#    define AO_short_fetch_and_sub1_dd_acquire_read(addr) \
+       AO_short_fetch_and_sub1(addr)
+#    define AO_HAVE_short_fetch_and_sub1_dd_acquire_read
+#  endif
+#endif
+
+/* int_load */
+#if defined(AO_HAVE_int_load_acquire) && !defined(AO_HAVE_int_load)
+#  define AO_int_load(addr) AO_int_load_acquire(addr)
+#  define AO_HAVE_int_load
+#endif
+
+#if defined(AO_HAVE_int_load_full) && !defined(AO_HAVE_int_load_acquire)
+#  define AO_int_load_acquire(addr) AO_int_load_full(addr)
+#  define AO_HAVE_int_load_acquire
+#endif
+
+#if defined(AO_HAVE_int_load_full) && !defined(AO_HAVE_int_load_read)
+#  define AO_int_load_read(addr) AO_int_load_full(addr)
+#  define AO_HAVE_int_load_read
+#endif
+
+#if !defined(AO_HAVE_int_load_acquire_read) && defined(AO_HAVE_int_load_acquire)
+#  define AO_int_load_acquire_read(addr) AO_int_load_acquire(addr)
+#  define AO_HAVE_int_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_int_load) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_int_load_acquire)
+   AO_INLINE unsigned int
+   AO_int_load_acquire(volatile unsigned int *addr)
+   {
+     unsigned int result = AO_int_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_full();
+     return result;
+   }
+#  define AO_HAVE_int_load_acquire
+#endif
+
+#if defined(AO_HAVE_int_load) && defined(AO_HAVE_nop_read) && \
+    !defined(AO_HAVE_int_load_read)
+   AO_INLINE unsigned int
+   AO_int_load_read(volatile unsigned int *addr)
+   {
+     unsigned int result = AO_int_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_read();
+     return result;
+   }
+#  define AO_HAVE_int_load_read
+#endif
+
+#if defined(AO_HAVE_int_load_acquire) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_int_load_full)
+#  define AO_int_load_full(addr) (AO_nop_full(), AO_int_load_acquire(addr))
+#  define AO_HAVE_int_load_full
+#endif
+#if !defined(AO_HAVE_int_load_acquire_read) && defined(AO_HAVE_int_load_read)
+#  define AO_int_load_acquire_read(addr) AO_int_load_read(addr)
+#  define AO_HAVE_int_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_int_load_acquire_read) && !defined(AO_HAVE_int_load)
+#  define AO_int_load(addr) AO_int_load_acquire_read(addr)
+#  define AO_HAVE_int_load
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_int_load_acquire_read)
+#    define AO_int_load_dd_acquire_read(addr) \
+       AO_int_load_acquire_read(addr)
+#    define AO_HAVE_int_load_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_int_load)
+#    define AO_int_load_dd_acquire_read(addr) \
+       AO_int_load(addr)
+#    define AO_HAVE_int_load_dd_acquire_read
+#  endif
+#endif
+
+
+/* int_store */
+
+#if defined(AO_HAVE_int_store_release) && !defined(AO_HAVE_int_store)
+#  define AO_int_store(addr, val) AO_int_store_release(addr,val)
+#  define AO_HAVE_int_store
+#endif
+
+#if defined(AO_HAVE_int_store_full) && !defined(AO_HAVE_int_store_release)
+#  define AO_int_store_release(addr,val) AO_int_store_full(addr,val)
+#  define AO_HAVE_int_store_release
+#endif
+
+#if defined(AO_HAVE_int_store_full) && !defined(AO_HAVE_int_store_write)
+#  define AO_int_store_write(addr,val) AO_int_store_full(addr,val)
+#  define AO_HAVE_int_store_write
+#endif
+
+#if defined(AO_HAVE_int_store_release) && \
+       !defined(AO_HAVE_int_store_release_write)
+#  define AO_int_store_release_write(addr, val) \
+       AO_int_store_release(addr,val)
+#  define AO_HAVE_int_store_release_write
+#endif
+
+#if defined(AO_HAVE_int_store_write) && !defined(AO_HAVE_int_store)
+#  define AO_int_store(addr, val) AO_int_store_write(addr,val)
+#  define AO_HAVE_int_store
+#endif
+
+#if defined(AO_HAVE_int_store) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_int_store_release)
+#  define AO_int_store_release(addr,val) \
+       (AO_nop_full(), AO_int_store(addr,val))
+#  define AO_HAVE_int_store_release
+#endif
+
+#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_int_store) && \
+     !defined(AO_HAVE_int_store_write)
+#  define AO_int_store_write(addr, val) \
+       (AO_nop_write(), AO_int_store(addr,val))
+#  define AO_HAVE_int_store_write
+#endif
+
+#if defined(AO_HAVE_int_store_write) && \
+     !defined(AO_HAVE_int_store_release_write)
+#  define AO_int_store_release_write(addr, val) AO_int_store_write(addr,val)
+#  define AO_HAVE_int_store_release_write
+#endif
+
+#if defined(AO_HAVE_int_store_release) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_int_store_full)
+#  define AO_int_store_full(addr, val) \
+       (AO_int_store_release(addr, val), AO_nop_full())
+#  define AO_HAVE_int_store_full
+#endif
+
+
+/* int_fetch_and_add */
+#if defined(AO_HAVE_int_compare_and_swap_full) && \
+    !defined(AO_HAVE_int_fetch_and_add_full)
+   AO_INLINE AO_t
+   AO_int_fetch_and_add_full(volatile unsigned int *addr,
+                              unsigned int incr)
+   {
+     unsigned int old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_int_compare_and_swap_full(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_int_fetch_and_add_full
+#endif
+
+#if defined(AO_HAVE_int_compare_and_swap_acquire) && \
+    !defined(AO_HAVE_int_fetch_and_add_acquire)
+   AO_INLINE AO_t
+   AO_int_fetch_and_add_acquire(volatile unsigned int *addr,
+                                 unsigned int incr)
+   {
+     unsigned int old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_int_compare_and_swap_acquire(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_int_fetch_and_add_acquire
+#endif
+
+#if defined(AO_HAVE_int_compare_and_swap_release) && \
+    !defined(AO_HAVE_int_fetch_and_add_release)
+   AO_INLINE AO_t
+   AO_int_fetch_and_add_release(volatile unsigned int *addr,
+                                 unsigned int incr)
+   {
+     unsigned int old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_int_compare_and_swap_release(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_int_fetch_and_add_release
+#endif
+
+#if defined(AO_HAVE_int_fetch_and_add_full)
+#  if !defined(AO_HAVE_int_fetch_and_add_release)
+#    define AO_int_fetch_and_add_release(addr, val) \
+        AO_int_fetch_and_add_full(addr, val)
+#    define AO_HAVE_int_fetch_and_add_release
+#  endif
+#  if !defined(AO_HAVE_int_fetch_and_add_acquire)
+#    define AO_int_fetch_and_add_acquire(addr, val) \
+        AO_int_fetch_and_add_full(addr, val)
+#    define AO_HAVE_int_fetch_and_add_acquire
+#  endif
+#  if !defined(AO_HAVE_int_fetch_and_add_write)
+#    define AO_int_fetch_and_add_write(addr, val) \
+        AO_int_fetch_and_add_full(addr, val)
+#    define AO_HAVE_int_fetch_and_add_write
+#  endif
+#  if !defined(AO_HAVE_int_fetch_and_add_read)
+#    define AO_int_fetch_and_add_read(addr, val) \
+        AO_int_fetch_and_add_full(addr, val)
+#    define AO_HAVE_int_fetch_and_add_read
+#  endif
+#endif /* AO_HAVE_int_fetch_and_add_full */
+
+#if !defined(AO_HAVE_int_fetch_and_add) && \
+    defined(AO_HAVE_int_fetch_and_add_release)
+#  define AO_int_fetch_and_add(addr, val) \
+       AO_int_fetch_and_add_release(addr, val)
+#  define AO_HAVE_int_fetch_and_add
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add) && \
+    defined(AO_HAVE_int_fetch_and_add_acquire)
+#  define AO_int_fetch_and_add(addr, val) \
+       AO_int_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_int_fetch_and_add
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add) && \
+    defined(AO_HAVE_int_fetch_and_add_write)
+#  define AO_int_fetch_and_add(addr, val) \
+       AO_int_fetch_and_add_write(addr, val)
+#  define AO_HAVE_int_fetch_and_add
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add) && \
+    defined(AO_HAVE_int_fetch_and_add_read)
+#  define AO_int_fetch_and_add(addr, val) \
+       AO_int_fetch_and_add_read(addr, val)
+#  define AO_HAVE_int_fetch_and_add
+#endif
+
+#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_int_fetch_and_add_full)
+#  define AO_int_fetch_and_add_full(addr, val) \
+       (AO_nop_full(), AO_int_fetch_and_add_acquire(addr, val))
+#endif
+
+#if !defined(AO_HAVE_int_fetch_and_add_release_write) && \
+    defined(AO_HAVE_int_fetch_and_add_write)
+#  define AO_int_fetch_and_add_release_write(addr, val) \
+       AO_int_fetch_and_add_write(addr, val)
+#  define AO_HAVE_int_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add_release_write) && \
+    defined(AO_HAVE_int_fetch_and_add_release)
+#  define AO_int_fetch_and_add_release_write(addr, val) \
+       AO_int_fetch_and_add_release(addr, val)
+#  define AO_HAVE_int_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_int_fetch_and_add_read)
+#  define AO_int_fetch_and_add_acquire_read(addr, val) \
+       AO_int_fetch_and_add_read(addr, val)
+#  define AO_HAVE_int_fetch_and_add_acquire_read
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_int_fetch_and_add_acquire)
+#  define AO_int_fetch_and_add_acquire_read(addr, val) \
+       AO_int_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_int_fetch_and_add_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_int_fetch_and_add_acquire_read)
+#    define AO_int_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_int_fetch_and_add_acquire_read(addr, val)
+#    define AO_HAVE_int_fetch_and_add_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_int_fetch_and_add)
+#    define AO_int_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_int_fetch_and_add(addr, val)
+#    define AO_HAVE_int_fetch_and_add_dd_acquire_read
+#  endif
+#endif
+  
+/* int_fetch_and_add1 */
+
+#if defined(AO_HAVE_int_fetch_and_add_full) &&\
+    !defined(AO_HAVE_int_fetch_and_add1_full)
+#  define AO_int_fetch_and_add1_full(addr) \
+       AO_int_fetch_and_add_full(addr,1)
+#  define AO_HAVE_int_fetch_and_add1_full
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_release) &&\
+    !defined(AO_HAVE_int_fetch_and_add1_release)
+#  define AO_int_fetch_and_add1_release(addr) \
+       AO_int_fetch_and_add_release(addr,1)
+#  define AO_HAVE_int_fetch_and_add1_release
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_int_fetch_and_add1_acquire)
+#  define AO_int_fetch_and_add1_acquire(addr) \
+       AO_int_fetch_and_add_acquire(addr,1)
+#  define AO_HAVE_int_fetch_and_add1_acquire
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_write) &&\
+    !defined(AO_HAVE_int_fetch_and_add1_write)
+#  define AO_int_fetch_and_add1_write(addr) \
+       AO_int_fetch_and_add_write(addr,1)
+#  define AO_HAVE_int_fetch_and_add1_write
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_read) &&\
+    !defined(AO_HAVE_int_fetch_and_add1_read)
+#  define AO_int_fetch_and_add1_read(addr) \
+       AO_int_fetch_and_add_read(addr,1)
+#  define AO_HAVE_int_fetch_and_add1_read
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_int_fetch_and_add1_release_write)
+#  define AO_int_fetch_and_add1_release_write(addr) \
+       AO_int_fetch_and_add_release_write(addr,1)
+#  define AO_HAVE_int_fetch_and_add1_release_write
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_int_fetch_and_add1_acquire_read)
+#  define AO_int_fetch_and_add1_acquire_read(addr) \
+       AO_int_fetch_and_add_acquire_read(addr,1)
+#  define AO_HAVE_int_fetch_and_add1_acquire_read
+#endif
+#if defined(AO_HAVE_int_fetch_and_add) &&\
+    !defined(AO_HAVE_int_fetch_and_add1)
+#  define AO_int_fetch_and_add1(addr) \
+       AO_int_fetch_and_add(addr,1)
+#  define AO_HAVE_int_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_int_fetch_and_add1_full)
+#  if !defined(AO_HAVE_int_fetch_and_add1_release)
+#    define AO_int_fetch_and_add1_release(addr) \
+        AO_int_fetch_and_add1_full(addr)
+#    define AO_HAVE_int_fetch_and_add1_release
+#  endif
+#  if !defined(AO_HAVE_int_fetch_and_add1_acquire)
+#    define AO_int_fetch_and_add1_acquire(addr) \
+        AO_int_fetch_and_add1_full(addr)
+#    define AO_HAVE_int_fetch_and_add1_acquire
+#  endif
+#  if !defined(AO_HAVE_int_fetch_and_add1_write)
+#    define AO_int_fetch_and_add1_write(addr) \
+        AO_int_fetch_and_add1_full(addr)
+#    define AO_HAVE_int_fetch_and_add1_write
+#  endif
+#  if !defined(AO_HAVE_int_fetch_and_add1_read)
+#    define AO_int_fetch_and_add1_read(addr) \
+        AO_int_fetch_and_add1_full(addr)
+#    define AO_HAVE_int_fetch_and_add1_read
+#  endif
+#endif /* AO_HAVE_int_fetch_and_add1_full */
+
+#if !defined(AO_HAVE_int_fetch_and_add1) && \
+    defined(AO_HAVE_int_fetch_and_add1_release)
+#  define AO_int_fetch_and_add1(addr) \
+       AO_int_fetch_and_add1_release(addr)
+#  define AO_HAVE_int_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add1) && \
+    defined(AO_HAVE_int_fetch_and_add1_acquire)
+#  define AO_int_fetch_and_add1(addr) \
+       AO_int_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_int_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add1) && \
+    defined(AO_HAVE_int_fetch_and_add1_write)
+#  define AO_int_fetch_and_add1(addr) \
+       AO_int_fetch_and_add1_write(addr)
+#  define AO_HAVE_int_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add1) && \
+    defined(AO_HAVE_int_fetch_and_add1_read)
+#  define AO_int_fetch_and_add1(addr) \
+       AO_int_fetch_and_add1_read(addr)
+#  define AO_HAVE_int_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_int_fetch_and_add1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_int_fetch_and_add1_full)
+#  define AO_int_fetch_and_add1_full(addr) \
+       (AO_nop_full(), AO_int_fetch_and_add1_acquire(addr))
+#  define AO_HAVE_int_fetch_and_add1_full
+#endif
+
+#if !defined(AO_HAVE_int_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_int_fetch_and_add1_write)
+#  define AO_int_fetch_and_add1_release_write(addr) \
+       AO_int_fetch_and_add1_write(addr)
+#  define AO_HAVE_int_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_int_fetch_and_add1_release)
+#  define AO_int_fetch_and_add1_release_write(addr) \
+       AO_int_fetch_and_add1_release(addr)
+#  define AO_HAVE_int_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_int_fetch_and_add1_read)
+#  define AO_int_fetch_and_add1_acquire_read(addr) \
+       AO_int_fetch_and_add1_read(addr)
+#  define AO_HAVE_int_fetch_and_add1_acquire_read
+#endif
+#if !defined(AO_HAVE_int_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_int_fetch_and_add1_acquire)
+#  define AO_int_fetch_and_add1_acquire_read(addr) \
+       AO_int_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_int_fetch_and_add1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_int_fetch_and_add1_acquire_read)
+#    define AO_int_fetch_and_add1_dd_acquire_read(addr) \
+       AO_int_fetch_and_add1_acquire_read(addr)
+#    define AO_HAVE_int_fetch_and_add1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_int_fetch_and_add1)
+#    define AO_int_fetch_and_add1_dd_acquire_read(addr) \
+       AO_int_fetch_and_add1(addr)
+#    define AO_HAVE_int_fetch_and_add1_dd_acquire_read
+#  endif
+#endif
+
+/* int_fetch_and_sub1 */
+
+#if defined(AO_HAVE_int_fetch_and_add_full) &&\
+    !defined(AO_HAVE_int_fetch_and_sub1_full)
+#  define AO_int_fetch_and_sub1_full(addr) \
+       AO_int_fetch_and_add_full(addr,(unsigned int)(-1))
+#  define AO_HAVE_int_fetch_and_sub1_full
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_release) &&\
+    !defined(AO_HAVE_int_fetch_and_sub1_release)
+#  define AO_int_fetch_and_sub1_release(addr) \
+       AO_int_fetch_and_add_release(addr,(unsigned int)(-1))
+#  define AO_HAVE_int_fetch_and_sub1_release
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_int_fetch_and_sub1_acquire)
+#  define AO_int_fetch_and_sub1_acquire(addr) \
+       AO_int_fetch_and_add_acquire(addr,(unsigned int)(-1))
+#  define AO_HAVE_int_fetch_and_sub1_acquire
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_write) &&\
+    !defined(AO_HAVE_int_fetch_and_sub1_write)
+#  define AO_int_fetch_and_sub1_write(addr) \
+       AO_int_fetch_and_add_write(addr,(unsigned int)(-1))
+#  define AO_HAVE_int_fetch_and_sub1_write
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_read) &&\
+    !defined(AO_HAVE_int_fetch_and_sub1_read)
+#  define AO_int_fetch_and_sub1_read(addr) \
+       AO_int_fetch_and_add_read(addr,(unsigned int)(-1))
+#  define AO_HAVE_int_fetch_and_sub1_read
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_int_fetch_and_sub1_release_write)
+#  define AO_int_fetch_and_sub1_release_write(addr) \
+       AO_int_fetch_and_add_release_write(addr,(unsigned int)(-1))
+#  define AO_HAVE_int_fetch_and_sub1_release_write
+#endif
+#if defined(AO_HAVE_int_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_int_fetch_and_sub1_acquire_read)
+#  define AO_int_fetch_and_sub1_acquire_read(addr) \
+       AO_int_fetch_and_add_acquire_read(addr,(unsigned int)(-1))
+#  define AO_HAVE_int_fetch_and_sub1_acquire_read
+#endif
+#if defined(AO_HAVE_int_fetch_and_add) &&\
+    !defined(AO_HAVE_int_fetch_and_sub1)
+#  define AO_int_fetch_and_sub1(addr) \
+       AO_int_fetch_and_add(addr,(unsigned int)(-1))
+#  define AO_HAVE_int_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_int_fetch_and_sub1_full)
+#  if !defined(AO_HAVE_int_fetch_and_sub1_release)
+#    define AO_int_fetch_and_sub1_release(addr) \
+        AO_int_fetch_and_sub1_full(addr)
+#    define AO_HAVE_int_fetch_and_sub1_release
+#  endif
+#  if !defined(AO_HAVE_int_fetch_and_sub1_acquire)
+#    define AO_int_fetch_and_sub1_acquire(addr) \
+        AO_int_fetch_and_sub1_full(addr)
+#    define AO_HAVE_int_fetch_and_sub1_acquire
+#  endif
+#  if !defined(AO_HAVE_int_fetch_and_sub1_write)
+#    define AO_int_fetch_and_sub1_write(addr) \
+        AO_int_fetch_and_sub1_full(addr)
+#    define AO_HAVE_int_fetch_and_sub1_write
+#  endif
+#  if !defined(AO_HAVE_int_fetch_and_sub1_read)
+#    define AO_int_fetch_and_sub1_read(addr) \
+        AO_int_fetch_and_sub1_full(addr)
+#    define AO_HAVE_int_fetch_and_sub1_read
+#  endif
+#endif /* AO_HAVE_int_fetch_and_sub1_full */
+
+#if !defined(AO_HAVE_int_fetch_and_sub1) && \
+    defined(AO_HAVE_int_fetch_and_sub1_release)
+#  define AO_int_fetch_and_sub1(addr) \
+       AO_int_fetch_and_sub1_release(addr)
+#  define AO_HAVE_int_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_int_fetch_and_sub1) && \
+    defined(AO_HAVE_int_fetch_and_sub1_acquire)
+#  define AO_int_fetch_and_sub1(addr) \
+       AO_int_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_int_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_int_fetch_and_sub1) && \
+    defined(AO_HAVE_int_fetch_and_sub1_write)
+#  define AO_int_fetch_and_sub1(addr) \
+       AO_int_fetch_and_sub1_write(addr)
+#  define AO_HAVE_int_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_int_fetch_and_sub1) && \
+    defined(AO_HAVE_int_fetch_and_sub1_read)
+#  define AO_int_fetch_and_sub1(addr) \
+       AO_int_fetch_and_sub1_read(addr)
+#  define AO_HAVE_int_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_int_fetch_and_sub1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_int_fetch_and_sub1_full)
+#  define AO_int_fetch_and_sub1_full(addr) \
+       (AO_nop_full(), AO_int_fetch_and_sub1_acquire(addr))
+#  define AO_HAVE_int_fetch_and_sub1_full
+#endif
+
+#if !defined(AO_HAVE_int_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_int_fetch_and_sub1_write)
+#  define AO_int_fetch_and_sub1_release_write(addr) \
+       AO_int_fetch_and_sub1_write(addr)
+#  define AO_HAVE_int_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_int_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_int_fetch_and_sub1_release)
+#  define AO_int_fetch_and_sub1_release_write(addr) \
+       AO_int_fetch_and_sub1_release(addr)
+#  define AO_HAVE_int_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_int_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_int_fetch_and_sub1_read)
+#  define AO_int_fetch_and_sub1_acquire_read(addr) \
+       AO_int_fetch_and_sub1_read(addr)
+#  define AO_HAVE_int_fetch_and_sub1_acquire_read
+#endif
+#if !defined(AO_HAVE_int_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_int_fetch_and_sub1_acquire)
+#  define AO_int_fetch_and_sub1_acquire_read(addr) \
+       AO_int_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_int_fetch_and_sub1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_int_fetch_and_sub1_acquire_read)
+#    define AO_int_fetch_and_sub1_dd_acquire_read(addr) \
+       AO_int_fetch_and_sub1_acquire_read(addr)
+#    define AO_HAVE_int_fetch_and_sub1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_int_fetch_and_sub1)
+#    define AO_int_fetch_and_sub1_dd_acquire_read(addr) \
+       AO_int_fetch_and_sub1(addr)
+#    define AO_HAVE_int_fetch_and_sub1_dd_acquire_read
+#  endif
+#endif
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize-small.template b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize-small.template
new file mode 100644 (file)
index 0000000..b7e02b0
--- /dev/null
@@ -0,0 +1,575 @@
+/* XSIZE_load */
+#if defined(AO_HAVE_XSIZE_load_acquire) && !defined(AO_HAVE_XSIZE_load)
+#  define AO_XSIZE_load(addr) AO_XSIZE_load_acquire(addr)
+#  define AO_HAVE_XSIZE_load
+#endif
+
+#if defined(AO_HAVE_XSIZE_load_full) && !defined(AO_HAVE_XSIZE_load_acquire)
+#  define AO_XSIZE_load_acquire(addr) AO_XSIZE_load_full(addr)
+#  define AO_HAVE_XSIZE_load_acquire
+#endif
+
+#if defined(AO_HAVE_XSIZE_load_full) && !defined(AO_HAVE_XSIZE_load_read)
+#  define AO_XSIZE_load_read(addr) AO_XSIZE_load_full(addr)
+#  define AO_HAVE_XSIZE_load_read
+#endif
+
+#if !defined(AO_HAVE_XSIZE_load_acquire_read) && defined(AO_HAVE_XSIZE_load_acquire)
+#  define AO_XSIZE_load_acquire_read(addr) AO_XSIZE_load_acquire(addr)
+#  define AO_HAVE_XSIZE_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_XSIZE_load) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_XSIZE_load_acquire)
+   AO_INLINE unsigned XCTYPE
+   AO_XSIZE_load_acquire(volatile unsigned XCTYPE *addr)
+   {
+     unsigned XCTYPE result = AO_XSIZE_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_full();
+     return result;
+   }
+#  define AO_HAVE_XSIZE_load_acquire
+#endif
+
+#if defined(AO_HAVE_XSIZE_load) && defined(AO_HAVE_nop_read) && \
+    !defined(AO_HAVE_XSIZE_load_read)
+   AO_INLINE unsigned XCTYPE
+   AO_XSIZE_load_read(volatile unsigned XCTYPE *addr)
+   {
+     unsigned XCTYPE result = AO_XSIZE_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_read();
+     return result;
+   }
+#  define AO_HAVE_XSIZE_load_read
+#endif
+
+#if defined(AO_HAVE_XSIZE_load_acquire) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_XSIZE_load_full)
+#  define AO_XSIZE_load_full(addr) (AO_nop_full(), AO_XSIZE_load_acquire(addr))
+#  define AO_HAVE_XSIZE_load_full
+#endif
+#if !defined(AO_HAVE_XSIZE_load_acquire_read) && defined(AO_HAVE_XSIZE_load_read)
+#  define AO_XSIZE_load_acquire_read(addr) AO_XSIZE_load_read(addr)
+#  define AO_HAVE_XSIZE_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_XSIZE_load_acquire_read) && !defined(AO_HAVE_XSIZE_load)
+#  define AO_XSIZE_load(addr) AO_XSIZE_load_acquire_read(addr)
+#  define AO_HAVE_XSIZE_load
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_XSIZE_load_acquire_read)
+#    define AO_XSIZE_load_dd_acquire_read(addr) \
+       AO_XSIZE_load_acquire_read(addr)
+#    define AO_HAVE_XSIZE_load_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_XSIZE_load)
+#    define AO_XSIZE_load_dd_acquire_read(addr) \
+       AO_XSIZE_load(addr)
+#    define AO_HAVE_XSIZE_load_dd_acquire_read
+#  endif
+#endif
+
+
+/* XSIZE_store */
+
+#if defined(AO_HAVE_XSIZE_store_release) && !defined(AO_HAVE_XSIZE_store)
+#  define AO_XSIZE_store(addr, val) AO_XSIZE_store_release(addr,val)
+#  define AO_HAVE_XSIZE_store
+#endif
+
+#if defined(AO_HAVE_XSIZE_store_full) && !defined(AO_HAVE_XSIZE_store_release)
+#  define AO_XSIZE_store_release(addr,val) AO_XSIZE_store_full(addr,val)
+#  define AO_HAVE_XSIZE_store_release
+#endif
+
+#if defined(AO_HAVE_XSIZE_store_full) && !defined(AO_HAVE_XSIZE_store_write)
+#  define AO_XSIZE_store_write(addr,val) AO_XSIZE_store_full(addr,val)
+#  define AO_HAVE_XSIZE_store_write
+#endif
+
+#if defined(AO_HAVE_XSIZE_store_release) && \
+       !defined(AO_HAVE_XSIZE_store_release_write)
+#  define AO_XSIZE_store_release_write(addr, val) \
+       AO_XSIZE_store_release(addr,val)
+#  define AO_HAVE_XSIZE_store_release_write
+#endif
+
+#if defined(AO_HAVE_XSIZE_store_write) && !defined(AO_HAVE_XSIZE_store)
+#  define AO_XSIZE_store(addr, val) AO_XSIZE_store_write(addr,val)
+#  define AO_HAVE_XSIZE_store
+#endif
+
+#if defined(AO_HAVE_XSIZE_store) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_XSIZE_store_release)
+#  define AO_XSIZE_store_release(addr,val) \
+       (AO_nop_full(), AO_XSIZE_store(addr,val))
+#  define AO_HAVE_XSIZE_store_release
+#endif
+
+#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_XSIZE_store) && \
+     !defined(AO_HAVE_XSIZE_store_write)
+#  define AO_XSIZE_store_write(addr, val) \
+       (AO_nop_write(), AO_XSIZE_store(addr,val))
+#  define AO_HAVE_XSIZE_store_write
+#endif
+
+#if defined(AO_HAVE_XSIZE_store_write) && \
+     !defined(AO_HAVE_XSIZE_store_release_write)
+#  define AO_XSIZE_store_release_write(addr, val) AO_XSIZE_store_write(addr,val)
+#  define AO_HAVE_XSIZE_store_release_write
+#endif
+
+#if defined(AO_HAVE_XSIZE_store_release) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_XSIZE_store_full)
+#  define AO_XSIZE_store_full(addr, val) \
+       (AO_XSIZE_store_release(addr, val), AO_nop_full())
+#  define AO_HAVE_XSIZE_store_full
+#endif
+
+
+/* XSIZE_fetch_and_add */
+#if defined(AO_HAVE_XSIZE_compare_and_swap_full) && \
+    !defined(AO_HAVE_XSIZE_fetch_and_add_full)
+   AO_INLINE AO_t
+   AO_XSIZE_fetch_and_add_full(volatile unsigned XCTYPE *addr,
+                              unsigned XCTYPE incr)
+   {
+     unsigned XCTYPE old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_XSIZE_compare_and_swap_full(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_XSIZE_fetch_and_add_full
+#endif
+
+#if defined(AO_HAVE_XSIZE_compare_and_swap_acquire) && \
+    !defined(AO_HAVE_XSIZE_fetch_and_add_acquire)
+   AO_INLINE AO_t
+   AO_XSIZE_fetch_and_add_acquire(volatile unsigned XCTYPE *addr,
+                                 unsigned XCTYPE incr)
+   {
+     unsigned XCTYPE old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_XSIZE_compare_and_swap_acquire(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_XSIZE_fetch_and_add_acquire
+#endif
+
+#if defined(AO_HAVE_XSIZE_compare_and_swap_release) && \
+    !defined(AO_HAVE_XSIZE_fetch_and_add_release)
+   AO_INLINE AO_t
+   AO_XSIZE_fetch_and_add_release(volatile unsigned XCTYPE *addr,
+                                 unsigned XCTYPE incr)
+   {
+     unsigned XCTYPE old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_XSIZE_compare_and_swap_release(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_XSIZE_fetch_and_add_release
+#endif
+
+#if defined(AO_HAVE_XSIZE_fetch_and_add_full)
+#  if !defined(AO_HAVE_XSIZE_fetch_and_add_release)
+#    define AO_XSIZE_fetch_and_add_release(addr, val) \
+        AO_XSIZE_fetch_and_add_full(addr, val)
+#    define AO_HAVE_XSIZE_fetch_and_add_release
+#  endif
+#  if !defined(AO_HAVE_XSIZE_fetch_and_add_acquire)
+#    define AO_XSIZE_fetch_and_add_acquire(addr, val) \
+        AO_XSIZE_fetch_and_add_full(addr, val)
+#    define AO_HAVE_XSIZE_fetch_and_add_acquire
+#  endif
+#  if !defined(AO_HAVE_XSIZE_fetch_and_add_write)
+#    define AO_XSIZE_fetch_and_add_write(addr, val) \
+        AO_XSIZE_fetch_and_add_full(addr, val)
+#    define AO_HAVE_XSIZE_fetch_and_add_write
+#  endif
+#  if !defined(AO_HAVE_XSIZE_fetch_and_add_read)
+#    define AO_XSIZE_fetch_and_add_read(addr, val) \
+        AO_XSIZE_fetch_and_add_full(addr, val)
+#    define AO_HAVE_XSIZE_fetch_and_add_read
+#  endif
+#endif /* AO_HAVE_XSIZE_fetch_and_add_full */
+
+#if !defined(AO_HAVE_XSIZE_fetch_and_add) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add_release)
+#  define AO_XSIZE_fetch_and_add(addr, val) \
+       AO_XSIZE_fetch_and_add_release(addr, val)
+#  define AO_HAVE_XSIZE_fetch_and_add
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add_acquire)
+#  define AO_XSIZE_fetch_and_add(addr, val) \
+       AO_XSIZE_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_XSIZE_fetch_and_add
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add_write)
+#  define AO_XSIZE_fetch_and_add(addr, val) \
+       AO_XSIZE_fetch_and_add_write(addr, val)
+#  define AO_HAVE_XSIZE_fetch_and_add
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add_read)
+#  define AO_XSIZE_fetch_and_add(addr, val) \
+       AO_XSIZE_fetch_and_add_read(addr, val)
+#  define AO_HAVE_XSIZE_fetch_and_add
+#endif
+
+#if defined(AO_HAVE_XSIZE_fetch_and_add_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_XSIZE_fetch_and_add_full)
+#  define AO_XSIZE_fetch_and_add_full(addr, val) \
+       (AO_nop_full(), AO_XSIZE_fetch_and_add_acquire(addr, val))
+#endif
+
+#if !defined(AO_HAVE_XSIZE_fetch_and_add_release_write) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add_write)
+#  define AO_XSIZE_fetch_and_add_release_write(addr, val) \
+       AO_XSIZE_fetch_and_add_write(addr, val)
+#  define AO_HAVE_XSIZE_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add_release_write) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add_release)
+#  define AO_XSIZE_fetch_and_add_release_write(addr, val) \
+       AO_XSIZE_fetch_and_add_release(addr, val)
+#  define AO_HAVE_XSIZE_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add_read)
+#  define AO_XSIZE_fetch_and_add_acquire_read(addr, val) \
+       AO_XSIZE_fetch_and_add_read(addr, val)
+#  define AO_HAVE_XSIZE_fetch_and_add_acquire_read
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add_acquire)
+#  define AO_XSIZE_fetch_and_add_acquire_read(addr, val) \
+       AO_XSIZE_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_XSIZE_fetch_and_add_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_XSIZE_fetch_and_add_acquire_read)
+#    define AO_XSIZE_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_XSIZE_fetch_and_add_acquire_read(addr, val)
+#    define AO_HAVE_XSIZE_fetch_and_add_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_XSIZE_fetch_and_add)
+#    define AO_XSIZE_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_XSIZE_fetch_and_add(addr, val)
+#    define AO_HAVE_XSIZE_fetch_and_add_dd_acquire_read
+#  endif
+#endif
+  
+/* XSIZE_fetch_and_add1 */
+
+#if defined(AO_HAVE_XSIZE_fetch_and_add_full) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_add1_full)
+#  define AO_XSIZE_fetch_and_add1_full(addr) \
+       AO_XSIZE_fetch_and_add_full(addr,1)
+#  define AO_HAVE_XSIZE_fetch_and_add1_full
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_release) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_add1_release)
+#  define AO_XSIZE_fetch_and_add1_release(addr) \
+       AO_XSIZE_fetch_and_add_release(addr,1)
+#  define AO_HAVE_XSIZE_fetch_and_add1_release
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_add1_acquire)
+#  define AO_XSIZE_fetch_and_add1_acquire(addr) \
+       AO_XSIZE_fetch_and_add_acquire(addr,1)
+#  define AO_HAVE_XSIZE_fetch_and_add1_acquire
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_write) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_add1_write)
+#  define AO_XSIZE_fetch_and_add1_write(addr) \
+       AO_XSIZE_fetch_and_add_write(addr,1)
+#  define AO_HAVE_XSIZE_fetch_and_add1_write
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_read) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_add1_read)
+#  define AO_XSIZE_fetch_and_add1_read(addr) \
+       AO_XSIZE_fetch_and_add_read(addr,1)
+#  define AO_HAVE_XSIZE_fetch_and_add1_read
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_add1_release_write)
+#  define AO_XSIZE_fetch_and_add1_release_write(addr) \
+       AO_XSIZE_fetch_and_add_release_write(addr,1)
+#  define AO_HAVE_XSIZE_fetch_and_add1_release_write
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_add1_acquire_read)
+#  define AO_XSIZE_fetch_and_add1_acquire_read(addr) \
+       AO_XSIZE_fetch_and_add_acquire_read(addr,1)
+#  define AO_HAVE_XSIZE_fetch_and_add1_acquire_read
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_add1)
+#  define AO_XSIZE_fetch_and_add1(addr) \
+       AO_XSIZE_fetch_and_add(addr,1)
+#  define AO_HAVE_XSIZE_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_XSIZE_fetch_and_add1_full)
+#  if !defined(AO_HAVE_XSIZE_fetch_and_add1_release)
+#    define AO_XSIZE_fetch_and_add1_release(addr) \
+        AO_XSIZE_fetch_and_add1_full(addr)
+#    define AO_HAVE_XSIZE_fetch_and_add1_release
+#  endif
+#  if !defined(AO_HAVE_XSIZE_fetch_and_add1_acquire)
+#    define AO_XSIZE_fetch_and_add1_acquire(addr) \
+        AO_XSIZE_fetch_and_add1_full(addr)
+#    define AO_HAVE_XSIZE_fetch_and_add1_acquire
+#  endif
+#  if !defined(AO_HAVE_XSIZE_fetch_and_add1_write)
+#    define AO_XSIZE_fetch_and_add1_write(addr) \
+        AO_XSIZE_fetch_and_add1_full(addr)
+#    define AO_HAVE_XSIZE_fetch_and_add1_write
+#  endif
+#  if !defined(AO_HAVE_XSIZE_fetch_and_add1_read)
+#    define AO_XSIZE_fetch_and_add1_read(addr) \
+        AO_XSIZE_fetch_and_add1_full(addr)
+#    define AO_HAVE_XSIZE_fetch_and_add1_read
+#  endif
+#endif /* AO_HAVE_XSIZE_fetch_and_add1_full */
+
+#if !defined(AO_HAVE_XSIZE_fetch_and_add1) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add1_release)
+#  define AO_XSIZE_fetch_and_add1(addr) \
+       AO_XSIZE_fetch_and_add1_release(addr)
+#  define AO_HAVE_XSIZE_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add1) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add1_acquire)
+#  define AO_XSIZE_fetch_and_add1(addr) \
+       AO_XSIZE_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_XSIZE_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add1) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add1_write)
+#  define AO_XSIZE_fetch_and_add1(addr) \
+       AO_XSIZE_fetch_and_add1_write(addr)
+#  define AO_HAVE_XSIZE_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add1) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add1_read)
+#  define AO_XSIZE_fetch_and_add1(addr) \
+       AO_XSIZE_fetch_and_add1_read(addr)
+#  define AO_HAVE_XSIZE_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_XSIZE_fetch_and_add1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_XSIZE_fetch_and_add1_full)
+#  define AO_XSIZE_fetch_and_add1_full(addr) \
+       (AO_nop_full(), AO_XSIZE_fetch_and_add1_acquire(addr))
+#  define AO_HAVE_XSIZE_fetch_and_add1_full
+#endif
+
+#if !defined(AO_HAVE_XSIZE_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add1_write)
+#  define AO_XSIZE_fetch_and_add1_release_write(addr) \
+       AO_XSIZE_fetch_and_add1_write(addr)
+#  define AO_HAVE_XSIZE_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add1_release)
+#  define AO_XSIZE_fetch_and_add1_release_write(addr) \
+       AO_XSIZE_fetch_and_add1_release(addr)
+#  define AO_HAVE_XSIZE_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add1_read)
+#  define AO_XSIZE_fetch_and_add1_acquire_read(addr) \
+       AO_XSIZE_fetch_and_add1_read(addr)
+#  define AO_HAVE_XSIZE_fetch_and_add1_acquire_read
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_XSIZE_fetch_and_add1_acquire)
+#  define AO_XSIZE_fetch_and_add1_acquire_read(addr) \
+       AO_XSIZE_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_XSIZE_fetch_and_add1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_XSIZE_fetch_and_add1_acquire_read)
+#    define AO_XSIZE_fetch_and_add1_dd_acquire_read(addr) \
+       AO_XSIZE_fetch_and_add1_acquire_read(addr)
+#    define AO_HAVE_XSIZE_fetch_and_add1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_XSIZE_fetch_and_add1)
+#    define AO_XSIZE_fetch_and_add1_dd_acquire_read(addr) \
+       AO_XSIZE_fetch_and_add1(addr)
+#    define AO_HAVE_XSIZE_fetch_and_add1_dd_acquire_read
+#  endif
+#endif
+
+/* XSIZE_fetch_and_sub1 */
+
+#if defined(AO_HAVE_XSIZE_fetch_and_add_full) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_sub1_full)
+#  define AO_XSIZE_fetch_and_sub1_full(addr) \
+       AO_XSIZE_fetch_and_add_full(addr,(unsigned XCTYPE)(-1))
+#  define AO_HAVE_XSIZE_fetch_and_sub1_full
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_release) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_sub1_release)
+#  define AO_XSIZE_fetch_and_sub1_release(addr) \
+       AO_XSIZE_fetch_and_add_release(addr,(unsigned XCTYPE)(-1))
+#  define AO_HAVE_XSIZE_fetch_and_sub1_release
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_sub1_acquire)
+#  define AO_XSIZE_fetch_and_sub1_acquire(addr) \
+       AO_XSIZE_fetch_and_add_acquire(addr,(unsigned XCTYPE)(-1))
+#  define AO_HAVE_XSIZE_fetch_and_sub1_acquire
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_write) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_sub1_write)
+#  define AO_XSIZE_fetch_and_sub1_write(addr) \
+       AO_XSIZE_fetch_and_add_write(addr,(unsigned XCTYPE)(-1))
+#  define AO_HAVE_XSIZE_fetch_and_sub1_write
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_read) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_sub1_read)
+#  define AO_XSIZE_fetch_and_sub1_read(addr) \
+       AO_XSIZE_fetch_and_add_read(addr,(unsigned XCTYPE)(-1))
+#  define AO_HAVE_XSIZE_fetch_and_sub1_read
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_sub1_release_write)
+#  define AO_XSIZE_fetch_and_sub1_release_write(addr) \
+       AO_XSIZE_fetch_and_add_release_write(addr,(unsigned XCTYPE)(-1))
+#  define AO_HAVE_XSIZE_fetch_and_sub1_release_write
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_sub1_acquire_read)
+#  define AO_XSIZE_fetch_and_sub1_acquire_read(addr) \
+       AO_XSIZE_fetch_and_add_acquire_read(addr,(unsigned XCTYPE)(-1))
+#  define AO_HAVE_XSIZE_fetch_and_sub1_acquire_read
+#endif
+#if defined(AO_HAVE_XSIZE_fetch_and_add) &&\
+    !defined(AO_HAVE_XSIZE_fetch_and_sub1)
+#  define AO_XSIZE_fetch_and_sub1(addr) \
+       AO_XSIZE_fetch_and_add(addr,(unsigned XCTYPE)(-1))
+#  define AO_HAVE_XSIZE_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_XSIZE_fetch_and_sub1_full)
+#  if !defined(AO_HAVE_XSIZE_fetch_and_sub1_release)
+#    define AO_XSIZE_fetch_and_sub1_release(addr) \
+        AO_XSIZE_fetch_and_sub1_full(addr)
+#    define AO_HAVE_XSIZE_fetch_and_sub1_release
+#  endif
+#  if !defined(AO_HAVE_XSIZE_fetch_and_sub1_acquire)
+#    define AO_XSIZE_fetch_and_sub1_acquire(addr) \
+        AO_XSIZE_fetch_and_sub1_full(addr)
+#    define AO_HAVE_XSIZE_fetch_and_sub1_acquire
+#  endif
+#  if !defined(AO_HAVE_XSIZE_fetch_and_sub1_write)
+#    define AO_XSIZE_fetch_and_sub1_write(addr) \
+        AO_XSIZE_fetch_and_sub1_full(addr)
+#    define AO_HAVE_XSIZE_fetch_and_sub1_write
+#  endif
+#  if !defined(AO_HAVE_XSIZE_fetch_and_sub1_read)
+#    define AO_XSIZE_fetch_and_sub1_read(addr) \
+        AO_XSIZE_fetch_and_sub1_full(addr)
+#    define AO_HAVE_XSIZE_fetch_and_sub1_read
+#  endif
+#endif /* AO_HAVE_XSIZE_fetch_and_sub1_full */
+
+#if !defined(AO_HAVE_XSIZE_fetch_and_sub1) && \
+    defined(AO_HAVE_XSIZE_fetch_and_sub1_release)
+#  define AO_XSIZE_fetch_and_sub1(addr) \
+       AO_XSIZE_fetch_and_sub1_release(addr)
+#  define AO_HAVE_XSIZE_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_sub1) && \
+    defined(AO_HAVE_XSIZE_fetch_and_sub1_acquire)
+#  define AO_XSIZE_fetch_and_sub1(addr) \
+       AO_XSIZE_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_XSIZE_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_sub1) && \
+    defined(AO_HAVE_XSIZE_fetch_and_sub1_write)
+#  define AO_XSIZE_fetch_and_sub1(addr) \
+       AO_XSIZE_fetch_and_sub1_write(addr)
+#  define AO_HAVE_XSIZE_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_sub1) && \
+    defined(AO_HAVE_XSIZE_fetch_and_sub1_read)
+#  define AO_XSIZE_fetch_and_sub1(addr) \
+       AO_XSIZE_fetch_and_sub1_read(addr)
+#  define AO_HAVE_XSIZE_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_XSIZE_fetch_and_sub1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_XSIZE_fetch_and_sub1_full)
+#  define AO_XSIZE_fetch_and_sub1_full(addr) \
+       (AO_nop_full(), AO_XSIZE_fetch_and_sub1_acquire(addr))
+#  define AO_HAVE_XSIZE_fetch_and_sub1_full
+#endif
+
+#if !defined(AO_HAVE_XSIZE_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_XSIZE_fetch_and_sub1_write)
+#  define AO_XSIZE_fetch_and_sub1_release_write(addr) \
+       AO_XSIZE_fetch_and_sub1_write(addr)
+#  define AO_HAVE_XSIZE_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_XSIZE_fetch_and_sub1_release)
+#  define AO_XSIZE_fetch_and_sub1_release_write(addr) \
+       AO_XSIZE_fetch_and_sub1_release(addr)
+#  define AO_HAVE_XSIZE_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_XSIZE_fetch_and_sub1_read)
+#  define AO_XSIZE_fetch_and_sub1_acquire_read(addr) \
+       AO_XSIZE_fetch_and_sub1_read(addr)
+#  define AO_HAVE_XSIZE_fetch_and_sub1_acquire_read
+#endif
+#if !defined(AO_HAVE_XSIZE_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_XSIZE_fetch_and_sub1_acquire)
+#  define AO_XSIZE_fetch_and_sub1_acquire_read(addr) \
+       AO_XSIZE_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_XSIZE_fetch_and_sub1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_XSIZE_fetch_and_sub1_acquire_read)
+#    define AO_XSIZE_fetch_and_sub1_dd_acquire_read(addr) \
+       AO_XSIZE_fetch_and_sub1_acquire_read(addr)
+#    define AO_HAVE_XSIZE_fetch_and_sub1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_XSIZE_fetch_and_sub1)
+#    define AO_XSIZE_fetch_and_sub1_dd_acquire_read(addr) \
+       AO_XSIZE_fetch_and_sub1(addr)
+#    define AO_HAVE_XSIZE_fetch_and_sub1_dd_acquire_read
+#  endif
+#endif
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize.h
new file mode 100644 (file)
index 0000000..0f42b32
--- /dev/null
@@ -0,0 +1,1292 @@
+/*
+ * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * Generalize atomic operations for atomic_ops.h.
+ * Should not be included directly.
+ *
+ * We make no attempt to define useless operations, such as
+ * AO_nop_acquire
+ * AO_nop_release
+ *
+ * We have also so far neglected to define some others, which
+ * do not appear likely to be useful, e.g. stores with acquire
+ * or read barriers.
+ *
+ * This file is sometimes included twice by atomic_ops.h.
+ * All definitions include explicit checks that we are not replacing
+ * an earlier definition.  In general, more desirable expansions
+ * appear earlier so that we are more likely to use them.
+ *
+ * We only make safe generalizations, except that by default we define
+ * the ...dd_acquire_read operations to be equivalent to those without
+ * a barrier.  On platforms for which this is unsafe, the platform-specific
+ * file must define AO_NO_DD_ORDERING.
+ */
+
+#ifndef ATOMIC_OPS_H
+# error Atomic_ops_generalize.h should not be included directly.
+#endif
+
+#if AO_CHAR_TS_T
+# define AO_TS_COMPARE_AND_SWAP_FULL(a,o,n) \
+        AO_char_compare_and_swap_full(a,o,n)
+# define AO_TS_COMPARE_AND_SWAP_ACQUIRE(a,o,n) \
+        AO_char_compare_and_swap_acquire(a,o,n)
+# define AO_TS_COMPARE_AND_SWAP_RELEASE(a,o,n) \
+        AO_char_compare_and_swap_release(a,o,n)
+# define AO_TS_COMPARE_AND_SWAP(a,o,n) \
+        AO_char_compare_and_swap(a,o,n)
+#endif
+
+#if AO_AO_TS_T
+# define AO_TS_COMPARE_AND_SWAP_FULL(a,o,n) \
+        AO_compare_and_swap_full(a,o,n)
+# define AO_TS_COMPARE_AND_SWAP_ACQUIRE(a,o,n) \
+        AO_compare_and_swap_acquire(a,o,n)
+# define AO_TS_COMPARE_AND_SWAP_RELEASE(a,o,n) \
+        AO_compare_and_swap_release(a,o,n)
+# define AO_TS_COMPARE_AND_SWAP(a,o,n) \
+        AO_compare_and_swap(a,o,n)
+#endif
+
+/* Generate test_and_set_full, if necessary and possible.      */
+#if !defined(AO_HAVE_test_and_set) && \
+    !defined(AO_HAVE_test_and_set_release) && \
+    !defined(AO_HAVE_test_and_set_acquire) && \
+    !defined(AO_HAVE_test_and_set_read) && \
+    !defined(AO_HAVE_test_and_set_full)
+#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_full) || \
+      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_full)
+     AO_INLINE AO_TS_VAL_t
+     AO_test_and_set_full(volatile AO_TS_t *addr)
+     {
+       if (AO_TS_COMPARE_AND_SWAP_FULL(addr, AO_TS_CLEAR, AO_TS_SET))
+         return AO_TS_CLEAR;
+       else
+         return AO_TS_SET;
+     }
+#    define AO_HAVE_test_and_set_full
+#  endif /* AO_HAVE_compare_and_swap_full */
+
+#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_acquire) || \
+      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_acquire)
+     AO_INLINE AO_TS_VAL_t
+     AO_test_and_set_acquire(volatile AO_TS_t *addr)
+     {
+       if (AO_TS_COMPARE_AND_SWAP_ACQUIRE(addr, AO_TS_CLEAR, AO_TS_SET))
+         return AO_TS_CLEAR;
+       else
+         return AO_TS_SET;
+     }
+#    define AO_HAVE_test_and_set_acquire
+#  endif /* AO_HAVE_compare_and_swap_acquire */
+
+#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap_release) || \
+      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap_release)
+     AO_INLINE AO_TS_VAL_t
+     AO_test_and_set_release(volatile AO_TS_t *addr)
+     {
+       if (AO_TS_COMPARE_AND_SWAP_RELEASE(addr, AO_TS_CLEAR, AO_TS_SET))
+         return AO_TS_CLEAR;
+       else
+         return AO_TS_SET;
+     }
+#    define AO_HAVE_test_and_set_release
+#  endif /* AO_HAVE_compare_and_swap_release */
+
+#  if AO_AO_TS_T && defined(AO_HAVE_compare_and_swap) || \
+      AO_CHAR_TS_T && defined(AO_HAVE_char_compare_and_swap)
+     AO_INLINE AO_TS_VAL_t
+     AO_test_and_set(volatile AO_TS_t *addr)
+     {
+       if (AO_TS_COMPARE_AND_SWAP(addr, AO_TS_CLEAR, AO_TS_SET))
+         return AO_TS_CLEAR;
+       else
+         return AO_TS_SET;
+     }
+#    define AO_HAVE_test_and_set
+#  endif /* AO_HAVE_compare_and_swap */
+
+#  if defined(AO_HAVE_test_and_set) && defined(AO_HAVE_nop_full) \
+      && !defined(AO_HAVE_test_and_set_acquire)
+     AO_INLINE AO_TS_VAL_t
+     AO_test_and_set_acquire(volatile AO_TS_t *addr)
+     {
+       AO_TS_VAL_t result = AO_test_and_set(addr);
+       AO_nop_full();
+       return result;
+     }
+#    define AO_HAVE_test_and_set_acquire
+#  endif
+
+#endif /* No prior test and set */
+
+/* Nop */
+#if !defined(AO_HAVE_nop)
+   AO_INLINE void AO_nop(void) {}
+#  define AO_HAVE_nop
+#endif
+
+#if defined(AO_HAVE_test_and_set_full) && !defined(AO_HAVE_nop_full)
+   AO_INLINE void
+   AO_nop_full()
+   {
+     AO_TS_t dummy = AO_TS_INITIALIZER;
+     AO_test_and_set_full(&dummy);
+   }
+#  define AO_HAVE_nop_full
+#endif
+
+#if defined(AO_HAVE_nop_acquire)
+#  error AO_nop_acquire is useless: dont define.
+#endif
+#if defined(AO_HAVE_nop_release)
+#  error AO_nop_release is useless: dont define.
+#endif
+
+#if defined(AO_HAVE_nop_full) && !defined(AO_HAVE_nop_read)
+#  define AO_nop_read() AO_nop_full()
+#  define AO_HAVE_nop_read
+#endif
+
+#if defined(AO_HAVE_nop_full) && !defined(AO_HAVE_nop_write)
+#  define AO_nop_write() AO_nop_full()
+#  define AO_HAVE_nop_write
+#endif
+
+/* Load */
+#if defined(AO_HAVE_load_full) && !defined(AO_HAVE_load_acquire)
+#  define AO_load_acquire(addr) AO_load_full(addr)
+#  define AO_HAVE_load_acquire
+#endif
+
+#if defined(AO_HAVE_load_acquire) && !defined(AO_HAVE_load)
+#  define AO_load(addr) AO_load_acquire(addr)
+#  define AO_HAVE_load
+#endif
+
+#if defined(AO_HAVE_load_full) && !defined(AO_HAVE_load_read)
+#  define AO_load_read(addr) AO_load_full(addr)
+#  define AO_HAVE_load_read
+#endif
+
+#if !defined(AO_HAVE_load_acquire_read) && defined(AO_HAVE_load_acquire)
+#  define AO_load_acquire_read(addr) AO_load_acquire(addr)
+#  define AO_HAVE_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_load) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_load_acquire)
+   AO_INLINE AO_t
+   AO_load_acquire(volatile AO_t *addr)
+   {
+     AO_t result = AO_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_full();
+     return result;
+   }
+#  define AO_HAVE_load_acquire
+#endif
+
+#if defined(AO_HAVE_load) && defined(AO_HAVE_nop_read) && \
+    !defined(AO_HAVE_load_read)
+   AO_INLINE AO_t
+   AO_load_read(volatile AO_t *addr)
+   {
+     AO_t result = AO_load(addr);
+     /* Acquire barrier would be useless, since the load could be delayed  */
+     /* beyond it.                                                        */
+     AO_nop_read();
+     return result;
+   }
+#  define AO_HAVE_load_read
+#endif
+
+#if defined(AO_HAVE_load_acquire) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_load_full)
+#  define AO_load_full(addr) (AO_nop_full(), AO_load_acquire(addr))
+#  define AO_HAVE_load_full
+#endif
+#if !defined(AO_HAVE_load_acquire_read) && defined(AO_HAVE_load_read)
+#  define AO_load_acquire_read(addr) AO_load_read(addr)
+#  define AO_HAVE_load_acquire_read
+#endif
+
+#if defined(AO_HAVE_load_acquire_read) && !defined(AO_HAVE_load)
+#  define AO_load(addr) AO_load_acquire_read(addr)
+#  define AO_HAVE_load
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_load_acquire_read)
+#    define AO_load_dd_acquire_read(addr) AO_load_acquire_read(addr)
+#    define AO_HAVE_load_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_load)
+#    define AO_load_dd_acquire_read(addr) AO_load(addr)
+#    define AO_HAVE_load_dd_acquire_read
+#  endif
+#endif
+
+
+/* Store */
+
+#if defined(AO_HAVE_store_full) && !defined(AO_HAVE_store_release)
+#  define AO_store_release(addr,val) AO_store_full(addr,val)
+#  define AO_HAVE_store_release
+#endif
+
+#if defined(AO_HAVE_store_release) && !defined(AO_HAVE_store)
+#  define AO_store(addr, val) AO_store_release(addr,val)
+#  define AO_HAVE_store
+#endif
+
+#if defined(AO_HAVE_store_full) && !defined(AO_HAVE_store_write)
+#  define AO_store_write(addr,val) AO_store_full(addr,val)
+#  define AO_HAVE_store_write
+#endif
+
+#if defined(AO_HAVE_store_release) && !defined(AO_HAVE_store_release_write)
+#  define AO_store_release_write(addr, val) AO_store_release(addr,val)
+#  define AO_HAVE_store_release_write
+#endif
+
+#if defined(AO_HAVE_store_write) && !defined(AO_HAVE_store)
+#  define AO_store(addr, val) AO_store_write(addr,val)
+#  define AO_HAVE_store
+#endif
+
+#if defined(AO_HAVE_store) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_store_release)
+#  define AO_store_release(addr,val) (AO_nop_full(), AO_store(addr,val))
+#  define AO_HAVE_store_release
+#endif
+
+#if defined(AO_HAVE_nop_write) && defined(AO_HAVE_store) && \
+     !defined(AO_HAVE_store_write)
+#  define AO_store_write(addr, val) (AO_nop_write(), AO_store(addr,val))
+#  define AO_HAVE_store_write
+#endif
+
+#if defined(AO_HAVE_store_write) && !defined(AO_HAVE_store_release_write)
+#  define AO_store_release_write(addr, val) AO_store_write(addr,val)
+#  define AO_HAVE_store_release_write
+#endif
+
+#if defined(AO_HAVE_store_release) && defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_store_full)
+#  define AO_store_full(addr, val) (AO_store_release(addr, val), AO_nop_full())
+#  define AO_HAVE_store_full
+#endif
+
+  
+/* Fetch_and_add */
+/* We first try to implement fetch_and_add variants in terms   */
+/* of the corresponding compare_and_swap variants to minimize  */
+/* adding barriers.                                            */
+#if defined(AO_HAVE_compare_and_swap_full) && \
+    !defined(AO_HAVE_fetch_and_add_full)
+   AO_INLINE AO_t
+   AO_fetch_and_add_full(volatile AO_t *addr, AO_t incr)
+   {
+     AO_t old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_compare_and_swap_full(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_fetch_and_add_full
+#endif
+
+#if defined(AO_HAVE_compare_and_swap_acquire) && \
+    !defined(AO_HAVE_fetch_and_add_acquire)
+   AO_INLINE AO_t
+   AO_fetch_and_add_acquire(volatile AO_t *addr, AO_t incr)
+   {
+     AO_t old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_compare_and_swap_acquire(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_fetch_and_add_acquire
+#endif
+
+#if defined(AO_HAVE_compare_and_swap_release) && \
+    !defined(AO_HAVE_fetch_and_add_release)
+   AO_INLINE AO_t
+   AO_fetch_and_add_release(volatile AO_t *addr, AO_t incr)
+   {
+     AO_t old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_compare_and_swap_release(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_fetch_and_add_release
+#endif
+
+#if defined(AO_HAVE_compare_and_swap) && \
+    !defined(AO_HAVE_fetch_and_add)
+   AO_INLINE AO_t
+   AO_fetch_and_add(volatile AO_t *addr, AO_t incr)
+   {
+     AO_t old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_compare_and_swap(addr, old, old+incr));
+     return old;
+   }
+#  define AO_HAVE_fetch_and_add
+#endif
+
+#if defined(AO_HAVE_fetch_and_add_full)
+#  if !defined(AO_HAVE_fetch_and_add_release)
+#    define AO_fetch_and_add_release(addr, val) \
+        AO_fetch_and_add_full(addr, val)
+#    define AO_HAVE_fetch_and_add_release
+#  endif
+#  if !defined(AO_HAVE_fetch_and_add_acquire)
+#    define AO_fetch_and_add_acquire(addr, val) \
+        AO_fetch_and_add_full(addr, val)
+#    define AO_HAVE_fetch_and_add_acquire
+#  endif
+#  if !defined(AO_HAVE_fetch_and_add_write)
+#    define AO_fetch_and_add_write(addr, val) \
+        AO_fetch_and_add_full(addr, val)
+#    define AO_HAVE_fetch_and_add_write
+#  endif
+#  if !defined(AO_HAVE_fetch_and_add_read)
+#    define AO_fetch_and_add_read(addr, val) \
+        AO_fetch_and_add_full(addr, val)
+#    define AO_HAVE_fetch_and_add_read
+#  endif
+#endif /* AO_HAVE_fetch_and_add_full */
+
+#if !defined(AO_HAVE_fetch_and_add) && \
+    defined(AO_HAVE_fetch_and_add_release)
+#  define AO_fetch_and_add(addr, val) \
+       AO_fetch_and_add_release(addr, val)
+#  define AO_HAVE_fetch_and_add
+#endif
+#if !defined(AO_HAVE_fetch_and_add) && \
+    defined(AO_HAVE_fetch_and_add_acquire)
+#  define AO_fetch_and_add(addr, val) \
+       AO_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_fetch_and_add
+#endif
+#if !defined(AO_HAVE_fetch_and_add) && \
+    defined(AO_HAVE_fetch_and_add_write)
+#  define AO_fetch_and_add(addr, val) \
+       AO_fetch_and_add_write(addr, val)
+#  define AO_HAVE_fetch_and_add
+#endif
+#if !defined(AO_HAVE_fetch_and_add) && \
+    defined(AO_HAVE_fetch_and_add_read)
+#  define AO_fetch_and_add(addr, val) \
+       AO_fetch_and_add_read(addr, val)
+#  define AO_HAVE_fetch_and_add
+#endif
+
+#if defined(AO_HAVE_fetch_and_add_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_fetch_and_add_full)
+#  define AO_fetch_and_add_full(addr, val) \
+       (AO_nop_full(), AO_fetch_and_add_acquire(addr, val))
+#  define AO_HAVE_fetch_and_add_full
+#endif
+
+#if !defined(AO_HAVE_fetch_and_add_release_write) && \
+    defined(AO_HAVE_fetch_and_add_write)
+#  define AO_fetch_and_add_release_write(addr, val) \
+       AO_fetch_and_add_write(addr, val)
+#  define AO_HAVE_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_fetch_and_add_release_write) && \
+    defined(AO_HAVE_fetch_and_add_release)
+#  define AO_fetch_and_add_release_write(addr, val) \
+       AO_fetch_and_add_release(addr, val)
+#  define AO_HAVE_fetch_and_add_release_write
+#endif
+#if !defined(AO_HAVE_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_fetch_and_add_read)
+#  define AO_fetch_and_add_acquire_read(addr, val) \
+       AO_fetch_and_add_read(addr, val)
+#  define AO_HAVE_fetch_and_add_acquire_read
+#endif
+#if !defined(AO_HAVE_fetch_and_add_acquire_read) && \
+    defined(AO_HAVE_fetch_and_add_acquire)
+#  define AO_fetch_and_add_acquire_read(addr, val) \
+       AO_fetch_and_add_acquire(addr, val)
+#  define AO_HAVE_fetch_and_add_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_fetch_and_add_acquire_read)
+#    define AO_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_fetch_and_add_acquire_read(addr, val)
+#    define AO_HAVE_fetch_and_add_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_fetch_and_add)
+#    define AO_fetch_and_add_dd_acquire_read(addr, val) \
+       AO_fetch_and_add(addr, val)
+#    define AO_HAVE_fetch_and_add_dd_acquire_read
+#  endif
+#endif
+  
+/* Fetch_and_add1 */
+
+#if defined(AO_HAVE_fetch_and_add_full) &&\
+    !defined(AO_HAVE_fetch_and_add1_full)
+#  define AO_fetch_and_add1_full(addr) AO_fetch_and_add_full(addr,1)
+#  define AO_HAVE_fetch_and_add1_full
+#endif
+#if defined(AO_HAVE_fetch_and_add_release) &&\
+    !defined(AO_HAVE_fetch_and_add1_release)
+#  define AO_fetch_and_add1_release(addr) AO_fetch_and_add_release(addr,1)
+#  define AO_HAVE_fetch_and_add1_release
+#endif
+#if defined(AO_HAVE_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_fetch_and_add1_acquire)
+#  define AO_fetch_and_add1_acquire(addr) AO_fetch_and_add_acquire(addr,1)
+#  define AO_HAVE_fetch_and_add1_acquire
+#endif
+#if defined(AO_HAVE_fetch_and_add_write) &&\
+    !defined(AO_HAVE_fetch_and_add1_write)
+#  define AO_fetch_and_add1_write(addr) AO_fetch_and_add_write(addr,1)
+#  define AO_HAVE_fetch_and_add1_write
+#endif
+#if defined(AO_HAVE_fetch_and_add_read) &&\
+    !defined(AO_HAVE_fetch_and_add1_read)
+#  define AO_fetch_and_add1_read(addr) AO_fetch_and_add_read(addr,1)
+#  define AO_HAVE_fetch_and_add1_read
+#endif
+#if defined(AO_HAVE_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_fetch_and_add1_release_write)
+#  define AO_fetch_and_add1_release_write(addr) \
+       AO_fetch_and_add_release_write(addr,1)
+#  define AO_HAVE_fetch_and_add1_release_write
+#endif
+#if defined(AO_HAVE_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_fetch_and_add1_acquire_read)
+#  define AO_fetch_and_add1_acquire_read(addr) \
+       AO_fetch_and_add_acquire_read(addr,1)
+#  define AO_HAVE_fetch_and_add1_acquire_read
+#endif
+#if defined(AO_HAVE_fetch_and_add) &&\
+    !defined(AO_HAVE_fetch_and_add1)
+#  define AO_fetch_and_add1(addr) \
+       AO_fetch_and_add(addr,1)
+#  define AO_HAVE_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_fetch_and_add1_full)
+#  if !defined(AO_HAVE_fetch_and_add1_release)
+#    define AO_fetch_and_add1_release(addr) \
+        AO_fetch_and_add1_full(addr)
+#    define AO_HAVE_fetch_and_add1_release
+#  endif
+#  if !defined(AO_HAVE_fetch_and_add1_acquire)
+#    define AO_fetch_and_add1_acquire(addr) \
+        AO_fetch_and_add1_full(addr)
+#    define AO_HAVE_fetch_and_add1_acquire
+#  endif
+#  if !defined(AO_HAVE_fetch_and_add1_write)
+#    define AO_fetch_and_add1_write(addr) \
+        AO_fetch_and_add1_full(addr)
+#    define AO_HAVE_fetch_and_add1_write
+#  endif
+#  if !defined(AO_HAVE_fetch_and_add1_read)
+#    define AO_fetch_and_add1_read(addr) \
+        AO_fetch_and_add1_full(addr)
+#    define AO_HAVE_fetch_and_add1_read
+#  endif
+#endif /* AO_HAVE_fetch_and_add1_full */
+
+#if !defined(AO_HAVE_fetch_and_add1) && \
+    defined(AO_HAVE_fetch_and_add1_release)
+#  define AO_fetch_and_add1(addr) \
+       AO_fetch_and_add1_release(addr)
+#  define AO_HAVE_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_fetch_and_add1) && \
+    defined(AO_HAVE_fetch_and_add1_acquire)
+#  define AO_fetch_and_add1(addr) \
+       AO_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_fetch_and_add1) && \
+    defined(AO_HAVE_fetch_and_add1_write)
+#  define AO_fetch_and_add1(addr) \
+       AO_fetch_and_add1_write(addr)
+#  define AO_HAVE_fetch_and_add1
+#endif
+#if !defined(AO_HAVE_fetch_and_add1) && \
+    defined(AO_HAVE_fetch_and_add1_read)
+#  define AO_fetch_and_add1(addr) \
+       AO_fetch_and_add1_read(addr)
+#  define AO_HAVE_fetch_and_add1
+#endif
+
+#if defined(AO_HAVE_fetch_and_add1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_fetch_and_add1_full)
+#  define AO_fetch_and_add1_full(addr) \
+       (AO_nop_full(), AO_fetch_and_add1_acquire(addr))
+#  define AO_HAVE_fetch_and_add1_full
+#endif
+
+#if !defined(AO_HAVE_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_fetch_and_add1_write)
+#  define AO_fetch_and_add1_release_write(addr) \
+       AO_fetch_and_add1_write(addr)
+#  define AO_HAVE_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_fetch_and_add1_release_write) && \
+    defined(AO_HAVE_fetch_and_add1_release)
+#  define AO_fetch_and_add1_release_write(addr) \
+       AO_fetch_and_add1_release(addr)
+#  define AO_HAVE_fetch_and_add1_release_write
+#endif
+#if !defined(AO_HAVE_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_fetch_and_add1_read)
+#  define AO_fetch_and_add1_acquire_read(addr) \
+       AO_fetch_and_add1_read(addr)
+#  define AO_HAVE_fetch_and_add1_acquire_read
+#endif
+#if !defined(AO_HAVE_fetch_and_add1_acquire_read) && \
+    defined(AO_HAVE_fetch_and_add1_acquire)
+#  define AO_fetch_and_add1_acquire_read(addr) \
+       AO_fetch_and_add1_acquire(addr)
+#  define AO_HAVE_fetch_and_add1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_fetch_and_add1_acquire_read)
+#    define AO_fetch_and_add1_dd_acquire_read(addr) \
+       AO_fetch_and_add1_acquire_read(addr)
+#    define AO_HAVE_fetch_and_add1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_fetch_and_add1)
+#    define AO_fetch_and_add1_dd_acquire_read(addr) AO_fetch_and_add1(addr)
+#    define AO_HAVE_fetch_and_add1_dd_acquire_read
+#  endif
+#endif
+
+/* Fetch_and_sub1 */
+
+#if defined(AO_HAVE_fetch_and_add_full) &&\
+    !defined(AO_HAVE_fetch_and_sub1_full)
+#  define AO_fetch_and_sub1_full(addr) AO_fetch_and_add_full(addr,(AO_t)(-1))
+#  define AO_HAVE_fetch_and_sub1_full
+#endif
+#if defined(AO_HAVE_fetch_and_add_release) &&\
+    !defined(AO_HAVE_fetch_and_sub1_release)
+#  define AO_fetch_and_sub1_release(addr) \
+       AO_fetch_and_add_release(addr,(AO_t)(-1))
+#  define AO_HAVE_fetch_and_sub1_release
+#endif
+#if defined(AO_HAVE_fetch_and_add_acquire) &&\
+    !defined(AO_HAVE_fetch_and_sub1_acquire)
+#  define AO_fetch_and_sub1_acquire(addr) \
+       AO_fetch_and_add_acquire(addr,(AO_t)(-1))
+#  define AO_HAVE_fetch_and_sub1_acquire
+#endif
+#if defined(AO_HAVE_fetch_and_add_write) &&\
+    !defined(AO_HAVE_fetch_and_sub1_write)
+#  define AO_fetch_and_sub1_write(addr) \
+       AO_fetch_and_add_write(addr,(AO_t)(-1))
+#  define AO_HAVE_fetch_and_sub1_write
+#endif
+#if defined(AO_HAVE_fetch_and_add_read) &&\
+    !defined(AO_HAVE_fetch_and_sub1_read)
+#  define AO_fetch_and_sub1_read(addr) \
+       AO_fetch_and_add_read(addr,(AO_t)(-1))
+#  define AO_HAVE_fetch_and_sub1_read
+#endif
+#if defined(AO_HAVE_fetch_and_add_release_write) &&\
+    !defined(AO_HAVE_fetch_and_sub1_release_write)
+#  define AO_fetch_and_sub1_release_write(addr) \
+       AO_fetch_and_add_release_write(addr,(AO_t)(-1))
+#  define AO_HAVE_fetch_and_sub1_release_write
+#endif
+#if defined(AO_HAVE_fetch_and_add_acquire_read) &&\
+    !defined(AO_HAVE_fetch_and_sub1_acquire_read)
+#  define AO_fetch_and_sub1_acquire_read(addr) \
+       AO_fetch_and_add_acquire_read(addr,(AO_t)(-1))
+#  define AO_HAVE_fetch_and_sub1_acquire_read
+#endif
+#if defined(AO_HAVE_fetch_and_add) &&\
+    !defined(AO_HAVE_fetch_and_sub1)
+#  define AO_fetch_and_sub1(addr) \
+       AO_fetch_and_add(addr,(AO_t)(-1))
+#  define AO_HAVE_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_fetch_and_sub1_full)
+#  if !defined(AO_HAVE_fetch_and_sub1_release)
+#    define AO_fetch_and_sub1_release(addr) \
+        AO_fetch_and_sub1_full(addr)
+#    define AO_HAVE_fetch_and_sub1_release
+#  endif
+#  if !defined(AO_HAVE_fetch_and_sub1_acquire)
+#    define AO_fetch_and_sub1_acquire(addr) \
+        AO_fetch_and_sub1_full(addr)
+#    define AO_HAVE_fetch_and_sub1_acquire
+#  endif
+#  if !defined(AO_HAVE_fetch_and_sub1_write)
+#    define AO_fetch_and_sub1_write(addr) \
+        AO_fetch_and_sub1_full(addr)
+#    define AO_HAVE_fetch_and_sub1_write
+#  endif
+#  if !defined(AO_HAVE_fetch_and_sub1_read)
+#    define AO_fetch_and_sub1_read(addr) \
+        AO_fetch_and_sub1_full(addr)
+#    define AO_HAVE_fetch_and_sub1_read
+#  endif
+#endif /* AO_HAVE_fetch_and_sub1_full */
+
+#if !defined(AO_HAVE_fetch_and_sub1) && \
+    defined(AO_HAVE_fetch_and_sub1_release)
+#  define AO_fetch_and_sub1(addr) \
+       AO_fetch_and_sub1_release(addr)
+#  define AO_HAVE_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_fetch_and_sub1) && \
+    defined(AO_HAVE_fetch_and_sub1_acquire)
+#  define AO_fetch_and_sub1(addr) \
+       AO_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_fetch_and_sub1) && \
+    defined(AO_HAVE_fetch_and_sub1_write)
+#  define AO_fetch_and_sub1(addr) \
+       AO_fetch_and_sub1_write(addr)
+#  define AO_HAVE_fetch_and_sub1
+#endif
+#if !defined(AO_HAVE_fetch_and_sub1) && \
+    defined(AO_HAVE_fetch_and_sub1_read)
+#  define AO_fetch_and_sub1(addr) \
+       AO_fetch_and_sub1_read(addr)
+#  define AO_HAVE_fetch_and_sub1
+#endif
+
+#if defined(AO_HAVE_fetch_and_sub1_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_fetch_and_sub1_full)
+#  define AO_fetch_and_sub1_full(addr) \
+       (AO_nop_full(), AO_fetch_and_sub1_acquire(addr))
+#  define AO_HAVE_fetch_and_sub1_full
+#endif
+
+#if !defined(AO_HAVE_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_fetch_and_sub1_write)
+#  define AO_fetch_and_sub1_release_write(addr) \
+       AO_fetch_and_sub1_write(addr)
+#  define AO_HAVE_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_fetch_and_sub1_release_write) && \
+    defined(AO_HAVE_fetch_and_sub1_release)
+#  define AO_fetch_and_sub1_release_write(addr) \
+       AO_fetch_and_sub1_release(addr)
+#  define AO_HAVE_fetch_and_sub1_release_write
+#endif
+#if !defined(AO_HAVE_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_fetch_and_sub1_read)
+#  define AO_fetch_and_sub1_acquire_read(addr) \
+       AO_fetch_and_sub1_read(addr)
+#  define AO_HAVE_fetch_and_sub1_acquire_read
+#endif
+#if !defined(AO_HAVE_fetch_and_sub1_acquire_read) && \
+    defined(AO_HAVE_fetch_and_sub1_acquire)
+#  define AO_fetch_and_sub1_acquire_read(addr) \
+       AO_fetch_and_sub1_acquire(addr)
+#  define AO_HAVE_fetch_and_sub1_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_fetch_and_sub1_acquire_read)
+#    define AO_fetch_and_sub1_dd_acquire_read(addr) \
+       AO_fetch_and_sub1_acquire_read(addr)
+#    define AO_HAVE_fetch_and_sub1_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_fetch_and_sub1)
+#    define AO_fetch_and_sub1_dd_acquire_read(addr) AO_fetch_and_sub1(addr)
+#    define AO_HAVE_fetch_and_sub1_dd_acquire_read
+#  endif
+#endif
+
+/* Atomic or */
+#if defined(AO_HAVE_compare_and_swap_full) && \
+    !defined(AO_HAVE_or_full)
+   AO_INLINE void
+   AO_or_full(volatile AO_t *addr, AO_t incr)
+   {
+     AO_t old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_compare_and_swap_full(addr, old, (old | incr)));
+   }
+#  define AO_HAVE_or_full
+#endif
+
+#if defined(AO_HAVE_or_full)
+#  if !defined(AO_HAVE_or_release)
+#    define AO_or_release(addr, val) \
+        AO_or_full(addr, val)
+#    define AO_HAVE_or_release
+#  endif
+#  if !defined(AO_HAVE_or_acquire)
+#    define AO_or_acquire(addr, val) \
+        AO_or_full(addr, val)
+#    define AO_HAVE_or_acquire
+#  endif
+#  if !defined(AO_HAVE_or_write)
+#    define AO_or_write(addr, val) \
+        AO_or_full(addr, val)
+#    define AO_HAVE_or_write
+#  endif
+#  if !defined(AO_HAVE_or_read)
+#    define AO_or_read(addr, val) \
+        AO_or_full(addr, val)
+#    define AO_HAVE_or_read
+#  endif
+#endif /* AO_HAVE_or_full */
+
+#if !defined(AO_HAVE_or) && \
+    defined(AO_HAVE_or_release)
+#  define AO_or(addr, val) \
+       AO_or_release(addr, val)
+#  define AO_HAVE_or
+#endif
+#if !defined(AO_HAVE_or) && \
+    defined(AO_HAVE_or_acquire)
+#  define AO_or(addr, val) \
+       AO_or_acquire(addr, val)
+#  define AO_HAVE_or
+#endif
+#if !defined(AO_HAVE_or) && \
+    defined(AO_HAVE_or_write)
+#  define AO_or(addr, val) \
+       AO_or_write(addr, val)
+#  define AO_HAVE_or
+#endif
+#if !defined(AO_HAVE_or) && \
+    defined(AO_HAVE_or_read)
+#  define AO_or(addr, val) \
+       AO_or_read(addr, val)
+#  define AO_HAVE_or
+#endif
+
+#if defined(AO_HAVE_or_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_or_full)
+#  define AO_or_full(addr, val) \
+       (AO_nop_full(), AO_or_acquire(addr, val))
+#endif
+
+#if !defined(AO_HAVE_or_release_write) && \
+    defined(AO_HAVE_or_write)
+#  define AO_or_release_write(addr, val) \
+       AO_or_write(addr, val)
+#  define AO_HAVE_or_release_write
+#endif
+#if !defined(AO_HAVE_or_release_write) && \
+    defined(AO_HAVE_or_release)
+#  define AO_or_release_write(addr, val) \
+       AO_or_release(addr, val)
+#  define AO_HAVE_or_release_write
+#endif
+#if !defined(AO_HAVE_or_acquire_read) && \
+    defined(AO_HAVE_or_read)
+#  define AO_or_acquire_read(addr, val) \
+       AO_or_read(addr, val)
+#  define AO_HAVE_or_acquire_read
+#endif
+#if !defined(AO_HAVE_or_acquire_read) && \
+    defined(AO_HAVE_or_acquire)
+#  define AO_or_acquire_read(addr, val) \
+       AO_or_acquire(addr, val)
+#  define AO_HAVE_or_acquire_read
+#endif
+
+/* dd_aquire_read is meaningless.      */
+  
+/* Test_and_set */
+  
+#if defined(AO_HAVE_test_and_set_full)
+#  if !defined(AO_HAVE_test_and_set_release)
+#    define AO_test_and_set_release(addr) \
+        AO_test_and_set_full(addr)
+#    define AO_HAVE_test_and_set_release
+#  endif
+#  if !defined(AO_HAVE_test_and_set_acquire)
+#    define AO_test_and_set_acquire(addr) \
+        AO_test_and_set_full(addr)
+#    define AO_HAVE_test_and_set_acquire
+#  endif
+#  if !defined(AO_HAVE_test_and_set_write)
+#    define AO_test_and_set_write(addr) \
+        AO_test_and_set_full(addr)
+#    define AO_HAVE_test_and_set_write
+#  endif
+#  if !defined(AO_HAVE_test_and_set_read)
+#    define AO_test_and_set_read(addr) \
+        AO_test_and_set_full(addr)
+#    define AO_HAVE_test_and_set_read
+#  endif
+#endif /* AO_HAVE_test_and_set_full */
+
+#if !defined(AO_HAVE_test_and_set) && \
+    defined(AO_HAVE_test_and_set_release)
+#  define AO_test_and_set(addr) \
+       AO_test_and_set_release(addr)
+#  define AO_HAVE_test_and_set
+#endif
+#if !defined(AO_HAVE_test_and_set) && \
+    defined(AO_HAVE_test_and_set_acquire)
+#  define AO_test_and_set(addr) \
+       AO_test_and_set_acquire(addr)
+#  define AO_HAVE_test_and_set
+#endif
+#if !defined(AO_HAVE_test_and_set) && \
+    defined(AO_HAVE_test_and_set_write)
+#  define AO_test_and_set(addr) \
+       AO_test_and_set_write(addr)
+#  define AO_HAVE_test_and_set
+#endif
+#if !defined(AO_HAVE_test_and_set) && \
+    defined(AO_HAVE_test_and_set_read)
+#  define AO_test_and_set(addr) \
+       AO_test_and_set_read(addr)
+#  define AO_HAVE_test_and_set
+#endif
+
+#if defined(AO_HAVE_test_and_set_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_test_and_set_full)
+#  define AO_test_and_set_full(addr) \
+       (AO_nop_full(), AO_test_and_set_acquire(addr))
+#  define AO_HAVE_test_and_set_full
+#endif
+
+#if !defined(AO_HAVE_test_and_set_release_write) && \
+    defined(AO_HAVE_test_and_set_write)
+#  define AO_test_and_set_release_write(addr) \
+       AO_test_and_set_write(addr)
+#  define AO_HAVE_test_and_set_release_write
+#endif
+#if !defined(AO_HAVE_test_and_set_release_write) && \
+    defined(AO_HAVE_test_and_set_release)
+#  define AO_test_and_set_release_write(addr) \
+       AO_test_and_set_release(addr)
+#  define AO_HAVE_test_and_set_release_write
+#endif
+#if !defined(AO_HAVE_test_and_set_acquire_read) && \
+    defined(AO_HAVE_test_and_set_read)
+#  define AO_test_and_set_acquire_read(addr) \
+       AO_test_and_set_read(addr)
+#  define AO_HAVE_test_and_set_acquire_read
+#endif
+#if !defined(AO_HAVE_test_and_set_acquire_read) && \
+    defined(AO_HAVE_test_and_set_acquire)
+#  define AO_test_and_set_acquire_read(addr) \
+       AO_test_and_set_acquire(addr)
+#  define AO_HAVE_test_and_set_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_test_and_set_acquire_read)
+#    define AO_test_and_set_dd_acquire_read(addr) \
+       AO_test_and_set_acquire_read(addr)
+#    define AO_HAVE_test_and_set_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_test_and_set)
+#    define AO_test_and_set_dd_acquire_read(addr) AO_test_and_set(addr)
+#    define AO_HAVE_test_and_set_dd_acquire_read
+#  endif
+#endif
+
+/* Compare_and_swap */
+#if defined(AO_HAVE_compare_and_swap) && defined(AO_HAVE_nop_full)\
+    && !defined(AO_HAVE_compare_and_swap_acquire)
+   AO_INLINE int
+   AO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val)
+   {
+     int result = AO_compare_and_swap(addr, old, new_val);
+     AO_nop_full();
+     return result;
+   }
+#  define AO_HAVE_compare_and_swap_acquire
+#endif
+#if defined(AO_HAVE_compare_and_swap) && defined(AO_HAVE_nop_full)\
+    && !defined(AO_HAVE_compare_and_swap_release)
+#  define AO_compare_and_swap_release(addr, old, new_val) \
+       (AO_nop_full(), AO_compare_and_swap(addr, old, new_val))
+#  define AO_HAVE_compare_and_swap_release
+#endif
+#if defined(AO_HAVE_compare_and_swap_full)
+#  if !defined(AO_HAVE_compare_and_swap_release)
+#    define AO_compare_and_swap_release(addr, old, new_val) \
+        AO_compare_and_swap_full(addr, old, new_val)
+#    define AO_HAVE_compare_and_swap_release
+#  endif
+#  if !defined(AO_HAVE_compare_and_swap_acquire)
+#    define AO_compare_and_swap_acquire(addr, old, new_val) \
+        AO_compare_and_swap_full(addr, old, new_val)
+#    define AO_HAVE_compare_and_swap_acquire
+#  endif
+#  if !defined(AO_HAVE_compare_and_swap_write)
+#    define AO_compare_and_swap_write(addr, old, new_val) \
+        AO_compare_and_swap_full(addr, old, new_val)
+#    define AO_HAVE_compare_and_swap_write
+#  endif
+#  if !defined(AO_HAVE_compare_and_swap_read)
+#    define AO_compare_and_swap_read(addr, old, new_val) \
+        AO_compare_and_swap_full(addr, old, new_val)
+#    define AO_HAVE_compare_and_swap_read
+#  endif
+#endif /* AO_HAVE_compare_and_swap_full */
+
+#if !defined(AO_HAVE_compare_and_swap) && \
+    defined(AO_HAVE_compare_and_swap_release)
+#  define AO_compare_and_swap(addr, old, new_val) \
+       AO_compare_and_swap_release(addr, old, new_val)
+#  define AO_HAVE_compare_and_swap
+#endif
+#if !defined(AO_HAVE_compare_and_swap) && \
+    defined(AO_HAVE_compare_and_swap_acquire)
+#  define AO_compare_and_swap(addr, old, new_val) \
+       AO_compare_and_swap_acquire(addr, old, new_val)
+#  define AO_HAVE_compare_and_swap
+#endif
+#if !defined(AO_HAVE_compare_and_swap) && \
+    defined(AO_HAVE_compare_and_swap_write)
+#  define AO_compare_and_swap(addr, old, new_val) \
+       AO_compare_and_swap_write(addr, old, new_val)
+#  define AO_HAVE_compare_and_swap
+#endif
+#if !defined(AO_HAVE_compare_and_swap) && \
+    defined(AO_HAVE_compare_and_swap_read)
+#  define AO_compare_and_swap(addr, old, new_val) \
+       AO_compare_and_swap_read(addr, old, new_val)
+#  define AO_HAVE_compare_and_swap
+#endif
+
+#if defined(AO_HAVE_compare_and_swap_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_compare_and_swap_full)
+#  define AO_compare_and_swap_full(addr, old, new_val) \
+       (AO_nop_full(), AO_compare_and_swap_acquire(addr, old, new_val))
+#  define AO_HAVE_compare_and_swap_full
+#endif
+
+#if !defined(AO_HAVE_compare_and_swap_release_write) && \
+    defined(AO_HAVE_compare_and_swap_write)
+#  define AO_compare_and_swap_release_write(addr, old, new_val) \
+       AO_compare_and_swap_write(addr, old, new_val)
+#  define AO_HAVE_compare_and_swap_release_write
+#endif
+#if !defined(AO_HAVE_compare_and_swap_release_write) && \
+    defined(AO_HAVE_compare_and_swap_release)
+#  define AO_compare_and_swap_release_write(addr, old, new_val) \
+       AO_compare_and_swap_release(addr, old, new_val)
+#  define AO_HAVE_compare_and_swap_release_write
+#endif
+#if !defined(AO_HAVE_compare_and_swap_acquire_read) && \
+    defined(AO_HAVE_compare_and_swap_read)
+#  define AO_compare_and_swap_acquire_read(addr, old, new_val) \
+       AO_compare_and_swap_read(addr, old, new_val)
+#  define AO_HAVE_compare_and_swap_acquire_read
+#endif
+#if !defined(AO_HAVE_compare_and_swap_acquire_read) && \
+    defined(AO_HAVE_compare_and_swap_acquire)
+#  define AO_compare_and_swap_acquire_read(addr, old, new_val) \
+       AO_compare_and_swap_acquire(addr, old, new_val)
+#  define AO_HAVE_compare_and_swap_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_compare_and_swap_acquire_read)
+#    define AO_compare_and_swap_dd_acquire_read(addr, old, new_val) \
+       AO_compare_and_swap_acquire_read(addr, old, new_val)
+#    define AO_HAVE_compare_and_swap_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_compare_and_swap)
+#    define AO_compare_and_swap_dd_acquire_read(addr, old, new_val) \
+       AO_compare_and_swap(addr, old, new_val)
+#    define AO_HAVE_compare_and_swap_dd_acquire_read
+#  endif
+#endif
+
+#include "generalize-small.h"
+
+/* Compare_double_and_swap_double */
+#if defined(AO_HAVE_compare_double_and_swap_double) && defined(AO_HAVE_nop_full)\
+    && !defined(AO_HAVE_compare_double_and_swap_double_acquire)
+   AO_INLINE int
+   AO_compare_double_and_swap_double_acquire(volatile AO_double_t *addr,
+                                            AO_t o1, AO_t o2,
+                                            AO_t n1, AO_t n2)
+   {
+     int result = AO_compare_double_and_swap_double(addr, o1, o2, n1, n2);
+     AO_nop_full();
+     return result;
+   }
+#  define AO_HAVE_compare_double_and_swap_double_acquire
+#endif
+#if defined(AO_HAVE_compare_double_and_swap_double) \
+    && defined(AO_HAVE_nop_full)\
+    && !defined(AO_HAVE_compare_double_and_swap_double_release)
+#  define AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2) \
+       (AO_nop_full(), AO_compare_double_and_swap_double(addr, o1, o2, n1, n2))
+#  define AO_HAVE_compare_double_and_swap_double_release
+#endif
+#if defined(AO_HAVE_compare_double_and_swap_double_full)
+#  if !defined(AO_HAVE_compare_double_and_swap_double_release)
+#    define AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2) \
+        AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)
+#    define AO_HAVE_compare_double_and_swap_double_release
+#  endif
+#  if !defined(AO_HAVE_compare_double_and_swap_double_acquire)
+#    define AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2) \
+        AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)
+#    define AO_HAVE_compare_double_and_swap_double_acquire
+#  endif
+#  if !defined(AO_HAVE_compare_double_and_swap_double_write)
+#    define AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2) \
+        AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)
+#    define AO_HAVE_compare_double_and_swap_double_write
+#  endif
+#  if !defined(AO_HAVE_compare_double_and_swap_double_read)
+#    define AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2) \
+        AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2)
+#    define AO_HAVE_compare_double_and_swap_double_read
+#  endif
+#endif /* AO_HAVE_compare_double_and_swap_double_full */
+
+#if !defined(AO_HAVE_compare_double_and_swap_double) && \
+    defined(AO_HAVE_compare_double_and_swap_double_release)
+#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2)
+#  define AO_HAVE_compare_double_and_swap_double
+#endif
+#if !defined(AO_HAVE_compare_double_and_swap_double) && \
+    defined(AO_HAVE_compare_double_and_swap_double_acquire)
+#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2)
+#  define AO_HAVE_compare_double_and_swap_double
+#endif
+#if !defined(AO_HAVE_compare_double_and_swap_double) && \
+    defined(AO_HAVE_compare_double_and_swap_double_write)
+#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2)
+#  define AO_HAVE_compare_double_and_swap_double
+#endif
+#if !defined(AO_HAVE_compare_double_and_swap_double) && \
+    defined(AO_HAVE_compare_double_and_swap_double_read)
+#  define AO_compare_double_and_swap_double(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2)
+#  define AO_HAVE_compare_double_and_swap_double
+#endif
+
+#if defined(AO_HAVE_compare_double_and_swap_double_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_compare_double_and_swap_double_full)
+#  define AO_compare_double_and_swap_double_full(addr, o1, o2, n1, n2) \
+       (AO_nop_full(), AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2))
+#  define AO_HAVE_compare_double_and_swap_double_full
+#endif
+
+#if !defined(AO_HAVE_compare_double_and_swap_double_release_write) && \
+    defined(AO_HAVE_compare_double_and_swap_double_write)
+#  define AO_compare_double_and_swap_double_release_write(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double_write(addr, o1, o2, n1, n2)
+#  define AO_HAVE_compare_double_and_swap_double_release_write
+#endif
+#if !defined(AO_HAVE_compare_double_and_swap_double_release_write) && \
+    defined(AO_HAVE_compare_double_and_swap_double_release)
+#  define AO_compare_double_and_swap_double_release_write(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double_release(addr, o1, o2, n1, n2)
+#  define AO_HAVE_compare_double_and_swap_double_release_write
+#endif
+#if !defined(AO_HAVE_compare_double_and_swap_double_acquire_read) && \
+    defined(AO_HAVE_compare_double_and_swap_double_read)
+#  define AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double_read(addr, o1, o2, n1, n2)
+#  define AO_HAVE_compare_double_and_swap_double_acquire_read
+#endif
+#if !defined(AO_HAVE_compare_double_and_swap_double_acquire_read) && \
+    defined(AO_HAVE_compare_double_and_swap_double_acquire)
+#  define AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double_acquire(addr, o1, o2, n1, n2)
+#  define AO_HAVE_compare_double_and_swap_double_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_compare_double_and_swap_double_acquire_read)
+#    define AO_compare_double_and_swap_double_dd_acquire_read(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double_acquire_read(addr, o1, o2, n1, n2)
+#    define AO_HAVE_compare_double_and_swap_double_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_compare_double_and_swap_double)
+#    define AO_compare_double_and_swap_double_dd_acquire_read(addr, o1, o2, n1, n2) \
+       AO_compare_double_and_swap_double(addr, o1, o2, n1, n2)
+#    define AO_HAVE_compare_double_and_swap_double_dd_acquire_read
+#  endif
+#endif
+
+/* Compare_and_swap_double */
+#if defined(AO_HAVE_compare_and_swap_double) && defined(AO_HAVE_nop_full)\
+    && !defined(AO_HAVE_compare_and_swap_double_acquire)
+   AO_INLINE int
+   AO_compare_and_swap_double_acquire(volatile AO_double_t *addr,
+                                            AO_t o1, AO_t o2,
+                                            AO_t n1, AO_t n2)
+   {
+     int result = AO_compare_and_swap_double(addr, o1, n1, n2);
+     AO_nop_full();
+     return result;
+   }
+#  define AO_HAVE_compare_and_swap_double_acquire
+#endif
+#if defined(AO_HAVE_compare_and_swap_double) \
+    && defined(AO_HAVE_nop_full)\
+    && !defined(AO_HAVE_compare_and_swap_double_release)
+#  define AO_compare_and_swap_double_release(addr, o1, n1, n2) \
+       (AO_nop_full(), AO_compare_and_swap_double(addr, o1, n1, n2))
+#  define AO_HAVE_compare_and_swap_double_release
+#endif
+#if defined(AO_HAVE_compare_and_swap_double_full)
+#  if !defined(AO_HAVE_compare_and_swap_double_release)
+#    define AO_compare_and_swap_double_release(addr, o1, n1, n2) \
+        AO_compare_and_swap_double_full(addr, o1, n1, n2)
+#    define AO_HAVE_compare_and_swap_double_release
+#  endif
+#  if !defined(AO_HAVE_compare_and_swap_double_acquire)
+#    define AO_compare_and_swap_double_acquire(addr, o1, n1, n2) \
+        AO_compare_and_swap_double_full(addr, o1, n1, n2)
+#    define AO_HAVE_compare_and_swap_double_acquire
+#  endif
+#  if !defined(AO_HAVE_compare_and_swap_double_write)
+#    define AO_compare_and_swap_double_write(addr, o1, n1, n2) \
+        AO_compare_and_swap_double_full(addr, o1, n1, n2)
+#    define AO_HAVE_compare_and_swap_double_write
+#  endif
+#  if !defined(AO_HAVE_compare_and_swap_double_read)
+#    define AO_compare_and_swap_double_read(addr, o1, n1, n2) \
+        AO_compare_and_swap_double_full(addr, o1, n1, n2)
+#    define AO_HAVE_compare_and_swap_double_read
+#  endif
+#endif /* AO_HAVE_compare_and_swap_double_full */
+
+#if !defined(AO_HAVE_compare_and_swap_double) && \
+    defined(AO_HAVE_compare_and_swap_double_release)
+#  define AO_compare_and_swap_double(addr, o1, n1, n2) \
+       AO_compare_and_swap_double_release(addr, o1, n1, n2)
+#  define AO_HAVE_compare_and_swap_double
+#endif
+#if !defined(AO_HAVE_compare_and_swap_double) && \
+    defined(AO_HAVE_compare_and_swap_double_acquire)
+#  define AO_compare_and_swap_double(addr, o1, n1, n2) \
+       AO_compare_and_swap_double_acquire(addr, o1, n1, n2)
+#  define AO_HAVE_compare_and_swap_double
+#endif
+#if !defined(AO_HAVE_compare_and_swap_double) && \
+    defined(AO_HAVE_compare_and_swap_double_write)
+#  define AO_compare_and_swap_double(addr, o1, n1, n2) \
+       AO_compare_and_swap_double_write(addr, o1, n1, n2)
+#  define AO_HAVE_compare_and_swap_double
+#endif
+#if !defined(AO_HAVE_compare_and_swap_double) && \
+    defined(AO_HAVE_compare_and_swap_double_read)
+#  define AO_compare_and_swap_double(addr, o1, n1, n2) \
+       AO_compare_and_swap_double_read(addr, o1, n1, n2)
+#  define AO_HAVE_compare_and_swap_double
+#endif
+
+#if defined(AO_HAVE_compare_and_swap_double_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_compare_and_swap_double_full)
+#  define AO_compare_and_swap_double_full(addr, o1, n1, n2) \
+       (AO_nop_full(), AO_compare_and_swap_double_acquire(addr, o1, n1, n2))
+#  define AO_HAVE_compare_and_swap_double_full
+#endif
+
+#if !defined(AO_HAVE_compare_and_swap_double_release_write) && \
+    defined(AO_HAVE_compare_and_swap_double_write)
+#  define AO_compare_and_swap_double_release_write(addr, o1, n1, n2) \
+       AO_compare_and_swap_double_write(addr, o1, n1, n2)
+#  define AO_HAVE_compare_and_swap_double_release_write
+#endif
+#if !defined(AO_HAVE_compare_and_swap_double_release_write) && \
+    defined(AO_HAVE_compare_and_swap_double_release)
+#  define AO_compare_and_swap_double_release_write(addr, o1, n1, n2) \
+       AO_compare_and_swap_double_release(addr, o1, n1, n2)
+#  define AO_HAVE_compare_and_swap_double_release_write
+#endif
+#if !defined(AO_HAVE_compare_and_swap_double_acquire_read) && \
+    defined(AO_HAVE_compare_and_swap_double_read)
+#  define AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2) \
+       AO_compare_and_swap_double_read(addr, o1, n1, n2)
+#  define AO_HAVE_compare_and_swap_double_acquire_read
+#endif
+#if !defined(AO_HAVE_compare_and_swap_double_acquire_read) && \
+    defined(AO_HAVE_compare_and_swap_double_acquire)
+#  define AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2) \
+       AO_compare_and_swap_double_acquire(addr, o1, n1, n2)
+#  define AO_HAVE_compare_and_swap_double_acquire_read
+#endif
+
+#ifdef AO_NO_DD_ORDERING
+#  if defined(AO_HAVE_compare_and_swap_double_acquire_read)
+#    define AO_compare_and_swap_double_dd_acquire_read(addr, o1, n1, n2) \
+       AO_compare_and_swap_double_acquire_read(addr, o1, n1, n2)
+#    define AO_HAVE_compare_and_swap_double_dd_acquire_read
+#  endif
+#else
+#  if defined(AO_HAVE_compare_and_swap_double)
+#    define AO_compare_and_swap_double_dd_acquire_read(addr, o1, n1, n2) \
+       AO_compare_and_swap_double(addr, o1, n1, n2)
+#    define AO_HAVE_compare_and_swap_double_dd_acquire_read
+#  endif
+#endif
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/Makefile.am b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/Makefile.am
new file mode 100644 (file)
index 0000000..8204d8d
--- /dev/null
@@ -0,0 +1,47 @@
+#General sysdep utility headers, followed by the arch-specific ones
+nobase_sysdep_HEADERS= generic_pthread.h \
+         atomic_load_store.h \
+         aligned_atomic_load_store.h \
+         acquire_release_volatile.h \
+         char_acquire_release_volatile.h \
+         char_atomic_load_store.h \
+         short_acquire_release_volatile.h \
+         short_aligned_atomic_load_store.h \
+         short_atomic_load_store.h \
+         int_acquire_release_volatile.h \
+         int_aligned_atomic_load_store.h \
+         int_atomic_load_store.h \
+         all_acquire_release_volatile.h \
+         all_aligned_atomic_load_store.h \
+         all_atomic_load_store.h \
+         read_ordered.h \
+         ordered_except_wr.h \
+         ordered.h \
+         ao_t_is_int.h \
+         test_and_set_t_is_ao_t.h \
+         test_and_set_t_is_char.h \
+         emul_cas.h \
+         standard_ao_double_t.h \
+         README \
+       \
+         gcc/alpha.h gcc/arm.h gcc/x86.h \
+         gcc/hppa.h gcc/ia64.h \
+         gcc/powerpc.h gcc/sparc.h \
+         gcc/hppa.h gcc/m68k.h gcc/s390.h \
+         gcc/ia64.h gcc/x86_64.h gcc/cris.h \
+       \
+         icc/ia64.h \
+       \
+         msftc/x86.h \
+         msftc/x86_64.h \
+       \
+         hpc/ia64.h hpc/hppa.h \
+       \
+         sunc/sparc.h \
+       \
+         ibmc/powerpc.h
+
+sysdepdir= ${includedir}/atomic_ops/sysdeps
+
+# A few architectures require special .S files
+EXTRA_DIST = sunc/sparc.S
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/README b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/README
new file mode 100644 (file)
index 0000000..605699f
--- /dev/null
@@ -0,0 +1,7 @@
+There are two kinds of entities in this directory:
+
+- Subdirectories corresponding to specific compilers (or compiler/OS combinations).
+  Each of these includes one or more architecture-specific headers.
+
+- More generic header files corresponding to a particular ordering and/or
+  atomicity property that might be shared by multiple hardware platforms.
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/acquire_release_volatile.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/acquire_release_volatile.h
new file mode 100644 (file)
index 0000000..1a387d3
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * This file adds definitions appropriate for environments in which an AO_t
+ * volatile load has acquire semantics, and an AO_t volatile store has release
+ * semantics.  This is arguably supposed to be true with the standard Itanium
+ * software conventions.
+ */
+
+/*
+ * Empirically gcc/ia64 does some reordering of ordinary operations around volatiles
+ * even when we think it shouldn't.  Gcc 3.3 and earlier could reorder a volatile store
+ * with another store.  As of March 2005, gcc pre-4 reused previously computed
+ * common subexpressions across a volatile load.
+ * Hence we now add compiler barriers for gcc.
+ */
+#if !defined(AO_GCC_BARRIER)
+#  if defined(__GNUC__)
+#    define AO_GCC_BARRIER() AO_compiler_barrier()
+#  else
+#    define AO_GCC_BARRIER()
+#  endif
+#endif
+
+AO_INLINE AO_t
+AO_load_acquire(volatile AO_t *p)
+{
+  AO_t result = *p;
+  /* A normal volatile load generates an ld.acq                */
+  AO_GCC_BARRIER();
+  return result;
+}
+#define AO_HAVE_load_acquire
+
+AO_INLINE void
+AO_store_release(volatile AO_t *p, AO_t val)
+{
+  AO_GCC_BARRIER();
+  /* A normal volatile store generates an st.rel       */
+  *p = val;
+}
+#define AO_HAVE_store_release
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/aligned_atomic_load_store.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/aligned_atomic_load_store.h
new file mode 100644 (file)
index 0000000..485b7f4
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * Definitions for architecturs on which loads and stores of AO_t are
+ * atomic fo all legal alignments.
+ */
+
+AO_INLINE AO_t
+AO_load(volatile AO_t *addr)
+{
+  assert(((size_t)addr & (sizeof(AO_t) - 1)) == 0);
+  /* Cast away the volatile for architectures where            */
+  /* volatile adds barrier semantics.                          */
+  return *(AO_t *)addr;
+}
+
+#define AO_HAVE_load
+
+AO_INLINE void
+AO_store(volatile AO_t *addr, AO_t new_val)
+{
+  assert(((size_t)addr & (sizeof(AO_t) - 1)) == 0);
+  (*(AO_t *)addr) = new_val;
+}
+
+#define AO_HAVE_store
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/all_acquire_release_volatile.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/all_acquire_release_volatile.h
new file mode 100644 (file)
index 0000000..6787387
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * Describes architectures on which volatile AO_t, unsigned char, unsigned
+ * short, and unsigned int loads and stores have acquire/release semantics for
+ * all normally legal alignments.
+ */
+#include "acquire_release_volatile.h"
+#include "char_acquire_release_volatile.h"
+#include "short_acquire_release_volatile.h"
+#include "int_acquire_release_volatile.h"
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/all_aligned_atomic_load_store.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/all_aligned_atomic_load_store.h
new file mode 100644 (file)
index 0000000..b9f7247
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * Describes architectures on which AO_t, unsigned char, unsigned short,
+ * and unsigned int loads and strores are atomic for all normally legal alignments.
+ */
+#include "aligned_atomic_load_store.h"
+#include "char_atomic_load_store.h"
+#include "short_aligned_atomic_load_store.h"
+#include "int_aligned_atomic_load_store.h"
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/all_atomic_load_store.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/all_atomic_load_store.h
new file mode 100644 (file)
index 0000000..d0ebe08
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * Describes architectures on which AO_t, unsigned char, unsigned short,
+ * and unsigned int loads and strores are atomic for all normally legal
+ * alignments.
+ */
+#include "atomic_load_store.h"
+#include "char_atomic_load_store.h"
+#include "short_atomic_load_store.h"
+#include "int_atomic_load_store.h"
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ao_t_is_int.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ao_t_is_int.h
new file mode 100644 (file)
index 0000000..18156c8
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * Inclusion of this file signifies that AO_t is in fact int.  Hence
+ * any AO_... operations can also server as AO_int_... operations.
+ * We currently define only the more important ones here, and allow for
+ * the normal generalization process to define the others.
+ * We should probably add others in the future.
+ */
+
+#if defined(AO_HAVE_compare_and_swap_full) && \
+    !defined(AO_HAVE_int_compare_and_swap_full)
+#  define AO_int_compare_and_swap_full(addr, old, new_val) \
+               AO_compare_and_swap_full((volatile AO_t *)addr, \
+                                        (AO_t) old, (AO_t)new_val)
+#  define AO_HAVE_int_compare_and_swap_full
+# endif
+
+#if defined(AO_HAVE_compare_and_swap_acquire) && \
+    !defined(AO_HAVE_int_compare_and_swap_acquire)
+#  define AO_int_compare_and_swap_acquire(addr, old, new_val) \
+               AO_compare_and_swap_acquire((volatile AO_t *)addr, \
+                                           (AO_t) old, (AO_t)new_val)
+#  define AO_HAVE_int_compare_and_swap_acquire
+# endif
+
+#if defined(AO_HAVE_compare_and_swap_release) && \
+    !defined(AO_HAVE_int_compare_and_swap_release)
+#  define AO_int_compare_and_swap_release(addr, old, new_val) \
+               AO_compare_and_swap_release((volatile AO_t *)addr, \
+                                        (AO_t) old, (AO_t)new_val)
+#  define AO_HAVE_int_compare_and_swap_release
+# endif
+
+#if defined(AO_HAVE_compare_and_swap_write) && \
+    !defined(AO_HAVE_int_compare_and_swap_write)
+#  define AO_int_compare_and_swap_write(addr, old, new_val) \
+               AO_compare_and_swap_write((volatile AO_t *)addr, \
+                                         (AO_t) old, (AO_t)new_val)
+#  define AO_HAVE_int_compare_and_swap_write
+# endif
+
+#if defined(AO_HAVE_compare_and_swap_read) && \
+    !defined(AO_HAVE_int_compare_and_swap_read)
+#  define AO_int_compare_and_swap_read(addr, old, new_val) \
+               AO_compare_and_swap_read((volatile AO_t *)addr, \
+                                        (AO_t) old, (AO_t)new_val)
+#  define AO_HAVE_int_compare_and_swap_read
+# endif
+
+#if defined(AO_HAVE_compare_and_swap) && \
+    !defined(AO_HAVE_int_compare_and_swap)
+#  define AO_int_compare_and_swap(addr, old, new_val) \
+               AO_compare_and_swap((volatile AO_t *)addr, \
+                                   (AO_t) old, (AO_t)new_val)
+#  define AO_HAVE_int_compare_and_swap
+# endif
+
+#if defined(AO_HAVE_load_acquire) && \
+    !defined(AO_HAVE_int_load_acquire)
+#  define AO_int_load_acquire(addr) (int)AO_load_acquire((volatile AO_t *)addr)
+#  define AO_HAVE_int_load_acquire
+# endif
+
+#if defined(AO_HAVE_store_release) && \
+    !defined(AO_HAVE_int_store_release)
+#  define AO_int_store_release(addr, val) \
+       AO_store_release((volatile AO_t *)addr, (AO_t)val)
+#  define AO_HAVE_int_store_release
+# endif
+
+#if defined(AO_HAVE_fetch_and_add_full) && \
+    !defined(AO_HAVE_int_fetch_and_add_full)
+#  define AO_int_fetch_and_add_full(addr, incr) \
+       (int)AO_fetch_and_add_full((volatile AO_t *)addr, (AO_t)incr)
+#  define AO_HAVE_int_fetch_and_add_full
+# endif
+
+#if defined(AO_HAVE_fetch_and_add1_acquire) && \
+    !defined(AO_HAVE_int_fetch_and_add1_acquire)
+#  define AO_int_fetch_and_add1_acquire(addr) \
+       (int)AO_fetch_and_add1_acquire((volatile AO_t *)addr)
+#  define AO_HAVE_int_fetch_and_add1_acquire
+# endif
+
+#if defined(AO_HAVE_fetch_and_add1_release) && \
+    !defined(AO_HAVE_int_fetch_and_add1_release)
+#  define AO_int_fetch_and_add1_release(addr) \
+       (int)AO_fetch_and_add1_release((volatile AO_t *)addr)
+#  define AO_HAVE_int_fetch_and_add1_release
+# endif
+
+#if defined(AO_HAVE_fetch_and_sub1_acquire) && \
+    !defined(AO_HAVE_int_fetch_and_sub1_acquire)
+#  define AO_int_fetch_and_sub1_acquire(addr) \
+       (int)AO_fetch_and_sub1_acquire((volatile AO_t *)addr)
+#  define AO_HAVE_int_fetch_and_sub1_acquire
+# endif
+
+#if defined(AO_HAVE_fetch_and_sub1_release) && \
+    !defined(AO_HAVE_int_fetch_and_sub1_release)
+#  define AO_int_fetch_and_sub1_release(addr) \
+       (int)AO_fetch_and_sub1_release((volatile AO_t *)addr)
+#  define AO_HAVE_int_fetch_and_sub1_release
+# endif
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/atomic_load_store.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/atomic_load_store.h
new file mode 100644 (file)
index 0000000..68c5179
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * Definitions for architecturs on which loads and stores of AO_t are
+ * atomic fo all legal alignments.
+ */
+
+AO_INLINE AO_t
+AO_load(volatile AO_t *addr)
+{
+  /* Cast away the volatile for architectures like IA64 where  */
+  /* volatile adds barrier semantics.                          */
+  return (*(AO_t *)addr);
+}
+
+#define AO_HAVE_load
+
+AO_INLINE void
+AO_store(volatile AO_t *addr, AO_t new_val)
+{
+  (*(AO_t *)addr) = new_val;
+}
+
+#define AO_HAVE_store
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/char_acquire_release_volatile.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/char_acquire_release_volatile.h
new file mode 100644 (file)
index 0000000..37aa021
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * This file adds definitions appropriate for environments in which an unsigned char
+ * volatile load has acquire semantics, and an unsigned char volatile store has release
+ * semantics.  This is true with the standard Itanium ABI.
+ */
+#if !defined(AO_GCC_BARRIER)
+#  if defined(__GNUC__)
+#    define AO_GCC_BARRIER() AO_compiler_barrier()
+#  else
+#    define AO_GCC_BARRIER()
+#  endif
+#endif
+
+AO_INLINE unsigned char
+AO_char_load_acquire(volatile unsigned char *p)
+{
+  unsigned char result = *p;
+  /* A normal volatile load generates an ld.acq                */
+  AO_GCC_BARRIER();
+  return result;
+}
+#define AO_HAVE_char_load_acquire
+
+AO_INLINE void
+AO_char_store_release(volatile unsigned char *p, unsigned char val)
+{
+  AO_GCC_BARRIER();
+  /* A normal volatile store generates an st.rel       */
+  *p = val;
+}
+#define AO_HAVE_char_store_release
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/char_atomic_load_store.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/char_atomic_load_store.h
new file mode 100644 (file)
index 0000000..6eb0978
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * Definitions for architecturs on which loads and stores of unsigned char are
+ * atomic for all legal alignments.
+ */
+
+AO_INLINE unsigned char
+AO_char_load(volatile unsigned char *addr)
+{
+  /* Cast away the volatile for architectures like IA64 where  */
+  /* volatile adds barrier semantics.                          */
+  return (*(unsigned char *)addr);
+}
+
+#define AO_HAVE_char_load
+
+AO_INLINE void
+AO_char_store(volatile unsigned char *addr, unsigned char new_val)
+{
+  (*(unsigned char *)addr) = new_val;
+}
+
+#define AO_HAVE_char_store
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/emul_cas.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/emul_cas.h
new file mode 100644 (file)
index 0000000..4187f9f
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * Ensure, if at all possible, that AO_compare_and_swap_full() is
+ * available.  The emulation should be brute-force signal-safe, even
+ * though it actually blocks.
+ * Including this file will generate an error if AO_compare_and_swap_full()
+ * cannot be made available.
+ * This will be included from platform-specific atomic_ops files
+ * id appropriate, and if AO_FORCE_CAS is defined.  It should not be
+ * included directly, especially since it affects the implementation
+ * of other atomic update primitives.
+ * The implementation assumes that only AO_store_XXX and AO_test_and_set_XXX
+ * variants are defined, and that AO_test_and_set_XXX is not used to
+ * operate on compare_and_swap locations.
+ */
+
+#if !defined(ATOMIC_OPS_H)
+#  error This file should not be included directly.
+#endif
+
+#ifndef AO_HAVE_double_t
+# include "standard_ao_double_t.h"
+#endif
+
+int AO_compare_and_swap_emulation(volatile AO_t *addr, AO_t old,
+                                 AO_t new_val);
+
+int AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,
+                                               AO_t old_val1, AO_t old_val2,
+                                               AO_t new_val1, AO_t new_val2);
+
+void AO_store_full_emulation(volatile AO_t *addr, AO_t val);
+
+#define AO_compare_and_swap_full(addr, old, newval) \
+       AO_compare_and_swap_emulation(addr, old, newval)
+#define AO_HAVE_compare_and_swap_full
+
+#ifndef AO_HAVE_compare_double_and_swap_double
+# define AO_compare_double_and_swap_double_full(addr, old1, old2, \
+                                               newval1, newval2) \
+        AO_compare_double_and_swap_double_emulation(addr, old1, old2, \
+                                                    newval1, newval2)
+# define AO_HAVE_compare_double_and_swap_double_full
+#endif
+
+#undef AO_store
+#undef AO_HAVE_store
+#undef AO_store_write
+#undef AO_HAVE_store_write
+#undef AO_store_release
+#undef AO_HAVE_store_release
+#undef AO_store_full
+#undef AO_HAVE_store_full
+#define AO_store_full(addr, val) AO_store_full_emulation(addr, val)
+#define AO_HAVE_store_full
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/alpha.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/alpha.h
new file mode 100644 (file)
index 0000000..90c060c
--- /dev/null
@@ -0,0 +1,68 @@
+/* 
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999-2003 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.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+#include "../atomic_load_store.h"
+
+#include "../test_and_set_t_is_ao_t.h"
+
+#define AO_NO_DD_ORDERING
+       /* Data dependence does not imply read ordering.        */
+
+AO_INLINE void
+AO_nop_full()
+{
+  __asm__ __volatile__("mb" : : : "memory");
+}
+
+#define AO_HAVE_nop_full
+
+AO_INLINE void
+AO_nop_write()
+{
+  __asm__ __volatile__("wmb" : : : "memory");
+}
+
+#define AO_HAVE_nop_write
+
+/* mb should be used for AO_nop_read().  That's the default.   */
+
+/* We believe that ldq_l ... stq_c does not imply any memory barrier.  */
+/* We should add an explicit fetch_and_add definition.                 */
+AO_INLINE int
+AO_compare_and_swap(volatile AO_t *addr,
+                   AO_t old, AO_t new_val) 
+{
+  unsigned long was_equal;
+  unsigned long temp;
+
+  __asm__ __volatile__(
+                     "1:     ldq_l %0,%1\n"
+                     "       cmpeq %0,%4,%2\n"
+                    "       mov %3,%0\n"
+                     "       beq %2,2f\n"
+                     "       stq_c %0,%1\n"
+                     "       beq %0,1b\n"
+                     "2:\n"
+                     :"=&r" (temp), "=m" (*addr), "=&r" (was_equal)
+                     : "r" (new_val), "Ir" (old)
+                    :"memory");
+  return was_equal;
+}
+
+#define AO_HAVE_compare_and_swap
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/arm.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/arm.h
new file mode 100644 (file)
index 0000000..d1a3232
--- /dev/null
@@ -0,0 +1,52 @@
+/* 
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999-2003 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.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+/* There exist multiprocessor SoC ARM processors, so this matters.     */
+/* This needs to be augmented for later ARM (e.g. V7) procesors.       */
+
+/* I found a slide set that, if I read it correctly, claims that       */
+/* Loads followed by either a Load or Store are ordered, but nothing   */
+/* else is.                                                            */
+/* It appears that SWP is the only simple memory barrier.              */
+#include "../all_atomic_load_store.h"
+
+#include "../read_ordered.h"
+
+#include "../test_and_set_t_is_ao_t.h" /* Probably suboptimal */
+
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr) {
+  AO_TS_VAL_t oldval;
+  /* SWP on ARM is very similar to XCHG on x86.                */
+  /* The first operand is the result, the second the value     */
+  /* to be stored.  Both registers must be different from addr.        */
+  /* Make the address operand an early clobber output so it     */
+  /* doesn't overlap with the other operands.  The early clobber*/
+  /* on oldval is neccessary to prevent the compiler allocating */
+  /* them to the same register if they are both unused.        */
+  __asm__ __volatile__("swp %0, %2, [%3]"
+                        : "=&r"(oldval), "=&r"(addr)
+                        : "r"(1), "1"(addr)
+                        : "memory");
+  return oldval;
+}
+
+#define AO_HAVE_test_and_set_full
+
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/cris.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/cris.h
new file mode 100644 (file)
index 0000000..3864905
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ *
+ * Most of this code originally comes from Hans-Peter Nilsson.  It is included
+ * here with his permission.
+ *
+ * This version has not been tested.  It was coped here from a GC
+ * patch so that we wouldn't lose the code in the upgrade to gc7.
+ */ 
+
+#include "../all_atomic_load_store.h"
+
+#include "../ordered.h"  /* There are no multiprocessor implementations. */
+
+#include "../test_and_set_t_is_ao_t.h"
+
+/*
+ * The architecture apparently supports an "f" flag which is
+ * set on preemption.  This essentially gives us load-locked,
+ * store-conditional primitives, though I'm not quite sure how
+ * this would work on a hypothetical multiprocessor.  -HB
+ *
+ * For details, see
+ * http://developer.axis.com/doc/hardware/etrax100lx/prog_man/
+ *      1_architectural_description.pdf
+ *
+ * Presumably many other primitives (notably CAS, including the double-
+ * width versions) could be implemented in this manner, if someone got
+ * around to it.
+ */
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr) {
+    /* Ripped from linuxthreads/sysdeps/cris/pt-machine.h */
+    register unsigned long int ret;
+
+    /* Note the use of a dummy output of *addr to expose the write.  The
+       memory barrier is to stop *other* writes being moved past this code.  */
+      __asm__ __volatile__("clearf\n"
+                          "0:\n\t"
+                          "movu.b [%2],%0\n\t"
+                          "ax\n\t"
+                          "move.b %3,[%2]\n\t"
+                          "bwf 0b\n\t"
+                          "clearf"
+                          : "=&r" (ret), "=m" (*addr)
+                          : "r" (addr), "r" ((int) 1), "m" (*addr)
+                          : "memory");
+    return ret;
+}
+
+#define AO_HAVE_test_and_set_full
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/hppa.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/hppa.h
new file mode 100644 (file)
index 0000000..f303d7f
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ *
+ * Modified by Carlos O'Donell <carlos@baldric.uwo.ca>, 2003
+ *     - Added self-aligning lock.
+ * 
+ */ 
+
+#include "../all_atomic_load_store.h"
+
+/* Some architecture set descriptions include special "ordered" memory */
+/* operations.  As far as we can tell, no existing processors actually */
+/* require those.  Nor does it appear likely that future processors    */
+/* will.                                                               */
+#include "../ordered.h"
+
+/* GCC will not guarantee the alignment we need, use four lock words   */
+/* and select the correctly aligned datum. See the glibc 2.3.2         */
+/* linuxthread port for the original implementation.                   */
+struct AO_pa_clearable_loc {
+  int data[4];
+};
+
+#undef AO_TS_INITIALIZER
+#define AO_TS_t struct AO_pa_clearable_loc
+#define AO_TS_INITIALIZER {1,1,1,1}
+/* Switch meaning of set and clear, since we only have an atomic clear */
+/* instruction.                                                                */
+typedef enum {AO_PA_TS_set = 0, AO_PA_TS_clear = 1} AO_PA_TS_val;
+#define AO_TS_VAL_t AO_PA_TS_val
+#define AO_TS_CLEAR AO_PA_TS_clear
+#define AO_TS_SET AO_PA_TS_set
+
+/* The hppa only has one atomic read and modify memory operation,      */
+/* load and clear, so hppa spinlocks must use zero to signify that     */
+/* someone is holding the lock.  The address used for the ldcw         */
+/* semaphore must be 16-byte aligned.                                  */
+
+#define __ldcw(a) ({ \
+  volatile unsigned int __ret;                                 \
+  __asm__ __volatile__("ldcw 0(%2),%0"                         \
+                      : "=r" (__ret), "=m" (*(a)) : "r" (a));  \
+  __ret;                                                       \
+})
+
+/* Because malloc only guarantees 8-byte alignment for malloc'd data,  */
+/* and GCC only guarantees 8-byte alignment for stack locals, we can't */
+/* be assured of 16-byte alignment for atomic lock data even if we     */
+/* specify "__attribute ((aligned(16)))" in the type declaration.  So, */
+/* we use a struct containing an array of four ints for the atomic lock        */
+/* type and dynamically select the 16-byte aligned int from the array  */
+/* for the semaphore.                                                  */
+#define __PA_LDCW_ALIGNMENT 16
+#define __ldcw_align(a) ({ \
+  unsigned long __ret = (unsigned long) a;                     \
+  __ret += __PA_LDCW_ALIGNMENT - 1;                                    \
+  __ret &= ~(__PA_LDCW_ALIGNMENT - 1);                                 \
+  (volatile unsigned int *) __ret;                                     \
+})
+
+/* Works on PA 1.1 and PA 2.0 systems */
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t * addr)
+{
+  volatile unsigned int *a = __ldcw_align (addr);
+  return (AO_TS_VAL_t) __ldcw (a);
+} 
+
+AO_INLINE void
+AO_pa_clear(volatile AO_TS_t * addr)
+{
+  volatile unsigned int *a = __ldcw_align (addr);
+  AO_compiler_barrier();
+  *a = 1;
+}
+#define AO_CLEAR(addr) AO_pa_clear(addr)
+
+#define AO_HAVE_test_and_set_full
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/ia64.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/ia64.h
new file mode 100644 (file)
index 0000000..119b9ed
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+#include "../all_atomic_load_store.h"
+
+#include "../all_acquire_release_volatile.h"
+
+#include "../test_and_set_t_is_char.h"
+
+#ifdef _ILP32
+  /* 32-bit HP/UX code.        */
+  /* This requires pointer "swizzling".  Pointers need to be expanded  */
+  /* to 64 bits using the addp4 instruction before use.  This makes it */
+  /* hard to share code, but we try anyway.                            */
+# define AO_LEN "4"
+  /* We assume that addr always appears in argument position 1 in asm  */
+  /* code.  If it is clobbered due to swizzling, we also need it in    */
+  /* second position.  Any later arguments are referenced symbolically,        */
+  /* so that we don't have to worry about their position.  This requires*/
+  /* gcc 3.1, but you shouldn't be using anything older than that on   */
+  /* IA64 anyway.                                                      */
+  /* The AO_MASK macro is a workaround for the fact that HP/UX gcc     */
+  /* appears to otherwise store 64-bit pointers in ar.ccv, i.e. it     */
+  /* doesn't appear to clear high bits in a pointer value we pass into */
+  /* assembly code, even if it is supposedly of type AO_t.             */
+# define AO_IN_ADDR "1"(addr)
+# define AO_OUT_ADDR , "=r"(addr)
+# define AO_SWIZZLE "addp4 %1=0,%1;;\n"
+# define AO_MASK(ptr) __asm__("zxt4 %1=%1": "=r"(ptr) : "0"(ptr));
+#else
+# define AO_LEN "8"
+# define AO_IN_ADDR "r"(addr)
+# define AO_OUT_ADDR
+# define AO_SWIZZLE
+# define AO_MASK(ptr)
+#endif
+
+AO_INLINE void
+AO_nop_full()
+{
+  __asm__ __volatile__("mf" : : : "memory");
+}
+#define AO_HAVE_nop_full
+
+AO_INLINE AO_t
+AO_fetch_and_add1_acquire (volatile AO_t *addr)
+{
+  AO_t result;
+
+  __asm__ __volatile__ (AO_SWIZZLE
+                       "fetchadd" AO_LEN ".acq %0=[%1],1":
+                       "=r" (result) AO_OUT_ADDR: AO_IN_ADDR :"memory");
+  return result;
+}
+#define AO_HAVE_fetch_and_add1_acquire
+
+AO_INLINE AO_t
+AO_fetch_and_add1_release (volatile AO_t *addr)
+{
+  AO_t result;
+
+  __asm__ __volatile__ (AO_SWIZZLE
+                       "fetchadd" AO_LEN ".rel %0=[%1],1":
+                       "=r" (result) AO_OUT_ADDR: AO_IN_ADDR :"memory");
+  return result;
+}
+
+#define AO_HAVE_fetch_and_add1_release
+
+AO_INLINE AO_t
+AO_fetch_and_sub1_acquire (volatile AO_t *addr)
+{
+  AO_t result;
+
+  __asm__ __volatile__ (AO_SWIZZLE
+                       "fetchadd" AO_LEN ".acq %0=[%1],-1":
+                       "=r" (result) AO_OUT_ADDR: AO_IN_ADDR :"memory");
+  return result;
+}
+
+#define AO_HAVE_fetch_and_sub1_acquire
+
+AO_INLINE AO_t
+AO_fetch_and_sub1_release (volatile AO_t *addr)
+{
+  AO_t result;
+
+  __asm__ __volatile__ (AO_SWIZZLE
+                       "fetchadd" AO_LEN ".rel %0=[%1],-1":
+                       "=r" (result) AO_OUT_ADDR: AO_IN_ADDR :"memory");
+  return result;
+}
+
+#define AO_HAVE_fetch_and_sub1_release
+
+#ifndef _ILP32
+
+AO_INLINE unsigned int
+AO_int_fetch_and_add1_acquire (volatile unsigned int *addr)
+{
+  unsigned int result;
+
+  __asm__ __volatile__ ("fetchadd4.acq %0=[%1],1":
+                       "=r" (result): AO_IN_ADDR :"memory");
+  return result;
+}
+#define AO_HAVE_int_fetch_and_add1_acquire
+
+AO_INLINE unsigned int
+AO_int_fetch_and_add1_release (volatile unsigned int *addr)
+{
+  unsigned int result;
+
+  __asm__ __volatile__ ("fetchadd4.rel %0=[%1],1":
+                       "=r" (result): AO_IN_ADDR :"memory");
+  return result;
+}
+
+#define AO_HAVE_int_fetch_and_add1_release
+
+AO_INLINE unsigned int
+AO_int_fetch_and_sub1_acquire (volatile unsigned int *addr)
+{
+  unsigned int result;
+
+  __asm__ __volatile__ ("fetchadd4.acq %0=[%1],-1":
+                       "=r" (result): AO_IN_ADDR :"memory");
+  return result;
+}
+
+#define AO_HAVE_int_fetch_and_sub1_acquire
+
+AO_INLINE unsigned int
+AO_int_fetch_and_sub1_release (volatile unsigned int *addr)
+{
+  unsigned int result;
+
+  __asm__ __volatile__ ("fetchadd4.rel %0=[%1],-1":
+                       "=r" (result): AO_IN_ADDR :"memory");
+  return result;
+}
+
+#define AO_HAVE_int_fetch_and_sub1_release
+
+#endif /* !_ILP32 */
+
+AO_INLINE int
+AO_compare_and_swap_acquire(volatile AO_t *addr,
+                            AO_t old, AO_t new_val) 
+{
+  AO_t oldval;
+  AO_MASK(old);
+  __asm__ __volatile__(AO_SWIZZLE
+                      "mov ar.ccv=%[old] ;; cmpxchg" AO_LEN
+                      ".acq %0=[%1],%[new_val],ar.ccv"
+                      : "=r"(oldval) AO_OUT_ADDR
+                      : AO_IN_ADDR, [new_val]"r"(new_val), [old]"r"(old)
+                      : "memory");
+  return (oldval == old);
+}
+
+#define AO_HAVE_compare_and_swap_acquire
+
+AO_INLINE int
+AO_compare_and_swap_release(volatile AO_t *addr,
+                            AO_t old, AO_t new_val) 
+{
+  AO_t oldval;
+  AO_MASK(old);
+  __asm__ __volatile__(AO_SWIZZLE
+                      "mov ar.ccv=%[old] ;; cmpxchg" AO_LEN
+                      ".rel %0=[%1],%[new_val],ar.ccv"
+                      : "=r"(oldval) AO_OUT_ADDR
+                      : AO_IN_ADDR, [new_val]"r"(new_val), [old]"r"(old)
+                      : "memory");
+  return (oldval == old);
+}
+
+#define AO_HAVE_compare_and_swap_release
+
+AO_INLINE int
+AO_char_compare_and_swap_acquire(volatile unsigned char *addr,
+                                unsigned char old, unsigned char new_val) 
+{
+  unsigned char oldval;
+  __asm__ __volatile__(AO_SWIZZLE
+              "mov ar.ccv=%[old] ;; cmpxchg1.acq %0=[%1],%[new_val],ar.ccv"
+              : "=r"(oldval) AO_OUT_ADDR
+              : AO_IN_ADDR, [new_val]"r"(new_val), [old]"r"((AO_t)old)
+              : "memory");
+  return (oldval == old);
+}
+
+#define AO_HAVE_char_compare_and_swap_acquire
+
+AO_INLINE int
+AO_char_compare_and_swap_release(volatile unsigned char *addr,
+                                unsigned char old, unsigned char new_val) 
+{
+  unsigned char oldval;
+  __asm__ __volatile__(AO_SWIZZLE
+               "mov ar.ccv=%[old] ;; cmpxchg1.rel %0=[%1],%[new_val],ar.ccv"
+               : "=r"(oldval) AO_OUT_ADDR
+               : AO_IN_ADDR, [new_val]"r"(new_val), [old]"r"((AO_t)old)
+               : "memory");
+  return (oldval == old);
+}
+
+#define AO_HAVE_char_compare_and_swap_release
+
+AO_INLINE int
+AO_short_compare_and_swap_acquire(volatile unsigned short *addr,
+                                 unsigned short old, unsigned short new_val) 
+{
+  unsigned short oldval;
+  __asm__ __volatile__(AO_SWIZZLE
+               "mov ar.ccv=%[old] ;; cmpxchg2.acq %0=[%1],%[new_val],ar.ccv"
+               : "=r"(oldval) AO_OUT_ADDR
+               : AO_IN_ADDR, [new_val]"r"(new_val), [old]"r"((AO_t)old)
+               : "memory");
+  return (oldval == old);
+}
+
+#define AO_HAVE_short_compare_and_swap_acquire
+
+AO_INLINE int
+AO_short_compare_and_swap_release(volatile unsigned short *addr,
+                                 unsigned short old, unsigned short new_val) 
+{
+  unsigned short oldval;
+  __asm__ __volatile__(AO_SWIZZLE
+               "mov ar.ccv=%[old] ;; cmpxchg2.rel %0=[%1],%[new_val],ar.ccv"
+               : "=r"(oldval) AO_OUT_ADDR
+               : AO_IN_ADDR, [new_val]"r"(new_val), [old]"r"((AO_t)old)
+               : "memory");
+  return (oldval == old);
+}
+
+#define AO_HAVE_short_compare_and_swap_release
+
+#ifndef _ILP32
+
+AO_INLINE int
+AO_int_compare_and_swap_acquire(volatile unsigned int *addr,
+                               unsigned int old, unsigned int new_val) 
+{
+  unsigned int oldval;
+  __asm__ __volatile__("mov ar.ccv=%3 ;; cmpxchg4.acq %0=[%1],%2,ar.ccv"
+                      : "=r"(oldval)
+                      : AO_IN_ADDR, "r"(new_val), "r"((AO_t)old) : "memory");
+  return (oldval == old);
+}
+
+#define AO_HAVE_int_compare_and_swap_acquire
+
+AO_INLINE int
+AO_int_compare_and_swap_release(volatile unsigned int *addr,
+                               unsigned int old, unsigned int new_val) 
+{
+  unsigned int oldval;
+  __asm__ __volatile__("mov ar.ccv=%3 ;; cmpxchg4.rel %0=[%1],%2,ar.ccv"
+                      : "=r"(oldval)
+                      : AO_IN_ADDR, "r"(new_val), "r"((AO_t)old) : "memory");
+  return (oldval == old);
+}
+
+#define AO_HAVE_int_compare_and_swap_release
+
+#endif /* !_ILP32 */
+
+/* FIXME: Add compare_and_swap_double as soon as there is widely       */
+/* available hardware that implements it.                              */
+
+/* FIXME: Add compare_double_and_swap_double for the _ILP32 case.      */
+
+#ifdef _ILP32
+# include "../ao_t_is_int.h"
+#endif
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/m68k.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/m68k.h
new file mode 100644 (file)
index 0000000..9e7f70a
--- /dev/null
@@ -0,0 +1,45 @@
+/* 
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999-2003 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.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+/* FIXME.  Very incomplete.  */
+#include "../all_aligned_atomic_load_store.h"
+
+/* Are there any m68k multiprocessors still around?    */
+/* AFAIK, Alliants were sequentially consistent.       */
+#include "../ordered.h"
+
+#include "../test_and_set_t_is_ao_t.h"
+
+/* Contributed by Tony Mantler or new.  Should be changed to MIT license? */
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr) {
+  int oldval;
+
+  /* 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) : "memory");
+   return oldval;
+}
+
+#define AO_HAVE_test_and_set_full
+
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/powerpc.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/powerpc.h
new file mode 100644 (file)
index 0000000..a014a7b
--- /dev/null
@@ -0,0 +1,270 @@
+/* 
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
+ *
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+/* FIXME.  Incomplete.  No support for 64 bits.                                */
+/* Memory model documented at http://www-106.ibm.com/developerworks/   */
+/* eserver/articles/archguide.html and (clearer)                       */
+/* http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html. */
+/* There appears to be no implicit ordering between any kind of                */
+/* independent memory references.                                      */
+/* Architecture enforces some ordering based on control dependence.    */
+/* I don't know if that could help.                                    */
+/* Data-dependent loads are always ordered.                            */
+/* Based on the above references, eieio is intended for use on         */
+/* uncached memory, which we don't support.  It does not order loads   */
+/* from cached memory.                                                 */
+/* Thanks to Maged Michael, Doug Lea, and Roger Hoover for helping to  */
+/* track some of this down and correcting my misunderstandings. -HB    */
+
+#include "../all_aligned_atomic_load_store.h"
+
+#include "../test_and_set_t_is_ao_t.h"
+       /* There seems to be no byte equivalent of lwarx, so this       */
+       /* may really be what we want, at least in the 32-bit case.     */
+
+AO_INLINE void
+AO_nop_full()
+{
+  __asm__ __volatile__("sync" : : : "memory");
+}
+
+#define AO_HAVE_nop_full
+
+/* lwsync apparently works for everything but a StoreLoad barrier.     */
+AO_INLINE void
+AO_lwsync()
+{
+  __asm__ __volatile__("lwsync" : : : "memory");
+}
+
+#define AO_nop_write() AO_lwsync()
+#define AO_HAVE_nop_write
+
+#define AO_nop_read() AO_lwsync()
+#define AO_HAVE_nop_read
+
+/* We explicitly specify load_acquire, since it is important, and can  */
+/* be implemented relatively cheaply.  It could be implemented         */
+/* with an ordinary load followed by a lwsync.  But the general wisdom */
+/* seems to be that a data dependent branch followed by an isync is    */
+/* cheaper.  And the documentation is fairly explicit that this also   */
+/* has acquire semantics.                                              */
+/* ppc64 uses ld not lwz */
+#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
+AO_INLINE AO_t
+AO_load_acquire(volatile AO_t *addr)
+{
+  AO_t result;
+
+  /* FIXME: We should get gcc to allocate one of the condition */
+  /* registers.  I always got "impossible constraint" when I   */
+  /* tried the "y" constraint.                                 */
+  __asm__ __volatile__ (
+    "ld %0,%1\n"
+    "cmpw cr7,%0,%0\n"
+    "bne- cr7,1f\n"
+    "1: isync\n"
+    : "=r" (result)
+    : "m"(*addr) : "memory", "cc");
+  return result;
+}
+#else
+AO_INLINE AO_t
+AO_load_acquire(volatile AO_t *addr)
+{
+  AO_t result;
+
+  /* FIXME: We should get gcc to allocate one of the condition */
+  /* registers.  I always got "impossible constraint" when I   */
+  /* tried the "y" constraint.                                 */
+  __asm__ __volatile__ (
+    "lwz %0,%1\n"
+    "cmpw cr7,%0,%0\n"
+    "bne- cr7,1f\n"
+    "1: isync\n"
+    : "=r" (result)
+    : "m"(*addr) : "memory", "cc");
+  return result;
+}
+#endif
+#define AO_HAVE_load_acquire
+
+/* We explicitly specify store_release, since it relies        */
+/* on the fact that lwsync is also a LoadStore barrier.                */
+AO_INLINE void
+AO_store_release(volatile AO_t *addr, AO_t value)
+{
+  AO_lwsync();
+  *addr = value;
+}
+
+#define AO_HAVE_load_acquire
+
+/* This is similar to the code in the garbage collector.  Deleting     */
+/* this and having it synthesized from compare_and_swap would probably */
+/* only cost us a load immediate instruction.                          */
+#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
+/* Completely untested.  And we should be using smaller objects anyway. */
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set(volatile AO_TS_t *addr) {
+  unsigned long oldval;
+  unsigned long temp = 1; /* locked value */
+
+  __asm__ __volatile__(
+               "1:ldarx %0,0,%1\n"   /* load and reserve               */
+               "cmpdi %0, 0\n"       /* if load is                     */
+               "bne 2f\n"            /*   non-zero, return already set */
+               "stdcx. %2,0,%1\n"    /* else store conditional         */
+               "bne- 1b\n"           /* retry if lost reservation      */
+               "2:\n"                /* oldval is zero if we set       */
+              : "=&r"(oldval)
+              : "r"(addr), "r"(temp)
+              : "memory", "cc");
+
+  return (AO_TS_VAL_t)oldval;
+}
+
+#else
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set(volatile AO_TS_t *addr) {
+  int oldval;
+  int temp = 1; /* locked value */
+
+  __asm__ __volatile__(
+               "1:lwarx %0,0,%1\n"   /* load and reserve               */
+               "cmpwi %0, 0\n"       /* if load is                     */
+               "bne 2f\n"            /*   non-zero, return already set */
+               "stwcx. %2,0,%1\n"    /* else store conditional         */
+               "bne- 1b\n"           /* retry if lost reservation      */
+               "2:\n"                /* oldval is zero if we set       */
+              : "=&r"(oldval)
+              : "r"(addr), "r"(temp)
+              : "memory", "cc");
+
+  return (AO_TS_VAL_t)oldval;
+}
+
+#endif
+
+#define AO_have_test_and_set
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_acquire(volatile AO_TS_t *addr) {
+  AO_TS_VAL_t result = AO_test_and_set(addr);
+  AO_lwsync();
+  return result;
+}
+
+#define AO_HAVE_test_and_set_acquire
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_release(volatile AO_TS_t *addr) {
+  AO_lwsync();
+  return AO_test_and_set(addr);
+}
+
+#define AO_HAVE_test_and_set_release
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr) {
+  AO_TS_VAL_t result;
+  AO_lwsync();
+  result = AO_test_and_set(addr);
+  AO_lwsync();
+  return result;
+}
+
+#define AO_HAVE_test_and_set_full
+
+#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
+/* FIXME: Completely untested. */
+AO_INLINE int
+AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {
+  AO_t oldval;
+  int result = 0;
+
+  __asm__ __volatile__(
+               "1:ldarx %0,0,%2\n"   /* load and reserve              */
+               "cmpd %0, %4\n"      /* if load is not equal to         */
+               "bne 2f\n"            /*   old, fail                    */
+               "stdcx. %3,0,%2\n"    /* else store conditional         */
+               "bne- 1b\n"           /* retry if lost reservation      */
+              "li %1,1\n"           /* result = 1;                     */
+               "2:\n"
+              : "=&r"(oldval), "=&r"(result)
+              : "r"(addr), "r"(new_val), "r"(old), "1"(result)
+              : "memory", "cc");
+
+  return result;
+}
+
+#else
+
+AO_INLINE int
+AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {
+  AO_t oldval;
+  int result = 0;
+
+  __asm__ __volatile__(
+               "1:lwarx %0,0,%2\n"   /* load and reserve              */
+               "cmpw %0, %4\n"      /* if load is not equal to         */
+               "bne 2f\n"            /*   old, fail                    */
+               "stwcx. %3,0,%2\n"    /* else store conditional         */
+               "bne- 1b\n"           /* retry if lost reservation      */
+              "li %1,1\n"           /* result = 1;                     */
+               "2:\n"
+              : "=&r"(oldval), "=&r"(result)
+              : "r"(addr), "r"(new_val), "r"(old), "1"(result)
+              : "memory", "cc");
+
+  return result;
+}
+#endif
+
+#define AO_HAVE_compare_and_swap
+
+AO_INLINE int
+AO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val) {
+  int result = AO_compare_and_swap(addr, old, new_val);
+  AO_lwsync();
+  return result;
+}
+
+#define AO_HAVE_compare_and_swap_acquire
+
+AO_INLINE int
+AO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val) {
+  AO_lwsync();
+  return AO_compare_and_swap(addr, old, new_val);
+}
+
+#define AO_HAVE_compare_and_swap_release
+
+AO_INLINE int
+AO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {
+  AO_t result;
+  AO_lwsync();
+  result = AO_compare_and_swap(addr, old, new_val);
+  AO_lwsync();
+  return result;
+}
+
+#define AO_HAVE_compare_and_swap_full
+
+/* FIXME: We should also implement fetch_and_add and or primitives     */
+/* directly.                                                           */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/s390.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/s390.h
new file mode 100644 (file)
index 0000000..7cb9986
--- /dev/null
@@ -0,0 +1,63 @@
+/* 
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999-2003 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.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+/* FIXME: untested.                                            */
+/* The relevant documentation appears to be at                 */
+/* http://publibz.boulder.ibm.com/epubs/pdf/dz9zr003.pdf       */
+/* around page 5-96.  Apparently:                              */
+/* - Memory references in general are atomic only for a single         */
+/*   byte.  But it appears that the most common load/store     */
+/*   instructions also guarantee atomicity for aligned                 */
+/*   operands of standard types.  WE FOOLISHLY ASSUME that     */
+/*   compilers only generate those.  If that turns out to be   */
+/*   wrong, we need inline assembly code for AO_load and       */
+/*   AO_store.                                                 */
+/* - A store followed by a load is unordered since the store   */
+/*   may be delayed.  Otherwise everything is ordered.         */
+/* - There is a hardware compare-and-swap (CS) instruction.    */
+
+#include "ordered_except_wr.h"
+#include "all_aligned_atomic_load_store.h"
+
+#include "../test_and_set_t_is_ao_t.h"
+/* FIXME: Is there a way to do byte-sized test-and-set?        */
+
+/* FIXME: AO_nop_full should probably be implemented directly. */
+/* It appears that certain BCR instructions have that effect.  */
+/* Presumably they're cheaper than CS?                         */
+
+AO_INLINE AO_t AO_compare_and_swap_full(volatile AO_t *addr,
+                                               AO_t old, AO_t new_val)
+{
+  int retval;
+  __asm__ __volatile__ (
+# ifndef __s390x__
+    "     cs  %1,%2,0(%3)\n"
+# else
+    "     csg %1,%2,0(%3)\n"
+# endif
+  "     ipm %0\n"
+  "     srl %0,28\n"
+  : "=&d" (retval), "+d" (old)
+  : "d" (new_val), "a" (addr)
+  : "cc", "memory");
+  return retval == 0;
+}
+
+#define AO_HAVE_compare_and_swap_full
+
+/* FIXME: Add double-wide compare-and-swap for 32-bit executables.     */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/sparc.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/sparc.h
new file mode 100644 (file)
index 0000000..4850855
--- /dev/null
@@ -0,0 +1,46 @@
+/* 
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999-2003 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.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+/* FIXME.  Very incomplete.  No support for sparc64.   */
+/* Non-ancient SPARCs provide compare-and-swap (casa). */
+/* We should make that available.                      */
+
+#include "../all_atomic_load_store.h"
+
+/* Real SPARC code uses TSO:                           */
+#include "../ordered_except_wr.h"
+
+/* Test_and_set location is just a byte.                */
+#include "../test_and_set_t_is_char.h"
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr) {
+  int oldval;
+
+   __asm__ __volatile__("ldstub %1,%0"
+                       : "=r"(oldval), "=m"(*addr)
+                       : "m"(*addr) : "memory");
+   return oldval;
+}
+
+#define AO_HAVE_test_and_set_full
+
+/* FIXME: This needs to be extended for SPARC v8 and v9.       */
+/* SPARC V8 also has swap.  V9 has CAS.                                */
+/* There are barriers like membar #LoadStore.                  */
+/* CASA (32-bit) and CASXA(64-bit) instructions were           */
+/* added in V9.                                                        */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/x86.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/x86.h
new file mode 100644 (file)
index 0000000..27e047e
--- /dev/null
@@ -0,0 +1,153 @@
+/* 
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999-2003 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.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ * Some of the machine specific code was borrowed from our GC distribution.
+ */
+
+/* The following really assume we have a 486 or better.  Unfortunately */
+/* gcc doesn't define a suitable feature test macro based on command   */
+/* line options.                                                       */
+/* We should perhaps test dynamically.                                 */
+
+#include "../all_aligned_atomic_load_store.h"
+
+/* Real X86 implementations, except for some old WinChips, appear      */
+/* to enforce ordering between memory operations, EXCEPT that a later  */
+/* read can pass earlier writes, presumably due to the visible         */
+/* presence of store buffers.                                          */
+/* We ignore both the WinChips, and the fact that the official specs   */
+/* seem to be much weaker (and arguably too weak to be usable).                */
+
+#include "../ordered_except_wr.h"
+
+#include "../test_and_set_t_is_char.h"
+
+#include "../standard_ao_double_t.h"
+
+#if defined(AO_USE_PENTIUM4_INSTRS)
+AO_INLINE void
+AO_nop_full()
+{
+  __asm__ __volatile__("mfence" : : : "memory");
+}
+
+#define AO_HAVE_nop_full
+
+#else
+
+/* We could use the cpuid instruction.  But that seems to be slower    */
+/* than the default implementation based on test_and_set_full.  Thus   */
+/* we omit that bit of misinformation here.                            */
+
+#endif
+
+/* As far as we can tell, the lfence and sfence instructions are not   */
+/* currently needed or useful for cached memory accesses.              */
+
+/* Really only works for 486 and later */
+AO_INLINE AO_t
+AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
+{
+  AO_t result;
+
+  __asm__ __volatile__ ("lock; xaddl %0, %1" :
+                       "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
+                       : "memory");
+  return result;
+}
+
+#define AO_HAVE_fetch_and_add_full
+
+AO_INLINE unsigned char
+AO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)
+{
+  unsigned char result;
+
+  __asm__ __volatile__ ("lock; xaddb %0, %1" :
+                       "=q" (result), "=m" (*p) : "0" (incr), "m" (*p)
+                       : "memory");
+  return result;
+}
+
+#define AO_HAVE_char_fetch_and_add_full
+
+AO_INLINE unsigned short
+AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
+{
+  unsigned short result;
+
+  __asm__ __volatile__ ("lock; xaddw %0, %1" :
+                       "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
+                       : "memory");
+  return result;
+}
+
+#define AO_HAVE_short_fetch_and_add_full
+
+/* Really only works for 486 and later */
+AO_INLINE void
+AO_or_full (volatile AO_t *p, AO_t incr)
+{
+  __asm__ __volatile__ ("lock; orl %1, %0" :
+                       "=m" (*p) : "r" (incr), "m" (*p) : "memory");
+}
+
+#define AO_HAVE_or_full
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr)
+{
+  unsigned char oldval;
+  /* Note: the "xchg" instruction does not need a "lock" prefix */
+  __asm__ __volatile__("xchgb %0, %1"
+               : "=q"(oldval), "=m"(*addr)
+               : "0"(0xff), "m"(*addr) : "memory");
+  return (AO_TS_VAL_t)oldval;
+}
+
+#define AO_HAVE_test_and_set_full
+
+/* Returns nonzero if the comparison succeeded. */
+AO_INLINE int
+AO_compare_and_swap_full(volatile AO_t *addr,
+                            AO_t old, AO_t new_val) 
+{
+  char result;
+  __asm__ __volatile__("lock; cmpxchgl %3, %0; setz %1"
+                      : "=m"(*addr), "=q"(result)
+                      : "m"(*addr), "r" (new_val), "a"(old) : "memory");
+  return (int) result;
+}
+
+#define AO_HAVE_compare_and_swap_full
+
+/* Returns nonzero if the comparison succeeded. */
+/* Really requires at least a Pentium.         */
+AO_INLINE int
+AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
+                                      AO_t old_val1, AO_t old_val2,
+                                      AO_t new_val1, AO_t new_val2) 
+{
+  char result;
+  __asm__ __volatile__("lock; cmpxchg8b %0; setz %1"
+                      : "=m"(*addr), "=q"(result)
+                      : "m"(*addr), "d" (old_val1), "a" (old_val2),
+                        "c" (new_val1), "b" (new_val2) : "memory");
+  return (int) result;
+}
+
+#define AO_HAVE_double_compare_and_swap_full
+
+#include "../ao_t_is_int.h"
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/x86_64.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/x86_64.h
new file mode 100644 (file)
index 0000000..75c2448
--- /dev/null
@@ -0,0 +1,147 @@
+/* 
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 1999-2003 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.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ * Some of the machine specific code was borrowed from our GC distribution.
+ */
+
+/* The following really assume we have a 486 or better.  Unfortunately */
+/* gcc doesn't define a suitable feature test macro based on command   */
+/* line options.                                                       */
+/* We should perhaps test dynamically.                                 */
+
+#include "../all_aligned_atomic_load_store.h"
+
+/* Real X86 implementations, except for some old WinChips, appear      */
+/* to enforce ordering between memory operations, EXCEPT that a later  */
+/* read can pass earlier writes, presumably due to the visible         */
+/* presence of store buffers.                                          */
+/* We ignore both the WinChips, and the fact that the official specs   */
+/* seem to be much weaker (and arguably too weak to be usable).                */
+
+#include "../ordered_except_wr.h"
+
+#include "../test_and_set_t_is_char.h"
+
+#if defined(AO_USE_PENTIUM4_INSTRS)
+AO_INLINE void
+AO_nop_full()
+{
+  __asm__ __volatile__("mfence" : : : "memory");
+}
+
+#define AO_HAVE_nop_full
+
+#else
+
+/* We could use the cpuid instruction.  But that seems to be slower    */
+/* than the default implementation based on test_and_set_full.  Thus   */
+/* we omit that bit of misinformation here.                            */
+
+#endif
+
+/* As far as we can tell, the lfence and sfence instructions are not   */
+/* currently needed or useful for cached memory accesses.              */
+
+/* Really only works for 486 and later */
+AO_INLINE AO_t
+AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
+{
+  AO_t result;
+
+  __asm__ __volatile__ ("lock; xaddq %0, %1" :
+                       "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
+                       : "memory");
+  return result;
+}
+
+#define AO_HAVE_fetch_and_add_full
+
+AO_INLINE unsigned char
+AO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)
+{
+  unsigned char result;
+
+  __asm__ __volatile__ ("lock; xaddb %0, %1" :
+                       "=q" (result), "=m" (*p) : "0" (incr), "m" (*p)
+                       : "memory");
+  return result;
+}
+
+#define AO_HAVE_char_fetch_and_add_full
+
+AO_INLINE unsigned short
+AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
+{
+  unsigned short result;
+
+  __asm__ __volatile__ ("lock; xaddw %0, %1" :
+                       "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
+                       : "memory");
+  return result;
+}
+
+#define AO_HAVE_short_fetch_and_add_full
+
+AO_INLINE unsigned short
+AO_int_fetch_and_add_full (volatile unsigned int *p, unsigned int incr)
+{
+  unsigned int result;
+
+  __asm__ __volatile__ ("lock; xaddl %0, %1" :
+                       "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
+                       : "memory");
+  return result;
+}
+
+#define AO_HAVE_int_fetch_and_add_full
+
+/* Really only works for 486 and later */
+AO_INLINE void
+AO_or_full (volatile AO_t *p, AO_t incr)
+{
+  __asm__ __volatile__ ("lock; orq %1, %0" :
+                       "=m" (*p) : "r" (incr), "m" (*p) : "memory");
+}
+
+#define AO_HAVE_or_full
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr)
+{
+  unsigned char oldval;
+  /* Note: the "xchg" instruction does not need a "lock" prefix */
+  __asm__ __volatile__("xchgb %0, %1"
+               : "=q"(oldval), "=m"(*addr)
+               : "0"(0xff), "m"(*addr) : "memory");
+  return (AO_TS_VAL_t)oldval;
+}
+
+#define AO_HAVE_test_and_set_full
+
+/* Returns nonzero if the comparison succeeded. */
+AO_INLINE int
+AO_compare_and_swap_full(volatile AO_t *addr,
+                            AO_t old, AO_t new_val) 
+{
+  char result;
+  __asm__ __volatile__("lock; cmpxchgq %3, %0; setz %1"
+                      : "=m"(*addr), "=q"(result)
+                      : "m"(*addr), "r" (new_val), "a"(old) : "memory");
+  return (int) result;
+}
+
+#define AO_HAVE_compare_and_swap_full
+
+/* FIXME: The Intel version has a 16byte CAS instruction.      */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/generic_pthread.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/generic_pthread.h
new file mode 100644 (file)
index 0000000..8d17c0a
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/* The following is useful primarily for debugging and documentation.  */
+/* We define various atomic operations by acquiring a global pthread   */
+/* lock.  The resulting implementation will perform poorly, but should */
+/* be correct unless it is used from signal handlers.                  */
+/* We assume that all pthread operations act like full memory barriers.        */
+/* (We believe that is the intent of the specification.)               */
+
+#include <pthread.h>
+
+#include "test_and_set_t_is_ao_t.h"
+       /* This is not necessarily compatible with the native           */
+       /* implementation.  But those can't be safely mixed anyway.     */
+
+/* We define only the full barrier variants, and count on the          */
+/* generalization section below to fill in the rest.                   */
+extern pthread_mutex_t AO_pt_lock;
+
+AO_INLINE void
+AO_nop_full()
+{
+  pthread_mutex_lock(&AO_pt_lock);
+  pthread_mutex_unlock(&AO_pt_lock);
+}
+
+#define AO_HAVE_nop_full
+
+AO_INLINE AO_t
+AO_load_full(volatile AO_t *addr)
+{
+  AO_t result;
+  pthread_mutex_lock(&AO_pt_lock);
+  result = *addr;
+  pthread_mutex_unlock(&AO_pt_lock);
+  return result;
+}
+
+#define AO_HAVE_load_full
+
+AO_INLINE void
+AO_store_full(volatile AO_t *addr, AO_t val)
+{
+  pthread_mutex_lock(&AO_pt_lock);
+  *addr = val;
+  pthread_mutex_unlock(&AO_pt_lock);
+}
+
+#define AO_HAVE_store_full
+
+AO_INLINE unsigned char
+AO_char_load_full(volatile unsigned char *addr)
+{
+  unsigned char result;
+  pthread_mutex_lock(&AO_pt_lock);
+  result = *addr;
+  pthread_mutex_unlock(&AO_pt_lock);
+  return result;
+}
+
+#define AO_HAVE_char_load_full
+
+AO_INLINE void
+AO_char_store_full(volatile unsigned char *addr, unsigned char val)
+{
+  pthread_mutex_lock(&AO_pt_lock);
+  *addr = val;
+  pthread_mutex_unlock(&AO_pt_lock);
+}
+
+#define AO_HAVE_char_store_full
+
+AO_INLINE unsigned short
+AO_short_load_full(volatile unsigned short *addr)
+{
+  unsigned short result;
+  pthread_mutex_lock(&AO_pt_lock);
+  result = *addr;
+  pthread_mutex_unlock(&AO_pt_lock);
+  return result;
+}
+
+#define AO_HAVE_short_load_full
+
+AO_INLINE void
+AO_short_store_full(volatile unsigned short *addr, unsigned short val)
+{
+  pthread_mutex_lock(&AO_pt_lock);
+  *addr = val;
+  pthread_mutex_unlock(&AO_pt_lock);
+}
+
+#define AO_HAVE_short_store_full
+
+AO_INLINE unsigned int
+AO_int_load_full(volatile unsigned int *addr)
+{
+  unsigned int result;
+  pthread_mutex_lock(&AO_pt_lock);
+  result = *addr;
+  pthread_mutex_unlock(&AO_pt_lock);
+  return result;
+}
+
+#define AO_HAVE_int_load_full
+
+AO_INLINE void
+AO_int_store_full(volatile unsigned int *addr, unsigned int val)
+{
+  pthread_mutex_lock(&AO_pt_lock);
+  *addr = val;
+  pthread_mutex_unlock(&AO_pt_lock);
+}
+
+#define AO_HAVE_int_store_full
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr)
+{
+  AO_TS_VAL_t result;
+  pthread_mutex_lock(&AO_pt_lock);
+  result = (AO_TS_VAL_t)(*addr);
+  *addr = AO_TS_SET;
+  pthread_mutex_unlock(&AO_pt_lock);
+  assert(result == AO_TS_SET || result == AO_TS_CLEAR);
+  return result;
+}
+
+#define AO_HAVE_test_and_set_full
+
+AO_INLINE AO_t
+AO_fetch_and_add_full(volatile AO_t *p, AO_t incr)
+{
+  AO_t tmp;
+
+  pthread_mutex_lock(&AO_pt_lock);
+  tmp = *p;
+  *p = tmp + incr;
+  pthread_mutex_unlock(&AO_pt_lock);
+  return tmp;
+}
+
+#define AO_HAVE_fetch_and_add_full
+
+AO_INLINE unsigned char
+AO_char_fetch_and_add_full(volatile unsigned char *p, unsigned char incr)
+{
+  unsigned char tmp;
+
+  pthread_mutex_lock(&AO_pt_lock);
+  tmp = *p;
+  *p = tmp + incr;
+  pthread_mutex_unlock(&AO_pt_lock);
+  return tmp;
+}
+
+#define AO_HAVE_char_fetch_and_add_full
+
+AO_INLINE unsigned short
+AO_short_fetch_and_add_full(volatile unsigned short *p, unsigned short incr)
+{
+  unsigned short tmp;
+
+  pthread_mutex_lock(&AO_pt_lock);
+  tmp = *p;
+  *p = tmp + incr;
+  pthread_mutex_unlock(&AO_pt_lock);
+  return tmp;
+}
+
+#define AO_HAVE_short_fetch_and_add_full
+
+AO_INLINE unsigned int
+AO_int_fetch_and_add_full(volatile unsigned int *p, unsigned int incr)
+{
+  unsigned int tmp;
+
+  pthread_mutex_lock(&AO_pt_lock);
+  tmp = *p;
+  *p = tmp + incr;
+  pthread_mutex_unlock(&AO_pt_lock);
+  return tmp;
+}
+
+#define AO_HAVE_int_fetch_and_add_full
+
+AO_INLINE void
+AO_or_full(volatile AO_t *p, AO_t incr)
+{
+  AO_t tmp;
+
+  pthread_mutex_lock(&AO_pt_lock);
+  tmp = *p;
+  *p = (tmp | incr);
+  pthread_mutex_unlock(&AO_pt_lock);
+}
+
+#define AO_HAVE_or_full
+
+AO_INLINE int
+AO_compare_and_swap_full(volatile AO_t *addr,
+                            AO_t old, AO_t new_val) 
+{
+  pthread_mutex_lock(&AO_pt_lock);
+  if (*addr == old)
+    {
+      *addr = new_val;
+      pthread_mutex_unlock(&AO_pt_lock);
+      return 1;
+    }
+  else
+    pthread_mutex_unlock(&AO_pt_lock);
+    return 0;
+}
+
+#define AO_HAVE_compare_and_swap_full
+
+/* Unlike real architectures, we define both double-width CAS variants. */
+
+typedef struct {
+       AO_t AO_val1;
+       AO_t AO_val2;
+} AO_double_t;
+
+#define AO_HAVE_double_t
+
+AO_INLINE int
+AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
+                                      AO_t old1, AO_t old2,
+                                      AO_t new1, AO_t new2) 
+{
+  pthread_mutex_lock(&AO_pt_lock);
+  if (addr -> AO_val1 == old1 && addr -> AO_val2 == old2)
+    {
+      addr -> AO_val1 = new1;
+      addr -> AO_val2 = new2;
+      pthread_mutex_unlock(&AO_pt_lock);
+      return 1;
+    }
+  else
+    pthread_mutex_unlock(&AO_pt_lock);
+    return 0;
+}
+
+#define AO_HAVE_compare_double_and_swap_double_full
+
+AO_INLINE int
+AO_compare_and_swap_double_full(volatile AO_double_t *addr,
+                               AO_t old1,
+                               AO_t new1, AO_t new2) 
+{
+  pthread_mutex_lock(&AO_pt_lock);
+  if (addr -> AO_val1 == old1)
+    {
+      addr -> AO_val1 = new1;
+      addr -> AO_val2 = new2;
+      pthread_mutex_unlock(&AO_pt_lock);
+      return 1;
+    }
+  else
+    pthread_mutex_unlock(&AO_pt_lock);
+    return 0;
+}
+
+#define AO_HAVE_compare_and_swap_double_full
+
+/* We can't use hardware loads and stores, since they don't    */
+/* interact correctly with atomic updates.                     */
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc/hppa.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc/hppa.h
new file mode 100644 (file)
index 0000000..80bd94c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ * 
+ * Derived from the corresponsing header file for gcc.
+ * 
+ */ 
+
+#include "../atomic_load_store.h"
+
+/* Some architecture set descriptions include special "ordered" memory */
+/* operations.  As far as we can tell, no existing processors actually */
+/* require those.  Nor does it appear likely that future processors    */
+/* will.                                                               */
+/* FIXME:                                                              */
+/* The PA emulator on Itanium may obey weaker restrictions.            */
+/* There should be a mode in which we don't assume sequential          */
+/* consistency here.                                                   */
+#include "../ordered.h"
+
+#include <machine/inline.h>
+
+/* GCC will not guarantee the alignment we need, use four lock words   */
+/* and select the correctly aligned datum. See the glibc 2.3.2         */
+/* linuxthread port for the original implementation.                   */
+struct AO_pa_clearable_loc {
+  int data[4];
+};
+
+#undef AO_TS_INITIALIZER
+#define AO_TS_t struct AO_pa_clearable_loc
+#define AO_TS_INITIALIZER {1,1,1,1}
+/* Switch meaning of set and clear, since we only have an atomic clear */
+/* instruction.                                                                */
+typedef enum {AO_PA_TS_set = 0, AO_PA_TS_clear = 1} AO_PA_TS_val;
+#define AO_TS_VAL_t AO_PA_TS_val
+#define AO_TS_CLEAR AO_PA_TS_clear
+#define AO_TS_SET AO_PA_TS_set
+
+/* The hppa only has one atomic read and modify memory operation,      */
+/* load and clear, so hppa spinlocks must use zero to signify that     */
+/* someone is holding the lock.  The address used for the ldcw         */
+/* semaphore must be 16-byte aligned.                                  */
+
+#define __ldcw(a, ret)  \
+  _LDCWX(0 /* index */, 0 /* s */, a /* base */, ret);
+
+/* Because malloc only guarantees 8-byte alignment for malloc'd data,  */
+/* and GCC only guarantees 8-byte alignment for stack locals, we can't */
+/* be assured of 16-byte alignment for atomic lock data even if we     */
+/* specify "__attribute ((aligned(16)))" in the type declaration.  So, */
+/* we use a struct containing an array of four ints for the atomic lock        */
+/* type and dynamically select the 16-byte aligned int from the array  */
+/* for the semaphore.                                                  */
+#define __PA_LDCW_ALIGNMENT 16
+
+#define __ldcw_align(a, ret) { \
+  ret = (unsigned long) a;                     \
+  ret += __PA_LDCW_ALIGNMENT - 1;                                      \
+  ret &= ~(__PA_LDCW_ALIGNMENT - 1);                                   \
+}
+
+/* Works on PA 1.1 and PA 2.0 systems */
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t * addr)
+{
+  register unsigned int ret;
+  register unsigned long a;
+  __ldcw_align (addr, a);
+  __ldcw (a, ret);
+  return ret;
+} 
+
+AO_INLINE void
+AO_pa_clear(volatile AO_TS_t * addr)
+{
+  unsigned long a;
+  __ldcw_align (addr,a);
+  AO_compiler_barrier();
+  *(volatile unsigned int *)a = 1;
+}
+#define AO_CLEAR(addr) AO_pa_clear(addr)
+
+#define AO_HAVE_test_and_set_full
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc/ia64.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc/ia64.h
new file mode 100644 (file)
index 0000000..99fdbb2
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * This file specifies Itanimum primitives for use with the HP compiler
+ * unde HP/UX.  We use intrinsics instead of the inline assembly code in the
+ * gcc file.
+ */
+
+#include "../all_atomic_load_store.h"
+
+#include "../all_acquire_release_volatile.h"
+
+#include "../test_and_set_t_is_char.h"
+
+#include <machine/sys/inline.h>
+
+#ifdef __LP64__
+# define AO_T_FASIZE _FASZ_D
+# define AO_T_SIZE _SZ_D
+#else
+# define AO_T_FASIZE _FASZ_W
+# define AO_T_SIZE _SZ_W
+#endif
+
+AO_INLINE void
+AO_nop_full()
+{
+  _Asm_mf();
+}
+#define AO_HAVE_nop_full
+
+AO_INLINE AO_t
+AO_fetch_and_add1_acquire (volatile AO_t *p)
+{
+  return _Asm_fetchadd(AO_T_FASIZE, _SEM_ACQ, p, 1,
+                      _LDHINT_NONE, _DOWN_MEM_FENCE);
+}
+#define AO_HAVE_fetch_and_add1_acquire
+
+AO_INLINE AO_t
+AO_fetch_and_add1_release (volatile AO_t *p)
+{
+  return _Asm_fetchadd(AO_T_FASIZE, _SEM_REL, p, 1,
+                      _LDHINT_NONE, _UP_MEM_FENCE);
+}
+
+#define AO_HAVE_fetch_and_add1_release
+
+AO_INLINE AO_t
+AO_fetch_and_sub1_acquire (volatile AO_t *p)
+{
+  return _Asm_fetchadd(AO_T_FASIZE, _SEM_ACQ, p, -1,
+                      _LDHINT_NONE, _DOWN_MEM_FENCE);
+}
+
+#define AO_HAVE_fetch_and_sub1_acquire
+
+AO_INLINE AO_t
+AO_fetch_and_sub1_release (volatile AO_t *p)
+{
+  return _Asm_fetchadd(AO_T_FASIZE, _SEM_REL, p, -1,
+                      _LDHINT_NONE, _UP_MEM_FENCE);
+}
+
+#define AO_HAVE_fetch_and_sub1_release
+
+AO_INLINE int
+AO_compare_and_swap_acquire(volatile AO_t *addr,
+                            AO_t old, AO_t new_val) 
+{
+  AO_t oldval;
+
+  _Asm_mov_to_ar(_AREG_CCV, old, _DOWN_MEM_FENCE);
+  oldval = _Asm_cmpxchg(AO_T_SIZE, _SEM_ACQ, addr,
+                       new_val, _LDHINT_NONE, _DOWN_MEM_FENCE);
+  return (oldval == old);
+}
+
+#define AO_HAVE_compare_and_swap_acquire
+
+AO_INLINE int
+AO_compare_and_swap_release(volatile AO_t *addr,
+                            AO_t old, AO_t new_val) 
+{
+  AO_t oldval;
+  _Asm_mov_to_ar(_AREG_CCV, old, _UP_MEM_FENCE);
+  oldval = _Asm_cmpxchg(AO_T_SIZE, _SEM_REL, addr,
+                       new_val, _LDHINT_NONE, _UP_MEM_FENCE);
+  /* Hopefully the compiler knows not to reorder the above two? */
+  return (oldval == old);
+}
+
+#define AO_HAVE_compare_and_swap_release
+
+AO_INLINE int
+AO_char_compare_and_swap_acquire(volatile unsigned char *addr,
+                                unsigned char old, unsigned char new_val) 
+{
+  unsigned char oldval;
+
+  _Asm_mov_to_ar(_AREG_CCV, old, _DOWN_MEM_FENCE);
+  oldval = _Asm_cmpxchg(_SZ_B, _SEM_ACQ, addr,
+                       new_val, _LDHINT_NONE, _DOWN_MEM_FENCE);
+  return (oldval == old);
+}
+
+#define AO_HAVE_char_compare_and_swap_acquire
+
+AO_INLINE int
+AO_char_compare_and_swap_release(volatile unsigned char *addr,
+                                unsigned char old, unsigned char new_val) 
+{
+  unsigned char oldval;
+  _Asm_mov_to_ar(_AREG_CCV, old, _UP_MEM_FENCE);
+  oldval = _Asm_cmpxchg(_SZ_B, _SEM_REL, addr,
+                       new_val, _LDHINT_NONE, _UP_MEM_FENCE);
+  /* Hopefully the compiler knows not to reorder the above two? */
+  return (oldval == old);
+}
+
+#define AO_HAVE_char_compare_and_swap_release
+
+AO_INLINE int
+AO_short_compare_and_swap_acquire(volatile unsigned short *addr,
+                                unsigned short old, unsigned short new_val) 
+{
+  unsigned short oldval;
+
+  _Asm_mov_to_ar(_AREG_CCV, old, _DOWN_MEM_FENCE);
+  oldval = _Asm_cmpxchg(_SZ_B, _SEM_ACQ, addr,
+                       new_val, _LDHINT_NONE, _DOWN_MEM_FENCE);
+  return (oldval == old);
+}
+
+#define AO_HAVE_short_compare_and_swap_acquire
+
+AO_INLINE int
+AO_short_compare_and_swap_release(volatile unsigned short *addr,
+                                unsigned short old, unsigned short new_val) 
+{
+  unsigned short oldval;
+  _Asm_mov_to_ar(_AREG_CCV, old, _UP_MEM_FENCE);
+  oldval = _Asm_cmpxchg(_SZ_B, _SEM_REL, addr,
+                       new_val, _LDHINT_NONE, _UP_MEM_FENCE);
+  /* Hopefully the compiler knows not to reorder the above two? */
+  return (oldval == old);
+}
+
+#define AO_HAVE_short_compare_and_swap_release
+
+#ifndef __LP64__
+# include "../ao_t_is_int.h"
+#endif
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ibmc/powerpc.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ibmc/powerpc.h
new file mode 100644 (file)
index 0000000..d1f9c50
--- /dev/null
@@ -0,0 +1,126 @@
+/* FIXME.  This is only a placeholder for the AIX compiler.            */
+/* It doesn't work.  Please send a patch.                              */
+/* Memory model documented at http://www-106.ibm.com/developerworks/   */
+/* eserver/articles/archguide.html and (clearer)                       */
+/* http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html. */
+/* There appears to be no implicit ordering between any kind of                */
+/* independent memory references.                                      */
+/* Architecture enforces some ordering based on control dependence.    */
+/* I don't know if that could help.                                    */
+/* Data-dependent loads are always ordered.                            */
+/* Based on the above references, eieio is intended for use on         */
+/* uncached memory, which we don't support.  It does not order loads   */
+/* from cached memory.                                                 */
+/* Thanks to Maged Michael, Doug Lea, and Roger Hoover for helping to  */
+/* track some of this down and correcting my misunderstandings. -HB    */
+
+#include "../all_aligned_atomic_load_store.h"
+
+void AO_sync(void);
+#pragma mc_func AO_sync { "7c0004ac" }
+
+void AO_lwsync(void);
+#pragma mc_func AO_lwsync { "7c2004ac" }
+
+#define AO_nop_write() AO_lwsync()
+#define AO_HAVE_nop_write
+
+#define AO_nop_read() AO_lwsync()
+#define AO_HAVE_nop_read
+
+/* We explicitly specify load_acquire and store_release, since these   */
+/* rely on the fact that lwsync is also a LoadStore barrier.           */
+AO_INLINE AO_t
+AO_load_acquire(volatile AO_t *addr)
+{
+  AO_t result = *addr;
+  AO_lwsync();
+  return result;
+}
+
+#define AO_HAVE_load_acquire
+
+AO_INLINE void
+AO_store_release(volatile AO_t *addr, AO_t value)
+{
+  AO_lwsync();
+  *addr = value;
+}
+
+#define AO_HAVE_load_acquire
+
+/* This is similar to the code in the garbage collector.  Deleting     */
+/* this and having it synthesized from compare_and_swap would probably */
+/* only cost us a load immediate instruction.                          */
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set(volatile AO_TS_t *addr) {
+# error Implement me
+}
+
+#define AO_have_test_and_set
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_acquire(volatile AO_TS_t *addr) {
+  AO_TS_VAL_t result = AO_test_and_set(addr);
+  AO_lwsync();
+  return result;
+}
+
+#define AO_HAVE_test_and_set_acquire
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_release(volatile AO_TS_t *addr) {
+  AO_lwsync();
+  return AO_test_and_set(addr);
+}
+
+#define AO_HAVE_test_and_set_release
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr) {
+  AO_TS_VAL_t result;
+  AO_lwsync();
+  result = AO_test_and_set(addr);
+  AO_lwsync();
+  return result;
+}
+
+#define AO_HAVE_test_and_set_full
+
+AO_INLINE AO_t
+AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {
+# error Implement me
+}
+
+#define AO_HAVE_compare_and_swap
+
+AO_INLINE AO_t
+AO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val) {
+  AO_t result = AO_compare_and_swap(addr, old, new_val);
+  AO_lwsync();
+  return result;
+}
+
+#define AO_HAVE_compare_and_swap_acquire
+
+AO_INLINE AO_t
+AO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val) {
+  AO_lwsync();
+  return AO_compare_and_swap(addr, old, new_val);
+}
+
+#define AO_HAVE_compare_and_swap_release
+
+AO_INLINE AO_t
+AO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {
+  AO_t result;
+  AO_lwsync();
+  result = AO_compare_and_swap(addr, old, new_val);
+  AO_lwsync();
+  return result;
+}
+
+#define AO_HAVE_compare_and_swap_full
+
+/* FIXME: We should also implement fetch_and_add and or primitives     */
+/* directly.                                                           */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/icc/ia64.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/icc/ia64.h
new file mode 100644 (file)
index 0000000..358ddda
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * This file specifies Itanimum primitives for use with the Intel (ecc)
+ * compiler.  We use intrinsics instead of the inline assembly code in the
+ * gcc file.
+ */
+
+#include "../all_atomic_load_store.h"
+
+#include "../test_and_set_t_is_char.h"
+
+#include <ia64intrin.h>
+
+/* The acquire release semantics of volatile can be turned off.  And volatile  */
+/* operations in icc9 don't imply ordering with respect to other nonvolatile   */
+/* operations.                                                                 */
+
+#define AO_INTEL_PTR_t void *
+
+AO_INLINE AO_t
+AO_load_acquire(volatile AO_t *p)
+{
+  return (AO_t)(__ld8_acq((AO_INTEL_PTR_t)p));
+}
+#define AO_HAVE_load_acquire
+
+AO_INLINE void
+AO_store_release(volatile AO_t *p, AO_t val)
+{
+  __st8_rel((AO_INTEL_PTR_t)p, (__int64)val);
+}
+#define AO_HAVE_store_release
+
+AO_INLINE unsigned char
+AO_char_load_acquire(volatile unsigned char *p)
+{
+  /* A normal volatile load generates an ld.acq                */
+  return (__ld1_acq((AO_INTEL_PTR_t)p));
+}
+#define AO_HAVE_char_load_acquire
+
+AO_INLINE void
+AO_char_store_release(volatile unsigned char *p, unsigned char val)
+{
+  __st1_rel((AO_INTEL_PTR_t)p, val);
+}
+#define AO_HAVE_char_store_release
+
+AO_INLINE unsigned short
+AO_short_load_acquire(volatile unsigned short *p)
+{
+  /* A normal volatile load generates an ld.acq                */
+  return (__ld2_acq((AO_INTEL_PTR_t)p));
+}
+#define AO_HAVE_short_load_acquire
+
+AO_INLINE void
+AO_short_store_release(volatile unsigned short *p, unsigned short val)
+{
+  __st2_rel((AO_INTEL_PTR_t)p, val);
+}
+#define AO_HAVE_short_store_release
+
+AO_INLINE unsigned int
+AO_int_load_acquire(volatile unsigned int *p)
+{
+  /* A normal volatile load generates an ld.acq                */
+  return (__ld4_acq((AO_INTEL_PTR_t)p));
+}
+#define AO_HAVE_int_load_acquire
+
+AO_INLINE void
+AO_int_store_release(volatile unsigned int *p, unsigned int val)
+{
+  __st4_rel((AO_INTEL_PTR_t)p, val);
+}
+#define AO_HAVE_int_store_release
+
+AO_INLINE void
+AO_nop_full()
+{
+  __mf();
+}
+#define AO_HAVE_nop_full
+
+AO_INLINE AO_t
+AO_fetch_and_add1_acquire (volatile AO_t *p)
+{
+  return __fetchadd8_acq((unsigned __int64 *)p, 1);
+}
+#define AO_HAVE_fetch_and_add1_acquire
+
+AO_INLINE AO_t
+AO_fetch_and_add1_release (volatile AO_t *p)
+{
+  return __fetchadd8_rel((unsigned __int64 *)p, 1);
+}
+
+#define AO_HAVE_fetch_and_add1_release
+
+AO_INLINE AO_t
+AO_fetch_and_sub1_acquire (volatile AO_t *p)
+{
+  return __fetchadd8_acq((unsigned __int64 *)p, -1);
+}
+
+#define AO_HAVE_fetch_and_sub1_acquire
+
+AO_INLINE AO_t
+AO_fetch_and_sub1_release (volatile AO_t *p)
+{
+  return __fetchadd8_rel((unsigned __int64 *)p, -1);
+}
+
+#define AO_HAVE_fetch_and_sub1_release
+
+AO_INLINE int
+AO_compare_and_swap_acquire(volatile AO_t *addr,
+                            AO_t old, AO_t new_val) 
+{
+  AO_t oldval;
+  oldval = _InterlockedCompareExchange64_acq(addr, new_val, old);
+  return (oldval == old);
+}
+
+#define AO_HAVE_compare_and_swap_acquire
+
+AO_INLINE int
+AO_compare_and_swap_release(volatile AO_t *addr,
+                            AO_t old, AO_t new_val) 
+{
+  AO_t oldval;
+  oldval = _InterlockedCompareExchange64_rel(addr, new_val, old);
+  return (oldval == old);
+}
+
+#define AO_HAVE_compare_and_swap_release
+
+AO_INLINE int
+AO_char_compare_and_swap_acquire(volatile unsigned char *addr,
+                                unsigned char old, unsigned char new_val) 
+{
+  unsigned char oldval;
+  oldval = _InterlockedCompareExchange8_acq(addr, new_val, old);
+  return (oldval == old);
+}
+
+#define AO_HAVE_char_compare_and_swap_acquire
+
+AO_INLINE int
+AO_char_compare_and_swap_release(volatile unsigned char *addr,
+                           unsigned char old, unsigned char new_val) 
+{
+  unsigned char oldval;
+  oldval = _InterlockedCompareExchange8_rel(addr, new_val, old);
+  return (oldval == old);
+}
+
+#define AO_HAVE_char_compare_and_swap_release
+
+AO_INLINE int
+AO_short_compare_and_swap_acquire(volatile unsigned short *addr,
+                                unsigned short old, unsigned short new_val) 
+{
+  unsigned short oldval;
+  oldval = _InterlockedCompareExchange16_acq(addr, new_val, old);
+  return (oldval == old);
+}
+
+#define AO_HAVE_short_compare_and_swap_acquire
+
+AO_INLINE int
+AO_short_compare_and_swap_release(volatile unsigned short *addr,
+                           unsigned short old, unsigned short new_val) 
+{
+  unsigned short oldval;
+  oldval = _InterlockedCompareExchange16_rel(addr, new_val, old);
+  return (oldval == old);
+}
+
+#define AO_HAVE_short_compare_and_swap_release
+
+AO_INLINE int
+AO_int_compare_and_swap_acquire(volatile unsigned int *addr,
+                                unsigned int old, unsigned int new_val) 
+{
+  unsigned int oldval;
+  oldval = _InterlockedCompareExchange_acq(addr, new_val, old);
+  return (oldval == old);
+}
+
+#define AO_HAVE_int_compare_and_swap_acquire
+
+AO_INLINE int
+AO_int_compare_and_swap_release(volatile unsigned int *addr,
+                           unsigned int old, unsigned int new_val) 
+{
+  unsigned int oldval;
+  oldval = _InterlockedCompareExchange_rel(addr, new_val, old);
+  return (oldval == old);
+}
+
+#define AO_HAVE_int_compare_and_swap_release
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/int_acquire_release_volatile.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/int_acquire_release_volatile.h
new file mode 100644 (file)
index 0000000..e0a6ed0
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * This file adds definitions appropriate for environments in which an unsigned
+ * int volatile load has acquire semantics, and an unsigned short volatile
+ * store has release semantics.  This is true with the standard Itanium ABI.
+ */
+#if !defined(AO_GCC_BARRIER)
+#  if defined(__GNUC__)
+#    define AO_GCC_BARRIER() AO_compiler_barrier()
+#  else
+#    define AO_GCC_BARRIER()
+#  endif
+#endif
+
+AO_INLINE unsigned int
+AO_int_load_acquire(volatile unsigned int *p)
+{
+  unsigned int result = *p;
+  /* A normal volatile load generates an ld.acq                */
+  AO_GCC_BARRIER();
+  return result;
+}
+#define AO_HAVE_int_load_acquire
+
+AO_INLINE void
+AO_int_store_release(volatile unsigned int *p, unsigned int val)
+{
+  AO_GCC_BARRIER();
+  /* A normal volatile store generates an st.rel       */
+  *p = val;
+}
+#define AO_HAVE_int_store_release
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/int_aligned_atomic_load_store.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/int_aligned_atomic_load_store.h
new file mode 100644 (file)
index 0000000..62927d2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * Definitions for architecturs on which loads and stores of unsigned int are
+ * atomic fo all legal alignments.
+ */
+
+AO_INLINE unsigned int
+AO_int_load(volatile unsigned int *addr)
+{
+  assert(((size_t)addr & (sizeof(unsigned int) - 1)) == 0);
+  /* Cast away the volatile for architectures like IA64 where  */
+  /* volatile adds barrier semantics.                          */
+  return (*(unsigned int *)addr);
+}
+
+#define AO_HAVE_int_load
+
+AO_INLINE void
+AO_int_store(volatile unsigned int *addr, unsigned int new_val)
+{
+  assert(((size_t)addr & (sizeof(unsigned int) - 1)) == 0);
+  (*(unsigned int *)addr) = new_val;
+}
+
+#define AO_HAVE_int_store
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/int_atomic_load_store.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/int_atomic_load_store.h
new file mode 100644 (file)
index 0000000..b2a4813
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * Definitions for architecturs on which loads and stores of unsigned int are
+ * atomic for all legal alignments.
+ */
+
+AO_INLINE unsigned int
+AO_int_load(volatile unsigned int *addr)
+{
+  /* Cast away the volatile for architectures like IA64 where  */
+  /* volatile adds barrier semantics.                          */
+  return (*(unsigned int *)addr);
+}
+
+#define AO_HAVE_int_load
+
+AO_INLINE void
+AO_int_store(volatile unsigned int *addr, unsigned int new_val)
+{
+  (*(unsigned int *)addr) = new_val;
+}
+
+#define AO_HAVE_int_store
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc/x86.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc/x86.h
new file mode 100644 (file)
index 0000000..ad44458
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/* The following really assume we have a 486 or better. */
+/* If ASSUME_WINDOWS98 is defined, we assume Windows 98 or newer.      */
+
+#include "../all_aligned_atomic_load_store.h"
+
+/* Real X86 implementations, except for some old WinChips, appear      */
+/* to enforce ordering between memory operations, EXCEPT that a later  */
+/* read can pass earlier writes, presumably due to the visible         */
+/* presence of store buffers.                                          */
+/* We ignore both the WinChips, and the fact that the official specs   */
+/* seem to be much weaker (and arguably too weak to be usable).                */
+
+#include "../ordered_except_wr.h"
+
+#include "../test_and_set_t_is_char.h"
+
+#include <windows.h>
+       /* Seems like over-kill, but that's what MSDN recommends.       */
+       /* And apparently winbase.h is not always self-contained.       */
+
+#if _MSC_VER < 1310
+
+#define _InterlockedIncrement       InterlockedIncrement
+#define _InterlockedDecrement       InterlockedDecrement
+#define _InterlockedExchange        InterlockedExchange 
+#define _InterlockedCompareExchange InterlockedCompareExchange
+
+#else
+
+#if _MSC_VER >= 1400
+#include <intrin.h>
+
+#pragma intrinsic (_ReadWriteBarrier)
+
+#else
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LONG __cdecl _InterlockedIncrement(LONG volatile *Addend);
+LONG __cdecl _InterlockedDecrement(LONG volatile *Addend);
+LONG __cdecl _InterlockedExchangeAdd(LONG volatile* Target, LONG Addend);
+LONG __cdecl _InterlockedExchange(LONG volatile* Target, LONG Value);
+LONG __cdecl _InterlockedCompareExchange(LONG volatile* Dest,
+                                         LONG Exchange, LONG Comp);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _MSC_VER >= 1400 */
+
+#pragma intrinsic (_InterlockedIncrement)
+#pragma intrinsic (_InterlockedDecrement)
+#pragma intrinsic (_InterlockedExchange)
+#pragma intrinsic (_InterlockedExchangeAdd)
+#pragma intrinsic (_InterlockedCompareExchange)
+
+#endif /* _MSC_VER < 1310 */
+
+/* As far as we can tell, the lfence and sfence instructions are not   */
+/* currently needed or useful for cached memory accesses.              */
+
+/* Unfortunately mfence doesn't exist everywhere.              */
+/* IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE128) is                */
+/* probably a conservative test for it?                                */
+
+#if defined(AO_USE_PENTIUM4_INSTRS)
+
+AO_INLINE void
+AO_nop_full()
+{
+  __asm { mfence }
+}
+
+#define AO_HAVE_nop_full
+
+#else
+
+/* We could use the cpuid instruction.  But that seems to be slower    */
+/* than the default implementation based on test_and_set_full.  Thus   */
+/* we omit that bit of misinformation here.                            */
+
+#endif
+
+AO_INLINE AO_t
+AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
+{
+  return _InterlockedExchangeAdd((LONG volatile*)p, (LONG)incr);
+}
+
+#define AO_HAVE_fetch_and_add_full
+
+AO_INLINE AO_t
+AO_fetch_and_add1_full (volatile AO_t *p)
+{
+  return _InterlockedIncrement((LONG volatile *)p) - 1;
+}
+
+#define AO_HAVE_fetch_and_add1_full
+
+AO_INLINE AO_t
+AO_fetch_and_sub1_full (volatile AO_t *p)
+{
+  return _InterlockedDecrement((LONG volatile *)p) + 1;
+}
+
+#define AO_HAVE_fetch_and_sub1_full
+
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr)
+{
+    __asm
+    {
+       mov     eax,AO_TS_SET           ;
+       mov     ebx,addr                ;
+       xchg    byte ptr [ebx],al       ;
+    }
+}
+
+#define AO_HAVE_test_and_set_full
+
+#ifdef AO_ASSUME_WINDOWS98
+/* Returns nonzero if the comparison succeeded. */
+AO_INLINE int
+AO_compare_and_swap_full(volatile AO_t *addr,
+                        AO_t old, AO_t new_val) 
+{
+    return _InterlockedCompareExchange((LONG volatile *)addr,
+                                       (LONG)new_val, (LONG)old)
+          == (LONG)old;
+}
+
+#define AO_HAVE_compare_and_swap_full
+#endif /* ASSUME_WINDOWS98 */
+
+#ifdef _WIN64
+#  error wrong architecture
+#endif
+
+#include "../ao_t_is_int.h"
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc/x86_64.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc/x86_64.h
new file mode 100644 (file)
index 0000000..7f0b647
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/* The following really assume we have a 486 or better. */
+/* If ASSUME_WINDOWS98 is defined, we assume Windows 98 or newer.      */
+
+#include "../all_aligned_atomic_load_store.h"
+
+/* Real X86 implementations, except for some old WinChips, appear      */
+/* to enforce ordering between memory operations, EXCEPT that a later  */
+/* read can pass earlier writes, presumably due to the visible         */
+/* presence of store buffers.                                          */
+/* We ignore both the WinChips, and the fact that the official specs   */
+/* seem to be much weaker (and arguably too weak to be usable).                */
+
+#include "../ordered_except_wr.h"
+
+#if 0
+FIXME: Need to reimplement testandset
+
+#include "../test_and_set_t_is_char.h"
+
+#else
+
+#include "../test_and_set_t_is_ao_t.h"
+
+#endif
+
+#include <windows.h>
+       /* Seems like over-kill, but that's what MSDN recommends.       */
+       /* And apparently winbase.h is not always self-contained.       */
+
+
+#include <intrin.h>
+
+#pragma intrinsic (_ReadWriteBarrier)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LONGLONG __cdecl _InterlockedIncrement64(LONGLONG volatile *Addend);
+LONGLONG __cdecl _InterlockedDecrement64(LONGLONG volatile *Addend);
+LONGLONG __cdecl _InterlockedExchangeAdd64(LONGLONG volatile* Target,
+                                          LONGLONG Addend);
+LONGLONG __cdecl _InterlockedExchange64(LONGLONG volatile* Target,
+                                       LONGLONG Value);
+LONGLONG __cdecl _InterlockedCompareExchange64(LONGLONG volatile* Dest,
+                                               LONGLONG Exchange,
+                                              LONGLONG Comp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma intrinsic (_InterlockedIncrement64)
+#pragma intrinsic (_InterlockedDecrement64)
+#pragma intrinsic (_InterlockedExchange64)
+#pragma intrinsic (_InterlockedExchangeAdd64)
+#pragma intrinsic (_InterlockedCompareExchange64)
+
+/* As far as we can tell, the lfence and sfence instructions are not   */
+/* currently needed or useful for cached memory accesses.              */
+
+/* Unfortunately mfence doesn't exist everywhere.              */
+/* IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE128) is                */
+/* probably a conservative test for it?                                */
+
+#if defined(AO_USE_PENTIUM4_INSTRS)
+
+AO_INLINE void
+AO_nop_full()
+{
+  __asm { mfence }
+}
+
+#define AO_HAVE_nop_full
+
+#else
+
+/* We could use the cpuid instruction.  But that seems to be slower    */
+/* than the default implementation based on test_and_set_full.  Thus   */
+/* we omit that bit of misinformation here.                            */
+
+#endif
+
+AO_INLINE AO_t
+AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
+{
+  return _InterlockedExchangeAdd64((LONGLONG volatile *)p, (LONGLONG)incr);
+}
+
+#define AO_HAVE_fetch_and_add_full
+
+AO_INLINE AO_t
+AO_fetch_and_add1_full (volatile AO_t *p)
+{
+  return _InterlockedIncrement64((LONGLONG volatile *)p) - 1;
+}
+
+#define AO_HAVE_fetch_and_add1_full
+
+AO_INLINE AO_t
+AO_fetch_and_sub1_full (volatile AO_t *p)
+{
+  return _InterlockedDecrement64((LONGLONG volatile *)p) + 1;
+}
+
+#define AO_HAVE_fetch_and_sub1_full
+
+AO_INLINE int
+AO_compare_and_swap_full(volatile AO_t *addr,
+                        AO_t old, AO_t new_val) 
+{
+    return _InterlockedCompareExchange64((LONGLONG volatile *)addr,
+                                         (LONGLONG)new_val, (LONGLONG)old)
+          == (LONGLONG)old;
+}
+
+#define AO_HAVE_compare_and_swap_full
+
+#if 0
+FIXME: (__asm not supported)
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr)
+{
+    __asm
+    {
+       mov     eax,AO_TS_SET           ;
+       mov     ebx,addr                ;
+       xchg    byte ptr [ebx],al       ;
+    }
+}
+
+#define AO_HAVE_test_and_set_full
+#endif
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ordered.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ordered.h
new file mode 100644 (file)
index 0000000..2bcd8d8
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * These are common definitions for architectures that provide processor
+ * ordered memory operations.
+ */
+
+#include "ordered_except_wr.h"
+
+AO_INLINE void
+AO_nop_full()
+{
+  AO_compiler_barrier();
+}
+
+#define AO_HAVE_nop_full
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ordered_except_wr.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ordered_except_wr.h
new file mode 100644 (file)
index 0000000..4f29303
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * These are common definitions for architectures that provide processor
+ * ordered memory operations except that a later read may pass an
+ * earlier write.  Real x86 implementations seem to be in this category,
+ * except apparently for some IDT WinChips, which we ignore.
+ */
+
+#include "read_ordered.h"
+
+AO_INLINE void
+AO_nop_write()
+{
+  AO_compiler_barrier();
+  /* sfence according to Intel docs.  Pentium 3 and up.        */
+  /* Unnecessary for cached accesses?                  */
+}
+
+#define AO_HAVE_NOP_WRITE
+
+#if defined(AO_HAVE_store)
+
+AO_INLINE void
+AO_store_write(volatile AO_t *addr, AO_t val)
+{
+  AO_compiler_barrier();
+  AO_store(addr, val);
+}
+# define AO_HAVE_store_write
+
+# define AO_store_release(addr, val) AO_store_write(addr, val)
+# define AO_HAVE_store_release
+
+#endif /* AO_HAVE_store */
+
+#if defined(AO_HAVE_char_store)
+
+AO_INLINE void
+AO_char_store_write(volatile unsigned char *addr, unsigned char val)
+{
+  AO_compiler_barrier();
+  AO_char_store(addr, val);
+}
+# define AO_HAVE_char_store_write
+
+# define AO_char_store_release(addr, val) AO_char_store_write(addr, val)
+# define AO_HAVE_char_store_release
+
+#endif /* AO_HAVE_char_store */
+
+#if defined(AO_HAVE_short_store)
+
+AO_INLINE void
+AO_short_store_write(volatile unsigned short *addr, unsigned short val)
+{
+  AO_compiler_barrier();
+  AO_short_store(addr, val);
+}
+# define AO_HAVE_short_store_write
+
+# define AO_short_store_release(addr, val) AO_short_store_write(addr, val)
+# define AO_HAVE_short_store_release
+
+#endif /* AO_HAVE_short_store */
+
+#if defined(AO_HAVE_int_store)
+
+AO_INLINE void
+AO_int_store_write(volatile unsigned int *addr, unsigned int val)
+{
+  AO_compiler_barrier();
+  AO_int_store(addr, val);
+}
+# define AO_HAVE_int_store_write
+
+# define AO_int_store_release(addr, val) AO_int_store_write(addr, val)
+# define AO_HAVE_int_store_release
+
+#endif /* AO_HAVE_int_store */
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/read_ordered.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/read_ordered.h
new file mode 100644 (file)
index 0000000..e928881
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * These are common definitions for architectures that provide processor
+ * ordered memory operations except that a later read may pass an
+ * earlier write.  Real x86 implementations seem to be in this category,
+ * except apparently for some IDT WinChips, which we ignore.
+ */
+
+AO_INLINE void
+AO_nop_read()
+{
+  AO_compiler_barrier();
+}
+
+#define AO_HAVE_NOP_READ
+
+#ifdef AO_HAVE_load
+
+AO_INLINE AO_t
+AO_load_read(volatile AO_t *addr)
+{
+  AO_t result = AO_load(addr);
+  AO_compiler_barrier();
+  return result;
+}
+#define AO_HAVE_load_read
+
+#define AO_load_acquire(addr) AO_load_read(addr)
+#define AO_HAVE_load_acquire
+
+#endif /* AO_HAVE_load */
+
+#ifdef AO_HAVE_char_load
+
+AO_INLINE AO_t
+AO_char_load_read(volatile unsigned char *addr)
+{
+  AO_t result = AO_char_load(addr);
+  AO_compiler_barrier();
+  return result;
+}
+#define AO_HAVE_char_load_read
+
+#define AO_char_load_acquire(addr) AO_char_load_read(addr)
+#define AO_HAVE_char_load_acquire
+
+#endif /* AO_HAVE_char_load */
+
+#ifdef AO_HAVE_short_load
+
+AO_INLINE AO_t
+AO_short_load_read(volatile unsigned short *addr)
+{
+  AO_t result = AO_short_load(addr);
+  AO_compiler_barrier();
+  return result;
+}
+#define AO_HAVE_short_load_read
+
+#define AO_short_load_acquire(addr) AO_short_load_read(addr)
+#define AO_HAVE_short_load_acquire
+
+#endif /* AO_HAVE_short_load */
+
+#ifdef AO_HAVE_int_load
+
+AO_INLINE AO_t
+AO_int_load_read(volatile unsigned int *addr)
+{
+  AO_t result = AO_int_load(addr);
+  AO_compiler_barrier();
+  return result;
+}
+#define AO_HAVE_int_load_read
+
+#define AO_int_load_acquire(addr) AO_int_load_read(addr)
+#define AO_HAVE_int_load_acquire
+
+#endif /* AO_HAVE_int_load */
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/short_acquire_release_volatile.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/short_acquire_release_volatile.h
new file mode 100644 (file)
index 0000000..035ada7
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003-2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/*
+ * This file adds definitions appropriate for environments in which an unsigned short
+ * volatile load has acquire semantics, and an unsigned short volatile store has release
+ * semantics.  This is true with the standard Itanium ABI.
+ */
+#if !defined(AO_GCC_BARRIER)
+#  if defined(__GNUC__)
+#    define AO_GCC_BARRIER() AO_compiler_barrier()
+#  else
+#    define AO_GCC_BARRIER()
+#  endif
+#endif
+
+AO_INLINE unsigned short
+AO_short_load_acquire(volatile unsigned short *p)
+{
+  unsigned short result = *p;
+  /* A normal volatile load generates an ld.acq                */
+  AO_GCC_BARRIER();
+  return result;
+}
+#define AO_HAVE_short_load_acquire
+
+AO_INLINE void
+AO_short_store_release(volatile unsigned short *p, unsigned short val)
+{
+  AO_GCC_BARRIER();
+  /* A normal volatile store generates an st.rel       */
+  *p = val;
+}
+#define AO_HAVE_short_store_release
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/short_aligned_atomic_load_store.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/short_aligned_atomic_load_store.h
new file mode 100644 (file)
index 0000000..3b285b8
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * Definitions for architecturs on which loads and stores of unsigned short are
+ * atomic fo all legal alignments.
+ */
+
+AO_INLINE unsigned short
+AO_short_load(volatile unsigned short *addr)
+{
+  assert(((size_t)addr & (sizeof(unsigned short) - 1)) == 0);
+  /* Cast away the volatile for architectures like IA64 where  */
+  /* volatile adds barrier semantics.                          */
+  return (*(unsigned short *)addr);
+}
+
+#define AO_HAVE_short_load
+
+AO_INLINE void
+AO_short_store(volatile unsigned short *addr, unsigned short new_val)
+{
+  assert(((size_t)addr & (sizeof(unsigned short) - 1)) == 0);
+  (*(unsigned short *)addr) = new_val;
+}
+
+#define AO_HAVE_short_store
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/short_atomic_load_store.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/short_atomic_load_store.h
new file mode 100644 (file)
index 0000000..f1b5281
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * Definitions for architecturs on which loads and stores of unsigned short are
+ * atomic for all legal alignments.
+ */
+
+AO_INLINE unsigned short
+AO_short_load(volatile unsigned short *addr)
+{
+  /* Cast away the volatile for architectures like IA64 where  */
+  /* volatile adds barrier semantics.                          */
+  return (*(unsigned short *)addr);
+}
+
+#define AO_HAVE_short_load
+
+AO_INLINE void
+AO_short_store(volatile unsigned short *addr, unsigned short new_val)
+{
+  (*(unsigned short *)addr) = new_val;
+}
+
+#define AO_HAVE_short_store
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/standard_ao_double_t.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/standard_ao_double_t.h
new file mode 100644 (file)
index 0000000..1d08fc7
--- /dev/null
@@ -0,0 +1,8 @@
+typedef union {
+    unsigned long long AO_whole;
+    struct {AO_t AO_v1; AO_t AO_v2;} AO_parts;
+} AO_double_t;
+#define AO_HAVE_double_t
+#define AO_val1 AO_parts.AO_v1
+#define AO_val2 AO_parts.AO_v2
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc/sparc.S b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc/sparc.S
new file mode 100644 (file)
index 0000000..81f0ef0
--- /dev/null
@@ -0,0 +1,5 @@
+       .seg    "text"
+       .globl  AO_test_and_set_full
+AO_test_and_set_full:
+       retl
+         ldstub        [%o0],%o0
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc/sparc.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc/sparc.h
new file mode 100644 (file)
index 0000000..3578722
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+#include "../all_atomic_load_store.h"
+
+/* Real SPARC code uses TSO:                            */
+#include "../ordered_except_wr.h"
+
+/* Test_and_set location is just a byte.               */
+#include "../test_and_set_t_is_char.h"
+
+extern AO_TS_VAL_t
+AO_test_and_set_full(volatile AO_TS_t *addr);
+/* Implemented in separate .S file, for now.   */
+
+#define AO_HAVE_test_and_set_full
+
+/* FIXME: Like the gcc version, this needs to be extended for V8       */
+/* and V9.                                                             */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/test_and_set_t_is_ao_t.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/test_and_set_t_is_ao_t.h
new file mode 100644 (file)
index 0000000..663bccf
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * These are common definitions for architectures on which test_and_set
+ * operates on pointer-sized quantities, the "clear" value contains
+ * all zeroes, and the "set" value contains all ones.
+ * This can be used if test_and_set is synthesized from compare_and_swap.
+ */
+typedef enum {AO_TS_clear = 0, AO_TS_set = 1} AO_TS_val; 
+#define AO_TS_VAL_t AO_TS_val
+#define AO_TS_CLEAR AO_TS_clear
+#define AO_TS_SET AO_TS_set
+
+#define AO_TS_t AO_t
+
+#define AO_AO_TS_T 1
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/test_and_set_t_is_char.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/test_and_set_t_is_char.h
new file mode 100644 (file)
index 0000000..bde0f21
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2004 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */ 
+
+/*
+ * These are common definitions for architectures on which test_and_set
+ * operates on byte sized quantities, the "clear" value contains
+ * all zeroes, and the "set" value contains all ones.
+ */
+
+#define AO_TS_t unsigned char
+typedef enum {AO_BYTE_TS_clear = 0, AO_BYTE_TS_set = 0xff} AO_BYTE_TS_val;
+#define AO_TS_VAL_t AO_BYTE_TS_val
+#define AO_TS_CLEAR AO_BYTE_TS_clear
+#define AO_TS_SET AO_BYTE_TS_set
+
+#define AO_CHAR_TS_T 1
+
+
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_malloc.c b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_malloc.c
new file mode 100644 (file)
index 0000000..dff4908
--- /dev/null
@@ -0,0 +1,288 @@
+/*  
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ * Original Author: Hans Boehm
+ *
+ * This file may be redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ * 
+ * It is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License in the
+ * file doc/COPYING for more details.
+ */
+
+#if defined(HAVE_CONFIG_H)
+# include "config.h"
+#endif
+
+#define AO_REQUIRE_CAS
+#include "atomic_ops_stack.h"
+#include <string.h>    /* for ffs, which is assumed reentrant. */
+#include <stdlib.h>
+#ifdef AO_TRACE_MALLOC
+# include <stdio.h>
+# include <pthread.h>
+#endif
+
+/*
+ * We round up each allocation request to the next power of two
+ * minus one word.
+ * We keep one stack of free objects for each size.  Each object
+ * has an initial word (offset -sizeof(AO_t) from the visible pointer)
+ * which contains either
+ *     The binary log of the object size in bytes (small objects)
+ *     The object size (a multiple of CHUNK_SIZE) for large objects.
+ * The second case only arises if mmap-based allocation is supported.
+ * We align the user-visible part of each object on a GRANULARITY
+ * byte boundary.  That means that the actual (hidden) start of
+ * the object starts a word before this boundary.
+ */
+
+#ifndef LOG_MAX_SIZE
+# define LOG_MAX_SIZE 16
+       /* We assume that 2**LOG_MAX_SIZE is a multiple of page size. */
+#endif
+
+#ifndef ALIGNMENT
+# define ALIGNMENT 16
+       /* Assumed to be at least sizeof(AO_t).         */
+#endif
+
+#define CHUNK_SIZE (1 << LOG_MAX_SIZE)
+
+#ifndef AO_INITIAL_HEAP_SIZE
+#  define AO_INITIAL_HEAP_SIZE (2*(LOG_MAX_SIZE+1)*CHUNK_SIZE)
+#endif
+
+char AO_initial_heap[AO_INITIAL_HEAP_SIZE];
+
+static volatile AO_t initial_heap_ptr = (AO_t)AO_initial_heap;
+static volatile char *initial_heap_lim = AO_initial_heap + AO_INITIAL_HEAP_SIZE;
+
+#if defined(HAVE_MMAP)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+static volatile AO_t mmap_enabled = 0;
+
+void
+AO_malloc_enable_mmap(void)
+{
+  AO_store(&mmap_enabled, 1);
+}
+
+static char *get_mmaped(size_t sz)
+{
+  char * result;
+
+  assert(!(sz & (CHUNK_SIZE - 1)));
+  if (!mmap_enabled) return 0;
+# if defined(MAP_ANONYMOUS)
+    result = mmap(0, sz, PROT_READ | PROT_WRITE,
+                 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+# elif defined(MAP_ANON)
+    result = mmap(0, sz, PROT_READ | PROT_WRITE,
+                 MAP_PRIVATE | MAP_ANON, -1, 0);
+# else
+    {
+      int zero_fd = open("/dev/zero", O_RDONLY);
+      result = mmap(0, sz, PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE, zero_fd, 0);
+      close(zero_fd);
+    }
+# endif
+  if (result == MAP_FAILED) result = 0;
+  return result;
+}
+
+/* Allocate an object of size (incl. header) of size > CHUNK_SIZE.     */
+/* sz includes space for an AO_t-sized header.                         */
+static char *
+AO_malloc_large(size_t sz)
+{
+ char * result;
+ /* The header will force us to waste ALIGNMENT bytes, incl. header.   */
+   sz += ALIGNMENT;
+ /* Round to multiple of CHUNK_SIZE.   */
+   sz = (sz + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
+ result = get_mmaped(sz);
+ if (result == 0) return 0;
+ result += ALIGNMENT;
+ ((AO_t *)result)[-1] = (AO_t)sz;
+ return result;
+}
+
+static void
+AO_free_large(char * p)
+{
+  AO_t sz = ((AO_t *)p)[-1];
+  if (munmap(p - ALIGNMENT, (size_t)sz) != 0)
+    abort();  /* Programmer error.  Not really async-signal-safe, but ... */
+}
+  
+
+#else /*  No MMAP */
+
+void
+AO_malloc_enable_mmap(void)
+{
+}
+
+static char *get_mmaped(size_t sz)
+{
+  return 0;
+}
+
+static char *
+AO_malloc_large(size_t sz)
+{
+  return 0;
+}
+
+static void
+AO_free_large(char * p)
+{
+  abort();  /* Programmer error.  Not really async-signal-safe, but ... */
+}
+
+#endif /* No MMAP */
+
+static char *
+get_chunk(void)
+{
+  char *initial_ptr;
+  char *my_chunk_ptr;
+  char * my_lim;
+
+retry:
+  initial_ptr = (char *)AO_load(&initial_heap_ptr);
+  my_chunk_ptr = (char *)(((AO_t)initial_ptr + (ALIGNMENT - 1))
+                         & ~(ALIGNMENT - 1));
+  if (initial_ptr != my_chunk_ptr)
+    {
+      /* Align correctly.  If this fails, someone else did it for us.  */
+      AO_compare_and_swap_acquire(&initial_heap_ptr, (AO_t)initial_ptr,
+                                 (AO_t)my_chunk_ptr);
+    }
+  my_lim = my_chunk_ptr + CHUNK_SIZE;
+  if (my_lim <= initial_heap_lim)
+    {
+      if (!AO_compare_and_swap(&initial_heap_ptr, (AO_t)my_chunk_ptr,
+                                                 (AO_t)my_lim))
+        goto retry;
+      return my_chunk_ptr;
+    }
+  /* We failed.  The initial heap is used up.  */
+  my_chunk_ptr = get_mmaped(CHUNK_SIZE);
+  assert (!((AO_t)my_chunk_ptr & (ALIGNMENT-1)));
+  return my_chunk_ptr;
+}
+
+/* Object free lists.  Ith entry corresponds to objects        */
+/* of total size 2**i bytes.                                   */
+AO_stack_t AO_free_list[LOG_MAX_SIZE+1];
+
+/* Chunk free list, linked through first word in chunks.       */
+/* All entries of size CHUNK_SIZE.                             */
+AO_stack_t AO_chunk_free_list;
+
+/* Break up the chunk, and add it to the object free list for  */
+/* the given size.  Sz must be a power of two.                 */
+/* We have exclusive access to chunk.                          */
+static void
+add_chunk_as(void * chunk, size_t sz, unsigned log_sz)
+{
+  char *first = (char *)chunk + ALIGNMENT - sizeof(AO_t);
+  char *limit = (char *)chunk + CHUNK_SIZE - sz;
+  char *next, *p;
+
+  for (p = first; p <= limit; p = next) {
+    next = p + sz;
+    AO_stack_push(AO_free_list+log_sz, (AO_t *)p);
+  }
+}
+
+static int msbs[16] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4};
+
+/* Return the position of the most significant set bit in the  */
+/* argument.                                                   */
+/* We follow the conventions of ffs(), i.e. the least          */
+/* significant bit is number one.                              */
+int msb(size_t s)
+{
+  int result = 0;
+  if ((s & 0xff) != s) {
+    /* The following shift often generates warnings on 32-bit arch's   */
+    /* That's OK, because it will never be executed there.             */
+    if (sizeof(size_t) > 4 && (s >> 32) != 0)
+      {
+       s >>= 32;
+       result += 32;
+      }
+    if ((s >> 16) != 0)
+      {
+       s >>= 16;
+       result += 16;
+      }
+    if ((s >> 8) != 0)
+      {
+       s >>= 8;
+       result += 8;
+      }
+  }
+  if (s > 15)
+    {
+      s >>= 4;
+      result += 4;
+    }
+  result += msbs[s];
+  return result;
+}
+
+void *
+AO_malloc(size_t sz)
+{
+  AO_t *result;
+  size_t adj_sz = sz + sizeof(AO_t);
+  int log_sz;
+  if (sz > CHUNK_SIZE)
+    return AO_malloc_large(sz);
+  log_sz = msb(adj_sz-1);
+  result = AO_stack_pop(AO_free_list+log_sz);
+  while (0 == result) {
+    void * chunk = get_chunk();
+    if (0 == chunk) return 0;
+    adj_sz = 1 << log_sz;
+    add_chunk_as(chunk, adj_sz, log_sz);
+    result = AO_stack_pop(AO_free_list+log_sz);
+  }
+  *result = log_sz;
+# ifdef AO_TRACE_MALLOC
+    fprintf(stderr, "%x: AO_malloc(%lu) = %p\n",
+                   (int)pthread_self(), (unsigned long)sz, result+1);
+# endif
+  return result + 1;
+}
+
+void
+AO_free(void *p)
+{
+  char *base = (char *)p - sizeof(AO_t);
+  int log_sz;
+
+  if (0 == p) return;
+  log_sz = *(AO_t *)base;
+# ifdef AO_TRACE_MALLOC
+    fprintf(stderr, "%x: AO_free(%p sz:%lu)\n", (int)pthread_self(), p,
+                   (unsigned long)
+                     (log_sz > LOG_MAX_SIZE? log_sz : (1 << log_sz)));
+# endif
+  if (log_sz > LOG_MAX_SIZE)
+    AO_free_large(p);
+  else
+    AO_stack_push(AO_free_list+log_sz, (AO_t *)base);
+}
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_malloc.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_malloc.h
new file mode 100644 (file)
index 0000000..c55d27c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/* Almost lock-free malloc implementation based on stack implementation. */
+/* See README.malloc file for detailed usage rules.                     */
+
+#ifndef AO_ATOMIC_H
+#define AO_ATOMIC_H
+
+#include <stdlib.h>    /* For size_t */
+
+#include "atomic_ops_stack.h"
+
+#ifdef AO_STACK_IS_LOCK_FREE
+# define AO_MALLOC_IS_LOCK_FREE
+#endif
+
+void AO_free(void *);
+
+void * AO_malloc(size_t);
+
+/* Allow use of mmpa to grow the heap.  No-op on some platforms.       */
+void AO_malloc_enable_mmap(void);
+
+#endif /* !AO_ATOMIC_H */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_stack.c b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_stack.c
new file mode 100644 (file)
index 0000000..c3df101
--- /dev/null
@@ -0,0 +1,302 @@
+/*  
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ * Original Author: Hans Boehm
+ *
+ * This file may be redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ * 
+ * It is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License in the
+ * file doc/COPYING for more details.
+ */
+
+#if defined(HAVE_CONFIG_H)
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#define AO_REQUIRE_CAS
+#include "atomic_ops_stack.h"
+
+#if defined(_MSC_VER) \
+    || defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
+  /* AO_pause not defined elsewhere */
+  /* FIXME: At least AO_spin should be factored out.   */
+#include <windows.h>
+
+AO_t dummy;
+
+/* Spin for 2**n units. */
+static void AO_spin(int n)
+{
+  int i;
+  AO_T j = AO_load(&dummy);
+
+  for (i = 0; i < (2 << n); ++i)
+    {
+       j *= 5;
+       j -= 4;
+    }
+  AO_store(&dummy, j);
+}
+
+void AO_pause(int n)
+{
+    if (n < 12)
+      AO_spin(n);
+    else
+      {
+        DWORD msecs;
+
+       /* Short async-signal-safe sleep. */
+       msecs = (n > 18? 100 : (1 << (n - 12)));
+       Sleep(msecs);
+      }
+}
+
+#else 
+
+/* AO_pause is available elsewhere */
+
+extern void AO_pause(int);
+
+#endif
+
+#ifdef AO_USE_ALMOST_LOCK_FREE
+
+/* LIFO linked lists based on compare-and-swap.  We need to avoid      */
+/* the case of a node deleton and reinsertion while I'm deleting       */
+/* it, since that may cause my CAS to succeed eventhough the next      */
+/* pointer is now wrong.  Our solution is not fully lock-free, but it  */
+/* is good enough for signal handlers, provided we have a suitably low */
+/* bound on the number of recursive signal handler reentries.                  */
+/* A list consists of a first pointer and a blacklist                  */
+/* of pointer values that are currently being removed.  No list element        */
+/* on the blacklist may be inserted.  If we would otherwise do so, we  */
+/* are allowed to insert a variant that differs only in the least      */
+/* significant, ignored, bits.  If the list is full, we wait.          */
+
+/* Crucial observation: A particular padded pointer x (i.e. pointer    */
+/* plus arbitrary low order bits) can never be newly inserted into     */
+/* a list while it's in the corresponding auxiliary data structure.    */
+
+/* The second argument is a pointer to the link field of the element   */
+/* to be inserted.                                                     */
+/* Both list headers and link fields contain "perturbed" pointers, i.e.        */
+/* pointers with extra bits "or"ed into the low order bits.            */
+void
+AO_stack_push_explicit_aux_release(volatile AO_t *list, AO_t *x,
+                                  AO_stack_aux *a)
+{
+  int i;
+  AO_t x_bits = (AO_t)x;
+  AO_t next;
+  
+  /* No deletions of x can start here, since x is not currently in the */
+  /* list.                                                             */
+ retry:
+# if AO_BL_SIZE == 2
+  {
+    /* Start all loads as close to concurrently as possible. */
+    AO_t entry1 = AO_load(a -> AO_stack_bl);
+    AO_t entry2 = AO_load(a -> AO_stack_bl + 1);
+    if (entry1 == x_bits || entry2 == x_bits)
+      {
+       /* Entry is currently being removed.  Change it a little.     */
+         ++x_bits;
+         if ((x_bits & AO_BIT_MASK) == 0)
+           /* Version count overflowed;         */
+           /* EXTREMELY unlikely, but possible. */
+           x_bits = (AO_t)x;
+       goto retry;
+      }
+  }
+# else
+    for (i = 0; i < AO_BL_SIZE; ++i)
+      {
+        if (AO_load(a -> AO_stack_bl + i) == x_bits)
+          {
+           /* Entry is currently being removed.  Change it a little.     */
+             ++x_bits;
+             if ((x_bits & AO_BIT_MASK) == 0)
+               /* Version count overflowed;         */
+               /* EXTREMELY unlikely, but possible. */
+               x_bits = (AO_t)x;
+           goto retry;
+          }
+      }
+# endif
+  /* x_bits is not currently being deleted */
+  do
+    {
+      next = AO_load(list);
+      *x = next;
+    }
+  while(!AO_compare_and_swap_release(list, next, x_bits));
+}
+
+/*
+ * I concluded experimentally that checking a value first before
+ * performing a compare-and-swap is usually beneficial on X86, but
+ * slows things down appreciably with contention on Itanium.
+ * ince the Itanium behavior makes more sense to me (more cache line
+ * movement unless we're mostly reading, but back-off should guard
+ * against that), we take Itanium as the default.  Measurements on
+ * other multiprocessor architectures would be useful.  (On a uniprocessor,
+ * the initial check is almost certainly a very small loss.) - HB
+ */
+#ifdef __i386__
+# define PRECHECK(a) (a) == 0 &&
+#else
+# define PRECHECK(a)
+#endif
+
+AO_t *
+AO_stack_pop_explicit_aux_acquire(volatile AO_t *list, AO_stack_aux * a)
+{
+  unsigned i;
+  int j = 0;
+  AO_t first;
+  AO_t * first_ptr;
+  AO_t next;
+
+ retry:
+  first = AO_load(list);
+  if (0 == first) return 0;
+  /* Insert first into aux black list.                                 */
+  /* This may spin if more than AO_BL_SIZE removals using auxiliary    */
+  /* structure a are currently in progress.                            */
+  for (i = 0; ; )
+    {
+      if (PRECHECK(a -> AO_stack_bl[i])
+         AO_compare_and_swap_acquire(a->AO_stack_bl+i, 0, first))
+        break;
+      ++i;
+      if ( i >= AO_BL_SIZE )
+       {
+         i = 0;
+         AO_pause(++j);
+       }
+    }
+  assert(i >= 0 && i < AO_BL_SIZE);
+  assert(a -> AO_stack_bl[i] == first);
+  /* First is on the auxiliary black list.  It may be removed by       */
+  /* another thread before we get to it, but a new insertion of x      */
+  /* cannot be started here.                                           */
+  /* Only we can remove it from the black list.                                */
+  /* We need to make sure that first is still the first entry on the   */
+  /* list.  Otherwise it's possible that a reinsertion of it was       */
+  /* already started before we added the black list entry.             */
+  if (first != AO_load(list)) {
+    AO_store_release(a->AO_stack_bl+i, 0);
+    goto retry;
+  }
+  first_ptr = AO_REAL_NEXT_PTR(first);
+  next = AO_load(first_ptr);
+  if (!AO_compare_and_swap_release(list, first, next)) {
+    AO_store_release(a->AO_stack_bl+i, 0);
+    goto retry;
+  }
+  assert(*list != first);
+  /* Since we never insert an entry on the black list, this cannot have        */
+  /* succeeded unless first remained on the list while we were running.        */
+  /* Thus its next link cannot have changed out from under us, and we  */
+  /* removed exactly one entry and preserved the rest of the list.     */
+  /* Note that it is quite possible that an additional entry was       */
+  /* inserted and removed while we were running; this is OK since the  */
+  /* part of the list following first must have remained unchanged, and        */
+  /* first must again have been at the head of the list when the       */
+  /* compare_and_swap succeeded.                                       */
+  AO_store_release(a->AO_stack_bl+i, 0);
+  return first_ptr;
+}
+
+#else /* ! USE_ALMOST_LOCK_FREE */
+
+/* Better names for fields in AO_stack_t */
+#define ptr AO_val2
+#define version AO_val1
+
+#if defined(AO_HAVE_compare_double_and_swap_double)
+
+void AO_stack_push_release(AO_stack_t *list, AO_t *element)
+{
+    AO_t next;
+
+    do {
+      next = AO_load(&(list -> ptr));
+      *element = next;
+    } while (!AO_compare_and_swap_release
+                   ( &(list -> ptr), next, (AO_t) element));
+    /* This uses a narrow CAS here, an old optimization suggested      */
+    /* by Treiber.  Pop is still safe, since we run into the ABA       */
+    /* problem only if there were both interveining "pop"s and "push"es.*/
+    /* Inthat case we still see a change inthe version number.         */
+}
+
+AO_t *AO_stack_pop_acquire(AO_stack_t *list)
+{
+    AO_t *cptr;
+    AO_t next;
+    AO_t cversion;
+
+    do {
+      /* Version must be loaded first. */
+      cversion = AO_load_acquire(&(list -> version));
+      cptr = (AO_t *)AO_load(&(list -> ptr));
+      if (cptr == 0) return 0;
+      next = *cptr;
+    } while (!AO_compare_double_and_swap_double_release
+                   (list, cversion, (AO_t) cptr, cversion+1, (AO_t) next));
+    return cptr;
+}
+
+
+#elif defined(AO_HAVE_compare_and_swap_double)
+
+/* Needed for future IA64 processors.  No current clients? */
+
+#error Untested!  Probably doesnt work.
+
+/* We have a wide CAS, but only does an AO_t-wide comparison.  */
+/* We can't use the Treiber optimization, since we only check  */
+/* for an unchanged version number, not an unchanged pointer.  */
+void AO_stack_push_release(AO_stack_t *list, AO_t *element)
+{
+    AO_t version;
+    AO_t next_ptr;
+
+    do {
+      /* Again version must be loaded first, for different reason.     */
+      version = AO_load_acquire(&(list -> version));
+      next_ptr = AO_load(&(list -> ptr));
+      *element = next_ptr;
+    } while (!AO_compare_and_swap_double_release(
+                          list, version,
+                          version+1, (AO_t) element));
+}
+
+AO_t *AO_stack_pop_acquire(AO_stack_t *list)
+{
+    AO_t *cptr;
+    AO_t next;
+    AO_t cversion;
+
+    do {
+      cversion = AO_load_acquire(&(list -> version));
+      cptr = (AO_t *)AO_load(&(list -> ptr));
+      if (cptr == 0) return 0;
+      next = *cptr;
+    } while (!AO_compare_double_and_swap_double_release
+                   (list, cversion, (AO_t) cptr, cversion+1, next));
+    return cptr;
+}
+
+
+#endif /* AO_HAVE_compare_and_swap_double */
+
+#endif /* ! USE_ALMOST_LOCK_FREE */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_stack.h b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_stack.h
new file mode 100644 (file)
index 0000000..f0c789b
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * The implementation of the routines described here is covered by the GPL.
+ * This header file is covered by the following license:
+ */
+
+/*
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. 
+ */
+
+/* Almost lock-free LIFO linked lists (linked stacks). */
+#ifndef AO_STACK_H
+#define AO_STACK_H
+
+#include "atomic_ops.h"
+
+#if !defined(AO_HAVE_compare_double_and_swap_double) \
+    && !defined(AO_HAVE_compare_double_and_swap) \
+    && defined(AO_HAVE_compare_and_swap)
+# define AO_USE_ALMOST_LOCK_FREE
+#else
+  /* If we have no compare-and-swap operation defined, we assume       */
+  /* that we will actually be using CAS emulation.  If we do that,     */
+  /* it's cheaper to use the version-based implementation.             */
+# define AO_STACK_IS_LOCK_FREE
+#endif
+
+/*
+ * These are not guaranteed to be completely lock-free.
+ * List insertion may spin under extremely unlikely conditions.
+ * It cannot deadlock due to recursive reentry unless AO_list_remove
+ * is called while at least AO_BL_SIZE activations of 
+ * AO_list_remove are currently active in the same thread, i.e.
+ * we must have at least AO_BL_SIZE recursive signal handler
+ * invocations.
+ *
+ * All operations take an AO_list_aux argument.  It is safe to
+ * share a single AO_list_aux structure among all lists, but that
+ * may increase contention.  Any given list must always be accessed
+ * with the same AO_list_aux structure.
+ *
+ * We make some machine-dependent assumptions:
+ *   - We have a compare-and-swap operation.
+ *   - At least _AO_N_BITS low order bits in pointers are
+ *     zero and normally unused.
+ *   - size_t and pointers have the same size.
+ *
+ * We do use a fully lock-free implementation if double-width
+ * compare-and-swap operations are available.
+ */
+
+#ifdef AO_USE_ALMOST_LOCK_FREE
+/* The number of low order pointer bits we can use for a small */
+/* version number.                                             */
+# if defined(__LP64__) || defined(_LP64) || defined(_WIN64)
+   /* WIN64 isn't really supported yet.        */
+#  define AO_N_BITS 3
+# else
+#  define AO_N_BITS 2
+# endif
+
+# define AO_BIT_MASK ((1 << AO_N_BITS) - 1)
+/*
+ * AO_stack_aux should be treated as opaque.
+ * It is fully defined here, so it can be allocated, and to facilitate
+ * debugging.
+ */
+#ifndef AO_BL_SIZE
+#  define AO_BL_SIZE 2
+#endif
+
+#if AO_BL_SIZE > (1 << AO_N_BITS)
+#  error AO_BL_SIZE too big
+#endif
+
+typedef struct AO__stack_aux {
+  volatile AO_t AO_stack_bl[AO_BL_SIZE];
+} AO_stack_aux;
+
+/* The stack implementation knows only about the lecation of   */
+/* link fields in nodes, and nothing about the rest of the     */
+/* stack elements.  Link fields hold an AO_t, which is not     */
+/* necessarily a real pointer.  This converts the AO_t to a    */
+/* real (AO_t *) which is either o, or points at the link      */
+/* field in the next node.                                     */
+#define AO_REAL_NEXT_PTR(x) (AO_t *)((x) & ~AO_BIT_MASK)
+
+/* The following two routines should not normally be used directly.    */
+/* We make them visible here for the rare cases in which it makes sense        */
+/* to share the an AO_stack_aux between stacks.                                */
+void
+AO_stack_push_explicit_aux_release(volatile AO_t *list, AO_t *x,
+                                 AO_stack_aux *);
+
+AO_t *
+AO_stack_pop_explicit_aux_acquire(volatile AO_t *list, AO_stack_aux *);
+
+/* And now AO_stack_t for the real interface:                          */
+
+typedef struct AO__stack {
+  volatile AO_t AO_ptr;
+  AO_stack_aux AO_aux;
+} AO_stack_t;
+
+#define AO_STACK_INITIALIZER {0}
+
+AO_INLINE void AO_stack_init(AO_stack_t *list)
+{
+# if AO_BL_SIZE == 2
+    list -> AO_aux.AO_stack_bl[0] = 0;
+    list -> AO_aux.AO_stack_bl[1] = 0;
+# else
+    int i;
+    for (i = 0; i < AO_BL_SIZE; ++i)
+      list -> AO_aux.AO_stack_bl[i] = 0;
+# endif
+  list -> AO_ptr = 0;
+}
+
+/* Convert an AO_stack_t to a pointer to the link field in     */
+/* the first element.                                          */
+#define AO_REAL_HEAD_PTR(x) AO_REAL_NEXT_PTR((x).AO_ptr)
+
+#define AO_stack_push_release(l, e) \
+       AO_stack_push_explicit_aux_release(&((l)->AO_ptr), e, &((l)->AO_aux))
+#define AO_HAVE_stack_push_release
+
+#define AO_stack_pop_acquire(l) \
+       AO_stack_pop_explicit_aux_acquire(&((l)->AO_ptr), &((l)->AO_aux))
+#define AO_HAVE_stack_pop_acquire
+
+# else /* Use fully non-blocking data structure, wide CAS      */
+
+#ifndef AO_HAVE_double_t
+  /* Can happen if we're using CAS emulation, since we don't want to   */
+  /* force that here, in case other atomic_ops clients don't want it.  */
+# include "atomic_ops/sysdeps/standard_ao_double_t.h"
+#endif
+
+typedef volatile AO_double_t AO_stack_t;
+/* AO_val1 is version, AO_val2 is pointer.     */
+
+#define AO_STACK_INITIALIZER {0}
+
+AO_INLINE void AO_stack_init(AO_stack_t *list)
+{
+  list -> AO_val1 = 0;
+  list -> AO_val2 = 0;
+}
+
+#define AO_REAL_HEAD_PTR(x) (AO_t *)((x).AO_val2)
+#define AO_REAL_NEXT_PTR(x) (AO_t *)(x)
+
+void AO_stack_push_release(AO_stack_t *list, AO_t *new_element);
+#define AO_HAVE_stack_push_release
+AO_t * AO_stack_pop_acquire(AO_stack_t *list);
+#define AO_HAVE_stack_pop_acquire
+
+#endif /* Wide CAS case */
+
+#if defined(AO_HAVE_stack_push_release) && !defined(AO_HAVE_stack_push)
+# define AO_stack_push(l, e) AO_stack_push_release(l, e)
+# define AO_HAVE_stack_push
+#endif
+
+#if defined(AO_HAVE_stack_pop_acquire) && !defined(AO_HAVE_stack_pop)
+# define AO_stack_pop(l) AO_stack_pop_acquire(l)
+# define AO_HAVE_stack_pop
+#endif
+
+#endif /* !AO_STACK_H */
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_sysdeps.S b/src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops_sysdeps.S
new file mode 100644 (file)
index 0000000..f586f23
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Include the appropriate system-dependent assembly file, if any.
+ * This is used only if the platform supports neither inline assembly
+ * code, nor appropriate compiler intrinsics.
+ */
+
+#if !defined(__GNUC__) && (defined(sparc) || defined(__sparc))
+#  include "atomic_ops/sysdeps/sunc/sparc.S"
+#endif
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/tests/Makefile.am b/src/mm/boehm-gc/libatomic_ops-1.2/tests/Makefile.am
new file mode 100644 (file)
index 0000000..0f186cc
--- /dev/null
@@ -0,0 +1,51 @@
+EXTRA_DIST=test_atomic.template list_atomic.template run_parallel.inc \
+          test_atomic_include.h
+# We distribute test_atomic_include.h, since it's hard to regenerate
+# on Windows without sed.
+
+BUILT_SOURCES = test_atomic_include.h list_atomic.i
+CLEANFILES = test_atomic_include.h list_atomic.c list_atomic.i
+
+AM_CPPFLAGS=-I$(srcdir)/../src
+
+TESTS=test_atomic test_atomic_pthreads test_stack test_malloc
+
+#create the test_atomic test program
+check_PROGRAMS=test_atomic test_atomic_pthreads test_stack test_malloc
+
+test_atomic_SOURCES=test_atomic.c
+test_atomic_LDADD=-lpthread ../src/libatomic_ops.a
+
+test_atomic_pthreads_SOURCES=test_atomic.c 
+test_atomic_pthreads_CPPFLAGS=-DAO_USE_PTHREAD_DEFS $(AM_CPPFLAGS)
+test_atomic_pthreads_LDADD=-lpthread ../src/libatomic_ops.a
+
+test_stack_SOURCES=test_stack.c 
+test_stack_LDADD=-lpthread ../src/libatomic_ops_gpl.a ../src/libatomic_ops.a 
+
+test_malloc_SOURCES=test_malloc.c 
+test_malloc_LDADD=-lpthread ../src/libatomic_ops_gpl.a ../src/libatomic_ops.a 
+
+test_atomic_include.h: test_atomic.template
+       sed -e s/XX// $? > $@
+       sed -e s/XX/_release/ $? >> $@
+       sed -e s/XX/_acquire/ $? >> $@
+       sed -e s/XX/_read/ $? >> $@
+       sed -e s/XX/_write/ $? >> $@
+       sed -e s/XX/_full/ $? >> $@
+       sed -e s/XX/_release_write/ $? >> $@
+       sed -e s/XX/_acquire_read/ $? >> $@
+
+list_atomic.c: list_atomic.template
+       echo "#include \"atomic_ops.h\" " > $@
+       sed -e s/XX// $? >> $@
+       sed -e s/XX/_release/ $? >> $@
+       sed -e s/XX/_acquire/ $? >> $@
+       sed -e s/XX/_read/ $? >> $@
+       sed -e s/XX/_write/ $? >> $@
+       sed -e s/XX/_full/ $? >> $@
+       sed -e s/XX/_release_write/ $? >> $@
+       sed -e s/XX/_acquire_read/ $? >> $@
+
+list_atomic.i: list_atomic.c
+       $(COMPILE) $? -E > list_atomic.i
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/tests/list_atomic.c b/src/mm/boehm-gc/libatomic_ops-1.2/tests/list_atomic.c
new file mode 100644 (file)
index 0000000..1faf5c4
--- /dev/null
@@ -0,0 +1,569 @@
+#include "atomic_ops.h" 
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* This generates a compilable program.  But it is really meant to be  */
+/* be used only with cc -E, to inspect the expensions generated by     */
+/* primitives.                                                         */
+
+/* The result will not link or run.                                    */
+
+void list_atomic(void)
+{
+  AO_T *addr, val, newval, oldval;
+  AO_TS_T tsaddr;
+  long incr;
+
+# if defined(AO_HAVE_nop)
+    "AO_nop(): ";
+    AO_nop();
+# else
+    "No AO_nop";
+# endif
+# if defined(AO_HAVE_load)
+    "AO_load(addr):";
+    AO_load(addr);
+# else
+    "No AO_load";
+# endif
+# if defined(AO_HAVE_store)
+    "AO_store(addr, val):";
+    AO_store(addr, val);
+# else
+    "No AO_store";
+# endif
+# if defined(AO_HAVE_test_and_set)
+    "AO_test_and_set(tsaddr):";
+    AO_test_and_set(tsaddr);
+# else
+    "No AO_test_and_set";
+# endif
+# if defined(AO_HAVE_fetch_and_add1)
+    "AO_fetch_and_add1(addr):";
+    AO_fetch_and_add1(addr);
+# else
+    "No AO_fetch_and_add1";
+# endif
+# if defined(AO_HAVE_fetch_and_sub1)
+    "AO_fetch_and_sub1(addr):";
+    AO_fetch_and_sub1(addr);
+# else
+    "No AO_fetch_and_sub1";
+# endif
+# if defined(AO_HAVE_fetch_and_add)
+    "AO_fetch_and_add(addr, incr):";
+    AO_fetch_and_add(addr, incr);
+# else
+    "No AO_fetch_and_add";
+# endif
+# if defined(AO_HAVE_compare_and_swap)
+    "AO_compare_and_swap(addr, oldval, newval):";
+    AO_compare_and_swap(addr, oldval, newval);
+# else
+    "No AO_compare_and_swap";
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* This generates a compilable program.  But it is really meant to be  */
+/* be used only with cc -E, to inspect the expensions generated by     */
+/* primitives.                                                         */
+
+/* The result will not link or run.                                    */
+
+void list_atomic_release(void)
+{
+  AO_T *addr, val, newval, oldval;
+  AO_TS_T tsaddr;
+  long incr;
+
+# if defined(AO_HAVE_nop_release)
+    "AO_nop_release(): ";
+    AO_nop_release();
+# else
+    "No AO_nop_release";
+# endif
+# if defined(AO_HAVE_load_release)
+    "AO_load_release(addr):";
+    AO_load_release(addr);
+# else
+    "No AO_load_release";
+# endif
+# if defined(AO_HAVE_store_release)
+    "AO_store_release(addr, val):";
+    AO_store_release(addr, val);
+# else
+    "No AO_store_release";
+# endif
+# if defined(AO_HAVE_test_and_set_release)
+    "AO_test_and_set_release(tsaddr):";
+    AO_test_and_set_release(tsaddr);
+# else
+    "No AO_test_and_set_release";
+# endif
+# if defined(AO_HAVE_fetch_and_add1_release)
+    "AO_fetch_and_add1_release(addr):";
+    AO_fetch_and_add1_release(addr);
+# else
+    "No AO_fetch_and_add1_release";
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_release)
+    "AO_fetch_and_sub1_release(addr):";
+    AO_fetch_and_sub1_release(addr);
+# else
+    "No AO_fetch_and_sub1_release";
+# endif
+# if defined(AO_HAVE_fetch_and_add_release)
+    "AO_fetch_and_add_release(addr, incr):";
+    AO_fetch_and_add_release(addr, incr);
+# else
+    "No AO_fetch_and_add_release";
+# endif
+# if defined(AO_HAVE_compare_and_swap_release)
+    "AO_compare_and_swap_release(addr, oldval, newval):";
+    AO_compare_and_swap_release(addr, oldval, newval);
+# else
+    "No AO_compare_and_swap_release";
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* This generates a compilable program.  But it is really meant to be  */
+/* be used only with cc -E, to inspect the expensions generated by     */
+/* primitives.                                                         */
+
+/* The result will not link or run.                                    */
+
+void list_atomic_acquire(void)
+{
+  AO_T *addr, val, newval, oldval;
+  AO_TS_T tsaddr;
+  long incr;
+
+# if defined(AO_HAVE_nop_acquire)
+    "AO_nop_acquire(): ";
+    AO_nop_acquire();
+# else
+    "No AO_nop_acquire";
+# endif
+# if defined(AO_HAVE_load_acquire)
+    "AO_load_acquire(addr):";
+    AO_load_acquire(addr);
+# else
+    "No AO_load_acquire";
+# endif
+# if defined(AO_HAVE_store_acquire)
+    "AO_store_acquire(addr, val):";
+    AO_store_acquire(addr, val);
+# else
+    "No AO_store_acquire";
+# endif
+# if defined(AO_HAVE_test_and_set_acquire)
+    "AO_test_and_set_acquire(tsaddr):";
+    AO_test_and_set_acquire(tsaddr);
+# else
+    "No AO_test_and_set_acquire";
+# endif
+# if defined(AO_HAVE_fetch_and_add1_acquire)
+    "AO_fetch_and_add1_acquire(addr):";
+    AO_fetch_and_add1_acquire(addr);
+# else
+    "No AO_fetch_and_add1_acquire";
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_acquire)
+    "AO_fetch_and_sub1_acquire(addr):";
+    AO_fetch_and_sub1_acquire(addr);
+# else
+    "No AO_fetch_and_sub1_acquire";
+# endif
+# if defined(AO_HAVE_fetch_and_add_acquire)
+    "AO_fetch_and_add_acquire(addr, incr):";
+    AO_fetch_and_add_acquire(addr, incr);
+# else
+    "No AO_fetch_and_add_acquire";
+# endif
+# if defined(AO_HAVE_compare_and_swap_acquire)
+    "AO_compare_and_swap_acquire(addr, oldval, newval):";
+    AO_compare_and_swap_acquire(addr, oldval, newval);
+# else
+    "No AO_compare_and_swap_acquire";
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* This generates a compilable program.  But it is really meant to be  */
+/* be used only with cc -E, to inspect the expensions generated by     */
+/* primitives.                                                         */
+
+/* The result will not link or run.                                    */
+
+void list_atomic_read(void)
+{
+  AO_T *addr, val, newval, oldval;
+  AO_TS_T tsaddr;
+  long incr;
+
+# if defined(AO_HAVE_nop_read)
+    "AO_nop_read(): ";
+    AO_nop_read();
+# else
+    "No AO_nop_read";
+# endif
+# if defined(AO_HAVE_load_read)
+    "AO_load_read(addr):";
+    AO_load_read(addr);
+# else
+    "No AO_load_read";
+# endif
+# if defined(AO_HAVE_store_read)
+    "AO_store_read(addr, val):";
+    AO_store_read(addr, val);
+# else
+    "No AO_store_read";
+# endif
+# if defined(AO_HAVE_test_and_set_read)
+    "AO_test_and_set_read(tsaddr):";
+    AO_test_and_set_read(tsaddr);
+# else
+    "No AO_test_and_set_read";
+# endif
+# if defined(AO_HAVE_fetch_and_add1_read)
+    "AO_fetch_and_add1_read(addr):";
+    AO_fetch_and_add1_read(addr);
+# else
+    "No AO_fetch_and_add1_read";
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_read)
+    "AO_fetch_and_sub1_read(addr):";
+    AO_fetch_and_sub1_read(addr);
+# else
+    "No AO_fetch_and_sub1_read";
+# endif
+# if defined(AO_HAVE_fetch_and_add_read)
+    "AO_fetch_and_add_read(addr, incr):";
+    AO_fetch_and_add_read(addr, incr);
+# else
+    "No AO_fetch_and_add_read";
+# endif
+# if defined(AO_HAVE_compare_and_swap_read)
+    "AO_compare_and_swap_read(addr, oldval, newval):";
+    AO_compare_and_swap_read(addr, oldval, newval);
+# else
+    "No AO_compare_and_swap_read";
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* This generates a compilable program.  But it is really meant to be  */
+/* be used only with cc -E, to inspect the expensions generated by     */
+/* primitives.                                                         */
+
+/* The result will not link or run.                                    */
+
+void list_atomic_write(void)
+{
+  AO_T *addr, val, newval, oldval;
+  AO_TS_T tsaddr;
+  long incr;
+
+# if defined(AO_HAVE_nop_write)
+    "AO_nop_write(): ";
+    AO_nop_write();
+# else
+    "No AO_nop_write";
+# endif
+# if defined(AO_HAVE_load_write)
+    "AO_load_write(addr):";
+    AO_load_write(addr);
+# else
+    "No AO_load_write";
+# endif
+# if defined(AO_HAVE_store_write)
+    "AO_store_write(addr, val):";
+    AO_store_write(addr, val);
+# else
+    "No AO_store_write";
+# endif
+# if defined(AO_HAVE_test_and_set_write)
+    "AO_test_and_set_write(tsaddr):";
+    AO_test_and_set_write(tsaddr);
+# else
+    "No AO_test_and_set_write";
+# endif
+# if defined(AO_HAVE_fetch_and_add1_write)
+    "AO_fetch_and_add1_write(addr):";
+    AO_fetch_and_add1_write(addr);
+# else
+    "No AO_fetch_and_add1_write";
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_write)
+    "AO_fetch_and_sub1_write(addr):";
+    AO_fetch_and_sub1_write(addr);
+# else
+    "No AO_fetch_and_sub1_write";
+# endif
+# if defined(AO_HAVE_fetch_and_add_write)
+    "AO_fetch_and_add_write(addr, incr):";
+    AO_fetch_and_add_write(addr, incr);
+# else
+    "No AO_fetch_and_add_write";
+# endif
+# if defined(AO_HAVE_compare_and_swap_write)
+    "AO_compare_and_swap_write(addr, oldval, newval):";
+    AO_compare_and_swap_write(addr, oldval, newval);
+# else
+    "No AO_compare_and_swap_write";
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* This generates a compilable program.  But it is really meant to be  */
+/* be used only with cc -E, to inspect the expensions generated by     */
+/* primitives.                                                         */
+
+/* The result will not link or run.                                    */
+
+void list_atomic_full(void)
+{
+  AO_T *addr, val, newval, oldval;
+  AO_TS_T tsaddr;
+  long incr;
+
+# if defined(AO_HAVE_nop_full)
+    "AO_nop_full(): ";
+    AO_nop_full();
+# else
+    "No AO_nop_full";
+# endif
+# if defined(AO_HAVE_load_full)
+    "AO_load_full(addr):";
+    AO_load_full(addr);
+# else
+    "No AO_load_full";
+# endif
+# if defined(AO_HAVE_store_full)
+    "AO_store_full(addr, val):";
+    AO_store_full(addr, val);
+# else
+    "No AO_store_full";
+# endif
+# if defined(AO_HAVE_test_and_set_full)
+    "AO_test_and_set_full(tsaddr):";
+    AO_test_and_set_full(tsaddr);
+# else
+    "No AO_test_and_set_full";
+# endif
+# if defined(AO_HAVE_fetch_and_add1_full)
+    "AO_fetch_and_add1_full(addr):";
+    AO_fetch_and_add1_full(addr);
+# else
+    "No AO_fetch_and_add1_full";
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_full)
+    "AO_fetch_and_sub1_full(addr):";
+    AO_fetch_and_sub1_full(addr);
+# else
+    "No AO_fetch_and_sub1_full";
+# endif
+# if defined(AO_HAVE_fetch_and_add_full)
+    "AO_fetch_and_add_full(addr, incr):";
+    AO_fetch_and_add_full(addr, incr);
+# else
+    "No AO_fetch_and_add_full";
+# endif
+# if defined(AO_HAVE_compare_and_swap_full)
+    "AO_compare_and_swap_full(addr, oldval, newval):";
+    AO_compare_and_swap_full(addr, oldval, newval);
+# else
+    "No AO_compare_and_swap_full";
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* This generates a compilable program.  But it is really meant to be  */
+/* be used only with cc -E, to inspect the expensions generated by     */
+/* primitives.                                                         */
+
+/* The result will not link or run.                                    */
+
+void list_atomic_release_write(void)
+{
+  AO_T *addr, val, newval, oldval;
+  AO_TS_T tsaddr;
+  long incr;
+
+# if defined(AO_HAVE_nop_release_write)
+    "AO_nop_release_write(): ";
+    AO_nop_release_write();
+# else
+    "No AO_nop_release_write";
+# endif
+# if defined(AO_HAVE_load_release_write)
+    "AO_load_release_write(addr):";
+    AO_load_release_write(addr);
+# else
+    "No AO_load_release_write";
+# endif
+# if defined(AO_HAVE_store_release_write)
+    "AO_store_release_write(addr, val):";
+    AO_store_release_write(addr, val);
+# else
+    "No AO_store_release_write";
+# endif
+# if defined(AO_HAVE_test_and_set_release_write)
+    "AO_test_and_set_release_write(tsaddr):";
+    AO_test_and_set_release_write(tsaddr);
+# else
+    "No AO_test_and_set_release_write";
+# endif
+# if defined(AO_HAVE_fetch_and_add1_release_write)
+    "AO_fetch_and_add1_release_write(addr):";
+    AO_fetch_and_add1_release_write(addr);
+# else
+    "No AO_fetch_and_add1_release_write";
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_release_write)
+    "AO_fetch_and_sub1_release_write(addr):";
+    AO_fetch_and_sub1_release_write(addr);
+# else
+    "No AO_fetch_and_sub1_release_write";
+# endif
+# if defined(AO_HAVE_fetch_and_add_release_write)
+    "AO_fetch_and_add_release_write(addr, incr):";
+    AO_fetch_and_add_release_write(addr, incr);
+# else
+    "No AO_fetch_and_add_release_write";
+# endif
+# if defined(AO_HAVE_compare_and_swap_release_write)
+    "AO_compare_and_swap_release_write(addr, oldval, newval):";
+    AO_compare_and_swap_release_write(addr, oldval, newval);
+# else
+    "No AO_compare_and_swap_release_write";
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* This generates a compilable program.  But it is really meant to be  */
+/* be used only with cc -E, to inspect the expensions generated by     */
+/* primitives.                                                         */
+
+/* The result will not link or run.                                    */
+
+void list_atomic_acquire_read(void)
+{
+  AO_T *addr, val, newval, oldval;
+  AO_TS_T tsaddr;
+  long incr;
+
+# if defined(AO_HAVE_nop_acquire_read)
+    "AO_nop_acquire_read(): ";
+    AO_nop_acquire_read();
+# else
+    "No AO_nop_acquire_read";
+# endif
+# if defined(AO_HAVE_load_acquire_read)
+    "AO_load_acquire_read(addr):";
+    AO_load_acquire_read(addr);
+# else
+    "No AO_load_acquire_read";
+# endif
+# if defined(AO_HAVE_store_acquire_read)
+    "AO_store_acquire_read(addr, val):";
+    AO_store_acquire_read(addr, val);
+# else
+    "No AO_store_acquire_read";
+# endif
+# if defined(AO_HAVE_test_and_set_acquire_read)
+    "AO_test_and_set_acquire_read(tsaddr):";
+    AO_test_and_set_acquire_read(tsaddr);
+# else
+    "No AO_test_and_set_acquire_read";
+# endif
+# if defined(AO_HAVE_fetch_and_add1_acquire_read)
+    "AO_fetch_and_add1_acquire_read(addr):";
+    AO_fetch_and_add1_acquire_read(addr);
+# else
+    "No AO_fetch_and_add1_acquire_read";
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_acquire_read)
+    "AO_fetch_and_sub1_acquire_read(addr):";
+    AO_fetch_and_sub1_acquire_read(addr);
+# else
+    "No AO_fetch_and_sub1_acquire_read";
+# endif
+# if defined(AO_HAVE_fetch_and_add_acquire_read)
+    "AO_fetch_and_add_acquire_read(addr, incr):";
+    AO_fetch_and_add_acquire_read(addr, incr);
+# else
+    "No AO_fetch_and_add_acquire_read";
+# endif
+# if defined(AO_HAVE_compare_and_swap_acquire_read)
+    "AO_compare_and_swap_acquire_read(addr, oldval, newval):";
+    AO_compare_and_swap_acquire_read(addr, oldval, newval);
+# else
+    "No AO_compare_and_swap_acquire_read";
+# endif
+}
+
+
+    
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/tests/list_atomic.template b/src/mm/boehm-gc/libatomic_ops-1.2/tests/list_atomic.template
new file mode 100644 (file)
index 0000000..a3d36e3
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* This generates a compilable program.  But it is really meant to be  */
+/* be used only with cc -E, to inspect the expensions generated by     */
+/* primitives.                                                         */
+
+/* The result will not link or run.                                    */
+
+void list_atomicXX(void)
+{
+  AO_T *addr, val, newval, oldval;
+  AO_TS_T tsaddr;
+  long incr;
+
+# if defined(AO_HAVE_nopXX)
+    "AO_nopXX(): ";
+    AO_nopXX();
+# else
+    "No AO_nopXX";
+# endif
+# if defined(AO_HAVE_loadXX)
+    "AO_loadXX(addr):";
+    AO_loadXX(addr);
+# else
+    "No AO_loadXX";
+# endif
+# if defined(AO_HAVE_storeXX)
+    "AO_storeXX(addr, val):";
+    AO_storeXX(addr, val);
+# else
+    "No AO_storeXX";
+# endif
+# if defined(AO_HAVE_test_and_setXX)
+    "AO_test_and_setXX(tsaddr):";
+    AO_test_and_setXX(tsaddr);
+# else
+    "No AO_test_and_setXX";
+# endif
+# if defined(AO_HAVE_fetch_and_add1XX)
+    "AO_fetch_and_add1XX(addr):";
+    AO_fetch_and_add1XX(addr);
+# else
+    "No AO_fetch_and_add1XX";
+# endif
+# if defined(AO_HAVE_fetch_and_sub1XX)
+    "AO_fetch_and_sub1XX(addr):";
+    AO_fetch_and_sub1XX(addr);
+# else
+    "No AO_fetch_and_sub1XX";
+# endif
+# if defined(AO_HAVE_fetch_and_addXX)
+    "AO_fetch_and_addXX(addr, incr):";
+    AO_fetch_and_addXX(addr, incr);
+# else
+    "No AO_fetch_and_addXX";
+# endif
+# if defined(AO_HAVE_compare_and_swapXX)
+    "AO_compare_and_swapXX(addr, oldval, newval):";
+    AO_compare_and_swapXX(addr, oldval, newval);
+# else
+    "No AO_compare_and_swapXX";
+# endif
+}
+
+
+    
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/tests/run_parallel.inc b/src/mm/boehm-gc/libatomic_ops-1.2/tests/run_parallel.inc
new file mode 100644 (file)
index 0000000..1a87c8b
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+#if defined(_MSC_VER) || \
+    defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) || \
+    defined(_WIN32_WINCE)
+#  define USE_WINTHREADS
+#elif defined(__vxworks)
+#  define USE_VXTHREADS
+#else
+#  define USE_PTHREADS
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef USE_PTHREADS
+# include <pthread.h>
+#endif
+
+#ifdef USE_VXTHREADS
+# include <vxworks.h>
+# include <taskLib.h>
+#endif
+
+#ifdef USE_WINTHREADS
+# include <windows.h>
+#endif
+
+#include "atomic_ops.h"
+
+typedef void * (* thr_func)(void *);
+
+typedef int (* test_func)(void);       /* Returns != 0 on success */
+
+void * run_parallel(int nthreads, thr_func f1, test_func t, const char *name);
+
+#ifdef USE_PTHREADS
+void * run_parallel(int nthreads, thr_func f1, test_func t, const char *name)
+{
+  pthread_attr_t attr;
+  pthread_t thr[100];
+  int i;
+  int code;
+
+  fprintf(stderr, "Testing %s\n", name);
+  if (nthreads > 100) 
+    {
+      fprintf(stderr, "run_parallel: requested too many threads\n");
+      abort();
+    }
+
+# ifdef _HPUX_SOURCE
+   /* Default stack size is too small, especially with the 64 bit ABI */
+   /* Increase it.                                                    */
+    if (pthread_default_stacksize_np(1024*1024, 0) != 0) {
+      fprintf(stderr, "pthread_default_stacksize_np failed. "
+                     "OK after first call.\n");
+    }
+# endif
+
+  pthread_attr_init(&attr);
+
+  for (i = 0; i < nthreads; ++i)
+    {
+      if ((code = pthread_create(thr + i, &attr, f1, (void *)(long)i)) != 0)
+       {
+         perror("Thread creation failed");
+         fprintf(stderr, "Pthread_create returned %d, thread %d\n", code, i);
+         abort();
+        }
+    }
+  for (i = 0; i < nthreads; ++i)
+    {
+      if ((code = pthread_join(thr[i], NULL)) != 0)
+       {
+         perror("Thread join failed");
+         fprintf(stderr, "Pthread_join returned %d, thread %d\n", code, i);
+         abort();
+        }
+    }
+  if (t())
+    {
+      fprintf(stderr, "Succeeded\n");
+    }
+  else
+    {
+      fprintf(stderr, "Failed\n");
+      abort();
+    }
+  return 0;
+}
+#endif /* USE_PTHREADS */
+
+#ifdef USE_VXTHREADS
+void * run_parallel(int nthreads, thr_func f1, test_func t, const char *name)
+{
+  int thr[100];
+  int i;
+
+  fprintf(stderr, "Testing %s\n", name);
+  if (nthreads > 100) 
+    {
+      fprintf(stderr, "run_parallel: requested too many threads\n");
+      taskSuspend(0);
+    }
+
+  for (i = 0; i < nthreads; ++i)
+    {
+      thr[i] = taskSpawn((char*) name, 180, 0, 32768, (FUNCPTR) f1, i,
+                         1, 2, 3, 4, 5, 6, 7, 8, 9);
+      if (thr[i] == ERROR)
+       {
+         fprintf(stderr, "taskSpawn failed with %d, thread %d\n",
+                         errno, i);
+         taskSuspend(0);
+        }
+    }
+  for (i = 0; i < nthreads; ++i)
+    {
+      while (taskIdVerify(thr[i]) == OK)
+        taskDelay(60);
+    }
+  if (t())
+    {
+      fprintf(stderr, "Succeeded\n");
+    }
+  else
+    {
+      fprintf(stderr, "Failed\n");
+      taskSuspend(0);
+    }
+  return 0;
+}
+#endif /* USE_VXTHREADS */
+
+#ifdef USE_WINTHREADS
+
+struct tramp_args {
+  thr_func fn;
+  long arg;
+};
+
+DWORD WINAPI tramp(LPVOID param)
+{
+  struct tramp_args *args = (struct tramp_args *)param;
+
+  return (DWORD)(args -> fn)((LPVOID)(args -> arg));
+}
+
+void * run_parallel(int nthreads, thr_func f1, test_func t, const char *name)
+{
+  HANDLE thr[100];
+  struct tramp_args args[100];
+  int i;
+  DWORD code;
+
+  fprintf(stderr, "Testing %s\n", name);
+  if (nthreads > 100) 
+    {
+      fprintf(stderr, "run_parallel: requested too many threads\n");
+      abort();
+    }
+
+  for (i = 0; i < nthreads; ++i)
+    {
+      args[i].fn = f1;
+      args[i].arg = i;
+      if ((thr[i] = CreateThread(NULL, 0, tramp, (LPVOID)(args+i), 0, NULL))
+         == NULL)
+       {
+         perror("Thread creation failed");
+         fprintf(stderr, "CreateThread failed with %d, thread %d\n",
+                         GetLastError(), i);
+         abort();
+        }
+    }
+  for (i = 0; i < nthreads; ++i)
+    {
+      if ((code = WaitForSingleObject(thr[i], INFINITE)) != WAIT_OBJECT_0)
+       {
+         perror("Thread join failed");
+         fprintf(stderr, "WaitForSingleObject returned %d, thread %d\n",
+                         code, i);
+         abort();
+        }
+    }
+  if (t())
+    {
+      fprintf(stderr, "Succeeded\n");
+    }
+  else
+    {
+      fprintf(stderr, "Failed\n");
+      abort();
+    }
+  return 0;
+}
+#endif /* USE_WINTHREADS */
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_atomic.c b/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_atomic.c
new file mode 100644 (file)
index 0000000..d31297d
--- /dev/null
@@ -0,0 +1,190 @@
+/*  
+ * Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
+ * Original Author: Hans Boehm
+ *
+ * This file may be redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ * 
+ * It is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License in the
+ * file doc/COPYING for more details.
+ */
+
+#if defined(HAVE_CONFIG_H)
+# include "config.h"
+#endif
+
+
+#include "run_parallel.inc"
+
+#include "test_atomic_include.h"
+
+#ifdef AO_USE_PTHREAD_DEFS
+# define NITERS 100000
+#else
+# define NITERS 10000000
+#endif
+
+void * add1sub1_thr(void * id);
+int add1sub1_test(void);
+void * acqrel_thr(void *id);
+int acqrel_test(void);
+void * test_and_set_thr(void * id);
+int test_and_set_test(void);
+
+#if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1)
+
+AO_t counter = 0;
+
+void * add1sub1_thr(void * id)
+{
+  int me = (int)(long)id;
+
+  int i;
+
+  for (i = 0; i < NITERS; ++i)
+    if (me & 1)
+      AO_fetch_and_sub1(&counter);
+    else
+      AO_fetch_and_add1(&counter);
+
+  return 0;
+}
+
+int add1sub1_test(void)
+{
+  return counter == 0;
+}
+
+#endif /* defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1) */
+
+#if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read)
+
+/* Invariant: counter1 >= counter2 */
+AO_t counter1 = 0;
+AO_t counter2 = 0;
+
+void * acqrel_thr(void *id)
+{
+  int me = (int)(long)id;
+
+  int i;
+
+  for (i = 0; i < NITERS; ++i)
+    if (me & 1)
+      {
+        AO_t my_counter1;
+       if (me != 1)
+         fprintf(stderr, "acqrel test: too many threads\n");
+       my_counter1 = AO_load(&counter1);
+       AO_store(&counter1, my_counter1 + 1);
+       AO_store_release_write(&counter2, my_counter1 + 1);
+      }
+    else
+      {
+       AO_t my_counter1a, my_counter2a;
+       AO_t my_counter1b, my_counter2b;
+
+       my_counter2a = AO_load_acquire_read(&counter2);
+       my_counter1a = AO_load(&counter1);
+       /* Redo this, to make sure that the second load of counter1     */
+       /* is not viewed as a common subexpression.                     */
+       my_counter2b = AO_load_acquire_read(&counter2);
+       my_counter1b = AO_load(&counter1);
+       if (my_counter1a < my_counter2a)
+         {
+           fprintf(stderr, "Saw release store out of order: %lu < %lu\n",
+                   (unsigned long)my_counter1a, (unsigned long)my_counter2a);
+           abort();
+         }
+       if (my_counter1b < my_counter2b)
+         {
+           fprintf(stderr,
+                   "Saw release store out of order (bad CSE?): %lu < %lu\n",
+                   (unsigned long)my_counter1b, (unsigned long)my_counter2b);
+           abort();
+         }
+      }
+
+  return 0;
+}
+
+int acqrel_test(void)
+{
+  return counter1 == NITERS && counter2 == NITERS;
+}
+
+#endif /* AO_HAVE_store_release_write && AO_HAVE_load_acquire_read */
+
+#if defined(AO_HAVE_test_and_set_acquire)
+
+AO_TS_T lock = AO_TS_INITIALIZER;
+
+unsigned long locked_counter;
+volatile unsigned long junk = 13;
+
+void * test_and_set_thr(void * id)
+{
+  unsigned long i;
+
+  for (i = 0; i < NITERS/10; ++i)
+    {
+      while (AO_test_and_set_acquire(&lock) != AO_TS_CLEAR);
+      ++locked_counter;
+      if (locked_counter != 1)
+        {
+          fprintf(stderr, "Test and set failure 1, counter = %ld\n",
+                     locked_counter);
+          abort();
+        }
+      locked_counter *= 2;
+      locked_counter -= 1;
+      locked_counter *= 5;
+      locked_counter -= 4;
+      if (locked_counter != 1)
+        {
+          fprintf(stderr, "Test and set failure 2, counter = %ld\n",
+                     locked_counter);
+          abort();
+        }
+      --locked_counter;
+      AO_CLEAR(&lock);
+      /* Spend a bit of time outside the lock. */
+        junk *= 17;
+        junk *= 17;
+    }
+  return 0;
+}
+
+int test_and_set_test(void)
+{
+  return locked_counter == 0;
+}
+
+#endif /* defined(AO_HAVE_test_and_set_acquire) */
+
+int main()
+{
+  test_atomic();
+  test_atomic_acquire();
+  test_atomic_release();
+  test_atomic_read();
+  test_atomic_write();
+  test_atomic_full();
+  test_atomic_release_write();
+  test_atomic_acquire_read();
+# if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1)
+    run_parallel(4, add1sub1_thr, add1sub1_test, "add1/sub1");
+# endif
+# if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read)
+    run_parallel(3, acqrel_thr, acqrel_test,
+                "store_release_write/load_acquire_read");
+# endif
+# if defined(AO_HAVE_test_and_set_acquire)
+    run_parallel(5, test_and_set_thr, test_and_set_test,
+                "test_and_set");
+# endif
+  return 0;
+}
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_atomic.template b/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_atomic.template
new file mode 100644 (file)
index 0000000..f80eac8
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* Some basic sanity tests.  These do not test the barrier semantics. */
+
+#undef TA_assert
+#define TA_assert(e) \
+  if (!(e)) { fprintf(stderr, "Assertion failed %s:%d (barrier: XX)\n", \
+                   __FILE__, __LINE__), exit(1); }
+
+#undef MISSING
+#define MISSING(name) \
+  fprintf(stderr, "Missing: %s\n", #name "XX")
+
+void test_atomicXX(void)
+{
+  AO_t x;
+  unsigned char b;
+  unsigned short s;
+  unsigned int zz;
+# if defined(AO_HAVE_test_and_setXX)
+    AO_TS_t z = AO_TS_INITIALIZER;
+# endif
+# if defined(AO_HAVE_double_t)
+    AO_double_t w;
+    w.AO_val1 = 0;
+    w.AO_val2 = 0;
+# endif
+
+# if defined(AO_HAVE_nopXX)
+    AO_nopXX();
+# else
+    MISSING(AO_nop);
+# endif
+# if defined(AO_HAVE_storeXX)
+    AO_storeXX(&x, 13);
+    TA_assert (x == 13);
+# else
+    MISSING(AO_store);
+    x = 13;
+# endif
+# if defined(AO_HAVE_loadXX)
+    TA_assert(AO_loadXX(&x) == 13);
+# else
+    MISSING(AO_load);
+# endif
+# if defined(AO_HAVE_test_and_setXX)
+    assert(AO_test_and_setXX(&z) == AO_TS_CLEAR);
+    assert(AO_test_and_setXX(&z) == AO_TS_SET);
+    assert(AO_test_and_setXX(&z) == AO_TS_SET);
+    AO_CLEAR(&z);
+# else
+    MISSING(AO_test_and_set);
+# endif
+# if defined(AO_HAVE_fetch_and_addXX)
+    TA_assert(AO_fetch_and_addXX(&x, 42) == 13);
+    TA_assert(AO_fetch_and_addXX(&x, -42) == 55);
+# else
+    MISSING(AO_fetch_and_add);
+# endif
+# if defined(AO_HAVE_fetch_and_add1XX)
+    TA_assert(AO_fetch_and_add1XX(&x) == 13);
+# else
+    MISSING(AO_fetch_and_add1);
+    ++x;
+# endif
+# if defined(AO_HAVE_fetch_and_sub1XX)
+    TA_assert(AO_fetch_and_sub1XX(&x) == 14);
+# else
+    MISSING(AO_fetch_and_sub1);
+    --x;
+# endif
+# if defined(AO_HAVE_short_storeXX)
+    AO_short_storeXX(&s, 13);
+# else
+    MISSING(AO_short_store);
+    s = 13;
+# endif
+# if defined(AO_HAVE_short_loadXX)
+    TA_assert(AO_short_load(&s) == 13);
+# else
+    MISSING(AO_short_load);
+# endif
+# if defined(AO_HAVE_short_fetch_and_addXX)
+    TA_assert(AO_short_fetch_and_addXX(&s, 42) == 13);
+    TA_assert(AO_short_fetch_and_addXX(&s, -42) == 55);
+# else
+    MISSING(AO_short_fetch_and_add);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add1XX)
+    TA_assert(AO_short_fetch_and_add1XX(&s) == 13);
+# else
+    MISSING(AO_short_fetch_and_add1);
+    ++s;
+# endif
+# if defined(AO_HAVE_short_fetch_and_sub1XX)
+    TA_assert(AO_short_fetch_and_sub1XX(&s) == 14);
+# else
+    MISSING(AO_short_fetch_and_sub1);
+    --s;
+# endif
+# if defined(AO_HAVE_char_storeXX)
+    AO_char_storeXX(&b, 13);
+# else
+    MISSING(AO_char_store);
+    b = 13;
+# endif
+# if defined(AO_HAVE_char_loadXX)
+    TA_assert(AO_char_load(&b) == 13);
+# else
+    MISSING(AO_char_load);
+# endif
+# if defined(AO_HAVE_char_fetch_and_addXX)
+    TA_assert(AO_char_fetch_and_addXX(&b, 42) == 13);
+    TA_assert(AO_char_fetch_and_addXX(&b, -42) == 55);
+# else
+    MISSING(AO_char_fetch_and_add);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add1XX)
+    TA_assert(AO_char_fetch_and_add1XX(&b) == 13);
+# else
+    MISSING(AO_char_fetch_and_add1);
+    ++b;
+# endif
+# if defined(AO_HAVE_char_fetch_and_sub1XX)
+    TA_assert(AO_char_fetch_and_sub1XX(&b) == 14);
+# else
+    MISSING(AO_char_fetch_and_sub1);
+    --b;
+# endif
+# if defined(AO_HAVE_int_storeXX)
+    AO_int_storeXX(&zz, 13);
+# else
+    MISSING(AO_int_store);
+    zz = 13;
+# endif
+# if defined(AO_HAVE_int_loadXX)
+    TA_assert(AO_int_load(&zz) == 13);
+# else
+    MISSING(AO_int_load);
+# endif
+# if defined(AO_HAVE_int_fetch_and_addXX)
+    TA_assert(AO_int_fetch_and_addXX(&zz, 42) == 13);
+    TA_assert(AO_int_fetch_and_addXX(&zz, -42) == 55);
+# else
+    MISSING(AO_int_fetch_and_add);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add1XX)
+    TA_assert(AO_int_fetch_and_add1XX(&zz) == 13);
+# else
+    MISSING(AO_int_fetch_and_add1);
+    ++zz;
+# endif
+# if defined(AO_HAVE_int_fetch_and_sub1XX)
+    TA_assert(AO_int_fetch_and_sub1XX(&zz) == 14);
+# else
+    MISSING(AO_int_fetch_and_sub1);
+    --zz;
+# endif
+# if defined(AO_HAVE_compare_and_swapXX)
+    TA_assert(!AO_compare_and_swapXX(&x, 14, 42));
+    TA_assert(x == 13);
+    TA_assert(AO_compare_and_swapXX(&x, 13, 42));
+    TA_assert(x == 42);
+# else
+    MISSING(AO_compare_and_swap);
+# endif
+# if defined(AO_HAVE_orXX)
+    AO_orXX(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
+# if defined(AO_HAVE_compare_double_and_swap_doubleXX)
+    TA_assert(!AO_compare_double_and_swap_doubleXX(&w, 17, 42, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_double_and_swap_doubleXX(&w, 0, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_double_and_swap_doubleXX(&w, 12, 13, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+    w.AO_val1 = 0; w.AO_val2 = 0;
+# else
+    MISSING(AO_compare_double_and_swap_double);
+# endif
+# if defined(AO_HAVE_compare_and_swap_doubleXX)
+    TA_assert(!AO_compare_and_swap_doubleXX(&w, 17, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_and_swap_doubleXX(&w, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_and_swap_doubleXX(&w, 12, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+# else
+    MISSING(AO_compare_and_swap_double);
+# endif
+}
+
+
+    
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_atomic_include.h b/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_atomic_include.h
new file mode 100644 (file)
index 0000000..bc280eb
--- /dev/null
@@ -0,0 +1,1633 @@
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+void test_atomic(void);
+void test_atomic_release(void);
+void test_atomic_acquire(void);
+void test_atomic_read(void);
+void test_atomic_write(void);
+void test_atomic_full(void);
+void test_atomic_release_write(void);
+void test_atomic_acquire_read(void);
+
+/* Some basic sanity tests.  These do not test the barrier semantics. */
+
+#undef TA_assert
+#define TA_assert(e) \
+  if (!(e)) { fprintf(stderr, "Assertion failed %s:%d (barrier: )\n", \
+                   __FILE__, __LINE__), exit(1); }
+
+#undef MISSING
+#define MISSING(name) \
+  fprintf(stderr, "Missing: %s\n", #name "")
+
+void test_atomic(void)
+{
+  AO_t x;
+  unsigned char b;
+  unsigned short s;
+  unsigned int zz;
+# if defined(AO_HAVE_test_and_set)
+    AO_TS_t z = AO_TS_INITIALIZER;
+# endif
+# if defined(AO_HAVE_double_t)
+    AO_double_t w;
+    w.AO_val1 = 0;
+    w.AO_val2 = 0;
+# endif
+
+# if defined(AO_HAVE_nop)
+    AO_nop();
+# else
+    MISSING(AO_nop);
+# endif
+# if defined(AO_HAVE_store)
+    AO_store(&x, 13);
+    TA_assert (x == 13);
+# else
+    MISSING(AO_store);
+    x = 13;
+# endif
+# if defined(AO_HAVE_load)
+    TA_assert(AO_load(&x) == 13);
+# else
+    MISSING(AO_load);
+# endif
+# if defined(AO_HAVE_test_and_set)
+    assert(AO_test_and_set(&z) == AO_TS_CLEAR);
+    assert(AO_test_and_set(&z) == AO_TS_SET);
+    assert(AO_test_and_set(&z) == AO_TS_SET);
+    AO_CLEAR(&z);
+# else
+    MISSING(AO_test_and_set);
+# endif
+# if defined(AO_HAVE_fetch_and_add)
+    TA_assert(AO_fetch_and_add(&x, 42) == 13);
+    TA_assert(AO_fetch_and_add(&x, -42) == 55);
+# else
+    MISSING(AO_fetch_and_add);
+# endif
+# if defined(AO_HAVE_fetch_and_add1)
+    TA_assert(AO_fetch_and_add1(&x) == 13);
+# else
+    MISSING(AO_fetch_and_add1);
+    ++x;
+# endif
+# if defined(AO_HAVE_fetch_and_sub1)
+    TA_assert(AO_fetch_and_sub1(&x) == 14);
+# else
+    MISSING(AO_fetch_and_sub1);
+    --x;
+# endif
+# if defined(AO_HAVE_short_store)
+    AO_short_store(&s, 13);
+# else
+    MISSING(AO_short_store);
+    s = 13;
+# endif
+# if defined(AO_HAVE_short_load)
+    TA_assert(AO_short_load(&s) == 13);
+# else
+    MISSING(AO_short_load);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add)
+    TA_assert(AO_short_fetch_and_add(&s, 42) == 13);
+    TA_assert(AO_short_fetch_and_add(&s, -42) == 55);
+# else
+    MISSING(AO_short_fetch_and_add);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add1)
+    TA_assert(AO_short_fetch_and_add1(&s) == 13);
+# else
+    MISSING(AO_short_fetch_and_add1);
+    ++s;
+# endif
+# if defined(AO_HAVE_short_fetch_and_sub1)
+    TA_assert(AO_short_fetch_and_sub1(&s) == 14);
+# else
+    MISSING(AO_short_fetch_and_sub1);
+    --s;
+# endif
+# if defined(AO_HAVE_char_store)
+    AO_char_store(&b, 13);
+# else
+    MISSING(AO_char_store);
+    b = 13;
+# endif
+# if defined(AO_HAVE_char_load)
+    TA_assert(AO_char_load(&b) == 13);
+# else
+    MISSING(AO_char_load);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add)
+    TA_assert(AO_char_fetch_and_add(&b, 42) == 13);
+    TA_assert(AO_char_fetch_and_add(&b, -42) == 55);
+# else
+    MISSING(AO_char_fetch_and_add);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add1)
+    TA_assert(AO_char_fetch_and_add1(&b) == 13);
+# else
+    MISSING(AO_char_fetch_and_add1);
+    ++b;
+# endif
+# if defined(AO_HAVE_char_fetch_and_sub1)
+    TA_assert(AO_char_fetch_and_sub1(&b) == 14);
+# else
+    MISSING(AO_char_fetch_and_sub1);
+    --b;
+# endif
+# if defined(AO_HAVE_int_store)
+    AO_int_store(&zz, 13);
+# else
+    MISSING(AO_int_store);
+    zz = 13;
+# endif
+# if defined(AO_HAVE_int_load)
+    TA_assert(AO_int_load(&zz) == 13);
+# else
+    MISSING(AO_int_load);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add)
+    TA_assert(AO_int_fetch_and_add(&zz, 42) == 13);
+    TA_assert(AO_int_fetch_and_add(&zz, -42) == 55);
+# else
+    MISSING(AO_int_fetch_and_add);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add1)
+    TA_assert(AO_int_fetch_and_add1(&zz) == 13);
+# else
+    MISSING(AO_int_fetch_and_add1);
+    ++zz;
+# endif
+# if defined(AO_HAVE_int_fetch_and_sub1)
+    TA_assert(AO_int_fetch_and_sub1(&zz) == 14);
+# else
+    MISSING(AO_int_fetch_and_sub1);
+    --zz;
+# endif
+# if defined(AO_HAVE_compare_and_swap)
+    TA_assert(!AO_compare_and_swap(&x, 14, 42));
+    TA_assert(x == 13);
+    TA_assert(AO_compare_and_swap(&x, 13, 42));
+    TA_assert(x == 42);
+# else
+    MISSING(AO_compare_and_swap);
+# endif
+# if defined(AO_HAVE_or)
+    AO_or(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
+# if defined(AO_HAVE_compare_double_and_swap_double)
+    TA_assert(!AO_compare_double_and_swap_double(&w, 17, 42, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_double_and_swap_double(&w, 0, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_double_and_swap_double(&w, 12, 13, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+    w.AO_val1 = 0; w.AO_val2 = 0;
+# else
+    MISSING(AO_compare_double_and_swap_double);
+# endif
+# if defined(AO_HAVE_compare_and_swap_double)
+    TA_assert(!AO_compare_and_swap_double(&w, 17, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_and_swap_double(&w, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_and_swap_double(&w, 12, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+# else
+    MISSING(AO_compare_and_swap_double);
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* Some basic sanity tests.  These do not test the barrier semantics. */
+
+#undef TA_assert
+#define TA_assert(e) \
+  if (!(e)) { fprintf(stderr, "Assertion failed %s:%d (barrier: _release)\n", \
+                   __FILE__, __LINE__), exit(1); }
+
+#undef MISSING
+#define MISSING(name) \
+  fprintf(stderr, "Missing: %s\n", #name "_release")
+
+void test_atomic_release(void)
+{
+  AO_t x;
+  unsigned char b;
+  unsigned short s;
+  unsigned int zz;
+# if defined(AO_HAVE_test_and_set_release)
+    AO_TS_t z = AO_TS_INITIALIZER;
+# endif
+# if defined(AO_HAVE_double_t)
+    AO_double_t w;
+    w.AO_val1 = 0;
+    w.AO_val2 = 0;
+# endif
+
+# if defined(AO_HAVE_nop_release)
+    AO_nop_release();
+# else
+    MISSING(AO_nop);
+# endif
+# if defined(AO_HAVE_store_release)
+    AO_store_release(&x, 13);
+    TA_assert (x == 13);
+# else
+    MISSING(AO_store);
+    x = 13;
+# endif
+# if defined(AO_HAVE_load_release)
+    TA_assert(AO_load_release(&x) == 13);
+# else
+    MISSING(AO_load);
+# endif
+# if defined(AO_HAVE_test_and_set_release)
+    assert(AO_test_and_set_release(&z) == AO_TS_CLEAR);
+    assert(AO_test_and_set_release(&z) == AO_TS_SET);
+    assert(AO_test_and_set_release(&z) == AO_TS_SET);
+    AO_CLEAR(&z);
+# else
+    MISSING(AO_test_and_set);
+# endif
+# if defined(AO_HAVE_fetch_and_add_release)
+    TA_assert(AO_fetch_and_add_release(&x, 42) == 13);
+    TA_assert(AO_fetch_and_add_release(&x, -42) == 55);
+# else
+    MISSING(AO_fetch_and_add);
+# endif
+# if defined(AO_HAVE_fetch_and_add1_release)
+    TA_assert(AO_fetch_and_add1_release(&x) == 13);
+# else
+    MISSING(AO_fetch_and_add1);
+    ++x;
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_release)
+    TA_assert(AO_fetch_and_sub1_release(&x) == 14);
+# else
+    MISSING(AO_fetch_and_sub1);
+    --x;
+# endif
+# if defined(AO_HAVE_short_store_release)
+    AO_short_store_release(&s, 13);
+# else
+    MISSING(AO_short_store);
+    s = 13;
+# endif
+# if defined(AO_HAVE_short_load_release)
+    TA_assert(AO_short_load(&s) == 13);
+# else
+    MISSING(AO_short_load);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add_release)
+    TA_assert(AO_short_fetch_and_add_release(&s, 42) == 13);
+    TA_assert(AO_short_fetch_and_add_release(&s, -42) == 55);
+# else
+    MISSING(AO_short_fetch_and_add);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add1_release)
+    TA_assert(AO_short_fetch_and_add1_release(&s) == 13);
+# else
+    MISSING(AO_short_fetch_and_add1);
+    ++s;
+# endif
+# if defined(AO_HAVE_short_fetch_and_sub1_release)
+    TA_assert(AO_short_fetch_and_sub1_release(&s) == 14);
+# else
+    MISSING(AO_short_fetch_and_sub1);
+    --s;
+# endif
+# if defined(AO_HAVE_char_store_release)
+    AO_char_store_release(&b, 13);
+# else
+    MISSING(AO_char_store);
+    b = 13;
+# endif
+# if defined(AO_HAVE_char_load_release)
+    TA_assert(AO_char_load(&b) == 13);
+# else
+    MISSING(AO_char_load);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add_release)
+    TA_assert(AO_char_fetch_and_add_release(&b, 42) == 13);
+    TA_assert(AO_char_fetch_and_add_release(&b, -42) == 55);
+# else
+    MISSING(AO_char_fetch_and_add);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add1_release)
+    TA_assert(AO_char_fetch_and_add1_release(&b) == 13);
+# else
+    MISSING(AO_char_fetch_and_add1);
+    ++b;
+# endif
+# if defined(AO_HAVE_char_fetch_and_sub1_release)
+    TA_assert(AO_char_fetch_and_sub1_release(&b) == 14);
+# else
+    MISSING(AO_char_fetch_and_sub1);
+    --b;
+# endif
+# if defined(AO_HAVE_int_store_release)
+    AO_int_store_release(&zz, 13);
+# else
+    MISSING(AO_int_store);
+    zz = 13;
+# endif
+# if defined(AO_HAVE_int_load_release)
+    TA_assert(AO_int_load(&zz) == 13);
+# else
+    MISSING(AO_int_load);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add_release)
+    TA_assert(AO_int_fetch_and_add_release(&zz, 42) == 13);
+    TA_assert(AO_int_fetch_and_add_release(&zz, -42) == 55);
+# else
+    MISSING(AO_int_fetch_and_add);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add1_release)
+    TA_assert(AO_int_fetch_and_add1_release(&zz) == 13);
+# else
+    MISSING(AO_int_fetch_and_add1);
+    ++zz;
+# endif
+# if defined(AO_HAVE_int_fetch_and_sub1_release)
+    TA_assert(AO_int_fetch_and_sub1_release(&zz) == 14);
+# else
+    MISSING(AO_int_fetch_and_sub1);
+    --zz;
+# endif
+# if defined(AO_HAVE_compare_and_swap_release)
+    TA_assert(!AO_compare_and_swap_release(&x, 14, 42));
+    TA_assert(x == 13);
+    TA_assert(AO_compare_and_swap_release(&x, 13, 42));
+    TA_assert(x == 42);
+# else
+    MISSING(AO_compare_and_swap);
+# endif
+# if defined(AO_HAVE_or_release)
+    AO_or_release(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
+# if defined(AO_HAVE_compare_double_and_swap_double_release)
+    TA_assert(!AO_compare_double_and_swap_double_release(&w, 17, 42, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_double_and_swap_double_release(&w, 0, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_double_and_swap_double_release(&w, 12, 13, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+    w.AO_val1 = 0; w.AO_val2 = 0;
+# else
+    MISSING(AO_compare_double_and_swap_double);
+# endif
+# if defined(AO_HAVE_compare_and_swap_double_release)
+    TA_assert(!AO_compare_and_swap_double_release(&w, 17, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_and_swap_double_release(&w, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_and_swap_double_release(&w, 12, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+# else
+    MISSING(AO_compare_and_swap_double);
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* Some basic sanity tests.  These do not test the barrier semantics. */
+
+#undef TA_assert
+#define TA_assert(e) \
+  if (!(e)) { fprintf(stderr, "Assertion failed %s:%d (barrier: _acquire)\n", \
+                   __FILE__, __LINE__), exit(1); }
+
+#undef MISSING
+#define MISSING(name) \
+  fprintf(stderr, "Missing: %s\n", #name "_acquire")
+
+void test_atomic_acquire(void)
+{
+  AO_t x;
+  unsigned char b;
+  unsigned short s;
+  unsigned int zz;
+# if defined(AO_HAVE_test_and_set_acquire)
+    AO_TS_t z = AO_TS_INITIALIZER;
+# endif
+# if defined(AO_HAVE_double_t)
+    AO_double_t w;
+    w.AO_val1 = 0;
+    w.AO_val2 = 0;
+# endif
+
+# if defined(AO_HAVE_nop_acquire)
+    AO_nop_acquire();
+# else
+    MISSING(AO_nop);
+# endif
+# if defined(AO_HAVE_store_acquire)
+    AO_store_acquire(&x, 13);
+    TA_assert (x == 13);
+# else
+    MISSING(AO_store);
+    x = 13;
+# endif
+# if defined(AO_HAVE_load_acquire)
+    TA_assert(AO_load_acquire(&x) == 13);
+# else
+    MISSING(AO_load);
+# endif
+# if defined(AO_HAVE_test_and_set_acquire)
+    assert(AO_test_and_set_acquire(&z) == AO_TS_CLEAR);
+    assert(AO_test_and_set_acquire(&z) == AO_TS_SET);
+    assert(AO_test_and_set_acquire(&z) == AO_TS_SET);
+    AO_CLEAR(&z);
+# else
+    MISSING(AO_test_and_set);
+# endif
+# if defined(AO_HAVE_fetch_and_add_acquire)
+    TA_assert(AO_fetch_and_add_acquire(&x, 42) == 13);
+    TA_assert(AO_fetch_and_add_acquire(&x, -42) == 55);
+# else
+    MISSING(AO_fetch_and_add);
+# endif
+# if defined(AO_HAVE_fetch_and_add1_acquire)
+    TA_assert(AO_fetch_and_add1_acquire(&x) == 13);
+# else
+    MISSING(AO_fetch_and_add1);
+    ++x;
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_acquire)
+    TA_assert(AO_fetch_and_sub1_acquire(&x) == 14);
+# else
+    MISSING(AO_fetch_and_sub1);
+    --x;
+# endif
+# if defined(AO_HAVE_short_store_acquire)
+    AO_short_store_acquire(&s, 13);
+# else
+    MISSING(AO_short_store);
+    s = 13;
+# endif
+# if defined(AO_HAVE_short_load_acquire)
+    TA_assert(AO_short_load(&s) == 13);
+# else
+    MISSING(AO_short_load);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add_acquire)
+    TA_assert(AO_short_fetch_and_add_acquire(&s, 42) == 13);
+    TA_assert(AO_short_fetch_and_add_acquire(&s, -42) == 55);
+# else
+    MISSING(AO_short_fetch_and_add);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add1_acquire)
+    TA_assert(AO_short_fetch_and_add1_acquire(&s) == 13);
+# else
+    MISSING(AO_short_fetch_and_add1);
+    ++s;
+# endif
+# if defined(AO_HAVE_short_fetch_and_sub1_acquire)
+    TA_assert(AO_short_fetch_and_sub1_acquire(&s) == 14);
+# else
+    MISSING(AO_short_fetch_and_sub1);
+    --s;
+# endif
+# if defined(AO_HAVE_char_store_acquire)
+    AO_char_store_acquire(&b, 13);
+# else
+    MISSING(AO_char_store);
+    b = 13;
+# endif
+# if defined(AO_HAVE_char_load_acquire)
+    TA_assert(AO_char_load(&b) == 13);
+# else
+    MISSING(AO_char_load);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add_acquire)
+    TA_assert(AO_char_fetch_and_add_acquire(&b, 42) == 13);
+    TA_assert(AO_char_fetch_and_add_acquire(&b, -42) == 55);
+# else
+    MISSING(AO_char_fetch_and_add);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add1_acquire)
+    TA_assert(AO_char_fetch_and_add1_acquire(&b) == 13);
+# else
+    MISSING(AO_char_fetch_and_add1);
+    ++b;
+# endif
+# if defined(AO_HAVE_char_fetch_and_sub1_acquire)
+    TA_assert(AO_char_fetch_and_sub1_acquire(&b) == 14);
+# else
+    MISSING(AO_char_fetch_and_sub1);
+    --b;
+# endif
+# if defined(AO_HAVE_int_store_acquire)
+    AO_int_store_acquire(&zz, 13);
+# else
+    MISSING(AO_int_store);
+    zz = 13;
+# endif
+# if defined(AO_HAVE_int_load_acquire)
+    TA_assert(AO_int_load(&zz) == 13);
+# else
+    MISSING(AO_int_load);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add_acquire)
+    TA_assert(AO_int_fetch_and_add_acquire(&zz, 42) == 13);
+    TA_assert(AO_int_fetch_and_add_acquire(&zz, -42) == 55);
+# else
+    MISSING(AO_int_fetch_and_add);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add1_acquire)
+    TA_assert(AO_int_fetch_and_add1_acquire(&zz) == 13);
+# else
+    MISSING(AO_int_fetch_and_add1);
+    ++zz;
+# endif
+# if defined(AO_HAVE_int_fetch_and_sub1_acquire)
+    TA_assert(AO_int_fetch_and_sub1_acquire(&zz) == 14);
+# else
+    MISSING(AO_int_fetch_and_sub1);
+    --zz;
+# endif
+# if defined(AO_HAVE_compare_and_swap_acquire)
+    TA_assert(!AO_compare_and_swap_acquire(&x, 14, 42));
+    TA_assert(x == 13);
+    TA_assert(AO_compare_and_swap_acquire(&x, 13, 42));
+    TA_assert(x == 42);
+# else
+    MISSING(AO_compare_and_swap);
+# endif
+# if defined(AO_HAVE_or_acquire)
+    AO_or_acquire(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
+# if defined(AO_HAVE_compare_double_and_swap_double_acquire)
+    TA_assert(!AO_compare_double_and_swap_double_acquire(&w, 17, 42, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_double_and_swap_double_acquire(&w, 0, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_double_and_swap_double_acquire(&w, 12, 13, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+    w.AO_val1 = 0; w.AO_val2 = 0;
+# else
+    MISSING(AO_compare_double_and_swap_double);
+# endif
+# if defined(AO_HAVE_compare_and_swap_double_acquire)
+    TA_assert(!AO_compare_and_swap_double_acquire(&w, 17, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_and_swap_double_acquire(&w, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_and_swap_double_acquire(&w, 12, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+# else
+    MISSING(AO_compare_and_swap_double);
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* Some basic sanity tests.  These do not test the barrier semantics. */
+
+#undef TA_assert
+#define TA_assert(e) \
+  if (!(e)) { fprintf(stderr, "Assertion failed %s:%d (barrier: _read)\n", \
+                   __FILE__, __LINE__), exit(1); }
+
+#undef MISSING
+#define MISSING(name) \
+  fprintf(stderr, "Missing: %s\n", #name "_read")
+
+void test_atomic_read(void)
+{
+  AO_t x;
+  unsigned char b;
+  unsigned short s;
+  unsigned int zz;
+# if defined(AO_HAVE_test_and_set_read)
+    AO_TS_t z = AO_TS_INITIALIZER;
+# endif
+# if defined(AO_HAVE_double_t)
+    AO_double_t w;
+    w.AO_val1 = 0;
+    w.AO_val2 = 0;
+# endif
+
+# if defined(AO_HAVE_nop_read)
+    AO_nop_read();
+# else
+    MISSING(AO_nop);
+# endif
+# if defined(AO_HAVE_store_read)
+    AO_store_read(&x, 13);
+    TA_assert (x == 13);
+# else
+    MISSING(AO_store);
+    x = 13;
+# endif
+# if defined(AO_HAVE_load_read)
+    TA_assert(AO_load_read(&x) == 13);
+# else
+    MISSING(AO_load);
+# endif
+# if defined(AO_HAVE_test_and_set_read)
+    assert(AO_test_and_set_read(&z) == AO_TS_CLEAR);
+    assert(AO_test_and_set_read(&z) == AO_TS_SET);
+    assert(AO_test_and_set_read(&z) == AO_TS_SET);
+    AO_CLEAR(&z);
+# else
+    MISSING(AO_test_and_set);
+# endif
+# if defined(AO_HAVE_fetch_and_add_read)
+    TA_assert(AO_fetch_and_add_read(&x, 42) == 13);
+    TA_assert(AO_fetch_and_add_read(&x, -42) == 55);
+# else
+    MISSING(AO_fetch_and_add);
+# endif
+# if defined(AO_HAVE_fetch_and_add1_read)
+    TA_assert(AO_fetch_and_add1_read(&x) == 13);
+# else
+    MISSING(AO_fetch_and_add1);
+    ++x;
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_read)
+    TA_assert(AO_fetch_and_sub1_read(&x) == 14);
+# else
+    MISSING(AO_fetch_and_sub1);
+    --x;
+# endif
+# if defined(AO_HAVE_short_store_read)
+    AO_short_store_read(&s, 13);
+# else
+    MISSING(AO_short_store);
+    s = 13;
+# endif
+# if defined(AO_HAVE_short_load_read)
+    TA_assert(AO_short_load(&s) == 13);
+# else
+    MISSING(AO_short_load);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add_read)
+    TA_assert(AO_short_fetch_and_add_read(&s, 42) == 13);
+    TA_assert(AO_short_fetch_and_add_read(&s, -42) == 55);
+# else
+    MISSING(AO_short_fetch_and_add);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add1_read)
+    TA_assert(AO_short_fetch_and_add1_read(&s) == 13);
+# else
+    MISSING(AO_short_fetch_and_add1);
+    ++s;
+# endif
+# if defined(AO_HAVE_short_fetch_and_sub1_read)
+    TA_assert(AO_short_fetch_and_sub1_read(&s) == 14);
+# else
+    MISSING(AO_short_fetch_and_sub1);
+    --s;
+# endif
+# if defined(AO_HAVE_char_store_read)
+    AO_char_store_read(&b, 13);
+# else
+    MISSING(AO_char_store);
+    b = 13;
+# endif
+# if defined(AO_HAVE_char_load_read)
+    TA_assert(AO_char_load(&b) == 13);
+# else
+    MISSING(AO_char_load);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add_read)
+    TA_assert(AO_char_fetch_and_add_read(&b, 42) == 13);
+    TA_assert(AO_char_fetch_and_add_read(&b, -42) == 55);
+# else
+    MISSING(AO_char_fetch_and_add);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add1_read)
+    TA_assert(AO_char_fetch_and_add1_read(&b) == 13);
+# else
+    MISSING(AO_char_fetch_and_add1);
+    ++b;
+# endif
+# if defined(AO_HAVE_char_fetch_and_sub1_read)
+    TA_assert(AO_char_fetch_and_sub1_read(&b) == 14);
+# else
+    MISSING(AO_char_fetch_and_sub1);
+    --b;
+# endif
+# if defined(AO_HAVE_int_store_read)
+    AO_int_store_read(&zz, 13);
+# else
+    MISSING(AO_int_store);
+    zz = 13;
+# endif
+# if defined(AO_HAVE_int_load_read)
+    TA_assert(AO_int_load(&zz) == 13);
+# else
+    MISSING(AO_int_load);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add_read)
+    TA_assert(AO_int_fetch_and_add_read(&zz, 42) == 13);
+    TA_assert(AO_int_fetch_and_add_read(&zz, -42) == 55);
+# else
+    MISSING(AO_int_fetch_and_add);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add1_read)
+    TA_assert(AO_int_fetch_and_add1_read(&zz) == 13);
+# else
+    MISSING(AO_int_fetch_and_add1);
+    ++zz;
+# endif
+# if defined(AO_HAVE_int_fetch_and_sub1_read)
+    TA_assert(AO_int_fetch_and_sub1_read(&zz) == 14);
+# else
+    MISSING(AO_int_fetch_and_sub1);
+    --zz;
+# endif
+# if defined(AO_HAVE_compare_and_swap_read)
+    TA_assert(!AO_compare_and_swap_read(&x, 14, 42));
+    TA_assert(x == 13);
+    TA_assert(AO_compare_and_swap_read(&x, 13, 42));
+    TA_assert(x == 42);
+# else
+    MISSING(AO_compare_and_swap);
+# endif
+# if defined(AO_HAVE_or_read)
+    AO_or_read(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
+# if defined(AO_HAVE_compare_double_and_swap_double_read)
+    TA_assert(!AO_compare_double_and_swap_double_read(&w, 17, 42, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_double_and_swap_double_read(&w, 0, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_double_and_swap_double_read(&w, 12, 13, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+    w.AO_val1 = 0; w.AO_val2 = 0;
+# else
+    MISSING(AO_compare_double_and_swap_double);
+# endif
+# if defined(AO_HAVE_compare_and_swap_double_read)
+    TA_assert(!AO_compare_and_swap_double_read(&w, 17, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_and_swap_double_read(&w, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_and_swap_double_read(&w, 12, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+# else
+    MISSING(AO_compare_and_swap_double);
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* Some basic sanity tests.  These do not test the barrier semantics. */
+
+#undef TA_assert
+#define TA_assert(e) \
+  if (!(e)) { fprintf(stderr, "Assertion failed %s:%d (barrier: _write)\n", \
+                   __FILE__, __LINE__), exit(1); }
+
+#undef MISSING
+#define MISSING(name) \
+  fprintf(stderr, "Missing: %s\n", #name "_write")
+
+void test_atomic_write(void)
+{
+  AO_t x;
+  unsigned char b;
+  unsigned short s;
+  unsigned int zz;
+# if defined(AO_HAVE_test_and_set_write)
+    AO_TS_t z = AO_TS_INITIALIZER;
+# endif
+# if defined(AO_HAVE_double_t)
+    AO_double_t w;
+    w.AO_val1 = 0;
+    w.AO_val2 = 0;
+# endif
+
+# if defined(AO_HAVE_nop_write)
+    AO_nop_write();
+# else
+    MISSING(AO_nop);
+# endif
+# if defined(AO_HAVE_store_write)
+    AO_store_write(&x, 13);
+    TA_assert (x == 13);
+# else
+    MISSING(AO_store);
+    x = 13;
+# endif
+# if defined(AO_HAVE_load_write)
+    TA_assert(AO_load_write(&x) == 13);
+# else
+    MISSING(AO_load);
+# endif
+# if defined(AO_HAVE_test_and_set_write)
+    assert(AO_test_and_set_write(&z) == AO_TS_CLEAR);
+    assert(AO_test_and_set_write(&z) == AO_TS_SET);
+    assert(AO_test_and_set_write(&z) == AO_TS_SET);
+    AO_CLEAR(&z);
+# else
+    MISSING(AO_test_and_set);
+# endif
+# if defined(AO_HAVE_fetch_and_add_write)
+    TA_assert(AO_fetch_and_add_write(&x, 42) == 13);
+    TA_assert(AO_fetch_and_add_write(&x, -42) == 55);
+# else
+    MISSING(AO_fetch_and_add);
+# endif
+# if defined(AO_HAVE_fetch_and_add1_write)
+    TA_assert(AO_fetch_and_add1_write(&x) == 13);
+# else
+    MISSING(AO_fetch_and_add1);
+    ++x;
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_write)
+    TA_assert(AO_fetch_and_sub1_write(&x) == 14);
+# else
+    MISSING(AO_fetch_and_sub1);
+    --x;
+# endif
+# if defined(AO_HAVE_short_store_write)
+    AO_short_store_write(&s, 13);
+# else
+    MISSING(AO_short_store);
+    s = 13;
+# endif
+# if defined(AO_HAVE_short_load_write)
+    TA_assert(AO_short_load(&s) == 13);
+# else
+    MISSING(AO_short_load);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add_write)
+    TA_assert(AO_short_fetch_and_add_write(&s, 42) == 13);
+    TA_assert(AO_short_fetch_and_add_write(&s, -42) == 55);
+# else
+    MISSING(AO_short_fetch_and_add);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add1_write)
+    TA_assert(AO_short_fetch_and_add1_write(&s) == 13);
+# else
+    MISSING(AO_short_fetch_and_add1);
+    ++s;
+# endif
+# if defined(AO_HAVE_short_fetch_and_sub1_write)
+    TA_assert(AO_short_fetch_and_sub1_write(&s) == 14);
+# else
+    MISSING(AO_short_fetch_and_sub1);
+    --s;
+# endif
+# if defined(AO_HAVE_char_store_write)
+    AO_char_store_write(&b, 13);
+# else
+    MISSING(AO_char_store);
+    b = 13;
+# endif
+# if defined(AO_HAVE_char_load_write)
+    TA_assert(AO_char_load(&b) == 13);
+# else
+    MISSING(AO_char_load);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add_write)
+    TA_assert(AO_char_fetch_and_add_write(&b, 42) == 13);
+    TA_assert(AO_char_fetch_and_add_write(&b, -42) == 55);
+# else
+    MISSING(AO_char_fetch_and_add);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add1_write)
+    TA_assert(AO_char_fetch_and_add1_write(&b) == 13);
+# else
+    MISSING(AO_char_fetch_and_add1);
+    ++b;
+# endif
+# if defined(AO_HAVE_char_fetch_and_sub1_write)
+    TA_assert(AO_char_fetch_and_sub1_write(&b) == 14);
+# else
+    MISSING(AO_char_fetch_and_sub1);
+    --b;
+# endif
+# if defined(AO_HAVE_int_store_write)
+    AO_int_store_write(&zz, 13);
+# else
+    MISSING(AO_int_store);
+    zz = 13;
+# endif
+# if defined(AO_HAVE_int_load_write)
+    TA_assert(AO_int_load(&zz) == 13);
+# else
+    MISSING(AO_int_load);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add_write)
+    TA_assert(AO_int_fetch_and_add_write(&zz, 42) == 13);
+    TA_assert(AO_int_fetch_and_add_write(&zz, -42) == 55);
+# else
+    MISSING(AO_int_fetch_and_add);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add1_write)
+    TA_assert(AO_int_fetch_and_add1_write(&zz) == 13);
+# else
+    MISSING(AO_int_fetch_and_add1);
+    ++zz;
+# endif
+# if defined(AO_HAVE_int_fetch_and_sub1_write)
+    TA_assert(AO_int_fetch_and_sub1_write(&zz) == 14);
+# else
+    MISSING(AO_int_fetch_and_sub1);
+    --zz;
+# endif
+# if defined(AO_HAVE_compare_and_swap_write)
+    TA_assert(!AO_compare_and_swap_write(&x, 14, 42));
+    TA_assert(x == 13);
+    TA_assert(AO_compare_and_swap_write(&x, 13, 42));
+    TA_assert(x == 42);
+# else
+    MISSING(AO_compare_and_swap);
+# endif
+# if defined(AO_HAVE_or_write)
+    AO_or_write(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
+# if defined(AO_HAVE_compare_double_and_swap_double_write)
+    TA_assert(!AO_compare_double_and_swap_double_write(&w, 17, 42, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_double_and_swap_double_write(&w, 0, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_double_and_swap_double_write(&w, 12, 13, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+    w.AO_val1 = 0; w.AO_val2 = 0;
+# else
+    MISSING(AO_compare_double_and_swap_double);
+# endif
+# if defined(AO_HAVE_compare_and_swap_double_write)
+    TA_assert(!AO_compare_and_swap_double_write(&w, 17, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_and_swap_double_write(&w, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_and_swap_double_write(&w, 12, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+# else
+    MISSING(AO_compare_and_swap_double);
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* Some basic sanity tests.  These do not test the barrier semantics. */
+
+#undef TA_assert
+#define TA_assert(e) \
+  if (!(e)) { fprintf(stderr, "Assertion failed %s:%d (barrier: _full)\n", \
+                   __FILE__, __LINE__), exit(1); }
+
+#undef MISSING
+#define MISSING(name) \
+  fprintf(stderr, "Missing: %s\n", #name "_full")
+
+void test_atomic_full(void)
+{
+  AO_t x;
+  unsigned char b;
+  unsigned short s;
+  unsigned int zz;
+# if defined(AO_HAVE_test_and_set_full)
+    AO_TS_t z = AO_TS_INITIALIZER;
+# endif
+# if defined(AO_HAVE_double_t)
+    AO_double_t w;
+    w.AO_val1 = 0;
+    w.AO_val2 = 0;
+# endif
+
+# if defined(AO_HAVE_nop_full)
+    AO_nop_full();
+# else
+    MISSING(AO_nop);
+# endif
+# if defined(AO_HAVE_store_full)
+    AO_store_full(&x, 13);
+    TA_assert (x == 13);
+# else
+    MISSING(AO_store);
+    x = 13;
+# endif
+# if defined(AO_HAVE_load_full)
+    TA_assert(AO_load_full(&x) == 13);
+# else
+    MISSING(AO_load);
+# endif
+# if defined(AO_HAVE_test_and_set_full)
+    assert(AO_test_and_set_full(&z) == AO_TS_CLEAR);
+    assert(AO_test_and_set_full(&z) == AO_TS_SET);
+    assert(AO_test_and_set_full(&z) == AO_TS_SET);
+    AO_CLEAR(&z);
+# else
+    MISSING(AO_test_and_set);
+# endif
+# if defined(AO_HAVE_fetch_and_add_full)
+    TA_assert(AO_fetch_and_add_full(&x, 42) == 13);
+    TA_assert(AO_fetch_and_add_full(&x, -42) == 55);
+# else
+    MISSING(AO_fetch_and_add);
+# endif
+# if defined(AO_HAVE_fetch_and_add1_full)
+    TA_assert(AO_fetch_and_add1_full(&x) == 13);
+# else
+    MISSING(AO_fetch_and_add1);
+    ++x;
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_full)
+    TA_assert(AO_fetch_and_sub1_full(&x) == 14);
+# else
+    MISSING(AO_fetch_and_sub1);
+    --x;
+# endif
+# if defined(AO_HAVE_short_store_full)
+    AO_short_store_full(&s, 13);
+# else
+    MISSING(AO_short_store);
+    s = 13;
+# endif
+# if defined(AO_HAVE_short_load_full)
+    TA_assert(AO_short_load(&s) == 13);
+# else
+    MISSING(AO_short_load);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add_full)
+    TA_assert(AO_short_fetch_and_add_full(&s, 42) == 13);
+    TA_assert(AO_short_fetch_and_add_full(&s, -42) == 55);
+# else
+    MISSING(AO_short_fetch_and_add);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add1_full)
+    TA_assert(AO_short_fetch_and_add1_full(&s) == 13);
+# else
+    MISSING(AO_short_fetch_and_add1);
+    ++s;
+# endif
+# if defined(AO_HAVE_short_fetch_and_sub1_full)
+    TA_assert(AO_short_fetch_and_sub1_full(&s) == 14);
+# else
+    MISSING(AO_short_fetch_and_sub1);
+    --s;
+# endif
+# if defined(AO_HAVE_char_store_full)
+    AO_char_store_full(&b, 13);
+# else
+    MISSING(AO_char_store);
+    b = 13;
+# endif
+# if defined(AO_HAVE_char_load_full)
+    TA_assert(AO_char_load(&b) == 13);
+# else
+    MISSING(AO_char_load);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add_full)
+    TA_assert(AO_char_fetch_and_add_full(&b, 42) == 13);
+    TA_assert(AO_char_fetch_and_add_full(&b, -42) == 55);
+# else
+    MISSING(AO_char_fetch_and_add);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add1_full)
+    TA_assert(AO_char_fetch_and_add1_full(&b) == 13);
+# else
+    MISSING(AO_char_fetch_and_add1);
+    ++b;
+# endif
+# if defined(AO_HAVE_char_fetch_and_sub1_full)
+    TA_assert(AO_char_fetch_and_sub1_full(&b) == 14);
+# else
+    MISSING(AO_char_fetch_and_sub1);
+    --b;
+# endif
+# if defined(AO_HAVE_int_store_full)
+    AO_int_store_full(&zz, 13);
+# else
+    MISSING(AO_int_store);
+    zz = 13;
+# endif
+# if defined(AO_HAVE_int_load_full)
+    TA_assert(AO_int_load(&zz) == 13);
+# else
+    MISSING(AO_int_load);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add_full)
+    TA_assert(AO_int_fetch_and_add_full(&zz, 42) == 13);
+    TA_assert(AO_int_fetch_and_add_full(&zz, -42) == 55);
+# else
+    MISSING(AO_int_fetch_and_add);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add1_full)
+    TA_assert(AO_int_fetch_and_add1_full(&zz) == 13);
+# else
+    MISSING(AO_int_fetch_and_add1);
+    ++zz;
+# endif
+# if defined(AO_HAVE_int_fetch_and_sub1_full)
+    TA_assert(AO_int_fetch_and_sub1_full(&zz) == 14);
+# else
+    MISSING(AO_int_fetch_and_sub1);
+    --zz;
+# endif
+# if defined(AO_HAVE_compare_and_swap_full)
+    TA_assert(!AO_compare_and_swap_full(&x, 14, 42));
+    TA_assert(x == 13);
+    TA_assert(AO_compare_and_swap_full(&x, 13, 42));
+    TA_assert(x == 42);
+# else
+    MISSING(AO_compare_and_swap);
+# endif
+# if defined(AO_HAVE_or_full)
+    AO_or_full(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
+# if defined(AO_HAVE_compare_double_and_swap_double_full)
+    TA_assert(!AO_compare_double_and_swap_double_full(&w, 17, 42, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_double_and_swap_double_full(&w, 0, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_double_and_swap_double_full(&w, 12, 13, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+    w.AO_val1 = 0; w.AO_val2 = 0;
+# else
+    MISSING(AO_compare_double_and_swap_double);
+# endif
+# if defined(AO_HAVE_compare_and_swap_double_full)
+    TA_assert(!AO_compare_and_swap_double_full(&w, 17, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_and_swap_double_full(&w, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_and_swap_double_full(&w, 12, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+# else
+    MISSING(AO_compare_and_swap_double);
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* Some basic sanity tests.  These do not test the barrier semantics. */
+
+#undef TA_assert
+#define TA_assert(e) \
+  if (!(e)) { fprintf(stderr, "Assertion failed %s:%d (barrier: _release_write)\n", \
+                   __FILE__, __LINE__), exit(1); }
+
+#undef MISSING
+#define MISSING(name) \
+  fprintf(stderr, "Missing: %s\n", #name "_release_write")
+
+void test_atomic_release_write(void)
+{
+  AO_t x;
+  unsigned char b;
+  unsigned short s;
+  unsigned int zz;
+# if defined(AO_HAVE_test_and_set_release_write)
+    AO_TS_t z = AO_TS_INITIALIZER;
+# endif
+# if defined(AO_HAVE_double_t)
+    AO_double_t w;
+    w.AO_val1 = 0;
+    w.AO_val2 = 0;
+# endif
+
+# if defined(AO_HAVE_nop_release_write)
+    AO_nop_release_write();
+# else
+    MISSING(AO_nop);
+# endif
+# if defined(AO_HAVE_store_release_write)
+    AO_store_release_write(&x, 13);
+    TA_assert (x == 13);
+# else
+    MISSING(AO_store);
+    x = 13;
+# endif
+# if defined(AO_HAVE_load_release_write)
+    TA_assert(AO_load_release_write(&x) == 13);
+# else
+    MISSING(AO_load);
+# endif
+# if defined(AO_HAVE_test_and_set_release_write)
+    assert(AO_test_and_set_release_write(&z) == AO_TS_CLEAR);
+    assert(AO_test_and_set_release_write(&z) == AO_TS_SET);
+    assert(AO_test_and_set_release_write(&z) == AO_TS_SET);
+    AO_CLEAR(&z);
+# else
+    MISSING(AO_test_and_set);
+# endif
+# if defined(AO_HAVE_fetch_and_add_release_write)
+    TA_assert(AO_fetch_and_add_release_write(&x, 42) == 13);
+    TA_assert(AO_fetch_and_add_release_write(&x, -42) == 55);
+# else
+    MISSING(AO_fetch_and_add);
+# endif
+# if defined(AO_HAVE_fetch_and_add1_release_write)
+    TA_assert(AO_fetch_and_add1_release_write(&x) == 13);
+# else
+    MISSING(AO_fetch_and_add1);
+    ++x;
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_release_write)
+    TA_assert(AO_fetch_and_sub1_release_write(&x) == 14);
+# else
+    MISSING(AO_fetch_and_sub1);
+    --x;
+# endif
+# if defined(AO_HAVE_short_store_release_write)
+    AO_short_store_release_write(&s, 13);
+# else
+    MISSING(AO_short_store);
+    s = 13;
+# endif
+# if defined(AO_HAVE_short_load_release_write)
+    TA_assert(AO_short_load(&s) == 13);
+# else
+    MISSING(AO_short_load);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add_release_write)
+    TA_assert(AO_short_fetch_and_add_release_write(&s, 42) == 13);
+    TA_assert(AO_short_fetch_and_add_release_write(&s, -42) == 55);
+# else
+    MISSING(AO_short_fetch_and_add);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add1_release_write)
+    TA_assert(AO_short_fetch_and_add1_release_write(&s) == 13);
+# else
+    MISSING(AO_short_fetch_and_add1);
+    ++s;
+# endif
+# if defined(AO_HAVE_short_fetch_and_sub1_release_write)
+    TA_assert(AO_short_fetch_and_sub1_release_write(&s) == 14);
+# else
+    MISSING(AO_short_fetch_and_sub1);
+    --s;
+# endif
+# if defined(AO_HAVE_char_store_release_write)
+    AO_char_store_release_write(&b, 13);
+# else
+    MISSING(AO_char_store);
+    b = 13;
+# endif
+# if defined(AO_HAVE_char_load_release_write)
+    TA_assert(AO_char_load(&b) == 13);
+# else
+    MISSING(AO_char_load);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add_release_write)
+    TA_assert(AO_char_fetch_and_add_release_write(&b, 42) == 13);
+    TA_assert(AO_char_fetch_and_add_release_write(&b, -42) == 55);
+# else
+    MISSING(AO_char_fetch_and_add);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add1_release_write)
+    TA_assert(AO_char_fetch_and_add1_release_write(&b) == 13);
+# else
+    MISSING(AO_char_fetch_and_add1);
+    ++b;
+# endif
+# if defined(AO_HAVE_char_fetch_and_sub1_release_write)
+    TA_assert(AO_char_fetch_and_sub1_release_write(&b) == 14);
+# else
+    MISSING(AO_char_fetch_and_sub1);
+    --b;
+# endif
+# if defined(AO_HAVE_int_store_release_write)
+    AO_int_store_release_write(&zz, 13);
+# else
+    MISSING(AO_int_store);
+    zz = 13;
+# endif
+# if defined(AO_HAVE_int_load_release_write)
+    TA_assert(AO_int_load(&zz) == 13);
+# else
+    MISSING(AO_int_load);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add_release_write)
+    TA_assert(AO_int_fetch_and_add_release_write(&zz, 42) == 13);
+    TA_assert(AO_int_fetch_and_add_release_write(&zz, -42) == 55);
+# else
+    MISSING(AO_int_fetch_and_add);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add1_release_write)
+    TA_assert(AO_int_fetch_and_add1_release_write(&zz) == 13);
+# else
+    MISSING(AO_int_fetch_and_add1);
+    ++zz;
+# endif
+# if defined(AO_HAVE_int_fetch_and_sub1_release_write)
+    TA_assert(AO_int_fetch_and_sub1_release_write(&zz) == 14);
+# else
+    MISSING(AO_int_fetch_and_sub1);
+    --zz;
+# endif
+# if defined(AO_HAVE_compare_and_swap_release_write)
+    TA_assert(!AO_compare_and_swap_release_write(&x, 14, 42));
+    TA_assert(x == 13);
+    TA_assert(AO_compare_and_swap_release_write(&x, 13, 42));
+    TA_assert(x == 42);
+# else
+    MISSING(AO_compare_and_swap);
+# endif
+# if defined(AO_HAVE_or_release_write)
+    AO_or_release_write(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
+# if defined(AO_HAVE_compare_double_and_swap_double_release_write)
+    TA_assert(!AO_compare_double_and_swap_double_release_write(&w, 17, 42, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_double_and_swap_double_release_write(&w, 0, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_double_and_swap_double_release_write(&w, 12, 13, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+    w.AO_val1 = 0; w.AO_val2 = 0;
+# else
+    MISSING(AO_compare_double_and_swap_double);
+# endif
+# if defined(AO_HAVE_compare_and_swap_double_release_write)
+    TA_assert(!AO_compare_and_swap_double_release_write(&w, 17, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_and_swap_double_release_write(&w, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_and_swap_double_release_write(&w, 12, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+# else
+    MISSING(AO_compare_and_swap_double);
+# endif
+}
+
+
+    
+/*
+ * Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+ *
+ * This file is covered by the GNU general public license, version 2.
+ * see doc/COPYING for details.
+ */
+
+/* Some basic sanity tests.  These do not test the barrier semantics. */
+
+#undef TA_assert
+#define TA_assert(e) \
+  if (!(e)) { fprintf(stderr, "Assertion failed %s:%d (barrier: _acquire_read)\n", \
+                   __FILE__, __LINE__), exit(1); }
+
+#undef MISSING
+#define MISSING(name) \
+  fprintf(stderr, "Missing: %s\n", #name "_acquire_read")
+
+void test_atomic_acquire_read(void)
+{
+  AO_t x;
+  unsigned char b;
+  unsigned short s;
+  unsigned int zz;
+# if defined(AO_HAVE_test_and_set_acquire_read)
+    AO_TS_t z = AO_TS_INITIALIZER;
+# endif
+# if defined(AO_HAVE_double_t)
+    AO_double_t w;
+    w.AO_val1 = 0;
+    w.AO_val2 = 0;
+# endif
+
+# if defined(AO_HAVE_nop_acquire_read)
+    AO_nop_acquire_read();
+# else
+    MISSING(AO_nop);
+# endif
+# if defined(AO_HAVE_store_acquire_read)
+    AO_store_acquire_read(&x, 13);
+    TA_assert (x == 13);
+# else
+    MISSING(AO_store);
+    x = 13;
+# endif
+# if defined(AO_HAVE_load_acquire_read)
+    TA_assert(AO_load_acquire_read(&x) == 13);
+# else
+    MISSING(AO_load);
+# endif
+# if defined(AO_HAVE_test_and_set_acquire_read)
+    assert(AO_test_and_set_acquire_read(&z) == AO_TS_CLEAR);
+    assert(AO_test_and_set_acquire_read(&z) == AO_TS_SET);
+    assert(AO_test_and_set_acquire_read(&z) == AO_TS_SET);
+    AO_CLEAR(&z);
+# else
+    MISSING(AO_test_and_set);
+# endif
+# if defined(AO_HAVE_fetch_and_add_acquire_read)
+    TA_assert(AO_fetch_and_add_acquire_read(&x, 42) == 13);
+    TA_assert(AO_fetch_and_add_acquire_read(&x, -42) == 55);
+# else
+    MISSING(AO_fetch_and_add);
+# endif
+# if defined(AO_HAVE_fetch_and_add1_acquire_read)
+    TA_assert(AO_fetch_and_add1_acquire_read(&x) == 13);
+# else
+    MISSING(AO_fetch_and_add1);
+    ++x;
+# endif
+# if defined(AO_HAVE_fetch_and_sub1_acquire_read)
+    TA_assert(AO_fetch_and_sub1_acquire_read(&x) == 14);
+# else
+    MISSING(AO_fetch_and_sub1);
+    --x;
+# endif
+# if defined(AO_HAVE_short_store_acquire_read)
+    AO_short_store_acquire_read(&s, 13);
+# else
+    MISSING(AO_short_store);
+    s = 13;
+# endif
+# if defined(AO_HAVE_short_load_acquire_read)
+    TA_assert(AO_short_load(&s) == 13);
+# else
+    MISSING(AO_short_load);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add_acquire_read)
+    TA_assert(AO_short_fetch_and_add_acquire_read(&s, 42) == 13);
+    TA_assert(AO_short_fetch_and_add_acquire_read(&s, -42) == 55);
+# else
+    MISSING(AO_short_fetch_and_add);
+# endif
+# if defined(AO_HAVE_short_fetch_and_add1_acquire_read)
+    TA_assert(AO_short_fetch_and_add1_acquire_read(&s) == 13);
+# else
+    MISSING(AO_short_fetch_and_add1);
+    ++s;
+# endif
+# if defined(AO_HAVE_short_fetch_and_sub1_acquire_read)
+    TA_assert(AO_short_fetch_and_sub1_acquire_read(&s) == 14);
+# else
+    MISSING(AO_short_fetch_and_sub1);
+    --s;
+# endif
+# if defined(AO_HAVE_char_store_acquire_read)
+    AO_char_store_acquire_read(&b, 13);
+# else
+    MISSING(AO_char_store);
+    b = 13;
+# endif
+# if defined(AO_HAVE_char_load_acquire_read)
+    TA_assert(AO_char_load(&b) == 13);
+# else
+    MISSING(AO_char_load);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add_acquire_read)
+    TA_assert(AO_char_fetch_and_add_acquire_read(&b, 42) == 13);
+    TA_assert(AO_char_fetch_and_add_acquire_read(&b, -42) == 55);
+# else
+    MISSING(AO_char_fetch_and_add);
+# endif
+# if defined(AO_HAVE_char_fetch_and_add1_acquire_read)
+    TA_assert(AO_char_fetch_and_add1_acquire_read(&b) == 13);
+# else
+    MISSING(AO_char_fetch_and_add1);
+    ++b;
+# endif
+# if defined(AO_HAVE_char_fetch_and_sub1_acquire_read)
+    TA_assert(AO_char_fetch_and_sub1_acquire_read(&b) == 14);
+# else
+    MISSING(AO_char_fetch_and_sub1);
+    --b;
+# endif
+# if defined(AO_HAVE_int_store_acquire_read)
+    AO_int_store_acquire_read(&zz, 13);
+# else
+    MISSING(AO_int_store);
+    zz = 13;
+# endif
+# if defined(AO_HAVE_int_load_acquire_read)
+    TA_assert(AO_int_load(&zz) == 13);
+# else
+    MISSING(AO_int_load);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add_acquire_read)
+    TA_assert(AO_int_fetch_and_add_acquire_read(&zz, 42) == 13);
+    TA_assert(AO_int_fetch_and_add_acquire_read(&zz, -42) == 55);
+# else
+    MISSING(AO_int_fetch_and_add);
+# endif
+# if defined(AO_HAVE_int_fetch_and_add1_acquire_read)
+    TA_assert(AO_int_fetch_and_add1_acquire_read(&zz) == 13);
+# else
+    MISSING(AO_int_fetch_and_add1);
+    ++zz;
+# endif
+# if defined(AO_HAVE_int_fetch_and_sub1_acquire_read)
+    TA_assert(AO_int_fetch_and_sub1_acquire_read(&zz) == 14);
+# else
+    MISSING(AO_int_fetch_and_sub1);
+    --zz;
+# endif
+# if defined(AO_HAVE_compare_and_swap_acquire_read)
+    TA_assert(!AO_compare_and_swap_acquire_read(&x, 14, 42));
+    TA_assert(x == 13);
+    TA_assert(AO_compare_and_swap_acquire_read(&x, 13, 42));
+    TA_assert(x == 42);
+# else
+    MISSING(AO_compare_and_swap);
+# endif
+# if defined(AO_HAVE_or_acquire_read)
+    AO_or_acquire_read(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
+# if defined(AO_HAVE_compare_double_and_swap_double_acquire_read)
+    TA_assert(!AO_compare_double_and_swap_double_acquire_read(&w, 17, 42, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_double_and_swap_double_acquire_read(&w, 0, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_double_and_swap_double_acquire_read(&w, 12, 13, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+    w.AO_val1 = 0; w.AO_val2 = 0;
+# else
+    MISSING(AO_compare_double_and_swap_double);
+# endif
+# if defined(AO_HAVE_compare_and_swap_double_acquire_read)
+    TA_assert(!AO_compare_and_swap_double_acquire_read(&w, 17, 12, 13));
+    TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
+    TA_assert(AO_compare_and_swap_double_acquire_read(&w, 0, 12, 13));
+    TA_assert(w.AO_val1 == 12 && w.AO_val2 == 13);
+    TA_assert(AO_compare_and_swap_double_acquire_read(&w, 12, 17, 42));
+    TA_assert(w.AO_val1 == 17 && w.AO_val2 == 42);
+# else
+    MISSING(AO_compare_and_swap_double);
+# endif
+}
+
+
+    
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_malloc.c b/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_malloc.c
new file mode 100644 (file)
index 0000000..4026e62
--- /dev/null
@@ -0,0 +1,182 @@
+/*  
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ * Original Author: Hans Boehm
+ *
+ * This file may be redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ * 
+ * It is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License in the
+ * file doc/COPYING for more details.
+ */
+
+#if defined(HAVE_CONFIG_H)
+# include "config.h"
+#endif
+
+#include "run_parallel.inc"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "atomic_ops_malloc.h"
+#define MAX_NTHREADS 100
+#define N_REVERSALS 1000 /* must be even */
+#define LENGTH 1000
+
+#ifdef USE_STANDARD_MALLOC
+# define AO_malloc(n) malloc(n)
+# define AO_free(p) free(p)
+# define AO_malloc_enable_mmap() 
+#endif
+
+typedef struct list_node {
+       struct list_node *next;
+       int data;
+} ln;
+
+ln *cons(int d, ln *tail)
+{
+  static size_t extra = 0;
+  size_t my_extra = extra;
+  ln *result;
+  int * extras;
+  int i;
+
+  if (my_extra > 100) 
+    extra = my_extra = 0;
+  else
+    ++extra;
+  result = AO_malloc(sizeof(ln) + sizeof(int)*my_extra);
+  if (result == 0)
+    {
+      fprintf(stderr, "Out of memory\n");
+       /* Normal for more than about 10 threads without mmap? */
+      abort();
+    }
+
+  result -> data = d;
+  result -> next = tail;
+  extras = (int *)(result+1);
+  for (i = 0; i < my_extra; ++i) extras[i] = 42;
+  return result;
+}
+
+void print_list(ln *l)
+{
+  ln *p;
+
+  for (p = l; p != 0; p = p -> next)
+    {
+      fprintf(stderr, "%d, ", p -> data);
+    }
+  fprintf(stderr, "\n");
+}
+
+/* Check that l contains numbers from m to n inclusive in ascending order */
+void check_list(ln *l, int m, int n)
+{
+  ln *p;
+  int i;
+
+  for (p = l, i = m; p != 0; p = p -> next, ++i)
+    {
+      if (i != p -> data)
+       {
+         fprintf(stderr, "Found %d, expected %d\n", p -> data, i);
+         abort();
+       }
+    }
+}
+
+/* Create a list of integers from m to n */
+ln *
+make_list(int m, int n)
+{
+  if (m > n) return 0;
+  return cons(m, make_list(m+1, n));
+}
+
+/* Reverse list x, and concatenate it to y, deallocating no longer needed */
+/* nodes in x.                                                           */
+ln *
+reverse(ln *x, ln *y)
+{
+  ln * result;
+
+  if (x == 0) return y;
+  result = reverse(x -> next, cons(x -> data, y));
+  AO_free(x);
+  return result;
+}
+
+int dummy_test(void) { return 1; }
+
+#define LARGE 200000
+
+void * run_one_test(void * arg) {
+  ln * x = make_list(1, LENGTH);
+  int i;
+  char *p = AO_malloc(LARGE);
+  char *q;
+
+  if (0 == p) {
+    fprintf(stderr, "AO_malloc(%d) failed: This is normal without mmap\n",
+           LARGE);
+    AO_free(p);
+  } else {
+    p[0] = p[LARGE/2] = p[LARGE-1] = 'a';
+    q = AO_malloc(LARGE);
+    q[0] = q[LARGE/2] = q[LARGE-1] = 'b';
+    if (p[0] != 'a' || p[LARGE/2] != 'a' || p[LARGE-1] != 'a') {
+      fprintf(stderr, "First large allocation smashed\n");
+      abort();
+    }
+    AO_free(p);
+    if (q[0] != 'b' || q[LARGE/2] != 'b' || q[LARGE-1] != 'b') {
+      fprintf(stderr, "Second large allocation smashed\n");
+      abort();
+    }
+    AO_free(q);
+  }
+# if 0 /* enable for debugging */
+    x = reverse(x, 0);
+    print_list(x);
+    x = reverse(x, 0);
+    print_list(x);
+# endif
+  for (i = 0; i < N_REVERSALS; ++i) {
+    x = reverse(x, 0);
+  }
+  check_list(x, 1, LENGTH);
+  return 0;
+}
+
+int main(int argc, char **argv) {
+    int nthreads;
+    int exper_n;
+
+    if (1 == argc) {
+#     if !defined(HAVE_MMAP)
+       nthreads = 3;
+#     else
+        nthreads = 10;
+#     endif
+    } else if (2 == argc) {
+      nthreads = atoi(argv[1]);
+      if (nthreads < 1 || nthreads > MAX_NTHREADS) {
+       fprintf(stderr, "Invalid # of threads argument\n");
+       exit(1);
+      }
+    } else {
+      fprintf(stderr, "Usage: %s [# of threads]\n", argv[0]);
+      exit(1);
+    }
+    printf("Performing %d reversals of %d element lists in %d threads\n",
+          N_REVERSALS, LENGTH, nthreads);
+    AO_malloc_enable_mmap();
+    run_parallel(nthreads, run_one_test, dummy_test, "AO_malloc/AO_free");
+    return 0;
+}
+
diff --git a/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_stack.c b/src/mm/boehm-gc/libatomic_ops-1.2/tests/test_stack.c
new file mode 100644 (file)
index 0000000..8a8ba50
--- /dev/null
@@ -0,0 +1,232 @@
+/*  
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ * Original Author: Hans Boehm
+ *
+ * This file may be redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later version.
+ * 
+ * It is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License in the
+ * file doc/COPYING for more details.
+ */
+
+#if defined(HAVE_CONFIG_H)
+# include "config.h"
+#endif
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "atomic_ops.h"
+#include "atomic_ops_stack.h"
+#define MAX_NTHREADS 100
+
+#ifndef NO_TIMES
+#include <time.h>
+#include <sys/time.h>
+/* Need 64-bit long long support */
+long long
+get_msecs(void)
+{
+  struct timeval tv;
+
+  gettimeofday(&tv, 0);
+  return (long long)tv.tv_sec * 1000 + tv.tv_usec/1000;
+}
+#else
+# define get_msecs() 0
+#endif
+
+typedef struct le {
+    AO_t next;
+    int data;
+} list_element;
+
+AO_stack_t the_list = AO_STACK_INITIALIZER;
+
+void add_elements(int n)
+{
+  list_element * le;
+  if (n == 0) return;
+  add_elements(n-1);
+  le = malloc(sizeof(list_element));
+  le -> data = n;
+  AO_stack_push(&the_list, (AO_t *)le);
+}
+
+void print_list()
+{
+  list_element *p;
+
+  for (p = (list_element *)AO_REAL_HEAD_PTR(the_list);
+       p != 0;
+       p = (list_element *)AO_REAL_NEXT_PTR(p -> next))
+    printf("%d\n", p -> data);
+}
+
+static char marks[MAX_NTHREADS * MAX_NTHREADS];
+
+void check_list(int n)
+{
+  list_element *p;
+  int i;
+
+  for (i = 1; i <= n; ++i) marks[i] = 0;
+  for (p = (list_element *)AO_REAL_HEAD_PTR(the_list);
+       p != 0;
+       p = (list_element *)AO_REAL_NEXT_PTR(p -> next))
+    {
+      if (p -> data > n || p -> data <= 0)
+        fprintf(stderr, "Found erroneous list element %d\n", p -> data);
+      if (marks[p -> data] != 0)
+        fprintf(stderr, "Found duplicate list element %d\n", p -> data);
+      marks[p -> data] = 1;
+    }
+  for (i = 1; i <= n; ++i)
+    if (marks[i] != 1)
+      fprintf(stderr, "Missing list element %d\n", i);
+}
+     
+volatile AO_t ops_performed = 0;
+
+#define LIMIT 1000000
+       /* Total number of push/pop ops in all threads per test. */
+
+#ifdef AO_HAVE_fetch_and_add
+# define fetch_and_add(addr, val) AO_fetch_and_add(addr, val)
+#else
+  /* Fake it.  This is really quite unacceptable for timing    */
+  /* purposes.  But as a correctness test, it should be OK.    */
+  AO_INLINE AO_t fetch_and_add(volatile AO_t * addr, AO_t val)
+  {
+    AO_t result = AO_load(addr);
+    AO_store(addr, result + val);
+    return result;
+  }
+#endif
+
+void * run_one_test(void * arg)
+{
+  list_element * t[MAX_NTHREADS + 1];
+  list_element * aux; 
+  long index = (long)arg;
+  int i;
+  int j = 0;
+
+# ifdef VERBOSE
+    printf("starting thread %d\n", index);
+# endif
+  while (fetch_and_add(&ops_performed, index + 1) + index + 1 < LIMIT)
+    {
+      for (i = 0; i < index + 1; ++i)
+        {
+          t[i] = (list_element *)AO_stack_pop(&the_list);
+          if (0 == t[i])
+           {
+              fprintf(stderr, "FAILED\n");
+              abort();
+            }
+        }
+      for (i = 0; i < index + 1; ++i)
+        {
+          AO_stack_push(&the_list, (AO_t *)t[i]);
+        }
+      j += (index + 1);
+    }
+# ifdef VERBOSE
+    printf("finished thread %d: %d total ops\n", index, j);
+# endif
+  return 0;
+}
+
+#define N_EXPERIMENTS 1
+
+unsigned long times[MAX_NTHREADS + 1][N_EXPERIMENTS];
+
+int main(int argc, char **argv)
+{
+  int nthreads;
+  int max_nthreads;
+  int exper_n;
+
+  if (1 == argc)
+    max_nthreads = 4;
+  else if (2 == argc)
+    {
+      max_nthreads = atoi(argv[1]);
+      if (max_nthreads < 1 || max_nthreads > MAX_NTHREADS)
+        {
+         fprintf(stderr, "Invalid max # of threads argument\n");
+         exit(1);
+        }
+    }
+  else
+    {
+      fprintf(stderr, "Usage: %s [max # of threads]\n", argv[0]);
+      exit(1);
+    }
+  for (exper_n = 0; exper_n < N_EXPERIMENTS; ++ exper_n)
+    for (nthreads = 1; nthreads <= max_nthreads; ++nthreads)
+      {
+        int i;
+        pthread_t thread[MAX_NTHREADS];
+        int list_length = nthreads*(nthreads+1)/2;
+        long long start_time;
+  
+        add_elements(list_length);
+  #     ifdef VERBOSE
+          printf("Initial list (nthreads = %d):\n", nthreads);
+          print_list();
+  #     endif
+        ops_performed = 0;
+        start_time = get_msecs();
+        for (i = 1; i < nthreads; ++i) {
+       int code;
+  
+          if ((code = pthread_create(thread+i, 0, run_one_test,
+           (void *)(long)i)) != 0) {
+             fprintf(stderr, "Thread creation failed %u\n", code);
+            exit(1);
+          }
+        }
+        /* We use the main thread to run one test.  This allows gprof  */
+        /* profiling to work, for example.                             */
+          run_one_test(0);
+        for (i = 1; i < nthreads; ++i) {
+         int code;
+          if ((code = pthread_join(thread[i], 0)) != 0) {
+           fprintf(stderr, "Thread join failed %u\n", code);
+          }
+        }
+        times[nthreads][exper_n] = (unsigned long)(get_msecs() - start_time);
+  #     ifdef VERBOSE
+          printf("%d %lu\n", nthreads,
+                            (unsigned long)(get_msecs() - start_time));
+          printf("final list (should be reordered initial list):\n");
+          print_list();
+  #     endif
+        check_list(list_length);
+        while ((list_element *)AO_stack_pop(&the_list));
+      }
+# ifndef NO_TIMES
+    for (nthreads = 1; nthreads <= max_nthreads; ++nthreads)
+      {
+        unsigned long sum = 0;
+
+        printf("About %d pushes + %d pops in %d threads:",
+               LIMIT, LIMIT, nthreads);
+        for (exper_n = 0; exper_n < N_EXPERIMENTS; ++exper_n)
+         {
+#           if defined(VERBOSE)
+             printf("[%lu] ", times[nthreads][exper_n]);
+#          endif
+           sum += times[nthreads][exper_n];
+          }
+        printf(" %lu msecs\n", (sum + N_EXPERIMENTS/2)/N_EXPERIMENTS);
+      }
+# endif /* NO_TIMES */
+  return 0;
+}
+
index 066bf6a5ce6dca41fad64dc0ad26ab172d94b6ac..0f53cb592ec026467985d5f69d6eff1be58d1e91 100644 (file)
@@ -1,31 +1,67 @@
-# libtool.m4 - Configure libtool for the host system. -*-Shell-script-*-
-## Copyright 1996, 1997, 1998, 1999, 2000, 2001
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+## Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
 ## Free Software Foundation, Inc.
 ## Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
 ##
-## This program is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-##
-## As a special exception to the GNU General Public License, if you
-## distribute this file as part of a program that contains a
-## configuration script generated by Autoconf, you may include it under
-## the same distribution terms that you use for the rest of that program.
+## This file is free software; the Free Software Foundation gives
+## unlimited permission to copy and/or distribute it, with or without
+## modifications, as long as this notice is preserved.
+
+# serial 48 AC_PROG_LIBTOOL
 
-# serial 46 AC_PROG_LIBTOOL
 
+# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED)
+# -----------------------------------------------------------
+# If this macro is not defined by Autoconf, define it here.
+m4_ifdef([AC_PROVIDE_IFELSE],
+         [],
+         [m4_define([AC_PROVIDE_IFELSE],
+                [m4_ifdef([AC_PROVIDE_$1],
+                          [$2], [$3])])])
+
+
+# AC_PROG_LIBTOOL
+# ---------------
 AC_DEFUN([AC_PROG_LIBTOOL],
+[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl
+dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX
+dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX.
+  AC_PROVIDE_IFELSE([AC_PROG_CXX],
+    [AC_LIBTOOL_CXX],
+    [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX
+  ])])
+dnl And a similar setup for Fortran 77 support
+  AC_PROVIDE_IFELSE([AC_PROG_F77],
+    [AC_LIBTOOL_F77],
+    [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77
+])])
+
+dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly.
+dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run
+dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both.
+  AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+    [AC_LIBTOOL_GCJ],
+    [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+      [AC_LIBTOOL_GCJ],
+      [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],
+       [AC_LIBTOOL_GCJ],
+      [ifdef([AC_PROG_GCJ],
+            [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([A][M_PROG_GCJ],
+            [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])])
+       ifdef([LT_AC_PROG_GCJ],
+            [define([LT_AC_PROG_GCJ],
+               defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])])
+])])# AC_PROG_LIBTOOL
+
+
+# _AC_PROG_LIBTOOL
+# ----------------
+AC_DEFUN([_AC_PROG_LIBTOOL],
 [AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl
+AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl
 
 # This can be used to rebuild libtool when needed
 LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
@@ -36,10 +72,13 @@ AC_SUBST(LIBTOOL)dnl
 
 # Prevent multiple expansion
 define([AC_PROG_LIBTOOL], [])
-])
+])# _AC_PROG_LIBTOOL
+
 
+# AC_LIBTOOL_SETUP
+# ----------------
 AC_DEFUN([AC_LIBTOOL_SETUP],
-[AC_PREREQ(2.13)dnl
+[AC_PREREQ(2.50)dnl
 AC_REQUIRE([AC_ENABLE_SHARED])dnl
 AC_REQUIRE([AC_ENABLE_STATIC])dnl
 AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
@@ -49,385 +88,277 @@ AC_REQUIRE([AC_PROG_CC])dnl
 AC_REQUIRE([AC_PROG_LD])dnl
 AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
 AC_REQUIRE([AC_PROG_NM])dnl
+
 AC_REQUIRE([AC_PROG_LN_S])dnl
 AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
+# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
 AC_REQUIRE([AC_OBJEXT])dnl
 AC_REQUIRE([AC_EXEEXT])dnl
 dnl
 
+AC_LIBTOOL_SYS_MAX_CMD_LEN
+AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+AC_LIBTOOL_OBJDIR
+
+AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
 _LT_AC_PROG_ECHO_BACKSLASH
-# Only perform the check for file, if the check method requires it
-case $deplibs_check_method in
-file_magic*)
-  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
-    AC_PATH_MAGIC
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
   fi
   ;;
 esac
 
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e 1s/^X//'
+[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g']
+
+# Same as above, but do not quote variable references.
+[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g']
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Constants:
+rm="rm -f"
+
+# Global variables:
+default_ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+ltmain="$ac_aux_dir/ltmain.sh"
+ofile="$default_ofile"
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+AC_CHECK_TOOL(AR, ar, false)
 AC_CHECK_TOOL(RANLIB, ranlib, :)
 AC_CHECK_TOOL(STRIP, strip, :)
 
-ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
-ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
-enable_win32_dll=yes, enable_win32_dll=no)
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
 
-AC_ARG_ENABLE(libtool-lock,
-  [  --disable-libtool-lock  avoid locking (might break parallel builds)])
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+# Set sane defaults for various variables
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+test -z "$AS" && AS=as
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+test -z "$LD" && LD=ld
+test -z "$LN_S" && LN_S="ln -s"
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+test -z "$NM" && NM=nm
+test -z "$SED" && SED=sed
+test -z "$OBJDUMP" && OBJDUMP=objdump
+test -z "$RANLIB" && RANLIB=:
+test -z "$STRIP" && STRIP=:
+test -z "$ac_objext" && ac_objext=o
 
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-*-*-irix6*)
-  # Find out which ABI we are using.
-  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.$ac_objext` in
-    *32-bit*)
-      LD="${LD-ld} -32"
-      ;;
-    *N32*)
-      LD="${LD-ld} -n32"
-      ;;
-    *64-bit*)
-      LD="${LD-ld} -64"
-      ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
 
-*-*-sco3.2v5*)
-  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
-  SAVE_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS -belf"
-  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
-    [AC_LANG_SAVE
-     AC_LANG_C
-     AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
-     AC_LANG_RESTORE])
-  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
-    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
-    CFLAGS="$SAVE_CFLAGS"
-  fi
-  ;;
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
 
-ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
-[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
-  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
-  AC_CHECK_TOOL(AS, as, false)
-  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+_LT_CC_BASENAME([$compiler])
 
-  # recent cygwin and mingw systems supply a stub DllMain which the user
-  # can override, but on older systems we have to supply one
-  AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain,
-    [AC_TRY_LINK([],
-      [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*);
-      DllMain (0, 0, 0);],
-      [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])])
-
-  case $host/$CC in
-  *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*)
-    # old mingw systems require "-dll" to link a DLL, while more recent ones
-    # require "-mdll"
-    SAVE_CFLAGS="$CFLAGS"
-    CFLAGS="$CFLAGS -mdll"
-    AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch,
-      [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])])
-    CFLAGS="$SAVE_CFLAGS" ;;
-  *-*-cygwin* | *-*-pw32*)
-    # cygwin systems need to pass --dll to the linker, and not link
-    # crt.o which will require a WinMain@16 definition.
-    lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;;
-  esac
+# Only perform the check for file, if the check method requires it
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    AC_PATH_MAGIC
+  fi
   ;;
-  ])
 esac
 
-_LT_AC_LTCONFIG_HACK
+AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+enable_win32_dll=yes, enable_win32_dll=no)
 
-])
+AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+       [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
 
-# AC_LIBTOOL_HEADER_ASSERT
-# ------------------------
-AC_DEFUN([AC_LIBTOOL_HEADER_ASSERT],
-[AC_CACHE_CHECK([whether $CC supports assert without backlinking],
-    [lt_cv_func_assert_works],
-    [case $host in
-    *-*-solaris*)
-      if test "$GCC" = yes && test "$with_gnu_ld" != yes; then
-        case `$CC --version 2>/dev/null` in
-        [[12]].*) lt_cv_func_assert_works=no ;;
-        *)        lt_cv_func_assert_works=yes ;;
-        esac
-      fi
-      ;;
-    esac])
+AC_ARG_WITH([pic],
+    [AC_HELP_STRING([--with-pic],
+       [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [pic_mode="$withval"],
+    [pic_mode=default])
+test -z "$pic_mode" && pic_mode=default
 
-if test "x$lt_cv_func_assert_works" = xyes; then
-  AC_CHECK_HEADERS(assert.h)
-fi
-])# AC_LIBTOOL_HEADER_ASSERT
+# Use C for the default configuration in the libtool script
+tagname=
+AC_LIBTOOL_LANG_C_CONFIG
+_LT_AC_TAGCONFIG
+])# AC_LIBTOOL_SETUP
 
-# _LT_AC_CHECK_DLFCN
-# --------------------
-AC_DEFUN([_LT_AC_CHECK_DLFCN],
-[AC_CHECK_HEADERS(dlfcn.h)
-])# _LT_AC_CHECK_DLFCN
 
-# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
-# ---------------------------------
-AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
-[AC_REQUIRE([AC_CANONICAL_HOST])
-AC_REQUIRE([AC_PROG_NM])
-AC_REQUIRE([AC_OBJEXT])
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-AC_MSG_CHECKING([command to parse $NM output])
-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [dnl
+# _LT_AC_SYS_COMPILER
+# -------------------
+AC_DEFUN([_LT_AC_SYS_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
 
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
 
-# Character class describing NM global symbol codes.
-symcode='[[BCDEGRST]]'
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
 
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_AC_SYS_COMPILER
 
-# Transform the above into a raw symbol and a C symbol.
-symxfrm='\1 \2\3 \3'
 
-# Transform an extracted symbol line into a proper C declaration
-lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'"
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+AC_DEFUN([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+])
 
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
 
-# Define system-specific variables.
-case $host_os in
-aix*)
-  symcode='[[BCDT]]'
-  ;;
-cygwin* | mingw* | pw32*)
-  symcode='[[ABCDGISTW]]'
-  ;;
-hpux*) # Its linker distinguishes data from code symbols
-  lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
-  lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
-  ;;
-irix*)
-  symcode='[[BCDEGRST]]'
-  ;;
-solaris* | sysv5*)
-  symcode='[[BDT]]'
-  ;;
-sysv4)
-  symcode='[[DFNSTU]]'
-  ;;
-esac
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+AC_DEFUN([_LT_COMPILER_BOILERPLATE],
+[ac_outfile=conftest.$ac_objext
+printf "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+AC_DEFUN([_LT_LINKER_BOILERPLATE],
+[ac_outfile=conftest.$ac_objext
+printf "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$rm conftest*
+])# _LT_LINKER_BOILERPLATE
+
+
+# _LT_AC_SYS_LIBPATH_AIX
+# ----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX],
+[AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
+}'`; fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_AC_SYS_LIBPATH_AIX
+
+
+# _LT_AC_SHELL_INIT(ARG)
+# ----------------------
+AC_DEFUN([_LT_AC_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+            [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+        [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_AC_SHELL_INIT
 
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $host_os in
-mingw*)
-  opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+
+# _LT_AC_PROG_ECHO_BACKSLASH
+# --------------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
+[_LT_AC_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$ECHO in
+X*--fallback-echo)
+  # Remove one level of quotation (which was required for Make).
+  ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
   ;;
 esac
 
-# If we're using GNU nm, then use its standard symbol codes.
-if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
-  symcode='[[ABCDGISTW]]'
+echo=${ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X[$]1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then
+  # Yippee, $echo works!
+  :
+else
+  # Restart under the correct shell.
+  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
 fi
 
-# Try without a prefix undercore, then with it.
-for ac_symprfx in "" "_"; do
-
-  # Write the raw and C identifiers.
-lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[       ]]\($symcode$symcode*\)[[       ]][[    ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
-
-  # Check to see that the pipe works correctly.
-  pipe_works=no
-  rm -f conftest*
-  cat > conftest.$ac_ext <<EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
+if test "X[$]1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+[$]*
 EOF
+  exit 0
+fi
 
-  if AC_TRY_EVAL(ac_compile); then
-    # Now try to grab the symbols.
-    nlist=conftest.nm
-    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
-      # Try sorting and uniquifying the output.
-      if sort "$nlist" | uniq > "$nlist"T; then
-       mv -f "$nlist"T "$nlist"
-      else
-       rm -f "$nlist"T
-      fi
-
-      # Make sure that we snagged all the symbols we need.
-      if egrep ' nm_test_var$' "$nlist" >/dev/null; then
-       if egrep ' nm_test_func$' "$nlist" >/dev/null; then
-         cat <<EOF > conftest.$ac_ext
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-EOF
-         # Now generate the symbol file.
-         eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext'
-
-         cat <<EOF >> conftest.$ac_ext
-#if defined (__STDC__) && __STDC__
-# define lt_ptr void *
-#else
-# define lt_ptr char *
-# define const
-#endif
-
-/* The mapping between symbol names and symbols. */
-const struct {
-  const char *name;
-  lt_ptr address;
-}
-lt_preloaded_symbols[[]] =
-{
-EOF
-         sed "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (lt_ptr) \&\2},/" < "$nlist" >> conftest.$ac_ext
-         cat <<\EOF >> conftest.$ac_ext
-  {0, (lt_ptr) 0}
-};
-
-#ifdef __cplusplus
-}
-#endif
-EOF
-         # Now try linking the two files.
-         mv conftest.$ac_objext conftstm.$ac_objext
-         save_LIBS="$LIBS"
-         save_CFLAGS="$CFLAGS"
-         LIBS="conftstm.$ac_objext"
-         CFLAGS="$CFLAGS$no_builtin_flag"
-         if AC_TRY_EVAL(ac_link) && test -s conftest; then
-           pipe_works=yes
-         fi
-         LIBS="$save_LIBS"
-         CFLAGS="$save_CFLAGS"
-       else
-         echo "cannot find nm_test_func in $nlist" >&AC_FD_CC
-       fi
-      else
-       echo "cannot find nm_test_var in $nlist" >&AC_FD_CC
-      fi
-    else
-      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC
-    fi
-  else
-    echo "$progname: failed program was:" >&AC_FD_CC
-    cat conftest.$ac_ext >&5
-  fi
-  rm -f conftest* conftst*
-
-  # Do not use the global_symbol_pipe unless it works.
-  if test "$pipe_works" = yes; then
-    break
-  else
-    lt_cv_sys_global_symbol_pipe=
-  fi
-done
-])
-global_symbol_pipe="$lt_cv_sys_global_symbol_pipe"
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
-  global_symbol_to_cdecl=
-  global_symbol_to_c_name_address=
-else
-  global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl"
-  global_symbol_to_c_name_address="$lt_cv_global_symbol_to_c_name_address"
-fi
-if test -z "$global_symbol_pipe$global_symbol_to_cdec$global_symbol_to_c_name_address";
-then
-  AC_MSG_RESULT(failed)
-else
-  AC_MSG_RESULT(ok)
-fi
-]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
-
-# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR
-# ---------------------------------
-AC_DEFUN([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR],
-[# Find the correct PATH separator.  Usually this is `:', but
-# DJGPP uses `;' like DOS.
-if test "X${PATH_SEPARATOR+set}" != Xset; then
-  UNAME=${UNAME-`uname 2>/dev/null`}
-  case X$UNAME in
-    *-DOS) lt_cv_sys_path_separator=';' ;;
-    *)     lt_cv_sys_path_separator=':' ;;
-  esac
-  PATH_SEPARATOR=$lt_cv_sys_path_separator
-fi
-])# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR
-
-# _LT_AC_PROG_ECHO_BACKSLASH
-# --------------------------
-# Add some code to the start of the generated configure script which
-# will find an echo command which doesn't interpret backslashes.
-AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
-[ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
-                             [AC_DIVERT_PUSH(NOTICE)])
-_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR
-
-# Check that we are running under the correct shell.
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-case X$ECHO in
-X*--fallback-echo)
-  # Remove one level of quotation (which was required for Make).
-  ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
-  ;;
-esac
-
-echo=${ECHO-echo}
-if test "X[$]1" = X--no-reexec; then
-  # Discard the --no-reexec flag, and continue.
-  shift
-elif test "X[$]1" = X--fallback-echo; then
-  # Avoid inline document here, it may be left over
-  :
-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
-  # Yippee, $echo works!
-  :
-else
-  # Restart under the correct shell.
-  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
-fi
-
-if test "X[$]1" = X--fallback-echo; then
-  # used as fallback echo
-  shift
-  cat <<EOF
-$*
-EOF
-  exit 0
-fi
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
 
 if test -z "$ECHO"; then
 if test "X${echo_test_string+set}" != Xset; then
 # find a string as large as possible, as long as the shell can cope with it
   for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
     # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
-    if (echo_test_string="`eval $cmd`") 2>/dev/null &&
-       echo_test_string="`eval $cmd`" &&
+    if (echo_test_string=`eval $cmd`) 2>/dev/null &&
+       echo_test_string=`eval $cmd` &&
        (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
     then
       break
@@ -446,8 +377,9 @@ else
   #
   # So, first we look for a working echo in the user's PATH.
 
-  IFS="${IFS=  }"; save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
   for dir in $PATH /usr/ucb; do
+    IFS="$lt_save_ifs"
     if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
        test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
        echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
@@ -456,7 +388,7 @@ else
       break
     fi
   done
-  IFS="$save_ifs"
+  IFS="$lt_save_ifs"
 
   if test "X$echo" = Xecho; then
     # We didn't find a better echo, so look for alternatives.
@@ -529,17 +461,365 @@ if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
 fi
 
 AC_SUBST(ECHO)
-AC_DIVERT_POP
-])# _LT_AC_PROG_ECHO_BACKSLASH
+])])# _LT_AC_PROG_ECHO_BACKSLASH
+
+
+# _LT_AC_LOCK
+# -----------
+AC_DEFUN([_LT_AC_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+    [AC_HELP_STRING([--disable-libtool-lock],
+       [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *ELF-32*)
+      HPUX_IA64_MODE="32"
+      ;;
+    *ELF-64*)
+      HPUX_IA64_MODE="64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+   if test "$lt_cv_prog_gnu_ld" = yes; then
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -melf32bsmip"
+      ;;
+    *N32*)
+      LD="${LD-ld} -melf32bmipn32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -melf64bmip"
+      ;;
+    esac
+   else
+    case `/usr/bin/file conftest.$ac_objext` in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+   fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *32-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_i386"
+          ;;
+        ppc64-*linux*|powerpc64-*linux*)
+          LD="${LD-ld} -m elf32ppclinux"
+          ;;
+        s390x-*linux*)
+          LD="${LD-ld} -m elf_s390"
+          ;;
+        sparc64-*linux*)
+          LD="${LD-ld} -m elf32_sparc"
+          ;;
+      esac
+      ;;
+    *64-bit*)
+      case $host in
+        x86_64-*linux*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        ppc*-*linux*|powerpc*-*linux*)
+          LD="${LD-ld} -m elf64ppc"
+          ;;
+        s390*-*linux*)
+          LD="${LD-ld} -m elf64_s390"
+          ;;
+        sparc*-*linux*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+sparc*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*) LD="${LD-ld} -m elf64_sparc" ;;
+      *)    LD="${LD-ld} -64" ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL],
+[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+  ])
+esac
+
+need_locks="$enable_libtool_lock"
+
+])# _LT_AC_LOCK
+
+
+# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#              [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION],
+[AC_REQUIRE([LT_AC_PROG_SED])
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+  ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $rm conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$5], , :, [$5])
+else
+    ifelse([$6], , :, [$6])
+fi
+])# AC_LIBTOOL_COMPILER_OPTION
+
+
+# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                          [ACTION-SUCCESS], [ACTION-FAILURE])
+# ------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([AC_LIBTOOL_LINKER_OPTION],
+[AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   printf "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $rm conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    ifelse([$4], , :, [$4])
+else
+    ifelse([$5], , :, [$5])
+fi
+])# AC_LIBTOOL_LINKER_OPTION
+
+
+# AC_LIBTOOL_SYS_MAX_CMD_LEN
+# --------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN],
+[# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536      # usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[       ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    # If test is not a shell built-in, we'll probably end up computing a
+    # maximum length that is only half of the actual maximum length, but
+    # we can't tell.
+    SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+    while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \
+              = "XX$teststring") >/dev/null 2>&1 &&
+           new_result=`expr "X$teststring" : ".*" 2>&1` &&
+           lt_cv_sys_max_cmd_len=$new_result &&
+           test $i != 17 # 1/2 MB should be enough
+    do
+      i=`expr $i + 1`
+      teststring=$teststring$teststring
+    done
+    teststring=
+    # Add a significant safety factor because C++ compilers can tack on massive
+    # amounts of additional arguments before passing them to the linker.
+    # It appears as though 1/2 is a usable value.
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+])# AC_LIBTOOL_SYS_MAX_CMD_LEN
+
+
+# _LT_AC_CHECK_DLFCN
+# ------------------
+AC_DEFUN([_LT_AC_CHECK_DLFCN],
+[AC_CHECK_HEADERS(dlfcn.h)dnl
+])# _LT_AC_CHECK_DLFCN
+
 
 # _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
 #                           ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
-# ------------------------------------------------------------------
+# ---------------------------------------------------------------------
 AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
-[if test "$cross_compiling" = yes; then :
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
   [$4]
 else
-  AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
@@ -600,17 +880,19 @@ int main ()
       else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
       /* dlclose (self); */
     }
+  else
+    puts (dlerror ());
 
     exit (status);
 }]
 EOF
   if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
-    (./conftest; exit; ) 2>/dev/null
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
     lt_status=$?
     case x$lt_status in
       x$lt_dlno_uscore) $1 ;;
       x$lt_dlneed_uscore) $2 ;;
-      x$lt_unknown|x*) $3 ;;
+      x$lt_dlunknown|x*) $3 ;;
     esac
   else :
     # compilation failed
@@ -620,10 +902,12 @@ fi
 rm -fr conftest*
 ])# _LT_AC_TRY_DLOPEN_SELF
 
+
 # AC_LIBTOOL_DLOPEN_SELF
-# -------------------
+# ----------------------
 AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
-[if test "x$enable_dlopen" != xyes; then
+[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
   enable_dlopen=unknown
   enable_dlopen_self=unknown
   enable_dlopen_self_static=unknown
@@ -638,24 +922,39 @@ else
     lt_cv_dlopen_self=yes
     ;;
 
-  cygwin* | mingw* | pw32*)
+  mingw* | pw32*)
     lt_cv_dlopen="LoadLibrary"
     lt_cv_dlopen_libs=
    ;;
 
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+   ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+   ;;
+
   *)
     AC_CHECK_FUNC([shl_load],
-          [lt_cv_dlopen="shl_load"],
+         [lt_cv_dlopen="shl_load"],
       [AC_CHECK_LIB([dld], [shl_load],
-            [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
+           [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
        [AC_CHECK_FUNC([dlopen],
              [lt_cv_dlopen="dlopen"],
          [AC_CHECK_LIB([dl], [dlopen],
-               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
            [AC_CHECK_LIB([svld], [dlopen],
-                 [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+                 [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
              [AC_CHECK_LIB([dld], [dld_link],
-                   [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
+                   [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
              ])
            ])
          ])
@@ -673,11 +972,10 @@ else
   case $lt_cv_dlopen in
   dlopen)
     save_CPPFLAGS="$CPPFLAGS"
-    AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
     test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
 
     save_LDFLAGS="$LDFLAGS"
-    eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
 
     save_LIBS="$LIBS"
     LIBS="$lt_cv_dlopen_libs $LIBS"
@@ -690,7 +988,7 @@ else
     ])
 
     if test "x$lt_cv_dlopen_self" = xyes; then
-      LDFLAGS="$LDFLAGS $link_static_flag"
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
       AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
          lt_cv_dlopen_self_static, [dnl
          _LT_AC_TRY_DLOPEN_SELF(
@@ -717,742 +1015,1866 @@ else
 fi
 ])# AC_LIBTOOL_DLOPEN_SELF
 
-AC_DEFUN([_LT_AC_LTCONFIG_HACK],
-[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])dnl
-# Sed substitution that helps us do robust quoting.  It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e s/^X//'
-sed_quote_subst='s/\([[\\"\\`$\\\\]]\)/\\\1/g'
 
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([[\\"\\`\\\\]]\)/\\\1/g'
+# AC_LIBTOOL_PROG_CC_C_O([TAGNAME])
+# ---------------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler
+AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $rm -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $rm conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files
+   $rm out/* && rmdir out
+   cd ..
+   rmdir conftest
+   $rm conftest*
+])
+])# AC_LIBTOOL_PROG_CC_C_O
 
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
 
-# Constants:
-rm="rm -f"
+# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME])
+# -----------------------------------------
+# Check to see if we can do hard links to lock some files if needed
+AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS],
+[AC_REQUIRE([_LT_AC_LOCK])dnl
 
-# Global variables:
-default_ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a `.a' archive for static linking (except M$VC,
-# which needs '.lib').
-libext=a
-ltmain="$ac_aux_dir/ltmain.sh"
-ofile="$default_ofile"
-with_gnu_ld="$lt_cv_prog_gnu_ld"
-need_locks="$enable_libtool_lock"
-
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
+hard_links="nottested"
+if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $rm conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS
 
-# Set sane defaults for various variables
-test -z "$AR" && AR=ar
-test -z "$AR_FLAGS" && AR_FLAGS=cru
-test -z "$AS" && AS=as
-test -z "$CC" && CC=cc
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-test -z "$LD" && LD=ld
-test -z "$LN_S" && LN_S="ln -s"
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-test -z "$NM" && NM=nm
-test -z "$OBJDUMP" && OBJDUMP=objdump
-test -z "$RANLIB" && RANLIB=:
-test -z "$STRIP" && STRIP=:
-test -z "$ac_objext" && ac_objext=o
 
-if test x"$host" != x"$build"; then
-  ac_tool_prefix=${host_alias}-
+# AC_LIBTOOL_OBJDIR
+# -----------------
+AC_DEFUN([AC_LIBTOOL_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
 else
-  ac_tool_prefix=
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
 fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+])# AC_LIBTOOL_OBJDIR
 
-# Transform linux* to *-*-linux-gnu*, to support old configure scripts.
-case $host_os in
-linux-gnu*) ;;
-linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
-esac
 
-case $host_os in
-aix3*)
-  # AIX sometimes has problems with the GCC collect2 program.  For some
-  # reason, if we set the COLLECT_NAMES environment variable, the problems
-  # vanish in a puff of smoke.
-  if test "X${COLLECT_NAMES+set}" != Xset; then
-    COLLECT_NAMES=
-    export COLLECT_NAMES
+# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME])
+# ----------------------------------------------
+# Check hardcoding attributes.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_AC_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \
+   test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \
+   test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existant directories.
+  if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_AC_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_AC_TAGVAR(hardcode_action, $1)=immediate
   fi
-  ;;
-esac
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_AC_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)])
 
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
+if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH
 
-if test -n "$RANLIB"; then
+
+# AC_LIBTOOL_SYS_LIB_STRIP
+# ------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP],
+[striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
   case $host_os in
-  openbsd*)
-    old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
-    ;;
-  *)
-    old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
+   darwin*)
+       if test -n "$STRIP" ; then
+         striplib="$STRIP -x"
+         AC_MSG_RESULT([yes])
+       else
+  AC_MSG_RESULT([no])
+fi
+       ;;
+   *)
+  AC_MSG_RESULT([no])
     ;;
   esac
-  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
 fi
+])# AC_LIBTOOL_SYS_LIB_STRIP
 
-# Allow CC to be a program name with arguments.
-set dummy $CC
-compiler="[$]2"
 
-## FIXME: this should be a separate macro
-##
-AC_MSG_CHECKING([for objdir])
-rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
-  objdir=.libs
+# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER],
+[AC_MSG_CHECKING([dynamic linker characteristics])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+if test "$GCC" = yes; then
+  sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
 else
-  # MS-DOS does not allow filenames that begin with a dot.
-  objdir=_libs
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
 fi
-rmdir .libs 2>/dev/null
-AC_MSG_RESULT($objdir)
-##
-## END FIXME
-
+need_lib_prefix=unknown
+hardcode_into_libs=no
 
-## FIXME: this should be a separate macro
-##
-AC_ARG_WITH(pic,
-[  --with-pic              try to use only PIC/non-PIC objects [default=use both]],
-pic_mode="$withval", pic_mode=default)
-test -z "$pic_mode" && pic_mode=default
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
 
-# We assume here that the value for lt_cv_prog_cc_pic will not be cached
-# in isolation, and that seeing it set (from the cache) indicates that
-# the associated values are set (in the cache) correctly too.
-AC_MSG_CHECKING([for $compiler option to produce PIC])
-AC_CACHE_VAL(lt_cv_prog_cc_pic,
-[ lt_cv_prog_cc_pic=
-  lt_cv_prog_cc_shlib=
-  lt_cv_prog_cc_wl=
-  lt_cv_prog_cc_static=
-  lt_cv_prog_cc_no_builtin=
-  lt_cv_prog_cc_can_build_shared=$can_build_shared
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
 
-  if test "$GCC" = yes; then
-    lt_cv_prog_cc_wl='-Wl,'
-    lt_cv_prog_cc_static='-static'
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
 
-    case $host_os in
-    aix*)
-      # Below there is a dirty hack to force normal static linking with -ldl
-      # The problem is because libdl dynamically linked with both libc and
-      # libC (AIX C++ library), which obviously doesn't included in libraries
-      # list by gcc. This cause undefined symbols with -static flags.
-      # This hack allows C programs to be linked with "-static -ldl", but
-      # not sure about C++ programs.
-      lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC"
-      ;;
-    amigaos*)
-      # FIXME: we need at least 68020 code to build shared libraries, but
-      # adding the `-m68020' flag to GCC prevents building anything better,
-      # like `-m68040'.
-      lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4'
-      ;;
-    beos* | irix5* | irix6* | osf3* | osf4* | osf5*)
-      # PIC is the default for these OSes.
-      ;;
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      lt_cv_prog_cc_pic='-fno-common'
-      ;;
-    cygwin* | mingw* | pw32* | os2*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      lt_cv_prog_cc_pic='-DDLL_EXPORT'
-      ;;
-    sysv4*MP*)
-      if test -d /usr/nec; then
-        lt_cv_prog_cc_pic=-Kconform_pic
-      fi
-      ;;
-    *)
-      lt_cv_prog_cc_pic='-fPIC'
-      ;;
-    esac
+aix4* | aix5*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
   else
-    # PORTME Check for PIC flags for the system compiler.
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
     case $host_os in
-    aix3* | aix4* | aix5*)
-      lt_cv_prog_cc_wl='-Wl,'
-      # All AIX code is PIC.
-      if test "$host_cpu" = ia64; then
-       # AIX 5 now supports IA64 processor
-       lt_cv_prog_cc_static='-Bstatic'
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+          echo ' yes '
+          echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
+       :
       else
-       lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp'
+       can_build_shared=no
       fi
       ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
 
-    hpux9* | hpux10* | hpux11*)
-      # Is there a better lt_cv_prog_cc_static that works with the bundled CC?
-      lt_cv_prog_cc_wl='-Wl,'
-      lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive"
-      lt_cv_prog_cc_pic='+Z'
-      ;;
-
-    irix5* | irix6*)
-      lt_cv_prog_cc_wl='-Wl,'
-      lt_cv_prog_cc_static='-non_shared'
-      # PIC (with -KPIC) is the default.
-      ;;
-
-    cygwin* | mingw* | pw32* | os2*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      lt_cv_prog_cc_pic='-DDLL_EXPORT'
-      ;;
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+  ;;
 
-    newsos6)
-      lt_cv_prog_cc_pic='-KPIC'
-      lt_cv_prog_cc_static='-Bstatic'
-      ;;
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
 
-    osf3* | osf4* | osf5*)
-      # All OSF/1 code is PIC.
-      lt_cv_prog_cc_wl='-Wl,'
-      lt_cv_prog_cc_static='-non_shared'
-      ;;
+bsdi[[45]]*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
 
-    sco3.2v5*)
-      lt_cv_prog_cc_pic='-Kpic'
-      lt_cv_prog_cc_static='-dn'
-      lt_cv_prog_cc_shlib='-belf'
-      ;;
+cygwin* | mingw* | pw32*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
 
-    solaris*)
-      lt_cv_prog_cc_pic='-KPIC'
-      lt_cv_prog_cc_static='-Bstatic'
-      lt_cv_prog_cc_wl='-Wl,'
-      ;;
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $rm \$dlpath'
+    shlibpath_overrides_runpath=yes
 
-    sunos4*)
-      lt_cv_prog_cc_pic='-PIC'
-      lt_cv_prog_cc_static='-Bstatic'
-      lt_cv_prog_cc_wl='-Qoption ld '
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
       ;;
-
-    sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
-      lt_cv_prog_cc_pic='-KPIC'
-      lt_cv_prog_cc_static='-Bstatic'
-      if test "x$host_vendor" = xsni; then
-       lt_cv_prog_cc_wl='-LD'
+    mingw*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
       else
-       lt_cv_prog_cc_wl='-Wl,'
-      fi
-      ;;
-
-    uts4*)
-      lt_cv_prog_cc_pic='-pic'
-      lt_cv_prog_cc_static='-Bstatic'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec ;then
-       lt_cv_prog_cc_pic='-Kconform_pic'
-       lt_cv_prog_cc_static='-Bstatic'
+        sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
       fi
       ;;
-
-    *)
-      lt_cv_prog_cc_can_build_shared=no
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
       ;;
     esac
-  fi
-])
-if test -z "$lt_cv_prog_cc_pic"; then
-  AC_MSG_RESULT([none])
-else
-  AC_MSG_RESULT([$lt_cv_prog_cc_pic])
-
-  # Check to make sure the pic_flag actually works.
-  AC_MSG_CHECKING([if $compiler PIC flag $lt_cv_prog_cc_pic works])
-  AC_CACHE_VAL(lt_cv_prog_cc_pic_works, [dnl
-    save_CFLAGS="$CFLAGS"
-    CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC"
-    AC_TRY_COMPILE([], [], [dnl
-      case $host_os in
-      hpux9* | hpux10* | hpux11*)
-       # On HP-UX, both CC and GCC only warn that PIC is supported... then
-       # they create non-PIC objects.  So, if there were any warnings, we
-       # assume that PIC is not supported.
-       if test -s conftest.err; then
-         lt_cv_prog_cc_pic_works=no
-       else
-         lt_cv_prog_cc_pic_works=yes
-       fi
-       ;;
-      *)
-       lt_cv_prog_cc_pic_works=yes
-       ;;
-      esac
-    ], [dnl
-      lt_cv_prog_cc_pic_works=no
-    ])
-    CFLAGS="$save_CFLAGS"
-  ])
-
-  if test "X$lt_cv_prog_cc_pic_works" = Xno; then
-    lt_cv_prog_cc_pic=
-    lt_cv_prog_cc_can_build_shared=no
-  else
-    lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic"
-  fi
+    ;;
 
-  AC_MSG_RESULT([$lt_cv_prog_cc_pic_works])
-fi
-##
-## END FIXME
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
 
-# Check for any special shared library compilation flags.
-if test -n "$lt_cv_prog_cc_shlib"; then
-  AC_MSG_WARN([\`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries])
-  if echo "$old_CC $old_CFLAGS " | egrep -e "[[        ]]$lt_cv_prog_cc_shlib[[        ]]" >/dev/null; then :
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+  # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same.
+  if test "$GCC" = yes; then
+    sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"`
   else
-   AC_MSG_WARN([add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure])
-    lt_cv_prog_cc_can_build_shared=no
+    sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib'
   fi
-fi
-
-## FIXME: this should be a separate macro
-##
-AC_MSG_CHECKING([if $compiler static flag $lt_cv_prog_cc_static works])
-AC_CACHE_VAL([lt_cv_prog_cc_static_works], [dnl
-  lt_cv_prog_cc_static_works=no
-  save_LDFLAGS="$LDFLAGS"
-  LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static"
-  AC_TRY_LINK([], [], [lt_cv_prog_cc_static_works=yes])
-  LDFLAGS="$save_LDFLAGS"
-])
-
-# Belt *and* braces to stop my trousers falling down:
-test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static=
-AC_MSG_RESULT([$lt_cv_prog_cc_static_works])
-
-pic_flag="$lt_cv_prog_cc_pic"
-special_shlib_compile_flags="$lt_cv_prog_cc_shlib"
-wl="$lt_cv_prog_cc_wl"
-link_static_flag="$lt_cv_prog_cc_static"
-no_builtin_flag="$lt_cv_prog_cc_no_builtin"
-can_build_shared="$lt_cv_prog_cc_can_build_shared"
-##
-## END FIXME
-
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
 
-## FIXME: this should be a separate macro
-##
-# Check to see if options -o and -c are simultaneously supported by compiler
-AC_MSG_CHECKING([if $compiler supports -c -o file.$ac_objext])
-AC_CACHE_VAL([lt_cv_compiler_c_o], [
-$rm -r conftest 2>/dev/null
-mkdir conftest
-cd conftest
-echo "int some_variable = 0;" > conftest.$ac_ext
-mkdir out
-# According to Tom Tromey, Ian Lance Taylor reported there are C compilers
-# that will create temporary files in the current directory regardless of
-# the output directory.  Thus, making CWD read-only will cause this test
-# to fail, enabling locking or at least warning the user not to do parallel
-# builds.
-chmod -w .
-save_CFLAGS="$CFLAGS"
-CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
-compiler_c_o=no
-if { (eval echo configure:__oline__: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
-  # The compiler can only warn and ignore the option if not recognized
-  # So say no if there are warnings
-  if test -s out/conftest.err; then
-    lt_cv_compiler_c_o=no
-  else
-    lt_cv_compiler_c_o=yes
-  fi
-else
-  # Append any errors to the config.log.
-  cat out/conftest.err 1>&AC_FD_CC
-  lt_cv_compiler_c_o=no
-fi
-CFLAGS="$save_CFLAGS"
-chmod u+w .
-$rm conftest* out/*
-rmdir out
-cd ..
-rmdir conftest
-$rm -r conftest 2>/dev/null
-])
-compiler_c_o=$lt_cv_compiler_c_o
-AC_MSG_RESULT([$compiler_c_o])
-
-if test x"$compiler_c_o" = x"yes"; then
-  # Check to see if we can write to a .lo
-  AC_MSG_CHECKING([if $compiler supports -c -o file.lo])
-  AC_CACHE_VAL([lt_cv_compiler_o_lo], [
-  lt_cv_compiler_o_lo=no
-  save_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS -c -o conftest.lo"
-  save_objext="$ac_objext"
-  ac_objext=lo
-  AC_TRY_COMPILE([], [int some_variable = 0;], [dnl
-    # The compiler can only warn and ignore the option if not recognized
-    # So say no if there are warnings
-    if test -s conftest.err; then
-      lt_cv_compiler_o_lo=no
-    else
-      lt_cv_compiler_o_lo=yes
-    fi
-  ])
-  ac_objext="$save_objext"
-  CFLAGS="$save_CFLAGS"
-  ])
-  compiler_o_lo=$lt_cv_compiler_o_lo
-  AC_MSG_RESULT([$compiler_o_lo])
-else
-  compiler_o_lo=no
-fi
-##
-## END FIXME
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
 
-## FIXME: this should be a separate macro
-##
-# Check to see if we can do hard links to lock some files if needed
-hard_links="nottested"
-if test "$compiler_c_o" = no && test "$need_locks" != no; then
-  # do not overwrite the value of need_locks provided by the user
-  AC_MSG_CHECKING([if we can lock with hard links])
-  hard_links=yes
-  $rm conftest*
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  touch conftest.a
-  ln conftest.a conftest.b 2>&5 || hard_links=no
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  AC_MSG_RESULT([$hard_links])
-  if test "$hard_links" = no; then
-    AC_MSG_WARN([\`$CC' does not support \`-c -o', so \`make -j' may be unsafe])
-    need_locks=warn
-  fi
-else
-  need_locks=no
-fi
-##
-## END FIXME
+freebsd1*)
+  dynamic_linker=no
+  ;;
 
-## FIXME: this should be a separate macro
-##
-if test "$GCC" = yes; then
-  # Check to see if options -fno-rtti -fno-exceptions are supported by compiler
-  AC_MSG_CHECKING([if $compiler supports -fno-rtti -fno-exceptions])
-  echo "int some_variable = 0;" > conftest.$ac_ext
-  save_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext"
-  compiler_rtti_exceptions=no
-  AC_TRY_COMPILE([], [int some_variable = 0;], [dnl
-    # The compiler can only warn and ignore the option if not recognized
-    # So say no if there are warnings
-    if test -s conftest.err; then
-      compiler_rtti_exceptions=no
-    else
-      compiler_rtti_exceptions=yes
-    fi
-  ])
-  CFLAGS="$save_CFLAGS"
-  AC_MSG_RESULT([$compiler_rtti_exceptions])
+kfreebsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
 
-  if test "$compiler_rtti_exceptions" = "yes"; then
-    no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions'
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
   else
-    no_builtin_flag=' -fno-builtin'
-  fi
-fi
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-# See if the linker supports building shared libraries.
-AC_MSG_CHECKING([whether the linker ($LD) supports shared libraries])
-
-allow_undefined_flag=
-no_undefined_flag=
-need_lib_prefix=unknown
-need_version=unknown
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-archive_cmds=
-archive_expsym_cmds=
-old_archive_from_new_cmds=
-old_archive_from_expsyms_cmds=
-export_dynamic_flag_spec=
-whole_archive_flag_spec=
-thread_safe_flag_spec=
-hardcode_into_libs=no
-hardcode_libdir_flag_spec=
-hardcode_libdir_separator=
-hardcode_direct=no
-hardcode_minus_L=no
-hardcode_shlibpath_var=unsupported
-runpath_var=
-link_all_deplibs=unknown
-always_export_symbols=no
-export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols'
-# include_expsyms should be a list of space-separated symbols to be *always*
-# included in the symbol list
-include_expsyms=
-# exclude_expsyms can be an egrep regular expression of symbols to exclude
-# it will be wrapped by ` (' and `)$', so one must not match beginning or
-# end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
-# as well as any symbol that contains `d'.
-exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
-# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
-# platforms (ab)use it in PIC code, but their linkers get confused if
-# the symbol is explicitly referenced.  Since portable code cannot
-# rely on this symbol name, it's probably fine to never include it in
-# preloaded symbol tables.
-extract_expsyms_cmds=
-
-case $host_os in
-cygwin* | mingw* | pw32*)
-  # FIXME: the MSVC++ port hasn't been tested in a loooong time
-  # When not using gcc, we currently assume that we are using
-  # Microsoft Visual C++.
-  if test "$GCC" != yes; then
-    with_gnu_ld=no
+    case $host_os in
+    freebsd[[123]]*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
   fi
-  ;;
-openbsd*)
-  with_gnu_ld=no
-  ;;
-esac
-
-ld_shlibs=yes
-if test "$with_gnu_ld" = yes; then
-  # If archive_cmds runs LD, not CC, wlarc should be empty
-  wlarc='${wl}'
-
-  # See if GNU ld supports shared libraries.
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
   case $host_os in
-  aix3* | aix4* | aix5*)
-    # On AIX, the GNU linker is very broken
-    # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available.
-    ld_shlibs=no
-    cat <<EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.9.1, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support.  If you
-*** really care for shared libraries, you may want to modify your PATH
-*** so that a non-GNU linker is found, and then restart.
-
-EOF
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
     ;;
-
-  amigaos*)
-    archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-    hardcode_libdir_flag_spec='-L$libdir'
-    hardcode_minus_L=yes
-
-    # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
-    # that the semantics of dynamic libraries on AmigaOS, at least up
-    # to version 4, is to share data among multiple programs linked
-    # with the same dynamic library.  Since this doesn't match the
-    # behavior of shared libraries on other platforms, we can use
-    # them.
-    ld_shlibs=no
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
     ;;
-
-  beos*)
-    if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
-      allow_undefined_flag=unsupported
-      # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
-      # support --undefined.  This deserves some investigation.  FIXME
-      archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-    else
-      ld_shlibs=no
-    fi
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
     ;;
+  freebsd*) # from 4.6 on
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
 
-  cygwin* | mingw* | pw32*)
-    # hardcode_libdir_flag_spec is actually meaningless, as there is
-    # no search path for DLLs.
-    hardcode_libdir_flag_spec='-L$libdir'
-    allow_undefined_flag=unsupported
-    always_export_symbols=yes
-
-    extract_expsyms_cmds='test -f $output_objdir/impgen.c || \
-      sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~
-      test -f $output_objdir/impgen.exe || (cd $output_objdir && \
-      if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \
-      else $CC -o impgen impgen.c ; fi)~
-      $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def'
-
-    old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib'
-
-    # cygwin and mingw dlls have different entry points and sets of symbols
-    # to exclude.
-    # FIXME: what about values for MSVC?
-    dll_entry=__cygwin_dll_entry@12
-    dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~
-    case $host_os in
-    mingw*)
-      # mingw values
-      dll_entry=_DllMainCRTStartup@12
-      dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~
-      ;;
-    esac
-
-    # mingw and cygwin differ, and it's simplest to just exclude the union
-    # of the two symbol sets.
-    dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
 
-    # recent cygwin and mingw systems supply a stub DllMain which the user
-    # can override, but on older systems we have to supply one (in ltdll.c)
-    if test "x$lt_cv_need_dllmain" = "xyes"; then
-      ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext "
-      ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $''0 > $output_objdir/$soname-ltdll.c~
-       test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~'
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
     else
-      ltdll_obj=
-      ltdll_cmds=
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
     fi
-
-    # Extract the symbol export list from an `--export-all' def file,
-    # then regenerate the def file from the symbol export list, so that
-    # the compiled dll only exports the symbol export list.
-    # Be careful not to strip the DATA tag left be newer dlltools.
-    export_symbols_cmds="$ltdll_cmds"'
-      $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~
-      sed -e "1,/EXPORTS/d" -e "s/ @ [[0-9]]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols'
-
-    # If the export-symbols file already is a .def file (1st line
-    # is EXPORTS), use it as is.
-    # If DATA tags from a recent dlltool are present, honour them!
-    archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then
-       cp $export_symbols $output_objdir/$soname-def;
-      else
-       echo EXPORTS > $output_objdir/$soname-def;
-       _lt_hint=1;
-       cat $export_symbols | while read symbol; do
-        set dummy \$symbol;
-        case \[$]# in
-          2) echo "   \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;;
-          *) echo "     \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;;
-        esac;
-        _lt_hint=`expr 1 + \$_lt_hint`;
-       done;
-      fi~
-      '"$ltdll_cmds"'
-      $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
-      $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~
-      $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
-      $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~
-      $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags'
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
     ;;
-
-  netbsd*)
-    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
-      archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
-      wlarc=
-    else
-      archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-      archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-    fi
+   hppa*64*)
+     shrext_cmds='.sl'
+     hardcode_into_libs=yes
+     dynamic_linker="$host_os dld.sl"
+     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+     library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+     soname_spec='${libname}${release}${shared_ext}$major'
+     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+     ;;
+   *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
     ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
 
-  solaris* | sysv5*)
-    if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then
-      ld_shlibs=no
-      cat <<EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems.  Therefore, libtool
-*** is disabling shared libraries support.  We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer.  Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-EOF
-    elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
-      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-      archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-    else
-      ld_shlibs=no
-    fi
-    ;;
+interix3*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
 
-  sunos4*)
-    archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-    wlarc=
-    hardcode_direct=yes
-    hardcode_shlibpath_var=no
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+       if test "$lt_cv_prog_gnu_ld" = yes; then
+               version_type=linux
+       else
+               version_type=irix
+       fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
     ;;
-
   *)
-    if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
-      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-      archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
-    else
-      ld_shlibs=no
-    fi
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
     ;;
   esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
 
-  if test "$ld_shlibs" = yes; then
-    runpath_var=LD_RUN_PATH
-    hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
-    export_dynamic_flag_spec='${wl}--export-dynamic'
-    case $host_os in
-    cygwin* | mingw* | pw32*)
-      # dlltool doesn't understand --whole-archive et. al.
-      whole_archive_flag_spec=
-      ;;
-    *)
-      # ancient GNU ld didn't support --whole-archive et. al.
-      if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then
-       whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
-      else
-       whole_archive_flag_spec=
-      fi
-      ;;
-    esac
-  fi
-else
-  # PORTME fill in a description of your system's linker (not GNU ld)
-  case $host_os in
-  aix3*)
-    allow_undefined_flag=unsupported
-    always_export_symbols=yes
-    archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
-    # Note: this linker hardcodes the directories in LIBPATH if there
-    # are no directories specified by -L.
-    hardcode_minus_L=yes
-    if test "$GCC" = yes && test -z "$link_static_flag"; then
-      # Neither direct hardcoding nor static linking is supported with a
-      # broken collect2.
-      hardcode_direct=unsupported
-    fi
-    ;;
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
 
-  aix4* | aix5*)
-    if test "$host_cpu" = ia64; then
-      # On IA64, the linker does run time linking by default, so we don't
-      # have to do anything special.
-      aix_use_runtimelinking=no
-      exp_sym_flag='-Bexport'
+# This must be Linux ELF.
+linux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:,   ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+knetbsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='GNU ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+nto-qnx*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+    *)                         need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+       shlibpath_overrides_runpath=no
+       ;;
+      *)
+       shlibpath_overrides_runpath=yes
+       ;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      export_dynamic_flag_spec='${wl}-Blargedynsym'
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+    shlibpath_overrides_runpath=no
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    shlibpath_overrides_runpath=yes
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+       ;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+])# AC_LIBTOOL_SYS_DYNAMIC_LINKER
+
+
+# _LT_AC_TAGCONFIG
+# ----------------
+AC_DEFUN([_LT_AC_TAGCONFIG],
+[AC_ARG_WITH([tags],
+    [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@],
+        [include additional configurations @<:@automatic@:>@])],
+    [tagnames="$withval"])
+
+if test -f "$ltmain" && test -n "$tagnames"; then
+  if test ! -f "${ofile}"; then
+    AC_MSG_WARN([output file `$ofile' does not exist])
+  fi
+
+  if test -z "$LTCC"; then
+    eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
+    if test -z "$LTCC"; then
+      AC_MSG_WARN([output file `$ofile' does not look like a libtool script])
+    else
+      AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile'])
+    fi
+  fi
+  if test -z "$LTCFLAGS"; then
+    eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`"
+  fi
+
+  # Extract list of available tagged configurations in $ofile.
+  # Note that this assumes the entire list is on one line.
+  available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'`
+
+  lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+  for tagname in $tagnames; do
+    IFS="$lt_save_ifs"
+    # Check whether tagname contains only valid characters
+    case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in
+    "") ;;
+    *)  AC_MSG_ERROR([invalid tag name: $tagname])
+       ;;
+    esac
+
+    if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
+    then
+      AC_MSG_ERROR([tag name \"$tagname\" already exists])
+    fi
+
+    # Update the list of available tags.
+    if test -n "$tagname"; then
+      echo appending configuration tag \"$tagname\" to $ofile
+
+      case $tagname in
+      CXX)
+       if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+           ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+           (test "X$CXX" != "Xg++"))) ; then
+         AC_LIBTOOL_LANG_CXX_CONFIG
+       else
+         tagname=""
+       fi
+       ;;
+
+      F77)
+       if test -n "$F77" && test "X$F77" != "Xno"; then
+         AC_LIBTOOL_LANG_F77_CONFIG
+       else
+         tagname=""
+       fi
+       ;;
+
+      GCJ)
+       if test -n "$GCJ" && test "X$GCJ" != "Xno"; then
+         AC_LIBTOOL_LANG_GCJ_CONFIG
+       else
+         tagname=""
+       fi
+       ;;
+
+      RC)
+       AC_LIBTOOL_LANG_RC_CONFIG
+       ;;
+
+      *)
+       AC_MSG_ERROR([Unsupported tag name: $tagname])
+       ;;
+      esac
+
+      # Append the new tag name to the list of available tags.
+      if test -n "$tagname" ; then
+      available_tags="$available_tags $tagname"
+    fi
+    fi
+  done
+  IFS="$lt_save_ifs"
+
+  # Now substitute the updated list of available tags.
+  if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then
+    mv "${ofile}T" "$ofile"
+    chmod +x "$ofile"
+  else
+    rm -f "${ofile}T"
+    AC_MSG_ERROR([unable to update list of available tagged configurations.])
+  fi
+fi
+])# _LT_AC_TAGCONFIG
+
+
+# AC_LIBTOOL_DLOPEN
+# -----------------
+# enable checks for dlopen support
+AC_DEFUN([AC_LIBTOOL_DLOPEN],
+ [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_DLOPEN
+
+
+# AC_LIBTOOL_WIN32_DLL
+# --------------------
+# declare package support for building win32 DLLs
+AC_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_BEFORE([$0], [AC_LIBTOOL_SETUP])
+])# AC_LIBTOOL_WIN32_DLL
+
+
+# AC_ENABLE_SHARED([DEFAULT])
+# ---------------------------
+# implement the --enable-shared flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_SHARED],
+[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([shared],
+    [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+       [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_shared=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]AC_ENABLE_SHARED_DEFAULT)
+])# AC_ENABLE_SHARED
+
+
+# AC_DISABLE_SHARED
+# -----------------
+# set the default shared flag to --disable-shared
+AC_DEFUN([AC_DISABLE_SHARED],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_SHARED(no)
+])# AC_DISABLE_SHARED
+
+
+# AC_ENABLE_STATIC([DEFAULT])
+# ---------------------------
+# implement the --enable-static flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_STATIC],
+[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([static],
+    [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+       [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_static=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]AC_ENABLE_STATIC_DEFAULT)
+])# AC_ENABLE_STATIC
+
+
+# AC_DISABLE_STATIC
+# -----------------
+# set the default static flag to --disable-static
+AC_DEFUN([AC_DISABLE_STATIC],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_STATIC(no)
+])# AC_DISABLE_STATIC
+
+
+# AC_ENABLE_FAST_INSTALL([DEFAULT])
+# ---------------------------------
+# implement the --enable-fast-install flag
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+AC_DEFUN([AC_ENABLE_FAST_INSTALL],
+[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE([fast-install],
+    [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_fast_install=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT)
+])# AC_ENABLE_FAST_INSTALL
+
+
+# AC_DISABLE_FAST_INSTALL
+# -----------------------
+# set the default to --disable-fast-install
+AC_DEFUN([AC_DISABLE_FAST_INSTALL],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+AC_ENABLE_FAST_INSTALL(no)
+])# AC_DISABLE_FAST_INSTALL
+
+
+# AC_LIBTOOL_PICMODE([MODE])
+# --------------------------
+# implement the --with-pic flag
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+AC_DEFUN([AC_LIBTOOL_PICMODE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+pic_mode=ifelse($#,1,$1,default)
+])# AC_LIBTOOL_PICMODE
+
+
+# AC_PROG_EGREP
+# -------------
+# This is predefined starting with Autoconf 2.54, so this conditional
+# definition can be removed once we require Autoconf 2.54 or later.
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+   [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])])
+
+
+# AC_PATH_TOOL_PREFIX
+# -------------------
+# find a file program which can recognise shared library
+AC_DEFUN([AC_PATH_TOOL_PREFIX],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="ifelse([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+       case $deplibs_check_method in
+       "file_magic "*)
+         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+           $EGREP "$file_magic_regex" > /dev/null; then
+           :
+         else
+           cat <<EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+EOF
+         fi ;;
+       esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+])# AC_PATH_TOOL_PREFIX
+
+
+# AC_PATH_MAGIC
+# -------------
+# find a file program which can recognise a shared library
+AC_DEFUN([AC_PATH_MAGIC],
+[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# AC_PATH_MAGIC
+
+
+# AC_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AC_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+    [AC_HELP_STRING([--with-gnu-ld],
+       [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])
+AC_REQUIRE([LT_AC_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break
+       ;;
+      *)
+       test "$with_gnu_ld" != yes && break
+       ;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_PROG_LD_GNU
+])# AC_PROG_LD
+
+
+# AC_PROG_LD_GNU
+# --------------
+AC_DEFUN([AC_PROG_LD_GNU],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AC_PROG_LD_GNU
+
+
+# AC_PROG_LD_RELOAD_FLAG
+# ----------------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+])# AC_PROG_LD_RELOAD_FLAG
+
+
+# AC_DEPLIBS_CHECK_METHOD
+# -----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
+[AC_CACHE_CHECK([how to recognise dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix4* | aix5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump'.
+  lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | kfreebsd*-gnu | dragonfly*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix3*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+nto-qnx*)
+  lt_cv_deplibs_check_method=unknown
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+])# AC_DEPLIBS_CHECK_METHOD
+
+
+# AC_PROG_NM
+# ----------
+# find the pathname to a BSD-compatible name lister
+AC_DEFUN([AC_PROG_NM],
+[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then 
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+       # Check to see if the nm accepts a BSD-compat flag.
+       # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+       #   nm: unknown option "B" ignored
+       # Tru64's nm complains that /dev/null is an invalid object file
+       case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+       */dev/null* | *'Invalid file or object type'*)
+         lt_cv_path_NM="$tmp_nm -B"
+         break
+         ;;
+       *)
+         case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+         */dev/null*)
+           lt_cv_path_NM="$tmp_nm -p"
+           break
+           ;;
+         *)
+           lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+           continue # so that we can try to find one that supports BSD flags
+           ;;
+         esac
+         ;;
+       esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
+fi])
+NM="$lt_cv_path_NM"
+])# AC_PROG_NM
+
+
+# AC_CHECK_LIBM
+# -------------
+# check for math library
+AC_DEFUN([AC_CHECK_LIBM],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+])# AC_CHECK_LIBM
+
+
+# AC_LIBLTDL_CONVENIENCE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl convenience library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-convenience to the configure arguments.  Note that
+# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+# it is assumed to be `libltdl'.  LIBLTDL will be prefixed with
+# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/'
+# (note the single quotes!).  If your package is not flat and you're not
+# using automake, define top_builddir and top_srcdir appropriately in
+# the Makefiles.
+AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  case $enable_ltdl_convenience in
+  no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
+  "") enable_ltdl_convenience=yes
+      ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
+  esac
+  LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
+  LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_CONVENIENCE
+
+
+# AC_LIBLTDL_INSTALLABLE([DIRECTORY])
+# -----------------------------------
+# sets LIBLTDL to the link flags for the libltdl installable library and
+# LTDLINCL to the include flags for the libltdl header and adds
+# --enable-ltdl-install to the configure arguments.  Note that
+# AC_CONFIG_SUBDIRS is not called here.  If DIRECTORY is not provided,
+# and an installed libltdl is not found, it is assumed to be `libltdl'.
+# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with
+# '${top_srcdir}/' (note the single quotes!).  If your package is not
+# flat and you're not using automake, define top_builddir and top_srcdir
+# appropriately in the Makefiles.
+# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
+AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
+[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
+  AC_CHECK_LIB(ltdl, lt_dlinit,
+  [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
+  [if test x"$enable_ltdl_install" = xno; then
+     AC_MSG_WARN([libltdl not installed, but installation disabled])
+   else
+     enable_ltdl_install=yes
+   fi
+  ])
+  if test x"$enable_ltdl_install" = x"yes"; then
+    ac_configure_args="$ac_configure_args --enable-ltdl-install"
+    LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
+    LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
+  else
+    ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
+    LIBLTDL="-lltdl"
+    LTDLINCL=
+  fi
+  # For backwards non-gettext consistent compatibility...
+  INCLTDL="$LTDLINCL"
+])# AC_LIBLTDL_INSTALLABLE
+
+
+# AC_LIBTOOL_CXX
+# --------------
+# enable support for C++ libraries
+AC_DEFUN([AC_LIBTOOL_CXX],
+[AC_REQUIRE([_LT_AC_LANG_CXX])
+])# AC_LIBTOOL_CXX
+
+
+# _LT_AC_LANG_CXX
+# ---------------
+AC_DEFUN([_LT_AC_LANG_CXX],
+[AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX])
+])# _LT_AC_LANG_CXX
+
+# _LT_AC_PROG_CXXCPP
+# ------------------
+AC_DEFUN([_LT_AC_PROG_CXXCPP],
+[
+AC_REQUIRE([AC_PROG_CXX])
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+fi
+])# _LT_AC_PROG_CXXCPP
+
+# AC_LIBTOOL_F77
+# --------------
+# enable support for Fortran 77 libraries
+AC_DEFUN([AC_LIBTOOL_F77],
+[AC_REQUIRE([_LT_AC_LANG_F77])
+])# AC_LIBTOOL_F77
+
+
+# _LT_AC_LANG_F77
+# ---------------
+AC_DEFUN([_LT_AC_LANG_F77],
+[AC_REQUIRE([AC_PROG_F77])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77])
+])# _LT_AC_LANG_F77
+
+
+# AC_LIBTOOL_GCJ
+# --------------
+# enable support for GCJ libraries
+AC_DEFUN([AC_LIBTOOL_GCJ],
+[AC_REQUIRE([_LT_AC_LANG_GCJ])
+])# AC_LIBTOOL_GCJ
+
+
+# _LT_AC_LANG_GCJ
+# ---------------
+AC_DEFUN([_LT_AC_LANG_GCJ],
+[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[],
+    [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[],
+      [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])],
+        [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])],
+          [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ])
+])# _LT_AC_LANG_GCJ
+
+
+# AC_LIBTOOL_RC
+# -------------
+# enable support for Windows resource files
+AC_DEFUN([AC_LIBTOOL_RC],
+[AC_REQUIRE([LT_AC_PROG_RC])
+_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC])
+])# AC_LIBTOOL_RC
+
+
+# AC_LIBTOOL_LANG_C_CONFIG
+# ------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG])
+AC_DEFUN([_LT_AC_LANG_C_CONFIG],
+[lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}\n'
+
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+AC_LIBTOOL_SYS_LIB_STRIP
+AC_LIBTOOL_DLOPEN_SELF
+
+# Report which library types will actually be built
+AC_MSG_CHECKING([if libtool supports shared libraries])
+AC_MSG_RESULT([$can_build_shared])
+
+AC_MSG_CHECKING([whether to build shared libraries])
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case $host_os in
+aix3*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds~\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+
+aix4* | aix5*)
+  if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+    test "$enable_shared" = yes && enable_static=no
+  fi
+    ;;
+esac
+AC_MSG_RESULT([$enable_shared])
+
+AC_MSG_CHECKING([whether to build static libraries])
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+AC_MSG_RESULT([$enable_static])
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_C_CONFIG
+
+
+# AC_LIBTOOL_LANG_CXX_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)])
+AC_DEFUN([_LT_AC_LANG_CXX_CONFIG],
+[AC_LANG_PUSH(C++)
+AC_REQUIRE([AC_PROG_CXX])
+AC_REQUIRE([_LT_AC_PROG_CXXCPP])
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Dependencies to place before and after the object being linked:
+_LT_AC_TAGVAR(predep_objects, $1)=
+_LT_AC_TAGVAR(postdep_objects, $1)=
+_LT_AC_TAGVAR(predeps, $1)=
+_LT_AC_TAGVAR(postdeps, $1)=
+_LT_AC_TAGVAR(compiler_lib_search_path, $1)=
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_LD=$LD
+lt_save_GCC=$GCC
+GCC=$GXX
+lt_save_with_gnu_ld=$with_gnu_ld
+lt_save_path_LD=$lt_cv_path_LD
+if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+  lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+else
+  $as_unset lt_cv_prog_gnu_ld
+fi
+if test -n "${lt_cv_path_LDCXX+set}"; then
+  lt_cv_path_LD=$lt_cv_path_LDCXX
+else
+  $as_unset lt_cv_path_LD
+fi
+test -z "${LDCXX+set}" || LD=$LDCXX
+CC=${CXX-"c++"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# We don't want -fno-exception wen compiling C++ code, so set the
+# no_builtin_flag separately
+if test "$GXX" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+else
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+fi
+
+if test "$GXX" = yes; then
+  # Set up default GNU C++ configuration
+
+  AC_PROG_LD
+
+  # Check if GNU C++ uses GNU ld as the underlying linker, since the
+  # archiving commands below assume that GNU ld is being used.
+  if test "$with_gnu_ld" = yes; then
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+    #     investigate it a little bit more. (MM)
+    wlarc='${wl}'
+
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if eval "`$CC -print-prog-name=ld` --help 2>&1" | \
+       grep 'no-whole-archive' > /dev/null; then
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    with_gnu_ld=no
+    wlarc=
+
+    # A generic and very simple default shared library creation
+    # command for GNU C++ for the case where it uses the native
+    # linker, instead of GNU ld.  If possible, this setting should
+    # overridden to take advantage of the native linker features on
+    # the platform it is being used on.
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+  fi
+
+  # Commands to make compiler produce verbose output that lists
+  # what "hidden" libraries, object files and flags are used when
+  # linking a shared library.
+  output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+else
+  GXX=no
+  with_gnu_ld=no
+  wlarc=
+fi
+
+# PORTME: fill in a description of your system's C++ link characteristics
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+_LT_AC_TAGVAR(ld_shlibs, $1)=yes
+case $host_os in
+  aix3*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  aix4* | aix5*)
+    if test "$host_cpu" = ia64; then
+      # On IA64, the linker does run time linking by default, so we don't
+      # have to do anything special.
+      aix_use_runtimelinking=no
+      exp_sym_flag='-Bexport'
       no_entry_flag=""
     else
       aix_use_runtimelinking=no
@@ -1462,11 +2884,14 @@ else
       # need to do runtime linking.
       case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
        for ld_flag in $LDFLAGS; do
-         if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+         case $ld_flag in
+         *-brtl*)
            aix_use_runtimelinking=yes
            break
-         fi
+           ;;
+         esac
        done
+       ;;
       esac
 
       exp_sym_flag='-bexport'
@@ -1479,34 +2904,43 @@ else
     # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
     # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
 
-    hardcode_direct=yes
-    archive_cmds=''
-    hardcode_libdir_separator=':'
-    if test "$GCC" = yes; then
+    _LT_AC_TAGVAR(archive_cmds, $1)=''
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+    if test "$GXX" = yes; then
       case $host_os in aix4.[[012]]|aix4.[[012]].*)
+      # We only want to do this on AIX 4.2 and lower, the check
+      # below for broken collect2 doesn't work under 4.3+
        collect2name=`${CC} -print-prog-name=collect2`
        if test -f "$collect2name" && \
-         strings "$collect2name" | grep resolve_lib_name >/dev/null
+          strings "$collect2name" | grep resolve_lib_name >/dev/null
        then
          # We have reworked collect2
-         hardcode_direct=yes
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
        else
          # We have old collect2
-         hardcode_direct=unsupported
+         _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
          # It fails to find uninstalled libraries when the uninstalled
          # path is not listed in the libpath.  Setting hardcode_minus_L
          # to unsupported forces relinking
-         hardcode_minus_L=yes
-         hardcode_libdir_flag_spec='-L$libdir'
-         hardcode_libdir_separator=
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
        fi
+       ;;
       esac
-
       shared_flag='-shared'
+      if test "$aix_use_runtimelinking" = yes; then
+       shared_flag="$shared_flag "'${wl}-G'
+      fi
     else
       # not using gcc
       if test "$host_cpu" = ia64; then
-       shared_flag='${wl}-G'
+       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+       # chokes on -Wl,-G. The following line is correct:
+       shared_flag='-G'
       else
        if test "$aix_use_runtimelinking" = yes; then
          shared_flag='${wl}-G'
@@ -1516,823 +2950,1011 @@ else
       fi
     fi
 
-    # It seems that -bexpall can do strange things, so it is better to
-    # generate a list of symbols to export.
-    always_export_symbols=yes
+    # It seems that -bexpall does not export symbols beginning with
+    # underscore (_), so it is better to generate a list of symbols to export.
+    _LT_AC_TAGVAR(always_export_symbols, $1)=yes
     if test "$aix_use_runtimelinking" = yes; then
       # Warning - without using the other runtime loading flags (-brtl),
       # -berok will link without error, but may produce a broken library.
-      allow_undefined_flag='-berok'
-      hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
-      archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
-    else
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+      # Determine the default libpath from the value encoded in an empty executable.
+      _LT_AC_SYS_LIBPATH_AIX
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+     else
       if test "$host_cpu" = ia64; then
-       hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
-       allow_undefined_flag="-z nodefs"
-       archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
       else
-       hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib'
+       # Determine the default libpath from the value encoded in an empty executable.
+       _LT_AC_SYS_LIBPATH_AIX
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
        # Warning - without using the other run time loading flags,
        # -berok will link without error, but may produce a broken library.
-       allow_undefined_flag='${wl}-berok'
-       # This is a bit strange, but is similar to how AIX traditionally builds
-       # it's shared libraries.
-       archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname'
+       _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+       # Exported symbols can be pulled into shared objects from archives
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+       _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+       # This is similar to how AIX traditionally builds its shared libraries.
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
       fi
     fi
     ;;
 
-  amigaos*)
-    archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-    hardcode_libdir_flag_spec='-L$libdir'
-    hardcode_minus_L=yes
-    # see comment about different semantics on the GNU ld section
-    ld_shlibs=no
+  beos*)
+    if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+      # support --undefined.  This deserves some investigation.  FIXME
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
     ;;
 
-  cygwin* | mingw* | pw32*)
-    # When not using gcc, we currently assume that we are using
-    # Microsoft Visual C++.
-    # hardcode_libdir_flag_spec is actually meaningless, as there is
-    # no search path for DLLs.
-    hardcode_libdir_flag_spec=' '
-    allow_undefined_flag=unsupported
-    # Tell ltmain to make .lib files, not .a files.
-    libext=lib
-    # FIXME: Setting linknames here is a bad hack.
-    archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames='
-    # The linker will automatically build a .lib file if we build a DLL.
-    old_archive_from_new_cmds='true'
-    # FIXME: Should let the user specify the lib program.
-    old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs'
-    fix_srcfile_path='`cygpath -w "$srcfile"`'
-    ;;
-
-  darwin* | rhapsody*)
-    case "$host_os" in
-    rhapsody* | darwin1.[[012]])
-      allow_undefined_flag='-undefined suppress'
-      ;;
-    *) # Darwin 1.3 on
-      allow_undefined_flag='-flat_namespace -undefined suppress'
-      ;;
+  chorus*)
+    case $cc_basename in
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
     esac
-    # FIXME: Relying on posixy $() will cause problems for
-    #        cross-compilation, but unfortunately the echo tests do not
-    #        yet detect zsh echo's removal of \ escapes.
-    archive_cmds='$nonopt $(test "x$module" = xyes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring'
-    # We need to add '_' to the symbols in $export_symbols first
-    #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols'
-    hardcode_direct=yes
-    hardcode_shlibpath_var=no
-    whole_archive_flag_spec='-all_load $convenience'
-    ;;
-
-  freebsd1*)
-    ld_shlibs=no
-    ;;
-
-  # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
-  # support.  Future versions do this automatically, but an explicit c++rt0.o
-  # does not break anything, and helps significantly (at the cost of a little
-  # extra space).
-  freebsd2.2*)
-    archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
-    hardcode_libdir_flag_spec='-R$libdir'
-    hardcode_direct=yes
-    hardcode_shlibpath_var=no
-    ;;
-
-  # Unfortunately, older versions of FreeBSD 2 do not have this feature.
-  freebsd2*)
-    archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-    hardcode_direct=yes
-    hardcode_minus_L=yes
-    hardcode_shlibpath_var=no
     ;;
 
-  # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
-  freebsd*)
-    archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
-    hardcode_libdir_flag_spec='-R$libdir'
-    hardcode_direct=yes
-    hardcode_shlibpath_var=no
-    ;;
+  cygwin* | mingw* | pw32*)
+    # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+    # as there is no search path for DLLs.
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+    _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+    _LT_AC_TAGVAR(always_export_symbols, $1)=no
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+    if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      # If the export-symbols file already is a .def file (1st line
+      # is EXPORTS), use it as is; otherwise, prepend...
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+       cp $export_symbols $output_objdir/$soname.def;
+      else
+       echo EXPORTS > $output_objdir/$soname.def;
+       cat $export_symbols >> $output_objdir/$soname.def;
+      fi~
+      $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+    else
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    fi
+  ;;
+      darwin* | rhapsody*)
+        case $host_os in
+        rhapsody* | darwin1.[[012]])
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+         ;;
+       *) # Darwin 1.3 on
+         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+         else
+           case ${MACOSX_DEPLOYMENT_TARGET} in
+             10.[[012]])
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+               ;;
+             10.*)
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+               ;;
+           esac
+         fi
+         ;;
+        esac
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+    if test "$GXX" = yes ; then
+      lt_int_apple_cc_single_mod=no
+      output_verbose_link_cmd='echo'
+      if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then
+       lt_int_apple_cc_single_mod=yes
+      fi
+      if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      else
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+        fi
+        _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+        # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+          if test "X$lt_int_apple_cc_single_mod" = Xyes ; then
+            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          else
+            _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          fi
+            _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      else
+      case $cc_basename in
+        xlc*)
+         output_verbose_link_cmd='echo'
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+          _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+          _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          ;;
+       *)
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+          ;;
+      esac
+      fi
+        ;;
 
-  hpux9* | hpux10* | hpux11*)
-    case $host_os in
-    hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;;
-    *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;;
+  dgux*)
+    case $cc_basename in
+      ec++*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      ghcx*)
+       # Green Hills C++ Compiler
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
     esac
-    hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
-    hardcode_libdir_separator=:
-    hardcode_direct=yes
-    hardcode_minus_L=yes # Not in the search PATH, but as the default
-                        # location of the library.
-    export_dynamic_flag_spec='${wl}-E'
     ;;
-
-  irix5* | irix6*)
-    if test "$GCC" = yes; then
-      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-    else
-      archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
-    fi
-    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
-    hardcode_libdir_separator=:
-    link_all_deplibs=yes
+  freebsd[[12]]*)
+    # C++ shared libraries reported to be fairly broken before switch to ELF
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
     ;;
-
-  netbsd*)
-    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
-      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
-    else
-      archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
-    fi
-    hardcode_libdir_flag_spec='-R$libdir'
-    hardcode_direct=yes
-    hardcode_shlibpath_var=no
+  freebsd-elf*)
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
     ;;
-
-  newsos6)
-    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-    hardcode_direct=yes
-    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
-    hardcode_libdir_separator=:
-    hardcode_shlibpath_var=no
+  freebsd* | kfreebsd*-gnu | dragonfly*)
+    # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+    # conventions
+    _LT_AC_TAGVAR(ld_shlibs, $1)=yes
     ;;
-
-  openbsd*)
-    hardcode_direct=yes
-    hardcode_shlibpath_var=no
-    if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-      archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags'
-      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
-      export_dynamic_flag_spec='${wl}-E'
-    else
-      case "$host_os" in
-      openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
-       archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-       hardcode_libdir_flag_spec='-R$libdir'
+  gnu*)
+    ;;
+  hpux9*)
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                               # but as the default
+                               # location of the library.
+
+    case $cc_basename in
+    CC*)
+      # FIXME: insert proper C++ library support
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    aCC*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      #
+      # There doesn't appear to be a way to prevent this compiler from
+      # explicitly linking system object files so we need to strip them
+      # from the output so that they don't get included in the library
+      # dependencies.
+      output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+      ;;
+    *)
+      if test "$GXX" = yes; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+        # FIXME: insert proper C++ library support
+        _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+    ;;
+  hpux10*|hpux11*)
+    if test $with_gnu_ld = no; then
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+      case $host_cpu in
+      hppa*64*|ia64*)
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
         ;;
       *)
-        archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags'
-        hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
         ;;
       esac
     fi
-    ;;
-
-  os2*)
-    hardcode_libdir_flag_spec='-L$libdir'
-    hardcode_minus_L=yes
-    allow_undefined_flag=unsupported
-    archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
-    old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
-    ;;
-
-  osf3*)
-    if test "$GCC" = yes; then
-      allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
-      archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-    else
-      allow_undefined_flag=' -expect_unresolved \*'
-      archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
-    fi
-    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
-    hardcode_libdir_separator=:
-    ;;
-
-  osf4* | osf5*)       # as osf3* with the addition of -msym flag
-    if test "$GCC" = yes; then
-      allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
-      archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
-    else
-      allow_undefined_flag=' -expect_unresolved \*'
-      archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
-      archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
-      $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
-
-      #Both c and cxx compiler support -rpath directly
-      hardcode_libdir_flag_spec='-rpath $libdir'
-    fi
-    hardcode_libdir_separator=:
-    ;;
-
-  sco3.2v5*)
-    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-    hardcode_shlibpath_var=no
-    runpath_var=LD_RUN_PATH
-    hardcode_runpath_var=yes
-    export_dynamic_flag_spec='${wl}-Bexport'
-    ;;
-
-  solaris*)
-    # gcc --version < 3.0 without binutils cannot create self contained
-    # shared libraries reliably, requiring libgcc.a to resolve some of
-    # the object symbols generated in some cases.  Libraries that use
-    # assert need libgcc.a to resolve __eprintf, for example.  Linking
-    # a copy of libgcc.a into every shared library to guarantee resolving
-    # such symbols causes other problems:  According to Tim Van Holder
-    # <tim.van.holder@pandora.be>, C++ libraries end up with a separate
-    # (to the application) exception stack for one thing.
-    no_undefined_flag=' -z defs'
-    if test "$GCC" = yes; then
-      case `$CC --version 2>/dev/null` in
-      [[12]].*)
-       cat <<EOF 1>&2
-
-*** Warning: Releases of GCC earlier than version 3.0 cannot reliably
-*** create self contained shared libraries on Solaris systems, without
-*** introducing a dependency on libgcc.a.  Therefore, libtool is disabling
-*** -no-undefined support, which will at least allow you to build shared
-*** libraries.  However, you may find that when you link such libraries
-*** into an application without using GCC, you have to manually add
-*** \`gcc --print-libgcc-file-name\` to the link command.  We urge you to
-*** upgrade to a newer version of GCC.  Another option is to rebuild your
-*** current GCC to use the GNU linker from GNU binutils 2.9.1 or newer.
+    case $host_cpu in
+    hppa*64*|ia64*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+    *)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                                             # but as the default
+                                             # location of the library.
+      ;;
+    esac
 
-EOF
-        no_undefined_flag=
+    case $cc_basename in
+      CC*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      aCC*)
+       case $host_cpu in
+       hppa*64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+         ;;
+       ia64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+         ;;
+       esac
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+      *)
+       if test "$GXX" = yes; then
+         if test $with_gnu_ld = no; then
+           case $host_cpu in
+           hppa*64*)
+             _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+             ;;
+           ia64*)
+             _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+             ;;
+           *)
+             _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+             ;;
+           esac
+         fi
+       else
+         # FIXME: insert proper C++ library support
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
        ;;
-      esac
-    fi
-    # $CC -shared without GNU ld will not create a library from C++
-    # object files and a static libstdc++, better avoid it by now
-    archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
-    archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
-               $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
-    hardcode_libdir_flag_spec='-R$libdir'
-    hardcode_shlibpath_var=no
-    case $host_os in
-    solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-    *) # Supported since Solaris 2.6 (maybe 2.5.1?)
-      whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
     esac
-    link_all_deplibs=yes
     ;;
-
-  sunos4*)
-    if test "x$host_vendor" = xsequent; then
-      # Use $CC to link under sequent, because it throws in some extra .o
-      # files that make .init and .fini sections work.
-      archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
-    else
-      archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
-    fi
-    hardcode_libdir_flag_spec='-L$libdir'
-    hardcode_direct=yes
-    hardcode_minus_L=yes
-    hardcode_shlibpath_var=no
+  interix3*)
+    _LT_AC_TAGVAR(hardcode_direct, $1)=no
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+    # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+    # Instead, shared libraries are loaded at an image base (0x10000000 by
+    # default) and relocated if they conflict, which is a slow very memory
+    # consuming and fragmenting process.  To avoid this, we pick a random,
+    # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+    # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
     ;;
-
-  sysv4)
-    if test "x$host_vendor" = xsno; then
-      archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      hardcode_direct=yes # is this really true???
-    else
-      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      hardcode_direct=no #Motorola manual says yes, but my tests say they lie
-    fi
-    runpath_var='LD_RUN_PATH'
-    hardcode_shlibpath_var=no
+  irix5* | irix6*)
+    case $cc_basename in
+      CC*)
+       # SGI C++
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+       # Archives containing C++ object files must be created using
+       # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+       # necessary to make sure instantiated templates are included
+       # in the archive.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+       ;;
+      *)
+       if test "$GXX" = yes; then
+         if test "$with_gnu_ld" = no; then
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+         else
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib'
+         fi
+       fi
+       _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+       ;;
+    esac
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
     ;;
-
-  sysv4.3*)
-    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-    hardcode_shlibpath_var=no
-    export_dynamic_flag_spec='-Bexport'
+  linux*)
+    case $cc_basename in
+      KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+       # KCC will only create a shared library if the output file
+       # ends with ".so" (or ".sl" for HP-UX), so rename the library
+       # to its proper name (with version) after linking.
+       _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+       # Archives containing C++ object files must be created using
+       # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+       ;;
+      icpc*)
+       # Intel C++
+       with_gnu_ld=yes
+       # version 8.0 and above of icpc choke on multiply defined symbols
+       # if we add $predep_objects and $postdep_objects, however 7.1 and
+       # earlier do not add the objects themselves.
+       case `$CC -V 2>&1` in
+       *"Version 7."*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         ;;
+       *)  # Version 8.0 or newer
+         tmp_idyn=
+         case $host_cpu in
+           ia64*) tmp_idyn=' -i_dynamic';;
+         esac
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         ;;
+       esac
+       _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+       ;;
+      pgCC*)
+        # Portland Group C++ compiler
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+        ;;
+      cxx*)
+       # Compaq C++
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+       runpath_var=LD_RUN_PATH
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+    esac
     ;;
-
-  sysv5*)
-    no_undefined_flag=' -z text'
-    # $CC -shared without GNU ld will not create a library from C++
-    # object files and a static libstdc++, better avoid it by now
-    archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
-    archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
-               $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
-    hardcode_libdir_flag_spec=
-    hardcode_shlibpath_var=no
-    runpath_var='LD_RUN_PATH'
+  lynxos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
     ;;
-
-  uts4*)
-    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-    hardcode_libdir_flag_spec='-L$libdir'
-    hardcode_shlibpath_var=no
+  m88k*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
     ;;
-
-  dgux*)
-    archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-    hardcode_libdir_flag_spec='-L$libdir'
-    hardcode_shlibpath_var=no
+  mvs*)
+    case $cc_basename in
+      cxx*)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
     ;;
-
-  sysv4*MP*)
-    if test -d /usr/nec; then
-      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      hardcode_shlibpath_var=no
-      runpath_var=LD_RUN_PATH
-      hardcode_runpath_var=yes
-      ld_shlibs=yes
+  netbsd*)
+    if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
     fi
+    # Workaround some broken pre-1.5 toolchains
+    output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
     ;;
-
-  sysv4.2uw2*)
-    archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
-    hardcode_direct=yes
-    hardcode_minus_L=no
-    hardcode_shlibpath_var=no
-    hardcode_runpath_var=yes
-    runpath_var=LD_RUN_PATH
+  openbsd2*)
+    # C++ shared libraries are fairly broken
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
     ;;
-
-  sysv5uw7* | unixware7*)
-    no_undefined_flag='${wl}-z ${wl}text'
-    if test "$GCC" = yes; then
-      archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
-    else
-      archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+  openbsd*)
+    _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+    if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
     fi
-    runpath_var='LD_RUN_PATH'
-    hardcode_shlibpath_var=no
-    ;;
-
-  *)
-    ld_shlibs=no
+    output_verbose_link_cmd='echo'
     ;;
-  esac
-fi
-AC_MSG_RESULT([$ld_shlibs])
-test "$ld_shlibs" = no && can_build_shared=no
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-# Check hardcoding attributes.
-AC_MSG_CHECKING([how to hardcode library paths into programs])
-hardcode_action=
-if test -n "$hardcode_libdir_flag_spec" || \
-   test -n "$runpath_var"; then
+  osf3*)
+    case $cc_basename in
+      KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
 
-  # We can hardcode non-existant directories.
-  if test "$hardcode_direct" != no &&
-     # If the only mechanism to avoid hardcoding is shlibpath_var, we
-     # have to relink, otherwise we might link with an installed library
-     # when we should be linking with a yet-to-be-installed one
-     ## test "$hardcode_shlibpath_var" != no &&
-     test "$hardcode_minus_L" != no; then
-    # Linking always hardcodes the temporary library directory.
-    hardcode_action=relink
-  else
-    # We can link without hardcoding, and we can hardcode nonexisting dirs.
-    hardcode_action=immediate
-  fi
-else
-  # We cannot hardcode anything, or else we can only hardcode existing
-  # directories.
-  hardcode_action=unsupported
-fi
-AC_MSG_RESULT([$hardcode_action])
-##
-## END FIXME
+       # KCC will only create a shared library if the output file
+       # ends with ".so" (or ".sl" for HP-UX), so rename the library
+       # to its proper name (with version) after linking.
+       _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
 
-## FIXME: this should be a separate macro
-##
-striplib=
-old_striplib=
-AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
-  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
-  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
-  AC_MSG_RESULT([yes])
-else
-  AC_MSG_RESULT([no])
-fi
-##
-## END FIXME
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
 
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
+       # Archives containing C++ object files must be created using
+       # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
 
-## FIXME: this should be a separate macro
-##
-# PORTME Fill in your ld.so characteristics
-AC_MSG_CHECKING([dynamic linker characteristics])
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+       ;;
+      RCC*)
+       # Rational C++ 2.4.1
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      cxx*)
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+      *)
+       if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
 
-case $host_os in
-aix3*)
-  version_type=linux
-  library_names_spec='${libname}${release}.so$versuffix $libname.a'
-  shlibpath_var=LIBPATH
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
 
-  # AIX has no versioning support, so we append a major version to the name.
-  soname_spec='${libname}${release}.so$major'
-  ;;
+         # Commands to make compiler produce verbose output that lists
+         # what "hidden" libraries, object files and flags are used when
+         # linking a shared library.
+         output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
 
-aix4* | aix5*)
-  version_type=linux
-  if test "$host_cpu" = ia64; then
-    # AIX 5 supports IA64
-    library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so'
-    shlibpath_var=LD_LIBRARY_PATH
-  else
-    # With GCC up to 2.95.x, collect2 would create an import file
-    # for dependence libraries.  The import file would start with
-    # the line `#! .'.  This would cause the generated library to
-    # depend on `.', always an invalid library.  This was fixed in
-    # development snapshots of GCC prior to 3.0.
-    case $host_os in
-      aix4 | aix4.[[01]] | aix4.[[01]].*)
-       if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
-            echo ' yes '
-            echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
-         :
        else
-         can_build_shared=no
+         # FIXME: insert proper C++ library support
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
        fi
        ;;
     esac
-    # AIX (on Power*) has no versioning support, so currently we can
-    # not hardcode correct soname into executable. Probably we can
-    # add versioning support to collect2, so additional links can
-    # be useful in future.
-    if test "$aix_use_runtimelinking" = yes; then
-      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
-      # instead of lib<name>.a to let people know that these are not
-      # typical AIX shared libraries.
-      library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
-    else
-      # We preserve .a as extension for shared libraries through AIX4.2
-      # and later when we are not doing run time linking.
-      library_names_spec='${libname}${release}.a $libname.a'
-      soname_spec='${libname}${release}.so$major'
-    fi
-    shlibpath_var=LIBPATH
-  fi
-  ;;
-
-amigaos*)
-  library_names_spec='$libname.ixlibrary $libname.a'
-  # Create ${libname}_ixlibrary.a entries in /sys/libs.
-  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done'
-  ;;
-
-beos*)
-  library_names_spec='${libname}.so'
-  dynamic_linker="$host_os ld.so"
-  shlibpath_var=LIBRARY_PATH
-  ;;
-
-bsdi4*)
-  version_type=linux
-  need_version=no
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
-  soname_spec='${libname}${release}.so$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
-  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
-  export_dynamic_flag_spec=-rdynamic
-  # the default ld.so.conf also contains /usr/contrib/lib and
-  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
-  # libtool to hard-code these into programs
-  ;;
-
-cygwin* | mingw* | pw32*)
-  version_type=windows
-  need_version=no
-  need_lib_prefix=no
-  case $GCC,$host_os in
-  yes,cygwin*)
-    library_names_spec='$libname.dll.a'
-    soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll'
-    postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~
-      dldir=$destdir/`dirname \$dlpath`~
-      test -d \$dldir || mkdir -p \$dldir~
-      $install_prog .libs/$dlname \$dldir/$dlname'
-    postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~
-      dlpath=$dir/\$dldll~
-       $rm \$dlpath'
-    ;;
-  yes,mingw*)
-    library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll'
-    sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"`
-    ;;
-  yes,pw32*)
-    library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll'
-    ;;
-  *)
-    library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll $libname.lib'
-    ;;
-  esac
-  dynamic_linker='Win32 ld.exe'
-  # FIXME: first we should search . and the directory the executable is in
-  shlibpath_var=PATH
-  ;;
-
-darwin* | rhapsody*)
-  dynamic_linker="$host_os dyld"
-  version_type=darwin
-  need_lib_prefix=no
-  need_version=no
-  # FIXME: Relying on posixy $() will cause problems for
-  #        cross-compilation, but unfortunately the echo tests do not
-  #        yet detect zsh echo's removal of \ escapes.
-  library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)'
-  soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)'
-  shlibpath_overrides_runpath=yes
-  shlibpath_var=DYLD_LIBRARY_PATH
-  ;;
-
-freebsd1*)
-  dynamic_linker=no
-  ;;
-
-freebsd*)
-  objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
-  version_type=freebsd-$objformat
-  case $version_type in
-    freebsd-elf*)
-      library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
-      need_version=no
-      need_lib_prefix=no
-      ;;
-    freebsd-*)
-      library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix'
-      need_version=yes
-      ;;
-  esac
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_os in
-  freebsd2*)
-    shlibpath_overrides_runpath=yes
-    ;;
-  *)
-    shlibpath_overrides_runpath=no
-    hardcode_into_libs=yes
     ;;
-  esac
-  ;;
-
-gnu*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so'
-  soname_spec='${libname}${release}.so$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  hardcode_into_libs=yes
-  ;;
+  osf4* | osf5*)
+    case $cc_basename in
+      KCC*)
+       # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+       # KCC will only create a shared library if the output file
+       # ends with ".so" (or ".sl" for HP-UX), so rename the library
+       # to its proper name (with version) after linking.
+       _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Archives containing C++ object files must be created using
+       # the KAI C++ compiler.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs'
+       ;;
+      RCC*)
+       # Rational C++ 2.4.1
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      cxx*)
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+         echo "-hidden">> $lib.exp~
+         $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp  `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~
+         $rm $lib.exp'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       # Commands to make compiler produce verbose output that lists
+       # what "hidden" libraries, object files and flags are used when
+       # linking a shared library.
+       #
+       # There doesn't appear to be a way to prevent this compiler from
+       # explicitly linking system object files so we need to strip them
+       # from the output so that they don't get included in the library
+       # dependencies.
+       output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list'
+       ;;
+      *)
+       if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
 
-hpux9* | hpux10* | hpux11*)
-  # Give a soname corresponding to the major version so that dld.sl refuses to
-  # link against other versions.
-  dynamic_linker="$host_os dld.sl"
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  shlibpath_var=SHLIB_PATH
-  shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
-  library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl'
-  soname_spec='${libname}${release}.sl$major'
-  # HP-UX runs *really* slowly unless shared libraries are mode 555.
-  postinstall_cmds='chmod 555 $lib'
-  ;;
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
 
-irix5* | irix6*)
-  version_type=irix
-  need_lib_prefix=no
-  need_version=no
-  soname_spec='${libname}${release}.so$major'
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so'
-  case $host_os in
-  irix5*)
-    libsuff= shlibsuff=
+         # Commands to make compiler produce verbose output that lists
+         # what "hidden" libraries, object files and flags are used when
+         # linking a shared library.
+         output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"'
+
+       else
+         # FIXME: insert proper C++ library support
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+    esac
     ;;
-  *)
-    case $LD in # libtool.m4 will add one of these switches to LD
-    *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;;
-    *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;;
-    *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;;
-    *) libsuff= shlibsuff= libmagic=never-match;;
+  psos*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  sunos4*)
+    case $cc_basename in
+      CC*)
+       # Sun C++ 4.x
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      lcc*)
+       # Lucid
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
     esac
     ;;
-  esac
-  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
-  shlibpath_overrides_runpath=no
-  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
-  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
-  ;;
+  solaris*)
+    case $cc_basename in
+      CC*)
+       # Sun C++ 4.2, 5.x and Centerline C++
+        _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes
+       _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+       $CC -G${allow_undefined_flag}  ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+       case $host_os in
+         solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+         *)
+           # The C++ compiler is used as linker so we must use $wl
+           # flag to pass the commands to the underlying system
+           # linker. We must also pass each convience library through
+           # to the system linker between allextract/defaultextract.
+           # The C++ compiler will combine linker options so we
+           # cannot just pass the convience library names through
+           # without $wl.
+           # Supported since Solaris 2.6 (maybe 2.5.1?)
+           _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract'
+           ;;
+       esac
+       _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
 
-# No shared lib support for Linux oldld, aout, or coff.
-linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*)
-  dynamic_linker=no
-  ;;
+       output_verbose_link_cmd='echo'
 
-# This must be Linux ELF.
-linux-gnu*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
-  soname_spec='${libname}${release}.so$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  # This implies no fast_install, which is unacceptable.
-  # Some rework will be needed to allow for fast_install
-  # before this can be enabled.
-  hardcode_into_libs=yes
+       # Archives containing C++ object files must be created using
+       # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+       # necessary to make sure instantiated templates are included
+       # in the archive.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+       ;;
+      gcx*)
+       # Green Hills C++ Compiler
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
 
-  # We used to test for /lib/ld.so.1 and disable shared libraries on
-  # powerpc, because MkLinux only supported shared libraries with the
-  # GNU dynamic linker.  Since this was broken with cross compilers,
-  # most powerpc-linux boxes support dynamic linking these days and
-  # people can always --disable-shared, the test was removed, and we
-  # assume the GNU/Linux dynamic linker is in use.
-  dynamic_linker='GNU/Linux ld.so'
-  ;;
+       # The C++ compiler must be used to create the archive.
+       _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+       ;;
+      *)
+       # GNU C++ compiler with Solaris linker
+       if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+         _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+         if $CC --version | grep -v '^2\.7' > /dev/null; then
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+           _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+         else
+           # g++ 2.7 appears to require `-G' NOT `-shared' on this
+           # platform.
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+           _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+               $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp'
+
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\""
+         fi
 
-netbsd*)
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
-    library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
-    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-    dynamic_linker='NetBSD (a.out) ld.so'
-  else
-    library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so'
-    soname_spec='${libname}${release}.so$major'
-    dynamic_linker='NetBSD ld.elf_so'
-  fi
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  ;;
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+       fi
+       ;;
+    esac
+    ;;
+  sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    runpath_var='LD_RUN_PATH'
 
-newsos6)
-  version_type=linux
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  ;;
+    case $cc_basename in
+      CC*)
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       ;;
+      *)
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       ;;
+    esac
+    ;;
+  sysv5* | sco3.2v5* | sco5v6*)
+    # Note: We can NOT use -z defs as we might desire, because we do not
+    # link with -lc, and that would cause any symbols used from libc to
+    # always be unresolved, which means just about no library would
+    # ever link correctly.  If we're not using GNU ld we use -z text
+    # though, which does catch some bad symbols but isn't as heavy-handed
+    # as -z defs.
+    # For security reasons, it is highly recommended that you always
+    # use absolute paths for naming shared libraries, and exclude the
+    # DT_RUNPATH tag from executables and libraries.  But doing so
+    # requires that you compile everything twice, which is a pain.
+    # So that behaviour is only enabled if SCOABSPATH is set to a
+    # non-empty value in the environment.  Most likely only useful for
+    # creating official distributions of packages.
+    # This is a hack until libtool officially supports absolute path
+    # names for shared libraries.
+    _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+    _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+    _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+    _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+    _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+    runpath_var='LD_RUN_PATH'
 
-openbsd*)
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-    case "$host_os" in
-    openbsd2.[[89]] | openbsd2.[[89]].*)
-      shlibpath_overrides_runpath=no
-      ;;
-    *)
-      shlibpath_overrides_runpath=yes
-      ;;
+    case $cc_basename in
+      CC*)
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       ;;
+      *)
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       ;;
     esac
-  else
-    shlibpath_overrides_runpath=yes
-  fi
-  library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
+    ;;
+  tandem*)
+    case $cc_basename in
+      NCC*)
+       # NonStop-UX NCC 3.20
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+      *)
+       # FIXME: insert proper C++ library support
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       ;;
+    esac
+    ;;
+  vxworks*)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+  *)
+    # FIXME: insert proper C++ library support
+    _LT_AC_TAGVAR(ld_shlibs, $1)=no
+    ;;
+esac
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_AC_TAGVAR(GCC, $1)="$GXX"
+_LT_AC_TAGVAR(LD, $1)="$LD"
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+AC_LIBTOOL_POSTDEP_PREDEP($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC=$lt_save_CC
+LDCXX=$LD
+LD=$lt_save_LD
+GCC=$lt_save_GCC
+with_gnu_ldcxx=$with_gnu_ld
+with_gnu_ld=$lt_save_with_gnu_ld
+lt_cv_path_LDCXX=$lt_cv_path_LD
+lt_cv_path_LD=$lt_save_path_LD
+lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+])# AC_LIBTOOL_LANG_CXX_CONFIG
+
+# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME])
+# ------------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+ifelse([$1],[],[cat > conftest.$ac_ext <<EOF
+int a;
+void foo (void) { a = 0; }
+EOF
+],[$1],[CXX],[cat > conftest.$ac_ext <<EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+EOF
+],[$1],[F77],[cat > conftest.$ac_ext <<EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+EOF
+],[$1],[GCJ],[cat > conftest.$ac_ext <<EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  # The `*' in the case matches for architectures that use `case' in
+  # $output_verbose_cmd can trigger glob expansion during the loop
+  # eval without this substitution.
+  output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"`
+
+  for p in `eval $output_verbose_link_cmd`; do
+    case $p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" \
+         || test $p = "-R"; then
+        prev=$p
+        continue
+       else
+        prev=
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+        case $p in
+        -L* | -R*)
+          # Internal compiler library paths should come after those
+          # provided the user.  The postdeps already come after the
+          # user supplied libs so there is no need to process them.
+          if test -z "$_LT_AC_TAGVAR(compiler_lib_search_path, $1)"; then
+            _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+          else
+            _LT_AC_TAGVAR(compiler_lib_search_path, $1)="${_LT_AC_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+          fi
+          ;;
+        # The "-l" case would never come before the object being
+        # linked, so don't bother handling this case.
+        esac
+       else
+        if test -z "$_LT_AC_TAGVAR(postdeps, $1)"; then
+          _LT_AC_TAGVAR(postdeps, $1)="${prev}${p}"
+        else
+          _LT_AC_TAGVAR(postdeps, $1)="${_LT_AC_TAGVAR(postdeps, $1)} ${prev}${p}"
+        fi
+       fi
+       ;;
+
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+        pre_test_object_deps_done=yes
+        continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+        if test -z "$_LT_AC_TAGVAR(predep_objects, $1)"; then
+          _LT_AC_TAGVAR(predep_objects, $1)="$p"
+        else
+          _LT_AC_TAGVAR(predep_objects, $1)="$_LT_AC_TAGVAR(predep_objects, $1) $p"
+        fi
+       else
+        if test -z "$_LT_AC_TAGVAR(postdep_objects, $1)"; then
+          _LT_AC_TAGVAR(postdep_objects, $1)="$p"
+        else
+          _LT_AC_TAGVAR(postdep_objects, $1)="$_LT_AC_TAGVAR(postdep_objects, $1) $p"
+        fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
 
-os2*)
-  libname_spec='$name'
-  need_lib_prefix=no
-  library_names_spec='$libname.dll $libname.a'
-  dynamic_linker='OS/2 ld.exe'
-  shlibpath_var=LIBPATH
-  ;;
+    esac
+  done
 
-osf3* | osf4* | osf5*)
-  version_type=osf
-  need_version=no
-  soname_spec='${libname}${release}.so'
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
-  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
-  ;;
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
 
-sco3.2v5*)
-  version_type=osf
-  soname_spec='${libname}${release}.so$major'
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
-  shlibpath_var=LD_LIBRARY_PATH
+$rm -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+ifelse([$1],[CXX],
+[case $host_os in
+interix3*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_AC_TAGVAR(predep_objects,$1)=
+  _LT_AC_TAGVAR(postdep_objects,$1)=
+  _LT_AC_TAGVAR(postdeps,$1)=
   ;;
 
 solaris*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
-  soname_spec='${libname}${release}.so$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  # ldd complains unless libraries are executable
-  postinstall_cmds='chmod +x $lib'
-  ;;
-
-sunos4*)
-  version_type=sunos
-  library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
-  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  if test "$with_gnu_ld" = yes; then
-    need_lib_prefix=no
-  fi
-  need_version=yes
-  ;;
-
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
-  version_type=linux
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
-  soname_spec='${libname}${release}.so$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_vendor in
-    sni)
-      shlibpath_overrides_runpath=no
-      ;;
-    motorola)
-      need_lib_prefix=no
-      need_version=no
-      shlibpath_overrides_runpath=no
-      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
-      ;;
+  case $cc_basename in
+  CC*)
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    _LT_AC_TAGVAR(postdeps,$1)='-lCstd -lCrun'
+    ;;
   esac
   ;;
+esac
+])
 
-uts4*)
-  version_type=linux
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
-  soname_spec='${libname}${release}.so$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
-
-dgux*)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
-  soname_spec='${libname}${release}.so$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
+case " $_LT_AC_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+])# AC_LIBTOOL_POSTDEP_PREDEP
 
-sysv4*MP*)
-  if test -d /usr/nec ;then
-    version_type=linux
-    library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so'
-    soname_spec='$libname.so.$major'
-    shlibpath_var=LD_LIBRARY_PATH
-  fi
-  ;;
+# AC_LIBTOOL_LANG_F77_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG], [_LT_AC_LANG_F77_CONFIG(F77)])
+AC_DEFUN([_LT_AC_LANG_F77_CONFIG],
+[AC_REQUIRE([AC_PROG_F77])
+AC_LANG_PUSH(Fortran 77)
+
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_AC_TAGVAR(allow_undefined_flag, $1)=
+_LT_AC_TAGVAR(always_export_symbols, $1)=no
+_LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_direct, $1)=no
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+_LT_AC_TAGVAR(hardcode_automatic, $1)=no
+_LT_AC_TAGVAR(module_cmds, $1)=
+_LT_AC_TAGVAR(module_expsym_cmds, $1)=
+_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_AC_TAGVAR(no_undefined_flag, $1)=
+_LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="      subroutine t\n      return\n      end\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="      program t\n      end\n"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
 
-*)
-  dynamic_linker=no
-  ;;
-esac
-AC_MSG_RESULT([$dynamic_linker])
-test "$dynamic_linker" = no && can_build_shared=no
-##
-## END FIXME
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${F77-"f77"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
 
-## FIXME: this should be a separate macro
-##
-# Report the final consequences.
 AC_MSG_CHECKING([if libtool supports shared libraries])
 AC_MSG_RESULT([$can_build_shared])
-##
-## END FIXME
 
-## FIXME: this should be a separate macro
-##
 AC_MSG_CHECKING([whether to build shared libraries])
 test "$can_build_shared" = "no" && enable_shared=no
 
 # On AIX, shared libraries and static libraries use the same namespace, and
 # are all built from PIC.
-case "$host_os" in
+case $host_os in
 aix3*)
   test "$enable_shared" = yes && enable_static=no
   if test -n "$RANLIB"; then
@@ -2340,137 +3962,218 @@ aix3*)
     postinstall_cmds='$RANLIB $lib'
   fi
   ;;
-
-aix4*)
+aix4* | aix5*)
   if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
     test "$enable_shared" = yes && enable_static=no
   fi
   ;;
 esac
 AC_MSG_RESULT([$enable_shared])
-##
-## END FIXME
 
-## FIXME: this should be a separate macro
-##
 AC_MSG_CHECKING([whether to build static libraries])
 # Make sure either enable_shared or enable_static is yes.
 test "$enable_shared" = yes || enable_static=yes
 AC_MSG_RESULT([$enable_static])
-##
-## END FIXME
 
-if test "$hardcode_action" = relink; then
-  # Fast installation is not supported
-  enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
-     test "$enable_shared" = no; then
-  # Fast installation is not necessary
-  enable_fast_install=needless
-fi
+_LT_AC_TAGVAR(GCC, $1)="$G77"
+_LT_AC_TAGVAR(LD, $1)="$LD"
 
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
-  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_POP
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_F77_CONFIG
+
+
+# AC_LIBTOOL_LANG_GCJ_CONFIG
+# --------------------------
+# Ensure that the configuration vars for the C compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG], [_LT_AC_LANG_GCJ_CONFIG(GCJ)])
+AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}\n"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }\n'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1)
+AC_LIBTOOL_PROG_COMPILER_PIC($1)
+AC_LIBTOOL_PROG_CC_C_O($1)
+AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1)
+AC_LIBTOOL_PROG_LD_SHLIBS($1)
+AC_LIBTOOL_SYS_DYNAMIC_LINKER($1)
+AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1)
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_GCJ_CONFIG
+
+
+# AC_LIBTOOL_LANG_RC_CONFIG
+# -------------------------
+# Ensure that the configuration vars for the Windows resource compiler are
+# suitably defined.  Those variables are subsequently used by
+# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'.
+AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG], [_LT_AC_LANG_RC_CONFIG(RC)])
+AC_DEFUN([_LT_AC_LANG_RC_CONFIG],
+[AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_AC_TAGVAR(objext, $1)=$objext
 
-AC_LIBTOOL_DLOPEN_SELF
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n'
 
-## FIXME: this should be a separate macro
-##
-if test "$enable_shared" = yes && test "$GCC" = yes; then
-  case $archive_cmds in
-  *'~'*)
-    # FIXME: we may have to deal with multi-command sequences.
-    ;;
-  '$CC '*)
-    # Test whether the compiler implicitly links with -lc since on some
-    # systems, -lgcc has to come before -lc. If gcc already passes -lc
-    # to ld, don't add -lc before -lgcc.
-    AC_MSG_CHECKING([whether -lc should be explicitly linked in])
-    AC_CACHE_VAL([lt_cv_archive_cmds_need_lc],
-    [$rm conftest*
-    echo 'static int dummy;' > conftest.$ac_ext
-
-    if AC_TRY_EVAL(ac_compile); then
-      soname=conftest
-      lib=conftest
-      libobjs=conftest.$ac_objext
-      deplibs=
-      wl=$lt_cv_prog_cc_wl
-      compiler_flags=-v
-      linker_flags=-v
-      verstring=
-      output_objdir=.
-      libname=conftest
-      save_allow_undefined_flag=$allow_undefined_flag
-      allow_undefined_flag=
-      if AC_TRY_EVAL(archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
-      then
-       lt_cv_archive_cmds_need_lc=no
-      else
-       lt_cv_archive_cmds_need_lc=yes
-      fi
-      allow_undefined_flag=$save_allow_undefined_flag
-    else
-      cat conftest.err 1>&5
-    fi])
-    AC_MSG_RESULT([$lt_cv_archive_cmds_need_lc])
-    ;;
-  esac
-fi
-need_lc=${lt_cv_archive_cmds_need_lc-yes}
-##
-## END FIXME
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
 
-## FIXME: this should be a separate macro
-##
-# The second clause should only fire when bootstrapping the
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_AC_SYS_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+CC=${RC-"windres"}
+compiler=$CC
+_LT_AC_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+AC_LIBTOOL_CONFIG($1)
+
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# AC_LIBTOOL_LANG_RC_CONFIG
+
+
+# AC_LIBTOOL_CONFIG([TAGNAME])
+# ----------------------------
+# If TAGNAME is not passed, then create an initial libtool script
+# with a default configuration from the untagged config vars.  Otherwise
+# add code to config.status for appending the configuration named by
+# TAGNAME from the matching tagged config vars.
+AC_DEFUN([AC_LIBTOOL_CONFIG],
+[# The else clause should only fire when bootstrapping the
 # libtool distribution, otherwise you forgot to ship ltmain.sh
 # with your package, and you will get complaints that there are
 # no rules to generate ltmain.sh.
 if test -f "$ltmain"; then
-  :
-else
-  # If there is no Makefile yet, we rely on a make rule to execute
-  # `config.status --recheck' to rerun these tests and create the
-  # libtool script then.
-  test -f Makefile && make "$ltmain"
-fi
-
-if test -f "$ltmain"; then
-  trap "$rm \"${ofile}T\"; exit 1" 1 2 15
-  $rm -f "${ofile}T"
-
-  echo creating $ofile
-
+  # See if we are running on zsh, and set the options which allow our commands through
+  # without removal of \ escapes.
+  if test -n "${ZSH_VERSION+set}" ; then
+    setopt NO_GLOB_SUBST
+  fi
   # Now quote all the things that may contain metacharacters while being
   # careful not to overquote the AC_SUBSTed values.  We take copies of the
   # variables and quote the copies for generation of the libtool script.
-  for var in echo old_CC old_CFLAGS \
-    AR AR_FLAGS CC LD LN_S NM SHELL \
-    reload_flag reload_cmds wl \
-    pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \
-    thread_safe_flag_spec whole_archive_flag_spec libname_spec \
-    library_names_spec soname_spec \
-    RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \
-    old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \
-    postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \
-    old_striplib striplib file_magic_cmd export_symbols_cmds \
-    deplibs_check_method allow_undefined_flag no_undefined_flag \
-    finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \
-    global_symbol_to_c_name_address \
-    hardcode_libdir_flag_spec hardcode_libdir_separator  \
+  for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \
+    SED SHELL STRIP \
+    libname_spec library_names_spec soname_spec extract_expsyms_cmds \
+    old_striplib striplib file_magic_cmd finish_cmds finish_eval \
+    deplibs_check_method reload_flag reload_cmds need_locks \
+    lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \
+    lt_cv_sys_global_symbol_to_c_name_address \
     sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
-    compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do
+    old_postinstall_cmds old_postuninstall_cmds \
+    _LT_AC_TAGVAR(compiler, $1) \
+    _LT_AC_TAGVAR(CC, $1) \
+    _LT_AC_TAGVAR(LD, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1) \
+    _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) \
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1) \
+    _LT_AC_TAGVAR(thread_safe_flag_spec, $1) \
+    _LT_AC_TAGVAR(whole_archive_flag_spec, $1) \
+    _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) \
+    _LT_AC_TAGVAR(old_archive_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) \
+    _LT_AC_TAGVAR(predep_objects, $1) \
+    _LT_AC_TAGVAR(postdep_objects, $1) \
+    _LT_AC_TAGVAR(predeps, $1) \
+    _LT_AC_TAGVAR(postdeps, $1) \
+    _LT_AC_TAGVAR(compiler_lib_search_path, $1) \
+    _LT_AC_TAGVAR(archive_cmds, $1) \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(postinstall_cmds, $1) \
+    _LT_AC_TAGVAR(postuninstall_cmds, $1) \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) \
+    _LT_AC_TAGVAR(allow_undefined_flag, $1) \
+    _LT_AC_TAGVAR(no_undefined_flag, $1) \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) \
+    _LT_AC_TAGVAR(hardcode_libdir_separator, $1) \
+    _LT_AC_TAGVAR(hardcode_automatic, $1) \
+    _LT_AC_TAGVAR(module_cmds, $1) \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) \
+    _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) \
+    _LT_AC_TAGVAR(exclude_expsyms, $1) \
+    _LT_AC_TAGVAR(include_expsyms, $1); do
 
     case $var in
-    reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \
-    old_postinstall_cmds | old_postuninstall_cmds | \
-    export_symbols_cmds | archive_cmds | archive_expsym_cmds | \
-    extract_expsyms_cmds | old_archive_from_expsyms_cmds | \
+    _LT_AC_TAGVAR(old_archive_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_new_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_cmds, $1) | \
+    _LT_AC_TAGVAR(archive_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(module_cmds, $1) | \
+    _LT_AC_TAGVAR(module_expsym_cmds, $1) | \
+    _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) | \
+    _LT_AC_TAGVAR(export_symbols_cmds, $1) | \
+    extract_expsyms_cmds | reload_cmds | finish_cmds | \
     postinstall_cmds | postuninstall_cmds | \
-    finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
+    old_postinstall_cmds | old_postuninstall_cmds | \
+    sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
       # Double-quote double-evaled strings.
       eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
       ;;
@@ -2480,14 +4183,31 @@ if test -f "$ltmain"; then
     esac
   done
 
-  cat <<__EOF__ > "${ofile}T"
-#! $SHELL
+  case $lt_echo in
+  *'\[$]0 --fallback-echo"')
+    lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\[$]0 --fallback-echo"[$]/[$]0 --fallback-echo"/'`
+    ;;
+  esac
+
+ifelse([$1], [],
+  [cfgfile="${ofile}T"
+  trap "$rm \"$cfgfile\"; exit 1" 1 2 15
+  $rm -f "$cfgfile"
+  AC_MSG_NOTICE([creating $ofile])],
+  [cfgfile="$ofile"])
 
-# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+  cat <<__EOF__ >> "$cfgfile"
+ifelse([$1], [],
+[#! $SHELL
+
+# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
 # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
 #
-# Copyright (C) 1996-2000 Free Software Foundation, Inc.
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
 # Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
 #
 # This program is free software; you can redistribute it and/or modify
@@ -2502,21 +4222,28 @@ if test -f "$ltmain"; then
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 #
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
 # configuration script generated by Autoconf, you may include it under
 # the same distribution terms that you use for the rest of that program.
 
+# A sed program that does not truncate output.
+SED=$lt_SED
+
 # Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="sed -e s/^X//"
+Xsed="$SED -e 1s/^X//"
 
 # The HP-UX ksh and POSIX shell print the target directory to stdout
 # if CDPATH is set.
-if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# The names of the tagged configurations supported by this script.
+available_tags=
 
-# ### BEGIN LIBTOOL CONFIG
+# ### BEGIN LIBTOOL CONFIG],
+[# ### BEGIN LIBTOOL TAG CONFIG: $tagname])
 
 # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
 
@@ -2530,7 +4257,10 @@ build_libtool_libs=$enable_shared
 build_old_libs=$enable_static
 
 # Whether or not to add -lc for building shared libraries.
-build_libtool_need_lc=$need_lc
+build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)
 
 # Whether or not to optimize for fast installation.
 fast_install=$enable_fast_install
@@ -2538,6 +4268,12 @@ fast_install=$enable_fast_install
 # The host system.
 host_alias=$host_alias
 host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
 
 # An echo program that does not interpret backslashes.
 echo=$lt_echo
@@ -2546,14 +4282,23 @@ echo=$lt_echo
 AR=$lt_AR
 AR_FLAGS=$lt_AR_FLAGS
 
-# The default C compiler.
-CC=$lt_CC
+# A C compiler.
+LTCC=$lt_LTCC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_LTCFLAGS
+
+# A language-specific compiler.
+CC=$lt_[]_LT_AC_TAGVAR(compiler, $1)
 
 # Is the compiler the GNU C compiler?
-with_gcc=$GCC
+with_gcc=$_LT_AC_TAGVAR(GCC, $1)
+
+# An ERE matcher.
+EGREP=$lt_EGREP
 
 # The linker used to build libraries.
-LD=$lt_LD
+LD=$lt_[]_LT_AC_TAGVAR(LD, $1)
 
 # Whether we need hard or soft links.
 LN_S=$lt_LN_S
@@ -2562,7 +4307,7 @@ LN_S=$lt_LN_S
 NM=$lt_NM
 
 # A symbol stripping program
-STRIP=$STRIP
+STRIP=$lt_STRIP
 
 # Used to examine libraries when file_magic_cmd begins "file"
 MAGIC_CMD=$MAGIC_CMD
@@ -2584,7 +4329,7 @@ reload_flag=$lt_reload_flag
 reload_cmds=$lt_reload_cmds
 
 # How to pass a linker flag through the compiler.
-wl=$lt_wl
+wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
 
 # Object file suffix (normally "o").
 objext="$ac_objext"
@@ -2592,973 +4337,1979 @@ objext="$ac_objext"
 # Old archive suffix (normally "a").
 libext="$libext"
 
+# Shared library suffix (normally ".so").
+shrext_cmds='$shrext_cmds'
+
 # Executable file suffix (normally "").
 exeext="$exeext"
 
-# Additional compiler flags for building library objects.
-pic_flag=$lt_pic_flag
-pic_mode=$pic_mode
+# Additional compiler flags for building library objects.
+pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+pic_mode=$pic_mode
+
+# What is the maximum length of a command?
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1)
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1)
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1)
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Commands used to build and install an old-style archive.
+RANLIB=$lt_RANLIB
+old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1)
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1)
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)
+
+# Commands used to build and install a shared archive.
+archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1)
+archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1)
+postinstall_cmds=$lt_postinstall_cmds
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1)
+module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1)
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1)
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1)
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1)
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1)
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd=$lt_file_magic_cmd
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1)
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1)
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=$lt_finish_eval
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1)
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)
+
+# If ld is used when linking, flag to hardcode \$libdir into
+# a binary during linking. This must work even if \$libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1)
+
+# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1)
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1)
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1)
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="$variables_saved_for_relink"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1)
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)"
+
+# Set to yes if exported symbols are required.
+always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1)
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1)
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1)
+
+# Symbols that must always be exported.
+include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1)
+
+ifelse([$1],[],
+[# ### END LIBTOOL CONFIG],
+[# ### END LIBTOOL TAG CONFIG: $tagname])
+
+__EOF__
+
+ifelse([$1],[], [
+  case $host_os in
+  aix3*)
+    cat <<\EOF >> "$cfgfile"
+
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+EOF
+    ;;
+  esac
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" || \
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+])
+else
+  # If there is no Makefile yet, we rely on a make rule to execute
+  # `config.status --recheck' to rerun these tests and create the
+  # libtool script then.
+  ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'`
+  if test -f "$ltmain_in"; then
+    test -f Makefile && make "$ltmain"
+  fi
+fi
+])# AC_LIBTOOL_CONFIG
+
+
+# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI],
+[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl
+
+_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI
+
+
+# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
+# ---------------------------------
+AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
+[AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_NM])
+AC_REQUIRE([AC_OBJEXT])
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Transform an extracted symbol line into a proper C declaration
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*) # Its linker distinguishes data from code symbols
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+  lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  ;;
+linux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDGIRSTW]]'
+    lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+    lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (lt_ptr) \&\2},/p'"
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
 
-# Does compiler simultaneously support -c and -o options?
-compiler_c_o=$lt_compiler_c_o
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
 
-# Can we write directly to a .lo ?
-compiler_o_lo=$lt_compiler_o_lo
+# Try without a prefix undercore, then with it.
+for ac_symprfx in "" "_"; do
 
-# Must we lock files when doing compilation ?
-need_locks=$lt_need_locks
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
 
-# Do we need the lib prefix for modules?
-need_lib_prefix=$need_lib_prefix
+  # Write the raw and C identifiers.
+  lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[     ]]\($symcode$symcode*\)[[       ]][[    ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
 
-# Do we need a version for libraries?
-need_version=$need_version
+  # Check to see that the pipe works correctly.
+  pipe_works=no
 
-# Whether dlopen is supported.
-dlopen_support=$enable_dlopen
+  rm -f conftest*
+  cat > conftest.$ac_ext <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
 
-# Whether dlopen of programs is supported.
-dlopen_self=$enable_dlopen_self
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+       mv -f "$nlist"T "$nlist"
+      else
+       rm -f "$nlist"T
+      fi
 
-# Whether dlopen of statically linked programs is supported.
-dlopen_self_static=$enable_dlopen_self_static
+      # Make sure that we snagged all the symbols we need.
+      if grep ' nm_test_var$' "$nlist" >/dev/null; then
+       if grep ' nm_test_func$' "$nlist" >/dev/null; then
+         cat <<EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-# Compiler flag to prevent dynamic linking.
-link_static_flag=$lt_link_static_flag
+EOF
+         # Now generate the symbol file.
+         eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext'
 
-# Compiler flag to turn off builtin functions.
-no_builtin_flag=$lt_no_builtin_flag
+         cat <<EOF >> conftest.$ac_ext
+#if defined (__STDC__) && __STDC__
+# define lt_ptr_t void *
+#else
+# define lt_ptr_t char *
+# define const
+#endif
 
-# Compiler flag to allow reflexive dlopens.
-export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+/* The mapping between symbol names and symbols. */
+const struct {
+  const char *name;
+  lt_ptr_t address;
+}
+lt_preloaded_symbols[[]] =
+{
+EOF
+         $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext
+         cat <<\EOF >> conftest.$ac_ext
+  {0, (lt_ptr_t) 0}
+};
 
-# Compiler flag to generate shared objects directly from archives.
-whole_archive_flag_spec=$lt_whole_archive_flag_spec
+#ifdef __cplusplus
+}
+#endif
+EOF
+         # Now try linking the two files.
+         mv conftest.$ac_objext conftstm.$ac_objext
+         lt_save_LIBS="$LIBS"
+         lt_save_CFLAGS="$CFLAGS"
+         LIBS="conftstm.$ac_objext"
+         CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+         if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+           pipe_works=yes
+         fi
+         LIBS="$lt_save_LIBS"
+         CFLAGS="$lt_save_CFLAGS"
+       else
+         echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+       fi
+      else
+       echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -f conftest* conftst*
 
-# Compiler flag to generate thread-safe objects.
-thread_safe_flag_spec=$lt_thread_safe_flag_spec
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
 
-# Library versioning type.
-version_type=$version_type
 
-# Format of library name prefix.
-libname_spec=$lt_libname_spec
+# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME])
+# ---------------------------------------
+AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC],
+[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=
 
-# List of archive names.  First name is the real one, the rest are links.
-# The last name is the one that the linker finds with -lNAME.
-library_names_spec=$lt_library_names_spec
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+ ifelse([$1],[CXX],[
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
 
-# The coded name of the library, if different from the real name.
-soname_spec=$lt_soname_spec
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | os2* | pw32*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    interix3*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix4* | aix5*)
+       # All AIX code is PIC.
+       if test "$host_cpu" = ia64; then
+         # AIX 5 now supports IA64 processor
+         _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       else
+         _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+       fi
+       ;;
+      chorus*)
+       case $cc_basename in
+       cxch68*)
+         # Green Hills C++ Compiler
+         # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+         ;;
+       esac
+       ;;
+       darwin*)
+         # PIC is the default on this platform
+         # Common symbols not allowed in MH_DYLIB files
+         case $cc_basename in
+           xlc*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           ;;
+         esac
+       ;;
+      dgux*)
+       case $cc_basename in
+         ec++*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         ghcx*)
+           # Green Hills C++ Compiler
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      freebsd* | kfreebsd*-gnu | dragonfly*)
+       # FreeBSD uses GNU C++
+       ;;
+      hpux9* | hpux10* | hpux11*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+           if test "$host_cpu" != ia64; then
+             _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+           fi
+           ;;
+         aCC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+           case $host_cpu in
+           hppa*64*|ia64*)
+             # +Z the default
+             ;;
+           *)
+             _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+             ;;
+           esac
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      interix*)
+       # This is c89, which is MS Visual C++ (no shared libs)
+       # Anyone wants to do a port?
+       ;;
+      irix5* | irix6* | nonstopux*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           # CC pic flag -KPIC is the default.
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      linux*)
+       case $cc_basename in
+         KCC*)
+           # KAI C++ Compiler
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+           ;;
+         icpc* | ecpc*)
+           # Intel C++
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           ;;
+         pgCC*)
+           # Portland Group C++ compiler.
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         cxx*)
+           # Compaq C++
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      lynxos*)
+       ;;
+      m88k*)
+       ;;
+      mvs*)
+       case $cc_basename in
+         cxx*)
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      netbsd*)
+       ;;
+      osf3* | osf4* | osf5*)
+       case $cc_basename in
+         KCC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           ;;
+         RCC*)
+           # Rational C++ 2.4.1
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         cxx*)
+           # Digital/Compaq C++
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      psos*)
+       ;;
+      solaris*)
+       case $cc_basename in
+         CC*)
+           # Sun C++ 4.2, 5.x and Centerline C++
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+           ;;
+         gcx*)
+           # Green Hills C++ Compiler
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      sunos4*)
+       case $cc_basename in
+         CC*)
+           # Sun C++ 4.x
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         lcc*)
+           # Lucid
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      tandem*)
+       case $cc_basename in
+         NCC*)
+           # NonStop-UX NCC 3.20
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+       case $cc_basename in
+         CC*)
+           _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+       esac
+       ;;
+      vxworks*)
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+       ;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
 
-# Commands used to build and install an old-style archive.
-RANLIB=$lt_RANLIB
-old_archive_cmds=$lt_old_archive_cmds
-old_postinstall_cmds=$lt_old_postinstall_cmds
-old_postuninstall_cmds=$lt_old_postuninstall_cmds
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
 
-# Create an old-style archive from a shared archive.
-old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+    amigaos*)
+      # FIXME: we need at least 68020 code to build shared libraries, but
+      # adding the `-m68020' flag to GCC prevents building anything better,
+      # like `-m68040'.
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+      ;;
 
-# Create a temporary old-style archive to link instead of a shared archive.
-old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+    beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
 
-# Commands used to build and install a shared archive.
-archive_cmds=$lt_archive_cmds
-archive_expsym_cmds=$lt_archive_expsym_cmds
-postinstall_cmds=$lt_postinstall_cmds
-postuninstall_cmds=$lt_postuninstall_cmds
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
 
-# Commands to strip libraries.
-old_striplib=$lt_old_striplib
-striplib=$lt_striplib
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
 
-# Method to check whether dependent libraries are shared objects.
-deplibs_check_method=$lt_deplibs_check_method
+    interix3*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
 
-# Command to use when deplibs_check_method == file_magic.
-file_magic_cmd=$lt_file_magic_cmd
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
 
-# Flag that allows shared libraries with undefined symbols to be built.
-allow_undefined_flag=$lt_allow_undefined_flag
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
 
-# Flag that forces no undefined symbols.
-no_undefined_flag=$lt_no_undefined_flag
+    hpux*)
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
 
-# Commands used to finish a libtool library installation in a directory.
-finish_cmds=$lt_finish_cmds
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+      darwin*)
+        # PIC is the default on this platform
+        # Common symbols not allowed in MH_DYLIB files
+       case $cc_basename in
+         xlc*)
+         _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon'
+         _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         ;;
+       esac
+       ;;
+
+    mingw* | pw32* | os2*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'
+      ;;
 
-# Same as above, but a single script fragment to be evaled but not shown.
-finish_eval=$lt_finish_eval
+    hpux9* | hpux10* | hpux11*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+       ;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
 
-# Take the output of nm and produce a listing of raw symbols and C names.
-global_symbol_pipe=$lt_global_symbol_pipe
+    irix5* | irix6* | nonstopux*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
 
-# Transform the output of nm in a proper C declaration
-global_symbol_to_cdecl=$lt_global_symbol_to_cdecl
+    newsos6)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
 
-# Transform the output of nm in a C name address pair
-global_symbol_to_c_name_address=$lt_global_symbol_to_c_name_address
+    linux*)
+      case $cc_basename in
+      icc* | ecc*)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      pgcc* | pgf77* | pgf90* | pgf95*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+       # which looks to be a dead project)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      esac
+      ;;
 
-# This is the shared library runtime path variable.
-runpath_var=$runpath_var
+    osf3* | osf4* | osf5*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
 
-# This is the shared library path variable.
-shlibpath_var=$shlibpath_var
+    solaris*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95*)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+       _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
 
-# Is shlibpath searched before the hard-coded library search path?
-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+    sunos4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
 
-# How to hardcode a shared library path into an executable.
-hardcode_action=$hardcode_action
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
 
-# Whether we should hardcode library paths into libraries.
-hardcode_into_libs=$hardcode_into_libs
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+       _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+       _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
 
-# Flag to hardcode \$libdir into a binary during linking.
-# This must work even if \$libdir does not exist.
-hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
 
-# Whether we need a single -rpath flag with a separated argument.
-hardcode_libdir_separator=$lt_hardcode_libdir_separator
+    unicos*)
+      _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
 
-# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
-# resulting binary.
-hardcode_direct=$hardcode_direct
+    uts4*)
+      _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
 
-# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
-# resulting binary.
-hardcode_minus_L=$hardcode_minus_L
+    *)
+      _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)])
 
-# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
-# the resulting binary.
-hardcode_shlibpath_var=$hardcode_shlibpath_var
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works],
+    _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1),
+    [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
 
-# Variables whose values should be saved in libtool wrapper scripts and
-# restored at relink time.
-variables_saved_for_relink="$variables_saved_for_relink"
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\"
+AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=])
+])
 
-# Whether libtool must link a program against all its dependency libraries.
-link_all_deplibs=$link_all_deplibs
 
-# Compile-time system search path for libraries
-sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME])
+# ------------------------------------
+# See if the linker supports building shared libraries.
+AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS],
+[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ifelse([$1],[CXX],[
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  case $host_os in
+  aix4* | aix5*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+  ;;
+  cygwin* | mingw*)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  *)
+    _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  esac
+],[
+  runpath_var=
+  _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+  _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_AC_TAGVAR(archive_cmds, $1)=
+  _LT_AC_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)=
+  _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+  _LT_AC_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+  _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_AC_TAGVAR(hardcode_direct, $1)=no
+  _LT_AC_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_AC_TAGVAR(hardcode_automatic, $1)=no
+  _LT_AC_TAGVAR(module_cmds, $1)=
+  _LT_AC_TAGVAR(module_expsym_cmds, $1)=
+  _LT_AC_TAGVAR(always_export_symbols, $1)=no
+  _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_AC_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_"
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  extract_expsyms_cmds=
+  # Just being paranoid about ensuring that cc_basename is set.
+  _LT_CC_BASENAME([$compiler])
+  case $host_os in
+  cygwin* | mingw* | pw32*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
 
-# Run-time system search path for libraries
-sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+  _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
 
-# Fix the shell variable \$srcfile for the compiler.
-fix_srcfile_path="$fix_srcfile_path"
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+    _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      else
+       _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>/dev/null` in
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
 
-# Set to yes if exported symbols are required.
-always_export_symbols=$always_export_symbols
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix3* | aix4* | aix5*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       cat <<EOF 1>&2
 
-# The commands to list exported symbols.
-export_symbols_cmds=$lt_export_symbols_cmds
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
 
-# The commands to extract the exported symbol list from a shared archive.
-extract_expsyms_cmds=$lt_extract_expsyms_cmds
+EOF
+      fi
+      ;;
 
-# Symbols that should not be listed in the preloaded symbols.
-exclude_expsyms=$lt_exclude_expsyms
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+
+      # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
+      # that the semantics of dynamic libraries on AmigaOS, at least up
+      # to version 4, is to share data among multiple programs linked
+      # with the same dynamic library.  Since this doesn't match the
+      # behavior of shared libraries on other platforms, we can't use
+      # them.
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
 
-# Symbols that must always be exported.
-include_expsyms=$lt_include_expsyms
+    beos*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+       # support --undefined.  This deserves some investigation.  FIXME
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
 
-# ### END LIBTOOL CONFIG
+    cygwin* | mingw* | pw32*)
+      # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=no
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+       # If the export-symbols file already is a .def file (1st line
+       # is EXPORTS), use it as is; otherwise, prepend...
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+         cp $export_symbols $output_objdir/$soname.def;
+       else
+         echo EXPORTS > $output_objdir/$soname.def;
+         cat $export_symbols >> $output_objdir/$soname.def;
+       fi~
+       $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
 
-__EOF__
+    interix3*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
 
-  case $host_os in
-  aix3*)
-    cat <<\EOF >> "${ofile}T"
+    linux*)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       tmp_addflag=
+       case $cc_basename,$host_cpu in
+       pgcc*)                          # Portland Group C compiler
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag'
+         ;;
+       pgf77* | pgf90* | pgf95*)       # Portland Group f77 and f90 compilers
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag -Mnomain' ;;
+       ecc*,ia64* | icc*,ia64*)                # Intel C compiler on ia64
+         tmp_addflag=' -i_dynamic' ;;
+       efc*,ia64* | ifort*,ia64*)      # Intel Fortran compiler on ia64
+         tmp_addflag=' -i_dynamic -nofor_main' ;;
+       ifc* | ifort*)                  # Intel Fortran compiler
+         tmp_addflag=' -nofor_main' ;;
+       esac
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
 
-# AIX sometimes has problems with the GCC collect2 program.  For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
-  COLLECT_NAMES=
-  export COLLECT_NAMES
-fi
-EOF
-    ;;
-  esac
+       if test $supports_anon_versioning = yes; then
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~
+  cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+  $echo "local: *; };" >> $output_objdir/$libname.ver~
+         $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+       fi
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
 
-  case $host_os in
-  cygwin* | mingw* | pw32* | os2*)
-    cat <<'EOF' >> "${ofile}T"
-      # This is a source program that is used to create dlls on Windows
-      # Don't remove nor modify the starting and closing comments
-# /* ltdll.c starts here */
-# #define WIN32_LEAN_AND_MEAN
-# #include <windows.h>
-# #undef WIN32_LEAN_AND_MEAN
-# #include <stdio.h>
-#
-# #ifndef __CYGWIN__
-# #  ifdef __CYGWIN32__
-# #    define __CYGWIN__ __CYGWIN32__
-# #  endif
-# #endif
-#
-# #ifdef __cplusplus
-# extern "C" {
-# #endif
-# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
-# #ifdef __cplusplus
-# }
-# #endif
-#
-# #ifdef __CYGWIN__
-# #include <cygwin/cygwin_dll.h>
-# DECLARE_CYGWIN_DLL( DllMain );
-# #endif
-# HINSTANCE __hDllInstance_base;
-#
-# BOOL APIENTRY
-# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
-# {
-#   __hDllInstance_base = hInst;
-#   return TRUE;
-# }
-# /* ltdll.c ends here */
-       # This is a source program that is used to create import libraries
-       # on Windows for dlls which lack them. Don't remove nor modify the
-       # starting and closing comments
-# /* impgen.c starts here */
-# /*   Copyright (C) 1999-2000 Free Software Foundation, Inc.
-#
-#  This file is part of GNU libtool.
-#
-#  This program is free software; you can redistribute it and/or modify
-#  it under the terms of the GNU General Public License as published by
-#  the Free Software Foundation; either version 2 of the License, or
-#  (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#  */
-#
-# #include <stdio.h>           /* for printf() */
-# #include <unistd.h>          /* for open(), lseek(), read() */
-# #include <fcntl.h>           /* for O_RDONLY, O_BINARY */
-# #include <string.h>          /* for strdup() */
-#
-# /* O_BINARY isn't required (or even defined sometimes) under Unix */
-# #ifndef O_BINARY
-# #define O_BINARY 0
-# #endif
-#
-# static unsigned int
-# pe_get16 (fd, offset)
-#      int fd;
-#      int offset;
-# {
-#   unsigned char b[2];
-#   lseek (fd, offset, SEEK_SET);
-#   read (fd, b, 2);
-#   return b[0] + (b[1]<<8);
-# }
-#
-# static unsigned int
-# pe_get32 (fd, offset)
-#     int fd;
-#     int offset;
-# {
-#   unsigned char b[4];
-#   lseek (fd, offset, SEEK_SET);
-#   read (fd, b, 4);
-#   return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# static unsigned int
-# pe_as32 (ptr)
-#      void *ptr;
-# {
-#   unsigned char *b = ptr;
-#   return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# int
-# main (argc, argv)
-#     int argc;
-#     char *argv[];
-# {
-#     int dll;
-#     unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
-#     unsigned long export_rva, export_size, nsections, secptr, expptr;
-#     unsigned long name_rvas, nexp;
-#     unsigned char *expdata, *erva;
-#     char *filename, *dll_name;
-#
-#     filename = argv[1];
-#
-#     dll = open(filename, O_RDONLY|O_BINARY);
-#     if (dll < 1)
-#      return 1;
-#
-#     dll_name = filename;
-#
-#     for (i=0; filename[i]; i++)
-#      if (filename[i] == '/' || filename[i] == '\\'  || filename[i] == ':')
-#          dll_name = filename + i +1;
-#
-#     pe_header_offset = pe_get32 (dll, 0x3c);
-#     opthdr_ofs = pe_header_offset + 4 + 20;
-#     num_entries = pe_get32 (dll, opthdr_ofs + 92);
-#
-#     if (num_entries < 1) /* no exports */
-#      return 1;
-#
-#     export_rva = pe_get32 (dll, opthdr_ofs + 96);
-#     export_size = pe_get32 (dll, opthdr_ofs + 100);
-#     nsections = pe_get16 (dll, pe_header_offset + 4 +2);
-#     secptr = (pe_header_offset + 4 + 20 +
-#            pe_get16 (dll, pe_header_offset + 4 + 16));
-#
-#     expptr = 0;
-#     for (i = 0; i < nsections; i++)
-#     {
-#      char sname[8];
-#      unsigned long secptr1 = secptr + 40 * i;
-#      unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
-#      unsigned long vsize = pe_get32 (dll, secptr1 + 16);
-#      unsigned long fptr = pe_get32 (dll, secptr1 + 20);
-#      lseek(dll, secptr1, SEEK_SET);
-#      read(dll, sname, 8);
-#      if (vaddr <= export_rva && vaddr+vsize > export_rva)
-#      {
-#          expptr = fptr + (export_rva - vaddr);
-#          if (export_rva + export_size > vaddr + vsize)
-#              export_size = vsize - (export_rva - vaddr);
-#          break;
-#      }
-#     }
-#
-#     expdata = (unsigned char*)malloc(export_size);
-#     lseek (dll, expptr, SEEK_SET);
-#     read (dll, expdata, export_size);
-#     erva = expdata - export_rva;
-#
-#     nexp = pe_as32 (expdata+24);
-#     name_rvas = pe_as32 (expdata+32);
-#
-#     printf ("EXPORTS\n");
-#     for (i = 0; i<nexp; i++)
-#     {
-#      unsigned long name_rva = pe_as32 (erva+name_rvas+i*4);
-#      printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i);
-#     }
-#
-#     return 0;
-# }
-# /* impgen.c ends here */
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+       wlarc=
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
 
-EOF
-    ;;
-  esac
+    solaris*)
+      if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       cat <<EOF 1>&2
 
-  # We use sed instead of cat because bash on DJGPP gets confused if
-  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
-  # text mode, it properly converts lines to CR/LF.  This bash problem
-  # is reportedly fixed, but why not run on old versions too?
-  sed '$q' "$ltmain" >> "${ofile}T" || (rm -f "${ofile}T"; exit 1)
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
 
-  mv -f "${ofile}T" "$ofile" || \
-    (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T")
-  chmod +x "$ofile"
-fi
-##
-## END FIXME
+EOF
+      elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
 
-])# _LT_AC_LTCONFIG_HACK
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) 
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+       cat <<_LT_EOF 1>&2
 
-# AC_LIBTOOL_DLOPEN - enable checks for dlopen support
-AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])])
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
 
-# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's
-AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])])
+_LT_EOF
+       ;;
+       *)
+         if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+           _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
+           _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib'
+           _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib'
+         else
+           _LT_AC_TAGVAR(ld_shlibs, $1)=no
+         fi
+       ;;
+      esac
+      ;;
 
-# AC_ENABLE_SHARED - implement the --enable-shared flag
-# Usage: AC_ENABLE_SHARED[(DEFAULT)]
-#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
-#   `yes'.
-AC_DEFUN([AC_ENABLE_SHARED],
-[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(shared,
-changequote(<<, >>)dnl
-<<  --enable-shared[=PKGS]  build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case $enableval in
-yes) enable_shared=yes ;;
-no) enable_shared=no ;;
-*)
-  enable_shared=no
-  # Look at the argument we got.  We use all the common list separators.
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
-  for pkg in $enableval; do
-    if test "X$pkg" = "X$p"; then
-      enable_shared=yes
-    fi
-  done
-  IFS="$ac_save_ifs"
-  ;;
-esac],
-enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl
-])
+    sunos4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
 
-# AC_DISABLE_SHARED - set the default shared flag to --disable-shared
-AC_DEFUN([AC_DISABLE_SHARED],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_SHARED(no)])
+    *)
+      if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
 
-# AC_ENABLE_STATIC - implement the --enable-static flag
-# Usage: AC_ENABLE_STATIC[(DEFAULT)]
-#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
-#   `yes'.
-AC_DEFUN([AC_ENABLE_STATIC],
-[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(static,
-changequote(<<, >>)dnl
-<<  --enable-static[=PKGS]  build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case $enableval in
-yes) enable_static=yes ;;
-no) enable_static=no ;;
-*)
-  enable_static=no
-  # Look at the argument we got.  We use all the common list separators.
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
-  for pkg in $enableval; do
-    if test "X$pkg" = "X$p"; then
-      enable_static=yes
+    if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=
     fi
-  done
-  IFS="$ac_save_ifs"
-  ;;
-esac],
-enable_static=AC_ENABLE_STATIC_DEFAULT)dnl
-])
-
-# AC_DISABLE_STATIC - set the default static flag to --disable-static
-AC_DEFUN([AC_DISABLE_STATIC],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_STATIC(no)])
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+       # Neither direct hardcoding nor static linking is supported with a
+       # broken collect2.
+       _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
 
+    aix4* | aix5*)
+      if test "$host_cpu" = ia64; then
+       # On IA64, the linker does run time linking by default, so we don't
+       # have to do anything special.
+       aix_use_runtimelinking=no
+       exp_sym_flag='-Bexport'
+       no_entry_flag=""
+      else
+       # If we're using GNU nm, then we don't want the "-C" option.
+       # -C means demangle to AIX nm, but means don't demangle with GNU nm
+       if $NM -V 2>&1 | grep 'GNU' > /dev/null; then
+         _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+       else
+         _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols'
+       fi
+       aix_use_runtimelinking=no
+
+       # Test if we are trying to use run time linking or normal
+       # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+       # need to do runtime linking.
+       case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
+         for ld_flag in $LDFLAGS; do
+         if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+           aix_use_runtimelinking=yes
+           break
+         fi
+         done
+         ;;
+       esac
 
-# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag
-# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)]
-#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
-#   `yes'.
-AC_DEFUN([AC_ENABLE_FAST_INSTALL],
-[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(fast-install,
-changequote(<<, >>)dnl
-<<  --enable-fast-install[=PKGS]  optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case $enableval in
-yes) enable_fast_install=yes ;;
-no) enable_fast_install=no ;;
-*)
-  enable_fast_install=no
-  # Look at the argument we got.  We use all the common list separators.
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
-  for pkg in $enableval; do
-    if test "X$pkg" = "X$p"; then
-      enable_fast_install=yes
-    fi
-  done
-  IFS="$ac_save_ifs"
-  ;;
-esac],
-enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl
-])
+       exp_sym_flag='-bexport'
+       no_entry_flag='-bnoentry'
+      fi
 
-# AC_DISABLE_FAST_INSTALL - set the default to --disable-fast-install
-AC_DEFUN([AC_DISABLE_FAST_INSTALL],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_FAST_INSTALL(no)])
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_AC_TAGVAR(archive_cmds, $1)=''
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+
+      if test "$GCC" = yes; then
+       case $host_os in aix4.[[012]]|aix4.[[012]].*)
+       # We only want to do this on AIX 4.2 and lower, the check
+       # below for broken collect2 doesn't work under 4.3+
+         collect2name=`${CC} -print-prog-name=collect2`
+         if test -f "$collect2name" && \
+          strings "$collect2name" | grep resolve_lib_name >/dev/null
+         then
+         # We have reworked collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+         else
+         # We have old collect2
+         _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported
+         # It fails to find uninstalled libraries when the uninstalled
+         # path is not listed in the libpath.  Setting hardcode_minus_L
+         # to unsupported forces relinking
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=
+         fi
+         ;;
+       esac
+       shared_flag='-shared'
+       if test "$aix_use_runtimelinking" = yes; then
+         shared_flag="$shared_flag "'${wl}-G'
+       fi
+      else
+       # not using gcc
+       if test "$host_cpu" = ia64; then
+       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+       # chokes on -Wl,-G. The following line is correct:
+         shared_flag='-G'
+       else
+         if test "$aix_use_runtimelinking" = yes; then
+           shared_flag='${wl}-G'
+         else
+           shared_flag='${wl}-bM:SRE'
+         fi
+       fi
+      fi
 
-# AC_LIBTOOL_PICMODE - implement the --with-pic flag
-# Usage: AC_LIBTOOL_PICMODE[(MODE)]
-#   Where MODE is either `yes' or `no'.  If omitted, it defaults to
-#   `both'.
-AC_DEFUN([AC_LIBTOOL_PICMODE],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-pic_mode=ifelse($#,1,$1,default)])
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_AC_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+       # Warning - without using the other runtime loading flags (-brtl),
+       # -berok will link without error, but may produce a broken library.
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok'
+       # Determine the default libpath from the value encoded in an empty executable.
+       _LT_AC_SYS_LIBPATH_AIX
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+       else
+       if test "$host_cpu" = ia64; then
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+       else
+        # Determine the default libpath from the value encoded in an empty executable.
+        _LT_AC_SYS_LIBPATH_AIX
+        _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+         # Warning - without using the other run time loading flags,
+         # -berok will link without error, but may produce a broken library.
+         _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+         # Exported symbols can be pulled into shared objects from archives
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+         # This is similar to how AIX traditionally builds its shared libraries.
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+       fi
+      fi
+      ;;
 
+    amigaos*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      # see comment about different semantics on the GNU ld section
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
 
-# AC_PATH_TOOL_PREFIX - find a file program which can recognise shared library
-AC_DEFUN([AC_PATH_TOOL_PREFIX],
-[AC_MSG_CHECKING([for $1])
-AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
-[case $MAGIC_CMD in
-  /*)
-  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
-  ;;
-  ?:/*)
-  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path.
-  ;;
-  *)
-  ac_save_MAGIC_CMD="$MAGIC_CMD"
-  IFS="${IFS=   }"; ac_save_ifs="$IFS"; IFS=":"
-dnl $ac_dummy forces splitting on constant user-supplied paths.
-dnl POSIX.2 word splitting is done only on the output of word expansions,
-dnl not every word.  This closes a longstanding sh security hole.
-  ac_dummy="ifelse([$2], , $PATH, [$2])"
-  for ac_dir in $ac_dummy; do
-    test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/$1; then
-      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
-      if test -n "$file_magic_test_file"; then
-       case $deplibs_check_method in
-       "file_magic "*)
-         file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
-         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
-           egrep "$file_magic_regex" > /dev/null; then
-           :
-         else
-           cat <<EOF 1>&2
+    bsdi[[45]]*)
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
 
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such.  This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem.  Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
+    cygwin* | mingw* | pw32*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true'
+      # FIXME: Should let the user specify the lib program.
+      _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs'
+      _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+      _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
 
-EOF
-         fi ;;
-       esac
-      fi
-      break
+    darwin* | rhapsody*)
+      case $host_os in
+        rhapsody* | darwin1.[[012]])
+         _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress'
+         ;;
+       *) # Darwin 1.3 on
+         if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then
+           _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+         else
+           case ${MACOSX_DEPLOYMENT_TARGET} in
+             10.[[012]])
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress'
+               ;;
+             10.*)
+               _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup'
+               ;;
+           esac
+         fi
+         ;;
+      esac
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_direct, $1)=no
+      _LT_AC_TAGVAR(hardcode_automatic, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+      _LT_AC_TAGVAR(whole_archive_flag_spec, $1)=''
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+    if test "$GCC" = yes ; then
+       output_verbose_link_cmd='echo'
+        _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
+      _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+      # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+      _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    else
+      case $cc_basename in
+        xlc*)
+         output_verbose_link_cmd='echo'
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring'
+         _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
+          # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
+         _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[    ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag  -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
+          ;;
+       *)
+         _LT_AC_TAGVAR(ld_shlibs, $1)=no
+          ;;
+      esac
     fi
-  done
-  IFS="$ac_save_ifs"
-  MAGIC_CMD="$ac_save_MAGIC_CMD"
-  ;;
-esac])
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-if test -n "$MAGIC_CMD"; then
-  AC_MSG_RESULT($MAGIC_CMD)
-else
-  AC_MSG_RESULT(no)
-fi
-])
+      ;;
 
+    dgux*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
 
-# AC_PATH_MAGIC - find a file program which can recognise a shared library
-AC_DEFUN([AC_PATH_MAGIC],
-[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl
-AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin:$PATH)
-if test -z "$lt_cv_path_MAGIC_CMD"; then
-  if test -n "$ac_tool_prefix"; then
-    AC_PATH_TOOL_PREFIX(file, /usr/bin:$PATH)
-  else
-    MAGIC_CMD=:
-  fi
-fi
-])
+    freebsd1*)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
 
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
 
-# AC_PROG_LD - find the path to the GNU or non-GNU linker
-AC_DEFUN([AC_PROG_LD],
-[AC_ARG_WITH(gnu-ld,
-[  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]],
-test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl
-ac_prog=ld
-if test "$GCC" = yes; then
-  # Check if gcc -print-prog-name=ld gives a path.
-  AC_MSG_CHECKING([for ld used by GCC])
-  case $host in
-  *-*-mingw*)
-    # gcc leaves a trailing carriage return which upsets mingw
-    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
-  *)
-    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
-  esac
-  case $ac_prog in
-    # Accept absolute paths.
-    [[\\/]]* | [[A-Za-z]]:[[\\/]]*)
-      re_direlt='/[[^/]][[^/]]*/\.\./'
-      # Canonicalize the path of ld
-      ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
-      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
-       ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
-      done
-      test -z "$LD" && LD="$ac_prog"
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
       ;;
-  "")
-    # If it fails, then pretend we aren't using GCC.
-    ac_prog=ld
-    ;;
-  *)
-    # If it is relative, then search for the first ld in PATH.
-    with_gnu_ld=unknown
-    ;;
-  esac
-elif test "$with_gnu_ld" = yes; then
-  AC_MSG_CHECKING([for GNU ld])
-else
-  AC_MSG_CHECKING([for non-GNU ld])
-fi
-AC_CACHE_VAL(lt_cv_path_LD,
-[if test -z "$LD"; then
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-  for ac_dir in $PATH; do
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      lt_cv_path_LD="$ac_dir/$ac_prog"
-      # Check to see if the program is GNU ld.  I'd rather use --version,
-      # but apparently some GNU ld's only accept -v.
-      # Break only if it was the GNU/non-GNU ld that we prefer.
-      if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
-       test "$with_gnu_ld" != no && break
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | kfreebsd*-gnu | dragonfly*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
       else
-       test "$with_gnu_ld" != yes && break
+       _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
       fi
-    fi
-  done
-  IFS="$ac_save_ifs"
-else
-  lt_cv_path_LD="$LD" # Let the user override the test with a path.
-fi])
-LD="$lt_cv_path_LD"
-if test -n "$LD"; then
-  AC_MSG_RESULT($LD)
-else
-  AC_MSG_RESULT(no)
-fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
-AC_PROG_LD_GNU
-])
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
 
-# AC_PROG_LD_GNU -
-AC_DEFUN([AC_PROG_LD_GNU],
-[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
-[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
-if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
-  lt_cv_prog_gnu_ld=yes
-else
-  lt_cv_prog_gnu_ld=no
-fi])
-with_gnu_ld=$lt_cv_prog_gnu_ld
-])
+    hpux10*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
 
-# AC_PROG_LD_RELOAD_FLAG - find reload flag for linker
-#   -- PORTME Some linkers may need a different reload flag.
-AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
-[AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag,
-[lt_cv_ld_reload_flag='-r'])
-reload_flag=$lt_cv_ld_reload_flag
-test -n "$reload_flag" && reload_flag=" $reload_flag"
-])
+       _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
 
-# AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies
-#  -- PORTME fill in with the dynamic library characteristics
-AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
-[AC_CACHE_CHECK([how to recognise dependant libraries],
-lt_cv_deplibs_check_method,
-[lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given egrep regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
+       # hardcode_minus_L: Not really in the search PATH,
+       # but as the default location of the library.
+       _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
 
-case $host_os in
-aix4* | aix5*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
+    hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+       case $host_cpu in
+       hppa*64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       esac
+      else
+       case $host_cpu in
+       hppa*64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       esac
+      fi
+      if test "$with_gnu_ld" = no; then
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       case $host_cpu in
+       hppa*64*|ia64*)
+         _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no
+         _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+         ;;
+       *)
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+         _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+         # hardcode_minus_L: Not really in the search PATH,
+         # but as the default location of the library.
+         _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+         ;;
+       esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
 
-beos*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
+    netbsd*)
+      if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
 
-bsdi4*)
-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
-  lt_cv_file_magic_cmd='/usr/bin/file -L'
-  lt_cv_file_magic_test_file=/shlib/libc.so
-  ;;
+    newsos6)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
 
-cygwin* | mingw* | pw32*)
-  lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
-  lt_cv_file_magic_cmd='$OBJDUMP -f'
-  ;;
+    openbsd*)
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      else
+       case $host_os in
+        openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+          _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+          _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+          ;;
+        *)
+          _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+          _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+          ;;
+       esac
+      fi
+      ;;
 
-darwin* | rhapsody*)
-  lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library'
-  lt_cv_file_magic_cmd='/usr/bin/file -L'
-  case "$host_os" in
-  rhapsody* | darwin1.[[012]])
-    lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1`
-    ;;
-  *) # Darwin 1.3 on
-    lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib'
-    ;;
-  esac
-  ;;
+    os2*)
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
 
-freebsd*)
-  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
-    case $host_cpu in
-    i*86 )
-      # Not sure whether the presence of OpenBSD here was a mistake.
-      # Let's accept both of them until this is cleared up.
-      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library'
-      lt_cv_file_magic_cmd=/usr/bin/file
-      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+    osf3*)
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
       ;;
-    esac
-  else
-    lt_cv_deplibs_check_method=pass_all
-  fi
-  ;;
 
-gnu*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
+    osf4* | osf5*)     # as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+       _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
+       $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp'
 
-hpux10.20*|hpux11*)
-  lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
-  lt_cv_file_magic_cmd=/usr/bin/file
-  lt_cv_file_magic_test_file=/usr/lib/libc.sl
-  ;;
+       # Both c and cxx compiler support -rpath directly
+       _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
 
-irix5* | irix6*)
-  case $host_os in
-  irix5*)
-    # this will be overridden with pass_all, but let us keep it just in case
-    lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1"
-    ;;
-  *)
-    case $LD in
-    *-32|*"-32 ") libmagic=32-bit;;
-    *-n32|*"-n32 ") libmagic=N32;;
-    *-64|*"-64 ") libmagic=64-bit;;
-    *) libmagic=never-match;;
-    esac
-    # this will be overridden with pass_all, but let us keep it just in case
-    lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1"
-    ;;
-  esac
-  lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*`
-  lt_cv_deplibs_check_method=pass_all
-  ;;
+    solaris*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text'
+      if test "$GCC" = yes; then
+       wlarc='${wl}'
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+         $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp'
+      else
+       wlarc=''
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
+       $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+       # The compiler driver will combine linker options so we
+       # cannot just pass the convience library names through
+       # without $wl, iff we do not link with $LD.
+       # Luckily, gcc supports the same syntax we need for Sun Studio.
+       # Supported since Solaris 2.6 (maybe 2.5.1?)
+       case $wlarc in
+       '')
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;;
+       *)
+         _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;;
+       esac ;;
+      esac
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
 
-# This must be Linux ELF.
-linux-gnu*)
-  case $host_cpu in
-  alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* )
-    lt_cv_deplibs_check_method=pass_all ;;
-  *)
-    # glibc up to 2.1.1 does not perform some relocations on ARM
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;;
-  esac
-  lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
-  ;;
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+       # Use $CC to link under sequent, because it throws in some extra .o
+       # files that make .init and .fini sections work.
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_direct, $1)=yes
+      _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
 
-netbsd*)
-  if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so\.[[0-9]]+\.[[0-9]]+$'
-  else
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so$'
-  fi
-  ;;
+    sysv4)
+      case $host_vendor in
+       sni)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+       ;;
+       siemens)
+         ## LD is ld it makes a PLAMLIB
+         ## CC just makes a GrossModule.
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no
+        ;;
+       motorola)
+         _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+       ;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
 
-newos6*)
-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
-  lt_cv_file_magic_cmd=/usr/bin/file
-  lt_cv_file_magic_test_file=/usr/lib/libnls.so
-  ;;
+    sysv4.3*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
 
-openbsd*)
-  lt_cv_file_magic_cmd=/usr/bin/file
-  lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
-  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object'
-  else
-    lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
-  fi
-  ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+       _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+       runpath_var=LD_RUN_PATH
+       hardcode_runpath_var=yes
+       _LT_AC_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
 
-osf3* | osf4* | osf5*)
-  # this will be overridden with pass_all, but let us keep it just in case
-  lt_cv_deplibs_check_method='file_magic COFF format alpha shared library'
-  lt_cv_file_magic_test_file=/shlib/libc.so
-  lt_cv_deplibs_check_method=pass_all
-  ;;
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*)
+      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
 
-sco3.2v5*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
 
-solaris*)
-  lt_cv_deplibs_check_method=pass_all
-  lt_cv_file_magic_test_file=/lib/libc.so
-  ;;
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
+      _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_AC_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
 
-sysv5uw[[78]]* | sysv4*uw2*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
+    uts4*)
+      _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
 
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
-  case $host_vendor in
-  motorola)
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
-    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
-    ;;
-  ncr)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  sequent)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
-    ;;
-  sni)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
-    lt_cv_file_magic_test_file=/lib/libc.so
-    ;;
-  esac
-  ;;
-esac
-])
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
+    *)
+      _LT_AC_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+  fi
 ])
+AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)])
+test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
 
-
-# AC_PROG_NM - find the path to a BSD-compatible name lister
-AC_DEFUN([AC_PROG_NM],
-[AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl
-AC_MSG_CHECKING([for BSD-compatible nm])
-AC_CACHE_VAL(lt_cv_path_NM,
-[if test -n "$NM"; then
-  # Let the user override the test.
-  lt_cv_path_NM="$NM"
-else
-  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-  for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
-    test -z "$ac_dir" && ac_dir=.
-    tmp_nm=$ac_dir/${ac_tool_prefix}nm
-    if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then
-      # Check to see if the nm accepts a BSD-compat flag.
-      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
-      #   nm: unknown option "B" ignored
-      # Tru64's nm complains that /dev/null is an invalid object file
-      if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then
-       lt_cv_path_NM="$tmp_nm -B"
-       break
-      elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
-       lt_cv_path_NM="$tmp_nm -p"
-       break
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_AC_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+      $rm conftest*
+      printf "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)
+       pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1)
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=
+        if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
+        then
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no
+        else
+         _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes
+        fi
+        _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
       else
-       lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
-       continue # so that we can try to find one that supports BSD flags
+        cat conftest.err 1>&5
       fi
-    fi
-  done
-  IFS="$ac_save_ifs"
-  test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
-fi])
-NM="$lt_cv_path_NM"
-AC_MSG_RESULT([$NM])
-])
-
-# AC_CHECK_LIBM - check for math library
-AC_DEFUN([AC_CHECK_LIBM],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-LIBM=
-case $host in
-*-*-beos* | *-*-cygwin* | *-*-pw32*)
-  # These system don't have libm
-  ;;
-*-ncr-sysv4.3*)
-  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
-  AC_CHECK_LIB(m, main, LIBM="$LIBM -lm")
-  ;;
-*)
-  AC_CHECK_LIB(m, main, LIBM="-lm")
+      $rm conftest*
+      AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)])
+      ;;
+    esac
+  fi
   ;;
 esac
-])
+])# AC_LIBTOOL_PROG_LD_SHLIBS
 
-# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for
-# the libltdl convenience library and INCLTDL to the include flags for
-# the libltdl header and adds --enable-ltdl-convenience to the
-# configure arguments.  Note that LIBLTDL and INCLTDL are not
-# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called.  If DIR is not
-# provided, it is assumed to be `libltdl'.  LIBLTDL will be prefixed
-# with '${top_builddir}/' and INCLTDL will be prefixed with
-# '${top_srcdir}/' (note the single quotes!).  If your package is not
-# flat and you're not using automake, define top_builddir and
-# top_srcdir appropriately in the Makefiles.
-AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-  case $enable_ltdl_convenience in
-  no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
-  "") enable_ltdl_convenience=yes
-      ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
-  esac
-  LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
-  INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
-])
 
-# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for
-# the libltdl installable library and INCLTDL to the include flags for
-# the libltdl header and adds --enable-ltdl-install to the configure
-# arguments.  Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is
-# AC_CONFIG_SUBDIRS called.  If DIR is not provided and an installed
-# libltdl is not found, it is assumed to be `libltdl'.  LIBLTDL will
-# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed
-# with '${top_srcdir}/' (note the single quotes!).  If your package is
-# not flat and you're not using automake, define top_builddir and
-# top_srcdir appropriately in the Makefiles.
-# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
-AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-  AC_CHECK_LIB(ltdl, main,
-  [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
-  [if test x"$enable_ltdl_install" = xno; then
-     AC_MSG_WARN([libltdl not installed, but installation disabled])
-   else
-     enable_ltdl_install=yes
-   fi
-  ])
-  if test x"$enable_ltdl_install" = x"yes"; then
-    ac_configure_args="$ac_configure_args --enable-ltdl-install"
-    LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
-    INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
-  else
-    ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
-    LIBLTDL="-lltdl"
-    INCLTDL=
-  fi
-])
+# _LT_AC_FILE_LTDLL_C
+# -------------------
+# Be careful that the start marker always follows a newline.
+AC_DEFUN([_LT_AC_FILE_LTDLL_C], [
+# /* ltdll.c starts here */
+# #define WIN32_LEAN_AND_MEAN
+# #include <windows.h>
+# #undef WIN32_LEAN_AND_MEAN
+# #include <stdio.h>
+#
+# #ifndef __CYGWIN__
+# #  ifdef __CYGWIN32__
+# #    define __CYGWIN__ __CYGWIN32__
+# #  endif
+# #endif
+#
+# #ifdef __cplusplus
+# extern "C" {
+# #endif
+# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
+# #ifdef __cplusplus
+# }
+# #endif
+#
+# #ifdef __CYGWIN__
+# #include <cygwin/cygwin_dll.h>
+# DECLARE_CYGWIN_DLL( DllMain );
+# #endif
+# HINSTANCE __hDllInstance_base;
+#
+# BOOL APIENTRY
+# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
+# {
+#   __hDllInstance_base = hInst;
+#   return TRUE;
+# }
+# /* ltdll.c ends here */
+])# _LT_AC_FILE_LTDLL_C
+
+
+# _LT_AC_TAGVAR(VARNAME, [TAGNAME])
+# ---------------------------------
+AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])])
+
 
 # old names
 AC_DEFUN([AM_PROG_LIBTOOL],   [AC_PROG_LIBTOOL])
@@ -3571,3 +6322,76 @@ AC_DEFUN([AM_PROG_NM],        [AC_PROG_NM])
 
 # This is just to silence aclocal about the macro not being used
 ifelse([AC_DISABLE_FAST_INSTALL])
+
+AC_DEFUN([LT_AC_PROG_GCJ],
+[AC_CHECK_TOOL(GCJ, gcj, no)
+  test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+  AC_SUBST(GCJFLAGS)
+])
+
+AC_DEFUN([LT_AC_PROG_RC],
+[AC_CHECK_TOOL(RC, windres, no)
+])
+
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+# LT_AC_PROG_SED
+# --------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+AC_DEFUN([LT_AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_MSG_RESULT([$SED])
+])
diff --git a/src/mm/boehm-gc/ltconfig b/src/mm/boehm-gc/ltconfig
deleted file mode 100644 (file)
index 962057f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-# I could find no versions of autoconf that don't invoke ltconfig, but
-# libtool no longer includes an ltconfig.  Yuch.
index df9d05e6033c6bd44bf4f6363cd97c5649020fca..247afb3ad6df7298670f16445ac5362695262d8f 100644 (file)
 #   endif
 # endif
 
-#if defined(RS6000) || defined(POWERPC)
-# include <ucontext.h>
-#endif
-
 #if defined(__MWERKS__) && !defined(POWERPC)
 
 asm static void PushMacRegisters()
@@ -72,82 +68,21 @@ asm static void PushMacRegisters()
 # if defined(SPARC) || defined(IA64)
     /* Value returned from register flushing routine; either sp (SPARC) */
     /* or ar.bsp (IA64)                                                        */
-    word GC_save_regs_ret_val;
+    ptr_t GC_save_regs_ret_val;
 # endif
 
 /* Routine to mark from registers that are preserved by the C compiler. */
-/* This must be ported to every new architecture.  There is a generic   */
-/* version at the end, that is likely, but not guaranteed to work       */
-/* on your architecture.  Run the test_setjmp program to see whether    */
-/* there is any chance it will work.                                    */
+/* This must be ported to every new architecture.  It is noe optional, */
+/* and should not be used on platforms that are either UNIX-like, or   */
+/* require thread support.                                             */
 
-#if !defined(USE_GENERIC_PUSH_REGS) && !defined(USE_ASM_PUSH_REGS)
 #undef HAVE_PUSH_REGS
+
+#if defined(USE_ASM_PUSH_REGS)
+#  define HAVE_PUSH_REGS
+#else  /* No asm implementation */
 void GC_push_regs()
 {
-#       ifdef RT
-         register long TMP_SP; /* must be bound to r11 */
-#       endif
-
-#       ifdef VAX
-         /* VAX - generic code below does not work under 4.2 */
-         /* r1 through r5 are caller save, and therefore     */
-         /* on the stack or dead.                            */
-         asm("pushl r11");     asm("calls $1,_GC_push_one");
-         asm("pushl r10");     asm("calls $1,_GC_push_one");
-         asm("pushl r9");      asm("calls $1,_GC_push_one");
-         asm("pushl r8");      asm("calls $1,_GC_push_one");
-         asm("pushl r7");      asm("calls $1,_GC_push_one");
-         asm("pushl r6");      asm("calls $1,_GC_push_one");
-#        define HAVE_PUSH_REGS
-#       endif
-#       if defined(M68K) && (defined(SUNOS4) || defined(NEXT))
-       /*  M68K SUNOS - could be replaced by generic code */
-         /* a0, a1 and d1 are caller save          */
-         /*  and therefore are on stack or dead.   */
-       
-         asm("subqw #0x4,sp");         /* allocate word on top of stack */
-
-         asm("movl a2,sp@");   asm("jbsr _GC_push_one");
-         asm("movl a3,sp@");   asm("jbsr _GC_push_one");
-         asm("movl a4,sp@");   asm("jbsr _GC_push_one");
-         asm("movl a5,sp@");   asm("jbsr _GC_push_one");
-         /* Skip frame pointer and stack pointer */
-         asm("movl d1,sp@");   asm("jbsr _GC_push_one");
-         asm("movl d2,sp@");   asm("jbsr _GC_push_one");
-         asm("movl d3,sp@");   asm("jbsr _GC_push_one");
-         asm("movl d4,sp@");   asm("jbsr _GC_push_one");
-         asm("movl d5,sp@");   asm("jbsr _GC_push_one");
-         asm("movl d6,sp@");   asm("jbsr _GC_push_one");
-         asm("movl d7,sp@");   asm("jbsr _GC_push_one");
-
-         asm("addqw #0x4,sp");         /* put stack back where it was  */
-#        define HAVE_PUSH_REGS
-#       endif
-
-#       if defined(M68K) && defined(HP)
-       /*  M68K HP - could be replaced by generic code */
-         /* a0, a1 and d1 are caller save.  */
-       
-         asm("subq.w &0x4,%sp");       /* allocate word on top of stack */
-
-         asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
-         asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
-         asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
-         asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
-         /* Skip frame pointer and stack pointer */
-         asm("mov.l %d1,(%sp)"); asm("jsr _GC_push_one");
-         asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
-         asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
-         asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
-         asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
-         asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
-         asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
-
-         asm("addq.w &0x4,%sp");       /* put stack back where it was  */
-#        define HAVE_PUSH_REGS
-#       endif /* M68K HP */
-
 #      if defined(M68K) && defined(AMIGA)
         /*  AMIGA - could be replaced by generic code                  */
         /* a0, a1, d0 and d1 are caller save */
@@ -217,216 +152,53 @@ void GC_push_regs()
 #        define HAVE_PUSH_REGS
 #      endif   /* __MWERKS__ */
 #   endif      /* MACOS */
+}
+#endif /* !USE_ASM_PUSH_REGS */
 
-#       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(NETBSD) && defined(__ELF__)) \
-       && !(defined(OPENBSD) && defined(__ELF__)) \
-       && !(defined(BEOS) && defined(__ELF__)) \
-       && !defined(DOS4GW) && !defined(HURD)
-       /* I386 code, generic code does not appear to work */
-       /* It does appear to work under OS2, and asms dont */
-       /* This is used for some 38g UNIX variants and for CYGWIN32 */
-         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");
-#        define HAVE_PUSH_REGS
-#       endif
-
-#      if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \
-       || ( defined(I386) && defined(FREEBSD) && defined(__ELF__) ) \
-       || ( defined(I386) && defined(NETBSD) && defined(__ELF__) ) \
-       || ( defined(I386) && defined(OPENBSD) && defined(__ELF__) ) \
-       || ( defined(I386) && defined(HURD) && defined(__ELF__) ) \
-       || ( defined(I386) && defined(DGUX) )
-
-       /* This is modified for Linux with ELF (Note: _ELF_ only) */
-       /* This section handles FreeBSD with ELF. */
-       /* 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");
-#        define HAVE_PUSH_REGS
-#      endif
-
-#      if ( defined(I386) && defined(BEOS) && defined(__ELF__) )
-       /* As far as I can understand from                              */
-       /* http://www.beunited.org/articles/jbq/nasm.shtml,             */
-       /* only ebp, esi, edi and ebx are not scratch. How MMX          */
-       /* etc. registers should be treated, I have no idea.            */
-         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");
-#        define HAVE_PUSH_REGS
-#       endif
-
-#       if defined(I386) && defined(MSWIN32) && !defined(__MINGW32__) \
-          && !defined(USE_GENERIC)
-       /* I386 code, Microsoft variant         */
-         __asm  push eax
-         __asm  call GC_push_one
-         __asm  add esp,4
-         __asm  push ebx
-         __asm  call GC_push_one
-         __asm  add esp,4
-         __asm  push ecx
-         __asm  call GC_push_one
-         __asm  add esp,4
-         __asm  push edx
-         __asm  call GC_push_one
-         __asm  add esp,4
-         __asm  push ebp
-         __asm  call GC_push_one
-         __asm  add esp,4
-         __asm  push esi
-         __asm  call GC_push_one
-         __asm  add esp,4
-         __asm  push edi
-         __asm  call GC_push_one
-         __asm  add esp,4
-#        define HAVE_PUSH_REGS
-#       endif
-
-#       if defined(I386) && (defined(SVR4) || defined(SCO) || defined(SCO_ELF))
-       /* I386 code, SVR4 variant, generic code does not appear to work */
-         asm("pushl %eax");  asm("call GC_push_one"); asm("addl $4,%esp");
-         asm("pushl %ebx");  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");
-#        define HAVE_PUSH_REGS
-#       endif
-
-#       ifdef NS32K
-         asm ("movd r3, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
-         asm ("movd r4, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
-         asm ("movd r5, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
-         asm ("movd r6, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
-         asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
-#        define HAVE_PUSH_REGS
-#       endif
-
-#       if defined(SPARC)
-         GC_save_regs_ret_val = GC_save_regs_in_stack();
-#        define HAVE_PUSH_REGS
-#       endif
-
-#      ifdef RT
-           GC_push_one(TMP_SP);    /* GC_push_one from r11 */
-
-           asm("cas r11, r6, r0"); GC_push_one(TMP_SP);        /* r6 */
-           asm("cas r11, r7, r0"); GC_push_one(TMP_SP);        /* through */
-           asm("cas r11, r8, r0"); GC_push_one(TMP_SP);        /* r10 */
-           asm("cas r11, r9, r0"); GC_push_one(TMP_SP);
-           asm("cas r11, r10, r0"); GC_push_one(TMP_SP);
-
-           asm("cas r11, r12, r0"); GC_push_one(TMP_SP); /* r12 */
-           asm("cas r11, r13, r0"); GC_push_one(TMP_SP); /* through */
-           asm("cas r11, r14, r0"); GC_push_one(TMP_SP); /* r15 */
-           asm("cas r11, r15, r0"); GC_push_one(TMP_SP);
-#          define HAVE_PUSH_REGS
-#       endif
-
-#       if defined(M68K) && defined(SYSV)
-       /*  Once again similar to SUN and HP, though setjmp appears to work.
-               --Parag
-        */
-#        ifdef __GNUC__
-         asm("subqw #0x4,%sp");        /* allocate word on top of stack */
-  
-         asm("movl %a2,%sp@"); asm("jbsr GC_push_one");
-         asm("movl %a3,%sp@"); asm("jbsr GC_push_one");
-         asm("movl %a4,%sp@"); asm("jbsr GC_push_one");
-         asm("movl %a5,%sp@"); asm("jbsr GC_push_one");
-         /* Skip frame pointer and stack pointer */
-         asm("movl %d1,%sp@"); asm("jbsr GC_push_one");
-         asm("movl %d2,%sp@"); asm("jbsr GC_push_one");
-         asm("movl %d3,%sp@"); asm("jbsr GC_push_one");
-         asm("movl %d4,%sp@"); asm("jbsr GC_push_one");
-         asm("movl %d5,%sp@"); asm("jbsr GC_push_one");
-         asm("movl %d6,%sp@"); asm("jbsr GC_push_one");
-         asm("movl %d7,%sp@"); asm("jbsr GC_push_one");
-  
-         asm("addqw #0x4,%sp");        /* put stack back where it was  */
-#        define HAVE_PUSH_REGS
-#        else /* !__GNUC__*/
-         asm("subq.w &0x4,%sp");       /* allocate word on top of stack */
-  
-         asm("mov.l %a2,(%sp)"); asm("jsr GC_push_one");
-         asm("mov.l %a3,(%sp)"); asm("jsr GC_push_one");
-         asm("mov.l %a4,(%sp)"); asm("jsr GC_push_one");
-         asm("mov.l %a5,(%sp)"); asm("jsr GC_push_one");
-         /* Skip frame pointer and stack pointer */
-         asm("mov.l %d1,(%sp)"); asm("jsr GC_push_one");
-         asm("mov.l %d2,(%sp)"); asm("jsr GC_push_one");
-         asm("mov.l %d3,(%sp)"); asm("jsr GC_push_one");
-         asm("mov.l %d4,(%sp)"); asm("jsr GC_push_one");
-         asm("mov.l %d5,(%sp)"); asm("jsr GC_push_one");
-         asm("mov.l %d6,(%sp)"); asm("jsr GC_push_one");
-         asm("mov.l %d7,(%sp)"); asm("jsr GC_push_one");
-  
-         asm("addq.w &0x4,%sp");       /* put stack back where it was  */
-#        define HAVE_PUSH_REGS
-#        endif /* !__GNUC__ */
-#       endif /* M68K/SYSV */
-
-#     if defined(PJ)
-       {
-           register int * sp asm ("optop");
-           extern int *__libc_stack_end;
-
-           GC_push_all_stack (sp, __libc_stack_end);
-#          define HAVE_PUSH_REGS
-           /* Isn't this redundant with the code to push the stack? */
-        }
-#     endif
+#if defined(HAVE_PUSH_REGS) && defined(THREADS)
+# error GC_push_regs cannot be used with threads
+ /* Would fail for GC_do_blocking.  There are probably other safety    */
+ /* issues.                                                            */
+# undef HAVE_PUSH_REGS
+#endif
 
-      /* other machines... */
-#       if !defined(HAVE_PUSH_REGS)
-           --> We just generated an empty GC_push_regs, which
-           --> is almost certainly broken.  Try defining
-           --> USE_GENERIC_PUSH_REGS instead.
-#       endif
-}
-#endif /* !USE_GENERIC_PUSH_REGS && !USE_ASM_PUSH_REGS */
+#if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
+# include <ucontext.h>
+#endif
 
-void GC_with_callee_saves_pushed(fn, arg)
-void (*fn)();
-ptr_t arg;
+/* Ensure that either registers are pushed, or callee-save registers   */
+/* are somewhere on the stack, and then call fn(arg, ctxt).            */
+/* ctxt is either a pointer to a ucontext_t we generated, or NULL.     */
+void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
+                                ptr_t arg)
 {
     word dummy;
-
-#   if defined(USE_GENERIC_PUSH_REGS)
-#     ifdef HAVE_BUILTIN_UNWIND_INIT
-        /* This was suggested by Richard Henderson as the way to       */
-        /* force callee-save registers and register windows onto       */
-        /* the stack.                                          */
-        __builtin_unwind_init();
-#     else /* !HAVE_BUILTIN_UNWIND_INIT */
-#      if defined(RS6000) || defined(POWERPC)
-       /* FIXME: RS6000 means AIX.                             */
-        /* This should probably be used in all Posix/non-gcc   */
-        /* settings.  We defer that change to minimize risk.   */
-        ucontext_t ctxt;
-        getcontext(&ctxt);
-#      else
+    void * context = 0;
+
+#   if defined(HAVE_PUSH_REGS)
+      GC_push_regs();
+#   elif defined(UNIX_LIKE) && !defined(DARWIN) && !defined(ARM32)
+      /* Older versions of Darwin seem to lack getcontext(). */
+      /* ARM Linux often doesn't support a real getcontext(). */
+      ucontext_t ctxt;
+      if (getcontext(&ctxt) < 0)
+       ABORT ("Getcontext failed: Use another register retrieval method?");
+      context = &ctxt;
+#     if defined(SPARC) || defined(IA64)
+        /* On a register window machine, we need to save register      */
+        /* contents on the stack for this to work.  This may already be        */
+        /* subsumed by the getcontext() call.                          */
+        {
+          GC_save_regs_ret_val = GC_save_regs_in_stack();
+        }
+#     endif /* register windows. */
+#   elif defined(HAVE_BUILTIN_UNWIND_INIT)
+      /* This was suggested by Richard Henderson as the way to */
+      /* force callee-save registers and register windows onto */
+      /* the stack.                                            */
+      __builtin_unwind_init();
+#   else /* !HAVE_BUILTIN_UNWIND_INIT && !UNIX_LIKE  */
+         /* && !HAVE_PUSH_REGS                      */
         /* Generic code                          */
         /* The idea is due to Parag Patel at HP. */
         /* We're not sure whether he would like  */
@@ -444,187 +216,30 @@ ptr_t arg;
                   || defined(UTS4) || defined(LINUX) || defined(EWS4800)
          (void) setjmp(regs);
 #       else
-            (void) _setjmp(regs);
+          (void) _setjmp(regs);
          /* We don't want to mess with signals. According to   */
          /* SUSV3, setjmp() may or may not save signal mask.   */
          /* _setjmp won't, but is less portable.               */
 #       endif
-#      endif /* !AIX ... */
-#     endif /* !HAVE_BUILTIN_UNWIND_INIT */
-#   else
-#     if defined(PTHREADS) && !defined(MSWIN32) /* !USE_GENERIC_PUSH_REGS */
-        /* We may still need this to save thread contexts.     */
-        ucontext_t ctxt;
-        getcontext(&ctxt);
-#     else  /* Shouldn't be needed */
-        ABORT("Unexpected call to GC_with_callee_saves_pushed");
-#     endif
-#   endif
-#   if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \
-       || 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.                                            */
-      {
-        GC_save_regs_ret_val = GC_save_regs_in_stack();
-       /* On IA64 gcc, could use __builtin_ia64_flushrs() and  */
-       /* __builtin_ia64_flushrs().  The latter will be done   */
-       /* implicitly by __builtin_unwind_init() for gcc3.0.1   */
-       /* and later.                                           */
-      }
-#   endif
-    fn(arg);
+#   endif /* !HAVE_PUSH_REGS ... */
+    fn(arg, context);
     /* Strongly discourage the compiler from treating the above        */
     /* as a tail-call, since that would pop the register       */
     /* contents before we get a chance to look at them.                */
     GC_noop1((word)(&dummy));
 }
 
-#if defined(USE_GENERIC_PUSH_REGS)
-void GC_generic_push_regs(cold_gc_frame)
-ptr_t cold_gc_frame;
+void GC_push_regs_and_stack(ptr_t cold_gc_frame)
 {
     GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame);
 }
-#endif /* USE_GENERIC_PUSH_REGS */
 
-/* On register window machines, we need a way to force registers into  */
-/* the stack.  Return sp.                                              */
-# ifdef SPARC
-    __asm__("  .seg    \"text\"");
-#   if defined(SVR4) || defined(NETBSD) || defined(FREEBSD)
-      __asm__("        .globl  GC_save_regs_in_stack");
-      __asm__("GC_save_regs_in_stack:");
-      __asm__("        .type GC_save_regs_in_stack,#function");
-#   else
-      __asm__("        .globl  _GC_save_regs_in_stack");
-      __asm__("_GC_save_regs_in_stack:");
-#   endif
-#   if defined(__arch64__) || defined(__sparcv9)
-      __asm__("        save    %sp,-128,%sp");
-      __asm__("        flushw");
-      __asm__("        ret");
-      __asm__("        restore %sp,2047+128,%o0");
-#   else
-      __asm__("        ta      0x3   ! ST_FLUSH_WINDOWS");
-      __asm__("        retl");
-      __asm__("        mov     %sp,%o0");
-#   endif
-#   ifdef SVR4
-      __asm__("        .GC_save_regs_in_stack_end:");
-      __asm__("        .size GC_save_regs_in_stack,.GC_save_regs_in_stack_end-GC_save_regs_in_stack");
-#   endif
-#   ifdef LINT
-       word GC_save_regs_in_stack() { return(0 /* sp really */);}
-#   endif
-# endif
-
-/* On IA64, we also need to flush register windows.  But they end      */
-/* up on the other side of the stack segment.                          */
-/* Returns the backing store pointer for the register stack.           */
-/* We now implement this as a separate assembly file, since inline     */
-/* assembly code here doesn't work with either the Intel or HP                 */
-/* compilers.                                                          */
-# if 0
-#   ifdef LINUX
-       asm("        .text");
-       asm("        .psr abi64");
-       asm("        .psr lsb");
-       asm("        .lsb");
-       asm("");
-       asm("        .text");
-       asm("        .align 16");
-       asm("        .global GC_save_regs_in_stack");
-       asm("        .proc GC_save_regs_in_stack");
-       asm("GC_save_regs_in_stack:");
-       asm("        .body");
-       asm("        flushrs");
-       asm("        ;;");
-       asm("        mov r8=ar.bsp");
-       asm("        br.ret.sptk.few rp");
-       asm("        .endp GC_save_regs_in_stack");
-#   endif /* LINUX */
-#   if 0 /* Other alternatives that don't work on HP/UX */
-       word GC_save_regs_in_stack() {
-#        if USE_BUILTINS
-           __builtin_ia64_flushrs();
-           return __builtin_ia64_bsp();
-#        else
-#          ifdef HPUX
-             _asm("        flushrs");
-             _asm("        ;;");
-             _asm("        mov r8=ar.bsp");
-             _asm("        br.ret.sptk.few rp");
-#          else
-             asm("        flushrs");
-             asm("        ;;");
-             asm("        mov r8=ar.bsp");
-             asm("        br.ret.sptk.few rp");
-#          endif
-#        endif
-       }
-#   endif
-# endif
-
-/* GC_clear_stack_inner(arg, limit) clears stack area up to limit and  */
-/* returns arg.  Stack clearing is crucial on SPARC, so we supply      */
-/* an assembly version that's more careful.  Assumes limit is hotter   */
-/* than sp, and limit is 8 byte aligned.                               */
 #if defined(ASM_CLEAR_CODE)
-#ifndef SPARC
-       --> fix it
-#endif
-# ifdef SUNOS4
-    __asm__(".globl _GC_clear_stack_inner");
-    __asm__("_GC_clear_stack_inner:");
-# else
-    __asm__(".globl GC_clear_stack_inner");
-    __asm__("GC_clear_stack_inner:");
-    __asm__(".type GC_save_regs_in_stack,#function");
-# endif
-#if defined(__arch64__) || defined(__sparcv9)
-  __asm__("mov %sp,%o2");              /* Save sp                      */
-  __asm__("add %sp,2047-8,%o3");       /* p = sp+bias-8                */
-  __asm__("add %o1,-2047-192,%sp");    /* Move sp out of the way,      */
-                               /* so that traps still work.    */
-                               /* Includes some extra words    */
-                               /* so we can be sloppy below.   */
-  __asm__("loop:");
-  __asm__("stx %g0,[%o3]");            /* *(long *)p = 0               */
-  __asm__("cmp %o3,%o1");
-  __asm__("bgu,pt %xcc, loop");        /* if (p > limit) goto loop     */
-    __asm__("add %o3,-8,%o3"); /* p -= 8 (delay slot) */
-  __asm__("retl");
-    __asm__("mov %o2,%sp");            /* Restore sp., delay slot      */
-#else
-  __asm__("mov %sp,%o2");              /* Save sp      */
-  __asm__("add %sp,-8,%o3");   /* p = sp-8     */
-  __asm__("clr %g1");          /* [g0,g1] = 0  */
-  __asm__("add %o1,-0x60,%sp");        /* Move sp out of the way,      */
-                               /* so that traps still work.    */
-                               /* Includes some extra words    */
-                               /* so we can be sloppy below.   */
-  __asm__("loop:");
-  __asm__("std %g0,[%o3]");            /* *(long long *)p = 0  */
-  __asm__("cmp %o3,%o1");
-  __asm__("bgu loop    ");             /* if (p > limit) goto loop     */
-    __asm__("add %o3,-8,%o3"); /* p -= 8 (delay slot) */
-  __asm__("retl");
-    __asm__("mov %o2,%sp");            /* Restore sp., delay slot      */
-#endif /* old SPARC */
-  /* First argument = %o0 = return value */
-#   ifdef SVR4
-      __asm__("        .GC_clear_stack_inner_end:");
-      __asm__("        .size GC_clear_stack_inner,.GC_clear_stack_inner_end-GC_clear_stack_inner");
-#   endif
-  
 # ifdef LINT
     /*ARGSUSED*/
     ptr_t GC_clear_stack_inner(arg, limit)
     ptr_t arg; word limit;
     { return(arg); }
+    /* The real version is in a .S file */
 # endif
-#endif  
+#endif /* ASM_CLEAR_CODE */ 
index 5e25fe460144a7d1cfbbc291dfc0b33143235ed9..a6baa6342b2c397998cc04dee6caef40b1de132f 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
- * Copyright (c) 2000 by Hewlett-Packard Company.  All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -12,8 +12,6 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, February 7, 1996 4:32 pm PST */
-
 #include "config.h"
  
 #include <stdio.h>
 #include <errno.h>
 #include "private/gc_priv.h"
 
-extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
-void GC_extend_size_map();     /* in misc.c. */
+extern void * GC_clear_stack(void *);  /* in misc.c, behaves like identity */
+void GC_extend_size_map(size_t);       /* in misc.c. */
 
 /* Allocate reclaim list for kind:     */
 /* Return TRUE on success              */
-GC_bool GC_alloc_reclaim_list(kind)
-register struct obj_kind * kind;
+GC_bool GC_alloc_reclaim_list(struct obj_kind *kind)
 {
     struct hblk ** result = (struct hblk **)
-               GC_scratch_alloc((MAXOBJSZ+1) * sizeof(struct hblk *));
+               GC_scratch_alloc((MAXOBJGRANULES+1) * sizeof(struct hblk *));
     if (result == 0) return(FALSE);
-    BZERO(result, (MAXOBJSZ+1)*sizeof(struct hblk *));
+    BZERO(result, (MAXOBJGRANULES+1)*sizeof(struct hblk *));
     kind -> ok_reclaim_list = result;
     return(TRUE);
 }
 
-/* Allocate a large block of size lw words.    */
+/* Allocate a large block of size lb bytes.    */
 /* The block is not cleared.                   */
 /* Flags is 0 or IGNORE_OFF_PAGE.              */
 /* We hold the allocation lock.                        */
-ptr_t GC_alloc_large(lw, k, flags)
-word lw;
-int k;
-unsigned flags;
+/* EXTRA_BYTES were already added to lb.       */
+ptr_t GC_alloc_large(size_t lb, int k, unsigned flags)
 {
     struct hblk * h;
-    word n_blocks = OBJ_SZ_TO_BLOCKS(lw);
+    word n_blocks;
     ptr_t result;
        
+    /* Round up to a multiple of a granule. */
+      lb = (lb + GRANULE_BYTES - 1) & ~(GRANULE_BYTES - 1);
+    n_blocks = OBJ_SZ_TO_BLOCKS(lb);
     if (!GC_is_initialized) GC_init_inner();
     /* Do our share of marking work */
         if(GC_incremental && !GC_dont_gc)
            GC_collect_a_little_inner((int)n_blocks);
-    h = GC_allochblk(lw, k, flags);
+    h = GC_allochblk(lb, k, flags);
 #   ifdef USE_MUNMAP
        if (0 == h) {
            GC_merge_unmapped();
-           h = GC_allochblk(lw, k, flags);
+           h = GC_allochblk(lb, k, flags);
        }
 #   endif
     while (0 == h && GC_collect_or_expand(n_blocks, (flags != 0))) {
-       h = GC_allochblk(lw, k, flags);
+       h = GC_allochblk(lb, k, flags);
     }
     if (h == 0) {
        result = 0;
     } else {
-       int total_bytes = n_blocks * HBLKSIZE;
+       size_t total_bytes = n_blocks * HBLKSIZE;
        if (n_blocks > 1) {
            GC_large_allocd_bytes += total_bytes;
            if (GC_large_allocd_bytes > GC_max_large_allocd_bytes)
                GC_max_large_allocd_bytes = GC_large_allocd_bytes;
        }
-       result = (ptr_t) (h -> hb_body);
-       GC_words_wasted += BYTES_TO_WORDS(total_bytes) - lw;
+       result = h -> hb_body;
     }
     return result;
 }
@@ -82,13 +79,11 @@ unsigned flags;
 
 /* Allocate a large block of size lb bytes.  Clear if appropriate.     */
 /* We hold the allocation lock.                                                */
-ptr_t GC_alloc_large_and_clear(lw, k, flags)
-word lw;
-int k;
-unsigned flags;
+/* EXTRA_BYTES were already added to lb.                               */
+ptr_t GC_alloc_large_and_clear(size_t lb, int k, unsigned flags)
 {
-    ptr_t result = GC_alloc_large(lw, k, flags);
-    word n_blocks = OBJ_SZ_TO_BLOCKS(lw);
+    ptr_t result = GC_alloc_large(lb, k, flags);
+    word n_blocks = OBJ_SZ_TO_BLOCKS(lb);
 
     if (0 == result) return 0;
     if (GC_debugging_started || GC_obj_kinds[k].ok_init) {
@@ -104,60 +99,34 @@ unsigned flags;
 /* require special handling on allocation.     */
 /* First a version that assumes we already     */
 /* hold lock:                                  */
-ptr_t GC_generic_malloc_inner(lb, k)
-register word lb;
-register int k;
+void * GC_generic_malloc_inner(size_t lb, int k)
 {
-register word lw;
-register ptr_t op;
-register ptr_t *opp;
-
-    if( SMALL_OBJ(lb) ) {
-        register struct obj_kind * kind = GC_obj_kinds + k;
-#       ifdef MERGE_SIZES
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-         if (lw == 0) lw = MIN_WORDS;
-#       endif
-       opp = &(kind -> ok_freelist[lw]);
+    void *op;
+
+    if(SMALL_OBJ(lb)) {
+        struct obj_kind * kind = GC_obj_kinds + k;
+       size_t lg = GC_size_map[lb];
+       void ** opp = &(kind -> ok_freelist[lg]);
+
         if( (op = *opp) == 0 ) {
-#          ifdef MERGE_SIZES
-             if (GC_size_map[lb] == 0) {
-               if (!GC_is_initialized)  GC_init_inner();
-               if (GC_size_map[lb] == 0) GC_extend_size_map(lb);
-               return(GC_generic_malloc_inner(lb, k));
-             }
-#          else
-             if (!GC_is_initialized) {
-               GC_init_inner();
-               return(GC_generic_malloc_inner(lb, k));
-             }
-#          endif
+           if (GC_size_map[lb] == 0) {
+             if (!GC_is_initialized)  GC_init_inner();
+             if (GC_size_map[lb] == 0) GC_extend_size_map(lb);
+             return(GC_generic_malloc_inner(lb, k));
+           }
            if (kind -> ok_reclaim_list == 0) {
                if (!GC_alloc_reclaim_list(kind)) goto out;
            }
-           op = GC_allocobj(lw, k);
+           op = GC_allocobj(lg, k);
            if (op == 0) goto out;
         }
-        /* Here everything is in a consistent state.   */
-        /* We assume the following assignment is       */
-        /* atomic.  If we get aborted                  */
-        /* after the assignment, we lose an object,    */
-        /* 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;
+        GC_bytes_allocd += GRANULES_TO_BYTES(lg);
     } else {
-       lw = ROUNDED_UP_WORDS(lb);
-       op = (ptr_t)GC_alloc_large_and_clear(lw, k, 0);
+       op = (ptr_t)GC_alloc_large_and_clear(ADD_SLOP(lb), k, 0);
+        GC_bytes_allocd += lb;
     }
-    GC_words_allocd += lw;
     
 out:
     return op;
@@ -166,46 +135,41 @@ out:
 /* Allocate a composite object of size n bytes.  The caller guarantees  */
 /* that pointers past the first page are not relevant.  Caller holds    */
 /* allocation lock.                                                     */
-ptr_t GC_generic_malloc_inner_ignore_off_page(lb, k)
-register size_t lb;
-register int k;
+void * GC_generic_malloc_inner_ignore_off_page(size_t lb, int k)
 {
-    register word lw;
-    ptr_t op;
+    word lb_adjusted;
+    void * op;
 
     if (lb <= HBLKSIZE)
-        return(GC_generic_malloc_inner((word)lb, k));
-    lw = ROUNDED_UP_WORDS(lb);
-    op = (ptr_t)GC_alloc_large_and_clear(lw, k, IGNORE_OFF_PAGE);
-    GC_words_allocd += lw;
+        return(GC_generic_malloc_inner(lb, k));
+    lb_adjusted = ADD_SLOP(lb);
+    op = GC_alloc_large_and_clear(lb_adjusted, k, IGNORE_OFF_PAGE);
+    GC_bytes_allocd += lb_adjusted;
     return op;
 }
 
-ptr_t GC_generic_malloc(lb, k)
-register word lb;
-register int k;
+void * GC_generic_malloc(size_t lb, int k)
 {
-    ptr_t result;
+    void * result;
     DCL_LOCK_STATE;
 
     if (GC_have_errors) GC_print_all_errors();
     GC_INVOKE_FINALIZERS();
     if (SMALL_OBJ(lb)) {
-       DISABLE_SIGNALS();
        LOCK();
         result = GC_generic_malloc_inner((word)lb, k);
        UNLOCK();
-       ENABLE_SIGNALS();
     } else {
-       word lw;
+       size_t lw;
+       size_t lb_rounded;
        word n_blocks;
        GC_bool init;
        lw = ROUNDED_UP_WORDS(lb);
-       n_blocks = OBJ_SZ_TO_BLOCKS(lw);
+       lb_rounded = WORDS_TO_BYTES(lw);
+       n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded);
        init = GC_obj_kinds[k].ok_init;
-       DISABLE_SIGNALS();
        LOCK();
-       result = (ptr_t)GC_alloc_large(lw, k, 0);
+       result = (ptr_t)GC_alloc_large(lb_rounded, k, 0);
        if (0 != result) {
          if (GC_debugging_started) {
            BZERO(result, n_blocks * HBLKSIZE);
@@ -220,9 +184,8 @@ register int k;
 #          endif
          }
        }
-       GC_words_allocd += lw;
+       GC_bytes_allocd += lb_rounded;
        UNLOCK();
-       ENABLE_SIGNALS();
        if (init && !GC_debugging_started && 0 != result) {
            BZERO(result, n_blocks * HBLKSIZE);
         }
@@ -236,40 +199,34 @@ register int k;
 
 
 #define GENERAL_MALLOC(lb,k) \
-    (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
+    GC_clear_stack(GC_generic_malloc(lb, k))
 /* We make the GC_clear_stack_call a tail call, hoping to get more of  */
 /* the stack.                                                          */
 
 /* Allocate lb bytes of atomic (pointerfree) data */
-# ifdef __STDC__
-    GC_PTR GC_malloc_atomic(size_t lb)
-# else
-    GC_PTR GC_malloc_atomic(lb)
-    size_t lb;
-# endif
+#ifdef THREAD_LOCAL_ALLOC
+  void * GC_core_malloc_atomic(size_t lb)
+#else
+  void * GC_malloc_atomic(size_t lb)
+#endif
 {
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-DCL_LOCK_STATE;
-
-    if( EXPECT(SMALL_OBJ(lb), 1) ) {
-#       ifdef MERGE_SIZES
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_aobjfreelist[lw]);
-       FASTLOCK();
-        if( EXPECT(!FASTLOCK_SUCCEEDED() || (op = *opp) == 0, 0) ) {
-            FASTUNLOCK();
+    void *op;
+    void ** opp;
+    size_t lg;
+    DCL_LOCK_STATE;
+
+    if(SMALL_OBJ(lb)) {
+       lg = GC_size_map[lb];
+       opp = &(GC_aobjfreelist[lg]);
+       LOCK();
+        if( EXPECT((op = *opp) == 0, 0) ) {
+            UNLOCK();
             return(GENERAL_MALLOC((word)lb, PTRFREE));
         }
-        /* See above comment on signals.       */
         *opp = obj_link(op);
-        GC_words_allocd += lw;
-        FASTUNLOCK();
-        return((GC_PTR) op);
+        GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+        UNLOCK();
+        return((void *) op);
    } else {
        return(GENERAL_MALLOC((word)lb, PTRFREE));
    }
@@ -296,28 +253,23 @@ DCL_LOCK_STATE;
 }
 
 /* Allocate lb bytes of composite (pointerful) data */
-# ifdef __STDC__
-    GC_PTR GC_malloc(size_t lb)
-# else
-    GC_PTR GC_malloc(lb)
-    size_t lb;
-# endif
+#ifdef THREAD_LOCAL_ALLOC
+  void * GC_core_malloc(size_t lb)
+#else
+  void * GC_malloc(size_t lb)
+#endif
 {
-register ptr_t op;
-register ptr_t *opp;
-register word lw;
-DCL_LOCK_STATE;
-
-    if( EXPECT(SMALL_OBJ(lb), 1) ) {
-#       ifdef MERGE_SIZES
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_objfreelist[lw]);
-       FASTLOCK();
-        if( EXPECT(!FASTLOCK_SUCCEEDED() || (op = *opp) == 0, 0) ) {
-            FASTUNLOCK();
+    void *op;
+    void **opp;
+    size_t lg;
+    DCL_LOCK_STATE;
+
+    if(SMALL_OBJ(lb)) {
+       lg = GC_size_map[lb];
+       opp = (void **)&(GC_objfreelist[lg]);
+       LOCK();
+        if( EXPECT((op = *opp) == 0, 0) ) {
+            UNLOCK();
             return(GENERAL_MALLOC((word)lb, NORMAL));
         }
         /* See above comment on signals.       */
@@ -328,11 +280,11 @@ DCL_LOCK_STATE;
                        >= (word)GC_least_plausible_heap_addr);
         *opp = obj_link(op);
         obj_link(op) = 0;
-        GC_words_allocd += lw;
-        FASTUNLOCK();
-        return((GC_PTR) op);
+        GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+        UNLOCK();
+        return op;
    } else {
-       return(GENERAL_MALLOC((word)lb, NORMAL));
+       return(GENERAL_MALLOC(lb, NORMAL));
    }
 }
 
@@ -350,19 +302,8 @@ DCL_LOCK_STATE;
 # define GC_debug_malloc_replacement(lb) \
        GC_debug_malloc(lb, RA "unknown", 0)
 
-# ifdef __STDC__
-    GC_PTR malloc(size_t lb)
-# else
-    GC_PTR malloc(lb)
-    size_t lb;
-# endif
+void * malloc(size_t lb)
   {
-#   if defined(GC_WIN32_THREADS) && defined(__GNUC__)
-      /* According to Gerard Allen, this helps with MINGW.     */
-      /* When using threads need to initalised before use, but GCC uses a malloc 
-         in  __w32_sharedptr_initialize (w32-shared-ptr.c) */
-      if (!GC_is_initialized) GC_init();
-#   endif
     /* It might help to manually inline the GC_malloc call here.       */
     /* But any decent compiler should reduce the extra procedure call  */
     /* to at most a jump instruction in this case.                     */
@@ -376,27 +317,63 @@ DCL_LOCK_STATE;
        */
       if (!GC_is_initialized) return sbrk(lb);
 #   endif /* I386 && GC_SOLARIS_THREADS */
-    return((GC_PTR)REDIRECT_MALLOC(lb));
+    return((void *)REDIRECT_MALLOC(lb));
   }
 
-# ifdef __STDC__
-    GC_PTR calloc(size_t n, size_t lb)
-# else
-    GC_PTR calloc(n, lb)
-    size_t n, lb;
-# endif
+#ifdef GC_LINUX_THREADS
+  static ptr_t GC_libpthread_start = 0;
+  static ptr_t GC_libpthread_end = 0;
+  static ptr_t GC_libld_start = 0;
+  static ptr_t GC_libld_end = 0;
+  extern GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp);
+       /* From os_dep.c */
+
+  void GC_init_lib_bounds(void)
   {
-    return((GC_PTR)REDIRECT_MALLOC(n*lb));
+    if (GC_libpthread_start != 0) return;
+    if (!GC_text_mapping("/lib/tls/libpthread-",
+                        &GC_libpthread_start, &GC_libpthread_end)
+       && !GC_text_mapping("/lib/libpthread-",
+                           &GC_libpthread_start, &GC_libpthread_end)) {
+       WARN("Failed to find libpthread.so text mapping: Expect crash\n", 0);
+        /* This might still work with some versions of libpthread,     */
+       /* so we don't abort.  Perhaps we should.                       */
+        /* Generate message only once:                                 */
+          GC_libpthread_start = (ptr_t)1;
+    }
+    if (!GC_text_mapping("/lib/ld-", &GC_libld_start, &GC_libld_end)) {
+       WARN("Failed to find ld.so text mapping: Expect crash\n", 0);
+    }
   }
+#endif
+
+void * calloc(size_t n, size_t lb)
+{
+#   if defined(GC_LINUX_THREADS) && !defined(USE_PROC_FOR_LIBRARIES)
+       /* libpthread allocated some memory that is only pointed to by  */
+       /* mmapped thread stacks.  Make sure it's not collectable.      */
+       {
+         static GC_bool lib_bounds_set = FALSE;
+         ptr_t caller = (ptr_t)__builtin_return_address(0);
+         /* This test does not need to ensure memory visibility, since */
+         /* the bounds will be set when/if we create another thread.   */
+         if (!lib_bounds_set) {
+           GC_init_lib_bounds();
+           lib_bounds_set = TRUE;
+         }
+         if (caller >= GC_libpthread_start && caller < GC_libpthread_end
+             || (caller >= GC_libld_start && caller < GC_libld_end))
+           return GC_malloc_uncollectable(n*lb);
+         /* The two ranges are actually usually adjacent, so there may */
+         /* be a way to speed this up.                                 */
+       }
+#   endif
+    return((void *)REDIRECT_MALLOC(n*lb));
+}
 
 #ifndef strdup
 # include <string.h>
-# ifdef __STDC__
-    char *strdup(const char *s)
-# else
-    char *strdup(s)
-    char *s;
-# endif
+  char *strdup(const char *s)
   {
     size_t len = strlen(s) + 1;
     char * result = ((char *)REDIRECT_MALLOC(len+1));
@@ -417,29 +394,27 @@ DCL_LOCK_STATE;
 # endif /* REDIRECT_MALLOC */
 
 /* Explicitly deallocate an object p.                          */
-# ifdef __STDC__
-    void GC_free(GC_PTR p)
-# else
-    void GC_free(p)
-    GC_PTR p;
-# endif
+void GC_free(void * p)
 {
-    register struct hblk *h;
-    register hdr *hhdr;
-    register signed_word sz;
-    register ptr_t * flh;
-    register int knd;
-    register struct obj_kind * ok;
+    struct hblk *h;
+    hdr *hhdr;
+    size_t sz; /* In bytes */
+    size_t ngranules;  /* sz in granules */
+    void **flh;
+    int knd;
+    struct obj_kind * ok;
     DCL_LOCK_STATE;
 
     if (p == 0) return;
        /* Required by ANSI.  It's not my fault ...     */
     h = HBLKPTR(p);
     hhdr = HDR(h);
+    sz = hhdr -> hb_sz;
+    ngranules = BYTES_TO_GRANULES(sz);
     GC_ASSERT(GC_base(p) == p);
 #   if defined(REDIRECT_MALLOC) && \
        (defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \
-        || defined(__MINGW32__)) /* Should this be MSWIN32 in general? */
+        || defined(MSWIN32))
        /* For Solaris, we have to redirect malloc calls during         */
        /* initialization.  For the others, this seems to happen        */
        /* implicitly.                                                  */
@@ -447,38 +422,27 @@ DCL_LOCK_STATE;
        if (0 == hhdr) return;
 #   endif
     knd = hhdr -> hb_obj_kind;
-    sz = hhdr -> hb_sz;
     ok = &GC_obj_kinds[knd];
-    if (EXPECT((sz <= MAXOBJSZ), 1)) {
-#      ifdef THREADS
-           DISABLE_SIGNALS();
-           LOCK();
-#      endif
-       GC_mem_freed += sz;
-       /* A signal here can make GC_mem_freed and GC_non_gc_bytes      */
-       /* inconsistent.  We claim this is benign.                      */
-       if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
+    if (EXPECT((ngranules <= MAXOBJGRANULES), 1)) {
+       LOCK();
+       GC_bytes_freed += sz;
+       if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
                /* Its unnecessary to clear the mark bit.  If the       */
                /* object is reallocated, it doesn't matter.  O.w. the  */
                /* collector will do it, since it's on a free list.     */
        if (ok -> ok_init) {
-           BZERO((word *)p + 1, WORDS_TO_BYTES(sz-1));
+           BZERO((word *)p + 1, sz-sizeof(word));
        }
-       flh = &(ok -> ok_freelist[sz]);
+       flh = &(ok -> ok_freelist[ngranules]);
        obj_link(p) = *flh;
        *flh = (ptr_t)p;
-#      ifdef THREADS
-           UNLOCK();
-           ENABLE_SIGNALS();
-#      endif
+       UNLOCK();
     } else {
-       DISABLE_SIGNALS();
         LOCK();
-        GC_mem_freed += sz;
-       if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
+        GC_bytes_freed += sz;
+       if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
         GC_freehblk(h);
         UNLOCK();
-        ENABLE_SIGNALS();
     }
 }
 
@@ -486,33 +450,35 @@ DCL_LOCK_STATE;
 /* Only used for internally allocated objects, so we can take some     */
 /* shortcuts.                                                          */
 #ifdef THREADS
-void GC_free_inner(GC_PTR p)
+void GC_free_inner(void * p)
 {
-    register struct hblk *h;
-    register hdr *hhdr;
-    register signed_word sz;
-    register ptr_t * flh;
-    register int knd;
-    register struct obj_kind * ok;
+    struct hblk *h;
+    hdr *hhdr;
+    size_t sz; /* bytes */
+    size_t ngranules;  /* sz in granules */
+    void ** flh;
+    int knd;
+    struct obj_kind * ok;
     DCL_LOCK_STATE;
 
     h = HBLKPTR(p);
     hhdr = HDR(h);
     knd = hhdr -> hb_obj_kind;
     sz = hhdr -> hb_sz;
+    ngranules = BYTES_TO_GRANULES(sz);
     ok = &GC_obj_kinds[knd];
-    if (sz <= MAXOBJSZ) {
-       GC_mem_freed += sz;
-       if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
+    if (ngranules <= MAXOBJGRANULES) {
+       GC_bytes_freed += sz;
+       if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
        if (ok -> ok_init) {
-           BZERO((word *)p + 1, WORDS_TO_BYTES(sz-1));
+           BZERO((word *)p + 1, sz-sizeof(word));
        }
-       flh = &(ok -> ok_freelist[sz]);
+       flh = &(ok -> ok_freelist[ngranules]);
        obj_link(p) = *flh;
        *flh = (ptr_t)p;
     } else {
-        GC_mem_freed += sz;
-       if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
+        GC_bytes_freed += sz;
+       if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
         GC_freehblk(h);
     }
 }
@@ -522,13 +488,22 @@ void GC_free_inner(GC_PTR p)
 #   define REDIRECT_FREE GC_free
 # endif
 # ifdef REDIRECT_FREE
-#   ifdef __STDC__
-      void free(GC_PTR p)
-#   else
-      void free(p)
-      GC_PTR p;
-#   endif
+  void free(void * p)
   {
+#   if defined(GC_LINUX_THREADS) && !defined(USE_PROC_FOR_LIBRARIES)
+       {
+         /* Don't bother with initialization checks.  If nothing       */
+         /* has been initialized, the check fails, and that's safe,    */
+         /* since we haven't allocated uncollectable objects either.   */
+         ptr_t caller = (ptr_t)__builtin_return_address(0);
+         /* This test does not need to ensure memory visibility, since */
+         /* the bounds will be set when/if we create another thread.   */
+         if (caller >= GC_libpthread_start && caller > GC_libpthread_end) {
+           GC_free(p);
+           return;
+         }
+       }
+#   endif
 #   ifndef IGNORE_FREE
       REDIRECT_FREE(p);
 #   endif
index b3783e0cc6121148e4ea302d561f4e3a2d3019cd..3126d119d5766eee372ba2a9ad04dfafacd78e61 100644 (file)
@@ -33,17 +33,15 @@ GC_bool GC_alloc_reclaim_list();    /* in malloc.c */
 /* Some externally visible but unadvertised variables to allow access to */
 /* free lists from inlined allocators without including gc_priv.h       */
 /* or introducing dependencies on internal data structure layouts.      */
-ptr_t * GC_CONST GC_objfreelist_ptr = GC_objfreelist;
-ptr_t * GC_CONST GC_aobjfreelist_ptr = GC_aobjfreelist;
-ptr_t * GC_CONST GC_uobjfreelist_ptr = GC_uobjfreelist;
+void ** const GC_objfreelist_ptr = GC_objfreelist;
+void ** const GC_aobjfreelist_ptr = GC_aobjfreelist;
+void ** const GC_uobjfreelist_ptr = GC_uobjfreelist;
 # ifdef ATOMIC_UNCOLLECTABLE
-    ptr_t * GC_CONST GC_auobjfreelist_ptr = GC_auobjfreelist;
+    void ** const GC_auobjfreelist_ptr = GC_auobjfreelist;
 # endif
 
 
-GC_PTR GC_generic_or_special_malloc(lb,knd)
-word lb;
-int knd;
+void * GC_generic_or_special_malloc(size_t lb, int knd)
 {
     switch(knd) {
 #     ifdef STUBBORN_ALLOC
@@ -70,26 +68,19 @@ int knd;
 /* lb bytes.  The object may be (and quite likely will be) moved.     */
 /* The kind (e.g. atomic) is the same as that of the old.            */
 /* Shrinking of large blocks is not implemented well.                 */
-# ifdef __STDC__
-    GC_PTR GC_realloc(GC_PTR p, size_t lb)
-# else
-    GC_PTR GC_realloc(p,lb)
-    GC_PTR p;
-    size_t lb;
-# endif
+void * GC_realloc(void * p, size_t lb)
 {
-register struct hblk * h;
-register hdr * hhdr;
-register word sz;       /* Current size in bytes       */
-register word orig_sz;  /* Original sz in bytes        */
-int obj_kind;
+    struct hblk * h;
+    hdr * hhdr;
+    size_t sz;  /* Current size in bytes       */
+    size_t orig_sz;     /* Original sz in bytes        */
+    int obj_kind;
 
     if (p == 0) return(GC_malloc(lb)); /* Required by ANSI */
     h = HBLKPTR(p);
     hhdr = HDR(h);
     sz = hhdr -> hb_sz;
     obj_kind = hhdr -> hb_obj_kind;
-    sz = WORDS_TO_BYTES(sz);
     orig_sz = sz;
 
     if (sz > MAXOBJBYTES) {
@@ -97,10 +88,16 @@ int obj_kind;
          register word descr;
          
          sz = (sz+HBLKSIZE-1) & (~HBLKMASK);
-         hhdr -> hb_sz = BYTES_TO_WORDS(sz);
+         hhdr -> hb_sz = sz;
          descr = GC_obj_kinds[obj_kind].ok_descriptor;
           if (GC_obj_kinds[obj_kind].ok_relocate_descr) descr += sz;
           hhdr -> hb_descr = descr;
+#        ifdef MARK_BIT_PER_OBJ
+           GC_ASSERT(hhdr -> hb_inv_sz == LARGE_INV_SZ);
+#        else
+           GC_ASSERT(hhdr -> hb_large_block &&
+                     hhdr -> hb_map[ANY_INDEX] == 1);
+#        endif
          if (IS_UNCOLLECTABLE(obj_kind)) GC_non_gc_bytes += (sz - orig_sz);
          /* Extra area is already cleared by GC_alloc_large_and_clear. */
     }
@@ -118,7 +115,7 @@ int obj_kind;
            return(p);
        } else {
            /* shrink */
-             GC_PTR result =
+             void * result =
                        GC_generic_or_special_malloc((word)lb, obj_kind);
 
              if (result == 0) return(0);
@@ -132,7 +129,7 @@ int obj_kind;
        }
     } else {
        /* grow */
-         GC_PTR result =
+         void * result =
                GC_generic_or_special_malloc((word)lb, obj_kind);
 
          if (result == 0) return(0);
@@ -159,13 +156,7 @@ int obj_kind;
 # define GC_debug_realloc_replacement(p, lb) \
        GC_debug_realloc(p, lb, RA "unknown", 0)
 
-# ifdef __STDC__
-    GC_PTR realloc(GC_PTR p, size_t lb)
-# else
-    GC_PTR realloc(p,lb)
-    GC_PTR p;
-    size_t lb;
-# endif
+void * realloc(void * p, size_t lb)
   {
     return(REDIRECT_REALLOC(p, lb));
   }
@@ -174,15 +165,14 @@ int obj_kind;
 # endif /* REDIRECT_REALLOC */
 
 
-/* Allocate memory such that only pointers to near the                 */
-/* beginning of the object are considered.                     */
+/* Allocate memory such that only pointers to near the          */
+/* beginning of the object are considered.                      */
 /* We avoid holding allocation lock while we clear memory.     */
-ptr_t GC_generic_malloc_ignore_off_page(lb, k)
-register size_t lb;
-register int k;
+void * GC_generic_malloc_ignore_off_page(size_t lb, int k)
 {
-    register ptr_t result;
-    word lw;
+    void *result;
+    size_t lw;
+    size_t lb_rounded;
     word n_blocks;
     GC_bool init;
     DCL_LOCK_STATE;
@@ -190,13 +180,13 @@ register int k;
     if (SMALL_OBJ(lb))
         return(GC_generic_malloc((word)lb, k));
     lw = ROUNDED_UP_WORDS(lb);
-    n_blocks = OBJ_SZ_TO_BLOCKS(lw);
+    lb_rounded = WORDS_TO_BYTES(lw);
+    n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded);
     init = GC_obj_kinds[k].ok_init;
     if (GC_have_errors) GC_print_all_errors();
     GC_INVOKE_FINALIZERS();
-    DISABLE_SIGNALS();
     LOCK();
-    result = (ptr_t)GC_alloc_large(lw, k, IGNORE_OFF_PAGE);
+    result = (ptr_t)GC_alloc_large(ADD_SLOP(lb), k, IGNORE_OFF_PAGE);
     if (0 != result) {
         if (GC_debugging_started) {
            BZERO(result, n_blocks * HBLKSIZE);
@@ -211,9 +201,8 @@ register int k;
 #          endif
         }
     }
-    GC_words_allocd += lw;
+    GC_bytes_allocd += lb_rounded;
     UNLOCK();
-    ENABLE_SIGNALS();
     if (0 == result) {
         return((*GC_oom_fn)(lb));
     } else {
@@ -224,113 +213,45 @@ register int k;
     }
 }
 
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_ignore_off_page(size_t lb)
-# else
-  char * GC_malloc_ignore_off_page(lb)
-  register size_t lb;
-# endif
+void * GC_malloc_ignore_off_page(size_t lb)
 {
-    return((GC_PTR)GC_generic_malloc_ignore_off_page(lb, NORMAL));
+    return((void *)GC_generic_malloc_ignore_off_page(lb, NORMAL));
 }
 
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_atomic_ignore_off_page(size_t lb)
-# else
-  char * GC_malloc_atomic_ignore_off_page(lb)
-  register size_t lb;
-# endif
+void * GC_malloc_atomic_ignore_off_page(size_t lb)
 {
-    return((GC_PTR)GC_generic_malloc_ignore_off_page(lb, PTRFREE));
+    return((void *)GC_generic_malloc_ignore_off_page(lb, PTRFREE));
 }
 
-/* Increment GC_words_allocd from code that doesn't have direct access         */
+/* Increment GC_bytes_allocd from code that doesn't have direct access         */
 /* to GC_arrays.                                                       */
-# ifdef __STDC__
-void GC_incr_words_allocd(size_t n)
+void GC_incr_bytes_allocd(size_t n)
 {
-    GC_words_allocd += n;
+    GC_bytes_allocd += n;
 }
 
-/* The same for GC_mem_freed.                          */
-void GC_incr_mem_freed(size_t n)
+/* The same for GC_bytes_freed.                                */
+void GC_incr_bytes_freed(size_t n)
 {
-    GC_mem_freed += n;
+    GC_bytes_freed += n;
 }
-# endif /* __STDC__ */
 
-/* Analogous to the above, but assumes a small object size, and        */
-/* bypasses MERGE_SIZES mechanism.  Used by gc_inline.h.               */
-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;
-
-    opp = &(kind -> ok_freelist[lw]);
-    if( (op = *opp) == 0 ) {
-        if (!GC_is_initialized) {
-            GC_init_inner();
-        }
-       if (kind -> ok_reclaim_list != 0 || GC_alloc_reclaim_list(kind)) {
-           op = GC_clear_stack(GC_allocobj((word)lw, k));
-       }
-       if (op == 0) {
-           UNLOCK();
-           ENABLE_SIGNALS();
-           return ((*GC_oom_fn)(WORDS_TO_BYTES(lw)));
-       }
-    }
-    *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;
-
-    if (GC_have_errors) GC_print_all_errors();
-    GC_INVOKE_FINALIZERS();
-    DISABLE_SIGNALS();
-    LOCK();
-    op = GC_generic_malloc_words_small_inner(lw, k);
-    UNLOCK();
-    ENABLE_SIGNALS();
-    return((ptr_t)op);
-}
+#if defined(THREADS)
 
-#if defined(THREADS) && !defined(SRC_M3)
-
-extern signed_word GC_mem_found;   /* Protected by GC lock.  */
+extern signed_word GC_bytes_found;   /* Protected by GC lock.  */
 
 #ifdef PARALLEL_MARK
-volatile signed_word GC_words_allocd_tmp = 0;
-                        /* Number of words of memory allocated since    */
+volatile signed_word GC_bytes_allocd_tmp = 0;
+                        /* Number of bytes of memory allocated since    */
                         /* we released the GC lock.  Instead of         */
                         /* reacquiring the GC lock just to add this in, */
                         /* we add it in the next time we reacquire      */
                         /* the lock.  (Atomically adding it doesn't     */
                         /* work, since we would have to atomically      */
                         /* update it in GC_malloc, which is too         */
-                        /* expensive.                                   */
+                        /* expensive.)                                   */
 #endif /* PARALLEL_MARK */
 
-/* See reclaim.c: */
-extern ptr_t GC_reclaim_generic();
-
 /* Return a list of 1 or more objects of the indicated size, linked    */
 /* through the first word in the object.  This has the advantage that  */
 /* it acquires the allocation lock only once, and may greatly reduce   */
@@ -340,40 +261,34 @@ extern ptr_t GC_reclaim_generic();
 /* GC_malloc_many or friends to replenish it.  (We do not round up     */
 /* object sizes, since a call indicates the intention to consume many  */
 /* objects of exactly this size.)                                      */
+/* We assume that the size is a multiple of GRANULE_BYTES.             */
 /* We return the free-list by assigning it to *result, since it is     */
 /* not safe to return, e.g. a linked list of pointer-free objects,     */
 /* since the collector would not retain the entire list if it were     */
 /* invoked just as we were returning.                                  */
 /* Note that the client should usually clear the link field.           */
-void GC_generic_malloc_many(lb, k, result)
-register word lb;
-register int k;
-ptr_t *result;
+void GC_generic_malloc_many(size_t lb, int k, void **result)
 {
-ptr_t op;
-ptr_t p;
-ptr_t *opp;
-word lw;
-word my_words_allocd = 0;
+void *op;
+void *p;
+void **opp;
+size_t lw;     /* Length in words.     */
+size_t lg;     /* Length in granules.  */
+signed_word my_bytes_allocd = 0;
 struct obj_kind * ok = &(GC_obj_kinds[k]);
 DCL_LOCK_STATE;
 
-#   if defined(GATHERSTATS) || defined(PARALLEL_MARK)
-#     define COUNT_ARG , &my_words_allocd
-#   else
-#     define COUNT_ARG
-#     define NEED_TO_COUNT
-#   endif
+    GC_ASSERT((lb & (GRANULE_BYTES-1)) == 0);
     if (!SMALL_OBJ(lb)) {
         op = GC_generic_malloc(lb, k);
         if(0 != op) obj_link(op) = 0;
        *result = op;
         return;
     }
-    lw = ALIGNED_WORDS(lb);
+    lw = BYTES_TO_WORDS(lb);
+    lg = BYTES_TO_GRANULES(lb);
     if (GC_have_errors) GC_print_all_errors();
     GC_INVOKE_FINALIZERS();
-    DISABLE_SIGNALS();
     LOCK();
     if (!GC_is_initialized) GC_init_inner();
     /* Do our share of marking work */
@@ -389,55 +304,45 @@ DCL_LOCK_STATE;
        struct hblk * hbp;
        hdr * hhdr;
 
-       rlh += lw;
+       rlh += lg;
        while ((hbp = *rlh) != 0) {
             hhdr = HDR(hbp);
             *rlh = hhdr -> hb_next;
+           GC_ASSERT(hhdr -> hb_sz == lb);
            hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
 #          ifdef PARALLEL_MARK
                {
-                 signed_word my_words_allocd_tmp = GC_words_allocd_tmp;
+                 signed_word my_bytes_allocd_tmp = GC_bytes_allocd_tmp;
 
-                 GC_ASSERT(my_words_allocd_tmp >= 0);
+                 GC_ASSERT(my_bytes_allocd_tmp >= 0);
                  /* We only decrement it while holding the GC lock.    */
                  /* Thus we can't accidentally adjust it down in more  */
                  /* than one thread simultaneously.                    */
-                 if (my_words_allocd_tmp != 0) {
-                   (void)GC_atomic_add(
-                               (volatile GC_word *)(&GC_words_allocd_tmp),
-                               (GC_word)(-my_words_allocd_tmp));
-                   GC_words_allocd += my_words_allocd_tmp;
+                 if (my_bytes_allocd_tmp != 0) {
+                   (void)AO_fetch_and_add(
+                               (volatile AO_t *)(&GC_bytes_allocd_tmp),
+                               (AO_t)(-my_bytes_allocd_tmp));
+                   GC_bytes_allocd += my_bytes_allocd_tmp;
                  }
                }
                GC_acquire_mark_lock();
                ++ GC_fl_builder_count;
                UNLOCK();
-               ENABLE_SIGNALS();
                GC_release_mark_lock();
 #          endif
-           op = GC_reclaim_generic(hbp, hhdr, lw,
-                                   ok -> ok_init, 0 COUNT_ARG);
+           op = GC_reclaim_generic(hbp, hhdr, lb,
+                                   ok -> ok_init, 0, &my_bytes_allocd);
             if (op != 0) {
-#            ifdef NEED_TO_COUNT
-               /* We are neither gathering statistics, nor marking in  */
-               /* parallel.  Thus GC_reclaim_generic doesn't count     */
-               /* for us.                                              */
-               for (p = op; p != 0; p = obj_link(p)) {
-                 my_words_allocd += lw;
-               }
-#            endif
-#            if defined(GATHERSTATS)
-               /* We also reclaimed memory, so we need to adjust       */
-               /* that count.                                          */
-               /* This should be atomic, so the results may be         */
-               /* inaccurate.                                          */
-               GC_mem_found += my_words_allocd;
-#            endif
+             /* We also reclaimed memory, so we need to adjust         */
+             /* that count.                                            */
+             /* This should be atomic, so the results may be           */
+             /* inaccurate.                                            */
+             GC_bytes_found += my_bytes_allocd;
 #            ifdef PARALLEL_MARK
                *result = op;
-               (void)GC_atomic_add(
-                               (volatile GC_word *)(&GC_words_allocd_tmp),
-                               (GC_word)(my_words_allocd));
+               (void)AO_fetch_and_add(
+                               (volatile AO_t *)(&GC_bytes_allocd_tmp),
+                               (AO_t)(my_bytes_allocd));
                GC_acquire_mark_lock();
                -- GC_fl_builder_count;
                if (GC_fl_builder_count == 0) GC_notify_all_builder();
@@ -445,7 +350,7 @@ DCL_LOCK_STATE;
                (void) GC_clear_stack(0);
                return;
 #            else
-               GC_words_allocd += my_words_allocd;
+               GC_bytes_allocd += my_bytes_allocd;
                goto out;
 #            endif
            }
@@ -454,7 +359,6 @@ DCL_LOCK_STATE;
              -- GC_fl_builder_count;
              if (GC_fl_builder_count == 0) GC_notify_all_builder();
              GC_release_mark_lock();
-             DISABLE_SIGNALS();
              LOCK();
              /* GC lock is needed for reclaim list access.     We      */
              /* must decrement fl_builder_count before reaquiring GC   */
@@ -465,33 +369,31 @@ DCL_LOCK_STATE;
     /* Next try to use prefix of global free list if there is one.     */
     /* We don't refill it, but we need to use it up before allocating  */
     /* a new block ourselves.                                          */
-      opp = &(GC_obj_kinds[k].ok_freelist[lw]);
+      opp = &(GC_obj_kinds[k].ok_freelist[lg]);
       if ( (op = *opp) != 0 ) {
        *opp = 0;
-        my_words_allocd = 0;
+        my_bytes_allocd = 0;
         for (p = op; p != 0; p = obj_link(p)) {
-          my_words_allocd += lw;
-          if (my_words_allocd >= BODY_SZ) {
+          my_bytes_allocd += lb;
+          if (my_bytes_allocd >= HBLKSIZE) {
             *opp = obj_link(p);
             obj_link(p) = 0;
             break;
          }
         }
-       GC_words_allocd += my_words_allocd;
+       GC_bytes_allocd += my_bytes_allocd;
        goto out;
       }
     /* Next try to allocate a new block worth of objects of this size. */
     {
-       struct hblk *h = GC_allochblk(lw, k, 0);
+       struct hblk *h = GC_allochblk(lb, k, 0);
        if (h != 0) {
          if (IS_UNCOLLECTABLE(k)) GC_set_hdr_marks(HDR(h));
-         GC_words_allocd += BYTES_TO_WORDS(HBLKSIZE)
-                              - BYTES_TO_WORDS(HBLKSIZE) % lw;
+         GC_bytes_allocd += HBLKSIZE - HBLKSIZE % lb;
 #        ifdef PARALLEL_MARK
            GC_acquire_mark_lock();
            ++ GC_fl_builder_count;
            UNLOCK();
-           ENABLE_SIGNALS();
            GC_release_mark_lock();
 #        endif
 
@@ -518,14 +420,15 @@ DCL_LOCK_STATE;
   out:
     *result = op;
     UNLOCK();
-    ENABLE_SIGNALS();
     (void) GC_clear_stack(0);
 }
 
-GC_PTR GC_malloc_many(size_t lb)
+void * GC_malloc_many(size_t lb)
 {
-    ptr_t result;
-    GC_generic_malloc_many(lb, NORMAL, &result);
+    void *result;
+    GC_generic_malloc_many(((lb + EXTRA_BYTES + GRANULE_BYTES-1)
+                          & ~(GRANULE_BYTES-1)),
+                          NORMAL, &result);
     return result;
 }
 
@@ -534,81 +437,69 @@ GC_PTR GC_malloc_many(size_t lb)
 # endif
 
 /* Allocate lb bytes of pointerful, traced, but not collectable data */
-# ifdef __STDC__
-    GC_PTR GC_malloc_uncollectable(size_t lb)
-# else
-    GC_PTR GC_malloc_uncollectable(lb)
-    size_t lb;
-# endif
+void * GC_malloc_uncollectable(size_t lb)
 {
-register ptr_t op;
-register ptr_t *opp;
-register word lw;
-DCL_LOCK_STATE;
+    void *op;
+    void **opp;
+    size_t lg;
+    DCL_LOCK_STATE;
 
     if( SMALL_OBJ(lb) ) {
-#       ifdef MERGE_SIZES
-         if (EXTRA_BYTES != 0 && lb != 0) lb--;
+       if (EXTRA_BYTES != 0 && lb != 0) lb--;
                  /* We don't need the extra byte, since this won't be  */
                  /* collected anyway.                                  */
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_uobjfreelist[lw]);
-       FASTLOCK();
-        if( FASTLOCK_SUCCEEDED() && (op = *opp) != 0 ) {
+       lg = GC_size_map[lb];
+       opp = &(GC_uobjfreelist[lg]);
+       LOCK();
+        if( (op = *opp) != 0 ) {
             /* See above comment on signals.   */
             *opp = obj_link(op);
             obj_link(op) = 0;
-            GC_words_allocd += lw;
+            GC_bytes_allocd += GRANULES_TO_BYTES(lg);
             /* Mark bit ws already set on free list.  It will be       */
            /* cleared only temporarily during a collection, as a       */
            /* result of the normal free list mark bit clearing.        */
-            GC_non_gc_bytes += WORDS_TO_BYTES(lw);
-            FASTUNLOCK();
-            return((GC_PTR) op);
-        }
-        FASTUNLOCK();
-        op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
+            GC_non_gc_bytes += GRANULES_TO_BYTES(lg);
+            UNLOCK();
+        } else {
+            UNLOCK();
+            op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
+           /* For small objects, the free lists are completely marked. */
+       }
+       GC_ASSERT(0 == op || GC_is_marked(op));
+        return((void *) op);
     } else {
-       op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
-    }
-    if (0 == op) return(0);
-    /* We don't need the lock here, since we have an undisguised       */
-    /* pointer.  We do need to hold the lock while we adjust           */
-    /* mark bits.                                                      */
-    {
-       register struct hblk * h;
+       hdr * hhdr;
        
-       h = HBLKPTR(op);
-       lw = HDR(h) -> hb_sz;
+       op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
+        if (0 == op) return(0);
        
-       DISABLE_SIGNALS();
+       GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0); /* large block */
+       hhdr = HDR((struct hbklk *)op);
+       /* We don't need the lock here, since we have an undisguised    */
+       /* pointer.  We do need to hold the lock while we adjust        */
+       /* mark bits.                                                   */
+       lb = hhdr -> hb_sz;
        LOCK();
-       GC_set_mark_bit(op);
-       GC_non_gc_bytes += WORDS_TO_BYTES(lw);
+       set_mark_bit_from_hdr(hhdr, 0); /* Only object. */
+       GC_ASSERT(hhdr -> hb_n_marks == 0);
+       hhdr -> hb_n_marks = 1;
        UNLOCK();
-       ENABLE_SIGNALS();
-       return((GC_PTR) op);
+       return((void *) op);
     }
 }
 
-#ifdef __STDC__
 /* Not well tested nor integrated.     */
 /* Debug version is tricky and currently missing.      */
 #include <limits.h>
 
-GC_PTR GC_memalign(size_t align, size_t lb) 
+void * GC_memalign(size_t align, size_t lb) 
 { 
     size_t new_lb;
     size_t offset;
     ptr_t result;
 
-#   ifdef ALIGN_DOUBLE
-       if (align <= WORDS_TO_BYTES(2) && lb > align) return GC_malloc(lb);
-#   endif
-    if (align <= WORDS_TO_BYTES(1)) return GC_malloc(lb);
+    if (align <= GRANULE_BYTES) return GC_malloc(lb);
     if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) {
         if (align > HBLKSIZE) return GC_oom_fn(LONG_MAX-1024) /* Fail */;
        return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb);
@@ -626,71 +517,59 @@ GC_PTR GC_memalign(size_t align, size_t lb)
            GC_register_displacement(offset);
        }
     }
-    result = (GC_PTR) ((ptr_t)result + offset);
+    result = (void *) ((ptr_t)result + offset);
     GC_ASSERT((word)result % align == 0);
     return result;
 }
-#endif 
 
 # ifdef ATOMIC_UNCOLLECTABLE
 /* Allocate lb bytes of pointerfree, untraced, uncollectable data      */
 /* This is normally roughly equivalent to the system malloc.           */
 /* But it may be useful if malloc is redefined.                                */
-# ifdef __STDC__
-    GC_PTR GC_malloc_atomic_uncollectable(size_t lb)
-# else
-    GC_PTR GC_malloc_atomic_uncollectable(lb)
-    size_t lb;
-# endif
+void * GC_malloc_atomic_uncollectable(size_t lb)
 {
-register ptr_t op;
-register ptr_t *opp;
-register word lw;
-DCL_LOCK_STATE;
+    void *op;
+    void **opp;
+    size_t lg;
+    DCL_LOCK_STATE;
 
     if( SMALL_OBJ(lb) ) {
-#       ifdef MERGE_SIZES
-         if (EXTRA_BYTES != 0 && lb != 0) lb--;
+       if (EXTRA_BYTES != 0 && lb != 0) lb--;
                  /* We don't need the extra byte, since this won't be  */
                  /* collected anyway.                                  */
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_auobjfreelist[lw]);
-       FASTLOCK();
-        if( FASTLOCK_SUCCEEDED() && (op = *opp) != 0 ) {
+       lg = GC_size_map[lb];
+       opp = &(GC_auobjfreelist[lg]);
+       LOCK();
+        if( (op = *opp) != 0 ) {
             /* See above comment on signals.   */
             *opp = obj_link(op);
             obj_link(op) = 0;
-            GC_words_allocd += lw;
+            GC_bytes_allocd += GRANULES_TO_BYTES(lg);
            /* Mark bit was already set while object was on free list. */
-            GC_non_gc_bytes += WORDS_TO_BYTES(lw);
-            FASTUNLOCK();
-            return((GC_PTR) op);
-        }
-        FASTUNLOCK();
-        op = (ptr_t)GC_generic_malloc((word)lb, AUNCOLLECTABLE);
+            GC_non_gc_bytes += GRANULES_TO_BYTES(lg);
+            UNLOCK();
+        } else {
+            UNLOCK();
+            op = (ptr_t)GC_generic_malloc(lb, AUNCOLLECTABLE);
+       }
+       GC_ASSERT(0 == op || GC_is_marked(op));
+        return((void *) op);
     } else {
-       op = (ptr_t)GC_generic_malloc((word)lb, AUNCOLLECTABLE);
-    }
-    if (0 == op) return(0);
-    /* We don't need the lock here, since we have an undisguised       */
-    /* pointer.  We do need to hold the lock while we adjust           */
-    /* mark bits.                                                      */
-    {
-       register struct hblk * h;
+       hdr * hhdr;
        
-       h = HBLKPTR(op);
-       lw = HDR(h) -> hb_sz;
+       op = (ptr_t)GC_generic_malloc(lb, AUNCOLLECTABLE);
+        if (0 == op) return(0);
+
+       GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0);
+       hhdr = HDR((struct hbklk *)op);
+       lb = hhdr -> hb_sz;
        
-       DISABLE_SIGNALS();
        LOCK();
-       GC_set_mark_bit(op);
-       GC_non_gc_bytes += WORDS_TO_BYTES(lw);
+       set_mark_bit_from_hdr(hhdr, 0); /* Only object. */
+       GC_ASSERT(hhdr -> hb_n_marks == 0);
+       hhdr -> hb_n_marks = 1;
        UNLOCK();
-       ENABLE_SIGNALS();
-       return((GC_PTR) op);
+       return((void *) op);
     }
 }
 
index 057534938b9ac529ce10face6f8ae9858aec3b28..838fef1fca6fdd6e818ef151ab45666aefc1b9fc 100644 (file)
 #endif
 
 /* Single argument version, robust against whole program analysis. */
-void GC_noop1(x)
-word x;
+void GC_noop1(word x)
 {
-    static VOLATILE word sink;
+    static volatile word sink;
 
     sink = x;
 }
 
 /* mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0} -- declared in gc_priv.h */
 
-word GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
+unsigned 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      */
@@ -71,15 +70,15 @@ struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
 
 # ifdef ATOMIC_UNCOLLECTABLE
 #   ifdef STUBBORN_ALLOC
-      int GC_n_kinds = 5;
+      unsigned GC_n_kinds = 5;
 #   else
-      int GC_n_kinds = 4;
+      unsigned GC_n_kinds = 4;
 #   endif
 # else
 #   ifdef STUBBORN_ALLOC
-      int GC_n_kinds = 4;
+      unsigned GC_n_kinds = 4;
 #   else
-      int GC_n_kinds = 3;
+      unsigned GC_n_kinds = 3;
 #   endif
 # endif
 
@@ -107,10 +106,18 @@ mse * GC_mark_stack;
 
 mse * GC_mark_stack_limit;
 
-word GC_mark_stack_size = 0;
+size_t GC_mark_stack_size = 0;
  
 #ifdef PARALLEL_MARK
-  mse * VOLATILE GC_mark_stack_top;
+# include "atomic_ops.h"
+
+  mse * volatile GC_mark_stack_top;
+  /* Updated only with mark lock held, but read asynchronously.        */
+  volatile AO_t GC_first_nonempty;
+       /* Lowest entry on mark stack   */
+       /* that may be nonempty.        */
+       /* Updated only by initiating   */
+       /* thread.                      */
 #else
   mse * GC_mark_stack_top;
 #endif
@@ -127,48 +134,54 @@ GC_bool GC_objects_are_marked = FALSE;    /* Are there collectable marked */
 /* Is a collection in progress?  Note that this can return true in the */
 /* nonincremental case, if a collection has been abandoned and the     */
 /* mark state is now MS_INVALID.                                       */
-GC_bool GC_collection_in_progress()
+GC_bool GC_collection_in_progress(void)
 {
     return(GC_mark_state != MS_NONE);
 }
 
 /* clear all mark bits in the header */
-void GC_clear_hdr_marks(hhdr)
-register hdr * hhdr;
+void GC_clear_hdr_marks(hdr *hhdr)
 {
+    size_t last_bit = FINAL_MARK_BIT(hhdr -> hb_sz);
+
 #   ifdef USE_MARK_BYTES
       BZERO(hhdr -> hb_marks, MARK_BITS_SZ);
+      hhdr -> hb_marks[last_bit] = 1;
 #   else
       BZERO(hhdr -> hb_marks, MARK_BITS_SZ*sizeof(word));
+      set_mark_bit_from_hdr(hhdr, last_bit);
 #   endif
+    hhdr -> hb_n_marks = 0;
 }
 
 /* Set all mark bits in the header.  Used for uncollectable blocks. */
-void GC_set_hdr_marks(hhdr)
-register hdr * hhdr;
+void GC_set_hdr_marks(hdr *hhdr)
 {
-    register int i;
+    unsigned i;
+    size_t sz = hhdr -> hb_sz;
+    size_t n_marks = FINAL_MARK_BIT(sz);
 
-    for (i = 0; i < MARK_BITS_SZ; ++i) {
-#     ifdef USE_MARK_BYTES
+#   ifdef USE_MARK_BYTES
+      for (i = 0; i <= n_marks; i += MARK_BIT_OFFSET(sz)) {
        hhdr -> hb_marks[i] = 1;
-#     else
+      }
+#   else
+      for (i = 0; i < divWORDSZ(n_marks + WORDSZ); ++i) {
        hhdr -> hb_marks[i] = ONES;
-#     endif
-    }
+      }
+#   endif
+#   ifdef MARK_BIT_PER_OBJ
+      hhdr -> hb_n_marks = n_marks - 1;
+#   else
+      hhdr -> hb_n_marks = HBLK_OBJS(sz);
+#   endif
 }
 
 /*
  * Clear all mark bits associated with block h.
  */
 /*ARGSUSED*/
-# if defined(__STDC__) || defined(__cplusplus)
-    static void clear_marks_for_block(struct hblk *h, word dummy)
-# else
-    static void clear_marks_for_block(h, dummy)
-    struct hblk *h;
-    word dummy;
-# endif
+static void clear_marks_for_block(struct hblk *h, word dummy)
 {
     register hdr * hhdr = HDR(h);
     
@@ -180,34 +193,47 @@ register hdr * hhdr;
 }
 
 /* Slow but general routines for setting/clearing/asking about mark bits */
-void GC_set_mark_bit(p)
-ptr_t p;
+void GC_set_mark_bit(ptr_t p)
 {
-    register struct hblk *h = HBLKPTR(p);
-    register hdr * hhdr = HDR(h);
-    register int word_no = (word *)p - (word *)h;
+    struct hblk *h = HBLKPTR(p);
+    hdr * hhdr = HDR(h);
+    word bit_no = MARK_BIT_NO(p - (ptr_t)h, hhdr -> hb_sz);
     
-    set_mark_bit_from_hdr(hhdr, word_no);
+    if (!mark_bit_from_hdr(hhdr, bit_no)) {
+      set_mark_bit_from_hdr(hhdr, bit_no);
+      ++hhdr -> hb_n_marks;
+    }
 }
 
-void GC_clear_mark_bit(p)
-ptr_t p;
+void GC_clear_mark_bit(ptr_t p)
 {
-    register struct hblk *h = HBLKPTR(p);
-    register hdr * hhdr = HDR(h);
-    register int word_no = (word *)p - (word *)h;
+    struct hblk *h = HBLKPTR(p);
+    hdr * hhdr = HDR(h);
+    word bit_no = MARK_BIT_NO(p - (ptr_t)h, hhdr -> hb_sz);
     
-    clear_mark_bit_from_hdr(hhdr, word_no);
+    if (mark_bit_from_hdr(hhdr, bit_no)) {
+      size_t n_marks;
+      clear_mark_bit_from_hdr(hhdr, bit_no);
+      n_marks = hhdr -> hb_n_marks - 1;
+#     ifdef PARALLEL_MARK
+        if (n_marks != 0)
+          hhdr -> hb_n_marks = n_marks; 
+        /* Don't decrement to zero.  The counts are approximate due to */
+        /* concurrency issues, but we need to ensure that a count of   */
+        /* zero implies an empty block.                                        */
+#     else
+          hhdr -> hb_n_marks = n_marks; 
+#     endif
+    }
 }
 
-GC_bool GC_is_marked(p)
-ptr_t p;
+GC_bool GC_is_marked(ptr_t p)
 {
-    register struct hblk *h = HBLKPTR(p);
-    register hdr * hhdr = HDR(h);
-    register int word_no = (word *)p - (word *)h;
+    struct hblk *h = HBLKPTR(p);
+    hdr * hhdr = HDR(h);
+    word bit_no = MARK_BIT_NO(p - (ptr_t)h, hhdr -> hb_sz);
     
-    return(mark_bit_from_hdr(hhdr, word_no));
+    return((GC_bool)mark_bit_from_hdr(hhdr, bit_no));
 }
 
 
@@ -216,24 +242,18 @@ ptr_t p;
  * the marker invariant, and sets GC_mark_state to reflect this.
  * (This implicitly starts marking to reestablish the invariant.)
  */
-void GC_clear_marks()
+void GC_clear_marks(void)
 {
     GC_apply_to_all_blocks(clear_marks_for_block, (word)0);
     GC_objects_are_marked = FALSE;
     GC_mark_state = MS_INVALID;
     scan_ptr = 0;
-#   ifdef GATHERSTATS
-       /* Counters reflect currently marked objects: reset here */
-        GC_composite_in_use = 0;
-        GC_atomic_in_use = 0;
-#   endif
-
 }
 
 /* Initiate a garbage collection.  Initiates a full collection if the  */
 /* mark        state is invalid.                                               */
 /*ARGSUSED*/
-void GC_initiate_gc()
+void GC_initiate_gc(void)
 {
     if (GC_dirty_maintained) GC_read_dirty();
 #   ifdef STUBBORN_ALLOC
@@ -257,7 +277,14 @@ void GC_initiate_gc()
 }
 
 
-static void alloc_mark_stack();
+static void alloc_mark_stack(size_t);
+
+# if defined(MSWIN32) || defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS)
+    /* Under rare conditions, we may end up marking from nonexistent memory. */
+    /* Hence we need to be prepared to recover by running GC_mark_some      */
+    /* with a suitable handler in place.                                    */
+#   define WRAP_MARK_SOME
+# endif
 
 /* Perform a small amount of marking.                  */
 /* We try to touch roughly a page of memory.           */
@@ -268,16 +295,14 @@ static void alloc_mark_stack();
 /* register values.                                    */
 /* We hold the allocation lock.  In the case of        */
 /* incremental collection, the world may not be stopped.*/
-#ifdef MSWIN32
+#ifdef WRAP_MARK_SOME
   /* For win32, this is called after we establish a structured */
   /* exception handler, in case Windows unmaps one of our root */
   /* segments.  See below.  In either case, we acquire the     */
   /* allocator lock long before we get here.                   */
-  GC_bool GC_mark_some_inner(cold_gc_frame)
-  ptr_t cold_gc_frame;
+  GC_bool GC_mark_some_inner(ptr_t cold_gc_frame)
 #else
-  GC_bool GC_mark_some(cold_gc_frame)
-  ptr_t cold_gc_frame;
+  GC_bool GC_mark_some(ptr_t cold_gc_frame)
 #endif
 {
     switch(GC_mark_state) {
@@ -296,12 +321,10 @@ static void alloc_mark_stack();
            } else {
                scan_ptr = GC_push_next_marked_dirty(scan_ptr);
                if (scan_ptr == 0) {
-#                  ifdef CONDPRINT
-                     if (GC_print_stats) {
-                       GC_printf1("Marked from %lu dirty pages\n",
-                                  (unsigned long)GC_n_rescuing_pages);
-                     }
-#                  endif
+                   if (GC_print_stats) {
+                       GC_log_printf("Marked from %u dirty pages\n",
+                                     GC_n_rescuing_pages);
+                   }
                    GC_push_roots(FALSE, cold_gc_frame);
                    GC_objects_are_marked = TRUE;
                    if (GC_mark_state != MS_INVALID) {
@@ -345,7 +368,7 @@ static void alloc_mark_stack();
              /* the allocation lock.                                   */
                if (GC_parallel) {
                  GC_do_parallel_mark();
-                 GC_ASSERT(GC_mark_stack_top < GC_first_nonempty);
+                 GC_ASSERT(GC_mark_stack_top < (mse *)GC_first_nonempty);
                  GC_mark_stack_top = GC_mark_stack - 1;
                  if (GC_mark_stack_too_small) {
                    alloc_mark_stack(2*GC_mark_stack_size);
@@ -403,9 +426,7 @@ static void alloc_mark_stack();
 }
 
 
-#ifdef MSWIN32
-
-# ifdef __GNUC__
+#if defined(MSWIN32) && defined(__GNUC__)
 
     typedef struct {
       EXCEPTION_REGISTRATION ex_reg;
@@ -440,15 +461,21 @@ static void alloc_mark_stack();
             return ExceptionContinueSearch;
         }
     }
-# endif /* __GNUC__ */
+# endif /* __GNUC__  && MSWIN32 */
 
+#ifdef GC_WIN32_THREADS
+  extern GC_bool GC_started_thread_while_stopped(void);
+  /* In win32_threads.c.  Did we invalidate mark phase with an */
+  /* unexpected thread start?                                  */
+#endif
 
-  GC_bool GC_mark_some(cold_gc_frame)
-  ptr_t cold_gc_frame;
+# ifdef WRAP_MARK_SOME
+  GC_bool GC_mark_some(ptr_t cold_gc_frame)
   {
       GC_bool ret_val;
 
-#   ifndef __GNUC__
+#   ifdef MSWIN32
+#    ifndef __GNUC__
       /* Windows 98 appears to asynchronously create and remove  */
       /* writable memory mappings, for reasons we haven't yet    */
       /* understood.  Since we look for writable regions to      */
@@ -458,10 +485,28 @@ static void alloc_mark_stack();
       /* This code does not appear to be necessary for Windows   */
       /* 95/NT/2000. Note that this code should never generate   */
       /* an incremental GC write fault.                          */
+      /* It's conceivable that this is the same issue with      */
+      /* terminating threads that we see with Linux and                 */
+      /* USE_PROC_FOR_LIBRARIES.                                */
 
       __try {
+          ret_val = GC_mark_some_inner(cold_gc_frame);
+      } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
+                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+         goto handle_ex;
+      }
+#     ifdef GC_WIN32_THREADS
+       /* With DllMain-based thread tracking, a thread may have        */
+       /* started while we were marking.  This is logically equivalent */
+       /* to the exception case; our results are invalid and we have   */
+       /* to start over.  This cannot be prevented since we can't      */
+       /* block in DllMain.                                            */
+       if (GC_started_thread_while_stopped()) goto handle_ex;
+#     endif
+     rm_handler:
+      return ret_val;
 
-#   else /* __GNUC__ */
+#    else /* __GNUC__ */
 
       /* Manually install an exception handler since GCC does    */
       /* not yet support Structured Exception Handling (SEH) on  */
@@ -473,132 +518,78 @@ static void alloc_mark_stack();
       er.ex_reg.handler = mark_ex_handler;
       asm volatile ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));
       asm volatile ("movl %0, %%fs:0" : : "r" (&er));
+      ret_val = GC_mark_some_inner(cold_gc_frame);
+      /* Prevent GCC from considering the following code unreachable */
+      /* and thus eliminating it.                                    */
+        if (er.alt_path == 0)
+          goto handle_ex;
+    rm_handler:
+      /* Uninstall the exception handler */
+      asm volatile ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
+      return ret_val;
 
-#   endif /* __GNUC__ */
-
-          ret_val = GC_mark_some_inner(cold_gc_frame);
-
-#   ifndef __GNUC__
-
-      } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
-                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
-
-#   else /* __GNUC__ */
-
-          /* Prevent GCC from considering the following code unreachable */
-          /* and thus eliminating it.                                    */
-          if (er.alt_path != 0)
-              goto rm_handler;
+#    endif /* __GNUC__ */
+#   else /* !MSWIN32 */
+      /* Here we are handling the case in which /proc is used for root */
+      /* finding, and we have threads.  We may find a stack for a      */
+      /* thread that is in the process of exiting, and disappears      */
+      /* while we are marking it.  This seems extremely difficult to   */
+      /* avoid otherwise.                                              */
+      if (GC_incremental)
+             WARN("Incremental GC incompatible with /proc roots\n", 0);
+       /* I'm not sure if this could still work ...    */
+      GC_setup_temporary_fault_handler();
+      if(SETJMP(GC_jmp_buf) != 0) goto handle_ex;
+      ret_val = GC_mark_some_inner(cold_gc_frame);
+    rm_handler:
+      GC_reset_fault_handler();
+      return ret_val;
+      
+#   endif /* !MSWIN32 */
 
 handle_ex:
-          /* Execution resumes from here on an access violation. */
-
-#   endif /* __GNUC__ */
-
-#         ifdef CONDPRINT
-            if (GC_print_stats) {
-             GC_printf0("Caught ACCESS_VIOLATION in marker. "
-                        "Memory mapping disappeared.\n");
-            }
-#         endif /* CONDPRINT */
-
-          /* We have bad roots on the stack.  Discard mark stack.  */
-          /* Rescan from marked objects.  Redetermine roots.    */
-          GC_invalidate_mark_state();  
-          scan_ptr = 0;
-
-          ret_val = FALSE;
-
-#   ifndef __GNUC__
-
+    /* Exception handler starts here for all cases. */
+      if (GC_print_stats) {
+        GC_log_printf("Caught ACCESS_VIOLATION in marker. "
+                     "Memory mapping disappeared.\n");
       }
 
-#   else /* __GNUC__ */
-
-rm_handler:
-      /* Uninstall the exception handler */
-      asm volatile ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
-
-#   endif /* __GNUC__ */
+      /* We have bad roots on the stack.  Discard mark stack.  */
+      /* Rescan from marked objects.  Redetermine roots.       */
+      GC_invalidate_mark_state();      
+      scan_ptr = 0;
 
-      return ret_val;
+      ret_val = FALSE;
+      goto rm_handler;  // Back to platform-specific code.
   }
-#endif /* MSWIN32 */
+#endif /* WRAP_MARK_SOME */
 
 
-GC_bool GC_mark_stack_empty()
+GC_bool GC_mark_stack_empty(void)
 {
     return(GC_mark_stack_top < GC_mark_stack);
 }      
 
-#ifdef PROF_MARKER
-    word GC_prof_array[10];
-#   define PROF(n) GC_prof_array[n]++
-#else
-#   define PROF(n)
-#endif
-
-/* Given a pointer to someplace other than a small object page or the  */
-/* first page of a large object, either:                               */
-/*     - return a pointer to somewhere in the first page of the large  */
-/*       object, if current points to a large object.                  */
-/*       In this case *hhdr is replaced with a pointer to the header   */
-/*       for the large object.                                         */
-/*     - just return current if it does not point to a large object.   */
-/*ARGSUSED*/
-ptr_t GC_find_start(current, hhdr, new_hdr_p)
-register ptr_t current;
-register hdr *hhdr, **new_hdr_p;
-{
-    if (GC_all_interior_pointers) {
-       if (hhdr != 0) {
-           register ptr_t orig = current;
-           
-           current = (ptr_t)HBLKPTR(current);
-           do {
-             current = current - HBLKSIZE*(word)hhdr;
-             hhdr = HDR(current);
-           } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
-           /* current points to near the start of the large object */
-           if (hhdr -> hb_flags & IGNORE_OFF_PAGE) return(orig);
-           if ((word *)orig - (word *)current
-                >= (ptrdiff_t)(hhdr->hb_sz)) {
-               /* Pointer past the end of the block */
-               return(orig);
-           }
-           *new_hdr_p = hhdr;
-           return(current);
-       } else {
-           return(current);
-        }
-    } else {
-        return(current);
-    }
-}
-
-void GC_invalidate_mark_state()
+void GC_invalidate_mark_state(void)
 {
     GC_mark_state = MS_INVALID;
     GC_mark_stack_top = GC_mark_stack-1;
 }
 
-mse * GC_signal_mark_stack_overflow(msp)
-mse * msp;
+mse * GC_signal_mark_stack_overflow(mse *msp)
 {
     GC_mark_state = MS_INVALID;
     GC_mark_stack_too_small = TRUE;
-#   ifdef CONDPRINT
-      if (GC_print_stats) {
-       GC_printf1("Mark stack overflow; current size = %lu entries\n",
-                   GC_mark_stack_size);
-      }
-#   endif
+    if (GC_print_stats) {
+       GC_log_printf("Mark stack overflow; current size = %lu entries\n",
+                     GC_mark_stack_size);
+    }
     return(msp - GC_MARK_STACK_DISCARDS);
 }
 
 /*
  * Mark objects pointed to by the regions described by
- * mark stack entries between GC_mark_stack and GC_mark_stack_top,
+ * mark stack entries between mark_stack and mark_stack_top,
  * inclusive.  Assumes the upper limit of a mark stack entry
  * 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.
@@ -610,19 +601,16 @@ mse * msp;
  * encoding, we optionally maintain a cache for the block address to
  * header mapping, we prefetch when an object is "grayed", etc. 
  */
-mse * GC_mark_from(mark_stack_top, mark_stack, mark_stack_limit)
-mse * mark_stack_top;
-mse * mark_stack;
-mse * mark_stack_limit;
+mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack, mse *mark_stack_limit)
 {
-  int credit = HBLKSIZE;       /* Remaining credit for marking work    */
-  register word * current_p;   /* Pointer to current candidate ptr.    */
-  register word current;       /* Candidate pointer.                   */
-  register word * limit;       /* (Incl) limit of current candidate    */
+  signed_word credit = HBLKSIZE;  /* Remaining credit for marking work */
+  ptr_t current_p;     /* Pointer to current candidate ptr.    */
+  word current;        /* Candidate pointer.                   */
+  ptr_t limit; /* (Incl) limit of current candidate    */
                                /* range                                */
-  register word descr;
-  register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
-  register ptr_t least_ha = GC_least_plausible_heap_addr;
+  word descr;
+  ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+  ptr_t least_ha = GC_least_plausible_heap_addr;
   DECLARE_HDR_CACHE;
 
 # define SPLIT_RANGE_WORDS 128  /* Must be power of 2.         */
@@ -653,6 +641,13 @@ mse * mark_stack_limit;
           /* stack.                                                    */
          GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
                            - (word)GC_least_plausible_heap_addr);
+#        ifdef ENABLE_TRACE
+           if (GC_trace_addr >= current_p
+               && GC_trace_addr < current_p + descr) {
+               GC_log_printf("GC:%d Large section; start %p len %lu\n",
+                             GC_gc_no, current_p, (unsigned long) descr);
+           }
+#        endif /* ENABLE_TRACE */
 #        ifdef PARALLEL_MARK
 #          define SHARE_BYTES 2048
            if (descr > SHARE_BYTES && GC_parallel
@@ -663,49 +658,84 @@ mse * mark_stack_limit;
                                        /* makes sure we handle         */
                                        /* misaligned pointers.         */
              mark_stack_top++;
-             current_p = (word *) ((char *)current_p + new_size);
+#            ifdef ENABLE_TRACE
+               if (GC_trace_addr >= current_p
+                   && GC_trace_addr < current_p + descr) {
+                   GC_log_printf("GC:%d splitting (parallel) %p at %p\n",
+                                 GC_gc_no, current_p, current_p + new_size);
+               }
+#            endif /* ENABLE_TRACE */
+             current_p += new_size;
              descr -= new_size;
              goto retry;
            }
 #        endif /* PARALLEL_MARK */
           mark_stack_top -> mse_start =
-               limit = current_p + SPLIT_RANGE_WORDS-1;
+               limit = current_p + WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
           mark_stack_top -> mse_descr =
                        descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
+#        ifdef ENABLE_TRACE
+           if (GC_trace_addr >= current_p
+               && GC_trace_addr < current_p + descr) {
+               GC_log_printf("GC:%d splitting %p at %p\n",
+                             GC_gc_no, current_p, limit);
+           }
+#        endif /* ENABLE_TRACE */
           /* Make sure that pointers overlapping the two ranges are    */
           /* considered.                                               */
-          limit = (word *)((char *)limit + sizeof(word) - ALIGNMENT);
+          limit += sizeof(word) - ALIGNMENT;
           break;
         case GC_DS_BITMAP:
           mark_stack_top--;
+#        ifdef ENABLE_TRACE
+           if (GC_trace_addr >= current_p
+               && GC_trace_addr < current_p + WORDS_TO_BYTES(WORDSZ-2)) {
+               GC_log_printf("GC:%d Tracing from %p bitmap descr %lu\n",
+                             GC_gc_no, current_p, (unsigned long) descr);
+           }
+#        endif /* ENABLE_TRACE */
           descr &= ~GC_DS_TAGS;
           credit -= WORDS_TO_BYTES(WORDSZ/2); /* guess */
           while (descr != 0) {
             if ((signed_word)descr < 0) {
-              current = *current_p;
+              current = *(word *)current_p;
              FIXUP_POINTER(current);
              if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
                PREFETCH((ptr_t)current);
-                HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
+#               ifdef ENABLE_TRACE
+                 if (GC_trace_addr == current_p) {
+                   GC_log_printf("GC:%d Considering(3) %p -> %p\n",
+                                 GC_gc_no, current_p, (ptr_t) current);
+                 }
+#               endif /* ENABLE_TRACE */
+                PUSH_CONTENTS((ptr_t)current, mark_stack_top,
                              mark_stack_limit, current_p, exit1);
              }
             }
            descr <<= 1;
-           ++ current_p;
+           current_p += sizeof(word);
           }
           continue;
         case GC_DS_PROC:
           mark_stack_top--;
+#        ifdef ENABLE_TRACE
+           if (GC_trace_addr >= current_p
+               && GC_base(current_p) != 0
+               && GC_base(current_p) == GC_base(GC_trace_addr)) {
+               GC_log_printf("GC:%d Tracing from %p proc descr %lu\n",
+                             GC_gc_no, current_p, (unsigned long) descr);
+           }
+#        endif /* ENABLE_TRACE */
           credit -= GC_PROC_BYTES;
           mark_stack_top =
               (*PROC(descr))
-                   (current_p, mark_stack_top,
+                   ((word *)current_p, mark_stack_top,
                    mark_stack_limit, ENV(descr));
           continue;
         case GC_DS_PER_OBJECT:
          if ((signed_word)descr >= 0) {
            /* Descriptor is in the object.     */
-            descr = *(word *)((ptr_t)current_p + descr - GC_DS_PER_OBJECT);
+            descr = *(word *)(current_p + descr - GC_DS_PER_OBJECT);
          } else {
            /* Descriptor is in type descriptor pointed to by first     */
            /* word in object.                                          */
@@ -728,7 +758,7 @@ mse * mark_stack_limit;
          }
          if (0 == descr) {
              /* Can happen either because we generated a 0 descriptor  */
-             /* or we saw a pointer to a free object.                  */
+             /* or we saw a pointer to a free object.          */
              mark_stack_top--;
              continue;
          }
@@ -736,12 +766,19 @@ mse * mark_stack_limit;
       }
     } else /* Small object with length descriptor */ {
       mark_stack_top--;
-      limit = (word *)(((ptr_t)current_p) + (word)descr);
+      limit = current_p + (word)descr;
     }
+#   ifdef ENABLE_TRACE
+       if (GC_trace_addr >= current_p
+           && GC_trace_addr < limit) {
+           GC_log_printf("GC:%d Tracing from %p len %lu\n",
+                         GC_gc_no, current_p, (unsigned long) descr);
+       }
+#   endif /* ENABLE_TRACE */
     /* The simple case in which we're scanning a range.        */
     GC_ASSERT(!((word)current_p & (ALIGNMENT-1)));
-    credit -= (ptr_t)limit - (ptr_t)current_p;
-    limit -= 1;
+    credit -= limit - current_p;
+    limit -= sizeof(word);
     {
 #     define PREF_DIST 4
 
@@ -755,11 +792,11 @@ mse * mark_stack_limit;
        /* 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);
+         PREFETCH(limit - PREF_DIST*CACHE_LINE_SIZE);
          GC_ASSERT(limit >= current_p);
-         deferred = *limit;
+         deferred = *(word *)limit;
          FIXUP_POINTER(deferred);
-         limit = (word *)((char *)limit - ALIGNMENT);
+         limit -= ALIGNMENT;
          if ((ptr_t)deferred >= least_ha && (ptr_t)deferred <  greatest_ha) {
            PREFETCH((ptr_t)deferred);
            break;
@@ -767,9 +804,9 @@ mse * mark_stack_limit;
          if (current_p > limit) goto next_object;
          /* Unroll once, so we don't do too many of the prefetches     */
          /* based on limit.                                            */
-         deferred = *limit;
+         deferred = *(word *)limit;
          FIXUP_POINTER(deferred);
-         limit = (word *)((char *)limit - ALIGNMENT);
+         limit -= ALIGNMENT;
          if ((ptr_t)deferred >= least_ha && (ptr_t)deferred <  greatest_ha) {
            PREFETCH((ptr_t)deferred);
            break;
@@ -780,26 +817,38 @@ mse * mark_stack_limit;
 
       while (current_p <= limit) {
        /* Empirically, unrolling this loop doesn't help a lot. */
-       /* Since HC_PUSH_CONTENTS expands to a lot of code,     */
+       /* Since PUSH_CONTENTS expands to a lot of code,        */
        /* we don't.                                            */
-        current = *current_p;
+        current = *(word *)current_p;
        FIXUP_POINTER(current);
-        PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE);
+        PREFETCH(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((ptr_t)current);
-          HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
+#         ifdef ENABLE_TRACE
+           if (GC_trace_addr == current_p) {
+               GC_log_printf("GC:%d Considering(1) %p -> %p\n",
+                             GC_gc_no, current_p, (ptr_t) current);
+           }
+#         endif /* ENABLE_TRACE */
+          PUSH_CONTENTS((ptr_t)current, mark_stack_top,
                           mark_stack_limit, current_p, exit2);
         }
-        current_p = (word *)((char *)current_p + ALIGNMENT);
+        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        */
+       /* We already know that it passes the preliminary pointer       */
        /* validity test.                                               */
-        HC_PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
+#       ifdef ENABLE_TRACE
+           if (GC_trace_addr == current_p) {
+               GC_log_printf("GC:%d Considering(2) %p -> %p\n",
+                             GC_gc_no, current_p, (ptr_t) deferred);
+           }
+#       endif /* ENABLE_TRACE */
+        PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
                         mark_stack_limit, current_p, exit4);
        next_object:;
 #     endif
@@ -814,7 +863,6 @@ mse * mark_stack_limit;
 GC_bool GC_help_wanted = FALSE;
 unsigned GC_helper_count = 0;
 unsigned GC_active_count = 0;
-mse * VOLATILE GC_first_nonempty;
 word GC_mark_no = 0;
 
 #define LOCAL_MARK_STACK_SIZE HBLKSIZE
@@ -835,33 +883,20 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
     mse *top = local - 1;
     unsigned i = 0;
 
-    /* Make sure that prior writes to the mark stack are visible. */
-    /* On some architectures, the fact that the reads are        */
-    /* volatile should suffice.                                          */
-#   if !defined(IA64) && !defined(HP_PA) && !defined(I386)
-      GC_memory_barrier();
-#   endif
     GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size);
     for (p = low; p <= high && i <= max; ++p) {
-       word descr = *(volatile word *) &(p -> mse_descr);
-       /* In the IA64 memory model, the following volatile store is    */
-       /* ordered after this read of descr.  Thus a thread must read   */
-       /* the original nonzero value.  HP_PA appears to be similar,    */
-       /* and if I'm reading the P4 spec correctly, X86 is probably    */
-       /* also OK.  In some other cases we need a barrier.             */
-#       if !defined(IA64) && !defined(HP_PA) && !defined(I386)
-          GC_memory_barrier();
-#       endif
+       word descr = AO_load((volatile AO_t *) &(p -> mse_descr));
        if (descr != 0) {
-           *(volatile word *) &(p -> mse_descr) = 0;
+           /* Must be ordered after read of descr: */
+           AO_store_release_write((volatile AO_t *) &(p -> mse_descr), 0);
            /* More than one thread may get this entry, but that's only */
            /* a minor performance problem.                             */
            ++top;
            top -> mse_descr = descr;
            top -> mse_start = p -> mse_start;
-           GC_ASSERT(  (top -> mse_descr & GC_DS_TAGS) != GC_DS_LENGTH || 
-                       top -> mse_descr < (ptr_t)GC_greatest_plausible_heap_addr
-                                          - (ptr_t)GC_least_plausible_heap_addr);
+           GC_ASSERT((top -> mse_descr & GC_DS_TAGS) != GC_DS_LENGTH || 
+                     top -> mse_descr < (ptr_t)GC_greatest_plausible_heap_addr
+                                        - (ptr_t)GC_least_plausible_heap_addr);
            /* If this is a big object, count it as                     */
            /* size/256 + 1 objects.                                    */
            ++i;
@@ -883,25 +918,22 @@ void GC_return_mark_stack(mse * low, mse * high)
     if (high < low) return;
     stack_size = high - low + 1;
     GC_acquire_mark_lock();
-    my_top = GC_mark_stack_top;
+    my_top = GC_mark_stack_top;        /* Concurrent modification impossible. */
     my_start = my_top + 1;
     if (my_start - GC_mark_stack + stack_size > GC_mark_stack_size) {
-#     ifdef CONDPRINT
-       if (GC_print_stats) {
-         GC_printf0("No room to copy back mark stack.");
-       }
-#     endif
+      if (GC_print_stats) {
+         GC_log_printf("No room to copy back mark stack.");
+      }
       GC_mark_state = MS_INVALID;
       GC_mark_stack_too_small = TRUE;
       /* We drop the local mark stack.  We'll fix things later.        */
     } else {
       BCOPY(low, my_start, stack_size * sizeof(mse));
-      GC_ASSERT(GC_mark_stack_top = my_top);
-#     if !defined(IA64) && !defined(HP_PA)
-        GC_memory_barrier();
-#     endif
-       /* On IA64, the volatile write acts as a release barrier. */
-      GC_mark_stack_top = my_top + stack_size;
+      GC_ASSERT((mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))
+               == my_top);
+      AO_store_release_write((volatile AO_t *)(&GC_mark_stack_top),
+                            (AO_t)(my_top + stack_size));
+               /* Ensures visibility of previously written stack contents. */
     }
     GC_release_mark_lock();
     GC_notify_all_marker();
@@ -931,15 +963,15 @@ void GC_do_local_mark(mse *local_mark_stack, mse *local_top)
                return;
            }
        }
-       if (GC_mark_stack_top < GC_first_nonempty &&
-           GC_active_count < GC_helper_count
+       if ((mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))
+           < (mse *)AO_load(&GC_first_nonempty)
+           && GC_active_count < GC_helper_count
            && local_top > local_mark_stack + 1) {
            /* Try to share the load, since the main stack is empty,    */
            /* and helper threads are waiting for a refill.             */
            /* The entries near the bottom of the stack are likely      */
            /* to require more work.  Thus we return those, eventhough  */
            /* it's harder.                                             */
-           mse * p;
            mse * new_bottom = local_mark_stack
                                + (local_top - local_mark_stack)/2;
            GC_ASSERT(new_bottom > local_mark_stack
@@ -969,41 +1001,44 @@ void GC_mark_local(mse *local_mark_stack, int id)
 
     GC_acquire_mark_lock();
     GC_active_count++;
-    my_first_nonempty = GC_first_nonempty;
-    GC_ASSERT(GC_first_nonempty >= GC_mark_stack && 
-             GC_first_nonempty <= GC_mark_stack_top + 1);
-#   ifdef PRINTSTATS
-       GC_printf1("Starting mark helper %lu\n", (unsigned long)id);
-#   endif
+    my_first_nonempty = (mse *)AO_load(&GC_first_nonempty);
+    GC_ASSERT((mse *)AO_load(&GC_first_nonempty) >= GC_mark_stack && 
+             (mse *)AO_load(&GC_first_nonempty) <=
+             (mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top)) + 1);
+    if (GC_print_stats == VERBOSE)
+       GC_log_printf("Starting mark helper %lu\n", (unsigned long)id);
     GC_release_mark_lock();
     for (;;) {
        size_t n_on_stack;
         size_t n_to_get;
-       mse *next;
        mse * my_top;
        mse * local_top;
-        mse * global_first_nonempty = GC_first_nonempty;
+        mse * global_first_nonempty = (mse *)AO_load(&GC_first_nonempty);
 
        GC_ASSERT(my_first_nonempty >= GC_mark_stack && 
-                 my_first_nonempty <= GC_mark_stack_top + 1);
+                 my_first_nonempty <=
+                 (mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))  + 1);
        GC_ASSERT(global_first_nonempty >= GC_mark_stack && 
-                 global_first_nonempty <= GC_mark_stack_top + 1);
+                 global_first_nonempty <= 
+                 (mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))  + 1);
        if (my_first_nonempty < global_first_nonempty) {
            my_first_nonempty = global_first_nonempty;
         } else if (global_first_nonempty < my_first_nonempty) {
-           GC_compare_and_exchange((word *)(&GC_first_nonempty)
-                                  (word) global_first_nonempty,
-                                  (word) my_first_nonempty);
+           AO_compare_and_swap(&GC_first_nonempty
+                               (AO_t) global_first_nonempty,
+                               (AO_t) my_first_nonempty);
            /* If this fails, we just go ahead, without updating        */
            /* GC_first_nonempty.                                       */
        }
        /* Perhaps we should also update GC_first_nonempty, if it */
        /* is less.  But that would require using atomic updates. */
-       my_top = GC_mark_stack_top;
+       my_top = (mse *)AO_load_acquire((volatile AO_t *)(&GC_mark_stack_top));
        n_on_stack = my_top - my_first_nonempty + 1;
         if (0 == n_on_stack) {
            GC_acquire_mark_lock();
             my_top = GC_mark_stack_top;
+               /* Asynchronous modification impossible here,   */
+               /* since we hold mark lock.                     */
             n_on_stack = my_top - my_first_nonempty + 1;
            if (0 == n_on_stack) {
                GC_active_count--;
@@ -1012,14 +1047,15 @@ void GC_mark_local(mse *local_mark_stack, int id)
                /* on the stack.                                */
                if (0 == GC_active_count) GC_notify_all_marker();
                while (GC_active_count > 0
-                      && GC_first_nonempty > GC_mark_stack_top) {
+                      && (mse *)AO_load(&GC_first_nonempty)
+                         > GC_mark_stack_top) {
                    /* We will be notified if either GC_active_count    */
                    /* reaches zero, or if more objects are pushed on   */
                    /* the global mark stack.                           */
                    GC_wait_marker();
                }
                if (GC_active_count == 0 &&
-                   GC_first_nonempty > GC_mark_stack_top) { 
+                   (mse *)AO_load(&GC_first_nonempty) > GC_mark_stack_top) { 
                    GC_bool need_to_notify = FALSE;
                    /* The above conditions can't be falsified while we */
                    /* hold the mark lock, since neither                */
@@ -1029,10 +1065,9 @@ void GC_mark_local(mse *local_mark_stack, int id)
                    /* both conditions actually held simultaneously.    */
                    GC_helper_count--;
                    if (0 == GC_helper_count) need_to_notify = TRUE;
-#                  ifdef PRINTSTATS
-                     GC_printf1(
+                   if (GC_print_stats == VERBOSE)
+                     GC_log_printf(
                        "Finished mark helper %lu\n", (unsigned long)id);
-#                  endif
                    GC_release_mark_lock();
                    if (need_to_notify) GC_notify_all_marker();
                    return;
@@ -1053,7 +1088,8 @@ void GC_mark_local(mse *local_mark_stack, int id)
                                        local_mark_stack, n_to_get,
                                        &my_first_nonempty);
         GC_ASSERT(my_first_nonempty >= GC_mark_stack && 
-                 my_first_nonempty <= GC_mark_stack_top + 1);
+                 my_first_nonempty <=
+                   (mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top)) + 1);
        GC_do_local_mark(local_mark_stack, local_top);
     }
 }
@@ -1065,8 +1101,6 @@ void GC_mark_local(mse *local_mark_stack, int id)
 void GC_do_parallel_mark()
 {
     mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
-    mse * local_top;
-    mse * my_top;
 
     GC_acquire_mark_lock();
     GC_ASSERT(I_HOLD_LOCK());
@@ -1074,11 +1108,10 @@ void GC_do_parallel_mark()
     /* all the time, especially since it's cheap.                      */
     if (GC_help_wanted || GC_active_count != 0 || GC_helper_count != 0)
        ABORT("Tried to start parallel mark in bad state");
-#   ifdef PRINTSTATS
-       GC_printf1("Starting marking for mark phase number %lu\n",
+    if (GC_print_stats == VERBOSE)
+       GC_log_printf("Starting marking for mark phase number %lu\n",
                   (unsigned long)GC_mark_no);
-#   endif
-    GC_first_nonempty = GC_mark_stack;
+    GC_first_nonempty = (AO_t)GC_mark_stack;
     GC_active_count = 0;
     GC_helper_count = 1;
     GC_help_wanted = TRUE;
@@ -1091,11 +1124,10 @@ void GC_do_parallel_mark()
     /* Done; clean up. */
     while (GC_helper_count > 0) GC_wait_marker();
     /* GC_helper_count cannot be incremented while GC_help_wanted == FALSE */
-#   ifdef PRINTSTATS
-       GC_printf1(
+    if (GC_print_stats == VERBOSE)
+       GC_log_printf(
            "Finished marking for mark phase number %lu\n",
            (unsigned long)GC_mark_no);
-#   endif
     GC_mark_no++;
     GC_release_mark_lock();
     GC_notify_all_marker();
@@ -1108,12 +1140,11 @@ void GC_help_marker(word my_mark_no)
 {
     mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
     unsigned my_id;
-    mse * my_first_nonempty;
 
     if (!GC_parallel) return;
     GC_acquire_mark_lock();
     while (GC_mark_no < my_mark_no
-           || !GC_help_wanted && GC_mark_no == my_mark_no) {
+           || (!GC_help_wanted && GC_mark_no == my_mark_no)) {
       GC_wait_marker();
     }
     my_id = GC_helper_count;
@@ -1131,46 +1162,54 @@ void GC_help_marker(word my_mark_no)
 
 #endif /* PARALLEL_MARK */
 
-/* Allocate or reallocate space for mark stack of size s words  */
-/* May silently fail.                                          */
-static void alloc_mark_stack(n)
-word n;
+/* Allocate or reallocate space for mark stack of size n entries.  */
+/* May silently fail.                                             */
+static void alloc_mark_stack(size_t n)
 {
     mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct GC_ms_entry));
+#   ifdef GWW_VDB
+      /* Don't recycle a stack segment obtained with the wrong flags.  */
+      /* Win32 GetWriteWatch requires the right kind of memory.                */
+      static GC_bool GC_incremental_at_stack_alloc = 0;
+      GC_bool recycle_old = (!GC_incremental || GC_incremental_at_stack_alloc);
+
+      GC_incremental_at_stack_alloc = GC_incremental;
+#   else
+#     define recycle_old 1
+#   endif
     
     GC_mark_stack_too_small = FALSE;
     if (GC_mark_stack_size != 0) {
         if (new_stack != 0) {
-          word displ = (word)GC_mark_stack & (GC_page_size - 1);
-          signed_word size = GC_mark_stack_size * sizeof(struct GC_ms_entry);
+         if (recycle_old) {
+            /* Recycle old space */
+              size_t page_offset = (word)GC_mark_stack & (GC_page_size - 1);
+              size_t size = GC_mark_stack_size * sizeof(struct GC_ms_entry);
+             size_t displ = 0;
           
-          /* Recycle old space */
-             if (0 != displ) displ = GC_page_size - displ;
+             if (0 != page_offset) displ = GC_page_size - page_offset;
              size = (size - displ) & ~(GC_page_size - 1);
              if (size > 0) {
                GC_add_to_heap((struct hblk *)
                                ((word)GC_mark_stack + displ), (word)size);
              }
+         }
           GC_mark_stack = new_stack;
           GC_mark_stack_size = n;
          GC_mark_stack_limit = new_stack + n;
-#        ifdef CONDPRINT
-           if (GC_print_stats) {
-             GC_printf1("Grew mark stack to %lu frames\n",
-                        (unsigned long) GC_mark_stack_size);
-           }
-#        endif
+         if (GC_print_stats) {
+             GC_log_printf("Grew mark stack to %lu frames\n",
+                           (unsigned long) GC_mark_stack_size);
+         }
         } else {
-#        ifdef CONDPRINT
-           if (GC_print_stats) {
-             GC_printf1("Failed to grow mark stack to %lu frames\n",
-                        (unsigned long) n);
-           }
-#        endif
+         if (GC_print_stats) {
+             GC_log_printf("Failed to grow mark stack to %lu frames\n",
+                           (unsigned long) n);
+         }
         }
     } else {
         if (new_stack == 0) {
-            GC_err_printf0("No space for mark stack\n");
+            GC_err_printf("No space for mark stack\n");
             EXIT();
         }
         GC_mark_stack = new_stack;
@@ -1192,9 +1231,7 @@ void GC_mark_init()
  * Should only be used if there is no possibility of mark stack
  * overflow.
  */
-void GC_push_all(bottom, top)
-ptr_t bottom;
-ptr_t top;
+void GC_push_all(ptr_t bottom, ptr_t top)
 {
     register word length;
     
@@ -1210,7 +1247,7 @@ ptr_t top;
        length += GC_DS_TAGS;
        length &= ~GC_DS_TAGS;
 #   endif
-    GC_mark_stack_top -> mse_start = (word *)bottom;
+    GC_mark_stack_top -> mse_start = bottom;
     GC_mark_stack_top -> mse_descr = length;
 }
 
@@ -1224,16 +1261,14 @@ ptr_t top;
  * or if it marks each object before pushing it, thus ensuring progress
  * in the event of a stack overflow.)
  */
-void GC_push_selected(bottom, top, dirty_fn, push_fn)
-ptr_t bottom;
-ptr_t top;
-int (*dirty_fn) GC_PROTO((struct hblk * h));
-void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top));
+void GC_push_selected(ptr_t bottom, ptr_t top,
+                     int (*dirty_fn) (struct hblk *),
+                     void (*push_fn) (ptr_t, ptr_t))
 {
-    register struct hblk * h;
+    struct hblk * h;
 
-    bottom = (ptr_t)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
-    top = (ptr_t)(((long) top) & ~(ALIGNMENT-1));
+    bottom = (ptr_t)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
+    top = (ptr_t)(((word) top) & ~(ALIGNMENT-1));
 
     if (top == 0 || bottom == top) return;
     h = HBLKPTR(bottom + HBLKSIZE);
@@ -1281,10 +1316,7 @@ void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top));
 #endif
 
 
-void GC_push_conditional(bottom, top, all)
-ptr_t bottom;
-ptr_t top;
-int all;
+void GC_push_conditional(ptr_t bottom, ptr_t top, GC_bool all)
 {
     if (all) {
       if (GC_dirty_maintained) {
@@ -1304,32 +1336,45 @@ int all;
 #endif
 
 # if defined(MSWIN32) || defined(MSWINCE)
-  void __cdecl GC_push_one(p)
+  void __cdecl GC_push_one(word p)
 # else
-  void GC_push_one(p)
+  void GC_push_one(word p)
 # endif
-word p;
 {
-    GC_PUSH_ONE_STACK(p, MARKED_FROM_REGISTER);
+    GC_PUSH_ONE_STACK((ptr_t)p, MARKED_FROM_REGISTER);
 }
 
-struct GC_ms_entry *GC_mark_and_push(obj, mark_stack_ptr, mark_stack_limit, src)
-GC_PTR obj;
-struct GC_ms_entry * mark_stack_ptr;
-struct GC_ms_entry * mark_stack_limit;
-GC_PTR *src;
+struct GC_ms_entry *GC_mark_and_push(void *obj,
+                                    mse *mark_stack_ptr,
+                                    mse *mark_stack_limit,
+                                    void **src)
 {
-   PREFETCH(obj);
-   PUSH_CONTENTS(obj, mark_stack_ptr /* modified */, mark_stack_limit, src,
-                was_marked /* internally generated exit label */);
-   return mark_stack_ptr;
-}
+    hdr * hhdr;
+
+    PREFETCH(obj);
+    GET_HDR(obj, hhdr);
+    if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr),FALSE)) {
+      if (GC_all_interior_pointers) {
+       hhdr = GC_find_header(GC_base(obj));
+       if (hhdr == 0) {
+          GC_ADD_TO_BLACK_LIST_NORMAL(obj, src);
+         return mark_stack_ptr;
+       }
+      } else {
+        GC_ADD_TO_BLACK_LIST_NORMAL(obj, src);
+       return mark_stack_ptr;
+      }
+    }
+    if (EXPECT(HBLK_IS_FREE(hhdr),0)) {
+       GC_ADD_TO_BLACK_LIST_NORMAL(obj, src);
+       return mark_stack_ptr;
+    }
 
-# ifdef __STDC__
-#   define BASE(p) (word)GC_base((void *)(p))
-# else
-#   define BASE(p) (word)GC_base((char *)(p))
-# endif
+    PUSH_CONTENTS_HDR(obj, mark_stack_ptr /* modified */, mark_stack_limit,
+                     src, was_marked, hhdr, TRUE);
+ was_marked:
+    return mark_stack_ptr;
+}
 
 /* Mark and push (i.e. gray) a single object p onto the main   */
 /* mark stack.  Consider p to be valid if it is an interior    */
@@ -1339,62 +1384,43 @@ GC_PTR *src;
 /* Mark bits are NOT atomically updated.  Thus this must be the        */
 /* only thread setting them.                                   */
 # if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
-    void GC_mark_and_push_stack(p, source)
-    ptr_t source;
+    void GC_mark_and_push_stack(ptr_t p, ptr_t source)
 # else
-    void GC_mark_and_push_stack(p)
+    void GC_mark_and_push_stack(ptr_t p)
 #   define source 0
 # endif
-register word p;
 {
-    register word r;
-    register hdr * hhdr; 
-    register int displ;
+    hdr * hhdr; 
+    ptr_t r = p;
   
+    PREFETCH(p);
     GET_HDR(p, hhdr);
-    if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+    if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr),FALSE)) {
         if (hhdr != 0) {
-          r = BASE(p);
+          r = GC_base(p);
          hhdr = HDR(r);
-         displ = BYTES_TO_WORDS(HBLKDISPL(r));
        }
-    } else {
-        register map_entry_type map_entry;
-        
-        displ = HBLKDISPL(p);
-        map_entry = MAP_ENTRY((hhdr -> hb_map), displ);
-        if (map_entry >= MAX_OFFSET) {
-          if (map_entry == OFFSET_TOO_BIG || !GC_all_interior_pointers) {
-              r = BASE(p);
-             displ = BYTES_TO_WORDS(HBLKDISPL(r));
-             if (r == 0) hhdr = 0;
-          } else {
-             /* Offset invalid, but map reflects interior pointers     */
-              hhdr = 0;
-          }
-        } else {
-          displ = BYTES_TO_WORDS(displ);
-          displ -= map_entry;
-          r = (word)((word *)(HBLKPTR(p)) + displ);
-        }
-    }
-    /* If hhdr != 0 then r == GC_base(p), only we did it faster. */
-    /* displ is the word index within the block.                */
-    if (hhdr == 0) {
-#      ifdef PRINT_BLACK_LIST
-         GC_add_to_black_list_stack(p, source);
-#      else
-         GC_add_to_black_list_stack(p);
-#      endif
-#      undef source  /* In case we had to define it. */
-    } else {
-       if (!mark_bit_from_hdr(hhdr, displ)) {
-           set_mark_bit_from_hdr(hhdr, displ);
-           GC_STORE_BACK_PTR(source, (ptr_t)r);
-           PUSH_OBJ((word *)r, hhdr, GC_mark_stack_top,
-                    GC_mark_stack_limit);
+        if (hhdr == 0) {
+            GC_ADD_TO_BLACK_LIST_STACK(p, source);
+           return;
        }
     }
+    if (EXPECT(HBLK_IS_FREE(hhdr),0)) {
+       GC_ADD_TO_BLACK_LIST_NORMAL(p, src);
+       return;
+    }
+#   if defined(MANUAL_VDB) && defined(THREADS)
+      /* Pointer is on the stack.  We may have dirtied the object      */
+      /* it points to, but not yet have called GC_dirty();     */
+      GC_dirty(p);     /* Implicitly affects entire object.    */
+#   endif
+    PUSH_CONTENTS_HDR(r, GC_mark_stack_top, GC_mark_stack_limit,
+                     source, mark_and_push_exit, hhdr, FALSE);
+  mark_and_push_exit: ;
+    /* We silently ignore pointers to near the end of a block, */
+    /* which is very mildly suboptimal.                                */
+    /* FIXME: We should probably add a header word to address  */
+    /* this.                                                   */
 }
 
 # ifdef TRACE_BUF
@@ -1404,7 +1430,7 @@ register word p;
 struct trace_entry {
     char * kind;
     word gc_no;
-    word words_allocd;
+    word bytes_allocd;
     word arg1;
     word arg2;
 } GC_trace_buf[TRACE_ENTRIES];
@@ -1415,7 +1441,7 @@ void GC_add_trace_entry(char *kind, word arg1, word arg2)
 {
     GC_trace_buf[GC_trace_buf_ptr].kind = kind;
     GC_trace_buf[GC_trace_buf_ptr].gc_no = GC_gc_no;
-    GC_trace_buf[GC_trace_buf_ptr].words_allocd = GC_words_allocd;
+    GC_trace_buf[GC_trace_buf_ptr].bytes_allocd = GC_bytes_allocd;
     GC_trace_buf[GC_trace_buf_ptr].arg1 = arg1 ^ 0x80000000;
     GC_trace_buf[GC_trace_buf_ptr].arg2 = arg2 ^ 0x80000000;
     GC_trace_buf_ptr++;
@@ -1432,8 +1458,8 @@ void GC_print_trace(word gc_no, GC_bool lock)
        if (i < 0) i = TRACE_ENTRIES-1;
        p = GC_trace_buf + i;
        if (p -> gc_no < gc_no || p -> kind == 0) return;
-       printf("Trace:%s (gc:%d,words:%d) 0x%X, 0x%X\n",
-               p -> kind, p -> gc_no, p -> words_allocd,
+       printf("Trace:%s (gc:%d,bytes:%d) 0x%X, 0x%X\n",
+               p -> kind, p -> gc_no, p -> bytes_allocd,
                (p -> arg1) ^ 0x80000000, (p -> arg2) ^ 0x80000000);
     }
     printf("Trace incomplete\n");
@@ -1447,14 +1473,12 @@ void GC_print_trace(word gc_no, GC_bool lock)
  * and scans the entire region immediately, in case the contents
  * change.
  */
-void GC_push_all_eager(bottom, top)
-ptr_t bottom;
-ptr_t top;
+void GC_push_all_eager(ptr_t bottom, ptr_t top)
 {
     word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
     word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
     register word *p;
-    register word q;
+    register ptr_t q;
     register word *lim;
     register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
     register ptr_t least_ha = GC_least_plausible_heap_addr;
@@ -1465,9 +1489,9 @@ ptr_t top;
     /* check all pointers in range and push if they appear     */
     /* to be valid.                                            */
       lim = t - 1 /* longword */;
-      for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
-       q = *p;
-       GC_PUSH_ONE_STACK(q, p);
+      for (p = b; p <= lim; p = (word *)(((ptr_t)p) + ALIGNMENT)) {
+       q = (ptr_t)(*p);
+       GC_PUSH_ONE_STACK((ptr_t)q, p);
       }
 #   undef GC_greatest_plausible_heap_addr
 #   undef GC_least_plausible_heap_addr
@@ -1480,11 +1504,13 @@ ptr_t top;
  * register values are not lost.
  * Cold_gc_frame delimits the stack section that must be scanned
  * eagerly.  A zero value indicates that no eager scanning is needed.
+ * We don't need to worry about the MANUAL_VDB case here, since this
+ * is only called in the single-threaded case.  We assume that we
+ * cannot collect between an assignment and the corresponding
+ * GC_dirty() call.
  */
-void GC_push_all_stack_partially_eager(bottom, top, cold_gc_frame)
-ptr_t bottom;
-ptr_t top;
-ptr_t cold_gc_frame;
+void GC_push_all_stack_partially_eager(ptr_t bottom, ptr_t top,
+                                      ptr_t cold_gc_frame)
 {
   if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
     /* Push the hot end of the stack eagerly, so that register values   */
@@ -1511,34 +1537,65 @@ ptr_t cold_gc_frame;
 }
 #endif /* !THREADS */
 
-void GC_push_all_stack(bottom, top)
-ptr_t bottom;
-ptr_t top;
+void GC_push_all_stack(ptr_t bottom, ptr_t top)
 {
-  if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
-    GC_push_all(bottom, top);
-  } else {
+# if defined(THREADS) && defined(MPROTECT_VDB)
     GC_push_all_eager(bottom, top);
-  }
+# else
+    if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
+      GC_push_all(bottom, top);
+    } else {
+      GC_push_all_eager(bottom, top);
+    }
+# endif
 }
 
-#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
+#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) && \
+    defined(MARK_BIT_PER_GRANULE)
+# if GC_GRANULE_WORDS == 1
+#   define USE_PUSH_MARKED_ACCELERATORS
+#   define PUSH_GRANULE(q) \
+               { ptr_t qcontents = (ptr_t)((q)[0]); \
+                 GC_PUSH_ONE_HEAP(qcontents, (q)); }
+# elif GC_GRANULE_WORDS == 2
+#   define USE_PUSH_MARKED_ACCELERATORS
+#   define PUSH_GRANULE(q) \
+               { ptr_t qcontents = (ptr_t)((q)[0]); \
+                 GC_PUSH_ONE_HEAP(qcontents, (q)); \
+                 qcontents = (ptr_t)((q)[1]); \
+                 GC_PUSH_ONE_HEAP(qcontents, (q)+1); }
+# elif GC_GRANULE_WORDS == 4
+#   define USE_PUSH_MARKED_ACCELERATORS
+#   define PUSH_GRANULE(q) \
+               { ptr_t qcontents = (ptr_t)((q)[0]); \
+                 GC_PUSH_ONE_HEAP(qcontents, (q)); \
+                 qcontents = (ptr_t)((q)[1]); \
+                 GC_PUSH_ONE_HEAP(qcontents, (q)+1); \
+                 qcontents = (ptr_t)((q)[2]); \
+                 GC_PUSH_ONE_HEAP(qcontents, (q)+2); \
+                 qcontents = (ptr_t)((q)[3]); \
+                 GC_PUSH_ONE_HEAP(qcontents, (q)+3); }
+# endif
+#endif
+
+#ifdef USE_PUSH_MARKED_ACCELERATORS
 /* Push all objects reachable from marked objects in the given block */
-/* of size 1 objects.                                               */
-void GC_push_marked1(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
+/* containing objects of size 1 granule.                            */
+void GC_push_marked1(struct hblk *h, hdr *hhdr)
 {
     word * mark_word_addr = &(hhdr->hb_marks[0]);
-    register word *p;
+    word *p;
     word *plim;
-    register int i;
-    register word q;
-    register word mark_word;
-    register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
-    register ptr_t least_ha = GC_least_plausible_heap_addr;
-    register mse * mark_stack_top = GC_mark_stack_top;
-    register mse * mark_stack_limit = GC_mark_stack_limit;
+    word *q;
+    word mark_word;
+
+    /* Allow registers to be used for some frequently acccessed        */
+    /* global variables.  Otherwise aliasing issues are likely */
+    /* to prevent that.                                                */
+    ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+    ptr_t least_ha = GC_least_plausible_heap_addr;
+    mse * mark_stack_top = GC_mark_stack_top;
+    mse * mark_stack_limit = GC_mark_stack_limit;
 #   define GC_mark_stack_top mark_stack_top
 #   define GC_mark_stack_limit mark_stack_limit
 #   define GC_greatest_plausible_heap_addr greatest_ha
@@ -1550,21 +1607,22 @@ register hdr * hhdr;
     /* go through all words in block */
        while( p < plim )  {
            mark_word = *mark_word_addr++;
-           i = 0;
+           q = p;
            while(mark_word != 0) {
              if (mark_word & 1) {
-                 q = p[i];
-                 GC_PUSH_ONE_HEAP(q, p + i);
+                 PUSH_GRANULE(q);
              }
-             i++;
+             q += GC_GRANULE_WORDS;
              mark_word >>= 1;
            }
-           p += WORDSZ;
+           p += WORDSZ*GC_GRANULE_WORDS;
        }
+
 #   undef GC_greatest_plausible_heap_addr
 #   undef GC_least_plausible_heap_addr        
 #   undef GC_mark_stack_top
 #   undef GC_mark_stack_limit
+
     GC_mark_stack_top = mark_stack_top;
 }
 
@@ -1572,21 +1630,20 @@ register hdr * hhdr;
 #ifndef UNALIGNED
 
 /* Push all objects reachable from marked objects in the given block */
-/* of size 2 objects.                                               */
-void GC_push_marked2(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
+/* of size 2 (granules) objects.                                    */
+void GC_push_marked2(struct hblk *h, hdr *hhdr)
 {
     word * mark_word_addr = &(hhdr->hb_marks[0]);
-    register word *p;
+    word *p;
     word *plim;
-    register int i;
-    register word q;
-    register word mark_word;
-    register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
-    register ptr_t least_ha = GC_least_plausible_heap_addr;
-    register mse * mark_stack_top = GC_mark_stack_top;
-    register mse * mark_stack_limit = GC_mark_stack_limit;
+    word *q;
+    word mark_word;
+
+    ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+    ptr_t least_ha = GC_least_plausible_heap_addr;
+    mse * mark_stack_top = GC_mark_stack_top;
+    mse * mark_stack_limit = GC_mark_stack_limit;
+
 #   define GC_mark_stack_top mark_stack_top
 #   define GC_mark_stack_limit mark_stack_limit
 #   define GC_greatest_plausible_heap_addr greatest_ha
@@ -1598,44 +1655,43 @@ register hdr * hhdr;
     /* go through all words in block */
        while( p < plim )  {
            mark_word = *mark_word_addr++;
-           i = 0;
+           q = p;
            while(mark_word != 0) {
              if (mark_word & 1) {
-                 q = p[i];
-                 GC_PUSH_ONE_HEAP(q, p + i);
-                 q = p[i+1];
-                 GC_PUSH_ONE_HEAP(q, p + i);
+                 PUSH_GRANULE(q);
+                 PUSH_GRANULE(q + GC_GRANULE_WORDS);
              }
-             i += 2;
+             q += 2 * GC_GRANULE_WORDS;
              mark_word >>= 2;
            }
-           p += WORDSZ;
+           p += WORDSZ*GC_GRANULE_WORDS;
        }
+
 #   undef GC_greatest_plausible_heap_addr
 #   undef GC_least_plausible_heap_addr        
 #   undef GC_mark_stack_top
 #   undef GC_mark_stack_limit
+
     GC_mark_stack_top = mark_stack_top;
 }
 
+# if GC_GRANULE_WORDS < 4
 /* Push all objects reachable from marked objects in the given block */
-/* of size 4 objects.                                               */
+/* of size 4 (granules) objects.                                    */
 /* There is a risk of mark stack overflow here.  But we handle that. */
 /* And only unmarked objects get pushed, so it's not very likely.    */
-void GC_push_marked4(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
+void GC_push_marked4(struct hblk *h, hdr *hhdr)
 {
     word * mark_word_addr = &(hhdr->hb_marks[0]);
-    register word *p;
+    word *p;
     word *plim;
-    register int i;
-    register word q;
-    register word mark_word;
-    register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
-    register ptr_t least_ha = GC_least_plausible_heap_addr;
-    register mse * mark_stack_top = GC_mark_stack_top;
-    register mse * mark_stack_limit = GC_mark_stack_limit;
+    word *q;
+    word mark_word;
+
+    ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+    ptr_t least_ha = GC_least_plausible_heap_addr;
+    mse * mark_stack_top = GC_mark_stack_top;
+    mse * mark_stack_limit = GC_mark_stack_limit;
 #   define GC_mark_stack_top mark_stack_top
 #   define GC_mark_stack_limit mark_stack_limit
 #   define GC_greatest_plausible_heap_addr greatest_ha
@@ -1647,22 +1703,18 @@ register hdr * hhdr;
     /* go through all words in block */
        while( p < plim )  {
            mark_word = *mark_word_addr++;
-           i = 0;
+           q = p;
            while(mark_word != 0) {
              if (mark_word & 1) {
-                 q = p[i];
-                 GC_PUSH_ONE_HEAP(q, p + i);
-                 q = p[i+1];
-                 GC_PUSH_ONE_HEAP(q, p + i + 1);
-                 q = p[i+2];
-                 GC_PUSH_ONE_HEAP(q, p + i + 2);
-                 q = p[i+3];
-                 GC_PUSH_ONE_HEAP(q, p + i + 3);
+                 PUSH_GRANULE(q);
+                 PUSH_GRANULE(q + GC_GRANULE_WORDS);
+                 PUSH_GRANULE(q + 2*GC_GRANULE_WORDS);
+                 PUSH_GRANULE(q + 3*GC_GRANULE_WORDS);
              }
-             i += 4;
+             q += 4 * GC_GRANULE_WORDS;
              mark_word >>= 4;
            }
-           p += WORDSZ;
+           p += WORDSZ*GC_GRANULE_WORDS;
        }
 #   undef GC_greatest_plausible_heap_addr
 #   undef GC_least_plausible_heap_addr        
@@ -1671,60 +1723,57 @@ register hdr * hhdr;
     GC_mark_stack_top = mark_stack_top;
 }
 
+#endif /* GC_GRANULE_WORDS < 4 */
+
 #endif /* UNALIGNED */
 
-#endif /* SMALL_CONFIG */
+#endif /* USE_PUSH_MARKED_ACCELERATORS */
 
 /* Push all objects reachable from marked objects in the given block */
-void GC_push_marked(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
+void GC_push_marked(struct hblk *h, hdr *hhdr)
 {
-    register int sz = hhdr -> hb_sz;
-    register int descr = hhdr -> hb_descr;
-    register word * p;
-    register int word_no;
-    register word * lim;
-    register mse * GC_mark_stack_top_reg;
-    register mse * mark_stack_limit = GC_mark_stack_limit;
+    size_t sz = hhdr -> hb_sz;
+    word descr = hhdr -> hb_descr;
+    ptr_t p;
+    word bit_no;
+    ptr_t lim;
+    mse * GC_mark_stack_top_reg;
+    mse * mark_stack_limit = GC_mark_stack_limit;
     
     /* Some quick shortcuts: */
        if ((0 | GC_DS_LENGTH) == descr) return;
         if (GC_block_empty(hhdr)/* nothing marked */) return;
     GC_n_rescuing_pages++;
     GC_objects_are_marked = TRUE;
-    if (sz > MAXOBJSZ) {
-        lim = (word *)h;
+    if (sz > MAXOBJBYTES) {
+        lim = h -> hb_body;
     } else {
-        lim = (word *)(h + 1) - sz;
+        lim = (h + 1)->hb_body - sz;
     }
     
-    switch(sz) {
-#   if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)   
+    switch(BYTES_TO_GRANULES(sz)) {
+#   if defined(USE_PUSH_MARKED_ACCELERATORS)
      case 1:
        GC_push_marked1(h, hhdr);
        break;
-#   endif
-#   if !defined(SMALL_CONFIG) && !defined(UNALIGNED) && \
-       !defined(USE_MARK_BYTES)
-     case 2:
-       GC_push_marked2(h, hhdr);
-       break;
-     case 4:
-       GC_push_marked4(h, hhdr);
-       break;
+#    if !defined(UNALIGNED)
+       case 2:
+         GC_push_marked2(h, hhdr);
+         break;
+#     if GC_GRANULE_WORDS < 4
+       case 4:
+         GC_push_marked4(h, hhdr);
+         break;
+#     endif
+#    endif
 #   endif       
      default:
       GC_mark_stack_top_reg = GC_mark_stack_top;
-      for (p = (word *)h, word_no = 0; p <= lim; p += sz, word_no += sz) {
-         if (mark_bit_from_hdr(hhdr, word_no)) {
+      for (p = h -> hb_body, bit_no = 0; p <= lim;
+          p += sz, bit_no += MARK_BIT_OFFSET(sz)) {
+         if (mark_bit_from_hdr(hhdr, bit_no)) {
            /* Mark from fields inside the object */
-             PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
-#           ifdef GATHERSTATS
-               /* Subtract this object from total, since it was        */
-               /* added in twice.                                      */
-               GC_composite_in_use -= sz;
-#           endif
+             PUSH_OBJ(p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
          }
       }
       GC_mark_stack_top = GC_mark_stack_top_reg;
@@ -1733,17 +1782,14 @@ register hdr * hhdr;
 
 #ifndef SMALL_CONFIG
 /* Test whether any page in the given block is dirty   */
-GC_bool GC_block_was_dirty(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
+GC_bool GC_block_was_dirty(struct hblk *h, hdr *hhdr)
 {
-    register int sz = hhdr -> hb_sz;
+    size_t sz = hhdr -> hb_sz;
     
-    if (sz <= MAXOBJSZ) {
+    if (sz <= MAXOBJBYTES) {
          return(GC_page_was_dirty(h));
     } else {
-        register ptr_t p = (ptr_t)h;
-         sz = WORDS_TO_BYTES(sz);
+        ptr_t p = (ptr_t)h;
          while (p < (ptr_t)h + sz) {
              if (GC_page_was_dirty((struct hblk *)p)) return(TRUE);
              p += HBLKSIZE;
@@ -1754,30 +1800,32 @@ register hdr * hhdr;
 #endif /* SMALL_CONFIG */
 
 /* Similar to GC_push_next_marked, but return address of next block    */
-struct hblk * GC_push_next_marked(h)
-struct hblk *h;
+struct hblk * GC_push_next_marked(struct hblk *h)
 {
-    register hdr * hhdr;
+    hdr * hhdr = HDR(h);
     
-    h = GC_next_used_block(h);
-    if (h == 0) return(0);
-    hhdr = HDR(h);
+    if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)) {
+      h = GC_next_used_block(h);
+      if (h == 0) return(0);
+      hhdr = GC_find_header((ptr_t)h);
+    }
     GC_push_marked(h, hhdr);
     return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
 }
 
 #ifndef SMALL_CONFIG
 /* Identical to above, but mark only from dirty pages  */
-struct hblk * GC_push_next_marked_dirty(h)
-struct hblk *h;
+struct hblk * GC_push_next_marked_dirty(struct hblk *h)
 {
-    register hdr * hhdr;
+    hdr * hhdr = HDR(h);
     
     if (!GC_dirty_maintained) { ABORT("dirty bits not set up"); }
     for (;;) {
-        h = GC_next_used_block(h);
-        if (h == 0) return(0);
-        hhdr = HDR(h);
+       if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)) {
+          h = GC_next_used_block(h);
+          if (h == 0) return(0);
+          hhdr = GC_find_header((ptr_t)h);
+       }
 #      ifdef STUBBORN_ALLOC
           if (hhdr -> hb_obj_kind == STUBBORN) {
             if (GC_page_was_changed(h) && GC_block_was_dirty(h, hhdr)) {
@@ -1790,6 +1838,7 @@ struct hblk *h;
          if (GC_block_was_dirty(h, hhdr)) break;
 #      endif
         h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
+       hhdr = HDR(h);
     }
     GC_push_marked(h, hhdr);
     return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
@@ -1798,20 +1847,21 @@ struct hblk *h;
 
 /* Similar to above, but for uncollectable pages.  Needed since we     */
 /* do not clear marks for such pages, even for full collections.       */
-struct hblk * GC_push_next_marked_uncollectable(h)
-struct hblk *h;
+struct hblk * GC_push_next_marked_uncollectable(struct hblk *h)
 {
-    register hdr * hhdr = HDR(h);
+    hdr * hhdr = HDR(h);
     
     for (;;) {
-        h = GC_next_used_block(h);
-        if (h == 0) return(0);
-        hhdr = HDR(h);
+       if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)) {
+          h = GC_next_used_block(h);
+          if (h == 0) return(0);
+          hhdr = GC_find_header((ptr_t)h);
+       }
        if (hhdr -> hb_obj_kind == UNCOLLECTABLE) break;
         h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
+       hhdr = HDR(h);
     }
     GC_push_marked(h, hhdr);
     return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
 }
 
-
index fb82d4ab0d05a63e802ef0378ccabc852ec8c0b8..c85d931ff86becf2dcf492d66252cedd88ddf9dc 100644 (file)
@@ -43,26 +43,26 @@ static int n_root_sets = 0;
 
 # if !defined(NO_DEBUGGING)
 /* For debugging:      */
-void GC_print_static_roots()
+void GC_print_static_roots(void)
 {
     register int i;
     size_t total = 0;
     
     for (i = 0; i < n_root_sets; i++) {
-        GC_printf2("From 0x%lx to 0x%lx ",
-                  (unsigned long) GC_static_roots[i].r_start,
-                  (unsigned long) GC_static_roots[i].r_end);
+        GC_printf("From %p to %p ",
+                 GC_static_roots[i].r_start,
+                 GC_static_roots[i].r_end);
         if (GC_static_roots[i].r_tmp) {
-            GC_printf0(" (temporary)\n");
+            GC_printf(" (temporary)\n");
         } else {
-            GC_printf0("\n");
+            GC_printf("\n");
         }
         total += GC_static_roots[i].r_end - GC_static_roots[i].r_start;
     }
-    GC_printf1("Total size: %ld\n", (unsigned long) total);
+    GC_printf("Total size: %ld\n", (unsigned long) total);
     if (GC_root_size != total) {
-       GC_printf1("GC_root_size incorrect: %ld!!\n",
-                  (unsigned long) GC_root_size);
+       GC_printf("GC_root_size incorrect: %ld!!\n",
+                 (unsigned long) GC_root_size);
     }
 }
 # endif /* NO_DEBUGGING */
@@ -70,8 +70,7 @@ void GC_print_static_roots()
 /* Primarily for debugging support:    */
 /* Is the address p in one of the registered static                    */
 /* root sections?                                                      */
-GC_bool GC_is_static_root(p)
-ptr_t p;
+GC_bool GC_is_static_root(ptr_t p)
 {
     static int last_root_set = MAX_ROOT_SETS;
     register int i;
@@ -101,8 +100,7 @@ ptr_t p;
        -- really defined in gc_priv.h
 */
 
-static int rt_hash(addr)
-char * addr;
+static INLINE int rt_hash(ptr_t addr)
 {
     word result = (word) addr;
 #   if CPP_WORDSZ > 8*LOG_RT_SIZE
@@ -119,11 +117,10 @@ char * addr;
 
 /* Is a range starting at b already in the table? If so return a       */
 /* pointer to it, else NIL.                                            */
-struct roots * GC_roots_present(b)
-char *b;
+struct roots * GC_roots_present(ptr_t b)
 {
-    register int h = rt_hash(b);
-    register struct roots *p = GC_root_index[h];
+    int h = rt_hash(b);
+    struct roots *p = GC_root_index[h];
     
     while (p != 0) {
         if (p -> r_start == (ptr_t)b) return(p);
@@ -133,10 +130,9 @@ char *b;
 }
 
 /* Add the given root structure to the index. */
-static void add_roots_to_index(p)
-struct roots *p;
+static void add_roots_to_index(struct roots *p)
 {
-    register int h = rt_hash(p -> r_start);
+    int h = rt_hash(p -> r_start);
     
     p -> r_next = GC_root_index[h];
     GC_root_index[h] = p;
@@ -153,16 +149,14 @@ struct roots *p;
 
 word GC_root_size = 0;
 
-void GC_add_roots(b, e)
-char * b; char * e;
+void GC_add_roots(void *b, void *e)
 {
     DCL_LOCK_STATE;
     
-    DISABLE_SIGNALS();
+    if (!GC_is_initialized) GC_init();
     LOCK();
-    GC_add_roots_inner(b, e, FALSE);
+    GC_add_roots_inner((ptr_t)b, (ptr_t)e, FALSE);
     UNLOCK();
-    ENABLE_SIGNALS();
 }
 
 
@@ -172,9 +166,7 @@ char * b; char * e;
 /* them correctly.)                                                    */
 /* Tmp specifies that the interval may be deleted before               */
 /* reregistering dynamic libraries.                                    */ 
-void GC_add_roots_inner(b, e, tmp)
-char * b; char * e;
-GC_bool tmp;
+void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp)
 {
     struct roots * old;
     
@@ -190,14 +182,14 @@ GC_bool tmp;
         
         for (i = 0; i < n_root_sets; i++) {
             old = GC_static_roots + i;
-            if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
-                if ((ptr_t)b < old -> r_start) {
-                    old -> r_start = (ptr_t)b;
-                    GC_root_size += (old -> r_start - (ptr_t)b);
+            if (b <= old -> r_end && e >= old -> r_start) {
+                if (b < old -> r_start) {
+                    old -> r_start = b;
+                    GC_root_size += (old -> r_start - b);
                 }
-                if ((ptr_t)e > old -> r_end) {
-                    old -> r_end = (ptr_t)e;
-                    GC_root_size += ((ptr_t)e - old -> r_end);
+                if (e > old -> r_end) {
+                    old -> r_end = e;
+                    GC_root_size += (e - old -> r_end);
                 }
                 old -> r_tmp &= tmp;
                 break;
@@ -209,23 +201,23 @@ GC_bool tmp;
             
             for (i++; i < n_root_sets; i++) {
               other = GC_static_roots + i;
-              b = (char *)(other -> r_start);
-              e = (char *)(other -> r_end);
-              if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
-                if ((ptr_t)b < old -> r_start) {
-                    old -> r_start = (ptr_t)b;
-                    GC_root_size += (old -> r_start - (ptr_t)b);
+              b = other -> r_start;
+              e = other -> r_end;
+              if (b <= old -> r_end && e >= old -> r_start) {
+                if (b < old -> r_start) {
+                    old -> r_start = b;
+                    GC_root_size += (old -> r_start - b);
                 }
-                if ((ptr_t)e > old -> r_end) {
-                    old -> r_end = (ptr_t)e;
-                    GC_root_size += ((ptr_t)e - old -> r_end);
+                if (e > old -> r_end) {
+                    old -> r_end = e;
+                    GC_root_size += (e - old -> r_end);
                 }
                 old -> r_tmp &= other -> r_tmp;
                 /* Delete this entry. */
                   GC_root_size -= (other -> r_end - other -> r_start);
                   other -> r_start = GC_static_roots[n_root_sets-1].r_start;
                   other -> r_end = GC_static_roots[n_root_sets-1].r_end;
-                                  n_root_sets--;
+                  n_root_sets--;
               }
             }
           return;
@@ -234,10 +226,10 @@ GC_bool tmp;
 #   else
       old = GC_roots_present(b);
       if (old != 0) {
-        if ((ptr_t)e <= old -> r_end) /* already there */ return;
+        if (e <= old -> r_end) /* already there */ return;
         /* else extend */
-        GC_root_size += (ptr_t)e - old -> r_end;
-        old -> r_end = (ptr_t)e;
+        GC_root_size += e - old -> r_end;
+        old -> r_end = e;
         return;
       }
 #   endif
@@ -251,17 +243,17 @@ GC_bool tmp;
       GC_static_roots[n_root_sets].r_next = 0;
 #   endif
     add_roots_to_index(GC_static_roots + n_root_sets);
-    GC_root_size += (ptr_t)e - (ptr_t)b;
+    GC_root_size += e - b;
     n_root_sets++;
 }
 
 static GC_bool roots_were_cleared = FALSE;
 
-void GC_clear_roots GC_PROTO((void))
+void GC_clear_roots (void)
 {
     DCL_LOCK_STATE;
     
-    DISABLE_SIGNALS();
+    if (!GC_is_initialized) GC_init();
     LOCK();
     roots_were_cleared = TRUE;
     n_root_sets = 0;
@@ -274,12 +266,10 @@ void GC_clear_roots GC_PROTO((void))
     }
 #   endif
     UNLOCK();
-    ENABLE_SIGNALS();
 }
 
 /* Internal use only; lock held.       */
-static void GC_remove_root_at_pos(i) 
-int i;
+static void GC_remove_root_at_pos(int i) 
 {
     GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
     GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
@@ -289,9 +279,9 @@ int i;
 }
 
 #if !defined(MSWIN32) && !defined(MSWINCE)
-static void GC_rebuild_root_index()
+static void GC_rebuild_root_index(void)
 {
-    register int i;
+    int i;
        
     for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
     for (i = 0; i < n_root_sets; i++)
@@ -300,9 +290,9 @@ static void GC_rebuild_root_index()
 #endif
 
 /* Internal use only; lock held.       */
-void GC_remove_tmp_roots()
+void GC_remove_tmp_roots(void)
 {
-    register int i;
+    int i;
     
     for (i = 0; i < n_root_sets; ) {
        if (GC_static_roots[i].r_tmp) {
@@ -317,25 +307,22 @@ void GC_remove_tmp_roots()
 }
 
 #if !defined(MSWIN32) && !defined(MSWINCE)
-void GC_remove_roots(b, e)
-char * b; char * e;
+void GC_remove_roots(void *b, void *e)
 {
     DCL_LOCK_STATE;
     
-    DISABLE_SIGNALS();
     LOCK();
-    GC_remove_roots_inner(b, e);
+    GC_remove_roots_inner((ptr_t)b, (ptr_t)e);
     UNLOCK();
-    ENABLE_SIGNALS();
 }
 
 /* Should only be called when the lock is held */
-void GC_remove_roots_inner(b,e)
-char * b; char * e;
+void GC_remove_roots_inner(ptr_t b, ptr_t e)
 {
     int i;
     for (i = 0; i < n_root_sets; ) {
-       if (GC_static_roots[i].r_start >= (ptr_t)b && GC_static_roots[i].r_end <= (ptr_t)e) {
+       if (GC_static_roots[i].r_start >= b
+           && GC_static_roots[i].r_end <= e) {
             GC_remove_root_at_pos(i);
        } else {
            i++;
@@ -348,8 +335,7 @@ char * b; char * e;
 #if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
 /* Workaround for the OS mapping and unmapping behind our back:                */
 /* Is the address p in one of the temporary static root sections?      */
-GC_bool GC_is_tmp_root(p)
-ptr_t p;
+GC_bool GC_is_tmp_root(ptr_t p)
 {
     static int last_root_set = MAX_ROOT_SETS;
     register int i;
@@ -369,9 +355,9 @@ ptr_t p;
 }
 #endif /* MSWIN32 || _WIN32_WCE_EMULATION */
 
-ptr_t GC_approx_sp()
+ptr_t GC_approx_sp(void)
 {
-    VOLATILE word dummy;
+    volatile word dummy;
 
     dummy = 42;        /* Force stack to grow if necessary.    Otherwise the   */
                /* later accesses might cause the kernel to think we're */
@@ -404,8 +390,7 @@ size_t GC_excl_table_entries = 0;   /* Number of entries in use.      */
 /* Return the first exclusion range that includes an address >= start_addr */
 /* Assumes the exclusion table contains at least one entry (namely the    */
 /* GC data structures).                                                           */
-struct exclusion * GC_next_exclusion(start_addr)
-ptr_t start_addr;
+struct exclusion * GC_next_exclusion(ptr_t start_addr)
 {
     size_t low = 0;
     size_t high = GC_excl_table_entries - 1;
@@ -424,9 +409,7 @@ ptr_t start_addr;
     return GC_excl_table + low;
 }
 
-void GC_exclude_static_roots(start, finish)
-GC_PTR start;
-GC_PTR finish;
+void GC_exclude_static_roots(void *start, void *finish)
 {
     struct exclusion * next;
     size_t next_index, i;
@@ -460,10 +443,7 @@ GC_PTR finish;
 }
 
 /* Invoke push_conditional on ranges that are not excluded. */
-void GC_push_conditional_with_exclusions(bottom, top, all)
-ptr_t bottom;
-ptr_t top;
-int all;
+void GC_push_conditional_with_exclusions(ptr_t bottom, ptr_t top, GC_bool all)
 {
     struct exclusion * next;
     ptr_t excl_start;
@@ -484,9 +464,9 @@ int all;
  * In the presence of threads, push enough of the current stack
  * to ensure that callee-save registers saved in collector frames have been
  * seen.
+ * FIXME: Merge with per-thread stuff.
  */
-void GC_push_current_stack(cold_gc_frame)
-ptr_t cold_gc_frame;
+void GC_push_current_stack(ptr_t cold_gc_frame, void * context)
 {
 #   if defined(THREADS)
        if (0 == cold_gc_frame) return;
@@ -538,23 +518,22 @@ ptr_t cold_gc_frame;
  * Push GC internal roots.  Only called if there is some reason to believe
  * these would not otherwise get registered.
  */
-void GC_push_gc_structures GC_PROTO((void))
+void GC_push_gc_structures(void)
 {
     GC_push_finalizer_structures();
-    GC_push_stubborn_structures();
 #   if defined(THREADS)
       GC_push_thread_structures();
 #   endif
 }
 
 #ifdef THREAD_LOCAL_ALLOC
-  void GC_mark_thread_local_free_lists();
+  void GC_mark_thread_local_free_lists(void);
 #endif
 
-void GC_cond_register_dynamic_libraries()
+void GC_cond_register_dynamic_libraries(void)
 {
-# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
-     || defined(PCR)) && !defined(SRC_M3)
+# if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
+     || defined(PCR)
     GC_remove_tmp_roots();
     if (!GC_no_dls) GC_register_dynamic_libraries();
 # else
@@ -571,12 +550,10 @@ void GC_cond_register_dynamic_libraries()
  * A zero value indicates that it's OK to miss some
  * register values.
  */
-void GC_push_roots(all, cold_gc_frame)
-GC_bool all;
-ptr_t cold_gc_frame;
+void GC_push_roots(GC_bool all, ptr_t cold_gc_frame)
 {
     int i;
-    int kind;
+    unsigned kind;
 
     /*
      * Next push static data.  This must happen early on, since it's
@@ -604,7 +581,7 @@ ptr_t cold_gc_frame;
      /* saves us the trouble of scanning them, and possibly that of    */
      /* marking the freelists.                                         */
        for (kind = 0; kind < GC_n_kinds; kind++) {
-        GC_PTR base = GC_base(GC_obj_kinds[kind].ok_freelist);
+        void *base = GC_base(GC_obj_kinds[kind].ok_freelist);
         if (0 != base) {
           GC_set_mark_bit(base);
         }
@@ -621,7 +598,7 @@ ptr_t cold_gc_frame;
      /* If the world is not stopped, this is unsafe.  It is    */
      /* also unnecessary, since we will do this again with the */
      /* world stopped.                                         */
-#      ifdef THREAD_LOCAL_ALLOC
+#      if defined(THREAD_LOCAL_ALLOC)
          if (GC_world_stopped) GC_mark_thread_local_free_lists();
 #      endif
 
@@ -629,23 +606,11 @@ ptr_t cold_gc_frame;
      * Now traverse stacks, and mark from register contents.
      * These must be done last, since they can legitimately overflow
      * the mark stack.
+     * This is usually done by saving the current context on the
+     * stack, and then just tracing from the stack.
      */
-#   ifdef USE_GENERIC_PUSH_REGS
-       GC_generic_push_regs(cold_gc_frame);
-       /* Also pushes stack, so that we catch callee-save registers    */
-       /* saved inside the GC_push_regs frame.                         */
-#   else
-       /*
-        * push registers - i.e., call GC_push_one(r) for each
-        * register contents r.
-        */
-        GC_push_regs(); /* usually defined in machine_dep.c */
-       GC_push_current_stack(cold_gc_frame);
-       /* In the threads case, this only pushes collector frames.      */
-       /* 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
+      GC_push_regs_and_stack(cold_gc_frame);
+
     if (GC_push_other_roots != 0) (*GC_push_other_roots)();
        /* In the threads case, this also pushes thread stacks. */
         /* Note that without interior pointer recognition lots */
old mode 100644 (file)
new mode 100755 (executable)
index 2c8d314..a556f95
@@ -18,6 +18,7 @@
 
 #include <stdio.h>
 #include <limits.h>
+#include <stdarg.h>
 #ifndef _WIN32_WCE
 #include <signal.h>
 #endif
 # include <tchar.h>
 #endif
 
+#ifdef UNIX_LIKE
+# include <fcntl.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+
+  int GC_log;  /* Forward decl, so we can set it.      */
+#endif
+
 #ifdef NONSTOP
 # include <floss.h>
 #endif
 
-# ifdef THREADS
-#   ifdef PCR
-#     include "il/PCR_IL.h"
-      PCR_Th_ML GC_allocate_ml;
-#   else
-#     ifdef SRC_M3
-       /* Critical section counter is defined in the M3 runtime        */
-       /* That's all we use.                                           */
-#     else
-#      ifdef GC_SOLARIS_THREADS
-         mutex_t GC_allocate_ml;       /* Implicitly initialized.      */
-#      else
-#          if defined(GC_WIN32_THREADS) 
-#             if defined(GC_PTHREADS)
-                 pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
-#            elif defined(GC_DLL)
-                __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
-#            else
-                CRITICAL_SECTION GC_allocate_ml;
-#            endif
-#          else
-#             if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS)
-#              if defined(USE_SPIN_LOCK)
-                 pthread_t GC_lock_holder = NO_THREAD;
-#              else
-                 pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
-                 pthread_t GC_lock_holder = NO_THREAD;
-                       /* Used only for assertions, and to prevent      */
-                       /* recursive reentry in the system call wrapper. */
-#              endif 
-#            else
-                 --> declare allocator lock here
-#            endif
-#         endif
-#      endif
-#     endif
-#   endif
-# endif
+#if defined(THREADS) && defined(PCR)
+# include "il/PCR_IL.h"
+  PCR_Th_ML GC_allocate_ml;
+#endif
+/* For other platforms with threads, the lock and possibly             */
+/* GC_lock_holder variables are defined in the thread support code.    */
 
 #if defined(NOSYS) || defined(ECOS)
 #undef STACKBASE
@@ -96,10 +73,10 @@ GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */;
 GC_bool GC_debugging_started = FALSE;
        /* defined here so we don't have to load debug_malloc.o */
 
-void (*GC_check_heap) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
-void (*GC_print_all_smashed) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
+void (*GC_check_heap) (void) = (void (*) (void))0;
+void (*GC_print_all_smashed) (void) = (void (*) (void))0;
 
-void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
+void (*GC_start_call_back) (void) = (void (*) (void))0;
 
 ptr_t GC_stackbottom = 0;
 
@@ -113,7 +90,9 @@ GC_bool GC_dont_precollect = 0;
 
 GC_bool GC_quiet = 0;
 
-GC_bool GC_print_stats = 0;
+#ifndef SMALL_CONFIG
+  GC_bool GC_print_stats = 0;
+#endif
 
 GC_bool GC_print_back_height = 0;
 
@@ -145,118 +124,87 @@ long GC_large_alloc_warn_suppressed = 0;
        /* Number of warnings suppressed so far.        */
 
 /*ARGSUSED*/
-GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested))
+void * GC_default_oom_fn(size_t bytes_requested)
 {
     return(0);
 }
 
-GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) = GC_default_oom_fn;
+void * (*GC_oom_fn) (size_t bytes_requested) = GC_default_oom_fn;
 
-extern signed_word GC_mem_found;
-
-void * GC_project2(arg1, arg2)
-void *arg1;
-void *arg2;
+void * GC_project2(void *arg1, void *arg2)
 {
   return arg2;
 }
 
-# ifdef MERGE_SIZES
-    /* Set things up so that GC_size_map[i] >= words(i),               */
-    /* but not too much bigger                                         */
-    /* and so that size_map contains relatively few distinct entries   */
-    /* This is stolen from Russ Atkinson's Cedar quantization          */
-    /* alogrithm (but we precompute it).                               */
-
-
-    void GC_init_size_map()
-    {
-       register unsigned i;
-
-       /* Map size 0 to something bigger.                      */
-       /* This avoids problems at lower levels.                */
-       /* One word objects don't have to be 2 word aligned,    */
-       /* unless we're using mark bytes.                       */
-         for (i = 0; i < sizeof(word); i++) {
-             GC_size_map[i] = MIN_WORDS;
-         }
-#        if MIN_WORDS > 1
-           GC_size_map[sizeof(word)] = MIN_WORDS;
-#        else
-           GC_size_map[sizeof(word)] = ROUNDED_UP_WORDS(sizeof(word));
-#        endif
-       for (i = sizeof(word) + 1; i <= 8 * sizeof(word); i++) {
-           GC_size_map[i] = ALIGNED_WORDS(i);
-       }
-       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. */
+/* Set things up so that GC_size_map[i] >= granules(i),                */
+/* but not too much bigger                                             */
+/* and so that size_map contains relatively few distinct entries       */
+/* This was originally stolen from Russ Atkinson's Cedar               */
+/* quantization alogrithm (but we precompute it).                      */ 
+void GC_init_size_map(void)
+{
+    int i;
+
+    /* Map size 0 to something bigger.                 */
+    /* This avoids problems at lower levels.           */
+      GC_size_map[0] = 1;
+    for (i = 1; i <= GRANULES_TO_BYTES(TINY_FREELISTS-1) - EXTRA_BYTES; i++) {
+        GC_size_map[i] = ROUNDED_UP_GRANULES(i);
+        GC_ASSERT(GC_size_map[i] < TINY_FREELISTS);
     }
+    /* We leave the rest of the array to be filled in on demand. */
+}
+
+/* Fill in additional entries in GC_size_map, including the ith one */
+/* We assume the ith entry is currently 0.                             */
+/* Note that a filled in section of the array ending at n always    */
+/* has length at least n/4.                                            */
+void GC_extend_size_map(size_t i)
+{
+    size_t orig_granule_sz = ROUNDED_UP_GRANULES(i);
+    size_t granule_sz = orig_granule_sz;
+    size_t byte_sz = GRANULES_TO_BYTES(granule_sz);
+                       /* The size we try to preserve.         */
+                       /* Close to i, unless this would        */
+                       /* introduce too many distinct sizes.   */
+    size_t smaller_than_i = byte_sz - (byte_sz >> 3);
+    size_t much_smaller_than_i = byte_sz - (byte_sz >> 2);
+    size_t low_limit;  /* The lowest indexed entry we  */
+                       /* initialize.                  */
+    size_t j;
     
-    /* Fill in additional entries in GC_size_map, including the ith one */
-    /* We assume the ith entry is currently 0.                         */
-    /* Note that a filled in section of the array ending at n always    */
-    /* has length at least n/4.                                                */
-    void GC_extend_size_map(i)
-    word i;
+    if (GC_size_map[smaller_than_i] == 0) {
+        low_limit = much_smaller_than_i;
+        while (GC_size_map[low_limit] != 0) low_limit++;
+    } else {
+        low_limit = smaller_than_i + 1;
+        while (GC_size_map[low_limit] != 0) low_limit++;
+        granule_sz = ROUNDED_UP_GRANULES(low_limit);
+        granule_sz += granule_sz >> 3;
+        if (granule_sz < orig_granule_sz) granule_sz = orig_granule_sz;
+    }
+    /* For these larger sizes, we use an even number of granules.      */
+    /* This makes it easier to, for example, construct a 16byte-aligned        */
+    /* allocator even if GRANULE_BYTES is 8.                           */
+        granule_sz += 1;
+        granule_sz &= ~1;
+    if (granule_sz > MAXOBJGRANULES) {
+        granule_sz = MAXOBJGRANULES;
+    }
+    /* If we can fit the same number of larger objects in a block,     */
+    /* do so.                                                  */ 
     {
-        word orig_word_sz = ROUNDED_UP_WORDS(i);
-        word word_sz = orig_word_sz;
-       register word byte_sz = WORDS_TO_BYTES(word_sz);
-                               /* The size we try to preserve.         */
-                               /* Close to to i, unless this would     */
-                               /* introduce too many distinct sizes.   */
-       word smaller_than_i = byte_sz - (byte_sz >> 3);
-       word much_smaller_than_i = byte_sz - (byte_sz >> 2);
-       register word low_limit;        /* The lowest indexed entry we  */
-                                       /* initialize.                  */
-       register word j;
-       
-       if (GC_size_map[smaller_than_i] == 0) {
-           low_limit = much_smaller_than_i;
-           while (GC_size_map[low_limit] != 0) low_limit++;
-       } else {
-           low_limit = smaller_than_i + 1;
-           while (GC_size_map[low_limit] != 0) low_limit++;
-           word_sz = ROUNDED_UP_WORDS(low_limit);
-           word_sz += word_sz >> 3;
-           if (word_sz < orig_word_sz) word_sz = orig_word_sz;
-       }
-#      ifdef ALIGN_DOUBLE
-           word_sz += 1;
-           word_sz &= ~1;
-#      endif
-       if (word_sz > MAXOBJSZ) {
-           word_sz = MAXOBJSZ;
-       }
-       /* If we can fit the same number of larger objects in a block,  */
-       /* do so.                                                       */ 
-       {
-           size_t number_of_objs = BODY_SZ/word_sz;
-           word_sz = BODY_SZ/number_of_objs;
-#          ifdef ALIGN_DOUBLE
-               word_sz &= ~1;
-#          endif
-       }
-       byte_sz = WORDS_TO_BYTES(word_sz);
-       if (GC_all_interior_pointers) {
-           /* We need one extra byte; don't fill in GC_size_map[byte_sz] */
-           byte_sz -= EXTRA_BYTES;
-       }
-
-       for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz;  
+        size_t number_of_objs = HBLK_GRANULES/granule_sz;
+        granule_sz = HBLK_GRANULES/number_of_objs;
+       granule_sz &= ~1;
     }
-# endif
+    byte_sz = GRANULES_TO_BYTES(granule_sz);
+    /* We may need one extra byte;                     */
+    /* don't always fill in GC_size_map[byte_sz]       */
+    byte_sz -= EXTRA_BYTES;
+
+    for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = granule_sz;  
+}
 
 
 /*
@@ -275,28 +223,26 @@ word GC_stack_last_cleared = 0;   /* GC_no when we last did this */
 # define CLEAR_SIZE 213  /* Granularity for GC_clear_stack_inner */
 # define DEGRADE_RATE 50
 
-word GC_min_sp;                /* Coolest stack pointer value from which we've */
+ptr_t GC_min_sp;       /* Coolest stack pointer value from which we've */
                        /* already cleared the stack.                   */
                        
-word GC_high_water;
+ptr_t GC_high_water;
                        /* "hottest" stack pointer value we have seen   */
                        /* recently.  Degrades over time.               */
 
-word GC_words_allocd_at_reset;
+word GC_bytes_allocd_at_reset;
 
 #if defined(ASM_CLEAR_CODE)
-  extern ptr_t GC_clear_stack_inner();
+  extern void *GC_clear_stack_inner(void *, ptr_t);
 #else  
 /* Clear the stack up to about limit.  Return arg. */
 /*ARGSUSED*/
-ptr_t GC_clear_stack_inner(arg, limit)
-ptr_t arg;
-word limit;
+void * GC_clear_stack_inner(void *arg, ptr_t limit)
 {
     word dummy[CLEAR_SIZE];
     
     BZERO(dummy, CLEAR_SIZE*sizeof(word));
-    if ((word)(dummy) COOLER_THAN limit) {
+    if ((ptr_t)(dummy) COOLER_THAN limit) {
         (void) GC_clear_stack_inner(arg, limit);
     }
     /* Make sure the recursive call is not a tail call, and the bzero  */
@@ -309,10 +255,9 @@ word limit;
 /* Clear some of the inaccessible part of the stack.  Returns its      */
 /* argument, so it can be used in a tail call position, hence clearing  */
 /* another frame.                                                      */
-ptr_t GC_clear_stack(arg)
-ptr_t arg;
+void * GC_clear_stack(void *arg)
 {
-    register word sp = (word)GC_approx_sp();  /* Hotter than actual sp */
+    ptr_t sp = GC_approx_sp();  /* Hotter than actual sp */
 #   ifdef THREADS
         word dummy[SMALL_CLEAR_SIZE];
        static unsigned random_no = 0;
@@ -320,7 +265,7 @@ ptr_t arg;
                                 /* Used to occasionally clear a bigger  */
                                 /* chunk.                               */
 #   endif
-    register word limit;
+    ptr_t limit;
     
 #   define SLOP 400
        /* Extra bytes we clear every time.  This clears our own        */
@@ -341,7 +286,8 @@ ptr_t arg;
     if (++random_no % 13 == 0) {
        limit = sp;
        MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
-        limit &= ~0xf; /* Make it sufficiently aligned for assembly    */
+       limit = (ptr_t)((word)limit & ~0xf);
+                       /* Make it sufficiently aligned for assembly    */
                        /* implementations of GC_clear_stack_inner.     */
        return GC_clear_stack_inner(arg, limit);
     } else {
@@ -351,10 +297,10 @@ ptr_t arg;
 # else
     if (GC_gc_no > GC_stack_last_cleared) {
         /* Start things over, so we clear the entire stack again */
-        if (GC_stack_last_cleared == 0) GC_high_water = (word) GC_stackbottom;
+        if (GC_stack_last_cleared == 0) GC_high_water = (ptr_t)GC_stackbottom;
         GC_min_sp = GC_high_water;
         GC_stack_last_cleared = GC_gc_no;
-        GC_words_allocd_at_reset = GC_words_allocd;
+        GC_bytes_allocd_at_reset = GC_bytes_allocd;
     }
     /* Adjust GC_high_water */
         MAKE_COOLER(GC_high_water, WORDS_TO_BYTES(DEGRADE_RATE) + GC_SLOP);
@@ -365,17 +311,17 @@ ptr_t arg;
     limit = GC_min_sp;
     MAKE_HOTTER(limit, SLOP);
     if (sp COOLER_THAN limit) {
-        limit &= ~0xf; /* Make it sufficiently aligned for assembly    */
+        limit = (ptr_t)((word)limit & ~0xf);
+                       /* Make it sufficiently aligned for assembly    */
                        /* implementations of GC_clear_stack_inner.     */
         GC_min_sp = sp;
         return(GC_clear_stack_inner(arg, limit));
-    } else if (WORDS_TO_BYTES(GC_words_allocd - GC_words_allocd_at_reset)
-              > CLEAR_THRESHOLD) {
+    } else if (GC_bytes_allocd - GC_bytes_allocd_at_reset > CLEAR_THRESHOLD) {
        /* Restart clearing process, but limit how much clearing we do. */
        GC_min_sp = sp;
        MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
        if (GC_min_sp HOTTER_THAN GC_high_water) GC_min_sp = GC_high_water;
-       GC_words_allocd_at_reset = GC_words_allocd;
+       GC_bytes_allocd_at_reset = GC_bytes_allocd;
     }  
     return(arg);
 # endif
@@ -384,20 +330,15 @@ ptr_t arg;
 
 /* Return a pointer to the base address of p, given a pointer to a     */
 /* an address within an object.  Return 0 o.w.                         */
-# ifdef __STDC__
-    GC_PTR GC_base(GC_PTR p)
-# else
-    GC_PTR GC_base(p)
-    GC_PTR p;
-# endif
+void * GC_base(void * p)
 {
-    register word r;
-    register struct hblk *h;
-    register bottom_index *bi;
-    register hdr *candidate_hdr;
-    register word limit;
+    ptr_t r;
+    struct hblk *h;
+    bottom_index *bi;
+    hdr *candidate_hdr;
+    ptr_t limit;
     
-    r = (word)p;
+    r = p;
     if (!GC_is_initialized) return 0;
     h = HBLKPTR(r);
     GET_BI(r, bi);
@@ -407,78 +348,68 @@ ptr_t arg;
     /* to the beginning.                                               */
        while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
           h = FORWARDED_ADDR(h,candidate_hdr);
-          r = (word)h;
+          r = (ptr_t)h;
           candidate_hdr = HDR(h);
        }
-    if (candidate_hdr -> hb_map == GC_invalid_map) return(0);
+    if (HBLK_IS_FREE(candidate_hdr)) return(0);
     /* Make sure r points to the beginning of the object */
-       r &= ~(WORDS_TO_BYTES(1) - 1);
+       r = (ptr_t)((word)r & ~(WORDS_TO_BYTES(1) - 1));
         {
-           register int offset = HBLKDISPL(r);
-           register signed_word sz = candidate_hdr -> hb_sz;
-           register signed_word map_entry;
-             
-           map_entry = MAP_ENTRY((candidate_hdr -> hb_map), offset);
-           if (map_entry > CPP_MAX_OFFSET) {
-               map_entry = (signed_word)(BYTES_TO_WORDS(offset)) % sz;
-            }
-            r -= WORDS_TO_BYTES(map_entry);
-            limit = r + WORDS_TO_BYTES(sz);
-           if (limit > (word)(h + 1)
-               && sz <= BYTES_TO_WORDS(HBLKSIZE)) {
+           size_t offset = HBLKDISPL(r);
+           signed_word sz = candidate_hdr -> hb_sz;
+           size_t obj_displ = offset % sz;
+
+           r -= obj_displ;
+            limit = r + sz;
+           if (limit > (ptr_t)(h + 1) && sz <= HBLKSIZE) {
                return(0);
            }
-           if ((word)p >= limit) return(0);
+           if ((ptr_t)p >= limit) return(0);
        }
-    return((GC_PTR)r);
+    return((void *)r);
 }
 
 
 /* Return the size of an object, given a pointer to its base.          */
 /* (For small obects this also happens to work from interior pointers, */
 /* but that shouldn't be relied upon.)                                 */
-# ifdef __STDC__
-    size_t GC_size(GC_PTR p)
-# else
-    size_t GC_size(p)
-    GC_PTR p;
-# endif
+size_t GC_size(void * p)
 {
-    register int sz;
-    register hdr * hhdr = HDR(p);
+    hdr * hhdr = HDR(p);
     
-    sz = WORDS_TO_BYTES(hhdr -> hb_sz);
-    return(sz);
+    return hhdr -> hb_sz;
 }
 
-size_t GC_get_heap_size GC_PROTO(())
+size_t GC_get_heap_size(void)
 {
-    return ((size_t) GC_heapsize);
+    return GC_heapsize;
 }
 
-size_t GC_get_free_bytes GC_PROTO(())
+size_t GC_get_free_bytes(void)
 {
-    return ((size_t) GC_large_free_bytes);
+    return GC_large_free_bytes;
 }
 
-size_t GC_get_bytes_since_gc GC_PROTO(())
+size_t GC_get_bytes_since_gc(void)
 {
-    return ((size_t) WORDS_TO_BYTES(GC_words_allocd));
+    return GC_bytes_allocd;
 }
 
-size_t GC_get_total_bytes GC_PROTO(())
+size_t GC_get_total_bytes(void)
 {
-    return ((size_t) WORDS_TO_BYTES(GC_words_allocd+GC_words_allocd_before_gc));
+    return GC_bytes_allocd+GC_bytes_allocd_before_gc;
 }
 
 GC_bool GC_is_initialized = FALSE;
 
-void GC_init()
+# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
+  extern void GC_init_parallel(void);
+# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
+
+void GC_init(void)
 {
     DCL_LOCK_STATE;
     
-    DISABLE_SIGNALS();
-
 #if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
     if (!GC_is_initialized) {
       BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
@@ -497,14 +428,12 @@ void GC_init()
     LOCK();
     GC_init_inner();
     UNLOCK();
-    ENABLE_SIGNALS();
 
 #   if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
        /* Make sure marker threads and started and thread local */
        /* allocation is initialized, in case we didn't get      */
        /* called from GC_init_parallel();                       */
         {
-         extern void GC_init_parallel(void);
          GC_init_parallel();
        }
 #   endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
@@ -524,7 +453,7 @@ void GC_init()
 #endif
 
 #ifdef MSWIN32
-    extern void GC_init_win32 GC_PROTO((void));
+    extern void GC_init_win32(void);
 #endif
 
 extern void GC_setpagesize();
@@ -536,23 +465,23 @@ extern GC_bool GC_no_win32_dlls;
 # define GC_no_win32_dlls FALSE
 #endif
 
-void GC_exit_check GC_PROTO((void))
+void GC_exit_check(void)
 {
    GC_gcollect();
 }
 
 #ifdef SEARCH_FOR_DATA_START
-  extern void GC_init_linux_data_start GC_PROTO((void));
+  extern void GC_init_linux_data_start(void);
 #endif
 
 #ifdef UNIX_LIKE
 
-extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int)));
+extern void GC_set_and_save_fault_handler(void (*handler)(int));
 
 static void looping_handler(sig)
 int sig;
 {
-    GC_err_printf1("Caught signal %d: looping in handler\n", sig);
+    GC_err_printf("Caught signal %d: looping in handler\n", sig);
     for(;;);
 }
 
@@ -582,15 +511,30 @@ void GC_init_inner()
     word initial_heap_sz = (word)MINHINCR;
     
     if (GC_is_initialized) return;
-#   ifdef PRINTSTATS
-      GC_print_stats = 1;
-#   endif
 #   if defined(MSWIN32) || defined(MSWINCE)
       InitializeCriticalSection(&GC_write_cs);
 #   endif
-    if (0 != GETENV("GC_PRINT_STATS")) {
-      GC_print_stats = 1;
-    } 
+#   if (!defined(SMALL_CONFIG))
+      if (0 != GETENV("GC_PRINT_STATS")) {
+        GC_print_stats = 1;
+      } 
+      if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) {
+        GC_print_stats = VERBOSE;
+      } 
+#     if defined(UNIX_LIKE)
+        {
+         char * file_name = GETENV("GC_LOG_FILE");
+          if (0 != file_name) {
+           int log_d = open(file_name, O_CREAT|O_WRONLY|O_APPEND, 0666);
+           if (log_d < 0) {
+             GC_log_printf("Failed to open %s as log file\n", file_name);
+           } else {
+             GC_log = log_d;
+           }
+         }
+       }
+#     endif
+#   endif
 #   ifndef NO_DEBUGGING
       if (0 != GETENV("GC_DUMP_REGULARLY")) {
         GC_dump_regularly = 1;
@@ -607,9 +551,7 @@ void GC_init_inner()
 #   endif
     if (0 != GETENV("GC_FIND_LEAK")) {
       GC_find_leak = 1;
-#     ifdef __STDC__
-        atexit(GC_exit_check);
-#     endif
+      atexit(GC_exit_check);
     }
     if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
       GC_all_interior_pointers = 1;
@@ -623,6 +565,23 @@ void GC_init_inner()
     if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) {
       GC_large_alloc_warn_interval = LONG_MAX;
     }
+    {
+      char * addr_string = GETENV("GC_TRACE");
+      if (0 != addr_string) {
+#       ifndef ENABLE_TRACE
+         WARN("Tracing not enabled: Ignoring GC_TRACE value\n", 0);
+#       else
+#        ifdef STRTOULL
+           long long addr = strtoull(addr_string, NULL, 16);
+#        else
+           long addr = strtoul(addr_string, NULL, 16);
+#        endif
+         if (addr < 0x1000)
+             WARN("Unlikely trace address: 0x%lx\n", (GC_word)addr);
+         GC_trace_addr = (ptr_t)addr;
+#      endif
+      }
+    }
     {
       char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
       if (0 != time_limit_string) {
@@ -662,31 +621,29 @@ void GC_init_inner()
 #   ifdef MSWIN32
        GC_init_win32();
 #   endif
+#   if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
+       WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0);
+       /* If thread stacks are cached, they tend to be scanned in      */
+       /* entirety as part of the root set.  This wil grow them to     */
+       /* maximum size, and is generally not desirable.                */
+#   endif
 #   if defined(SEARCH_FOR_DATA_START)
        GC_init_linux_data_start();
 #   endif
 #   if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
        GC_init_netbsd_elf();
 #   endif
-#   if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
-       || defined(GC_WIN32_THREADS)
-        GC_thr_init();
-#   endif
-#   ifdef GC_SOLARIS_THREADS
-       /* We need dirty bits in order to find live stack sections.     */
-        GC_dirty_init();
-#   endif
 #   if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \
        || defined(GC_SOLARIS_THREADS)
       if (GC_stackbottom == 0) {
-       GC_stackbottom = GC_get_stack_base();
+       GC_stackbottom = GC_get_main_stack_base();
 #       if (defined(LINUX) || defined(HPUX)) && defined(IA64)
          GC_register_stackbottom = GC_get_register_stack_base();
 #       endif
       } else {
 #       if (defined(LINUX) || defined(HPUX)) && defined(IA64)
          if (GC_register_stackbottom == 0) {
-           WARN("GC_register_stackbottom should be set with GC_stackbottom", 0);
+           WARN("GC_register_stackbottom should be set with GC_stackbottom\n", 0);
            /* The following may fail, since we may rely on             */
            /* alignment properties that may not hold with a user set   */
            /* GC_stackbottom.                                          */
@@ -695,18 +652,11 @@ void GC_init_inner()
 #      endif
       }
 #   endif
+    /* Ignore gcc -Wall warnings on the following. */
     GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word));
     GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
     GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
 #   ifndef THREADS
-#     if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
-       ABORT(
-         "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
-#     endif
-#     if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
-       ABORT(
-         "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
-#     endif
 #     ifdef STACK_GROWS_DOWN
         GC_ASSERT((word)(&dummy) <= (word)GC_stackbottom);
 #     else
@@ -717,7 +667,20 @@ void GC_init_inner()
       GC_ASSERT((word)(-1) > (word)0);
       /* word should be unsigned */
 #   endif
+    GC_ASSERT((ptr_t)(word)(-1) > (ptr_t)0);
+       /* Ptr_t comparisons should behave as unsigned comparisons.     */
     GC_ASSERT((signed_word)(-1) < (signed_word)0);
+#   if !defined(SMALL_CONFIG)
+      if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
+       /* This used to test for !GC_no_win32_dlls.  Why? */
+        GC_setpagesize();
+       /* For GWW_MPROTECT on Win32, this needs to happen before any   */
+       /* heap memory is allocated.                                    */
+        GC_dirty_init();
+        GC_ASSERT(GC_bytes_allocd == 0)
+       GC_incremental = TRUE;
+      }
+#   endif /* !SMALL_CONFIG */
     
     /* Add initial guess of root sets.  Do this first, since sbrk(0)   */
     /* might be used.                                                  */
@@ -749,19 +712,18 @@ void GC_init_inner()
        }
     }
     if (!GC_expand_hp_inner(initial_heap_sz)) {
-        GC_err_printf0("Can't start up: not enough memory\n");
+        GC_err_printf("Can't start up: not enough memory\n");
         EXIT();
     }
-    /* Preallocate large object map.  It's otherwise inconvenient to   */
-    /* deal with failure.                                              */
-      if (!GC_add_map_entry((word)0)) {
-        GC_err_printf0("Can't start up: not enough memory\n");
-        EXIT();
-      }
+    GC_initialize_offsets();
     GC_register_displacement_inner(0L);
-#   ifdef MERGE_SIZES
-      GC_init_size_map();
+#   if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
+      if (!GC_all_interior_pointers) {
+       /* TLS ABI uses pointer-sized offsets for dtv. */
+        GC_register_displacement_inner(sizeof(void *));
+      }
 #   endif
+    GC_init_size_map();
 #   ifdef PCR
       if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
           != PCR_ERes_okay) {
@@ -772,23 +734,21 @@ void GC_init_inner()
       PCR_IL_Unlock();
       GC_pcr_install();
 #   endif
-#   if !defined(SMALL_CONFIG)
-      if (!GC_no_win32_dlls && 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
-       GC_ASSERT(!GC_incremental);
-        GC_setpagesize();
-#       ifndef GC_SOLARIS_THREADS
-          GC_dirty_init();
-#       endif
-        GC_ASSERT(GC_words_allocd == 0)
-       GC_incremental = TRUE;
-      }
-#   endif /* !SMALL_CONFIG */
+    GC_is_initialized = TRUE;
+#   if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
+        GC_thr_init();
+#   endif
     COND_DUMP;
     /* Get black list set up and/or incremental GC started */
       if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
-    GC_is_initialized = TRUE;
 #   ifdef STUBBORN_ALLOC
        GC_stubborn_init();
+#   endif
+#   if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
+       {
+         extern void GC_init_lib_bounds(void);
+         GC_init_lib_bounds();
+       }
 #   endif
     /* Convince lint that some things are used */
 #   ifdef LINT
@@ -808,7 +768,7 @@ void GC_init_inner()
 #   endif
 }
 
-void GC_enable_incremental GC_PROTO(())
+void GC_enable_incremental(void)
 {
 # if !defined(SMALL_CONFIG) && !defined(KEEP_BACK_PTRS)
   /* If we are keeping back pointers, the GC itself dirties all        */
@@ -817,43 +777,48 @@ void GC_enable_incremental GC_PROTO(())
   if (!GC_find_leak) {
     DCL_LOCK_STATE;
     
-    DISABLE_SIGNALS();
     LOCK();
     if (GC_incremental) goto out;
     GC_setpagesize();
-    if (GC_no_win32_dlls) goto out;
-#   ifndef GC_SOLARIS_THREADS 
-      maybe_install_looping_handler();  /* Before write fault handler! */
-      GC_dirty_init();
-#   endif
+    /* if (GC_no_win32_dlls) goto out; Should be win32S test? */
+    maybe_install_looping_handler();  /* Before write fault handler! */
+    GC_incremental = TRUE;
     if (!GC_is_initialized) {
         GC_init_inner();
+    } else {
+       GC_dirty_init();
     }
-    if (GC_incremental) goto out;
+    if (!GC_dirty_maintained) goto out;
     if (GC_dont_gc) {
         /* Can't easily do it. */
         UNLOCK();
-       ENABLE_SIGNALS();
        return;
     }
-    if (GC_words_allocd > 0) {
+    if (GC_bytes_allocd > 0) {
        /* There may be unmarked reachable objects      */
        GC_gcollect_inner();
     }   /* else we're OK in assuming everything's      */
        /* clean since nothing can point to an          */
        /* unmarked object.                             */
     GC_read_dirty();
-    GC_incremental = TRUE;
 out:
     UNLOCK();
-    ENABLE_SIGNALS();
+  } else {
+    GC_init();
   }
+# else
+    GC_init();
 # endif
 }
 
 
 #if defined(MSWIN32) || defined(MSWINCE)
-# define LOG_FILE _T("gc.log")
+# if defined(_MSC_VER) && defined(_DEBUG)
+#  include <crtdbg.h>
+# endif
+# ifdef OLD_WIN32_LOG_FILE
+#   define LOG_FILE _T("gc.log")
+# endif
 
   HANDLE GC_stdout = 0;
 
@@ -864,36 +829,56 @@ out:
       }
   }
 
-  int GC_write(buf, len)
-  GC_CONST char * buf;
-  size_t len;
+# ifndef THREADS
+#   define GC_need_to_lock 0  /* Not defined without threads */
+# endif
+  int GC_write(const char *buf, size_t len)
   {
       BOOL tmp;
       DWORD written;
       if (len == 0)
          return 0;
-      EnterCriticalSection(&GC_write_cs);
+      if (GC_need_to_lock) EnterCriticalSection(&GC_write_cs);
       if (GC_stdout == INVALID_HANDLE_VALUE) {
+          if (GC_need_to_lock) LeaveCriticalSection(&GC_write_cs);
          return -1;
       } else if (GC_stdout == 0) {
-         GC_stdout = CreateFile(LOG_FILE, GENERIC_WRITE,
-                                FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
-                                NULL); 
-         if (GC_stdout == INVALID_HANDLE_VALUE) ABORT("Open of log file failed");
+       char * file_name = GETENV("GC_LOG_FILE");
+       char logPath[_MAX_PATH + 5];
+
+        if (0 == file_name) {
+#         ifdef OLD_WIN32_LOG_FILE
+           strcpy(logPath, LOG_FILE);
+#        else
+           GetModuleFileName(NULL, logPath, _MAX_PATH);
+           strcat(logPath, ".log");
+#        endif
+         file_name = logPath;
+       }
+       GC_stdout = CreateFile(logPath, GENERIC_WRITE,
+                              FILE_SHARE_READ,
+                              NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
+                              NULL); 
+       if (GC_stdout == INVALID_HANDLE_VALUE)
+           ABORT("Open of log file failed");
       }
-      tmp = WriteFile(GC_stdout, buf, len, &written, NULL);
+      tmp = WriteFile(GC_stdout, buf, (DWORD)len, &written, NULL);
       if (!tmp)
          DebugBreak();
-      LeaveCriticalSection(&GC_write_cs);
+#     if defined(_MSC_VER) && defined(_DEBUG)
+         _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%.*s", len, buf);
+#     endif
+      if (GC_need_to_lock) LeaveCriticalSection(&GC_write_cs);
       return tmp ? (int)written : -1;
   }
+# undef GC_need_to_lock
 
 #endif
 
 #if defined(OS2) || defined(MACOS)
 FILE * GC_stdout = NULL;
 FILE * GC_stderr = NULL;
+FILE * GC_log = NULL;
 int GC_tmp;  /* Should really be local ... */
 
   void GC_set_files()
@@ -904,12 +889,16 @@ int GC_tmp;  /* Should really be local ... */
     if (GC_stderr == NULL) {
        GC_stderr = stderr;
     }
+    if (GC_log == NULL) {
+       GC_log = stderr;
+    }
   }
 #endif
 
 #if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
   int GC_stdout = 1;
   int GC_stderr = 2;
+  int GC_log = 2;
 # if !defined(AMIGA)
 #   include <unistd.h>
 # endif
@@ -919,7 +908,7 @@ int GC_tmp;  /* Should really be local ... */
     && !defined(MACOS)  && !defined(ECOS) && !defined(NOSYS)
 int GC_write(fd, buf, len)
 int fd;
-GC_CONST char *buf;
+const char *buf;
 size_t len;
 {
      register int bytes_written = 0;
@@ -957,6 +946,7 @@ int GC_write(fd, buf, len)
 
 
 #if defined(MSWIN32) || defined(MSWINCE)
+    /* FIXME: This is pretty ugly ... */
 #   define WRITE(f, buf, len) GC_write(buf, len)
 #else
 #   if defined(OS2) || defined(MACOS)
@@ -968,71 +958,77 @@ int GC_write(fd, buf, len)
 #   endif
 #endif
 
+#define BUFSZ 1024
+#ifdef _MSC_VER
+# define vsnprintf _vsnprintf
+#endif
 /* A version of printf that is unlikely to call malloc, and is thus safer */
 /* to call from the collector in case malloc has been bound to GC_malloc. */
-/* Assumes that no more than 1023 characters are written at once.        */
-/* Assumes that all arguments have been converted to something of the    */
-/* same size as long, and that the format conversions expect something   */
-/* of that size.                                                         */
-void GC_printf(format, a, b, c, d, e, f)
-GC_CONST char * format;
-long a, b, c, d, e, f;
+/* Floating point arguments ans formats should be avoided, since fp      */
+/* conversion is more likely to allocate.                                */
+/* Assumes that no more than BUFSZ-1 characters are written at once.     */
+void GC_printf(const char *format, ...)
 {
-    char buf[1025];
+    va_list args;
+    char buf[BUFSZ+1];
     
+    va_start(args, format);
     if (GC_quiet) return;
-    buf[1024] = 0x15;
-    (void) sprintf(buf, format, a, b, c, d, e, f);
-    if (buf[1024] != 0x15) ABORT("GC_printf clobbered stack");
+    buf[BUFSZ] = 0x15;
+    (void) vsnprintf(buf, BUFSZ, format, args);
+    va_end(args);
+    if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
     if (WRITE(GC_stdout, buf, strlen(buf)) < 0) ABORT("write to stdout failed");
 }
 
-void GC_err_printf(format, a, b, c, d, e, f)
-GC_CONST char * format;
-long a, b, c, d, e, f;
+void GC_err_printf(const char *format, ...)
 {
-    char buf[1025];
+    va_list args;
+    char buf[BUFSZ+1];
     
-    buf[1024] = 0x15;
-    (void) sprintf(buf, format, a, b, c, d, e, f);
-    if (buf[1024] != 0x15) ABORT("GC_err_printf clobbered stack");
+    va_start(args, format);
+    buf[BUFSZ] = 0x15;
+    (void) vsnprintf(buf, BUFSZ, format, args);
+    va_end(args);
+    if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
     if (WRITE(GC_stderr, buf, strlen(buf)) < 0) ABORT("write to stderr failed");
 }
 
-void GC_err_puts(s)
-GC_CONST char *s;
+void GC_log_printf(const char *format, ...)
+{
+    va_list args;
+    char buf[BUFSZ+1];
+    
+    va_start(args, format);
+    buf[BUFSZ] = 0x15;
+    (void) vsnprintf(buf, BUFSZ, format, args);
+    va_end(args);
+    if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
+    if (WRITE(GC_log, buf, strlen(buf)) < 0) ABORT("write to log failed");
+}
+
+void GC_err_puts(const char *s)
 {
     if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed");
 }
 
 #if defined(LINUX) && !defined(SMALL_CONFIG)
 void GC_err_write(buf, len)
-GC_CONST char *buf;
+const char *buf;
 size_t len;
 {
     if (WRITE(GC_stderr, buf, len) < 0) ABORT("write to stderr failed");
 }
 #endif
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_default_warn_proc(char *msg, GC_word arg)
-# else
-    void GC_default_warn_proc(msg, arg)
-    char *msg;
-    GC_word arg;
-# endif
+void GC_default_warn_proc(char *msg, GC_word arg)
 {
-    GC_err_printf1(msg, (unsigned long)arg);
+    GC_err_printf(msg, arg);
 }
 
 GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
 
-# if defined(__STDC__) || defined(__cplusplus)
-    GC_warn_proc GC_set_warn_proc(GC_warn_proc p)
-# else
-    GC_warn_proc GC_set_warn_proc(p)
-    GC_warn_proc p;
-# endif
+GC_warn_proc GC_set_warn_proc(GC_warn_proc p)
 {
     GC_warn_proc result;
 
@@ -1046,12 +1042,7 @@ GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
     return(result);
 }
 
-# if defined(__STDC__) || defined(__cplusplus)
-    GC_word GC_set_free_space_divisor (GC_word value)
-# else
-    GC_word GC_set_free_space_divisor (value)
-    GC_word value;
-# endif
+GC_word GC_set_free_space_divisor (GC_word value)
 {
     GC_word old = GC_free_space_divisor;
     GC_free_space_divisor = value;
@@ -1059,13 +1050,12 @@ GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
 }
 
 #ifndef PCR
-void GC_abort(msg)
-GC_CONST char * msg;
+void GC_abort(const char *msg)
 {
 #   if defined(MSWIN32)
       (void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK);
 #   else
-      GC_err_printf1("%s\n", msg);
+      GC_err_printf("%s\n", msg);
 #   endif
     if (GETENV("GC_LOOP_ON_ABORT") != NULL) {
            /* In many cases it's easier to debug a running process.    */
@@ -1099,31 +1089,28 @@ void GC_disable()
 /* Helper procedures for new kind creation.    */
 void ** GC_new_free_list_inner()
 {
-    void *result = GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
+    void *result = GC_INTERNAL_MALLOC((MAXOBJGRANULES+1)*sizeof(ptr_t),
+                                     PTRFREE);
     if (result == 0) ABORT("Failed to allocate freelist for new kind");
-    BZERO(result, (MAXOBJSZ+1)*sizeof(ptr_t));
+    BZERO(result, (MAXOBJGRANULES+1)*sizeof(ptr_t));
     return result;
 }
 
 void ** GC_new_free_list()
 {
     void *result;
-    LOCK(); DISABLE_SIGNALS();
+    LOCK();
     result = GC_new_free_list_inner();
-    UNLOCK(); ENABLE_SIGNALS();
+    UNLOCK();
     return result;
 }
 
-int GC_new_kind_inner(fl, descr, adjust, clear)
-void **fl;
-GC_word descr;
-int adjust;
-int clear;
+unsigned GC_new_kind_inner(void **fl, GC_word descr, int adjust, int clear)
 {
-    int result = GC_n_kinds++;
+    unsigned result = GC_n_kinds++;
 
     if (GC_n_kinds > MAXOBJKINDS) ABORT("Too many kinds");
-    GC_obj_kinds[result].ok_freelist = (ptr_t *)fl;
+    GC_obj_kinds[result].ok_freelist = fl;
     GC_obj_kinds[result].ok_reclaim_list = 0;
     GC_obj_kinds[result].ok_descriptor = descr;
     GC_obj_kinds[result].ok_relocate_descr = adjust;
@@ -1131,53 +1118,60 @@ int clear;
     return result;
 }
 
-int GC_new_kind(fl, descr, adjust, clear)
-void **fl;
-GC_word descr;
-int adjust;
-int clear;
+unsigned GC_new_kind(void **fl, GC_word descr, int adjust, int clear)
 {
-    int result;
-    LOCK(); DISABLE_SIGNALS();
+    unsigned result;
+    LOCK();
     result = GC_new_kind_inner(fl, descr, adjust, clear);
-    UNLOCK(); ENABLE_SIGNALS();
+    UNLOCK();
     return result;
 }
 
-int GC_new_proc_inner(proc)
-GC_mark_proc proc;
+unsigned GC_new_proc_inner(GC_mark_proc proc)
 {
-    int result = GC_n_mark_procs++;
+    unsigned result = GC_n_mark_procs++;
 
     if (GC_n_mark_procs > MAX_MARK_PROCS) ABORT("Too many mark procedures");
     GC_mark_procs[result] = proc;
     return result;
 }
 
-int GC_new_proc(proc)
-GC_mark_proc proc;
+unsigned GC_new_proc(GC_mark_proc proc)
 {
-    int result;
-    LOCK(); DISABLE_SIGNALS();
+    unsigned result;
+    LOCK();
     result = GC_new_proc_inner(proc);
-    UNLOCK(); ENABLE_SIGNALS();
+    UNLOCK();
     return result;
 }
 
+void * GC_call_with_stack_base(GC_stack_base_func fn, void *arg)
+{
+    int dummy;
+    struct GC_stack_base base;
+
+    base.mem_base = (void *)&dummy;
+#   ifdef IA64
+      base.reg_base = (void *)GC_save_regs_in_stack();
+      /* Unnecessarily flushes register stack,                 */
+      /* but that probably doesn't hurt.               */
+#   endif
+    return fn(&base, arg);
+}
 
 #if !defined(NO_DEBUGGING)
 
 void GC_dump()
 {
-    GC_printf0("***Static roots:\n");
+    GC_printf("***Static roots:\n");
     GC_print_static_roots();
-    GC_printf0("\n***Heap sections:\n");
+    GC_printf("\n***Heap sections:\n");
     GC_print_heap_sects();
-    GC_printf0("\n***Free blocks:\n");
+    GC_printf("\n***Free blocks:\n");
     GC_print_hblkfreelist();
-    GC_printf0("\n***Blocks in use:\n");
+    GC_printf("\n***Blocks in use:\n");
     GC_print_block_list();
-    GC_printf0("\n***Finalization statistics:\n");
+    GC_printf("\n***Finalization statistics:\n");
     GC_print_finalization_stats();
 }
 
diff --git a/src/mm/boehm-gc/mkinstalldirs b/src/mm/boehm-gc/mkinstalldirs
new file mode 100755 (executable)
index 0000000..82a561f
--- /dev/null
@@ -0,0 +1,101 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.1.1.1 2005/10/10 22:33:34 hboehm Exp $
+
+errstatus=0
+dirmode=""
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..."
+
+# process command line arguments
+while test $# -gt 0 ; do
+   case "${1}" in
+     -h | --help | --h* )                      # -h for help
+       echo "${usage}" 1>&2; exit 0 ;;
+     -m )                                      # -m PERM arg
+       shift
+       test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; }
+       dirmode="${1}"
+       shift ;;
+     -- ) shift; break ;;                      # stop option processing
+     -* ) echo "${usage}" 1>&2; exit 1 ;;      # unknown option
+     * )  break ;;                             # first non-opt arg
+   esac
+done
+
+for file
+do
+  if test -d "$file"; then
+    shift
+  else
+    break
+  fi
+done
+
+case $# in
+0) exit 0 ;;
+esac
+
+case $dirmode in
+'')
+  if mkdir -p -- . 2>/dev/null; then
+    echo "mkdir -p -- $*"
+    exec mkdir -p -- "$@"
+  fi ;;
+*)
+  if mkdir -m "$dirmode" -p -- . 2>/dev/null; then
+    echo "mkdir -m $dirmode -p -- $*"
+    exec mkdir -m "$dirmode" -p -- "$@"
+  fi ;;
+esac
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+       echo "mkdir $pathcomp"
+
+       mkdir "$pathcomp" || lasterr=$?
+
+       if test ! -d "$pathcomp"; then
+         errstatus=$lasterr
+       else
+         if test ! -z "$dirmode"; then
+            echo "chmod $dirmode $pathcomp"
+
+            lasterr=""
+            chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+            if test ! -z "$lasterr"; then
+              errstatus=$lasterr
+            fi
+         fi
+       fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 3
+# End:
+# mkinstalldirs ends here
diff --git a/src/mm/boehm-gc/msvc_dbg.c b/src/mm/boehm-gc/msvc_dbg.c
new file mode 100644 (file)
index 0000000..b172025
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+  Copyright (c) 2004 Andrei Polushin
+
+  Permission is hereby granted, free of charge,  to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction,  including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+#ifndef _M_AMD64
+
+/* X86_64 is ccurrently missing some meachine-dependent code below. */
+
+#include "private/msvc_dbg.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#pragma pack(push, 8)
+#include <imagehlp.h>
+#pragma pack(pop)
+
+#pragma comment(lib, "dbghelp.lib")
+#pragma optimize("gy", off)
+
+#ifdef _WIN64
+       typedef ULONG_PTR ULONG_ADDR;
+#else
+       typedef ULONG     ULONG_ADDR;
+#endif
+
+static HANDLE GetSymHandle()
+{
+       static HANDLE symHandle = NULL;
+       if (!symHandle) {
+               BOOL bRet = SymInitialize(symHandle = GetCurrentProcess(), NULL, FALSE);
+               if (bRet) {
+                       DWORD dwOptions = SymGetOptions();
+                       dwOptions &= ~SYMOPT_UNDNAME;
+                       dwOptions |= SYMOPT_LOAD_LINES;
+                       SymSetOptions(dwOptions);
+               }
+       }
+       return symHandle;
+}
+
+static void* CALLBACK FunctionTableAccess(HANDLE hProcess, ULONG_ADDR dwAddrBase)
+{
+       return SymFunctionTableAccess(hProcess, dwAddrBase);
+}
+
+static ULONG_ADDR CALLBACK GetModuleBase(HANDLE hProcess, ULONG_ADDR dwAddress)
+{
+       MEMORY_BASIC_INFORMATION memoryInfo;
+       ULONG_ADDR dwAddrBase = SymGetModuleBase(hProcess, dwAddress);
+       if (dwAddrBase) {
+               return dwAddrBase;
+       }
+       if (VirtualQueryEx(hProcess, (void*)(ULONG_PTR)dwAddress, &memoryInfo, sizeof(memoryInfo))) {
+               char filePath[_MAX_PATH];
+               char curDir[_MAX_PATH];
+               char exePath[_MAX_PATH];
+               DWORD size = GetModuleFileNameA((HINSTANCE)memoryInfo.AllocationBase, filePath, sizeof(filePath));
+
+               // Save and restore current directory around SymLoadModule, see KB article Q189780
+               GetCurrentDirectoryA(sizeof(curDir), curDir);
+               GetModuleFileNameA(NULL, exePath, sizeof(exePath));
+               strcat_s(exePath, sizeof(exePath), "\\..");
+               SetCurrentDirectoryA(exePath);
+#ifdef _DEBUG
+               GetCurrentDirectoryA(sizeof(exePath), exePath);
+#endif
+               SymLoadModule(hProcess, NULL, size ? filePath : NULL, NULL, (ULONG_ADDR)(ULONG_PTR)memoryInfo.AllocationBase, 0);
+               SetCurrentDirectoryA(curDir);
+       }
+       return (ULONG_ADDR)(ULONG_PTR)memoryInfo.AllocationBase;
+}
+
+static ULONG_ADDR CheckAddress(void* address)
+{
+       ULONG_ADDR dwAddress = (ULONG_ADDR)(ULONG_PTR)address;
+       GetModuleBase(GetSymHandle(), dwAddress);
+       return dwAddress;
+}
+
+size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames)
+{
+       HANDLE hProcess = GetSymHandle();
+       HANDLE hThread = GetCurrentThread();
+       CONTEXT context;
+       context.ContextFlags = CONTEXT_FULL;
+       if (!GetThreadContext(hThread, &context)) {
+               return 0;
+       }
+       // GetThreadContext might return invalid context for the current thread
+#if defined(_M_IX86)
+    __asm mov context.Ebp, ebp
+#endif
+       return GetStackFramesFromContext(hProcess, hThread, &context, skip + 1, frames, maxFrames);
+}
+
+size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread, CONTEXT* context, size_t skip, void* frames[], size_t maxFrames)
+{
+       size_t frameIndex;
+       DWORD machineType;
+       STACKFRAME stackFrame = { 0 };
+       stackFrame.AddrPC.Mode      = AddrModeFlat;
+#if defined(_M_IX86)
+       machineType                 = IMAGE_FILE_MACHINE_I386;
+       stackFrame.AddrPC.Offset    = context->Eip;
+       stackFrame.AddrStack.Mode   = AddrModeFlat;
+       stackFrame.AddrStack.Offset = context->Esp;
+       stackFrame.AddrFrame.Mode   = AddrModeFlat;
+       stackFrame.AddrFrame.Offset = context->Ebp;
+#elif defined(_M_MRX000)
+       machineType                 = IMAGE_FILE_MACHINE_R4000;
+       stackFrame.AddrPC.Offset    = context->Fir;
+#elif defined(_M_ALPHA)
+       machineType                 = IMAGE_FILE_MACHINE_ALPHA;
+       stackFrame.AddrPC.Offset    = (unsigned long)context->Fir;
+#elif defined(_M_PPC)
+       machineType                 = IMAGE_FILE_MACHINE_POWERPC;
+       stackFrame.AddrPC.Offset    = context->Iar;
+#elif defined(_M_IA64)
+       machineType                 = IMAGE_FILE_MACHINE_IA64;
+       stackFrame.AddrPC.Offset    = context->StIIP;
+#elif defined(_M_ALPHA64)
+       machineType                 = IMAGE_FILE_MACHINE_ALPHA64;
+       stackFrame.AddrPC.Offset    = context->Fir;
+#else
+#error Unknown CPU
+#endif
+       for (frameIndex = 0; frameIndex < maxFrames; ) {
+               BOOL bRet = StackWalk(machineType, hProcess, hThread, &stackFrame, &context, NULL, FunctionTableAccess, GetModuleBase, NULL);
+               if (!bRet) {
+                       break;
+               }
+               if (skip) {
+                       skip--;
+               } else {
+                       frames[frameIndex++] = (void*)(ULONG_PTR)stackFrame.AddrPC.Offset;
+               }
+       }
+       return frameIndex;
+}
+
+size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size)
+{
+       if (size) *moduleName = 0;
+       {
+               const char* sourceName;
+               IMAGEHLP_MODULE moduleInfo = { sizeof (moduleInfo) };
+               if (!SymGetModuleInfo(GetSymHandle(), CheckAddress(address), &moduleInfo)) {
+                       return 0;
+               }
+               sourceName = strrchr(moduleInfo.ImageName, '\\');
+               if (sourceName) {
+                       sourceName++;
+               } else {
+                       sourceName = moduleInfo.ImageName;
+               }
+               if (size) {
+                       strncpy(moduleName, sourceName, size)[size - 1] = 0;
+               }
+               return strlen(sourceName);
+       }
+}
+
+size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size)
+{
+       void* address = NULL;
+       GetStackFrames(skip + 1, &address, 1);
+       if (address) {
+               return GetModuleNameFromAddress(address, moduleName, size);
+       }
+       return 0;
+}
+
+size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, size_t* offsetBytes)
+{
+       if (size) *symbolName = 0;
+       if (offsetBytes) *offsetBytes = 0;
+       __try {
+               ULONG_ADDR dwOffset = 0;
+               union {
+                       IMAGEHLP_SYMBOL sym;
+                       char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME];
+               } u;
+               u.sym.SizeOfStruct  = sizeof(u.sym);
+               u.sym.MaxNameLength = sizeof(u.symNameBuffer) - sizeof(u.sym);
+
+               if (!SymGetSymFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset, &u.sym)) {
+                       return 0;
+               } else {
+                       const char* sourceName = u.sym.Name;
+                       char undName[1024];
+                       if (UnDecorateSymbolName(u.sym.Name, undName, sizeof(undName), UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS)) {
+                               sourceName = undName;
+                       } else if (SymUnDName(&u.sym, undName, sizeof(undName))) {
+                               sourceName = undName;
+                       }
+                       if (offsetBytes) {
+                               *offsetBytes = dwOffset;
+                       }
+                       if (size) {
+                               strncpy(symbolName, sourceName, size)[size - 1] = 0;
+                       }
+                       return strlen(sourceName);
+               }
+       } __except (EXCEPTION_EXECUTE_HANDLER) {
+               SetLastError(GetExceptionCode());
+       }
+       return 0;
+}
+
+size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size, size_t* offsetBytes)
+{
+       void* address = NULL;
+       GetStackFrames(skip + 1, &address, 1);
+       if (address) {
+               return GetSymbolNameFromAddress(address, symbolName, size, offsetBytes);
+       }
+       return 0;
+}
+
+size_t GetFileLineFromAddress(void* address, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes)
+{
+       if (size) *fileName = 0;
+       if (lineNumber) *lineNumber = 0;
+       if (offsetBytes) *offsetBytes = 0;
+       {
+               char* sourceName;
+               IMAGEHLP_LINE line = { sizeof (line) };
+               ULONG_PTR dwOffset = 0;
+               if (!SymGetLineFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset, &line)) {
+                       return 0;
+               }
+               if (lineNumber) {
+                       *lineNumber = line.LineNumber;
+               }
+               if (offsetBytes) {
+                       *offsetBytes = dwOffset;
+               }
+               sourceName = line.FileName;
+               // TODO: resolve relative filenames, found in 'source directories' registered with MSVC IDE.
+               if (size) {
+                       strncpy(fileName, sourceName, size)[size - 1] = 0;
+               }
+               return strlen(sourceName);
+       }
+}
+
+size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes)
+{
+       void* address = NULL;
+       GetStackFrames(skip + 1, &address, 1);
+       if (address) {
+               return GetFileLineFromAddress(address, fileName, size, lineNumber, offsetBytes);
+       }
+       return 0;
+}
+
+size_t GetDescriptionFromAddress(void* address, const char* format, char* buffer, size_t size)
+{
+       char*const begin = buffer;
+       char*const end = buffer + size;
+       size_t line_number = 0;
+       char   str[128];
+
+       if (size) {
+               *buffer = 0;
+       }
+       buffer += GetFileLineFromAddress(address, buffer, size, &line_number, NULL);
+       size = end < buffer ? 0 : end - buffer;
+
+       if (line_number) {
+               wsprintf(str, "(%d) : ", line_number);
+               if (size) {
+                       strncpy(buffer, str, size)[size - 1] = 0;
+               }
+               buffer += strlen(str);
+               size = end < buffer ? 0 : end - buffer;
+       }
+
+       if (size) {
+               strncpy(buffer, "at ", size)[size - 1] = 0;
+       }
+       buffer += strlen("at ");
+       size = end < buffer ? 0 : end - buffer;
+
+       buffer += GetSymbolNameFromAddress(address, buffer, size, NULL);
+       size = end < buffer ? 0 : end - buffer;
+
+       if (size) {
+               strncpy(buffer, " in ", size)[size - 1] = 0;
+       }
+       buffer += strlen(" in ");
+       size = end < buffer ? 0 : end - buffer;
+       
+       buffer += GetModuleNameFromAddress(address, buffer, size);
+       size = end < buffer ? 0 : end - buffer;
+       
+       return buffer - begin;
+}
+
+size_t GetDescriptionFromStack(void*const frames[], size_t count, const char* format, char* description[], size_t size)
+{
+       char*const begin = (char*)description;
+       char*const end = begin + size;
+       char* buffer = begin + (count + 1) * sizeof(char*);
+       size_t i;
+       for (i = 0; i < count; ++i) {
+               if (description) description[i] = buffer;
+               size = end < buffer ? 0 : end - buffer;
+               buffer += 1 + GetDescriptionFromAddress(frames[i], NULL, buffer, size);
+       }
+       if (description) description[count] = NULL;
+       return buffer - begin;
+}
+
+/* Compatibility with <execinfo.h> */
+
+int backtrace(void* addresses[], int count)
+{
+       return GetStackFrames(1, addresses, count);
+}
+
+char** backtrace_symbols(void*const* addresses, int count)
+{
+       size_t size = GetDescriptionFromStack(addresses, count, NULL, NULL, 0);
+       char** symbols = (char**)malloc(size);
+       GetDescriptionFromStack(addresses, count, NULL, symbols, size);
+       return symbols;
+}
+
+#endif /* !_M_AMD64 */
index 150e72ce46167aea0438b6ffa4505d9c13ac2ba3..de99ddcd0bab640e3e1c30f09ac95340216021fa 100644 (file)
@@ -14,7 +14,7 @@
  *
  * This file contains the functions:
  *     ptr_t GC_build_flXXX(h, old_fl)
- *     void GC_new_hblk(n)
+ *     void GC_new_hblk(size)
  */
 /* Boehm, May 19, 1994 2:09 pm PDT */
 
 
 #ifndef SMALL_CONFIG
 /*
- * Build a free list for size 1 objects inside hblk h.  Set the last link to
+ * Build a free list for size 2 (words) cleared objects inside hblk h.
+ * Set the last link to
  * be ofl.  Return a pointer tpo the first free list entry.
  */
-ptr_t GC_build_fl1(h, ofl)
-struct hblk *h;
-ptr_t ofl;
+ptr_t GC_build_fl_clear2(struct hblk *h, ptr_t ofl)
 {
-    register word * p = h -> hb_body;
-    register word * lim = (word *)(h + 1);
-    
-    p[0] = (word)ofl;
-    p[1] = (word)(p);
-    p[2] = (word)(p+1);
-    p[3] = (word)(p+2);
-    p += 4;
-    for (; p < lim; p += 4) {
-        p[0] = (word)(p-1);
-        p[1] = (word)(p);
-        p[2] = (word)(p+1);
-        p[3] = (word)(p+2);
-    };
-    return((ptr_t)(p-1));
-}
-
-/* The same for size 2 cleared objects */
-ptr_t GC_build_fl_clear2(h, ofl)
-struct hblk *h;
-ptr_t ofl;
-{
-    register word * p = h -> hb_body;
-    register word * lim = (word *)(h + 1);
+    word * p = (word *)(h -> hb_body);
+    word * lim = (word *)(h + 1);
     
     p[0] = (word)ofl;
     p[1] = 0;
@@ -71,33 +48,11 @@ ptr_t ofl;
     return((ptr_t)(p-2));
 }
 
-/* The same for size 3 cleared objects */
-ptr_t GC_build_fl_clear3(h, ofl)
-struct hblk *h;
-ptr_t ofl;
-{
-    register word * p = h -> hb_body;
-    register word * lim = (word *)(h + 1) - 2;
-    
-    p[0] = (word)ofl;
-    p[1] = 0;
-    p[2] = 0;
-    p += 3;
-    for (; p < lim; p += 3) {
-        p[0] = (word)(p-3);
-        p[1] = 0;
-        p[2] = 0;
-    };
-    return((ptr_t)(p-3));
-}
-
 /* The same for size 4 cleared objects */
-ptr_t GC_build_fl_clear4(h, ofl)
-struct hblk *h;
-ptr_t ofl;
+ptr_t GC_build_fl_clear4(struct hblk *h, ptr_t ofl)
 {
-    register word * p = h -> hb_body;
-    register word * lim = (word *)(h + 1);
+    word * p = (word *)(h -> hb_body);
+    word * lim = (word *)(h + 1);
     
     p[0] = (word)ofl;
     p[1] = 0;
@@ -114,12 +69,10 @@ ptr_t ofl;
 }
 
 /* The same for size 2 uncleared objects */
-ptr_t GC_build_fl2(h, ofl)
-struct hblk *h;
-ptr_t ofl;
+ptr_t GC_build_fl2(struct hblk *h, ptr_t ofl)
 {
-    register word * p = h -> hb_body;
-    register word * lim = (word *)(h + 1);
+    word * p = (word *)(h -> hb_body);
+    word * lim = (word *)(h + 1);
     
     p[0] = (word)ofl;
     p[2] = (word)p;
@@ -132,12 +85,10 @@ ptr_t ofl;
 }
 
 /* The same for size 4 uncleared objects */
-ptr_t GC_build_fl4(h, ofl)
-struct hblk *h;
-ptr_t ofl;
+ptr_t GC_build_fl4(struct hblk *h, ptr_t ofl)
 {
-    register word * p = h -> hb_body;
-    register word * lim = (word *)(h + 1);
+    word * p = (word *)(h -> hb_body);
+    word * lim = (word *)(h + 1);
     
     p[0] = (word)ofl;
     p[4] = (word)p;
@@ -159,11 +110,7 @@ ptr_t ofl;
 /* This could be called without the main GC lock, if we ensure that    */
 /* there is no concurrent collection which might reclaim objects that  */
 /* we have not yet allocated.                                          */
-ptr_t GC_build_fl(h, sz, clear, list)
-struct hblk *h;
-word sz;
-GC_bool clear;
-ptr_t list;
+ptr_t GC_build_fl(struct hblk *h, size_t sz, GC_bool clear, ptr_t list)
 {
   word *p, *prev;
   word *last_object;           /* points to last object in new hblk    */
@@ -180,18 +127,11 @@ ptr_t list;
   /* the difference is less significant.                               */
 #  ifndef SMALL_CONFIG
     switch (sz) {
-        case 1: return GC_build_fl1(h, list);
         case 2: if (clear) {
                    return GC_build_fl_clear2(h, list);
                } else {
                    return GC_build_fl2(h, list);
                }
-        case 3: if (clear) {
-                   return GC_build_fl_clear3(h, list);
-               } else {
-                   /* It's messy to do better than the default here. */
-                   break;
-               }
         case 4: if (clear) {
                    return GC_build_fl_clear4(h, list);
                } else {
@@ -206,8 +146,8 @@ ptr_t list;
     if (clear) BZERO(h, HBLKSIZE);
     
   /* Add objects to free list */
-    p = &(h -> hb_body[sz]);   /* second object in *h  */
-    prev = &(h -> hb_body[0]);         /* One object behind p  */
+    p = (word *)(h -> hb_body) + sz;   /* second object in *h  */
+    prev = (word *)(h -> hb_body);             /* One object behind p  */
     last_object = (word *)((char *)h + HBLKSIZE);
     last_object -= sz;
                            /* Last place for last object to start */
@@ -229,36 +169,34 @@ ptr_t list;
       return ((ptr_t)p);
 }
 
+
 /*
- * Allocate a new heapblock for small objects of size n.
+ * Allocate a new heapblock for small objects of size gran granules.
  * Add all of the heapblock's objects to the free list for objects
  * of that size.
  * Set all mark bits if objects are uncollectable.
  * Will fail to do anything if we are out of memory.
  */
-void GC_new_hblk(sz, kind)
-register word sz;
-int kind;
+void GC_new_hblk(size_t gran, int kind)
 {
-    register struct hblk *h;   /* the new heap block                   */
-    register GC_bool clear = GC_obj_kinds[kind].ok_init;
+  struct hblk *h;      /* the new heap block                   */
+  GC_bool clear = GC_obj_kinds[kind].ok_init;
 
-#   ifdef PRINTSTATS
-       if ((sizeof (struct hblk)) > HBLKSIZE) {
-           ABORT("HBLK SZ inconsistency");
-        }
-#   endif
+  /* Ignore gcc "no effect" warning on the following: */
+  GC_STATIC_ASSERT((sizeof (struct hblk)) == HBLKSIZE);
+  
   if (GC_debugging_started) clear = TRUE;
 
   /* Allocate a new heap block */
-    h = GC_allochblk(sz, kind, 0);
+    h = GC_allochblk(GRANULES_TO_BYTES(gran), kind, 0);
     if (h == 0) return;
 
   /* Mark all objects if appropriate. */
       if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(HDR(h));
 
   /* Build the free list */
-      GC_obj_kinds[kind].ok_freelist[sz] =
-       GC_build_fl(h, sz, clear, GC_obj_kinds[kind].ok_freelist[sz]);
+      GC_obj_kinds[kind].ok_freelist[gran] =
+       GC_build_fl(h, GRANULES_TO_WORDS(gran), clear,
+                   GC_obj_kinds[kind].ok_freelist[gran]);
 }
 
index 81782b2cc764b6414b61320d21f529ebccced388..080f16a263ae127d7e3fab9470daf0296c1a449f 100644 (file)
  
 # include "private/gc_priv.h"
 
-map_entry_type * GC_invalid_map = 0;
-
-/* Invalidate the object map associated with a block.  Free blocks     */
-/* are identified by invalid maps.                                     */
-void GC_invalidate_map(hhdr)
-hdr *hhdr;
-{
-    register int displ;
-    
-    if (GC_invalid_map == 0) {
-        GC_invalid_map = (map_entry_type *)GC_scratch_alloc(MAP_SIZE);
-        if (GC_invalid_map == 0) {
-            GC_err_printf0(
-               "Cant initialize GC_invalid_map: insufficient memory\n");
-            EXIT();
-        }
-        for (displ = 0; displ < HBLKSIZE; displ++) {
-            MAP_ENTRY(GC_invalid_map, displ) = OBJ_INVALID;
-        }
-    }
-    hhdr -> hb_map = GC_invalid_map;
-}
-
 /* Consider pointers that are offset bytes displaced from the beginning */
 /* of an object to be valid.                                            */
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_register_displacement(GC_word offset)
-# else
-    void GC_register_displacement(offset) 
-    GC_word offset;
-# endif
+void GC_register_displacement(size_t offset)
 {
     DCL_LOCK_STATE;
     
-    DISABLE_SIGNALS();
     LOCK();
     GC_register_displacement_inner(offset);
     UNLOCK();
-    ENABLE_SIGNALS();
 }
 
-void GC_register_displacement_inner(offset) 
-word offset;
+void GC_register_displacement_inner(size_t offset) 
 {
-    register unsigned i;
-    word map_entry = BYTES_TO_WORDS(offset);
-    
     if (offset >= VALID_OFFSET_SZ) {
         ABORT("Bad argument to GC_register_displacement");
     }
-    if (map_entry > MAX_OFFSET) map_entry = OFFSET_TOO_BIG;
     if (!GC_valid_offsets[offset]) {
       GC_valid_offsets[offset] = TRUE;
       GC_modws_valid_offsets[offset % sizeof(word)] = TRUE;
-      if (!GC_all_interior_pointers) {
-        for (i = 0; i <= MAXOBJSZ; i++) {
-          if (GC_obj_map[i] != 0) {
-             if (i == 0) {
-               GC_obj_map[i][offset] = (map_entry_type)map_entry;
-             } else {
-               register unsigned j;
-               register unsigned lb = WORDS_TO_BYTES(i);
-               
-               if (offset < lb) {
-                 for (j = offset; j < HBLKSIZE; j += lb) {
-                   GC_obj_map[i][j] = (map_entry_type)map_entry;
-                 }
-               }
-             }
-          }
-       }
-      }
     }
 }
 
-
-/* Add a heap block map for objects of size sz to obj_map.     */
-/* Return FALSE on failure.                                    */
-GC_bool GC_add_map_entry(sz)
-word sz;
+#ifdef MARK_BIT_PER_GRANULE
+/* Add a heap block map for objects of size granules to obj_map.       */
+/* Return FALSE on failure.                                            */
+/* A size of 0 granules is used for large objects.                     */
+GC_bool GC_add_map_entry(size_t granules)
 {
-    register unsigned obj_start;
-    register unsigned displ;
-    register map_entry_type * new_map;
-    word map_entry;
+    unsigned displ;
+    short * new_map;
     
-    if (sz > MAXOBJSZ) sz = 0;
-    if (GC_obj_map[sz] != 0) {
+    if (granules > BYTES_TO_GRANULES(MAXOBJBYTES)) granules = 0;
+    if (GC_obj_map[granules] != 0) {
         return(TRUE);
     }
-    new_map = (map_entry_type *)GC_scratch_alloc(MAP_SIZE);
+    new_map = (short *)GC_scratch_alloc(MAP_LEN * sizeof(short));
     if (new_map == 0) return(FALSE);
-#   ifdef PRINTSTATS
-        GC_printf1("Adding block map for size %lu\n", (unsigned long)sz);
-#   endif
-    for (displ = 0; displ < HBLKSIZE; displ++) {
-        MAP_ENTRY(new_map,displ) = OBJ_INVALID;
-    }
-    if (sz == 0) {
-        for(displ = 0; displ <= HBLKSIZE; displ++) {
-            if (OFFSET_VALID(displ)) {
-               map_entry = BYTES_TO_WORDS(displ);
-               if (map_entry > MAX_OFFSET) map_entry = OFFSET_TOO_BIG;
-                MAP_ENTRY(new_map,displ) = (map_entry_type)map_entry;
-            }
-        }
+    if (GC_print_stats)
+        GC_printf("Adding block map for size of %u granules (%u bytes)\n",
+                 (unsigned)granules, (unsigned)(GRANULES_TO_BYTES(granules)));
+    if (granules == 0) {
+      for (displ = 0; displ < BYTES_TO_GRANULES(HBLKSIZE); displ++) {
+        new_map[displ] = 1;  /* Nonzero to get us out of marker fast path. */
+      }
     } else {
-        for (obj_start = 0;
-             obj_start + WORDS_TO_BYTES(sz) <= HBLKSIZE;
-             obj_start += WORDS_TO_BYTES(sz)) {
-             for (displ = 0; displ < WORDS_TO_BYTES(sz); displ++) {
-                 if (OFFSET_VALID(displ)) {
-                    map_entry = BYTES_TO_WORDS(displ);
-                    if (map_entry > MAX_OFFSET) map_entry = OFFSET_TOO_BIG;
-                     MAP_ENTRY(new_map, obj_start + displ) =
-                                               (map_entry_type)map_entry;
-                 }
-             }
-        }
+      for (displ = 0; displ < BYTES_TO_GRANULES(HBLKSIZE); displ++) {
+       new_map[displ] = (short)(displ % granules);
+      }
     }
-    GC_obj_map[sz] = new_map;
+    GC_obj_map[granules] = new_map;
     return(TRUE);
 }
+#endif
+
+static GC_bool offsets_initialized = FALSE;
+
+void GC_initialize_offsets(void)
+{
+    if (!offsets_initialized) {
+      int i;
+      if (GC_all_interior_pointers) {
+       for (i = 0; i < VALID_OFFSET_SZ; ++i) GC_valid_offsets[i] = TRUE;
+      }
+      offsets_initialized = TRUE;
+    }
+}
index f18253b7d64c32ba71f208848d6a733603f96bc6..7d9c721367ce6efb3ca5fbc2a9d879039c76af68 100644 (file)
@@ -17,6 +17,9 @@
 #include "config.h"
 
 # include "private/gc_priv.h"
+# ifdef THREADS
+#   include "atomic_ops.h"
+# endif
 
 # if defined(LINUX) && !defined(POWERPC)
 #   include <linux/version.h>
@@ -50,7 +53,7 @@
 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
     && !defined(MSWINCE)
 #   include <sys/types.h>
-#   if !defined(MSWIN32) && !defined(SUNOS4)
+#   if !defined(MSWIN32)
 #      include <unistd.h>
 #   endif
 # endif
 #   include <signal.h>
 # endif
 
+#ifdef UNIX_LIKE
+# include <fcntl.h>
+#endif
+
 #if defined(LINUX) || defined(LINUX_STACKBOTTOM)
 # include <ctype.h>
 #endif
 /* Blatantly OS dependent routines, except for those that are related  */
 /* to dynamic loading.                                                 */
 
-# if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)
-#   define NEED_FIND_LIMIT
-# endif
-
-# if !defined(STACKBOTTOM) && defined(HEURISTIC2)
-#   define NEED_FIND_LIMIT
-# endif
-
-# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)
-#   define NEED_FIND_LIMIT
-# endif
-
-# if (defined(SVR4) || defined(AUX) || defined(DGUX) \
-      || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
-#   define NEED_FIND_LIMIT
-# endif
-
-#if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__))
-#  include <machine/trap.h>
-#  if !defined(PCR)
-#    define NEED_FIND_LIMIT
-#  endif
-#endif
-
-#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \
-    && !defined(NEED_FIND_LIMIT)
-   /* Used by GC_init_netbsd_elf() below.      */
-#  define NEED_FIND_LIMIT
-#endif
-
-#ifdef NEED_FIND_LIMIT
-#   include <setjmp.h>
-#endif
-
 #ifdef AMIGA
 # define GC_AMIGA_DEF
 # include "AmigaOS.c"
 # undef GC_AMIGA_DEF
 #endif
 
-#if defined(MSWIN32) || defined(MSWINCE)
+#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
 # define WIN32_LEAN_AND_MEAN
 # define NOSERVICE
 # include <windows.h>
+  /* It's not clear this is completely kosher under Cygwin.  But it    */
+  /* allows us to get a working GC_get_stack_base.                     */
 #endif
 
 #ifdef MACOS
 # include <sys/uio.h>
 # include <malloc.h>   /* for locking */
 #endif
-#if defined(USE_MMAP) || defined(USE_MUNMAP)
-# ifndef USE_MMAP
+
+#if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) || defined(IRIX5) \
+       || defined(USE_MMAP) || defined(USE_MUNMAP)
+# define MMAP_SUPPORTED
+#endif
+
+#if defined(MMAP_SUPPORTED) || defined(ADD_HEAP_GUARD_PAGES)
+# if defined(USE_MUNMAP) && !defined(USE_MMAP)
     --> USE_MUNMAP requires USE_MMAP
 # endif
 # include <sys/types.h>
 # include <errno.h>
 #endif
 
-#ifdef UNIX_LIKE
-# include <fcntl.h>
-# if defined(SUNOS5SIGS) && !defined(FREEBSD)
-#  include <sys/siginfo.h>
-# endif
-  /* Define SETJMP and friends to be the version that restores */
-  /* the signal mask.                                          */
-# define SETJMP(env) sigsetjmp(env, 1)
-# define LONGJMP(env, val) siglongjmp(env, val)
-# define JMP_BUF sigjmp_buf
-#else
-# define SETJMP(env) setjmp(env)
-# define LONGJMP(env, val) longjmp(env, val)
-# define JMP_BUF jmp_buf
-#endif
-
 #ifdef DARWIN
 /* for get_etext and friends */
 #include <mach-o/getsect.h>
 
 #if defined(LINUX) && \
     (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) || !defined(SMALL_CONFIG))
+# define NEED_PROC_MAPS
+#endif
 
+#ifdef NEED_PROC_MAPS
 /* We need to parse /proc/self/maps, either to find dynamic libraries, */
 /* and/or to find the register backing store base (IA64).  Do it once  */
 /* here.                                                               */
@@ -197,35 +165,96 @@ ssize_t GC_repeat_read(int fd, char *buf, size_t count)
     return num_read;
 }
 
+/* Determine the length of a file by incrementally reading it into a   */
+/* This would be sily to use on a file supporting lseek, but Linux     */
+/* /proc files usually do not.                                         */
+size_t GC_get_file_len(int f)
+{
+    size_t total = 0;
+    ssize_t result;
+#   define GET_FILE_LEN_BUF_SZ 500
+    char buf[GET_FILE_LEN_BUF_SZ];
+
+    do {
+       result = read(f, buf, GET_FILE_LEN_BUF_SZ);
+       if (result == -1) return 0;
+       total += result;
+    } while (result > 0);
+    return total;
+}
+
+size_t GC_get_maps_len(void)
+{
+    int f = open("/proc/self/maps", O_RDONLY);
+    size_t result = GC_get_file_len(f);
+    close(f);
+    return result;
+}
+
 /*
- * Apply fn to a buffer containing the contents of /proc/self/maps.
- * Return the result of fn or, if we failed, 0.
- * We currently do nothing to /proc/self/maps other than simply read
- * it.  This code could be simplified if we could determine its size
+ * Copy the contents of /proc/self/maps to a buffer in our address space.
+ * Return the address of the buffer, or zero on failure.
+ * This code could be simplified if we could determine its size
  * ahead of time.
  */
-
-word GC_apply_to_maps(word (*fn)(char *))
+char * GC_get_maps(void)
 {
     int f;
     int result;
-    size_t maps_size = 4000;  /* Initial guess.        */
     static char init_buf[1];
     static char *maps_buf = init_buf;
     static size_t maps_buf_sz = 1;
+    size_t maps_size, old_maps_size = 0;
+
+    /* The buffer is essentially static, so there must be a single client. */
+    GC_ASSERT(I_HOLD_LOCK());
+
+    /* Note that in the presence of threads, the maps file can */
+    /* essentially shrink asynchronously and unexpectedly as   */
+    /* threads that we already think of as dead release their  */
+    /* stacks.  And there is no easy way to read the entire    */
+    /* file atomically.  This is arguably a misfeature of the  */
+    /* /proc/.../maps interface.                               */
+
+    /* Since we dont believe the file can grow                 */
+    /* asynchronously, it should suffice to first determine    */
+    /* the size (using lseek or read), and then to reread the  */
+    /* file.  If the size is inconsistent we have to retry.    */
+    /* This only matters with threads enabled, and if we use   */
+    /* this to locate roots (not the default).                 */
+
+    /* Determine the initial size of /proc/self/maps.          */
+    /* Note that lseek doesn't work, at least as of 2.6.15.    */
+#   ifdef THREADS
+       maps_size = GC_get_maps_len();
+       if (0 == maps_size) return 0;
+#   else
+       maps_size = 4000;       /* Guess */
+#   endif
 
     /* Read /proc/self/maps, growing maps_buf as necessary.    */
-        /* Note that we may not allocate conventionally, and   */
-        /* thus can't use stdio.                               */
+    /* Note that we may not allocate conventionally, and       */
+    /* thus can't use stdio.                                   */
        do {
-           if (maps_size >= maps_buf_sz) {
+           while (maps_size >= maps_buf_sz) {
              /* Grow only by powers of 2, since we leak "too small" buffers. */
              while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
              maps_buf = GC_scratch_alloc(maps_buf_sz);
+#            ifdef THREADS
+               /* Recompute initial length, since we allocated.        */
+               /* This can only happen a few times per program         */
+               /* execution.                                           */
+               maps_size = GC_get_maps_len();
+               if (0 == maps_size) return 0;
+#            endif
              if (maps_buf == 0) return 0;
            }
+           GC_ASSERT(maps_buf_sz >= maps_size + 1);
            f = open("/proc/self/maps", O_RDONLY);
            if (-1 == f) return 0;
+#          ifdef THREADS
+             old_maps_size = maps_size;
+#          endif
            maps_size = 0;
            do {
                result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);
@@ -233,17 +262,23 @@ word GC_apply_to_maps(word (*fn)(char *))
                maps_size += result;
            } while (result == maps_buf_sz-1);
            close(f);
-       } while (maps_size >= maps_buf_sz);
+#          ifdef THREADS
+             if (maps_size > old_maps_size) {
+               GC_err_printf("Old maps size = %d, new maps size = %d\n",
+                             old_maps_size, maps_size);
+               ABORT("Unexpected asynchronous /proc/self/maps growth: "
+                     "Unregistered thread?");
+             }
+#          endif
+       } while (maps_size >= maps_buf_sz || maps_size < old_maps_size);
+               /* In the single-threaded case, the second clause is false.     */
         maps_buf[maps_size] = '\0';
        
     /* Apply fn to result. */
-       return fn(maps_buf);
+       return maps_buf;
 }
 
-#endif /* Need GC_apply_to_maps */
-
-#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64))
-//
+/*
 //  GC_parse_map_entry parses an entry from /proc/self/maps so we can
 //  locate all writable data segments that belong to shared libraries.
 //  The format of one of these entries and the fields we care about
@@ -252,19 +287,22 @@ word GC_apply_to_maps(word (*fn)(char *))
 //  ^^^^^^^^ ^^^^^^^^ ^^^^          ^^
 //  start    end      prot          maj_dev
 //
-//  Note that since about auguat 2003 kernels, the columns no longer have
+//  Note that since about august 2003 kernels, the columns no longer have
 //  fixed offsets on 64-bit kernels.  Hence we no longer rely on fixed offsets
 //  anywhere, which is safer anyway.
-//
+*/
 
 /*
  * Assign various fields of the first line in buf_ptr to *start, *end,
- * *prot_buf and *maj_dev.  Only *prot_buf may be set for unwritable maps.
+ * *prot, *maj_dev and *mapping_name.  Mapping_name may be NULL.
+ * *prot and *mapping_name are assigned pointers into the original
+ * buffer.
  */
-char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
-                                char *prot_buf, unsigned int *maj_dev)
+char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
+                                char **prot, unsigned int *maj_dev,
+                               char **mapping_name)
 {
-    char *start_start, *end_start, *prot_start, *maj_dev_start;
+    char *start_start, *end_start, *maj_dev_start;
     char *p;
     char *endp;
 
@@ -276,37 +314,109 @@ char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
     while (isspace(*p)) ++p;
     start_start = p;
     GC_ASSERT(isxdigit(*start_start));
-    *start = strtoul(start_start, &endp, 16); p = endp;
+    *start = (ptr_t)strtoul(start_start, &endp, 16); p = endp;
     GC_ASSERT(*p=='-');
 
     ++p;
     end_start = p;
     GC_ASSERT(isxdigit(*end_start));
-    *end = strtoul(end_start, &endp, 16); p = endp;
+    *end = (ptr_t)strtoul(end_start, &endp, 16); p = endp;
     GC_ASSERT(isspace(*p));
 
     while (isspace(*p)) ++p;
-    prot_start = p;
-    GC_ASSERT(*prot_start == 'r' || *prot_start == '-');
-    memcpy(prot_buf, prot_start, 4);
-    prot_buf[4] = '\0';
-    if (prot_buf[1] == 'w') {/* we can skip the rest if it's not writable. */
-       /* Skip past protection field to offset field */
-          while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
-          GC_ASSERT(isxdigit(*p));
-       /* Skip past offset field, which we ignore */
+    GC_ASSERT(*p == 'r' || *p == '-');
+    *prot = p;
+    /* Skip past protection field to offset field */
+       while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
+    GC_ASSERT(isxdigit(*p));
+    /* Skip past offset field, which we ignore */
           while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
-       maj_dev_start = p;
-        GC_ASSERT(isxdigit(*maj_dev_start));
-        *maj_dev = strtoul(maj_dev_start, NULL, 16);
-    }
+    maj_dev_start = p;
+    GC_ASSERT(isxdigit(*maj_dev_start));
+    *maj_dev = strtoul(maj_dev_start, NULL, 16);
 
-    while (*p && *p++ != '\n');
+    if (mapping_name == 0) {
+      while (*p && *p++ != '\n');
+    } else {
+      while (*p && *p != '\n' && *p != '/' && *p != '[') p++;
+      *mapping_name = p;
+      while (*p && *p++ != '\n');
+    }
 
     return p;
 }
 
-#endif /* Need to parse /proc/self/maps. */    
+/* Try to read the backing store base from /proc/self/maps.            */
+/* Return the bounds of the writable mapping with a 0 major device,    */
+/* which includes the address passed as data.                          */
+/* Return FALSE if there is no such mapping.                           */
+GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp)
+{
+  char *prot;
+  ptr_t my_start, my_end;
+  unsigned int maj_dev;
+  char *maps = GC_get_maps();
+  char *buf_ptr = maps;
+  
+  if (0 == maps) return(FALSE);
+  for (;;) {
+    buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
+                                &prot, &maj_dev, 0);
+
+    if (buf_ptr == NULL) return FALSE;
+    if (prot[1] == 'w' && maj_dev == 0) {
+        if (my_end > addr && my_start <= addr) {
+         *startp = my_start;
+         *endp = my_end;
+         return TRUE;
+       }
+    }
+  }
+  return FALSE;
+}
+
+/* Find the text(code) mapping for the library whose name starts with nm. */
+GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp)
+{
+  size_t nm_len = strlen(nm);
+  char *prot;
+  char *map_path;
+  ptr_t my_start, my_end;
+  unsigned int maj_dev;
+  char *maps = GC_get_maps();
+  char *buf_ptr = maps;
+  
+  if (0 == maps) return(FALSE);
+  for (;;) {
+    buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
+                                &prot, &maj_dev, &map_path);
+
+    if (buf_ptr == NULL) return FALSE;
+    if (prot[0] == 'r' && prot[1] == '-' && prot[2] == 'x' &&
+       strncmp(nm, map_path, nm_len) == 0) {
+         *startp = my_start;
+         *endp = my_end;
+         return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+#ifdef IA64
+static ptr_t backing_store_base_from_proc(void)
+{
+    ptr_t my_start, my_end;
+    if (!GC_enclosing_mapping(GC_save_regs_in_stack(), &my_start, &my_end)) {
+       if (GC_print_stats) {
+           GC_log_printf("Failed to find backing store base from /proc\n");
+       }
+       return 0;
+    }
+    return my_start;
+}
+#endif
+
+#endif /* NEED_PROC_MAPS */    
 
 #if defined(SEARCH_FOR_DATA_START)
   /* The I386 case can be handled without a search.  The Alpha case    */
@@ -314,7 +424,7 @@ char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
   /* for recent Linux versions.  This seems to be the easiest way to   */
   /* cover all versions.                                               */
 
-# ifdef LINUX
+# if defined(LINUX) || defined(HURD)
     /* 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  */
@@ -331,9 +441,9 @@ char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
 
   void GC_init_linux_data_start()
   {
-    extern ptr_t GC_find_limit();
+    extern ptr_t GC_find_limit(ptr_t, GC_bool);
 
-#   ifdef LINUX
+#   if defined(LINUX) || defined(HURD)
       /* Try the easy approaches first:        */
       if ((ptr_t)__data_start != 0) {
          GC_data_start = (ptr_t)(__data_start);
@@ -354,10 +464,6 @@ char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
 # define ECOS_GC_MEMORY_SIZE (448 * 1024)
 # endif /* ECOS_GC_MEMORY_SIZE */
 
-// setjmp() function, as described in ANSI para 7.6.1.1
-#undef SETJMP
-#define SETJMP( __env__ )  hal_setjmp( __env__ )
-
 // FIXME: This is a simple way of allocating memory which is
 // compatible with ECOS early releases.  Later releases use a more
 // sophisticated means of allocating memory than this simple static
@@ -385,9 +491,9 @@ static void *tiny_sbrk(ptrdiff_t increment)
 #if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
   ptr_t GC_data_start;
 
-  void GC_init_netbsd_elf()
+  void GC_init_netbsd_elf(void)
   {
-    extern ptr_t GC_find_limit();
+    extern ptr_t GC_find_limit(ptr_t, GC_bool);
     extern char **environ;
        /* This may need to be environ, without the underscore, for     */
        /* some versions.                                               */
@@ -503,7 +609,7 @@ void GC_enable_signals(void)
       && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) \
       && !defined(NOSYS) && !defined(ECOS)
 
-#   if defined(sigmask) && !defined(UTS4) && !defined(HURD)
+#   if 0
        /* Use the traditional BSD interface */
 #      define SIGSET_T int
 #      define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
@@ -512,14 +618,15 @@ void GC_enable_signals(void)
          /* longjmp implementations.  Most systems appear not to have  */
          /* a signal 32.                                               */
 #      define SIGSETMASK(old, new) (old) = sigsetmask(new)
-#   else
-       /* Use POSIX/SYSV interface     */
-#      define SIGSET_T sigset_t
-#      define SIG_DEL(set, signal) sigdelset(&(set), (signal))
-#      define SIG_FILL(set) sigfillset(&set)
-#      define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
 #   endif
 
+    /* Use POSIX/SYSV interface        */
+#   define SIGSET_T sigset_t
+#   define SIG_DEL(set, signal) sigdelset(&(set), (signal))
+#   define SIG_FILL(set) sigfillset(&set)
+#   define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
+
+
 static GC_bool mask_initialized = FALSE;
 
 static SIGSET_T new_mask;
@@ -528,12 +635,12 @@ static SIGSET_T old_mask;
 
 static SIGSET_T dummy;
 
-#if defined(PRINTSTATS) && !defined(THREADS)
+#if defined(GC_ASSERTIONS) && !defined(THREADS)
 # define CHECK_SIGNALS
   int GC_sig_disabled = 0;
 #endif
 
-void GC_disable_signals()
+void GC_disable_signals(void)
 {
     if (!mask_initialized) {
        SIG_FILL(new_mask);
@@ -562,7 +669,7 @@ void GC_disable_signals()
     SIGSETMASK(old_mask,new_mask);
 }
 
-void GC_enable_signals()
+void GC_enable_signals(void)
 {
 #   ifdef CHECK_SIGNALS
        if (GC_sig_disabled != 1) ABORT("Unmatched enable");
@@ -585,22 +692,21 @@ void GC_enable_signals()
 word GC_page_size;
 
 # if defined(MSWIN32) || defined(MSWINCE)
-  void GC_setpagesize()
+  void GC_setpagesize(void)
   {
     GetSystemInfo(&GC_sysinfo);
     GC_page_size = GC_sysinfo.dwPageSize;
   }
 
 # else
-#   if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP) \
-       || defined(USE_MUNMAP)
-       void GC_setpagesize()
+#   if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP)
+       void GC_setpagesize(void)
        {
            GC_page_size = GETPAGESIZE();
        }
 #   else
        /* It's acceptable to fake it. */
-       void GC_setpagesize()
+       void GC_setpagesize(void)
        {
            GC_page_size = HBLKSIZE;
        }
@@ -613,7 +719,7 @@ word GC_page_size;
  * With threads, GC_mark_roots needs to know how to do this.
  * Called with allocator lock held.
  */
-# if defined(MSWIN32) || defined(MSWINCE)
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
 # define is_writable(prot) ((prot) == PAGE_READWRITE \
                            || (prot) == PAGE_WRITECOPY \
                            || (prot) == PAGE_EXECUTE_READWRITE \
@@ -639,22 +745,33 @@ word GC_get_writable_length(ptr_t p, ptr_t *base)
     return(buf.RegionSize);
 }
 
-ptr_t GC_get_stack_base()
+int GC_get_stack_base(struct GC_stack_base *sb)
 {
     int dummy;
     ptr_t sp = (ptr_t)(&dummy);
     ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
     word size = GC_get_writable_length(trunc_sp, 0);
    
-    return(trunc_sp + size);
+    sb -> mem_base = trunc_sp + size;
+    return GC_SUCCESS;
 }
 
+#define HAVE_GET_STACK_BASE
+
+/* This is always called from the main thread. */
+ptr_t GC_get_main_stack_base(void)
+{
+    struct GC_stack_base sb;
+
+    GC_get_stack_base(&sb);
+    return (ptr_t)sb.mem_base;
+}
 
 # endif /* MS Windows */
 
 # ifdef BEOS
 # include <kernel/OS.h>
-ptr_t GC_get_stack_base(){
+ptr_t GC_get_main_stack_base(void){
        thread_info th;
        get_thread_info(find_thread(NULL),&th);
        return th.stack_end;
@@ -664,13 +781,13 @@ ptr_t GC_get_stack_base(){
 
 # ifdef OS2
 
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base(void)
 {
     PTIB ptib;
     PPIB ppib;
     
     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
-       GC_err_printf0("DosGetInfoBlocks failed\n");
+       GC_err_printf("DosGetInfoBlocks failed\n");
        ABORT("DosGetInfoBlocks failed\n");
     }
     return((ptr_t)(ptib -> tib_pstacklimit));
@@ -686,16 +803,12 @@ ptr_t GC_get_stack_base()
 
 # if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
 
-#   ifdef __STDC__
-       typedef void (*handler)(int);
-#   else
-       typedef void (*handler)();
-#   endif
+    typedef void (*handler)(int);
 
 #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
     || defined(HURD) || defined(NETBSD)
        static struct sigaction old_segv_act;
-#      if defined(IRIX5) || defined(HPUX) \
+#      if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \
        || defined(HURD) || defined(NETBSD)
            static struct sigaction old_bus_act;
 #      endif
@@ -703,12 +816,7 @@ ptr_t GC_get_stack_base()
         static handler old_segv_handler, old_bus_handler;
 #   endif
     
-#   ifdef __STDC__
-      void GC_set_and_save_fault_handler(handler h)
-#   else
-      void GC_set_and_save_fault_handler(h)
-      handler h;
-#   endif
+    void GC_set_and_save_fault_handler(handler h)
     {
 #      if defined(SUNOS5SIGS) || defined(IRIX5)  \
         || defined(OSF1) || defined(HURD) || defined(NETBSD)
@@ -728,11 +836,9 @@ ptr_t GC_get_stack_base()
                /* and setting a handler at the same time.              */
                (void) sigaction(SIGSEGV, 0, &old_segv_act);
                (void) sigaction(SIGSEGV, &act, 0);
-               (void) sigaction(SIGBUS, 0, &old_bus_act);
-               (void) sigaction(SIGBUS, &act, 0);
 #        else
                (void) sigaction(SIGSEGV, &act, &old_segv_act);
-#              if defined(IRIX5) \
+#              if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
                   || defined(HPUX) || defined(HURD) || defined(NETBSD)
                    /* Under Irix 5.x or HP/UX, we may get SIGBUS.      */
                    /* Pthreads doesn't exist under Irix 5.x, so we     */
@@ -749,29 +855,31 @@ ptr_t GC_get_stack_base()
     }
 # endif /* NEED_FIND_LIMIT || UNIX_LIKE */
 
-# ifdef NEED_FIND_LIMIT
+# if defined(NEED_FIND_LIMIT) || \
+     defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS)
   /* Some tools to implement HEURISTIC2        */
 #   define MIN_PAGE_SIZE 256   /* Smallest conceivable page size, bytes */
-    /* static */ JMP_BUF GC_jmp_buf;
     
     /*ARGSUSED*/
-    void GC_fault_handler(sig)
-    int sig;
+    void GC_fault_handler(int sig)
     {
         LONGJMP(GC_jmp_buf, 1);
     }
 
-    void GC_setup_temporary_fault_handler()
+    void GC_setup_temporary_fault_handler(void)
     {
+       /* Handler is process-wide, so this should only happen in */
+       /* one thread at a time.                                  */
+       GC_ASSERT(I_HOLD_LOCK());
        GC_set_and_save_fault_handler(GC_fault_handler);
     }
     
-    void GC_reset_fault_handler()
+    void GC_reset_fault_handler(void)
     {
 #       if defined(SUNOS5SIGS) || defined(IRIX5) \
           || defined(OSF1) || defined(HURD) || defined(NETBSD)
          (void) sigaction(SIGSEGV, &old_segv_act, 0);
-#        if defined(IRIX5) \
+#        if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
             || defined(HPUX) || defined(HURD) || defined(NETBSD)
              (void) sigaction(SIGBUS, &old_bus_act, 0);
 #        endif
@@ -786,17 +894,16 @@ ptr_t GC_get_stack_base()
     /* Return the first nonaddressible location > p (up) or    */
     /* the smallest location q s.t. [q,p) is addressable (!up).        */
     /* We assume that p (up) or p-1 (!up) is addressable.      */
-    ptr_t GC_find_limit(p, up)
-    ptr_t p;
-    GC_bool up;
+    /* Requires allocation lock.                               */
+    ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound)
     {
-        static VOLATILE ptr_t result;
-               /* Needs to be static, since otherwise it may not be    */
+        static volatile ptr_t result;
+               /* Safer if static, since otherwise it may not be       */
                /* preserved across the longjmp.  Can safely be         */
-               /* static since it's only called once, with the         */
+               /* static since it's only called with the               */
                /* allocation lock held.                                */
 
-
+       GC_ASSERT(I_HOLD_LOCK());
        GC_setup_temporary_fault_handler();
        if (SETJMP(GC_jmp_buf) == 0) {
            result = (ptr_t)(((word)(p))
@@ -804,8 +911,10 @@ ptr_t GC_get_stack_base()
            for (;;) {
                if (up) {
                    result += MIN_PAGE_SIZE;
+                   if (result >= bound) return bound;
                } else {
                    result -= MIN_PAGE_SIZE;
+                   if (result <= bound) return bound;
                }
                GC_noop1((word)(*result));
            }
@@ -816,10 +925,19 @@ ptr_t GC_get_stack_base()
        }
        return(result);
     }
+
+    ptr_t GC_find_limit(ptr_t p, GC_bool up)
+    {
+      if (up) {
+       return GC_find_limit_with_bound(p, up, (ptr_t)(word)(-1));
+      } else {
+       return GC_find_limit_with_bound(p, up, 0);
+      }
+    }
 # endif
 
 #if defined(ECOS) || defined(NOSYS)
-  ptr_t GC_get_stack_base()
+  ptr_t GC_get_main_stack_base(void)
   {
     return STACKBOTTOM;
   }
@@ -862,33 +980,6 @@ ptr_t GC_get_stack_base()
 #endif
 
 # ifdef IA64
-    /* Try to read the backing store base from /proc/self/maps.        */
-    /* We look for the writable mapping with a 0 major device,  */
-    /* which is        as close to our frame as possible, but below it.*/
-    static word backing_store_base_from_maps(char *maps)
-    {
-      char prot_buf[5];
-      char *buf_ptr = maps;
-      word start, end;
-      unsigned int maj_dev;
-      word current_best = 0;
-      word dummy;
-  
-      for (;;) {
-        buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
-       if (buf_ptr == NULL) return current_best;
-       if (prot_buf[1] == 'w' && maj_dev == 0) {
-           if (end < (word)(&dummy) && start > current_best) current_best = start;
-       }
-      }
-      return current_best;
-    }
-
-    static word backing_store_base_from_proc(void)
-    {
-        return GC_apply_to_maps(backing_store_base_from_maps);
-    }
-
 #   ifdef USE_LIBC_PRIVATES
 #     pragma weak __libc_ia64_register_backing_store_base
       extern ptr_t __libc_ia64_register_backing_store_base;
@@ -896,6 +987,8 @@ ptr_t GC_get_stack_base()
 
     ptr_t GC_get_register_stack_base(void)
     {
+      ptr_t result;
+
 #     ifdef USE_LIBC_PRIVATES
         if (0 != &__libc_ia64_register_backing_store_base
            && 0 != __libc_ia64_register_backing_store_base) {
@@ -906,16 +999,14 @@ ptr_t GC_get_stack_base()
          return __libc_ia64_register_backing_store_base;
         }
 #     endif
-      word result = backing_store_base_from_proc();
+      result = backing_store_base_from_proc();
       if (0 == result) {
-         /* Use dumb heuristics.  Works only for default configuration. */
-         result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
-         result += BACKING_STORE_ALIGNMENT - 1;
-         result &= ~(BACKING_STORE_ALIGNMENT - 1);
-         /* Verify that it's at least readable.  If not, we goofed. */
-         GC_noop1(*(word *)result); 
+         result = GC_find_limit(GC_save_regs_in_stack(), FALSE);
+         /* Now seems to work better than constant displacement        */
+         /* heuristic used in 6.X versions.  The latter seems to       */
+         /* fail for 2.6 kernels.                                      */
       }
-      return (ptr_t)result;
+      return result;
     }
 # endif
 
@@ -940,15 +1031,14 @@ ptr_t GC_get_stack_base()
     /* this.                                                   */  
 #   ifdef USE_LIBC_PRIVATES
       if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
-#       ifdef IA64
+#       if defined(IA64)
          /* Some versions of glibc set the address 16 bytes too        */
          /* low while the initialization code is running.              */
          if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
            return __libc_stack_end + 0x10;
          } /* Otherwise it's not safe to add 16 bytes and we fall      */
            /* back to using /proc.                                     */
-#      else 
-#      ifdef SPARC
+#      elif defined(SPARC)
          /* Older versions of glibc for 64-bit Sparc do not set
           * this variable correctly, it gets set to either zero
           * or one.
@@ -957,7 +1047,6 @@ ptr_t GC_get_stack_base()
            return __libc_stack_end;
 #      else
          return __libc_stack_end;
-#      endif
 #      endif
       }
 #   endif
@@ -1009,15 +1098,15 @@ ptr_t GC_get_stack_base()
 #endif /* FREEBSD_STACKBOTTOM */
 
 #if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
-    && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS)
+    && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS) \
+    && !defined(CYGWIN32)
 
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base(void)
 {
-#   if defined(HEURISTIC1) || defined(HEURISTIC2) || \
-       defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM)
-    word dummy;
-    ptr_t result;
+#   if defined(HEURISTIC1) || defined(HEURISTIC2)
+      word dummy;
 #   endif
+    ptr_t result;
 
 #   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
 
@@ -1069,6 +1158,84 @@ ptr_t GC_get_stack_base()
 
 # endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS, !NOSYS, !ECOS */
 
+#if defined(GC_LINUX_THREADS) && !defined(HAVE_GET_STACK_BASE)
+
+#include <pthread.h>
+
+#ifdef IA64
+  ptr_t GC_greatest_stack_base_below(ptr_t bound);
+       /* From pthread_support.c */
+#endif
+
+int GC_get_stack_base(struct GC_stack_base *b)
+{
+    pthread_attr_t attr;
+    size_t size;
+
+    if (pthread_getattr_np(pthread_self(), &attr) != 0) {
+       WARN("pthread_getattr_np failed\n", 0);
+       return GC_UNIMPLEMENTED;
+    }
+    if (pthread_attr_getstack(&attr, &(b -> mem_base), &size) != 0) {
+       ABORT("pthread_attr_getstack failed");
+    }
+#   ifdef STACK_GROWS_DOWN
+        b -> mem_base = (char *)(b -> mem_base) + size;
+#   endif
+#   ifdef IA64
+      /* We could try backing_store_base_from_proc, but that's safe    */
+      /* only if no mappings are being asynchronously created.         */
+      /* Subtracting the size from the stack base doesn't work for at  */
+      /* least the main thread.                                                */
+      LOCK();
+      {
+       ptr_t bsp = GC_save_regs_in_stack();
+       ptr_t next_stack = GC_greatest_stack_base_below(bsp);
+       if (0 == next_stack) {
+          b -> reg_base = GC_find_limit(bsp, FALSE);
+       } else {
+         /* Avoid walking backwards into preceding memory stack and    */
+         /* growing it.                                                */
+          b -> reg_base = GC_find_limit_with_bound(bsp, FALSE, next_stack);
+       }
+      }
+      UNLOCK();
+#   endif
+    return GC_SUCCESS;
+}
+
+#define HAVE_GET_STACK_BASE
+
+#endif /* GC_LINUX_THREADS */
+
+#ifndef HAVE_GET_STACK_BASE
+/* Retrieve stack base.                                                */
+/* Using the GC_find_limit version is risky.                   */
+/* On IA64, for example, there is no guard page between the    */
+/* stack of one thread and the register backing store of the   */
+/* next.  Thus this is likely to identify way too large a      */
+/* "stack" and thus at least result in disastrous performance. */
+/* FIXME - Implement better strategies here.                   */
+int GC_get_stack_base(struct GC_stack_base *b)
+{
+    int dummy;
+
+#   ifdef NEED_FIND_LIMIT
+#     ifdef STACK_GROWS_DOWN
+       b -> mem_base = GC_find_limit((ptr_t)(&dummy), TRUE);
+#       ifdef IA64
+         b -> reg_base = GC_find_limit(GC_save_regs_in_stack(), FALSE);
+#       endif
+#     else
+       b -> mem_base = GC_find_limit(&dummy, FALSE);
+#     endif
+      return GC_SUCCESS;
+#   else
+      return GC_UNIMPLEMENTED;
+#   endif
+}
+#endif
+
 /*
  * Register static data segment(s) as roots.
  * If more data segments are added later then they need to be registered
@@ -1079,7 +1246,7 @@ ptr_t GC_get_stack_base()
 
 # ifdef OS2
 
-void GC_register_data_segments()
+void GC_register_data_segments(void)
 {
     PTIB ptib;
     PPIB ppib;
@@ -1094,12 +1261,12 @@ void GC_register_data_segments()
     
     
     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
-       GC_err_printf0("DosGetInfoBlocks failed\n");
+       GC_err_printf("DosGetInfoBlocks failed\n");
        ABORT("DosGetInfoBlocks failed\n");
     }
     module_handle = ppib -> pib_hmte;
     if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
-       GC_err_printf0("DosQueryModuleName failed\n");
+       GC_err_printf("DosQueryModuleName failed\n");
        ABORT("DosGetInfoBlocks failed\n");
     }
     myexefile = fopen(path, "rb");
@@ -1160,7 +1327,7 @@ void GC_register_data_segments()
       if (!(flags & OBJWRITE)) continue;
       if (!(flags & OBJREAD)) continue;
       if (flags & OBJINVALID) {
-          GC_err_printf0("Object with invalid pages?\n");
+          GC_err_printf("Object with invalid pages?\n");
           continue;
       } 
       GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg), FALSE);
@@ -1183,12 +1350,77 @@ void GC_register_data_segments()
        /* This used to be set for gcc, to avoid dealing with           */
        /* the structured exception handling issues.  But we now have   */
        /* assembly code to do that right.                              */
+
+# if defined(GWW_VDB)
+
+#   ifndef _BASETSD_H_
+      typedef ULONG * PULONG_PTR;
+#   endif
+    typedef UINT (WINAPI * GetWriteWatch_type)(
+      DWORD, PVOID, SIZE_T, PVOID*, PULONG_PTR, PULONG);
+    static GetWriteWatch_type GetWriteWatch_func;
+    static DWORD GetWriteWatch_alloc_flag;
+
+#   define GC_GWW_AVAILABLE() (GetWriteWatch_func != NULL)
+
+    static void detect_GetWriteWatch(void)
+    {
+      static GC_bool done;
+      if (done)
+        return;
+
+      GetWriteWatch_func = (GetWriteWatch_type)
+        GetProcAddress(GetModuleHandle("kernel32.dll"), "GetWriteWatch");
+      if (GetWriteWatch_func != NULL) {
+        /* Also check whether VirtualAlloc accepts MEM_WRITE_WATCH,   */
+        /* as some versions of kernel32.dll have one but not the      */
+        /* other, making the feature completely broken.               */
+        void * page = VirtualAlloc(NULL, GC_page_size,
+                                    MEM_WRITE_WATCH | MEM_RESERVE,
+                                    PAGE_READWRITE);
+        if (page != NULL) {
+          PVOID pages[16];
+          ULONG_PTR count = 16;
+          DWORD page_size;
+          /* Check that it actually works.  In spite of some           */
+         /* documentation it actually seems to exist on W2K.           */
+         /* This test may be unnecessary, but ...                      */
+          if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
+                                 page, GC_page_size,
+                                 pages,
+                                 &count,
+                                 &page_size) != 0) {
+            /* GetWriteWatch always fails. */
+            GetWriteWatch_func = NULL;
+          } else {
+            GetWriteWatch_alloc_flag = MEM_WRITE_WATCH;
+          }
+          VirtualFree(page, GC_page_size, MEM_RELEASE);
+        } else {
+          /* GetWriteWatch will be useless. */
+          GetWriteWatch_func = NULL;
+        }
+      }
+      if (GC_print_stats) {
+        if (GetWriteWatch_func == NULL) {
+          GC_log_printf("Did not find a usable GetWriteWatch()\n");
+        } else {
+          GC_log_printf("Using GetWriteWatch()\n");
+        }
+      }
+      done = TRUE;
+    }
+
+# endif /* GWW_VDB */
+
   GC_bool GC_wnt = FALSE;
-        /* This is a Windows NT derivative, i.e. NT, W2K, XP or later.  */
+         /* This is a Windows NT derivative, i.e. NT, W2K, XP or later.  */
   
-  void GC_init_win32()
+  void GC_init_win32(void)
   {
-    /* if we're running under win32s, assume that no DLLs will be loaded */
+    /* Set GC_wnt.                                                      */
+    /* If we're running under win32s, assume that no DLLs will be loaded */
+    /* I doubt anyone still runs win32s, but ...                        */
     DWORD v = GetVersion();
     GC_wnt = !(v & 0x80000000);
     GC_no_win32_dlls |= ((!GC_wnt) && (v & 0xff) <= 3);
@@ -1200,7 +1432,7 @@ void GC_register_data_segments()
   ptr_t GC_least_described_address(ptr_t start)
   {  
     MEMORY_BASIC_INFORMATION buf;
-    DWORD result;
+    size_t result;
     LPVOID limit;
     ptr_t p;
     LPVOID q;
@@ -1214,7 +1446,7 @@ void GC_register_data_segments()
        if (result != sizeof(buf) || buf.AllocationBase == 0) break;
        p = (ptr_t)(buf.AllocationBase);
     }
-    return(p);
+    return p;
   }
 # endif
 
@@ -1250,7 +1482,7 @@ void GC_register_data_segments()
   void *GC_get_allocation_base(void *p)
   {
     MEMORY_BASIC_INFORMATION buf;
-    DWORD result = VirtualQuery(p, &buf, sizeof(buf));
+    size_t result = VirtualQuery(p, &buf, sizeof(buf));
     if (result != sizeof(buf)) {
       ABORT("Weird VirtualQuery result");
     }
@@ -1281,11 +1513,9 @@ void GC_register_data_segments()
          free(new_l); return;
        }
     }
-#   ifdef CONDPRINT
-      if (GC_print_stats)
-         GC_printf1("Found new system malloc AllocationBase at 0x%lx\n",
-                     candidate);
-#   endif
+    if (GC_print_stats)
+         GC_log_printf("Found new system malloc AllocationBase at %p\n",
+                        candidate);
     new_l -> allocation_base = candidate;
     new_l -> next = GC_malloc_heap_l;
     GC_malloc_heap_l = new_l;
@@ -1300,7 +1530,7 @@ void GC_register_data_segments()
      unsigned i;
      
 #    ifndef REDIRECT_MALLOC
-       static word last_gc_no = -1;
+       static word last_gc_no = (word)(-1);
      
        if (last_gc_no != GC_gc_no) {
         GC_add_current_malloc_heap();
@@ -1319,7 +1549,7 @@ void GC_register_data_segments()
   void GC_register_root_section(ptr_t static_root)
   {
       MEMORY_BASIC_INFORMATION buf;
-      DWORD result;
+      size_t result;
       DWORD protect;
       LPVOID p;
       char * base;
@@ -1362,9 +1592,7 @@ void GC_register_data_segments()
 
 # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
       || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
-ptr_t GC_SysVGetDataStart(max_page_size, etext_addr)
-int max_page_size;
-int * etext_addr;
+ptr_t GC_SysVGetDataStart(size_t max_page_size, ptr_t etext_addr)
 {
     word text_end = ((word)(etext_addr) + sizeof(word) - 1)
                    & ~(sizeof(word) - 1);
@@ -1372,7 +1600,7 @@ int * etext_addr;
     word next_page = ((text_end + (word)max_page_size - 1)
                      & ~((word)max_page_size - 1));
     word page_offset = (text_end & ((word)max_page_size - 1));
-    VOLATILE char * result = (char *)(next_page + page_offset);
+    volatile char * result = (char *)(next_page + page_offset);
     /* Note that this isnt equivalent to just adding           */
     /* max_page_size to &etext if &etext is at a page boundary */
     
@@ -1394,28 +1622,26 @@ int * etext_addr;
 }
 # endif
 
-# if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__)) && !defined(PCR)
+# if defined(FREEBSD) && (defined(I386) || defined(X86_64) || defined(powerpc) || defined(__powerpc__)) && !defined(PCR)
 /* Its unclear whether this should be identical to the above, or       */
 /* whether it should apply to non-X86 architectures.                   */
 /* For now we don't assume that there is always an empty page after    */
 /* etext.  But in some cases there actually seems to be slightly more.  */
 /* This also deals with holes between read-only data and writable data.        */
-ptr_t GC_FreeBSDGetDataStart(max_page_size, etext_addr)
-int max_page_size;
-int * etext_addr;
+ptr_t GC_FreeBSDGetDataStart(size_t max_page_size, ptr_t etext_addr)
 {
     word text_end = ((word)(etext_addr) + sizeof(word) - 1)
                     & ~(sizeof(word) - 1);
        /* etext rounded to word boundary       */
-    VOLATILE word next_page = (text_end + (word)max_page_size - 1)
+    volatile word next_page = (text_end + (word)max_page_size - 1)
                              & ~((word)max_page_size - 1);
-    VOLATILE ptr_t result = (ptr_t)text_end;
+    volatile ptr_t result = (ptr_t)text_end;
     GC_setup_temporary_fault_handler();
     if (SETJMP(GC_jmp_buf) == 0) {
        /* Try reading at the address.                          */
        /* This should happen before there is another thread.   */
        for (; next_page < (word)(DATAEND); next_page += (word)max_page_size)
-           *(VOLATILE char *)next_page;
+           *(volatile char *)next_page;
        GC_reset_fault_handler();
     } else {
        GC_reset_fault_handler();
@@ -1436,9 +1662,9 @@ int * etext_addr;
 
 #else /* !OS2 && !Windows && !AMIGA */
 
-void GC_register_data_segments()
+void GC_register_data_segments(void)
 {
-#   if !defined(PCR) && !defined(SRC_M3) && !defined(MACOS)
+#   if !defined(PCR) && !defined(MACOS)
 #     if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
        /* As of Solaris 2.3, the Solaris threads implementation        */
        /* allocates the data structure for the initial thread with     */
@@ -1447,11 +1673,11 @@ void GC_register_data_segments()
        /* hanging from it.  We're on thin ice here ...                 */
         extern caddr_t sbrk();
 
-       GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
+       GC_add_roots_inner(DATASTART, (ptr_t)sbrk(0), FALSE);
 #     else
-       GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
+       GC_add_roots_inner(DATASTART, (ptr_t)(DATAEND), FALSE);
 #       if defined(DATASTART2)
-         GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), FALSE);
+          GC_add_roots_inner(DATASTART2, (ptr_t)(DATAEND2), FALSE);
 #       endif
 #     endif
 #   endif
@@ -1505,48 +1731,9 @@ void GC_register_data_segments()
        && !defined(MSWIN32) && !defined(MSWINCE) \
        && !defined(MACOS) && !defined(DOS4GW) && !defined(NONSTOP)
 
-# ifdef SUNOS4
-    extern caddr_t sbrk();
-# endif
-# ifdef __STDC__
-#   define SBRK_ARG_T ptrdiff_t
-# else
-#   define SBRK_ARG_T int
-# endif
-
-
-# if 0 && defined(RS6000)  /* We now use mmap */
-/* The compiler seems to generate speculative reads one past the end of        */
-/* an allocated object.  Hence we need to make sure that the page      */
-/* following the last heap page is also mapped.                                */
-ptr_t GC_unix_get_mem(bytes)
-word bytes;
-{
-    caddr_t cur_brk = (caddr_t)sbrk(0);
-    caddr_t result;
-    SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
-    static caddr_t my_brk_val = 0;
-    
-    if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
-    if (lsbs != 0) {
-        if((caddr_t)(sbrk(GC_page_size - lsbs)) == (caddr_t)(-1)) return(0);
-    }
-    if (cur_brk == my_brk_val) {
-       /* Use the extra block we allocated last time. */
-        result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
-        if (result == (caddr_t)(-1)) return(0);
-        result -= GC_page_size;
-    } else {
-        result = (ptr_t)sbrk(GC_page_size + (SBRK_ARG_T)bytes);
-        if (result == (caddr_t)(-1)) return(0);
-    }
-    my_brk_val = result + bytes + GC_page_size;        /* Always page aligned */
-    return((ptr_t)result);
-}
-
-#else  /* Not RS6000 */
+# define SBRK_ARG_T ptrdiff_t
 
-#if defined(USE_MMAP) || defined(USE_MUNMAP)
+#if defined(MMAP_SUPPORTED)
 
 #ifdef USE_MMAP_FIXED
 #   define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
@@ -1568,17 +1755,11 @@ word bytes;
 # define OPT_MAP_ANON 0
 #endif 
 
-#endif /* defined(USE_MMAP) || defined(USE_MUNMAP) */
-
-#if defined(USE_MMAP)
-/* Tested only under Linux, IRIX5 and Solaris 2 */
-
 #ifndef HEAP_START
 #   define HEAP_START 0
 #endif
 
-ptr_t GC_unix_get_mem(bytes)
-word bytes;
+ptr_t GC_unix_mmap_get_mem(word bytes)
 {
     void *result;
     static ptr_t last_addr = HEAP_START;
@@ -1606,7 +1787,7 @@ word bytes;
        /* don't work, so we discard it and try again.                  */
        munmap(result, (size_t)(-GC_page_size) - (size_t)result);
                        /* Leave last page mapped, so we can't repeat. */
-       return GC_unix_get_mem(bytes);
+       return GC_unix_mmap_get_mem(bytes);
       }
 #   else
       GC_ASSERT(last_addr != 0);
@@ -1614,9 +1795,18 @@ word bytes;
     return((ptr_t)result);
 }
 
-#else /* Not RS6000, not USE_MMAP */
-ptr_t GC_unix_get_mem(bytes)
-word bytes;
+# endif  /* MMAP_SUPPORTED */
+
+#if defined(USE_MMAP)
+
+ptr_t GC_unix_get_mem(word bytes)
+{
+    return GC_unix_mmap_get_mem(bytes);
+}
+
+#else /* Not USE_MMAP */
+
+ptr_t GC_unix_sbrk_get_mem(word bytes)
 {
   ptr_t result;
 # ifdef IRIX5
@@ -1638,6 +1828,15 @@ word bytes;
            goto out;
        }
     }
+#   ifdef ADD_HEAP_GUARD_PAGES
+      /* This is useful for catching severe memory overwrite problems that */
+      /* span heap sections.  It shouldn't otherwise be turned on.        */
+      {
+       ptr_t guard = (ptr_t)sbrk((SBRK_ARG_T)GC_page_size);
+       if (mprotect(guard, GC_page_size, PROT_NONE) != 0)
+           ABORT("ADD_HEAP_GUARD_PAGES: mprotect failed");
+      }
+#   endif /* ADD_HEAP_GUARD_PAGES */
     result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
     if (result == (ptr_t)(-1)) result = 0;
   }
@@ -1648,8 +1847,36 @@ word bytes;
   return(result);
 }
 
+#if defined(MMAP_SUPPORTED)
+
+/* By default, we try both sbrk and mmap, in that order. */
+ptr_t GC_unix_get_mem(word bytes)
+{
+    static GC_bool sbrk_failed = FALSE;
+    ptr_t result = 0;
+
+    if (!sbrk_failed) result = GC_unix_sbrk_get_mem(bytes);
+    if (0 == result) {
+       sbrk_failed = TRUE;
+       result = GC_unix_mmap_get_mem(bytes);
+    }
+    if (0 == result) {
+       /* Try sbrk again, in case sbrk memory became available. */
+       result = GC_unix_sbrk_get_mem(bytes);
+    }
+    return result;
+}
+
+#else /* !MMAP_SUPPORTED */
+
+ptr_t GC_unix_get_mem(word bytes)
+{
+    return GC_unix_sbrk_get_mem(bytes);
+}
+
+#endif
+
 #endif /* Not USE_MMAP */
-#endif /* Not RS6000 */
 
 # endif /* UN*X */
 
@@ -1685,8 +1912,11 @@ SYSTEM_INFO GC_sysinfo;
 
 word GC_n_heap_bases = 0;
 
-ptr_t GC_win32_get_mem(bytes)
-word bytes;
+word GC_mem_top_down = 0;  /* Change to MEM_TOP_DOWN  for better 64-bit */
+                          /* testing.  Otherwise all addresses tend to */
+                          /* end up in first 4GB, hiding bugs.         */
+
+ptr_t GC_win32_get_mem(word bytes)
 {
     ptr_t result;
 
@@ -1695,7 +1925,7 @@ word bytes;
        /* There are also unconfirmed rumors of other           */
        /* problems, so we dodge the issue.                     */
         result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
-        result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));
+        result = (ptr_t)(((word)result + HBLKSIZE - 1) & ~(HBLKSIZE-1));
     } else {
        /* VirtualProtect only works on regions returned by a   */
        /* single VirtualAlloc call.  Thus we allocate one      */
@@ -1705,8 +1935,17 @@ word bytes;
        /* This wastes a small amount of memory, and risks      */
        /* increased fragmentation.  But better alternatives    */
        /* would require effort.                                */
+        /* Pass the MEM_WRITE_WATCH only if GetWriteWatch-based */
+        /* VDBs are enabled and the GetWriteWatch function is   */
+        /* available.  Otherwise we waste resources or possibly */
+        /* cause VirtualAlloc to fail (observed in Windows 2000 */
+        /* SP2).                                                */
         result = (ptr_t) VirtualAlloc(NULL, bytes + 1,
-                                     MEM_COMMIT | MEM_RESERVE,
+#                                     ifdef GWW_VDB
+                                        GetWriteWatch_alloc_flag |
+#                                     endif
+                                     MEM_COMMIT | MEM_RESERVE
+                                     | GC_mem_top_down,
                                      PAGE_EXECUTE_READWRITE);
     }
     if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
@@ -1717,7 +1956,7 @@ word bytes;
     return(result);                      
 }
 
-void GC_win32_free_heap ()
+void GC_win32_free_heap(void)
 {
     if (GC_no_win32_dlls) {
        while (GC_n_heap_bases > 0) {
@@ -1738,8 +1977,7 @@ void GC_win32_free_heap ()
 # ifdef MSWINCE
 word GC_n_heap_bases = 0;
 
-ptr_t GC_wince_get_mem(bytes)
-word bytes;
+ptr_t GC_wince_get_mem(word bytes)
 {
     ptr_t result;
     word i;
@@ -1761,10 +1999,10 @@ word bytes;
        /* Reserve more pages */
        word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
                         & ~(GC_sysinfo.dwAllocationGranularity-1);
-       /* If we ever support MPROTECT_VDB here, we will probably need to       */
-       /* ensure that res_bytes is strictly > bytes, so that VirtualProtect    */
-       /* never spans regions.  It seems to be OK for a VirtualFree argument   */
-       /* to span regions, so we should be OK for now.                         */
+       /* If we ever support MPROTECT_VDB here, we will probably need to    */
+       /* ensure that res_bytes is strictly > bytes, so that VirtualProtect */
+       /* never spans regions.  It seems to be OK for a VirtualFree         */
+       /* argument to span regions, so we should be OK for now.             */
        result = (ptr_t) VirtualAlloc(NULL, res_bytes,
                                      MEM_RESERVE | MEM_TOP_DOWN,
                                      PAGE_EXECUTE_READWRITE);
@@ -1809,7 +2047,7 @@ word bytes;
 /* Compute a page aligned starting address for the unmap       */
 /* operation on a block of size bytes starting at start.       */
 /* Return 0 if the block is too small to make this feasible.   */
-ptr_t GC_unmap_start(ptr_t start, word bytes)
+ptr_t GC_unmap_start(ptr_t start, size_t bytes)
 {
     ptr_t result = start;
     /* Round start to next page boundary.       */
@@ -1821,7 +2059,7 @@ ptr_t GC_unmap_start(ptr_t start, word bytes)
 
 /* Compute end address for an unmap operation on the indicated */
 /* block.                                                      */
-ptr_t GC_unmap_end(ptr_t start, word bytes)
+ptr_t GC_unmap_end(ptr_t start, size_t bytes)
 {
     ptr_t end_addr = start + bytes;
     end_addr = (ptr_t)((word)end_addr & ~(GC_page_size - 1));
@@ -1839,7 +2077,7 @@ ptr_t GC_unmap_end(ptr_t start, word bytes)
 /* We assume that GC_remap is called on exactly the same range */
 /* as a previous call to GC_unmap.  It is safe to consistently */
 /* round the endpoints in both places.                         */
-void GC_unmap(ptr_t start, word bytes)
+void GC_unmap(ptr_t start, size_t bytes)
 {
     ptr_t start_addr = GC_unmap_start(start, bytes);
     ptr_t end_addr = GC_unmap_end(start, bytes);
@@ -1874,7 +2112,7 @@ void GC_unmap(ptr_t start, word bytes)
 }
 
 
-void GC_remap(ptr_t start, word bytes)
+void GC_remap(ptr_t start, size_t bytes)
 {
     ptr_t start_addr = GC_unmap_start(start, bytes);
     ptr_t end_addr = GC_unmap_end(start, bytes);
@@ -1909,9 +2147,9 @@ void GC_remap(ptr_t start, word bytes)
       result = mprotect(start_addr, len,
                        PROT_READ | PROT_WRITE | OPT_PROT_EXEC);
       if (result != 0) {
-         GC_err_printf3(
-               "Mprotect failed at 0x%lx (length %ld) with errno %ld\n",
-               start_addr, len, errno);
+         GC_err_printf(
+               "Mprotect failed at %p (length %ld) with errno %d\n",
+               start_addr, (unsigned long)len, errno);
          ABORT("Mprotect remapping failed");
       }
       GC_unmapped_bytes -= len;
@@ -1922,7 +2160,7 @@ void GC_remap(ptr_t start, word bytes)
 /* be merged.  Unmap the whole block.  This typically requires         */
 /* that we unmap a small section in the middle that was not previously */
 /* unmapped due to alignment constraints.                              */
-void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2)
+void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2, size_t bytes2)
 {
     ptr_t start1_addr = GC_unmap_start(start1, bytes1);
     ptr_t end1_addr = GC_unmap_end(start1, bytes1);
@@ -1930,7 +2168,7 @@ void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2)
     ptr_t end2_addr = GC_unmap_end(start2, bytes2);
     ptr_t start_addr = end1_addr;
     ptr_t end_addr = start2_addr;
-    word len;
+    size_t len;
     GC_ASSERT(start1 + bytes1 == start2);
     if (0 == start1_addr) start_addr = GC_unmap_start(start1, bytes1 + bytes2);
     if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);
@@ -1962,7 +2200,7 @@ void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2)
 /* environment, this is also responsible for marking from      */
 /* thread stacks.                                              */
 #ifndef THREADS
-void (*GC_push_other_roots)() = 0;
+void (*GC_push_other_roots)(void) = 0;
 #else /* THREADS */
 
 # ifdef PCR
@@ -1987,7 +2225,7 @@ PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any data)
 }
 
 
-void GC_default_push_other_roots GC_PROTO((void))
+void GC_default_push_other_roots(void)
 {
     /* Traverse data allocated by previous memory managers.            */
        {
@@ -2009,77 +2247,43 @@ void GC_default_push_other_roots GC_PROTO((void))
 
 # endif /* PCR */
 
-# ifdef SRC_M3
-
-# ifdef ALL_INTERIOR_POINTERS
-    --> misconfigured
-# endif
-
-void GC_push_thread_structures GC_PROTO((void))
-{
-    /* Not our responsibibility. */
-}
-
-extern void ThreadF__ProcessStacks();
-
-void GC_push_thread_stack(start, stop)
-word start, stop;
-{
-   GC_push_all_stack((ptr_t)start, (ptr_t)stop + sizeof(word));
-}
-
-/* Push routine with M3 specific calling convention. */
-GC_m3_push_root(dummy1, p, dummy2, dummy3)
-word *p;
-ptr_t dummy1, dummy2;
-int dummy3;
-{
-    word q = *p;
-    
-    GC_PUSH_ONE_STACK(q, p);
-}
-
-/* M3 set equivalent to RTHeap.TracedRefTypes */
-typedef struct { int elts[1]; }  RefTypeSet;
-RefTypeSet GC_TracedRefTypes = {{0x1}};
-
-void GC_default_push_other_roots GC_PROTO((void))
-{
-    /* Use the M3 provided routine for finding static roots.    */
-    /* This is a bit dubious, since it presumes no C roots.     */
-    /* We handle the collector roots explicitly in GC_push_roots */
-       RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);
-       if (GC_words_allocd > 0) {
-           ThreadF__ProcessStacks(GC_push_thread_stack);
-       }
-       /* Otherwise this isn't absolutely necessary, and we have       */
-       /* startup ordering problems.                                   */
-}
-
-# endif /* SRC_M3 */
 
-# if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS) || \
-     defined(GC_WIN32_THREADS)
+# if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
 
-extern void GC_push_all_stacks();
+extern void GC_push_all_stacks(void);
 
-void GC_default_push_other_roots GC_PROTO((void))
+void GC_default_push_other_roots(void)
 {
     GC_push_all_stacks();
 }
 
-# endif /* GC_SOLARIS_THREADS || GC_PTHREADS */
+# endif /* GC_WIN32_THREADS || GC_PTHREADS */
 
-void (*GC_push_other_roots) GC_PROTO((void)) = GC_default_push_other_roots;
+void (*GC_push_other_roots)(void) = GC_default_push_other_roots;
 
 #endif /* THREADS */
 
 /*
  * Routines for accessing dirty  bits on virtual pages.
- * We plan to eventually implement four strategies for doing so:
+ * There are six ways to maintain this information:
  * DEFAULT_VDB:        A simple dummy implementation that treats every page
  *             as possibly dirty.  This makes incremental collection
  *             useless, but the implementation is still correct.
+ * MANUAL_VDB:  Stacks and static data are always considered dirty.
+ *             Heap pages are considered dirty if GC_dirty(p) has been
+ *             called on some pointer p pointing to somewhere inside
+ *             an object on that page.  A GC_dirty() call on a large
+ *             object directly dirties only a single page, but for
+ *             MANUAL_VDB we are careful to treat an object with a dirty
+ *             page as completely dirty.
+ *             In order to avoid races, an object must be marked dirty
+ *             after it is written, and a reference to the object
+ *             must be kept on a stack or in a register in the interim.
+ *             With threads enabled, an object directly reachable from the
+ *             stack at the time of a collection is treated as dirty.
+ *             In single-threaded mode, it suffices to ensure that no
+ *             collection can take place between the pointer assignment
+ *             and the GC_dirty() call.
  * PCR_VDB:    Use PPCRs virtual dirty bit facility.
  * PROC_VDB:   Use the /proc facility for reading dirty bits.  Only
  *             works under some SVR4 variants.  Even then, it may be
@@ -2093,44 +2297,177 @@ void (*GC_push_other_roots) GC_PROTO((void)) = GC_default_push_other_roots;
  *             call from doing so.  It is the clients responsibility to
  *             make sure that other system calls are similarly protected
  *             or write only to the stack.
+ * GWW_VDB:     Use the Win32 GetWriteWatch functions, if available, to
+ *              read dirty bits.  In case it is not available (because we
+ *              are running on Windows 95, Windows 2000 or earlier),
+ *              MPROTECT_VDB may be defined as a fallback strategy.
  */
 GC_bool GC_dirty_maintained = FALSE;
 
-# ifdef DEFAULT_VDB
-
-/* All of the following assume the allocation lock is held, and        */
-/* signals are disabled.                                       */
-
-/* The client asserts that unallocated pages in the heap are never     */
-/* written.                                                            */
+#if defined(PROC_VDB) || defined(GWW_VDB)
 
-/* Initialize virtual dirty bit implementation.                        */
-void GC_dirty_init()
+/* Add all pages in pht2 to pht1 */
+void GC_or_pages(page_hash_table pht1, page_hash_table pht2)
 {
-#   ifdef PRINTSTATS
-      GC_printf0("Initializing DEFAULT_VDB...\n");
-#   endif
-    GC_dirty_maintained = TRUE;
+    register int i;
+    
+    for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
 }
 
-/* Retrieve system dirty bits for heap to a local buffer.      */
-/* Restore the systems notion of which pages are dirty.                */
-void GC_read_dirty()
-{}
+#endif
 
-/* Is the HBLKSIZE sized page at h marked dirty in the local buffer?   */
-/* If the actual page size is different, this returns TRUE if any      */
-/* of the pages overlapping h are dirty.  This routine may err on the  */
-/* side of labelling pages as dirty (and this implementation does).    */
-/*ARGSUSED*/
-GC_bool GC_page_was_dirty(h)
-struct hblk *h;
-{
-    return(TRUE);
-}
+#ifdef GWW_VDB
 
-/*
- * The following two routines are typically less crucial.  They matter
+# define GC_GWW_BUF_LEN 1024
+  static PVOID gww_buf[GC_GWW_BUF_LEN];
+
+# ifdef MPROTECT_VDB
+    GC_bool GC_gww_dirty_init(void)
+    {
+      detect_GetWriteWatch();
+      return GC_GWW_AVAILABLE();
+    }
+# else
+    void GC_dirty_init(void)
+    {
+      detect_GetWriteWatch();
+      GC_dirty_maintained = GC_GWW_AVAILABLE();
+    }
+# endif
+
+# ifdef MPROTECT_VDB
+    static void GC_gww_read_dirty(void)
+# else
+    void GC_read_dirty(void)
+# endif
+  {
+    word i;
+
+    BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
+
+    for (i = 0; i != GC_n_heap_sects; ++i) {
+      ULONG_PTR count;
+
+      do {
+        PVOID * pages, * pages_end;
+        DWORD page_size;
+
+        pages = gww_buf;
+        count = GC_GWW_BUF_LEN;
+        /*
+        * GetWriteWatch is documented as returning non-zero when it fails,
+        * but the documentation doesn't explicitly say why it would fail or
+        * what its behaviour will be if it fails.
+       * It does appear to fail, at least on recent W2K instances, if
+       * the underlying memory was not allocated with the appropriate
+       * flag.  This is common if GC_enable_incremental is called
+       * shortly after GC initialization.  To avoid modifying the
+       * interface, we silently work around such a failure, it it only
+       * affects the initial (small) heap allocation.
+       * If there are more dirty
+        * pages than will fit in the buffer, this is not treated as a
+        * failure; we must check the page count in the loop condition.
+       * Since each partial call will reset the status of some
+       * pages, this should eventually terminate even in the overflow
+       * case.
+        */
+        if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
+                               GC_heap_sects[i].hs_start,
+                               GC_heap_sects[i].hs_bytes,
+                               pages,
+                               &count,
+                               &page_size) != 0) {
+          static int warn_count = 0;
+          unsigned j;
+          struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start;
+          static struct hblk *last_warned = 0;
+          size_t nblocks = divHBLKSZ(GC_heap_sects[i].hs_bytes);
+
+          if ( i != 0 && last_warned != start && warn_count++ < 5) {
+            last_warned = start;
+            WARN(
+              "GC_gww_read_dirty unexpectedly failed at %ld: "
+              "Falling back to marking all pages dirty\n", start);
+          }
+          for (j = 0; j < nblocks; ++j) {
+              word hash = PHT_HASH(start + j);
+              set_pht_entry_from_index(GC_grungy_pages, hash);
+          }
+          count = 1;  /* Done with this section. */
+        } else /* succeeded */{
+          pages_end = pages + count;
+          while (pages != pages_end) {
+            struct hblk * h = (struct hblk *) *pages++;
+            struct hblk * h_end = (struct hblk *) ((char *) h + page_size);
+            do
+              set_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
+            while (++h < h_end);
+          }
+        }
+      } while (count == GC_GWW_BUF_LEN);
+    }
+
+    GC_or_pages(GC_written_pages, GC_grungy_pages);
+  }
+
+# ifdef MPROTECT_VDB
+    static GC_bool GC_gww_page_was_dirty(struct hblk * h)
+# else
+    GC_bool GC_page_was_dirty(struct hblk * h)
+# endif
+  {
+    return HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
+  }
+
+# ifdef MPROTECT_VDB
+    static GC_bool GC_gww_page_was_ever_dirty(struct hblk * h)
+# else
+    GC_bool GC_page_was_ever_dirty(struct hblk * h)
+# endif
+  {
+    return HDR(h) == 0 || get_pht_entry_from_index(GC_written_pages, PHT_HASH(h));
+  }
+
+# ifndef MPROTECT_VDB
+    void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
+    {}
+# endif
+
+# endif /* GWW_VDB */
+
+# ifdef DEFAULT_VDB
+
+/* All of the following assume the allocation lock is held, and        */
+/* signals are disabled.                                       */
+
+/* The client asserts that unallocated pages in the heap are never     */
+/* written.                                                            */
+
+/* Initialize virtual dirty bit implementation.                        */
+void GC_dirty_init(void)
+{
+    if (GC_print_stats == VERBOSE)
+      GC_log_printf("Initializing DEFAULT_VDB...\n");
+    GC_dirty_maintained = TRUE;
+}
+
+/* Retrieve system dirty bits for heap to a local buffer.      */
+/* Restore the systems notion of which pages are dirty.                */
+void GC_read_dirty(void)
+{}
+
+/* Is the HBLKSIZE sized page at h marked dirty in the local buffer?   */
+/* If the actual page size is different, this returns TRUE if any      */
+/* of the pages overlapping h are dirty.  This routine may err on the  */
+/* side of labelling pages as dirty (and this implementation does).    */
+/*ARGSUSED*/
+GC_bool GC_page_was_dirty(struct hblk *h)
+{
+    return(TRUE);
+}
+
+/*
+ * The following two routines are typically less crucial.  They matter
  * most with large dynamic libraries, or if we can't accurately identify
  * stacks, e.g. under Solaris 2.X.  Otherwise the following default
  * versions are adequate.
@@ -2138,19 +2475,11 @@ struct hblk *h;
  
 /* Could any valid GC heap pointer ever have been written to this page?        */
 /*ARGSUSED*/
-GC_bool GC_page_was_ever_dirty(h)
-struct hblk *h;
+GC_bool GC_page_was_ever_dirty(struct hblk *h)
 {
     return(TRUE);
 }
 
-/* Reset the n pages starting at h to "was never dirty" status.        */
-void GC_is_fresh(h, n)
-struct hblk *h;
-word n;
-{
-}
-
 /* A call that:                                                */
 /* I) hints that [h, h+nblocks) is about to be written.        */
 /* II) guarantees that protection is removed.          */
@@ -2159,15 +2488,68 @@ word n;
 /* pointer-free system call buffers in the heap are    */
 /* not protected.                                      */
 /*ARGSUSED*/
-void GC_remove_protection(h, nblocks, is_ptrfree)
-struct hblk *h;
-word nblocks;
-GC_bool is_ptrfree;
+void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
 {
 }
 
 # endif /* DEFAULT_VDB */
 
+# ifdef MANUAL_VDB
+
+/* Initialize virtual dirty bit implementation.                        */
+void GC_dirty_init(void)
+{
+    if (GC_print_stats == VERBOSE)
+      GC_log_printf("Initializing MANUAL_VDB...\n");
+    /* GC_dirty_pages and GC_grungy_pages are already cleared. */
+    GC_dirty_maintained = TRUE;
+}
+
+/* Retrieve system dirty bits for heap to a local buffer.      */
+/* Restore the systems notion of which pages are dirty.                */
+void GC_read_dirty(void)
+{
+    BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
+          (sizeof GC_dirty_pages));
+    BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
+}
+
+/* Is the HBLKSIZE sized page at h marked dirty in the local buffer?   */
+/* If the actual page size is different, this returns TRUE if any      */
+/* of the pages overlapping h are dirty.  This routine may err on the  */
+/* side of labelling pages as dirty (and this implementation does).    */
+/*ARGSUSED*/
+GC_bool GC_page_was_dirty(struct hblk *h)
+{
+    register word index;
+    
+    index = PHT_HASH(h);
+    return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
+}
+/* Could any valid GC heap pointer ever have been written to this page?        */
+/*ARGSUSED*/
+GC_bool GC_page_was_ever_dirty(struct hblk *h)
+{
+    /* FIXME - implement me.   */
+    return(TRUE);
+}
+
+/* Mark the page containing p as dirty.  Logically, this dirties the   */
+/* entire object.                                                      */
+void GC_dirty(ptr_t p)
+{
+    word index = PHT_HASH(p);
+    async_set_pht_entry_from_index(GC_dirty_pages, index);
+}
+
+/*ARGSUSED*/
+void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
+{
+}
+
+# endif /* MANUAL_VDB */
+
 
 # ifdef MPROTECT_VDB
 
@@ -2185,7 +2567,6 @@ GC_bool is_ptrfree;
  * heap, and do even that only if we are on a platform on which those
  * are not protected.  Another alternative is to wrap system calls
  * (see example for read below), but the current implementation holds
- * a lock across blocking calls, making it problematic for multithreaded
  * applications. 
  * We assume the page size is a multiple of HBLKSIZE.
  * We prefer them to be the same.  We avoid protecting POINTERFREE
@@ -2237,7 +2618,7 @@ GC_bool is_ptrfree;
          if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READ, \
                              &protect_junk)) { \
            DWORD last_error = GetLastError(); \
-           GC_printf1("Last error code: %lx\n", last_error); \
+           GC_printf("Last error code: %lx\n", last_error); \
            ABORT("VirtualProtect failed"); \
          }
 #   define UNPROTECT(addr, len) \
@@ -2248,88 +2629,33 @@ GC_bool is_ptrfree;
 # endif /* !DARWIN */
 # endif /* MSWIN32 || MSWINCE || DARWIN */
 
-#if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS))
-    typedef void (* SIG_PF)();
-#endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
-
-#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
-    || defined(HURD)
-# ifdef __STDC__
-    typedef void (* SIG_PF)(int);
-# else
-    typedef void (* SIG_PF)();
-# endif
-#endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */
-
 #if defined(MSWIN32)
-    typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
+    typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_HNDLR_PTR;
 #   undef SIG_DFL
 #   define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)
-#endif
-#if defined(MSWINCE)
-    typedef LONG (WINAPI *SIG_PF)(struct _EXCEPTION_POINTERS *);
+#elif defined(MSWINCE)
+    typedef LONG (WINAPI *SIG_HNDLR_PTR)(struct _EXCEPTION_POINTERS *);
 #   undef SIG_DFL
-#   define SIG_DFL (SIG_PF) (-1)
+#   define SIG_DFL (SIG_HNDLR_PTR) (-1)
+#elif defined(DARWIN)
+    typedef void (* SIG_HNDLR_PTR)();
+#else
+    typedef void (* SIG_HNDLR_PTR)(int, siginfo_t *, void *);
+    typedef void (* PLAIN_HNDLR_PTR)(int);
 #endif
 
-#if defined(IRIX5) || defined(OSF1) || defined(HURD)
-    typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
-#endif /* IRIX5 || OSF1 || HURD */
-
-#if defined(SUNOS5SIGS)
-# if defined(HPUX) || defined(FREEBSD)
-#   define SIGINFO_T siginfo_t
-# else
-#   define SIGINFO_T struct siginfo
-# endif
-# ifdef __STDC__
-    typedef void (* REAL_SIG_PF)(int, SIGINFO_T *, void *);
-# else
-    typedef void (* REAL_SIG_PF)();
-# endif
-#endif /* SUNOS5SIGS */
-
-#if defined(LINUX)
-#   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
-      typedef struct sigcontext s_c;
-#   else  /* glibc < 2.2 */
-#     include <linux/version.h>
-#     if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(ARM32)
-        typedef struct sigcontext s_c;
-#     else
-        typedef struct sigcontext_struct s_c;
-#     endif
-#   endif  /* glibc < 2.2 */
-#   if defined(ALPHA) || defined(M68K)
-      typedef void (* REAL_SIG_PF)(int, int, s_c *);
-#   else
-#     if defined(IA64) || defined(HP_PA) || defined(X86_64)
-        typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *);
-       /* FIXME:                                                 */
-       /* According to SUSV3, the last argument should have type */
-       /* void * or ucontext_t *                                 */
-#     else
-        typedef void (* REAL_SIG_PF)(int, s_c);
-#     endif
+#if defined(__GLIBC__)
+#   if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
+#      error glibc too old?
 #   endif
-#   ifdef ALPHA
-    /* Retrieve fault address from sigcontext structure by decoding    */
-    /* instruction.                                                    */
-    char * get_fault_addr(s_c *sc) {
-        unsigned instr;
-       word faultaddr;
-
-       instr = *((unsigned *)(sc->sc_pc));
-       faultaddr = sc->sc_regs[(instr >> 16) & 0x1f];
-       faultaddr += (word) (((int)instr << 16) >> 16);
-       return (char *)faultaddr;
-    }
-#   endif /* !ALPHA */
-# endif /* LINUX */
+#endif
 
 #ifndef DARWIN
-SIG_PF GC_old_bus_handler;
-SIG_PF GC_old_segv_handler;    /* Also old MSWIN32 ACCESS_VIOLATION filter */
+SIG_HNDLR_PTR GC_old_bus_handler;
+GC_bool GC_old_bus_handler_used_si;
+SIG_HNDLR_PTR GC_old_segv_handler;
+                       /* Also old MSWIN32 ACCESS_VIOLATION filter */
+GC_bool GC_old_segv_handler_used_si;
 #endif /* !DARWIN */
 
 #if defined(THREADS)
@@ -2340,25 +2666,27 @@ SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */
 /* safe fallback algorithm of setting all bits in the word.            */
 /* Contention should be very rare, so we do the minimum to handle it   */
 /* correctly.                                                          */
-#ifdef GC_TEST_AND_SET_DEFINED
-  static VOLATILE unsigned int fault_handler_lock = 0;
-  void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
-    while (GC_test_and_set(&fault_handler_lock)) {}
+#ifdef AO_HAVE_test_and_set_acquire
+  static volatile AO_TS_t fault_handler_lock = 0;
+  void async_set_pht_entry_from_index(volatile page_hash_table db, size_t index) {
+    while (AO_test_and_set_acquire(&fault_handler_lock) == AO_TS_SET) {}
     /* Could also revert to set_pht_entry_from_index_safe if initial   */
     /* GC_test_and_set fails.                                          */
     set_pht_entry_from_index(db, index);
-    GC_clear(&fault_handler_lock);
+    AO_CLEAR(&fault_handler_lock);
   }
-#else /* !GC_TEST_AND_SET_DEFINED */
-  /* THIS IS INCORRECT! The dirty bit vector may be temporarily wrong, */
+#else /* !AO_have_test_and_set_acquire */
+# error No test_and_set operation: Introduces a race.
+  /* THIS WOULD BE INCORRECT!                                          */
+  /* The dirty bit vector may be temporarily wrong,                    */
   /* just before we notice the conflict and correct it. We may end up   */
   /* looking at it while it's wrong.  But this requires contention     */
   /* exactly when a GC is triggered, which seems far less likely to    */
   /* fail than the old code, which had no reported failures.  Thus we  */
   /* leave it this way while we think of something better, or support  */
   /* GC_test_and_set on the remaining platforms.                       */
-  static VOLATILE word currently_updating = 0;
-  void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
+  static volatile word currently_updating = 0;
+  void async_set_pht_entry_from_index(volatile page_hash_table db, size_t index) {
     unsigned int update_dummy;
     currently_updating = (word)(&update_dummy);
     set_pht_entry_from_index(db, index);
@@ -2374,182 +2702,72 @@ SIG_PF GC_old_segv_handler;    /* Also old MSWIN32 ACCESS_VIOLATION filter */
        /* returning us to a safe state, though not soon enough.        */
     }
   }
-#endif /* !GC_TEST_AND_SET_DEFINED */
+#endif /* !AO_HAVE_test_and_set_acquire */
 #else /* !THREADS */
 # define async_set_pht_entry_from_index(db, index) \
        set_pht_entry_from_index(db, index)
 #endif /* !THREADS */
 
-/*ARGSUSED*/
 #if !defined(DARWIN)
-# if defined (SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS))
-    void GC_write_fault_handler(sig, code, scp, addr)
-    int sig, code;
-    struct sigcontext *scp;
-    char * addr;
-#   ifdef SUNOS4
-#     define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
-#     define CODE_OK (FC_CODE(code) == FC_PROT \
-                   || (FC_CODE(code) == FC_OBJERR \
-                      && FC_ERRNO(code) == FC_PROT))
-#   endif
-#   ifdef FREEBSD
-#     define SIG_OK (sig == SIGBUS)
-#     define CODE_OK TRUE
-#   endif
-# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
-
-# if defined(IRIX5) || defined(OSF1) || defined(HURD)
 #   include <errno.h>
-    void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
-#   ifdef OSF1
+#   if defined(FREEBSD)
+#     define SIG_OK TRUE
+#     define CODE_OK (code == BUS_PAGE_FAULT)
+#   elif defined(OSF1)
 #     define SIG_OK (sig == SIGSEGV)
 #     define CODE_OK (code == 2 /* experimentally determined */)
-#   endif
-#   ifdef IRIX5
+#   elif defined(IRIX5)
 #     define SIG_OK (sig == SIGSEGV)
 #     define CODE_OK (code == EACCES)
-#   endif
-#   ifdef HURD
+#   elif defined(HURD)
 #     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)  
 #     define CODE_OK  TRUE
-#   endif
-# endif /* IRIX5 || OSF1 || HURD */
-
-# if defined(LINUX)
-#   if defined(ALPHA) || defined(M68K)
-      void GC_write_fault_handler(int sig, int code, s_c * sc)
-#   else
-#     if defined(IA64) || defined(HP_PA) || defined(X86_64)
-        void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp)
-#     else
-#       if defined(ARM32)
-          void GC_write_fault_handler(int sig, int a2, int a3, int a4, s_c sc)
-#       else
-          void GC_write_fault_handler(int sig, s_c sc)
-#       endif
-#     endif
-#   endif
-#   define SIG_OK (sig == SIGSEGV)
-#   define CODE_OK TRUE
+#   elif defined(LINUX)
+#     define SIG_OK (sig == SIGSEGV)
+#     define CODE_OK TRUE
        /* Empirically c.trapno == 14, on IA32, but is that useful?     */
        /* Should probably consider alignment issues on other           */
        /* architectures.                                               */
-# endif /* LINUX */
-
-# if defined(SUNOS5SIGS)
-#  ifdef __STDC__
-    void GC_write_fault_handler(int sig, SIGINFO_T *scp, void * context)
-#  else
-    void GC_write_fault_handler(sig, scp, context)
-    int sig;
-    SIGINFO_T *scp;
-    void * context;
-#  endif
-#   ifdef HPUX
+#   elif defined(HPUX)
 #     define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
-#     define CODE_OK (scp -> si_code == SEGV_ACCERR) \
-                    || (scp -> si_code == BUS_ADRERR) \
-                    || (scp -> si_code == BUS_UNKNOWN) \
-                    || (scp -> si_code == SEGV_UNKNOWN) \
-                    || (scp -> si_code == BUS_OBJERR)
-#   else
-#     ifdef FREEBSD
-#       define SIG_OK (sig == SIGBUS)
-#       define CODE_OK (scp -> si_code == BUS_PAGE_FAULT)
-#     else
-#       define SIG_OK (sig == SIGSEGV)
-#       define CODE_OK (scp -> si_code == SEGV_ACCERR)
-#     endif
+#     define CODE_OK (si -> si_code == SEGV_ACCERR) \
+                    || (si -> si_code == BUS_ADRERR) \
+                    || (si -> si_code == BUS_UNKNOWN) \
+                    || (si -> si_code == SEGV_UNKNOWN) \
+                    || (si -> si_code == BUS_OBJERR)
+#   elif defined(FREEBSD)
+#     define SIG_OK (sig == SIGBUS)
+#     define CODE_OK (si -> si_code == BUS_PAGE_FAULT)
+#   elif defined(SUNOS5SIGS)
+#     define SIG_OK (sig == SIGSEGV)
+#     define CODE_OK (si -> si_code == SEGV_ACCERR)
+#   elif defined(MSWIN32) || defined(MSWINCE)
+#     define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode \
+                    == STATUS_ACCESS_VIOLATION)
+#     define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] \
+                     == 1) /* Write fault */
 #   endif    
-# endif /* SUNOS5SIGS */
 
 # if defined(MSWIN32) || defined(MSWINCE)
     LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
-#   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
-                       STATUS_ACCESS_VIOLATION)
-#   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
-                       /* Write fault */
+# else
+#   include <ucontext.h>
+    /*ARGSUSED*/
+    void GC_write_fault_handler(int sig, siginfo_t *si, void *raw_sc)
 # endif /* MSWIN32 || MSWINCE */
 {
-    register unsigned i;
-#   if defined(HURD) 
-       char *addr = (char *) code;
-#   endif
-#   ifdef IRIX5
-       char * addr = (char *) (size_t) (scp -> sc_badvaddr);
-#   endif
-#   if defined(OSF1) && defined(ALPHA)
-       char * addr = (char *) (scp -> sc_traparg_a0);
-#   endif
-#   ifdef SUNOS5SIGS
-       char * addr = (char *) (scp -> si_addr);
-#   endif
-#   ifdef LINUX
-#     if defined(I386)
-       char * addr = (char *) (sc.cr2);
-#     else
-#      if defined(M68K)
-          char * addr = NULL;
-
-         struct sigcontext *scp = (struct sigcontext *)(sc);
-
-         int format = (scp->sc_formatvec >> 12) & 0xf;
-         unsigned long *framedata = (unsigned long *)(scp + 1); 
-         unsigned long ea;
-
-         if (format == 0xa || format == 0xb) {
-               /* 68020/030 */
-               ea = framedata[2];
-         } else if (format == 7) {
-               /* 68040 */
-               ea = framedata[3];
-               if (framedata[1] & 0x08000000) {
-                       /* correct addr on misaligned access */
-                       ea = (ea+4095)&(~4095);
-               }
-         } else if (format == 4) {
-               /* 68060 */
-               ea = framedata[0];
-               if (framedata[1] & 0x08000000) {
-                       /* correct addr on misaligned access */
-                       ea = (ea+4095)&(~4095);
-               }
-         }     
-         addr = (char *)ea;
-#      else
-#        ifdef ALPHA
-            char * addr = get_fault_addr(sc);
-#        else
-#          if defined(IA64) || defined(HP_PA) || defined(X86_64)
-             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);
-#            else
-#               if defined(ARM32)
-                  char * addr = (char *)sc.fault_address;
-#               else
-#                if defined(CRIS)
-                   char * addr = (char *)sc.regs.csraddr;
-#                else
-                   --> architecture not supported
-#                endif
-#               endif
-#            endif
-#          endif
-#        endif
-#      endif
-#     endif
+#   if !defined(MSWIN32) && !defined(MSWINCE)
+      int code = si -> si_code;  /* Ignore gcc unused var. warning. */
+      ucontext_t * scp = (ucontext_t *)raw_sc;
+                               /* Ignore gcc unused var. warning. */
+      char *addr = si -> si_addr;
 #   endif
 #   if defined(MSWIN32) || defined(MSWINCE)
        char * addr = (char *) (exc_info -> ExceptionRecord
                                -> ExceptionInformation[1]);
 #      define sig SIGSEGV
 #   endif
+    unsigned i;
     
     if (SIG_OK && CODE_OK) {
         register struct hblk * h =
@@ -2573,53 +2791,38 @@ SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */
            /* sequence, which often depends on SA_SIGINFO.     */
 
            /* Heap blocks now begin and end on page boundaries */
-            SIG_PF old_handler;
+            SIG_HNDLR_PTR old_handler;
+           GC_bool used_si;
             
             if (sig == SIGSEGV) {
                old_handler = GC_old_segv_handler;
+               used_si = GC_old_segv_handler_used_si;
             } else {
                 old_handler = GC_old_bus_handler;
+               used_si = GC_old_bus_handler_used_si;
             }
-            if (old_handler == SIG_DFL) {
+            if (old_handler == (SIG_HNDLR_PTR)SIG_DFL) {
 #              if !defined(MSWIN32) && !defined(MSWINCE)
-                   GC_err_printf1("Segfault at 0x%lx\n", addr);
+                   GC_err_printf("Segfault at %p\n", addr);
                     ABORT("Unexpected bus error or segmentation fault");
 #              else
                    return(EXCEPTION_CONTINUE_SEARCH);
 #              endif
             } else {
-#              if defined (SUNOS4) \
-                    || (defined(FREEBSD) && !defined(SUNOS5SIGS))
-                   (*old_handler) (sig, code, scp, addr);
-                   return;
-#              endif
-#              if defined (SUNOS5SIGS)
-                    /*
-                     * FIXME: For FreeBSD, this code should check if the 
-                     * old signal handler used the traditional BSD style and
-                     * if so call it using that style.
-                     */
-                   (*(REAL_SIG_PF)old_handler) (sig, scp, context);
-                   return;
-#              endif
-#              if defined (LINUX)
-#                  if defined(ALPHA) || defined(M68K)
-                       (*(REAL_SIG_PF)old_handler) (sig, code, sc);
-#                  else 
-#                    if defined(IA64) || defined(HP_PA) || defined(X86_64)
-                       (*(REAL_SIG_PF)old_handler) (sig, si, scp);
-#                    else
-                       (*(REAL_SIG_PF)old_handler) (sig, sc);
-#                    endif
-#                  endif
-                   return;
-#              endif
-#              if defined (IRIX5) || defined(OSF1) || defined(HURD)
-                   (*(REAL_SIG_PF)old_handler) (sig, code, scp);
-                   return;
-#              endif
+                /*
+                 * FIXME: This code should probably check if the 
+                 * old signal handler used the traditional style and
+                 * if so call it using that style.
+                 */
 #              ifdef MSWIN32
                    return((*old_handler)(exc_info));
+#              else
+                   if (used_si)
+                     ((SIG_HNDLR_PTR)old_handler) (sig, si, raw_sc);
+                   else
+                     /* FIXME: should pass nonstandard args as well. */
+                     ((PLAIN_HNDLR_PTR)old_handler) (sig);
+                   return;
 #              endif
             }
         }
@@ -2636,14 +2839,10 @@ SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */
        /* and then to have the thread stopping code set the dirty      */
        /* flag, if necessary.                                          */
         for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
-            register int index = PHT_HASH(h+i);
+            size_t index = PHT_HASH(h+i);
             
             async_set_pht_entry_from_index(GC_dirty_pages, index);
         }
-#      if defined(OSF1)
-           /* These reset the signal handler each time by default. */
-           signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
-#      endif
        /* The write may not take place before dirty bits are read.     */
        /* But then we'll fault again ...                               */
 #      if defined(MSWIN32) || defined(MSWINCE)
@@ -2655,7 +2854,7 @@ SIG_PF GC_old_segv_handler;       /* Also old MSWIN32 ACCESS_VIOLATION filter */
 #if defined(MSWIN32) || defined(MSWINCE)
     return EXCEPTION_CONTINUE_SEARCH;
 #else
-    GC_err_printf1("Segfault at 0x%lx\n", addr);
+    GC_err_printf("Segfault at %p\n", addr);
     ABORT("Unexpected bus error or segmentation fault");
 #endif
 }
@@ -2667,23 +2866,23 @@ SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */
  * starting at h are no longer protected.  If is_ptrfree is false,
  * also ensure that they will subsequently appear to be dirty.
  */
-void GC_remove_protection(h, nblocks, is_ptrfree)
-struct hblk *h;
-word nblocks;
-GC_bool is_ptrfree;
+void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
 {
     struct hblk * h_trunc;  /* Truncated to page boundary */
     struct hblk * h_end;    /* Page boundary following block end */
     struct hblk * current;
     GC_bool found_clean;
     
+#   if defined(GWW_VDB)
+      if (GC_GWW_AVAILABLE()) return;
+#   endif
     if (!GC_dirty_maintained) return;
     h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
     h_end = (struct hblk *)(((word)(h + nblocks) + GC_page_size-1)
                            & ~(GC_page_size-1));
     found_clean = FALSE;
     for (current = h_trunc; current < h_end; ++current) {
-        int index = PHT_HASH(current);
+        size_t index = PHT_HASH(current);
             
         if (!is_ptrfree || current < h || current >= h + nblocks) {
             async_set_pht_entry_from_index(GC_dirty_pages, index);
@@ -2693,21 +2892,12 @@ GC_bool is_ptrfree;
 }
 
 #if !defined(DARWIN)
-void GC_dirty_init()
+void GC_dirty_init(void)
 {
-#   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
-       defined(OSF1) || defined(HURD)
+#   if !defined(MSWIN32) && !defined(MSWINCE)
       struct sigaction act, oldact;
-      /* We should probably specify SA_SIGINFO for Linux, and handle   */
-      /* the different architectures more uniformly.                   */
-#     if defined(IRIX5) || defined(LINUX) && !defined(X86_64) \
-        || defined(OSF1) || defined(HURD)
-       act.sa_flags    = SA_RESTART;
-        act.sa_handler  = (SIG_PF)GC_write_fault_handler;
-#     else
-       act.sa_flags    = SA_RESTART | SA_SIGINFO;
-        act.sa_sigaction = GC_write_fault_handler;
-#     endif
+      act.sa_flags     = SA_RESTART | SA_SIGINFO;
+      act.sa_sigaction = GC_write_fault_handler;
       (void)sigemptyset(&act.sa_mask);
 #     ifdef SIG_SUSPEND
         /* Arrange to postpone SIG_SUSPEND while we're in a write fault        */
@@ -2715,42 +2905,16 @@ void GC_dirty_init()
         /* stopping the world for GC.                                  */
         (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
 #     endif /* SIG_SUSPEND */
-#    endif
-#   ifdef PRINTSTATS
-       GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
 #   endif
+    if (GC_print_stats == VERBOSE)
+       GC_log_printf(
+               "Initializing mprotect virtual dirty bit implementation\n");
     GC_dirty_maintained = TRUE;
     if (GC_page_size % HBLKSIZE != 0) {
-        GC_err_printf0("Page size not multiple of HBLKSIZE\n");
+        GC_err_printf("Page size not multiple of HBLKSIZE\n");
         ABORT("Page size not multiple of HBLKSIZE");
     }
-#   if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS))
-      GC_old_bus_handler = signal(SIGBUS, GC_write_fault_handler);
-      if (GC_old_bus_handler == SIG_IGN) {
-        GC_err_printf0("Previously ignored bus error!?");
-        GC_old_bus_handler = SIG_DFL;
-      }
-      if (GC_old_bus_handler != SIG_DFL) {
-#      ifdef PRINTSTATS
-          GC_err_printf0("Replaced other SIGBUS handler\n");
-#      endif
-      }
-#   endif
-#   if defined(SUNOS4)
-      GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
-      if (GC_old_segv_handler == SIG_IGN) {
-        GC_err_printf0("Previously ignored segmentation violation!?");
-        GC_old_segv_handler = SIG_DFL;
-      }
-      if (GC_old_segv_handler != SIG_DFL) {
-#      ifdef PRINTSTATS
-          GC_err_printf0("Replaced other SIGSEGV handler\n");
-#      endif
-      }
-#   endif
-#   if (defined(SUNOS5SIGS) && !defined(FREEBSD)) || defined(IRIX5) \
-       || defined(LINUX) || defined(OSF1) || defined(HURD)
-      /* SUNOS5SIGS includes HPUX */
+#   if !defined(MSWIN32) && !defined(MSWINCE)
 #     if defined(GC_IRIX_THREADS)
        sigaction(SIGSEGV, 0, &oldact);
        sigaction(SIGSEGV, &act, 0);
@@ -2760,47 +2924,50 @@ void GC_dirty_init()
          if (res != 0) ABORT("Sigaction failed");
        }
 #     endif
-#     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
-       /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */
-       /* sa_sigaction.                                        */
-       GC_old_segv_handler = oldact.sa_handler;
-#     else /* Irix 6.x or SUNOS5SIGS or LINUX */
-        if (oldact.sa_flags & SA_SIGINFO) {
-          GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
-        } else {
-          GC_old_segv_handler = oldact.sa_handler;
-        }
-#     endif
-      if (GC_old_segv_handler == SIG_IGN) {
-            GC_err_printf0("Previously ignored segmentation violation!?");
-            GC_old_segv_handler = SIG_DFL;
+      if (oldact.sa_flags & SA_SIGINFO) {
+        GC_old_segv_handler = oldact.sa_sigaction;
+       GC_old_segv_handler_used_si = TRUE;
+      } else {
+        GC_old_segv_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
+       GC_old_segv_handler_used_si = FALSE;
       }
-      if (GC_old_segv_handler != SIG_DFL) {
-#       ifdef PRINTSTATS
-         GC_err_printf0("Replaced other SIGSEGV handler\n");
-#       endif
+      if (GC_old_segv_handler == (SIG_HNDLR_PTR)SIG_IGN) {
+       GC_err_printf("Previously ignored segmentation violation!?");
+       GC_old_segv_handler = (SIG_HNDLR_PTR)SIG_DFL;
       }
-#   endif /* (SUNOS5SIGS && !FREEBSD) || IRIX5 || LINUX || OSF1 || HURD */
+      if (GC_old_segv_handler != (SIG_HNDLR_PTR)SIG_DFL) {
+       if (GC_print_stats == VERBOSE)
+         GC_log_printf("Replaced other SIGSEGV handler\n");
+      }
+#   endif /* ! MS windows */
 #   if defined(HPUX) || defined(LINUX) || defined(HURD) \
       || (defined(FREEBSD) && defined(SUNOS5SIGS))
       sigaction(SIGBUS, &act, &oldact);
-      GC_old_bus_handler = oldact.sa_handler;
-      if (GC_old_bus_handler == SIG_IGN) {
-            GC_err_printf0("Previously ignored bus error!?");
-            GC_old_bus_handler = SIG_DFL;
+      if (oldact.sa_flags & SA_SIGINFO) {
+        GC_old_bus_handler = oldact.sa_sigaction;
+       GC_old_bus_handler_used_si = TRUE;
+      } else {
+        GC_old_bus_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
+       GC_old_bus_handler_used_si = FALSE;
       }
-      if (GC_old_bus_handler != SIG_DFL) {
-#       ifdef PRINTSTATS
-         GC_err_printf0("Replaced other SIGBUS handler\n");
-#       endif
+      if (GC_old_bus_handler == (SIG_HNDLR_PTR)SIG_IGN) {
+            GC_err_printf("Previously ignored bus error!?");
+            GC_old_bus_handler = (SIG_HNDLR_PTR)SIG_DFL;
+      }
+      if (GC_old_bus_handler != (SIG_HNDLR_PTR)SIG_DFL) {
+       if (GC_print_stats == VERBOSE)
+         GC_log_printf("Replaced other SIGBUS handler\n");
       }
 #   endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */
 #   if defined(MSWIN32)
+#     if defined(GWW_VDB)
+        if (GC_gww_dirty_init())
+          return;
+#     endif
       GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
       if (GC_old_segv_handler != NULL) {
-#      ifdef PRINTSTATS
-          GC_err_printf0("Replaced other UnhandledExceptionFilter\n");
-#      endif
+       if (GC_print_stats)
+          GC_log_printf("Replaced other UnhandledExceptionFilter\n");
       } else {
           GC_old_segv_handler = SIG_DFL;
       }
@@ -2808,7 +2975,7 @@ void GC_dirty_init()
 }
 #endif /* !DARWIN */
 
-int GC_incremental_protection_needs()
+int GC_incremental_protection_needs(void)
 {
     if (GC_page_size == HBLKSIZE) {
        return GC_PROTECTS_POINTER_HEAP;
@@ -2822,10 +2989,10 @@ int GC_incremental_protection_needs()
 #define IS_PTRFREE(hhdr) ((hhdr)->hb_descr == 0)
 
 #define PAGE_ALIGNED(x) !((word)(x) & (GC_page_size - 1))
-void GC_protect_heap()
+void GC_protect_heap(void)
 {
     ptr_t start;
-    word len;
+    size_t len;
     struct hblk * current;
     struct hblk * current_start;  /* Start of block to be protected. */
     struct hblk * limit;
@@ -2884,19 +3051,30 @@ void GC_protect_heap()
 
 /* We assume that either the world is stopped or its OK to lose dirty  */
 /* bits while this is happenning (as in GC_enable_incremental).                */
-void GC_read_dirty()
+void GC_read_dirty(void)
 {
+#   if defined(GWW_VDB)
+      if (GC_GWW_AVAILABLE()) {
+        GC_gww_read_dirty();
+        return;
+      }
+#   endif
     BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
           (sizeof GC_dirty_pages));
     BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
     GC_protect_heap();
 }
 
-GC_bool GC_page_was_dirty(h)
-struct hblk * h;
+GC_bool GC_page_was_dirty(struct hblk *h)
 {
-    register word index = PHT_HASH(h);
+    register word index;
     
+#   if defined(GWW_VDB)
+      if (GC_GWW_AVAILABLE())
+        return GC_gww_page_was_dirty(h);
+#   endif
+
+    index = PHT_HASH(h);
     return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
 }
 
@@ -2910,15 +3088,18 @@ struct hblk * h;
 
 static GC_bool syscall_acquired_lock = FALSE;  /* Protected by GC lock. */
  
-void GC_begin_syscall()
+#if 0
+void GC_begin_syscall(void)
 {
+    /* FIXME: Resurrecting this code would require fixing the  */
+    /* test, which can spuriously return TRUE.                 */
     if (!I_HOLD_LOCK()) {
        LOCK();
        syscall_acquired_lock = TRUE;
     }
 }
 
-void GC_end_syscall()
+void GC_end_syscall(void)
 {
     if (syscall_acquired_lock) {
        syscall_acquired_lock = FALSE;
@@ -2926,9 +3107,7 @@ void GC_end_syscall()
     }
 }
 
-void GC_unprotect_range(addr, len)
-ptr_t addr;
-word len;
+void GC_unprotect_range(ptr_t addr, word len)
 {
     struct hblk * start_block;
     struct hblk * end_block;
@@ -2953,7 +3132,6 @@ word len;
              ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
 }
 
-#if 0
 
 /* We no longer wrap read by default, since that was causing too many  */
 /* problems.  It is preferred that the client instead avoids writing   */
@@ -2970,20 +3148,9 @@ word len;
 /* make sure that input is available.                                    */
 /* Another, preferred alternative is to ensure that system calls never           */
 /* write to the protected heap (see above).                              */
-# 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
-      int read(fd, buf, nbyte)
-#   else
-      int GC_read(fd, buf, nbyte)
-#   endif
-    int fd;
-    char *buf;
-    int nbyte;
-# endif
+# include <unistd.h>
+# include <sys/uio.h>
+ssize_t read(int fd, void *buf, size_t nbyte)
 {
     int result;
     
@@ -3042,20 +3209,15 @@ word len;
 #endif /* 0 */
 
 /*ARGSUSED*/
-GC_bool GC_page_was_ever_dirty(h)
-struct hblk *h;
+GC_bool GC_page_was_ever_dirty(struct hblk *h)
 {
+#   if defined(GWW_VDB)
+      if (GC_GWW_AVAILABLE())
+        return GC_gww_page_was_ever_dirty(h);
+#   endif
     return(TRUE);
 }
 
-/* Reset the n pages starting at h to "was never dirty" status.        */
-/*ARGSUSED*/
-void GC_is_fresh(h, n)
-struct hblk *h;
-word n;
-{
-}
-
 # endif /* MPROTECT_VDB */
 
 # ifdef PROC_VDB
@@ -3083,49 +3245,23 @@ word n;
 word GC_proc_buf_size = INITIAL_BUF_SZ;
 char *GC_proc_buf;
 
-#ifdef GC_SOLARIS_THREADS
-/* We don't have exact sp values for threads.  So we count on  */
-/* occasionally declaring stack pages to be fresh.  Thus we    */
-/* need a real implementation of GC_is_fresh.  We can't clear  */
-/* entries in GC_written_pages, since that would declare all   */
-/* pages with the given hash address to be fresh.              */
-#   define MAX_FRESH_PAGES 8*1024      /* Must be power of 2 */
-    struct hblk ** GC_fresh_pages;     /* A direct mapped cache.       */
-                                       /* Collisions are dropped.      */
-
-#   define FRESH_PAGE_SLOT(h) (divHBLKSZ((word)(h)) & (MAX_FRESH_PAGES-1))
-#   define ADD_FRESH_PAGE(h) \
-       GC_fresh_pages[FRESH_PAGE_SLOT(h)] = (h)
-#   define PAGE_IS_FRESH(h) \
-       (GC_fresh_pages[FRESH_PAGE_SLOT(h)] == (h) && (h) != 0)
-#endif
-
-/* Add all pages in pht2 to pht1 */
-void GC_or_pages(pht1, pht2)
-page_hash_table pht1, pht2;
-{
-    register int i;
-    
-    for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
-}
-
 int GC_proc_fd;
 
-void GC_dirty_init()
+void GC_dirty_init(void)
 {
     int fd;
     char buf[30];
 
     GC_dirty_maintained = TRUE;
-    if (GC_words_allocd != 0 || GC_words_allocd_before_gc != 0) {
+    if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) {
        register int i;
     
         for (i = 0; i < PHT_SIZE; i++) GC_written_pages[i] = (word)(-1);
-#       ifdef PRINTSTATS
-           GC_printf1("Allocated words:%lu:all pages may have been written\n",
-                      (unsigned long)
-                               (GC_words_allocd + GC_words_allocd_before_gc));
-#      endif       
+       if (GC_print_stats == VERBOSE)
+           GC_log_printf(
+                     "Allocated bytes:%lu:all pages may have been written\n",
+                     (unsigned long)
+                               (GC_bytes_allocd + GC_bytes_allocd_before_gc));
     }
     sprintf(buf, "/proc/%d", getpid());
     fd = open(buf, O_RDONLY);
@@ -3139,15 +3275,6 @@ void GC_dirty_init()
        ABORT("/proc ioctl failed");
     }
     GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
-#   ifdef GC_SOLARIS_THREADS
-       GC_fresh_pages = (struct hblk **)
-         GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));
-       if (GC_fresh_pages == 0) {
-           GC_err_printf0("No space for fresh pages\n");
-           EXIT();
-       }
-       BZERO(GC_fresh_pages, MAX_FRESH_PAGES * sizeof (struct hblk *));
-#   endif
 }
 
 /* Ignore write hints. They don't help us here.        */
@@ -3159,13 +3286,9 @@ GC_bool is_ptrfree;
 {
 }
 
-#ifdef GC_SOLARIS_THREADS
-#   define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)
-#else
-#   define READ(fd,buf,nbytes) read(fd, buf, nbytes)
-#endif
+# define READ(fd,buf,nbytes) read(fd, buf, nbytes)
 
-void GC_read_dirty()
+void GC_read_dirty(void)
 {
     unsigned long ps, np;
     int nmaps;
@@ -3174,16 +3297,14 @@ void GC_read_dirty()
     char * bufp;
     ptr_t current_addr, limit;
     int i;
-int dummy;
 
     BZERO(GC_grungy_pages, (sizeof GC_grungy_pages));
     
     bufp = GC_proc_buf;
     if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
-#      ifdef PRINTSTATS
-            GC_printf1("/proc read failed: GC_proc_buf_size = %lu\n",
-                      GC_proc_buf_size);
-#      endif       
+       if (GC_print_stats)
+            GC_log_printf("/proc read failed: GC_proc_buf_size = %lu\n",
+                         (unsigned long)GC_proc_buf_size);
         {
             /* Retry with larger buffer. */
             word new_size = 2 * GC_proc_buf_size;
@@ -3198,10 +3319,6 @@ int dummy;
                 /* Punt:       */
                memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
                memset(GC_written_pages, 0xff, sizeof(page_hash_table));
-#              ifdef GC_SOLARIS_THREADS
-                   BZERO(GC_fresh_pages,
-                         MAX_FRESH_PAGES * sizeof (struct hblk *)); 
-#              endif
                return;
             }
         }
@@ -3228,15 +3345,6 @@ int dummy;
                        register word index = PHT_HASH(h);
                        
                        set_pht_entry_from_index(GC_grungy_pages, index);
-#                      ifdef GC_SOLARIS_THREADS
-                         {
-                           register int slot = FRESH_PAGE_SLOT(h);
-                           
-                           if (GC_fresh_pages[slot] == h) {
-                               GC_fresh_pages[slot] = 0;
-                           }
-                         }
-#                      endif
                        h++;
                    }
                }
@@ -3246,65 +3354,28 @@ int dummy;
        }
     /* Update GC_written_pages. */
         GC_or_pages(GC_written_pages, GC_grungy_pages);
-#   ifdef GC_SOLARIS_THREADS
-      /* Make sure that old stacks are considered completely clean     */
-      /* unless written again.                                         */
-       GC_old_stacks_are_fresh();
-#   endif
 }
 
 #undef READ
 
-GC_bool GC_page_was_dirty(h)
-struct hblk *h;
+GC_bool GC_page_was_dirty(struct hblk *h)
 {
     register word index = PHT_HASH(h);
     register GC_bool result;
     
     result = get_pht_entry_from_index(GC_grungy_pages, index);
-#   ifdef GC_SOLARIS_THREADS
-       if (result && PAGE_IS_FRESH(h)) result = FALSE;
-       /* This happens only if page was declared fresh since   */
-       /* the read_dirty call, e.g. because it's in an unused  */
-       /* thread stack.  It's OK to treat it as clean, in      */
-       /* that case.  And it's consistent with                 */
-       /* GC_page_was_ever_dirty.                              */
-#   endif
     return(result);
 }
 
-GC_bool GC_page_was_ever_dirty(h)
-struct hblk *h;
+GC_bool GC_page_was_ever_dirty(struct hblk *h)
 {
     register word index = PHT_HASH(h);
     register GC_bool result;
     
     result = get_pht_entry_from_index(GC_written_pages, index);
-#   ifdef GC_SOLARIS_THREADS
-       if (result && PAGE_IS_FRESH(h)) result = FALSE;
-#   endif
     return(result);
 }
 
-/* Caller holds allocation lock.       */
-void GC_is_fresh(h, n)
-struct hblk *h;
-word n;
-{
-
-    register word index;
-    
-#   ifdef GC_SOLARIS_THREADS
-      register word i;
-      
-      if (GC_fresh_pages != 0) {
-        for (i = 0; i < n; i++) {
-          ADD_FRESH_PAGE(h + i);
-        }
-      }
-#   endif
-}
-
 # endif /* PROC_VDB */
 
 
@@ -3319,7 +3390,7 @@ PCR_VD_DB  GC_grungy_bits[NPAGES];
 ptr_t GC_vd_base;      /* Address corresponding to GC_grungy_bits[0]   */
                        /* HBLKSIZE aligned.                            */
 
-void GC_dirty_init()
+void GC_dirty_init(void)
 {
     GC_dirty_maintained = TRUE;
     /* For the time being, we assume the heap generally grows up */
@@ -3333,7 +3404,7 @@ void GC_dirty_init()
     }
 }
 
-void GC_read_dirty()
+void GC_read_dirty(void)
 {
     /* lazily enable dirty bits on newly added heap sects */
     {
@@ -3353,8 +3424,7 @@ void GC_read_dirty()
     }
 }
 
-GC_bool GC_page_was_dirty(h)
-struct hblk *h;
+GC_bool GC_page_was_dirty(struct hblk *h)
 {
     if((ptr_t)h < GC_vd_base || (ptr_t)h >= GC_vd_base + NPAGES*HBLKSIZE) {
        return(TRUE);
@@ -3363,10 +3433,7 @@ struct hblk *h;
 }
 
 /*ARGSUSED*/
-void GC_remove_protection(h, nblocks, is_ptrfree)
-struct hblk *h;
-word nblocks;
-GC_bool is_ptrfree;
+void GC_remove_protection(struct hblk *h, word nblocks, GC_bool is_ptrfree)
 {
     PCR_VD_WriteProtectDisable(h, nblocks*HBLKSIZE);
     PCR_VD_WriteProtectEnable(h, nblocks*HBLKSIZE);
@@ -3379,15 +3446,16 @@ GC_bool is_ptrfree;
    code:
       1. Apple's mach/xnu documentation
       2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
-         omnigroup's macosx-dev list. 
-         www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
+         omnigroup's macosx-dev list.
+         www.omnigroup.com/mailman/archive/macosx-dev/2000-June/014178.html
       3. macosx-nat.c from Apple's GDB source code.
 */
-   
+
 /* The bug that caused all this trouble should now be fixed. This should
    eventually be removed if all goes well. */
-/* define BROKEN_EXCEPTION_HANDLING */
-    
+
+/* #define BROKEN_EXCEPTION_HANDLING */
+
 #include <mach/mach.h>
 #include <mach/mach_error.h>
 #include <mach/thread_status.h>
@@ -3395,21 +3463,29 @@ GC_bool is_ptrfree;
 #include <mach/task.h>
 #include <pthread.h>
 
+extern void GC_darwin_register_mach_handler_thread(mach_port_t);
+
 /* These are not defined in any header, although they are documented */
-extern boolean_t exc_server(mach_msg_header_t *,mach_msg_header_t *);
-extern kern_return_t exception_raise(
-    mach_port_t,mach_port_t,mach_port_t,
-    exception_type_t,exception_data_t,mach_msg_type_number_t);
-extern kern_return_t exception_raise_state(
-    mach_port_t,mach_port_t,mach_port_t,
-    exception_type_t,exception_data_t,mach_msg_type_number_t,
-    thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
-    thread_state_t,mach_msg_type_number_t*);
-extern kern_return_t exception_raise_state_identity(
-    mach_port_t,mach_port_t,mach_port_t,
-    exception_type_t,exception_data_t,mach_msg_type_number_t,
-    thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
-    thread_state_t,mach_msg_type_number_t*);
+extern boolean_t
+exc_server(mach_msg_header_t *, mach_msg_header_t *);
+
+extern kern_return_t
+exception_raise(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
+               exception_data_t, mach_msg_type_number_t);
+
+extern kern_return_t
+exception_raise_state(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
+                     exception_data_t, mach_msg_type_number_t,
+                     thread_state_flavor_t*, thread_state_t,
+                     mach_msg_type_number_t, thread_state_t,
+                     mach_msg_type_number_t*);
+
+extern kern_return_t
+exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
+                              exception_type_t, exception_data_t,
+                              mach_msg_type_number_t, thread_state_flavor_t*,
+                              thread_state_t, mach_msg_type_number_t,
+                              thread_state_t, mach_msg_type_number_t*);
 
 
 #define MAX_EXCEPTION_PORTS 16
@@ -3451,63 +3527,57 @@ typedef enum {
 GC_mprotect_state_t GC_mprotect_state;
 
 /* The following should ONLY be called when the world is stopped  */
-static void GC_mprotect_thread_notify(mach_msg_id_t id) {
-    struct {
-        GC_msg_t msg;
-        mach_msg_trailer_t trailer;
-    } buf;
-    mach_msg_return_t r;
-    /* remote, local */
-    buf.msg.head.msgh_bits = 
-        MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
-    buf.msg.head.msgh_size = sizeof(buf.msg);
-    buf.msg.head.msgh_remote_port = GC_ports.exception;
-    buf.msg.head.msgh_local_port = MACH_PORT_NULL;
-    buf.msg.head.msgh_id = id;
-            
-    r = mach_msg(
-        &buf.msg.head,
-        MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_LARGE,
-        sizeof(buf.msg),
-        sizeof(buf),
-        GC_ports.reply,
-        MACH_MSG_TIMEOUT_NONE,
-        MACH_PORT_NULL);
-    if(r != MACH_MSG_SUCCESS)
-       ABORT("mach_msg failed in GC_mprotect_thread_notify");
-    if(buf.msg.head.msgh_id != ID_ACK)
-        ABORT("invalid ack in GC_mprotect_thread_notify");
+static void GC_mprotect_thread_notify(mach_msg_id_t id)
+{
+
+  struct {
+    GC_msg_t msg;
+    mach_msg_trailer_t trailer;
+  } buf;
+
+  mach_msg_return_t r;
+  /* remote, local */
+  buf.msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
+  buf.msg.head.msgh_size = sizeof(buf.msg);
+  buf.msg.head.msgh_remote_port = GC_ports.exception;
+  buf.msg.head.msgh_local_port = MACH_PORT_NULL;
+  buf.msg.head.msgh_id = id;
+
+  r = mach_msg(&buf.msg.head, MACH_SEND_MSG | MACH_RCV_MSG | MACH_RCV_LARGE,
+              sizeof(buf.msg), sizeof(buf), GC_ports.reply,
+              MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  if(r != MACH_MSG_SUCCESS)
+    ABORT("mach_msg failed in GC_mprotect_thread_notify");
+  if(buf.msg.head.msgh_id != ID_ACK)
+    ABORT("invalid ack in GC_mprotect_thread_notify");
 }
 
 /* Should only be called by the mprotect thread */
-static void GC_mprotect_thread_reply() {
-    GC_msg_t msg;
-    mach_msg_return_t r;
-    /* remote, local */
-    msg.head.msgh_bits = 
-        MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
-    msg.head.msgh_size = sizeof(msg);
-    msg.head.msgh_remote_port = GC_ports.reply;
-    msg.head.msgh_local_port = MACH_PORT_NULL;
-    msg.head.msgh_id = ID_ACK;
-            
-    r = mach_msg(
-        &msg.head,
-        MACH_SEND_MSG,
-        sizeof(msg),
-        0,
-        MACH_PORT_NULL,
-        MACH_MSG_TIMEOUT_NONE,
-        MACH_PORT_NULL);
-    if(r != MACH_MSG_SUCCESS)
-       ABORT("mach_msg failed in GC_mprotect_thread_reply");
+static void GC_mprotect_thread_reply(void)
+{
+
+  GC_msg_t msg;
+  mach_msg_return_t r;
+  /* remote, local */
+  msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
+  msg.head.msgh_size = sizeof(msg);
+  msg.head.msgh_remote_port = GC_ports.reply;
+  msg.head.msgh_local_port = MACH_PORT_NULL;
+  msg.head.msgh_id = ID_ACK;
+
+  r = mach_msg(&msg.head, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
+              MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  if(r != MACH_MSG_SUCCESS)
+    ABORT("mach_msg failed in GC_mprotect_thread_reply");
 }
 
-void GC_mprotect_stop() {
-    GC_mprotect_thread_notify(ID_STOP);
+void GC_mprotect_stop(void)
+{
+  GC_mprotect_thread_notify(ID_STOP);
 }
-void GC_mprotect_resume() {
-    GC_mprotect_thread_notify(ID_RESUME);
+void GC_mprotect_resume(void)
+{
+  GC_mprotect_thread_notify(ID_RESUME);
 }
 
 #else /* !THREADS */
@@ -3515,98 +3585,89 @@ void GC_mprotect_resume() {
 #define GC_mprotect_state GC_MP_NORMAL
 #endif
 
-static void *GC_mprotect_thread(void *arg) {
-    mach_msg_return_t r;
-    /* These two structures contain some private kernel data. We don't need to
-       access any of it so we don't bother defining a proper struct. The
-       correct definitions are in the xnu source code. */
-    struct {
-        mach_msg_header_t head;
-        char data[256];
-    } reply;
-    struct {
-        mach_msg_header_t head;
-        mach_msg_body_t msgh_body;
-        char data[1024];
-    } msg;
-
-    mach_msg_id_t id;
-
-    GC_darwin_register_mach_handler_thread(mach_thread_self());
-    
-    for(;;) {
-        r = mach_msg(
-            &msg.head,
-            MACH_RCV_MSG|MACH_RCV_LARGE|
-                (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
-            0,
-            sizeof(msg),
-            GC_ports.exception,
-            GC_mprotect_state == GC_MP_DISCARDING ? 0 : MACH_MSG_TIMEOUT_NONE,
-            MACH_PORT_NULL);
-        
-        id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
-        
-#if defined(THREADS)
-        if(GC_mprotect_state == GC_MP_DISCARDING) {
-            if(r == MACH_RCV_TIMED_OUT) {
-                GC_mprotect_state = GC_MP_STOPPED;
-                GC_mprotect_thread_reply();
-                continue;
-            }
-            if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
-                ABORT("out of order mprotect thread request");
-        }
-#endif
-        
-        if(r != MACH_MSG_SUCCESS) {
-            GC_err_printf2("mach_msg failed with %d %s\n", 
-                (int)r,mach_error_string(r));
-            ABORT("mach_msg failed");
-        }
-        
-        switch(id) {
-#if defined(THREADS)
-            case ID_STOP:
-                if(GC_mprotect_state != GC_MP_NORMAL)
-                    ABORT("Called mprotect_stop when state wasn't normal");
-                GC_mprotect_state = GC_MP_DISCARDING;
-                break;
-            case ID_RESUME:
-                if(GC_mprotect_state != GC_MP_STOPPED)
-                    ABORT("Called mprotect_resume when state wasn't stopped");
-                GC_mprotect_state = GC_MP_NORMAL;
-                GC_mprotect_thread_reply();
-                break;
-#endif /* THREADS */
-            default:
-                   /* Handle the message (calls catch_exception_raise) */
-               if(!exc_server(&msg.head,&reply.head))
-                    ABORT("exc_server failed");
-                /* Send the reply */
-                r = mach_msg(
-                    &reply.head,
-                    MACH_SEND_MSG,
-                    reply.head.msgh_size,
-                    0,
-                    MACH_PORT_NULL,
-                    MACH_MSG_TIMEOUT_NONE,
-                    MACH_PORT_NULL);
-               if(r != MACH_MSG_SUCCESS) {
-                       /* This will fail if the thread dies, but the thread shouldn't
-                          die... */
-                       #ifdef BROKEN_EXCEPTION_HANDLING
-                       GC_err_printf2(
-                        "mach_msg failed with %d %s while sending exc reply\n",
-                        (int)r,mach_error_string(r));
-               #else
-                       ABORT("mach_msg failed while sending exception reply");
-               #endif
-               }
-        } /* switch */
-    } /* for(;;) */
+static void *GC_mprotect_thread(void *arg)
+{
+  mach_msg_return_t r;
+  /* These two structures contain some private kernel data. We don't need to
+     access any of it so we don't bother defining a proper struct. The
+     correct definitions are in the xnu source code. */
+  struct {
+    mach_msg_header_t head;
+    char data[256];
+  } reply;
+  struct {
+    mach_msg_header_t head;
+    mach_msg_body_t msgh_body;
+    char data[1024];
+  } msg;
+
+  mach_msg_id_t id;
+
+  GC_darwin_register_mach_handler_thread(mach_thread_self());
+
+  for(;;) {
+    r = mach_msg(&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE |
+                (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
+                0, sizeof(msg), GC_ports.exception,
+                GC_mprotect_state == GC_MP_DISCARDING ? 0
+                : MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+    id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
+
+#   if defined(THREADS)
+      if(GC_mprotect_state == GC_MP_DISCARDING) {
+       if(r == MACH_RCV_TIMED_OUT) {
+         GC_mprotect_state = GC_MP_STOPPED;
+         GC_mprotect_thread_reply();
+         continue;
+       }
+       if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
+         ABORT("out of order mprotect thread request");
+      }
+#   endif /* THREADS */
+
+    if(r != MACH_MSG_SUCCESS) {
+      GC_err_printf("mach_msg failed with %d %s\n", (int)r,
+                   mach_error_string(r));
+      ABORT("mach_msg failed");
+    }
+
+    switch(id) {
+#     if defined(THREADS)
+        case ID_STOP:
+         if(GC_mprotect_state != GC_MP_NORMAL)
+           ABORT("Called mprotect_stop when state wasn't normal");
+         GC_mprotect_state = GC_MP_DISCARDING;
+         break;
+        case ID_RESUME:
+         if(GC_mprotect_state != GC_MP_STOPPED)
+           ABORT("Called mprotect_resume when state wasn't stopped");
+         GC_mprotect_state = GC_MP_NORMAL;
+         GC_mprotect_thread_reply();
+         break;
+#     endif /* THREADS */
+        default:
+         /* Handle the message (calls catch_exception_raise) */
+         if(!exc_server(&msg.head, &reply.head))
+           ABORT("exc_server failed");
+         /* Send the reply */
+         r = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0,
+                      MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+                      MACH_PORT_NULL);
+         if(r != MACH_MSG_SUCCESS) {
+           /* This will fail if the thread dies, but the thread */
+           /* shouldn't die... */
+#           ifdef BROKEN_EXCEPTION_HANDLING
+             GC_err_printf("mach_msg failed with %d %s while sending"
+                           "exc reply\n", (int)r,mach_error_string(r));
+#           else
+             ABORT("mach_msg failed while sending exception reply");
+#           endif
+         }
+    } /* switch */
+  } /* for(;;) */
     /* NOT REACHED */
-    return NULL;
+  return NULL;
 }
 
 /* All this SIGBUS code shouldn't be necessary. All protection faults should
@@ -3615,322 +3676,322 @@ static void *GC_mprotect_thread(void *arg) {
    meaningless and safe to ignore. */
 #ifdef BROKEN_EXCEPTION_HANDLING
 
-typedef void (* SIG_PF)();
-static SIG_PF GC_old_bus_handler;
+static SIG_HNDLR_PTR GC_old_bus_handler;
 
 /* Updates to this aren't atomic, but the SIGBUSs seem pretty rare.
    Even if this doesn't get updated property, it isn't really a problem */
 static int GC_sigbus_count;
 
-static void GC_darwin_sigbus(int num,siginfo_t *sip,void *context) {
-    if(num != SIGBUS) ABORT("Got a non-sigbus signal in the sigbus handler");
-    
-    /* Ugh... some seem safe to ignore, but too many in a row probably means
-       trouble. GC_sigbus_count is reset for each mach exception that is
-       handled */
-    if(GC_sigbus_count >= 8) {
-        ABORT("Got more than 8 SIGBUSs in a row!");
-    } else {
-        GC_sigbus_count++;
-        GC_err_printf0("GC: WARNING: Ignoring SIGBUS.\n");
-    }
+static void GC_darwin_sigbus(int num, siginfo_t *sip, void *context)
+{
+  if(num != SIGBUS)
+    ABORT("Got a non-sigbus signal in the sigbus handler");
+
+  /* Ugh... some seem safe to ignore, but too many in a row probably means
+     trouble. GC_sigbus_count is reset for each mach exception that is
+     handled */
+  if(GC_sigbus_count >= 8) {
+    ABORT("Got more than 8 SIGBUSs in a row!");
+  } else {
+    GC_sigbus_count++;
+    WARN("Ignoring SIGBUS.\n", 0);
+  }
 }
 #endif /* BROKEN_EXCEPTION_HANDLING */
 
-void GC_dirty_init() {
-    kern_return_t r;
-    mach_port_t me;
-    pthread_t thread;
-    pthread_attr_t attr;
-    exception_mask_t mask;
-    
-#   ifdef PRINTSTATS
-        GC_printf0("Inititalizing mach/darwin mprotect virtual dirty bit "
-            "implementation\n");
-#   endif  
-#      ifdef BROKEN_EXCEPTION_HANDLING
-        GC_err_printf0("GC: WARNING: Enabling workarounds for various darwin "
-            "exception handling bugs.\n");
-#      endif
-    GC_dirty_maintained = TRUE;
-    if (GC_page_size % HBLKSIZE != 0) {
-        GC_err_printf0("Page size not multiple of HBLKSIZE\n");
-        ABORT("Page size not multiple of HBLKSIZE");
-    }
-    
-    GC_task_self = me = mach_task_self();
-    
-    r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.exception);
-    if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (exception port)");
-    
-    r = mach_port_insert_right(me,GC_ports.exception,GC_ports.exception,
-       MACH_MSG_TYPE_MAKE_SEND);
-    if(r != KERN_SUCCESS)
-       ABORT("mach_port_insert_right failed (exception port)");
-
-    #if defined(THREADS)
-        r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.reply);
-        if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (reply port)");
-    #endif
-
-    /* The exceptions we want to catch */  
-    mask = EXC_MASK_BAD_ACCESS;
-
-    r = task_get_exception_ports(
-        me,
-        mask,
-        GC_old_exc_ports.masks,
-        &GC_old_exc_ports.count,
-        GC_old_exc_ports.ports,
-        GC_old_exc_ports.behaviors,
-        GC_old_exc_ports.flavors
-    );
-    if(r != KERN_SUCCESS) ABORT("task_get_exception_ports failed");
-        
-    r = task_set_exception_ports(
-        me,
-        mask,
-        GC_ports.exception,
-        EXCEPTION_DEFAULT,
-        MACHINE_THREAD_STATE
-    );
-    if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed");
-
-    if(pthread_attr_init(&attr) != 0) ABORT("pthread_attr_init failed");
-    if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0) 
-        ABORT("pthread_attr_setdetachedstate failed");
-
-#      undef pthread_create
-    /* This will call the real pthread function, not our wrapper */
-    if(pthread_create(&thread,&attr,GC_mprotect_thread,NULL) != 0)
-        ABORT("pthread_create failed");
-    pthread_attr_destroy(&attr);
-    
-    /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
-    #ifdef BROKEN_EXCEPTION_HANDLING 
+void GC_dirty_init(void)
+{
+  kern_return_t r;
+  mach_port_t me;
+  pthread_t thread;
+  pthread_attr_t attr;
+  exception_mask_t mask;
+
+  if (GC_print_stats == VERBOSE)
+    GC_log_printf("Inititalizing mach/darwin mprotect virtual dirty bit "
+                 "implementation\n");
+# ifdef BROKEN_EXCEPTION_HANDLING
+    WARN("Enabling workarounds for various darwin "
+        "exception handling bugs.\n", 0);
+# endif
+  GC_dirty_maintained = TRUE;
+  if (GC_page_size % HBLKSIZE != 0) {
+    GC_err_printf("Page size not multiple of HBLKSIZE\n");
+    ABORT("Page size not multiple of HBLKSIZE");
+  }
+
+  GC_task_self = me = mach_task_self();
+
+  r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.exception);
+  if(r != KERN_SUCCESS)
+    ABORT("mach_port_allocate failed (exception port)");
+
+  r = mach_port_insert_right(me, GC_ports.exception, GC_ports.exception,
+                            MACH_MSG_TYPE_MAKE_SEND);
+  if(r != KERN_SUCCESS)
+    ABORT("mach_port_insert_right failed (exception port)");
+
+#  if defined(THREADS)
+     r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.reply);
+     if(r != KERN_SUCCESS)
+       ABORT("mach_port_allocate failed (reply port)");
+#  endif
+
+  /* The exceptions we want to catch */
+  mask = EXC_MASK_BAD_ACCESS;
+
+  r = task_get_exception_ports(me, mask, GC_old_exc_ports.masks,
+                              &GC_old_exc_ports.count, GC_old_exc_ports.ports,
+                              GC_old_exc_ports.behaviors,
+                              GC_old_exc_ports.flavors);
+  if(r != KERN_SUCCESS)
+    ABORT("task_get_exception_ports failed");
+
+  r = task_set_exception_ports(me, mask, GC_ports.exception, EXCEPTION_DEFAULT,
+                              GC_MACH_THREAD_STATE);
+  if(r != KERN_SUCCESS)
+    ABORT("task_set_exception_ports failed");
+  if(pthread_attr_init(&attr) != 0)
+    ABORT("pthread_attr_init failed");
+  if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
+    ABORT("pthread_attr_setdetachedstate failed");
+
+# undef pthread_create
+  /* This will call the real pthread function, not our wrapper */
+  if(pthread_create(&thread, &attr, GC_mprotect_thread, NULL) != 0)
+    ABORT("pthread_create failed");
+  pthread_attr_destroy(&attr);
+
+  /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
+# ifdef BROKEN_EXCEPTION_HANDLING
     {
-        struct sigaction sa, oldsa;
-        sa.sa_handler = (SIG_PF)GC_darwin_sigbus;
-        sigemptyset(&sa.sa_mask);
-        sa.sa_flags = SA_RESTART|SA_SIGINFO;
-        if(sigaction(SIGBUS,&sa,&oldsa) < 0) ABORT("sigaction");
-        GC_old_bus_handler = (SIG_PF)oldsa.sa_handler;
-        if (GC_old_bus_handler != SIG_DFL) {
-#              ifdef PRINTSTATS
-                GC_err_printf0("Replaced other SIGBUS handler\n");
-#              endif
-        }
+      struct sigaction sa, oldsa;
+      sa.sa_handler = (SIG_HNDLR_PTR)GC_darwin_sigbus;
+      sigemptyset(&sa.sa_mask);
+      sa.sa_flags = SA_RESTART|SA_SIGINFO;
+      if(sigaction(SIGBUS, &sa, &oldsa) < 0)
+       ABORT("sigaction");
+      GC_old_bus_handler = (SIG_HNDLR_PTR)oldsa.sa_handler;
+      if (GC_old_bus_handler != SIG_DFL) {
+       if (GC_print_stats == VERBOSE)
+         GC_err_printf("Replaced other SIGBUS handler\n");
+      }
     }
-    #endif /* BROKEN_EXCEPTION_HANDLING  */
+#  endif /* BROKEN_EXCEPTION_HANDLING  */
 }
+
 /* The source code for Apple's GDB was used as a reference for the exception
-   forwarding code. This code is similar to be GDB code only because there is 
+   forwarding code. This code is similar to be GDB code only because there is
    only one way to do it. */
-static kern_return_t GC_forward_exception(
-        mach_port_t thread,
-        mach_port_t task,
-        exception_type_t exception,
-        exception_data_t data,
-        mach_msg_type_number_t data_count
-) {
-    int i;
-    kern_return_t r;
-    mach_port_t port;
-    exception_behavior_t behavior;
-    thread_state_flavor_t flavor;
-    
-    thread_state_t thread_state;
-    mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
-        
-    for(i=0;i<GC_old_exc_ports.count;i++)
-        if(GC_old_exc_ports.masks[i] & (1 << exception))
-            break;
-    if(i==GC_old_exc_ports.count) ABORT("No handler for exception!");
-    
-    port = GC_old_exc_ports.ports[i];
-    behavior = GC_old_exc_ports.behaviors[i];
-    flavor = GC_old_exc_ports.flavors[i];
-
-    if(behavior != EXCEPTION_DEFAULT) {
-        r = thread_get_state(thread,flavor,thread_state,&thread_state_count);
-        if(r != KERN_SUCCESS)
-            ABORT("thread_get_state failed in forward_exception");
-    }
-    
-    switch(behavior) {
-        case EXCEPTION_DEFAULT:
-            r = exception_raise(port,thread,task,exception,data,data_count);
-            break;
-        case EXCEPTION_STATE:
-            r = exception_raise_state(port,thread,task,exception,data,
-                data_count,&flavor,thread_state,thread_state_count,
-                thread_state,&thread_state_count);
-            break;
-        case EXCEPTION_STATE_IDENTITY:
-            r = exception_raise_state_identity(port,thread,task,exception,data,
-                data_count,&flavor,thread_state,thread_state_count,
-                thread_state,&thread_state_count);
-            break;
-        default:
-            r = KERN_FAILURE; /* make gcc happy */
-            ABORT("forward_exception: unknown behavior");
-            break;
-    }
-    
-    if(behavior != EXCEPTION_DEFAULT) {
-        r = thread_set_state(thread,flavor,thread_state,thread_state_count);
-        if(r != KERN_SUCCESS)
-            ABORT("thread_set_state failed in forward_exception");
+static kern_return_t GC_forward_exception(mach_port_t thread, mach_port_t task,
+                                         exception_type_t exception,
+                                         exception_data_t data,
+                                         mach_msg_type_number_t data_count)
+{
+  unsigned int i;
+  kern_return_t r;
+  mach_port_t port;
+  exception_behavior_t behavior;
+  thread_state_flavor_t flavor;
+
+  thread_state_t thread_state = NULL;
+  mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
+
+  for(i=0; i < GC_old_exc_ports.count; i++)
+    if(GC_old_exc_ports.masks[i] & (1 << exception))
+      break;
+  if(i==GC_old_exc_ports.count)
+    ABORT("No handler for exception!");
+
+  port = GC_old_exc_ports.ports[i];
+  behavior = GC_old_exc_ports.behaviors[i];
+  flavor = GC_old_exc_ports.flavors[i];
+
+  if(behavior != EXCEPTION_DEFAULT) {
+    r = thread_get_state(thread, flavor, thread_state, &thread_state_count);
+    if(r != KERN_SUCCESS)
+      ABORT("thread_get_state failed in forward_exception");
     }
-    
-    return r;
+
+  switch(behavior) {
+    case EXCEPTION_DEFAULT:
+      r = exception_raise(port, thread, task, exception, data, data_count);
+      break;
+    case EXCEPTION_STATE:
+      r = exception_raise_state(port, thread, task, exception, data, data_count,
+                               &flavor, thread_state, thread_state_count,
+                               thread_state, &thread_state_count);
+      break;
+    case EXCEPTION_STATE_IDENTITY:
+      r = exception_raise_state_identity(port, thread, task, exception, data,
+                                        data_count, &flavor, thread_state,
+                                        thread_state_count, thread_state,
+                                        &thread_state_count);
+      break;
+    default:
+      r = KERN_FAILURE; /* make gcc happy */
+      ABORT("forward_exception: unknown behavior");
+      break;
+  }
+
+  if(behavior != EXCEPTION_DEFAULT) {
+    r = thread_set_state(thread, flavor, thread_state, thread_state_count);
+    if(r != KERN_SUCCESS)
+      ABORT("thread_set_state failed in forward_exception");
+  }
+
+  return r;
 }
 
-#define FWD() GC_forward_exception(thread,task,exception,code,code_count)
+#define FWD() GC_forward_exception(thread, task, exception, code, code_count)
 
 /* This violates the namespace rules but there isn't anything that can be done
    about it. The exception handling stuff is hard coded to call this */
 kern_return_t
-catch_exception_raise(
-   mach_port_t exception_port,mach_port_t thread,mach_port_t task,
-   exception_type_t exception,exception_data_t code,
-   mach_msg_type_number_t code_count
-) {
-    kern_return_t r;
-    char *addr;
-    struct hblk *h;
-    int i;
-#   if defined(POWERPC)
-#     if CPP_WORDSZ == 32
-        thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
-        mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
-        ppc_exception_state_t exc_state;
-#     else
-        thread_state_flavor_t flavor = PPC_EXCEPTION_STATE64;
-        mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE64_COUNT;
-        ppc_exception_state64_t exc_state;
-#     endif
-#   elif defined(I386)
-        thread_state_flavor_t flavor = i386_EXCEPTION_STATE;
-        mach_msg_type_number_t exc_state_count = i386_EXCEPTION_STATE_COUNT;
-        i386_exception_state_t exc_state;
+catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
+                     mach_port_t task, exception_type_t exception,
+                     exception_data_t code, mach_msg_type_number_t code_count)
+{
+  kern_return_t r;
+  char *addr;
+  struct hblk *h;
+  unsigned int i;
+# if defined(POWERPC)
+#   if CPP_WORDSZ == 32
+      thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
+      mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
+      ppc_exception_state_t exc_state;
+#   else
+      thread_state_flavor_t flavor = PPC_EXCEPTION_STATE64;
+      mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE64_COUNT;
+      ppc_exception_state64_t exc_state;
+#   endif
+# elif defined(I386) || defined(X86_64)
+#   if CPP_WORDSZ == 32
+      thread_state_flavor_t flavor = x86_EXCEPTION_STATE32;
+      mach_msg_type_number_t exc_state_count = x86_EXCEPTION_STATE32_COUNT;
+      x86_exception_state32_t exc_state;
 #   else
-#      error FIXME for non-ppc/x86 darwin
+      thread_state_flavor_t flavor = x86_EXCEPTION_STATE64;
+      mach_msg_type_number_t exc_state_count = x86_EXCEPTION_STATE64_COUNT;
+      x86_exception_state64_t exc_state;
 #   endif
+# else
+#   error FIXME for non-ppc/x86 darwin
+# endif
 
-    
-    if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
-        #ifdef DEBUG_EXCEPTION_HANDLING
-        /* We aren't interested, pass it on to the old handler */
-        GC_printf3("Exception: 0x%x Code: 0x%x 0x%x in catch....\n",
-            exception,
-            code_count > 0 ? code[0] : -1,
-            code_count > 1 ? code[1] : -1); 
-        #endif
-        return FWD();
-    }
 
-    r = thread_get_state(thread,flavor,
-        (natural_t*)&exc_state,&exc_state_count);
-    if(r != KERN_SUCCESS) {
-        /* The thread is supposed to be suspended while the exception handler
-           is called. This shouldn't fail. */
-        #ifdef BROKEN_EXCEPTION_HANDLING
-            GC_err_printf0("thread_get_state failed in "
-                "catch_exception_raise\n");
-            return KERN_SUCCESS;
-        #else
-            ABORT("thread_get_state failed in catch_exception_raise");
-        #endif
-    }
-    
+  if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
+#   ifdef DEBUG_EXCEPTION_HANDLING
+      /* We aren't interested, pass it on to the old handler */
+      GC_printf("Exception: 0x%x Code: 0x%x 0x%x in catch....\n", exception,
+               code_count > 0 ? code[0] : -1, code_count > 1 ? code[1] : -1);
+#   endif
+    return FWD();
+  }
+
+  r = thread_get_state(thread, flavor, (natural_t*)&exc_state,
+                      &exc_state_count);
+  if(r != KERN_SUCCESS) {
+    /* The thread is supposed to be suspended while the exception handler
+       is called. This shouldn't fail. */
+#   ifdef BROKEN_EXCEPTION_HANDLING
+      GC_err_printf("thread_get_state failed in catch_exception_raise\n");
+      return KERN_SUCCESS;
+#   else
+      ABORT("thread_get_state failed in catch_exception_raise");
+#   endif
+  }
+
     /* This is the address that caused the fault */
-#if defined(POWERPC)
-    addr = (char*) exc_state.dar;
-#elif defined (I386)
-    addr = (char*) exc_state.faultvaddr;
-#else
+# if defined(POWERPC)
+    addr = (char*) exc_state. THREAD_FLD(dar);
+# elif defined (I386) || defined (X86_64)
+    addr = (char*) exc_state. THREAD_FLD(faultvaddr);
+# else
 #   error FIXME for non POWERPC/I386
-#endif
-        
+# endif
+
     if((HDR(addr)) == 0) {
-        /* Ugh... just like the SIGBUS problem above, it seems we get a bogus 
-           KERN_PROTECTION_FAILURE every once and a while. We wait till we get
-           a bunch in a row before doing anything about it. If a "real" fault 
-           ever occurres it'll just keep faulting over and over and we'll hit
-           the limit pretty quickly. */
-        #ifdef BROKEN_EXCEPTION_HANDLING
-            static char *last_fault;
-            static int last_fault_count;
-            
-            if(addr != last_fault) {
-                last_fault = addr;
-                last_fault_count = 0;
-            }
-            if(++last_fault_count < 32) {
-                if(last_fault_count == 1)
-                    GC_err_printf1(
-                        "GC: WARNING: Ignoring KERN_PROTECTION_FAILURE at %p\n",
-                        addr);
-                return KERN_SUCCESS;
-            }
-            
-            GC_err_printf1("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
-            /* Can't pass it along to the signal handler because that is
-               ignoring SIGBUS signals. We also shouldn't call ABORT here as
-               signals don't always work too well from the exception handler. */
-            GC_err_printf0("Aborting\n");
-            exit(EXIT_FAILURE);
-        #else /* BROKEN_EXCEPTION_HANDLING */
-            /* Pass it along to the next exception handler 
-               (which should call SIGBUS/SIGSEGV) */
-            return FWD();
-        #endif /* !BROKEN_EXCEPTION_HANDLING */
+      /* Ugh... just like the SIGBUS problem above, it seems we get a bogus
+        KERN_PROTECTION_FAILURE every once and a while. We wait till we get
+        a bunch in a row before doing anything about it. If a "real" fault
+        ever occurres it'll just keep faulting over and over and we'll hit
+        the limit pretty quickly. */
+#     ifdef BROKEN_EXCEPTION_HANDLING
+        static char *last_fault;
+       static int last_fault_count;
+
+       if(addr != last_fault) {
+         last_fault = addr;
+         last_fault_count = 0;
+       }
+       if(++last_fault_count < 32) {
+         if(last_fault_count == 1)
+           WARN("Ignoring KERN_PROTECTION_FAILURE at %lx\n", (GC_word)addr);
+         return KERN_SUCCESS;
+       }
+
+       GC_err_printf("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
+       /* Can't pass it along to the signal handler because that is
+          ignoring SIGBUS signals. We also shouldn't call ABORT here as
+          signals don't always work too well from the exception handler. */
+       GC_err_printf("Aborting\n");
+       exit(EXIT_FAILURE);
+#     else /* BROKEN_EXCEPTION_HANDLING */
+       /* Pass it along to the next exception handler
+          (which should call SIGBUS/SIGSEGV) */
+       return FWD();
+#     endif /* !BROKEN_EXCEPTION_HANDLING */
     }
 
-    #ifdef BROKEN_EXCEPTION_HANDLING
-        /* Reset the number of consecutive SIGBUSs */
-        GC_sigbus_count = 0;
-    #endif
-    
+#   ifdef BROKEN_EXCEPTION_HANDLING
+      /* Reset the number of consecutive SIGBUSs */
+      GC_sigbus_count = 0;
+#   endif
+
     if(GC_mprotect_state == GC_MP_NORMAL) { /* common case */
-        h = (struct hblk*)((word)addr & ~(GC_page_size-1));
-        UNPROTECT(h, GC_page_size);    
-        for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
-            register int index = PHT_HASH(h+i);
-            async_set_pht_entry_from_index(GC_dirty_pages, index);
-        }
+      h = (struct hblk*)((word)addr & ~(GC_page_size-1));
+      UNPROTECT(h, GC_page_size);
+      for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
+       register int index = PHT_HASH(h+i);
+       async_set_pht_entry_from_index(GC_dirty_pages, index);
+      }
     } else if(GC_mprotect_state == GC_MP_DISCARDING) {
-        /* Lie to the thread for now. No sense UNPROTECT()ing the memory
-           when we're just going to PROTECT() it again later. The thread
-           will just fault again once it resumes */
+      /* Lie to the thread for now. No sense UNPROTECT()ing the memory
+        when we're just going to PROTECT() it again later. The thread
+        will just fault again once it resumes */
     } else {
-        /* Shouldn't happen, i don't think */
-        GC_printf0("KERN_PROTECTION_FAILURE while world is stopped\n");
-        return FWD();
+      /* Shouldn't happen, i don't think */
+      GC_printf("KERN_PROTECTION_FAILURE while world is stopped\n");
+      return FWD();
     }
     return KERN_SUCCESS;
 }
 #undef FWD
 
 /* These should never be called, but just in case...  */
-kern_return_t catch_exception_raise_state(mach_port_name_t exception_port,
-    int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
-    int flavor, thread_state_t old_state, int old_stateCnt,
-    thread_state_t new_state, int new_stateCnt)
+kern_return_t
+catch_exception_raise_state(mach_port_name_t exception_port, int exception,
+                           exception_data_t code,
+                           mach_msg_type_number_t codeCnt, int flavor,
+                           thread_state_t old_state, int old_stateCnt,
+                           thread_state_t new_state, int new_stateCnt)
 {
-    ABORT("catch_exception_raise_state");
-    return(KERN_INVALID_ARGUMENT);
+  ABORT("catch_exception_raise_state");
+  return(KERN_INVALID_ARGUMENT);
 }
-kern_return_t catch_exception_raise_state_identity(
-    mach_port_name_t exception_port, mach_port_t thread, mach_port_t task,
-    int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
-    int flavor, thread_state_t old_state, int old_stateCnt, 
-    thread_state_t new_state, int new_stateCnt)
+
+kern_return_t
+catch_exception_raise_state_identity(mach_port_name_t exception_port,
+                                    mach_port_t thread, mach_port_t task,
+                                    int exception, exception_data_t code,
+                                    mach_msg_type_number_t codeCnt, int flavor,
+                                    thread_state_t old_state, int old_stateCnt,
+                                    thread_state_t new_state, int new_stateCnt)
 {
-    ABORT("catch_exception_raise_state_identity");
-    return(KERN_INVALID_ARGUMENT);
+  ABORT("catch_exception_raise_state_identity");
+  return(KERN_INVALID_ARGUMENT);
 }
 
 
@@ -3976,27 +4037,17 @@ kern_return_t catch_exception_raise_state_identity(
        long    fr_argd[6];
        long    fr_argx[0];
      };
+#  elif defined (DRSNX)
+#    include <sys/sparc/frame.h>
+#  elif defined(OPENBSD)
+#    include <frame.h>
+#  elif defined(FREEBSD) || defined(NETBSD)
+#    include <machine/frame.h>
 #  else
-#    if defined(SUNOS4)
-#      include <machine/frame.h>
-#    else
-#      if defined (DRSNX)
-#       include <sys/sparc/frame.h>
-#      else
-#       if defined(OPENBSD)
-#         include <frame.h>
-#       else
-#         if defined(FREEBSD) || defined(NETBSD)
-#           include <machine/frame.h>
-#         else
-#           include <sys/frame.h>
-#         endif
-#       endif
-#      endif
-#    endif
+#    include <sys/frame.h>
 #  endif
 #  if NARGS > 6
-       --> We only know how to to get the first 6 arguments
+#    error We only know how to to get the first 6 arguments
 #  endif
 #endif /* SPARC */
 
@@ -4011,7 +4062,11 @@ kern_return_t catch_exception_raise_state_identity(
 #endif /* NEED_CALLINFO */
 
 #if defined(GC_HAVE_BUILTIN_BACKTRACE)
-# include <execinfo.h>
+# ifdef _MSC_VER
+#  include "private/msvc_dbg.h"
+# else
+#  include <execinfo.h>
+# endif
 #endif
 
 #ifdef SAVE_CALL_CHAIN
@@ -4029,8 +4084,7 @@ kern_return_t catch_exception_raise_state_identity(
   GC_in_save_callers = FALSE;
 #endif
 
-void GC_save_callers (info) 
-struct callinfo info[NFRAMES];
+void GC_save_callers (struct callinfo info[NFRAMES]) 
 {
   void * tmp_info[NFRAMES + 1];
   int npcs, i;
@@ -4071,8 +4125,7 @@ struct callinfo info[NFRAMES];
 #   define BIAS 0
 #endif
 
-void GC_save_callers (info) 
-struct callinfo info[NFRAMES];
+void GC_save_callers (struct callinfo info[NFRAMES]) 
 {
   struct frame *frame;
   struct frame *fp;
@@ -4108,8 +4161,7 @@ struct callinfo info[NFRAMES];
 #ifdef NEED_CALLINFO
 
 /* Print info to stderr.  We do NOT hold the allocation lock */
-void GC_print_callers (info)
-struct callinfo info[NFRAMES];
+void GC_print_callers (struct callinfo info[NFRAMES])
 {
     register int i;
     static int reentry_count = 0;
@@ -4122,9 +4174,9 @@ struct callinfo info[NFRAMES];
     UNLOCK();
     
 #   if NFRAMES == 1
-      GC_err_printf0("\tCaller at allocation:\n");
+      GC_err_printf("\tCaller at allocation:\n");
 #   else
-      GC_err_printf0("\tCall chain at allocation:\n");
+      GC_err_printf("\tCall chain at allocation:\n");
 #   endif
     for (i = 0; i < NFRAMES && !stop ; i++) {
        if (info[i].ci_pc == 0) break;
@@ -4132,19 +4184,19 @@ struct callinfo info[NFRAMES];
        {
          int j;
 
-         GC_err_printf0("\t\targs: ");
+         GC_err_printf("\t\targs: ");
          for (j = 0; j < NARGS; j++) {
-           if (j != 0) GC_err_printf0(", ");
-           GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
+           if (j != 0) GC_err_printf(", ");
+           GC_err_printf("%d (0x%X)", ~(info[i].ci_arg[j]),
                                        ~(info[i].ci_arg[j]));
          }
-         GC_err_printf0("\n");
+         GC_err_printf("\n");
        }
 #      endif
         if (reentry_count > 1) {
            /* We were called during an allocation during       */
            /* a previous GC_print_callers call; punt.          */
-           GC_err_printf1("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
+           GC_err_printf("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
            continue;
        }
        {
@@ -4219,8 +4271,8 @@ struct callinfo info[NFRAMES];
                if (result_buf[result_len - 1] == '\n') --result_len;
                result_buf[result_len] = 0;
                if (result_buf[0] == '?'
-                   || result_buf[result_len-2] == ':' 
-                      && result_buf[result_len-1] == '0') {
+                   || (result_buf[result_len-2] == ':' 
+                       && result_buf[result_len-1] == '0')) {
                    pclose(pipe);
                    goto out;
                }
@@ -4244,7 +4296,7 @@ struct callinfo info[NFRAMES];
                out:;
            }
 #        endif /* LINUX */
-         GC_err_printf1("\t\t%s\n", name);
+         GC_err_printf("\t\t%s\n", name);
 #        if defined(GC_HAVE_BUILTIN_BACKTRACE) \
             && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
            free(sym_name);  /* May call GC_free; that's OK */
@@ -4271,11 +4323,11 @@ static word dump_maps(char *maps)
     return 1;
 }
 
-void GC_print_address_map()
+void GC_print_address_map(void)
 {
-    GC_err_printf0("---------- Begin address map ----------\n");
-    GC_apply_to_maps(dump_maps);
-    GC_err_printf0("---------- End address map ----------\n");
+    GC_err_printf("---------- Begin address map ----------\n");
+    dump_maps(GC_get_maps());
+    GC_err_printf("---------- End address map ----------\n");
 }
 
 #endif
diff --git a/src/mm/boehm-gc/pc_excludes b/src/mm/boehm-gc/pc_excludes
deleted file mode 100644 (file)
index 15c9045..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-solaris_threads.c
-solaris_pthreads.c
-irix_threads.c
-pcr_interface.c
-real_malloc.c
-mips_mach_dep.s
-rs6000_mach_dep.s
-alpha_mach_dep.s
-sparc_mach_dep.s
-PCR-Makefile
-setjmp_t.c
-callprocs
-doc/gc.man
-pc_excludes
-barrett_diagram
-include/gc_c++.h
-include/gc_inline.h
-doc/README.hp
-doc/README.rs6000
-doc/README.sgi
-
index b7d6f913772438a3688a9247703c28e19e14c9cd..519d8c0954e79187185270ef281bf3fa7b7a2984 100644 (file)
@@ -68,26 +68,27 @@ typedef struct {
   PCR_Any ed_client_data;
 } enumerate_data;
 
-void GC_enumerate_block(h, ed)
-register struct hblk *h;
-enumerate_data * ed;
+void GC_enumerate_block(struct hblk *h; enumerate_data * ed)
 {
     register hdr * hhdr;
     register int sz;
-    word *p;
-    word * lim;
+    ptr_t p;
+    ptr_t lim;
+    word descr;
+#   error This code was updated without testing.
+#   error and its precursor was clearly broken.
     
     hhdr = HDR(h);
+    descr = hhdr -> hb_descr;
     sz = hhdr -> hb_sz;
-    if (sz >= 0 && ed -> ed_pointerfree
-       || sz <= 0 && !(ed -> ed_pointerfree)) return;
-    if (sz < 0) sz = -sz;
-    lim = (word *)(h+1) - sz;
-    p = (word *)h;
+    if (descr != 0 && ed -> ed_pointerfree
+       || descr == 0 && !(ed -> ed_pointerfree)) return;
+    lim = (ptr_t)(h+1) - sz;
+    p = (ptr_t)h;
     do {
         if (PCR_ERes_IsErr(ed -> ed_fail_code)) return;
         ed -> ed_fail_code =
-            (*(ed -> ed_proc))(p, WORDS_TO_BYTES(sz), ed -> ed_client_data);
+            (*(ed -> ed_proc))(p, sz, ed -> ed_client_data);
         p+= sz;
     } while (p <= lim);
 }
diff --git a/src/mm/boehm-gc/powerpc_darwin_mach_dep.s b/src/mm/boehm-gc/powerpc_darwin_mach_dep.s
deleted file mode 100644 (file)
index 1121ee8..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#if defined(__ppc64__)
-#define MODE_CHOICE(x, y) y
-#else
-#define MODE_CHOICE(x, y) x
-#endif
-
-#define lgu     MODE_CHOICE(lwzu, ldu)
-
-#define g_long  MODE_CHOICE(long, quad)         /* usage is ".g_long" */
-
-#define LOG2_GPR_BYTES  MODE_CHOICE(2,3)        /* log2(GPR_BYTES) */
-
-; GC_push_regs function. Under some optimization levels GCC will clobber
-; some of the non-volatile registers before we get a chance to save them
-; therefore, this cannot be inline asm.
-
-.text
-       .align LOG2_GPR_BYTES
-       .globl _GC_push_regs
-_GC_push_regs:
-    
-    ; Prolog
-       mflr r0
-       stw r0,8(r1)
-       stwu r1,-80(r1)
-
-       ; Push r13-r31
-       mr r3,r13
-       bl L_GC_push_one$stub
-       mr r3,r14
-       bl L_GC_push_one$stub
-       mr r3,r15
-       bl L_GC_push_one$stub
-       mr r3,r16
-       bl L_GC_push_one$stub
-       mr r3,r17
-       bl L_GC_push_one$stub
-       mr r3,r18
-       bl L_GC_push_one$stub
-       mr r3,r19
-       bl L_GC_push_one$stub
-       mr r3,r20
-       bl L_GC_push_one$stub
-       mr r3,r21
-       bl L_GC_push_one$stub
-       mr r3,r22
-       bl L_GC_push_one$stub
-       mr r3,r23
-       bl L_GC_push_one$stub
-       mr r3,r24
-       bl L_GC_push_one$stub
-       mr r3,r25
-       bl L_GC_push_one$stub
-       mr r3,r26
-       bl L_GC_push_one$stub
-       mr r3,r27
-       bl L_GC_push_one$stub
-       mr r3,r28
-       bl L_GC_push_one$stub
-       mr r3,r29
-       bl L_GC_push_one$stub
-       mr r3,r30
-       bl L_GC_push_one$stub
-       mr r3,r31
-       bl L_GC_push_one$stub
-
-    ; 
-    lwz r0,88(r1)
-    addi r1,r1,80
-       mtlr r0
-       
-       ; Return
-       blr
-
-; PIC stuff, generated by GCC
-
-.data
-.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
-       .align LOG2_GPR_BYTES
-L_GC_push_one$stub:
-       .indirect_symbol _GC_push_one
-       mflr r0
-       bcl 20,31,L0$_GC_push_one
-L0$_GC_push_one:
-       mflr r11
-       addis r11,r11,ha16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)
-       mtlr r0
-       lgu r12,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)(r11)
-       mtctr r12
-       bctr
-.data
-.lazy_symbol_pointer
-L_GC_push_one$lazy_ptr:
-       .indirect_symbol _GC_push_one
-       .g_long dyld_stub_binding_helper
index 7c8e33edf607799566b05cf627639bc55ea2b7cd..ce5d869a2cc2be7dcd86b20ac2dffb8f03f2d3e1 100644 (file)
@@ -2,18 +2,14 @@
 
 #include "private/pthread_support.h"
 
-#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
-     && !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS)
+#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && \
+    !defined(GC_DARWIN_THREADS)
 
 #include <signal.h>
 #include <semaphore.h>
 #include <errno.h>
 #include <unistd.h>
-#include <sys/time.h>
-#ifndef HPUX
-# include <sys/select.h>
-  /* Doesn't exist on HP/UX 11.11. */
-#endif
+#include "atomic_ops.h"
 
 #if DEBUG_THREADS
 
@@ -36,11 +32,11 @@ void GC_print_sig_mask()
 
     if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
        ABORT("pthread_sigmask");
-    GC_printf0("Blocked: ");
+    GC_printf("Blocked: ");
     for (i = 1; i < NSIG; i++) {
-        if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
+        if (sigismember(&blocked, i)) { GC_printf("%d ", i); }
     }
-    GC_printf0("\n");
+    GC_printf("\n");
 }
 
 #endif
@@ -49,14 +45,12 @@ void GC_print_sig_mask()
 /* handler from a set.                                         */
 void GC_remove_allowed_signals(sigset_t *set)
 {
-#   ifdef NO_SIGNALS
-      if (sigdelset(set, SIGINT) != 0
+    if (sigdelset(set, SIGINT) != 0
          || sigdelset(set, SIGQUIT) != 0
          || sigdelset(set, SIGABRT) != 0
          || sigdelset(set, SIGTERM) != 0) {
         ABORT("sigdelset() failed");
-      }
-#   endif
+    }
 
 #   ifdef MPROTECT_VDB
       /* Handlers write to the thread structure, which is in the heap, */
@@ -73,23 +67,15 @@ void GC_remove_allowed_signals(sigset_t *set)
 
 static sigset_t suspend_handler_mask;
 
-volatile sig_atomic_t GC_stop_count;
+volatile AO_t GC_stop_count;
                        /* Incremented at the beginning of GC_stop_world. */
 
-volatile sig_atomic_t GC_world_is_stopped = FALSE;
+volatile AO_t GC_world_is_stopped = FALSE;
                        /* FALSE ==> it is safe for threads to restart, i.e. */
                        /* they will see another suspend signal before they  */
                        /* are expected to stop (unless they have voluntarily */
                        /* stopped).                                         */
 
-void GC_brief_async_signal_safe_sleep()
-{
-    struct timeval tv;
-    tv.tv_sec = 0;
-    tv.tv_usec = 1000 * TIME_LIMIT / 2;
-    select(0, 0, 0, 0, &tv);
-}
-
 #ifdef GC_OSF1_THREADS
   GC_bool GC_retry_signals = TRUE;
 #else
@@ -129,35 +115,32 @@ sem_t GC_suspend_ack_sem;
   sem_t GC_restart_ack_sem;
 #endif
 
-void GC_suspend_handler_inner(ptr_t sig_arg);
+void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
 /* int cacao_suspendhandler(void *); */
 
-#if defined(IA64) || defined(HP_PA)
-extern void GC_with_callee_saves_pushed();
-
-void GC_suspend_handler(int sig)
+#if defined(IA64) || defined(HP_PA) || defined(M68K)
+void GC_suspend_handler(int sig, siginfo_t *info, void *context)
 {
    int old_errno = errno;
    GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
    errno = old_errno;
 }
 #else
-/* We believe that in all other cases the full context is already     */
-/* in the signal handler frame.                                               */
-void GC_suspend_handler(int sig, siginfo_t *info, void *uctx)
+/* We believe that in all other cases the full context is already      */
+/* in the signal handler frame.                                                */
+void GC_suspend_handler(int sig, siginfo_t *info, void *context)
 {
    int old_errno = errno;
 
 /*    if (cacao_suspendhandler(uctx)) */
 /*      return; */
 
-   GC_suspend_handler_inner((ptr_t)(word)sig);
+   GC_suspend_handler_inner((ptr_t)(word)sig, context);
    errno = old_errno;
 }
 #endif
-void GC_suspend_handler_inner(ptr_t sig_arg)
+
+void GC_suspend_handler_inner(ptr_t sig_arg, void *context)
 {
     int sig = (int)(word)sig_arg;
     int dummy;
@@ -169,13 +152,13 @@ void GC_suspend_handler_inner(ptr_t sig_arg)
        /* guaranteed to be the mark_no correspending to our            */
        /* suspension, i.e. the marker can't have incremented it yet.   */
 #   endif
-    word my_stop_count = GC_stop_count;
+    AO_t my_stop_count = AO_load(&GC_stop_count);
 
     if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
 
-#if DEBUG_THREADS
-    GC_printf1("Suspending 0x%lx\n", my_thread);
-#endif
+#   if DEBUG_THREADS
+      GC_printf("Suspending 0x%x\n", (unsigned)my_thread);
+#   endif
 
     me = GC_lookup_thread(my_thread);
     /* The lookup here is safe, since I'm doing this on behalf  */
@@ -191,12 +174,12 @@ void GC_suspend_handler_inner(ptr_t sig_arg)
        return;
     }
 #   ifdef SPARC
-       me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
+       me -> stop_info.stack_ptr = GC_save_regs_in_stack();
 #   else
        me -> stop_info.stack_ptr = (ptr_t)(&dummy);
 #   endif
 #   ifdef IA64
-       me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
+       me -> backing_store_ptr = GC_save_regs_in_stack();
 #   endif
 
     /* Tell the thread that wants to stop the world that this   */
@@ -216,13 +199,10 @@ void GC_suspend_handler_inner(ptr_t sig_arg)
     /* primitive and expensive mechanism to wait until it's    */
     /* really safe to proceed.  Under normal circumstances,    */
     /* this code should not be executed.                       */
-    sigsuspend(&suspend_handler_mask);        /* Wait for signal */
-    while (GC_world_is_stopped && GC_stop_count == my_stop_count) {
-        GC_brief_async_signal_safe_sleep();
-#       if DEBUG_THREADS
-         GC_err_printf0("Sleeping in signal handler");
-#       endif
-    }
+    do {
+       sigsuspend (&suspend_handler_mask);
+    } while (AO_load_acquire(&GC_world_is_stopped)
+            && AO_load(&GC_stop_count) == my_stop_count);
     /* If the RESTART signal gets lost, we can still lose.  That should be  */
     /* less likely than losing the SUSPEND signal, since we don't do much   */
     /* between the sem_post and sigsuspend.                                */
@@ -230,20 +210,21 @@ void GC_suspend_handler_inner(ptr_t sig_arg)
     /* Simply dropping the sigsuspend call should be safe, but is unlikely  */
     /* to be efficient.                                                            */
 
-#if DEBUG_THREADS
-    GC_printf1("Continuing 0x%lx\n", my_thread);
-#endif
+#   if DEBUG_THREADS
+      GC_printf("Continuing 0x%x\n", (unsigned)my_thread);
+#   endif
 }
 
 void GC_restart_handler(int sig)
 {
     pthread_t my_thread = pthread_self();
+    GC_thread me;
 
     if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
 
-#ifdef GC_NETBSD_THREADS_WORKAROUND
-    sem_post(&GC_restart_ack_sem);
-#endif
+#   ifdef GC_NETBSD_THREADS_WORKAROUND
+      sem_post(&GC_restart_ack_sem);
+#   endif
 
     /*
     ** Note: even if we don't do anything useful here,
@@ -253,9 +234,9 @@ void GC_restart_handler(int sig)
     ** will thus not interrupt the sigsuspend() above.
     */
 
-#if DEBUG_THREADS
-    GC_printf1("In GC_restart_handler for 0x%lx\n", pthread_self());
-#endif
+#   if DEBUG_THREADS
+      GC_printf("In GC_restart_handler for 0x%x\n", (unsigned)pthread_self());
+#   endif
 }
 
 # ifdef IA64
@@ -268,6 +249,7 @@ void GC_restart_handler(int sig)
 void GC_push_all_stacks()
 {
     GC_bool found_me = FALSE;
+    size_t nthreads = 0;
     int i;
     GC_thread p;
     ptr_t lo, hi;
@@ -276,13 +258,14 @@ void GC_push_all_stacks()
     pthread_t me = pthread_self();
     
     if (!GC_thr_initialized) GC_thr_init();
-    #if DEBUG_THREADS
-        GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
-    #endif
+#   if DEBUG_THREADS
+        GC_printf("Pushing stacks from thread 0x%x\n", (unsigned) me);
+#   endif
     for (i = 0; i < THREAD_TABLE_SZ; i++) {
       for (p = GC_threads[i]; p != 0; p = p -> next) {
         if (p -> flags & FINISHED) continue;
-        if (pthread_equal(p -> id, me)) {
+       ++nthreads;
+        if (THREAD_EQUAL(p -> id, me)) {
 #          ifdef SPARC
                lo = (ptr_t)GC_save_regs_in_stack();
 #          else
@@ -302,11 +285,10 @@ void GC_push_all_stacks()
             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 DEBUG_THREADS
+            GC_printf("Stack for thread 0x%x = [%p,%p)\n",
+                     (unsigned)(p -> id), lo, hi);
+#      endif
        if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
 #       ifdef STACK_GROWS_UP
          /* We got them backwards! */
@@ -316,11 +298,10 @@ void GC_push_all_stacks()
 #      endif
 #      ifdef IA64
 #         if DEBUG_THREADS
-            GC_printf3("Reg stack for thread 0x%lx = [%lx,%lx)\n",
-               (unsigned long) p -> id,
-               (unsigned long) bs_lo, (unsigned long) bs_hi);
+            GC_printf("Reg stack for thread 0x%x = [%lx,%lx)\n",
+                     (unsigned)p -> id, bs_lo, bs_hi);
 #        endif
-          if (pthread_equal(p -> id, me)) {
+          if (THREAD_EQUAL(p -> id, me)) {
            /* FIXME:  This may add an unbounded number of entries,     */
            /* and hence overflow the mark stack, which is bad.         */
            GC_push_all_eager(bs_lo, bs_hi);
@@ -330,6 +311,9 @@ void GC_push_all_stacks()
 #      endif
       }
     }
+    if (GC_print_stats == VERBOSE) {
+       GC_log_printf("Pushed %d thread stacks\n", nthreads);
+    }
     if (!found_me && !GC_in_thread_creation)
       ABORT("Collecting from unknown thread.");
 }
@@ -354,16 +338,17 @@ int GC_suspend_all()
     GC_stopping_pid = getpid();                /* debugging only.      */
     for (i = 0; i < THREAD_TABLE_SZ; i++) {
       for (p = GC_threads[i]; p != 0; p = p -> next) {
-        if (p -> id != my_thread) {
+        if (!THREAD_EQUAL(p -> id, my_thread)) {
             if (p -> flags & FINISHED) continue;
             if (p -> stop_info.last_stop_count == GC_stop_count) continue;
            if (p -> thread_blocked) /* Will wait */ continue;
             n_live_threads++;
-           #if DEBUG_THREADS
-             GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
-           #endif
+#          if DEBUG_THREADS
+             GC_printf("Sending suspend signal to 0x%x\n",
+                       (unsigned)(p -> id));
+#          endif
         
-        result = pthread_kill(p -> id, SIG_SUSPEND);
+            result = pthread_kill(p -> id, SIG_SUSPEND);
            switch(result) {
                 case ESRCH:
                     /* Not really there anymore.  Possible? */
@@ -383,16 +368,16 @@ int GC_suspend_all()
 void lock_stopworld(int);
 void unlock_stopworld();
 
-/* Caller holds allocation lock.       */
 void GC_stop_world()
 {
     int i;
     int n_live_threads;
     int code;
 
-    #if DEBUG_THREADS
-    GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
-    #endif
+    GC_ASSERT(I_HOLD_LOCK());
+#   if DEBUG_THREADS
+      GC_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());
+#   endif
 
     lock_stopworld(1);
        
@@ -405,8 +390,9 @@ void GC_stop_world()
       GC_ASSERT(GC_fl_builder_count == 0);
       /* We should have previously waited for it to become zero. */
 #   endif /* PARALLEL_MARK */
-    ++GC_stop_count;
-    GC_world_is_stopped = TRUE;
+    AO_store(&GC_stop_count, GC_stop_count+1);
+       /* Only concurrent reads are possible. */
+    AO_store_release(&GC_world_is_stopped, TRUE);
     n_live_threads = GC_suspend_all();
 
       if (GC_retry_signals) {
@@ -421,12 +407,10 @@ void GC_stop_world()
              if (wait_usecs > RETRY_INTERVAL) {
                  int newly_sent = GC_suspend_all();
 
-#                 ifdef CONDPRINT
-                   if (GC_print_stats) {
-                     GC_printf1("Resent %ld signals after timeout\n",
-                                newly_sent);
-                   }
-#                 endif
+                 if (GC_print_stats) {
+                     GC_log_printf("Resent %d signals after timeout\n",
+                               newly_sent);
+                 }
                  sem_getvalue(&GC_suspend_ack_sem, &ack_count);
                  if (newly_sent < n_live_threads - ack_count) {
                      WARN("Lost some threads during GC_stop_world?!\n",0);
@@ -439,18 +423,22 @@ void GC_stop_world()
          }
       }
     for (i = 0; i < n_live_threads; i++) {
-         while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
-             if (errno != EINTR) {
-                GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
-                ABORT("sem_wait for handler failed");
+       retry:
+         if (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
+             /* On Linux, sem_wait is documented to always return zero.*/
+             /* But the documentation appears to be incorrect.         */
+             if (errno == EINTR) {
+               /* Seems to happen with some versions of gdb.   */
+               goto retry;
              }
+             ABORT("sem_wait for handler failed");
          }
     }
 #   ifdef PARALLEL_MARK
       GC_release_mark_lock();
 #   endif
     #if DEBUG_THREADS
-      GC_printf1("World stopped from 0x%lx\n", pthread_self());
+      GC_printf("World stopped from 0x%x\n", (unsigned)pthread_self());
     #endif
     GC_stopping_thread = 0;  /* debugging only */
 }
@@ -464,24 +452,26 @@ void GC_start_world()
     register GC_thread p;
     register int n_live_threads = 0;
     register int result;
-#ifdef GC_NETBSD_THREADS_WORKAROUND
-    int code;
-#endif
+#   ifdef GC_NETBSD_THREADS_WORKAROUND
+      int code;
+#   endif
 
 #   if DEBUG_THREADS
-      GC_printf0("World starting\n");
+      GC_printf("World starting\n");
 #   endif
 
-    GC_world_is_stopped = FALSE;
+    AO_store(&GC_world_is_stopped, FALSE);
     for (i = 0; i < THREAD_TABLE_SZ; i++) {
       for (p = GC_threads[i]; p != 0; p = p -> next) {
-        if (p -> id != my_thread) {
+        if (!THREAD_EQUAL(p -> id, my_thread)) {
             if (p -> flags & FINISHED) continue;
            if (p -> thread_blocked) continue;
             n_live_threads++;
            #if DEBUG_THREADS
-             GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
+             GC_printf("Sending restart signal to 0x%x\n",
+                       (unsigned)(p -> id));
            #endif
+        
             result = pthread_kill(p -> id, SIG_THR_RESTART);
            switch(result) {
                 case ESRCH:
@@ -496,20 +486,21 @@ void GC_start_world()
         }
       }
     }
-#ifdef GC_NETBSD_THREADS_WORKAROUND
-    for (i = 0; i < n_live_threads; i++)
+#   ifdef GC_NETBSD_THREADS_WORKAROUND
+      for (i = 0; i < n_live_threads; i++)
        while (0 != (code = sem_wait(&GC_restart_ack_sem)))
            if (errno != EINTR) {
-               GC_err_printf1("sem_wait() returned %ld\n", (unsigned long)code);
+               GC_err_printf1("sem_wait() returned %ld\n",
+                              (unsigned long)code);
                ABORT("sem_wait() for restart handler failed");
            }
-#endif
+#    endif
 
        unlock_stopworld();
 
-    #if DEBUG_THREADS
-      GC_printf0("World started\n");
-    #endif
+#    if DEBUG_THREADS
+      GC_printf("World started\n");
+#    endif
 }
 
 void GC_stop_init() {
@@ -517,10 +508,10 @@ void GC_stop_init() {
     
     if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
         ABORT("sem_init failed");
-#ifdef GC_NETBSD_THREADS_WORKAROUND
-    if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
+#   ifdef GC_NETBSD_THREADS_WORKAROUND
+      if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
        ABORT("sem_init failed");
-#endif
+#   endif
 
     act.sa_flags = SA_RESTART | SA_SIGINFO;
     if (sigfillset(&act.sa_mask) != 0) {
@@ -529,11 +520,12 @@ void GC_stop_init() {
     GC_remove_allowed_signals(&act.sa_mask);
     /* SIG_THR_RESTART is set in the resulting mask.           */
     /* It is unmasked by the handler when necessary.           */
-    act.sa_handler = GC_suspend_handler;
+    act.sa_sigaction = GC_suspend_handler;
     if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
        ABORT("Cannot set SIG_SUSPEND handler");
     }
 
+    act.sa_flags &= ~ SA_SIGINFO;
     act.sa_handler = GC_restart_handler;
     if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
        ABORT("Cannot set SIG_THR_RESTART handler");
@@ -552,11 +544,9 @@ void GC_stop_init() {
       if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
          GC_retry_signals = FALSE;
       }
-#     ifdef CONDPRINT
-          if (GC_print_stats && GC_retry_signals) {
-              GC_printf0("Will retry suspend signal if necessary.\n");
-         }
-#     endif
+      if (GC_print_stats && GC_retry_signals) {
+          GC_log_printf("Will retry suspend signal if necessary.\n");
+      }
 }
 
 /* Added for cacao */
index 512006899e2ce92a48e7dabd4d94e1de3a85e3a3..098a3c1880fc185209cb5883f6767bd447b68cf0 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
  * Copyright (c) 1998 by Fergus Henderson.  All rights reserved.
- * Copyright (c) 2000-2004 by Hewlett-Packard Company.  All rights reserved.
+ * Copyright (c) 2000-2005 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.
  * modified is included with the above copyright notice.
  */
 /*
- * Support code for LinuxThreads, the clone()-based kernel
+ * Support code originally for LinuxThreads, the clone()-based kernel
  * thread package for Linux which is included in libc6.
  *
- * This code relies on implementation details of LinuxThreads,
- * (i.e. properties not guaranteed by the Pthread standard),
- * though this version now does less of that than the other Pthreads
- * support code.
- *
- * Note that there is a lot of code duplication between linux_threads.c
- * and thread support for some of the other Posix platforms; any changes
- * made here may need to be reflected there too.
+ * This code no doubt makes some assumptions beyond what is
+ * guaranteed by the pthread standard, though it now does
+ * very little of that.  It now also supports NPTL, and many
+ * other Posix thread implementations.  We are trying to merge
+ * all flavors of pthread dupport code into this file.
  */
  /* DG/UX ix86 support <takis@xfree86.org> */
 /*
 #include "config.h"
 
 /*#define DEBUG_THREADS 1*/
-/*#define GC_ASSERTIONS*/
 
 # include "private/pthread_support.h"
 
-# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
-     && !defined(GC_WIN32_THREADS)
-
-# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
-     && !defined(USE_COMPILER_TLS)
-#   ifdef __GNUC__
-#     define USE_PTHREAD_SPECIFIC
-      /* Empirically, as of gcc 3.3, USE_COMPILER_TLS doesn't work.    */
-#   else
-#     define USE_COMPILER_TLS
-#   endif
-# endif
-
-# if defined USE_HPUX_TLS
-    --> Macro replaced by USE_COMPILER_TLS
-# endif
-
-# if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
-      defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS) || \
-      defined(GC_NETBSD_THREADS))                             \
-      && !defined(USE_PTHREAD_SPECIFIC)
-#   define USE_PTHREAD_SPECIFIC
-# endif
+# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
 
 # if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
 #   define _POSIX4A_DRAFT10_SOURCE 1
 #   define _USING_POSIX4A_DRAFT10 1
 # endif
 
-# ifdef THREAD_LOCAL_ALLOC
-#   if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_COMPILER_TLS)
-#     include "private/specific.h"
-#   endif
-#   if defined(USE_PTHREAD_SPECIFIC)
-#     define GC_getspecific pthread_getspecific
-#     define GC_setspecific pthread_setspecific
-#     define GC_key_create pthread_key_create
-      typedef pthread_key_t GC_key_t;
-#   endif
-#   if defined(USE_COMPILER_TLS)
-#     define GC_getspecific(x) (x)
-#     define GC_setspecific(key, v) ((key) = (v), 0)
-#     define GC_key_create(key, d) 0
-      typedef void * GC_key_t;
-#   endif
-# endif
 # include <stdlib.h>
 # include <pthread.h>
 # include <sched.h>
 # include <fcntl.h>
 # include <signal.h>
 
+# include "gc_inline.h"
+
 #if defined(GC_DARWIN_THREADS)
 # include "private/darwin_semaphore.h"
 #else
 #if defined(GC_NETBSD_THREADS)
 # include <sys/param.h>
 # include <sys/sysctl.h>
-#endif /* GC_NETBSD_THREADS */
+#endif        /* GC_NETBSD_THREADS */
+
+/* Allocator lock definitions.         */
+#if !defined(USE_SPIN_LOCK)
+  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
+#endif
+unsigned long GC_lock_holder = NO_THREAD;
+               /* Used only for assertions, and to prevent      */
+               /* recursive reentry in the system call wrapper. */
 
 #if defined(GC_DGUX386_THREADS)
 # include <sys/dg_sys_info.h>
 #   define __inline__
 #endif
 
+/* Undefine macros used to redirect pthread primitives. */
+# undef pthread_create
+# if !defined(GC_DARWIN_THREADS)
+#   undef pthread_sigmask
+# endif
+# undef pthread_join
+# undef pthread_detach
+# if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
+     && !defined(_PTHREAD_USE_PTDNAM_)
+  /* Restore the original mangled names on Tru64 UNIX.  */
+#   define pthread_create __pthread_create
+#   define pthread_join __pthread_join
+#   define pthread_detach __pthread_detach
+# endif
+
 #ifdef GC_USE_LD_WRAP
 #   define WRAP_FUNC(f) __wrap_##f
 #   define REAL_FUNC(f) __real_##f
 #else
-#   define WRAP_FUNC(f) GC_##f
-#   if !defined(GC_DGUX386_THREADS)
-#     define REAL_FUNC(f) f
-#   else /* GC_DGUX386_THREADS */
-#     define REAL_FUNC(f) __d10_##f
-#   endif /* GC_DGUX386_THREADS */
-#   undef pthread_create
-#   if !defined(GC_DARWIN_THREADS)
-#     undef pthread_sigmask
-#   endif
-#   undef pthread_join
-#   undef pthread_detach
-#   if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
-       && !defined(_PTHREAD_USE_PTDNAM_)
-/* Restore the original mangled names on Tru64 UNIX.  */
-#     define pthread_create __pthread_create
-#     define pthread_join __pthread_join
-#     define pthread_detach __pthread_detach
+#   ifdef GC_USE_DLOPEN_WRAP
+#     include <dlfcn.h>
+#     define WRAP_FUNC(f) f
+#     define REAL_FUNC(f) GC_real_##f
+      /* We define both GC_f and plain f to be the wrapped function.   */
+      /* In that way plain calls work, as do calls from files that     */
+      /* included gc.h, wich redefined f to GC_f.                      */
+      /* FIXME: Needs work for DARWIN and True64 (OSF1) */
+      typedef int (* GC_pthread_create_t)(pthread_t *, const pthread_attr_t *,
+                                         void * (*)(void *), void *);
+      static GC_pthread_create_t GC_real_pthread_create;
+      typedef int (* GC_pthread_sigmask_t)(int, const sigset_t *, sigset_t *);
+      static GC_pthread_sigmask_t GC_real_pthread_sigmask;
+      typedef int (* GC_pthread_join_t)(pthread_t, void **);
+      static GC_pthread_join_t GC_real_pthread_join;
+      typedef int (* GC_pthread_detach_t)(pthread_t);
+      static GC_pthread_detach_t GC_real_pthread_detach;
+#   else
+#     define WRAP_FUNC(f) GC_##f
+#     if !defined(GC_DGUX386_THREADS)
+#       define REAL_FUNC(f) f
+#     else /* GC_DGUX386_THREADS */
+#       define REAL_FUNC(f) __d10_##f
+#     endif /* GC_DGUX386_THREADS */
 #   endif
 #endif
 
-void GC_thr_init();
-
-static GC_bool parallel_initialized = FALSE;
-
-void GC_init_parallel();
+#if defined(GC_USE_DL_WRAP) || defined(GC_USE_DLOPEN_WRAP)
+/* Define GC_ functions as aliases for the plain ones, which will      */
+/* be intercepted.  This allows files which include gc.h, and hence    */
+/* generate referemces to the GC_ symbols, to see the right symbols.   */
+      int GC_pthread_create(pthread_t * t, const pthread_attr_t * a,
+                        void * (* fn)(void *), void * arg) {
+         return pthread_create(t, a, fn, arg);
+      }
+      int GC_pthread_sigmask(int how, const sigset_t *mask, sigset_t *old) {
+         return pthread_sigmask(how, mask, old);
+      }
+      int GC_pthread_join(pthread_t t, void **res) {
+         return pthread_join(t, res);
+      }
+      int GC_pthread_detach(pthread_t t) {
+         return pthread_detach(t);
+      }
+#endif /* Linker-based interception. */
 
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
+#ifdef GC_USE_DLOPEN_WRAP
+  static GC_bool GC_syms_initialized = FALSE;
 
-/* We don't really support thread-local allocation with DBG_HDRS_ALL */
+  void GC_init_real_syms(void)
+  {
+    void *dl_handle;
+#   define LIBPTHREAD_NAME "libpthread.so.0"
+#   define LIBPTHREAD_NAME_LEN 16 /* incl. trailing 0 */
+    size_t len = LIBPTHREAD_NAME_LEN - 1;
+    char namebuf[LIBPTHREAD_NAME_LEN];
+    static char *libpthread_name = LIBPTHREAD_NAME;
+
+    if (GC_syms_initialized) return;
+#   ifdef RTLD_NEXT
+      dl_handle = RTLD_NEXT;
+#   else
+      dl_handle = dlopen(libpthread_name, RTLD_LAZY);
+      if (NULL == dl_handle) {
+        while (isdigit(libpthread_name[len-1])) --len;
+        if (libpthread_name[len-1] == '.') --len;
+        memcpy(namebuf, libpthread_name, len);
+        namebuf[len] = '\0';
+        dl_handle = dlopen(namebuf, RTLD_LAZY);
+      }
+      if (NULL == dl_handle) ABORT("Couldn't open libpthread\n");
+#   endif
+    GC_real_pthread_create = (GC_pthread_create_t)
+                               dlsym(dl_handle, "pthread_create");
+    GC_real_pthread_sigmask = (GC_pthread_sigmask_t)
+                               dlsym(dl_handle, "pthread_sigmask");
+    GC_real_pthread_join = (GC_pthread_join_t)
+                               dlsym(dl_handle, "pthread_join");
+    GC_real_pthread_detach = (GC_pthread_detach_t)
+                               dlsym(dl_handle, "pthread_detach");
+    GC_syms_initialized = TRUE;
+  }
 
-#ifdef USE_COMPILER_TLS
-  __thread
+# define INIT_REAL_SYMS() if (!GC_syms_initialized) GC_init_real_syms();
+#else
+# define INIT_REAL_SYMS()
 #endif
-GC_key_t GC_thread_key;
-
-static GC_bool keys_initialized;
-
-/* Recover the contents of the freelist array fl into the global one gfl.*/
-/* Note that the indexing scheme differs, in that gfl has finer size   */
-/* resolution, even if not all entries are used.                       */
-/* We hold the allocator lock.                                         */
-static void return_freelists(ptr_t *fl, ptr_t *gfl)
-{
-    int i;
-    ptr_t q, *qptr;
-    size_t nwords;
-
-    for (i = 1; i < NFREELISTS; ++i) {
-       nwords = i * (GRANULARITY/sizeof(word));
-        qptr = fl + i; 
-       q = *qptr;
-       if ((word)q >= HBLKSIZE) {
-         if (gfl[nwords] == 0) {
-           gfl[nwords] = q;
-         } else {
-           /* Concatenate: */
-           for (; (word)q >= HBLKSIZE; qptr = &(obj_link(q)), q = *qptr);
-           GC_ASSERT(0 == q);
-           *qptr = gfl[nwords];
-           gfl[nwords] = fl[i];
-         }
-       }
-       /* Clear fl[i], since the thread structure may hang around.     */
-       /* Do it in a way that is likely to trap if we access it.       */
-       fl[i] = (ptr_t)HBLKSIZE;
-    }
-}
 
-/* We statically allocate a single "size 0" object. It is linked to    */
-/* itself, and is thus repeatedly reused for all size 0 allocation     */
-/* requests.  (Size 0 gcj allocation requests are incorrect, and       */
-/* we arrange for those to fault asap.)                                        */
-static ptr_t size_zero_object = (ptr_t)(&size_zero_object);
-
-/* Each thread structure must be initialized.  */
-/* This call must be made from the new thread. */
-/* Caller holds allocation lock.               */
-void GC_init_thread_local(GC_thread p)
-{
-    int i;
-
-    if (!keys_initialized) {
-       if (0 != GC_key_create(&GC_thread_key, 0)) {
-           ABORT("Failed to create key for local allocator");
-        }
-       keys_initialized = TRUE;
-    }
-    if (0 != GC_setspecific(GC_thread_key, p)) {
-       ABORT("Failed to set thread specific allocation pointers");
-    }
-    for (i = 1; i < NFREELISTS; ++i) {
-       p -> ptrfree_freelists[i] = (ptr_t)1;
-       p -> normal_freelists[i] = (ptr_t)1;
-#      ifdef GC_GCJ_SUPPORT
-         p -> gcj_freelists[i] = (ptr_t)1;
-#      endif
-    }   
-    /* Set up the size 0 free lists.   */
-    p -> ptrfree_freelists[0] = (ptr_t)(&size_zero_object);
-    p -> normal_freelists[0] = (ptr_t)(&size_zero_object);
-#   ifdef GC_GCJ_SUPPORT
-        p -> gcj_freelists[0] = (ptr_t)(-1);
-#   endif
-}
+void GC_thr_init(void);
 
-#ifdef GC_GCJ_SUPPORT
-  extern ptr_t * GC_gcjobjfreelist;
-#endif
+static GC_bool parallel_initialized = FALSE;
 
-/* We hold the allocator lock. */
-void GC_destroy_thread_local(GC_thread p)
-{
-    /* We currently only do this from the thread itself or from        */
-    /* the fork handler for a child process.                   */
-#   ifndef HANDLE_FORK
-      GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
-#   endif
-    return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
-    return_freelists(p -> normal_freelists, GC_objfreelist);
-#   ifdef GC_GCJ_SUPPORT
-       return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
-#   endif
-}
+GC_bool GC_need_to_lock = FALSE;
 
-extern GC_PTR GC_generic_malloc_many();
+void GC_init_parallel(void);
 
-GC_PTR GC_local_malloc(size_t bytes)
-{
-    if (EXPECT(!SMALL_ENOUGH(bytes),0)) {
-        return(GC_malloc(bytes));
-    } else {
-       int index = INDEX_FROM_BYTES(bytes);
-       ptr_t * my_fl;
-       ptr_t my_entry;
-#      if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
-       GC_key_t k = GC_thread_key;
-#      endif
-       void * tsd;
-
-#      if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
-           if (EXPECT(0 == k, 0)) {
-               /* This can happen if we get called when the world is   */
-               /* being initialized.  Whether we can actually complete */
-               /* the initialization then is unclear.                  */
-               GC_init_parallel();
-               k = GC_thread_key;
-           }
-#      endif
-       tsd = GC_getspecific(GC_thread_key);
-#      ifdef GC_ASSERTIONS
-         LOCK();
-         GC_ASSERT(tsd == (void *)GC_lookup_thread(pthread_self()));
-         UNLOCK();
-#      endif
-       my_fl = ((GC_thread)tsd) -> normal_freelists + index;
-       my_entry = *my_fl;
-       if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
-           ptr_t next = obj_link(my_entry);
-           GC_PTR result = (GC_PTR)my_entry;
-           *my_fl = next;
-           obj_link(my_entry) = 0;
-           PREFETCH_FOR_WRITE(next);
-           return result;
-       } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
-           *my_fl = my_entry + index + 1;
-            return GC_malloc(bytes);
-       } else {
-           GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl);
-           if (*my_fl == 0) return GC_oom_fn(bytes);
-           return GC_local_malloc(bytes);
-       }
-    }
-}
+long GC_nprocs = 1;    /* Number of processors.  We may not have       */
+                       /* access to all of them, but this is as good   */
+                       /* a guess as any ...                           */
 
-GC_PTR GC_local_malloc_atomic(size_t bytes)
+#ifdef THREAD_LOCAL_ALLOC
+/* We must explicitly mark ptrfree and gcj free lists, since the free  */
+/* list links wouldn't otherwise be found.  We also set them in the    */
+/* normal free lists, since that involves touching less memory than if */
+/* we scanned them normally.                                           */
+void GC_mark_thread_local_free_lists(void)
 {
-    if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
-        return(GC_malloc_atomic(bytes));
-    } else {
-       int index = INDEX_FROM_BYTES(bytes);
-       ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
-                       -> ptrfree_freelists + index;
-       ptr_t my_entry = *my_fl;
+    int i;
+    GC_thread p;
     
-       if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
-           GC_PTR result = (GC_PTR)my_entry;
-           *my_fl = obj_link(my_entry);
-           return result;
-       } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
-           *my_fl = my_entry + index + 1;
-        return GC_malloc_atomic(bytes);
-       } else {
-           GC_generic_malloc_many(BYTES_FROM_INDEX(index), PTRFREE, my_fl);
-           /* *my_fl is updated while the collector is excluded;       */
-           /* the free list is always visible to the collector as      */
-           /* such.                                                    */
-           if (*my_fl == 0) return GC_oom_fn(bytes);
-           return GC_local_malloc_atomic(bytes);
-       }
+    for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+      for (p = GC_threads[i]; 0 != p; p = p -> next) {
+       GC_mark_thread_local_fls_for(&(p->tlfs));
+      }
     }
 }
 
-#ifdef GC_GCJ_SUPPORT
-
-#include "include/gc_gcj.h"
-
-#ifdef GC_ASSERTIONS
-  extern GC_bool GC_gcj_malloc_initialized;
-#endif
-
-extern int GC_gcj_kind;
-
-GC_PTR GC_local_gcj_malloc(size_t bytes,
-                          void * ptr_to_struct_containing_descr)
-{
-    GC_ASSERT(GC_gcj_malloc_initialized);
-    if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
-        return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
-    } else {
-       int index = INDEX_FROM_BYTES(bytes);
-       ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
-                       -> gcj_freelists + index;
-       ptr_t my_entry = *my_fl;
-       if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
-           GC_PTR result = (GC_PTR)my_entry;
-           GC_ASSERT(!GC_incremental);
-           /* We assert that any concurrent marker will stop us.       */
-           /* Thus it is impossible for a mark procedure to see the    */
-           /* allocation of the next object, but to see this object    */
-           /* still containing a free list pointer.  Otherwise the     */
-           /* marker might find a random "mark descriptor".            */
-           *(volatile ptr_t *)my_fl = obj_link(my_entry);
-           /* We must update the freelist before we store the pointer. */
-           /* Otherwise a GC at this point would see a corrupted       */
-           /* free list.                                               */
-           /* A memory barrier is probably never needed, since the     */
-           /* action of stopping this thread will cause prior writes   */
-           /* to complete.                                             */
-           GC_ASSERT(((void * volatile *)result)[1] == 0); 
-           *(void * volatile *)result = ptr_to_struct_containing_descr; 
-           return result;
-       } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
-           if (!GC_incremental) *my_fl = my_entry + index + 1;
-               /* In the incremental case, we always have to take this */
-               /* path.  Thus we leave the counter alone.              */
-            return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
-       } else {
-           GC_generic_malloc_many(BYTES_FROM_INDEX(index), GC_gcj_kind, my_fl);
-           if (*my_fl == 0) return GC_oom_fn(bytes);
-           return GC_local_gcj_malloc(bytes, ptr_to_struct_containing_descr);
+#if defined(GC_ASSERTIONS)
+    /* Check that all thread-local free-lists are completely marked.   */
+    /* also check that thread-specific-data structures are marked.     */
+    void GC_check_tls(void) {
+       int i;
+       GC_thread p;
+       
+       for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+         for (p = GC_threads[i]; 0 != p; p = p -> next) {
+           GC_check_tls_for(&(p->tlfs));
+         }
        }
+#       if defined(USE_CUSTOM_SPECIFIC)
+         if (GC_thread_key != 0)
+           GC_check_tsd_marks(GC_thread_key);
+#      endif 
     }
-}
-
-#endif /* GC_GCJ_SUPPORT */
-
-# else  /* !THREAD_LOCAL_ALLOC  && !DBG_HDRS_ALL */
-
-#   define GC_destroy_thread_local(t)
-
-# endif /* !THREAD_LOCAL_ALLOC */
+#endif /* GC_ASSERTIONS */
 
-#if 0
-/*
-To make sure that we're using LinuxThreads and not some other thread
-package, we generate a dummy reference to `pthread_kill_other_threads_np'
-(was `__pthread_initial_thread_bos' but that disappeared),
-which is a symbol defined in LinuxThreads, but (hopefully) not in other
-thread packages.
-
-We no longer do this, since this code is now portable enough that it might
-actually work for something else.
-*/
-void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np;
-#endif /* 0 */
-
-long GC_nprocs = 1;    /* Number of processors.  We may not have       */
-                       /* access to all of them, but this is as good   */
-                       /* a guess as any ...                           */
+#endif /* Thread_local_alloc */
 
 #ifdef PARALLEL_MARK
 
@@ -431,12 +270,18 @@ long GC_nprocs = 1;       /* Number of processors.  We may not have       */
 # endif
 
 static ptr_t marker_sp[MAX_MARKERS] = {0};
+#ifdef IA64
+  static ptr_t marker_bsp[MAX_MARKERS] = {0};
+#endif
 
 void * GC_mark_thread(void * id)
 {
   word my_mark_no = 0;
 
   marker_sp[(word)id] = GC_approx_sp();
+# ifdef IA64
+    marker_bsp[(word)id] = GC_save_regs_in_stack();
+# endif
   for (;; ++my_mark_no) {
     /* GC_mark_no is passed only to allow GC_help_marker to terminate  */
     /* promptly.  This is important if it were called from the signal  */
@@ -450,7 +295,7 @@ void * GC_mark_thread(void * id)
        my_mark_no = GC_mark_no;
     }
 #   ifdef DEBUG_THREADS
-       GC_printf1("Starting mark helper for mark number %ld\n", my_mark_no);
+       GC_printf("Starting mark helper for mark number %lu\n", my_mark_no);
 #   endif
     GC_help_marker(my_mark_no);
   }
@@ -464,7 +309,7 @@ pthread_t GC_mark_threads[MAX_MARKERS];
 
 #define PTHREAD_CREATE REAL_FUNC(pthread_create)
 
-static void start_mark_threads()
+static void start_mark_threads(void)
 {
     unsigned i;
     pthread_attr_t attr;
@@ -495,11 +340,9 @@ static void start_mark_threads()
        }
       }
 #   endif /* HPUX || GC_DGUX386_THREADS */
-#   ifdef CONDPRINT
-      if (GC_print_stats) {
-       GC_printf1("Starting %ld marker threads\n", GC_markers - 1);
-      }
-#   endif
+    if (GC_print_stats) {
+       GC_log_printf("Starting %ld marker threads\n", GC_markers - 1);
+    }
     for (i = 0; i < GC_markers - 1; ++i) {
       if (0 != PTHREAD_CREATE(GC_mark_threads + i, &attr,
                              GC_mark_thread, (void *)(word)i)) {
@@ -508,71 +351,41 @@ static void start_mark_threads()
     }
 }
 
-#else  /* !PARALLEL_MARK */
-
-static __inline__ void start_mark_threads()
-{
-}
-
-#endif /* !PARALLEL_MARK */
+#endif /* PARALLEL_MARK */
 
 GC_bool GC_thr_initialized = FALSE;
 
 volatile GC_thread GC_threads[THREAD_TABLE_SZ];
 
-void GC_push_thread_structures GC_PROTO((void))
+void GC_push_thread_structures(void)
 {
+    GC_ASSERT(I_HOLD_LOCK());
     GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
-#   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
+#   if defined(THREAD_LOCAL_ALLOC)
       GC_push_all((ptr_t)(&GC_thread_key),
          (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
 #   endif
 }
 
-#ifdef THREAD_LOCAL_ALLOC
-/* We must explicitly mark ptrfree and gcj free lists, since the free  */
-/* list links wouldn't otherwise be found.  We also set them in the    */
-/* normal free lists, since that involves touching less memory than if */
-/* we scanned them normally.                                           */
-void GC_mark_thread_local_free_lists(void)
-{
-    int i, j;
-    GC_thread p;
-    ptr_t q;
-    
-    for (i = 0; i < THREAD_TABLE_SZ; ++i) {
-      for (p = GC_threads[i]; 0 != p; p = p -> next) {
-       for (j = 1; j < NFREELISTS; ++j) {
-         q = p -> ptrfree_freelists[j];
-         if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
-         q = p -> normal_freelists[j];
-         if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
-#        ifdef GC_GCJ_SUPPORT
-           q = p -> gcj_freelists[j];
-           if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
-#        endif /* GC_GCJ_SUPPORT */
-       }
-      }
-    }
-}
-#endif /* THREAD_LOCAL_ALLOC */
-
+/* It may not be safe to allocate when we register the first thread.   */
 static struct GC_Thread_Rep first_thread;
 
 /* Add a thread to GC_threads.  We assume it wasn't already there.     */
 /* Caller holds allocation lock.                                       */
 GC_thread GC_new_thread(pthread_t id)
 {
-    int hv = ((word)id) % THREAD_TABLE_SZ;
+    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
     GC_thread result;
     static GC_bool first_thread_used = FALSE;
     
+    GC_ASSERT(I_HOLD_LOCK());
     if (!first_thread_used) {
        result = &first_thread;
        first_thread_used = TRUE;
     } else {
         result = (struct GC_Thread_Rep *)
                 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
+       GC_ASSERT(result -> flags == 0);
     }
     if (result == 0) return(0);
     result -> id = id;
@@ -584,14 +397,14 @@ GC_thread GC_new_thread(pthread_t id)
 
 /* Delete a thread from GC_threads.  We assume it is there.    */
 /* (The code intentionally traps if it wasn't.)                        */
-/* Caller holds allocation lock.                               */
 void GC_delete_thread(pthread_t id)
 {
-    int hv = ((word)id) % THREAD_TABLE_SZ;
+    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
     register GC_thread p = GC_threads[hv];
     register GC_thread prev = 0;
     
-    while (!pthread_equal(p -> id, id)) {
+    GC_ASSERT(I_HOLD_LOCK());
+    while (!THREAD_EQUAL(p -> id, id)) {
         prev = p;
         p = p -> next;
     }
@@ -600,11 +413,9 @@ void GC_delete_thread(pthread_t id)
     } else {
         prev -> next = p -> next;
     }
-       
-#ifdef GC_DARWIN_THREADS
+#   ifdef GC_DARWIN_THREADS
        mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
-#endif
-       
+#   endif
     GC_INTERNAL_FREE(p);
 }
 
@@ -612,12 +423,14 @@ void GC_delete_thread(pthread_t id)
 /* been notified, then there may be more than one thread       */
 /* in the table with the same pthread id.                      */
 /* This is OK, but we need a way to delete a specific one.     */
-void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
+void GC_delete_gc_thread(GC_thread gc_id)
 {
-    int hv = ((word)id) % THREAD_TABLE_SZ;
+    pthread_t id = gc_id -> id;
+    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
     register GC_thread p = GC_threads[hv];
     register GC_thread prev = 0;
 
+    GC_ASSERT(I_HOLD_LOCK());
     while (p != gc_id) {
         prev = p;
         p = p -> next;
@@ -627,11 +440,9 @@ void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
     } else {
         prev -> next = p -> next;
     }
-       
-#ifdef GC_DARWIN_THREADS
+#   ifdef GC_DARWIN_THREADS
        mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
-#endif
-       
+#   endif
     GC_INTERNAL_FREE(p);
 }
 
@@ -643,10 +454,10 @@ void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
 /* return the most recent one.                                 */
 GC_thread GC_lookup_thread(pthread_t id)
 {
-    int hv = ((word)id) % THREAD_TABLE_SZ;
+    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
     register GC_thread p = GC_threads[hv];
     
-    while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
+    while (p != 0 && !THREAD_EQUAL(p -> id, id)) p = p -> next;
     return(p);
 }
 
@@ -665,13 +476,13 @@ void GC_remove_all_threads_but_me(void)
       me = 0;
       for (p = GC_threads[hv]; 0 != p; p = next) {
        next = p -> next;
-       if (p -> id == self) {
+       if (THREAD_EQUAL(p -> id, self)) {
          me = p;
          p -> next = 0;
        } else {
 #        ifdef THREAD_LOCAL_ALLOC
            if (!(p -> flags & FINISHED)) {
-             GC_destroy_thread_local(p);
+             GC_destroy_thread_local(&(p->tlfs));
            }
 #        endif /* THREAD_LOCAL_ALLOC */
          if (p != &first_thread) GC_INTERNAL_FREE(p);
@@ -683,34 +494,66 @@ void GC_remove_all_threads_but_me(void)
 #endif /* HANDLE_FORK */
 
 #ifdef USE_PROC_FOR_LIBRARIES
-int GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
+GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
 {
     int i;
     GC_thread p;
     
+    GC_ASSERT(I_HOLD_LOCK());
 #   ifdef PARALLEL_MARK
       for (i = 0; i < GC_markers; ++i) {
-       if (marker_sp[i] > lo & marker_sp[i] < hi) return 1;
+       if (marker_sp[i] > lo & marker_sp[i] < hi) return TRUE;
+#       ifdef IA64
+         if (marker_bsp[i] > lo & marker_bsp[i] < hi) return TRUE;
+#      endif
       }
 #   endif
     for (i = 0; i < THREAD_TABLE_SZ; i++) {
       for (p = GC_threads[i]; p != 0; p = p -> next) {
        if (0 != p -> stack_end) {
 #        ifdef STACK_GROWS_UP
-            if (p -> stack_end >= lo && p -> stack_end < hi) return 1;
+            if (p -> stack_end >= lo && p -> stack_end < hi) return TRUE;
 #        else /* STACK_GROWS_DOWN */
-            if (p -> stack_end > lo && p -> stack_end <= hi) return 1;
+            if (p -> stack_end > lo && p -> stack_end <= hi) return TRUE;
 #        endif
        }
       }
     }
-    return 0;
+    return FALSE;
 }
 #endif /* USE_PROC_FOR_LIBRARIES */
 
+#ifdef IA64
+/* Find the largest stack_base smaller than bound.  May be used        */
+/* to find the boundary between a register stack and adjacent  */
+/* immediately preceding memory stack.                         */
+ptr_t GC_greatest_stack_base_below(ptr_t bound)
+{
+    int i;
+    GC_thread p;
+    ptr_t result = 0;
+    
+    GC_ASSERT(I_HOLD_LOCK());
+#   ifdef PARALLEL_MARK
+      for (i = 0; i < GC_markers; ++i) {
+       if (marker_sp[i] > result && marker_sp[i] < bound)
+         result = marker_sp[i];
+      }
+#   endif
+    for (i = 0; i < THREAD_TABLE_SZ; i++) {
+      for (p = GC_threads[i]; p != 0; p = p -> next) {
+       if (p -> stack_end > result && p -> stack_end < bound) {
+         result = p -> stack_end;
+       }
+      }
+    }
+    return result;
+}
+#endif /* IA64 */
+
 #ifdef GC_LINUX_THREADS
 /* Return the number of processors, or i<= 0 if it can't be determined.        */
-int GC_get_nprocs()
+int GC_get_nprocs(void)
 {
     /* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that      */
     /* appears to be buggy in many cases.                              */
@@ -749,9 +592,10 @@ int GC_get_nprocs()
 /* If wait_for_all is true, then we exit with the GC lock held and no  */
 /* collection in progress; otherwise we just wait for the current GC   */
 /* to finish.                                                          */
-extern GC_bool GC_collection_in_progress();
+extern GC_bool GC_collection_in_progress(void);
 void GC_wait_for_gc_completion(GC_bool wait_for_all)
 {
+    GC_ASSERT(I_HOLD_LOCK());
     if (GC_incremental && GC_collection_in_progress()) {
        int old_gc_no = GC_gc_no;
 
@@ -829,7 +673,7 @@ void GC_fork_child_proc(void)
 
 #if defined(GC_DGUX386_THREADS)
 /* Return the number of processors, or i<= 0 if it can't be determined. */
-int GC_get_nprocs()
+int GC_get_nprocs(void)
 {
     /* <takis@XFree86.Org> */
     int numCpus;
@@ -846,7 +690,7 @@ int GC_get_nprocs()
       numCpus = pm_sysinfo.idle_vp_count;
 
 #  ifdef DEBUG_THREADS
-    GC_printf1("Number of active CPUs in this system: %d\n", numCpus);
+    GC_printf("Number of active CPUs in this system: %d\n", numCpus);
 #  endif
     return(numCpus);
 }
@@ -864,11 +708,15 @@ static int get_ncpu(void)
 }
 #endif /* GC_NETBSD_THREADS */
 
+# if defined(GC_LINUX_THREADS) && defined(INCLUDE_LINUX_THREAD_DESCR)
+__thread int dummy_thread_local;
+# endif
+
 /* We hold the allocation lock.        */
-void GC_thr_init()
+void GC_thr_init(void)
 {
 #   ifndef GC_DARWIN_THREADS
-      int dummy;
+        int dummy;
 #   endif
     GC_thread t;
 
@@ -880,6 +728,21 @@ void GC_thr_init()
         pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc,
                       GC_fork_child_proc);
 #   endif /* HANDLE_FORK */
+#   if defined(INCLUDE_LINUX_THREAD_DESCR)
+      /* Explicitly register the region including the address          */
+      /* of a thread local variable.  This should included thread      */
+      /* locals for the main thread, except for those allocated                */
+      /* in response to dlopen calls.                                  */  
+       {
+         ptr_t thread_local_addr = (ptr_t)(&dummy_thread_local);
+         ptr_t main_thread_start, main_thread_end;
+          if (!GC_enclosing_mapping(thread_local_addr, &main_thread_start,
+                                   &main_thread_end)) {
+           ABORT("Failed to find mapping for main thread thread locals");
+         }
+         GC_add_roots_inner(main_thread_start, main_thread_end, FALSE);
+       }
+#   endif
     /* Add the initial thread, so we can stop it.      */
       t = GC_new_thread(pthread_self());
 #     ifdef GC_DARWIN_THREADS
@@ -901,7 +764,8 @@ void GC_thr_init()
 #       if defined(GC_HPUX_THREADS)
          GC_nprocs = pthread_num_processors_np();
 #       endif
-#      if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS)
+#      if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \
+          || defined(GC_SOLARIS_THREADS)
          GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
          if (GC_nprocs <= 0) GC_nprocs = 1;
 #      endif
@@ -921,6 +785,9 @@ void GC_thr_init()
 #      if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
           GC_nprocs = GC_get_nprocs();
 #      endif
+#       if defined(GC_GNU_THREADS)
+         if (GC_nprocs <= 0) GC_nprocs = 1;
+#       endif
       }
       if (GC_nprocs <= 0) {
        WARN("GC_get_nprocs() returned %ld\n", GC_nprocs);
@@ -941,19 +808,16 @@ void GC_thr_init()
 #      endif
       }
 #   ifdef PARALLEL_MARK
-#     ifdef CONDPRINT
-        if (GC_print_stats) {
-          GC_printf2("Number of processors = %ld, "
+      if (GC_print_stats) {
+          GC_log_printf("Number of processors = %ld, "
                 "number of marker threads = %ld\n", GC_nprocs, GC_markers);
-       }
-#     endif
+      }
       if (GC_markers == 1) {
        GC_parallel = FALSE;
-#      ifdef CONDPRINT
-         if (GC_print_stats) {
-           GC_printf0("Single marker thread, turning off parallel marking\n");
-         }
-#      endif
+       if (GC_print_stats) {
+           GC_log_printf(
+               "Single marker thread, turning off parallel marking\n");
+       }
       } else {
        GC_parallel = TRUE;
        /* Disable true incremental collection, but generational is OK. */
@@ -969,8 +833,8 @@ void GC_thr_init()
 /* may require allocation.                             */
 /* Called without allocation lock.                     */
 /* Must be called before a second thread is created.   */
-/* Called without allocation lock.                     */
-void GC_init_parallel()
+/* Did we say it's called without the allocation lock? */
+void GC_init_parallel(void)
 {
     if (parallel_initialized) return;
     parallel_initialized = TRUE;
@@ -978,9 +842,9 @@ void GC_init_parallel()
     /* GC_init() calls us back, so set flag first.     */
     if (!GC_is_initialized) GC_init();
     /* Initialize thread local free lists if used.     */
-#   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
+#   if defined(THREAD_LOCAL_ALLOC)
       LOCK();
-      GC_init_thread_local(GC_lookup_thread(pthread_self()));
+      GC_init_thread_local(&(GC_lookup_thread(pthread_self())->tlfs));
       UNLOCK();
 #   endif
 }
@@ -991,6 +855,7 @@ int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
 {
     sigset_t fudged_set;
     
+    INIT_REAL_SYMS();
     if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
         fudged_set = *set;
         sigdelset(&fudged_set, SIG_SUSPEND);
@@ -1000,64 +865,45 @@ int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
 }
 #endif /* !GC_DARWIN_THREADS */
 
-/* Wrappers for functions that are likely to block for an appreciable  */
-/* length of time.  Must be called in pairs, if at all.                        */
-/* Nothing much beyond the system call itself should be executed       */
-/* between these.                                                      */
+/* Wrapper for functions that are likely to block for an appreciable   */
+/* length of time.                                                     */
+
+struct blocking_data {
+    void (*fn)(void *);
+    void *arg;
+};
 
-void GC_start_blocking(void) {
-#   define SP_SLOP 128
+static void GC_do_blocking_inner(ptr_t data, void * context) {
+    struct blocking_data * d = (struct blocking_data *) data;
     GC_thread me;
     LOCK();
     me = GC_lookup_thread(pthread_self());
     GC_ASSERT(!(me -> thread_blocked));
 #   ifdef SPARC
-       me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
-#   else
-#   ifndef GC_DARWIN_THREADS
-       me -> stop_info.stack_ptr = (ptr_t)GC_approx_sp();
-#   endif
+       me -> stop_info.stack_ptr = GC_save_regs_in_stack();
+#   elif !defined(GC_DARWIN_THREADS)
+       me -> stop_info.stack_ptr = GC_approx_sp();
 #   endif
 #   ifdef IA64
-       me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack() + SP_SLOP;
-#   endif
-    /* Add some slop to the stack pointer, since the wrapped call may  */
-    /* end up pushing more callee-save registers.                      */
-#   ifndef GC_DARWIN_THREADS
-#   ifdef STACK_GROWS_UP
-       me -> stop_info.stack_ptr += SP_SLOP;
-#   else
-       me -> stop_info.stack_ptr -= SP_SLOP;
-#   endif
+       me -> backing_store_ptr = GC_save_regs_in_stack();
 #   endif
     me -> thread_blocked = TRUE;
+    /* Save context here if we want to support precise stack marking */
     UNLOCK();
-}
-
-void GC_end_blocking(void) {
-    GC_thread me;
+    (d -> fn)(d -> arg);
     LOCK();   /* This will block if the world is stopped.      */
-    me = GC_lookup_thread(pthread_self());
-    GC_ASSERT(me -> thread_blocked);
     me -> thread_blocked = FALSE;
     UNLOCK();
 }
-    
-#if defined(GC_DGUX386_THREADS)
-#define __d10_sleep sleep
-#endif /* GC_DGUX386_THREADS */
 
-/* A wrapper for the standard C sleep function */
-int WRAP_FUNC(sleep) (unsigned int seconds)
-{
-    int result;
+void GC_do_blocking(void (*fn)(void *), void *arg) {
+    struct blocking_data my_data;
 
-    GC_start_blocking();
-    result = REAL_FUNC(sleep)(seconds);
-    GC_end_blocking();
-    return result;
+    my_data.fn = fn;
+    my_data.arg = arg;
+    GC_with_callee_saves_pushed(GC_do_blocking_inner, (ptr_t)(&my_data));
 }
-
+    
 struct start_info {
     void *(*start_routine)(void *);
     void *arg;
@@ -1066,30 +912,38 @@ struct start_info {
                                /* parent hasn't yet noticed.           */
 };
 
-/* Called at thread exit.                              */
-/* Never called for main thread.  That's OK, since it  */
-/* results in at most a tiny one-time leak.  And       */
-/* linuxthreads doesn't reclaim the main threads       */
-/* resources or id anyway.                             */
-void GC_thread_exit_proc(void *arg)
+int GC_unregister_my_thread(void)
 {
     GC_thread me;
 
     LOCK();
+    /* Wait for any GC that may be marking from our stack to   */
+    /* complete before we remove this thread.                  */
+    GC_wait_for_gc_completion(FALSE);
     me = GC_lookup_thread(pthread_self());
-    GC_destroy_thread_local(me);
+#   if defined(THREAD_LOCAL_ALLOC)
+      GC_destroy_thread_local(&(me->tlfs));
+#   endif
     if (me -> flags & DETACHED) {
        GC_delete_thread(pthread_self());
     } else {
        me -> flags |= FINISHED;
     }
-#   if defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_SPECIFIC) \
-       && !defined(USE_COMPILER_TLS) && !defined(DBG_HDRS_ALL)
+#   if defined(THREAD_LOCAL_ALLOC)
       GC_remove_specific(GC_thread_key);
 #   endif
-    /* The following may run the GC from "nonexistent" thread. */
-    GC_wait_for_gc_completion(FALSE);
     UNLOCK();
+    return GC_SUCCESS;
+}
+
+/* Called at thread exit.                              */
+/* Never called for main thread.  That's OK, since it  */
+/* results in at most a tiny one-time leak.  And       */
+/* linuxthreads doesn't reclaim the main threads       */
+/* resources or id anyway.                             */
+void GC_thread_exit_proc(void *arg)
+{
+    GC_unregister_my_thread();
 }
 
 int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
@@ -1097,6 +951,7 @@ int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
     int result;
     GC_thread thread_gc_id;
     
+    INIT_REAL_SYMS();
     LOCK();
     thread_gc_id = GC_lookup_thread(thread);
     /* This is guaranteed to be the intended one, since the thread id  */
@@ -1117,7 +972,7 @@ int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
     if (result == 0) {
         LOCK();
         /* Here the pthread thread id may have been recycled. */
-        GC_delete_gc_thread(thread, thread_gc_id);
+        GC_delete_gc_thread(thread_gc_id);
         UNLOCK();
     }
     return result;
@@ -1129,6 +984,7 @@ WRAP_FUNC(pthread_detach)(pthread_t thread)
     int result;
     GC_thread thread_gc_id;
     
+    INIT_REAL_SYMS();
     LOCK();
     thread_gc_id = GC_lookup_thread(thread);
     UNLOCK();
@@ -1138,18 +994,57 @@ WRAP_FUNC(pthread_detach)(pthread_t thread)
       thread_gc_id -> flags |= DETACHED;
       /* Here the pthread thread id may have been recycled. */
       if (thread_gc_id -> flags & FINISHED) {
-        GC_delete_gc_thread(thread, thread_gc_id);
+        GC_delete_gc_thread(thread_gc_id);
       }
       UNLOCK();
     }
     return result;
 }
 
-GC_bool GC_in_thread_creation = FALSE;
+GC_bool GC_in_thread_creation = FALSE;  /* Protected by allocation lock. */
 
-void * GC_start_routine(void * arg)
+GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,
+                                     pthread_t my_pthread)
+{
+    GC_thread me;
+
+    GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
+    me = GC_new_thread(my_pthread);
+    GC_in_thread_creation = FALSE;
+#   ifdef GC_DARWIN_THREADS
+      me -> stop_info.mach_thread = mach_thread_self();
+#   else
+      me -> stop_info.stack_ptr = sb -> mem_base;
+#   endif
+    me -> stack_end = sb -> mem_base;
+#   ifdef IA64
+      me -> backing_store_end = sb -> reg_base;
+#   endif /* IA64 */
+    return me;
+}
+
+int GC_register_my_thread(struct GC_stack_base *sb)
+{
+    pthread_t my_pthread = pthread_self();
+    GC_thread me;
+
+    LOCK();
+    me = GC_lookup_thread(my_pthread);
+    if (0 == me) {
+        me = GC_register_my_thread_inner(sb, my_pthread);
+       me -> flags |= DETACHED;
+         /* Treat as detached, since we do not need to worry about     */
+         /* pointer results.                                           */
+       UNLOCK();
+        return GC_SUCCESS;
+    } else {
+       UNLOCK();
+       return GC_DUPLICATE;
+    }
+}
+
+void * GC_inner_start_routine(struct GC_stack_base *sb, void * arg)
 {
-    int dummy;
     struct start_info * si = arg;
     void * result;
     GC_thread me;
@@ -1159,62 +1054,31 @@ void * GC_start_routine(void * 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);
+        GC_printf("Starting thread 0x%x\n", (unsigned)my_pthread);
+        GC_printf("pid = %ld\n", (long) getpid());
+        GC_printf("sp = 0x%lx\n", (long) &arg);
 #   endif
     LOCK();
-    GC_in_thread_creation = TRUE;
-    me = GC_new_thread(my_pthread);
-    GC_in_thread_creation = FALSE;
-#ifdef GC_DARWIN_THREADS
-    me -> stop_info.mach_thread = mach_thread_self();
-#else
-    me -> stop_info.stack_ptr = 0;
-#endif
+    me = GC_register_my_thread_inner(sb, my_pthread);
     me -> flags = si -> flags;
-    /* 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));
-#        ifndef GC_DARWIN_THREADS
-        me -> stop_info.stack_ptr = me -> stack_end - 0x10;
-#        endif
-       /* 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 -> stop_info.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;
 #   ifdef DEBUG_THREADS
-       GC_printf1("start_routine = 0x%lx\n", start);
+       GC_printf("start_routine = %p\n", (void *)start);
 #   endif
     start_arg = si -> arg;
     sem_post(&(si -> registered));     /* Last action on si.   */
                                        /* OK to deallocate.    */
     pthread_cleanup_push(GC_thread_exit_proc, 0);
-#   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
+#   if defined(THREAD_LOCAL_ALLOC)
        LOCK();
-        GC_init_thread_local(me);
+        GC_init_thread_local(&(me->tlfs));
        UNLOCK();
 #   endif
     result = (*start)(start_arg);
-#if DEBUG_THREADS
-        GC_printf1("Finishing thread 0x%x\n", pthread_self());
-#endif
+#   if DEBUG_THREADS
+        GC_printf("Finishing thread 0x%x\n", (unsigned)pthread_self());
+#   endif
     me -> status = result;
     pthread_cleanup_pop(1);
     /* Cleanup acquires lock, ensuring that we can't exit              */
@@ -1223,6 +1087,29 @@ void * GC_start_routine(void * arg)
     return(result);
 }
 
+void * GC_start_routine(void * arg)
+{
+#   ifdef INCLUDE_LINUX_THREAD_DESCR
+      struct GC_stack_base sb;
+
+#     ifdef REDIRECT_MALLOC
+       /* GC_get_stack_base may call pthread_getattr_np, which can     */
+        /* unfortunately call realloc, which may allocate from an      */
+        /* unregistered thread.  This is unpleasant, since it might    */ 
+        /* force heap growth.                                          */
+        GC_disable();
+#     endif
+      if (GC_get_stack_base(&sb) != GC_SUCCESS)
+       ABORT("Failed to get thread stack base.");
+#     ifdef REDIRECT_MALLOC
+        GC_enable();
+#     endif
+      return GC_inner_start_routine(&sb, arg);
+#   else
+      return GC_call_with_stack_base(GC_inner_start_routine, arg);
+#   endif
+}
+
 int
 WRAP_FUNC(pthread_create)(pthread_t *new_thread,
                  const pthread_attr_t *attr,
@@ -1239,6 +1126,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
     /* even if the default is unreasonably small.  That's the client's */
     /* responsibility.                                                 */
 
+    INIT_REAL_SYMS();
     LOCK();
     si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
                                                 NORMAL);
@@ -1252,13 +1140,22 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
     if (!GC_thr_initialized) GC_thr_init();
 #   ifdef GC_ASSERTIONS
       {
-       size_t stack_size;
-       if (NULL == attr) {
+       size_t stack_size = 0;
+       if (NULL != attr) {
+          pthread_attr_getstacksize(attr, &stack_size);
+       }
+       if (0 == stack_size) {
           pthread_attr_t my_attr;
           pthread_attr_init(&my_attr);
           pthread_attr_getstacksize(&my_attr, &stack_size);
-       } else {
-          pthread_attr_getstacksize(attr, &stack_size);
+       }
+       /* On Solaris 10, with default attr initialization,     */
+       /* stack_size remains 0.  Fudge it.                     */
+       if (0 == stack_size) {
+#          ifndef SOLARIS
+             WARN("Failed to get stack size for assertion checking\n", 0);
+#          endif
+           stack_size = 1000000;
        }
 #       ifdef PARALLEL_MARK
          GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
@@ -1281,14 +1178,15 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
     si -> flags = my_flags;
     UNLOCK();
 #   ifdef DEBUG_THREADS
-        GC_printf1("About to start new thread from thread 0x%X\n",
-                  pthread_self());
+        GC_printf("About to start new thread from thread 0x%x\n",
+                 (unsigned)pthread_self());
 #   endif
+    GC_need_to_lock = TRUE;
 
     result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
 
 #   ifdef DEBUG_THREADS
-        GC_printf1("Started thread 0x%X\n", *new_thread);
+        GC_printf("Started thread 0x%x\n", (unsigned)(*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  */
@@ -1307,38 +1205,9 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
     return(result);
 }
 
-#ifdef GENERIC_COMPARE_AND_SWAP
-  pthread_mutex_t GC_compare_and_swap_lock = PTHREAD_MUTEX_INITIALIZER;
-
-  GC_bool GC_compare_and_exchange(volatile GC_word *addr,
-                                 GC_word old, GC_word new_val)
-  {
-    GC_bool result;
-    pthread_mutex_lock(&GC_compare_and_swap_lock);
-    if (*addr == old) {
-      *addr = new_val;
-      result = TRUE;
-    } else {
-      result = FALSE;
-    }
-    pthread_mutex_unlock(&GC_compare_and_swap_lock);
-    return result;
-  }
-  
-  GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much)
-  {
-    GC_word old;
-    pthread_mutex_lock(&GC_compare_and_swap_lock);
-    old = *addr;
-    *addr = old + how_much;
-    pthread_mutex_unlock(&GC_compare_and_swap_lock);
-    return old;
-  }
-
-#endif /* GENERIC_COMPARE_AND_SWAP */
 /* Spend a few cycles in a way that can't introduce contention with    */
 /* othre threads.                                                      */
-void GC_pause()
+void GC_pause(void)
 {
     int i;
 #   if !defined(__GNUC__) || defined(__INTEL_COMPILER)
@@ -1358,7 +1227,7 @@ void GC_pause()
 #define SPIN_MAX 128   /* Maximum number of calls to GC_pause before   */
                        /* give up.                                     */
 
-VOLATILE GC_bool GC_collecting = 0;
+volatile GC_bool GC_collecting = 0;
                        /* A hint that we're in the collector and       */
                         /* holding the allocation lock for an           */
                         /* extended period.                             */
@@ -1430,10 +1299,10 @@ void GC_generic_lock(pthread_mutex_t * lock)
 /* as STL alloc.h.  This isn't really the right way to do this.   */
 /* but until the POSIX scheduling mess gets straightened out ...  */
 
-volatile unsigned int GC_allocate_lock = 0;
+volatile AO_TS_t GC_allocate_lock = 0;
 
 
-void GC_lock()
+void GC_lock(void)
 {
 #   define low_spin_max 30  /* spin cycles if we suspect uniprocessor */
 #   define high_spin_max SPIN_MAX /* spin cycles for multiprocessor */
@@ -1443,18 +1312,18 @@ void GC_lock()
     unsigned my_last_spins;
     int i;
 
-    if (!GC_test_and_set(&GC_allocate_lock)) {
+    if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
         return;
     }
     my_spin_max = spin_max;
     my_last_spins = last_spins;
     for (i = 0; i < my_spin_max; i++) {
         if (GC_collecting || GC_nprocs == 1) goto yield;
-        if (i < my_last_spins/2 || GC_allocate_lock) {
+        if (i < my_last_spins/2) {
             GC_pause();
             continue;
         }
-        if (!GC_test_and_set(&GC_allocate_lock)) {
+        if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
            /*
              * got it!
              * Spinning worked.  Thus we're probably not being scheduled
@@ -1470,7 +1339,7 @@ void GC_lock()
     spin_max = low_spin_max;
 yield:
     for (i = 0;; ++i) {
-        if (!GC_test_and_set(&GC_allocate_lock)) {
+        if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
             return;
         }
 #       define SLEEP_THRESHOLD 12
@@ -1496,7 +1365,7 @@ yield:
 }
 
 #else  /* !USE_SPINLOCK */
-void GC_lock()
+void GC_lock(void)
 {
 #ifndef NO_PTHREAD_TRYLOCK
     if (1 == GC_nprocs || GC_collecting) {
@@ -1514,7 +1383,7 @@ void GC_lock()
 #if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
 
 #ifdef GC_ASSERTIONS
-  pthread_t GC_mark_lock_holder = NO_THREAD;
+  unsigned long GC_mark_lock_holder = NO_THREAD;
 #endif
 
 #if 0
@@ -1533,7 +1402,7 @@ void GC_lock()
 
 static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
 
-void GC_acquire_mark_lock()
+void GC_acquire_mark_lock(void)
 {
 /*
     if (pthread_mutex_lock(&mark_mutex) != 0) {
@@ -1542,13 +1411,13 @@ void GC_acquire_mark_lock()
 */
     GC_generic_lock(&mark_mutex);
 #   ifdef GC_ASSERTIONS
-       GC_mark_lock_holder = pthread_self();
+       GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
 #   endif
 }
 
-void GC_release_mark_lock()
+void GC_release_mark_lock(void)
 {
-    GC_ASSERT(GC_mark_lock_holder == pthread_self());
+    GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
 #   ifdef GC_ASSERTIONS
        GC_mark_lock_holder = NO_THREAD;
 #   endif
@@ -1562,9 +1431,9 @@ void GC_release_mark_lock()
 /* 2) Partial free lists referenced only by locals may not be scanned  */
 /*    correctly, e.g. if they contain "pointer-free" objects, since the        */
 /*    free-list link may be ignored.                                   */
-void GC_wait_builder()
+void GC_wait_builder(void)
 {
-    GC_ASSERT(GC_mark_lock_holder == pthread_self());
+    GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
 #   ifdef GC_ASSERTIONS
        GC_mark_lock_holder = NO_THREAD;
 #   endif
@@ -1573,11 +1442,11 @@ void GC_wait_builder()
     }
     GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
 #   ifdef GC_ASSERTIONS
-       GC_mark_lock_holder = pthread_self();
+       GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
 #   endif
 }
 
-void GC_wait_for_reclaim()
+void GC_wait_for_reclaim(void)
 {
     GC_acquire_mark_lock();
     while (GC_fl_builder_count > 0) {
@@ -1586,9 +1455,9 @@ void GC_wait_for_reclaim()
     GC_release_mark_lock();
 }
 
-void GC_notify_all_builder()
+void GC_notify_all_builder(void)
 {
-    GC_ASSERT(GC_mark_lock_holder == pthread_self());
+    GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
     if (pthread_cond_broadcast(&builder_cv) != 0) {
        ABORT("pthread_cond_broadcast failed");
     }
@@ -1600,9 +1469,9 @@ void GC_notify_all_builder()
 
 static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
 
-void GC_wait_marker()
+void GC_wait_marker(void)
 {
-    GC_ASSERT(GC_mark_lock_holder == pthread_self());
+    GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
 #   ifdef GC_ASSERTIONS
        GC_mark_lock_holder = NO_THREAD;
 #   endif
@@ -1611,11 +1480,11 @@ void GC_wait_marker()
     }
     GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
 #   ifdef GC_ASSERTIONS
-       GC_mark_lock_holder = pthread_self();
+       GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
 #   endif
 }
 
-void GC_notify_all_marker()
+void GC_notify_all_marker(void)
 {
     if (pthread_cond_broadcast(&mark_cv) != 0) {
        ABORT("pthread_cond_broadcast failed");
index 9b716faf010e73834600318340e84db574baf481..dd0529c359629abfef0bbbcfa91ae175b470b68c 100644 (file)
 
 #include "private/gc_pmark.h"
 
-#ifdef __STDC__
-void GC_default_same_obj_print_proc(GC_PTR p, GC_PTR q)
-#else
-void GC_default_same_obj_print_proc (p, q)
-GC_PTR p, q;
-#endif
+void GC_default_same_obj_print_proc(void * p, void * q)
 {
-    GC_err_printf2("0x%lx and 0x%lx are not in the same object\n",
-                  (unsigned long)p, (unsigned long)q);
+    GC_err_printf("%p and %p are not in the same object\n", p, q);
     ABORT("GC_same_obj test failed");
 }
 
-void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR, GC_PTR))
+void (*GC_same_obj_print_proc) (void *, void *)
                = GC_default_same_obj_print_proc;
 
 /* Check that p and q point to the same object.  Call          */
@@ -44,17 +38,12 @@ void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR, GC_PTR))
 /* We assume this is performance critical.  (It shouldn't      */
 /* be called by production code, but this can easily make      */
 /* debugging intolerably slow.)                                        */
-#ifdef __STDC__
-  GC_PTR GC_same_obj(register void *p, register void *q)
-#else
-  GC_PTR GC_same_obj(p, q)
-  register char *p, *q;
-#endif
+void * GC_same_obj(void *p, void *q)
 {
-    register struct hblk *h;
-    register hdr *hhdr;
-    register ptr_t base, limit;
-    register word sz;
+    struct hblk *h;
+    hdr *hhdr;
+    ptr_t base, limit;
+    word sz;
     
     if (!GC_is_initialized) GC_init();
     hhdr = HDR((word)p);
@@ -74,13 +63,13 @@ void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR, GC_PTR))
           h = FORWARDED_ADDR(h, hhdr);
           hhdr = HDR(h);
        }
-       limit = (ptr_t)((word *)h + hhdr -> hb_sz);
+       limit = (ptr_t)h + hhdr -> hb_sz;
        if ((ptr_t)p >= limit || (ptr_t)q >= limit || (ptr_t)q < (ptr_t)h ) {
            goto fail;
        }
        return(p);
     }
-    sz = WORDS_TO_BYTES(hhdr -> hb_sz);
+    sz = hhdr -> hb_sz;
     if (sz > MAXOBJBYTES) {
       base = (ptr_t)HBLKPTR(p);
       limit = base + sz;
@@ -88,19 +77,15 @@ void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR, GC_PTR))
         goto fail;
       }
     } else {
-      register int map_entry;
-      register int pdispl = HBLKDISPL(p);
+      size_t offset;
+      size_t pdispl = HBLKDISPL(p);
       
-      map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
-      if (map_entry > CPP_MAX_OFFSET) {
-         map_entry = BYTES_TO_WORDS(pdispl) % BYTES_TO_WORDS(sz);
-        if (HBLKPTR(p) != HBLKPTR(q)) goto fail;
+      offset = pdispl % sz;
+      if (HBLKPTR(p) != HBLKPTR(q)) goto fail;
                /* W/o this check, we might miss an error if    */
                /* q points to the first object on a page, and  */
                /* points just before the page.                 */
-      }
-      base = (char *)((word)p & ~(WORDS_TO_BYTES(1) - 1));
-      base -= WORDS_TO_BYTES(map_entry);
+      base = (ptr_t)p - offset;
       limit = base + sz;
     }
     /* [base, limit) delimits the object containing p, if any. */
@@ -116,19 +101,13 @@ fail:
     return(p);
 }
 
-#ifdef __STDC__
-void GC_default_is_valid_displacement_print_proc (GC_PTR p)
-#else
-void GC_default_is_valid_displacement_print_proc (p)
-GC_PTR p;
-#endif
+void GC_default_is_valid_displacement_print_proc (void *p)
 {
-    GC_err_printf1("0x%lx does not point to valid object displacement\n",
-                  (unsigned long)p);
+    GC_err_printf("%p does not point to valid object displacement\n", p);
     ABORT("GC_is_valid_displacement test failed");
 }
 
-void (*GC_is_valid_displacement_print_proc) GC_PROTO((GC_PTR)) = 
+void (*GC_is_valid_displacement_print_proc)(void *) = 
        GC_default_is_valid_displacement_print_proc;
 
 /* Check that if p is a pointer to a heap page, then it points to      */
@@ -137,18 +116,13 @@ void (*GC_is_valid_displacement_print_proc) GC_PROTO((GC_PTR)) =
 /* Always returns its argument.                                                */
 /* Note that we don't lock, since nothing relevant about the header    */
 /* should change while we have a valid object pointer to the block.    */
-#ifdef __STDC__
-  void * GC_is_valid_displacement(void *p)
-#else
-  char *GC_is_valid_displacement(p)
-  char *p;
-#endif
+void * GC_is_valid_displacement(void *p)
 {
-    register hdr *hhdr;
-    register word pdispl;
-    register struct hblk *h;
-    register map_entry_type map_entry;
-    register word sz;
+    hdr *hhdr;
+    word pdispl;
+    word offset;
+    struct hblk *h;
+    word sz;
     
     if (!GC_is_initialized) GC_init();
     hhdr = HDR((word)p);
@@ -163,11 +137,12 @@ void (*GC_is_valid_displacement_print_proc) GC_PROTO((GC_PTR)) =
     if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
        goto fail;
     }
-    sz = WORDS_TO_BYTES(hhdr -> hb_sz);
+    sz = hhdr -> hb_sz;
     pdispl = HBLKDISPL(p);
-    map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
-    if (map_entry == OBJ_INVALID
-       || sz > MAXOBJBYTES && (ptr_t)p >= (ptr_t)h + sz) {
+    offset = pdispl % sz;
+    if ((sz > MAXOBJBYTES && (ptr_t)p >= (ptr_t)h + sz)
+       || !GC_valid_offsets[offset]
+       || (ptr_t)p - offset + sz > (ptr_t)(h + 1)) {
        goto fail;
     }
     return(p);
@@ -176,24 +151,16 @@ fail:
     return(p);
 }
 
-#ifdef __STDC__
-void GC_default_is_visible_print_proc(GC_PTR p)
-#else
-void GC_default_is_visible_print_proc(p)
-GC_PTR p;
-#endif
+void GC_default_is_visible_print_proc(void * p)
 {
-    GC_err_printf1("0x%lx is not a GC visible pointer location\n",
-                  (unsigned long)p);
+    GC_err_printf("%p is not a GC visible pointer location\n", p);
     ABORT("GC_is_visible test failed");
 }
 
-void (*GC_is_visible_print_proc) GC_PROTO((GC_PTR p)) = 
-       GC_default_is_visible_print_proc;
+void (*GC_is_visible_print_proc)(void * p) = GC_default_is_visible_print_proc;
 
 /* Could p be a stack address? */
-GC_bool GC_on_stack(p)
-ptr_t p;
+GC_bool GC_on_stack(ptr_t p)
 {
 #   ifdef THREADS
        return(TRUE);
@@ -220,14 +187,9 @@ ptr_t p;
 /* untyped allocations.  The idea is that it should be possible, though        */
 /* slow, to add such a call to all indirect pointer stores.)           */
 /* Currently useless for multithreaded worlds.                         */
-#ifdef __STDC__
-  void * GC_is_visible(void *p)
-#else
-  char *GC_is_visible(p)
-  char *p;
-#endif
+void * GC_is_visible(void *p)
 {
-    register hdr *hhdr;
+    hdr *hhdr;
     
     if ((word)p & (ALIGNMENT - 1)) goto fail;
     if (!GC_is_initialized) GC_init();
@@ -249,12 +211,9 @@ ptr_t p;
            if (GC_is_static_root(p)) return(p);
            /* Else do it again correctly:      */
 #           if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || \
-               defined(MSWINCE) || defined(PCR)) \
-                && !defined(SRC_M3)
-               DISABLE_SIGNALS();
+               defined(MSWINCE) || defined(PCR))
                GC_register_dynamic_libraries();
                result = GC_is_static_root(p);
-               ENABLE_SIGNALS();
                if (result) return(p);
 #          endif
            goto fail;
@@ -302,12 +261,10 @@ fail:
 }
 
 
-GC_PTR GC_pre_incr (p, how_much)
-GC_PTR *p;
-size_t how_much;
+void * GC_pre_incr (void **p, size_t how_much)
 {
-    GC_PTR initial = *p;
-    GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
+    void * initial = *p;
+    void * result = GC_same_obj((void *)((word)initial + how_much), initial);
     
     if (!GC_all_interior_pointers) {
        (void) GC_is_valid_displacement(result);
@@ -315,12 +272,10 @@ size_t how_much;
     return (*p = result);
 }
 
-GC_PTR GC_post_incr (p, how_much)
-GC_PTR *p;
-size_t how_much;
+void * GC_post_incr (void **p, size_t how_much)
 {
-    GC_PTR initial = *p;
-    GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
+    void * initial = *p;
+    void * result = GC_same_obj((void *)((word)initial + how_much), initial);
  
     if (!GC_all_interior_pointers) {
        (void) GC_is_valid_displacement(result);
index b176676b06c4a51a61d63afe55d6279e1a0f0954..c5c4628519535310980b425460a9c534fd2271b0 100644 (file)
 # define PCR_NO_RENAME
 # include <stdlib.h>
 
-# ifdef __STDC__
-    char * real_malloc(size_t size)
-# else 
-    char * real_malloc()
-    int size;
-# endif
+void * real_malloc(size_t size)
 {
-    return((char *)malloc(size));
+    return(malloc(size));
 }
 #endif /* PCR */
 
index 243fbae24aeeefb015c747e6e25b6e67b38f8432..dd3645dd47c79b29ebc3245dd90bb047ba5a12f9 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
- * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -19,8 +19,8 @@
 #include <stdio.h>
 #include "private/gc_priv.h"
 
-signed_word GC_mem_found = 0;
-                       /* Number of words of memory reclaimed     */
+signed_word GC_bytes_found = 0;
+                       /* Number of bytes of memory reclaimed     */
 
 #if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
   word GC_fl_builder_count = 0;
@@ -38,8 +38,7 @@ unsigned GC_n_leaked = 0;
 
 GC_bool GC_have_errors = FALSE;
 
-void GC_add_leaked(leaked)
-ptr_t leaked;
+void GC_add_leaked(ptr_t leaked)
 {
     if (GC_n_leaked < MAX_LEAKED) {
       GC_have_errors = TRUE;
@@ -67,12 +66,12 @@ void GC_print_all_errors ()
     for (i = 0; i < GC_n_leaked; ++i) {
        ptr_t p = GC_leaked[i];
        if (HDR(p) -> hb_obj_kind == PTRFREE) {
-           GC_err_printf0("Leaked atomic object at ");
+           GC_err_printf("Leaked atomic object at ");
        } else {
-           GC_err_printf0("Leaked composite object at ");
+           GC_err_printf("Leaked composite object at ");
        }
        GC_print_heap_obj(p);
-       GC_err_printf0("\n");
+       GC_err_printf("\n");
        GC_free(p);
        GC_leaked[i] = 0;
     }
@@ -81,11 +80,6 @@ void GC_print_all_errors ()
 }
 
 
-#   define FOUND_FREE(hblk, word_no) \
-      { \
-         GC_add_leaked((ptr_t)hblk + WORDS_TO_BYTES(word_no)); \
-      }
-
 /*
  * reclaim phase
  *
@@ -98,245 +92,49 @@ void GC_print_all_errors ()
  * memory.
  */
  
-GC_bool GC_block_empty(hhdr)
-register hdr * hhdr;
-{
-    /* We treat hb_marks as an array of words here, even if it is      */
-    /* actually an array of bytes.  Since we only check for zero, there        */
-    /* are no endian-ness issues.                                      */
-    register word *p = (word *)(&(hhdr -> hb_marks[0]));
-    register word * plim =
-           (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ]));
-    while (p < plim) {
-       if (*p++) return(FALSE);
-    }
-    return(TRUE);
-}
-
-/* The following functions sometimes return a DONT_KNOW value. */
-#define DONT_KNOW  2
-
-#ifdef SMALL_CONFIG
-# define GC_block_nearly_full1(hhdr, pat1) DONT_KNOW
-# define GC_block_nearly_full3(hhdr, pat1, pat2) DONT_KNOW
-# define GC_block_nearly_full(hhdr) DONT_KNOW
-#endif
-
-#if !defined(SMALL_CONFIG) && defined(USE_MARK_BYTES)
-
-# define GC_block_nearly_full1(hhdr, pat1) GC_block_nearly_full(hhdr)
-# define GC_block_nearly_full3(hhdr, pat1, pat2) GC_block_nearly_full(hhdr)
-
-GC_bool GC_block_nearly_full(hhdr)
-register hdr * hhdr;
-{
-    /* We again treat hb_marks as an array of words, even though it    */
-    /* isn't.  We first sum up all the words, resulting in a word      */
-    /* containing 4 or 8 separate partial sums.                        */
-    /* We then sum the bytes in the word of partial sums.              */
-    /* This is still endian independant.  This fails if the partial    */
-    /* sums can overflow.                                              */
-#   if (BYTES_TO_WORDS(MARK_BITS_SZ)) >= 256
-       --> potential overflow; fix the code
-#   endif
-    register word *p = (word *)(&(hhdr -> hb_marks[0]));
-    register word * plim =
-           (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ]));
-    word sum_vector = 0;
-    unsigned sum;
-    while (p < plim) {
-       sum_vector += *p;
-       ++p;
-    }
-    sum = 0;
-    while (sum_vector > 0) {
-       sum += sum_vector & 0xff;
-       sum_vector >>= 8;
-    }
-    return (sum > BYTES_TO_WORDS(7*HBLKSIZE/8)/(hhdr -> hb_sz));
-}
-#endif  /* USE_MARK_BYTES */
-
-#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
-
-/*
- * Test whether nearly all of the mark words consist of the same
- * repeating pattern.
- */
-#define FULL_THRESHOLD (MARK_BITS_SZ/16)
-
-GC_bool GC_block_nearly_full1(hhdr, pat1)
-hdr *hhdr;
-word pat1;
+GC_bool GC_block_empty(hdr *hhdr)
 {
-    unsigned i;
-    unsigned misses = 0;
-    GC_ASSERT((MARK_BITS_SZ & 1) == 0);
-    for (i = 0; i < MARK_BITS_SZ; ++i) {
-       if ((hhdr -> hb_marks[i] | ~pat1) != ONES) {
-           if (++misses > FULL_THRESHOLD) return FALSE;
-       }
-    }
-    return TRUE;
+    return (hhdr -> hb_n_marks == 0);
 }
 
-/*
- * Test whether the same repeating 3 word pattern occurs in nearly
- * all the mark bit slots.
- * This is used as a heuristic, so we're a bit sloppy and ignore
- * the last one or two words.
- */
-GC_bool GC_block_nearly_full3(hhdr, pat1, pat2, pat3)
-hdr *hhdr;
-word pat1, pat2, pat3;
+GC_bool GC_block_nearly_full(hdr *hhdr)
 {
-    unsigned i;
-    unsigned misses = 0;
-
-    if (MARK_BITS_SZ < 4) {
-      return DONT_KNOW;
-    }
-    for (i = 0; i < MARK_BITS_SZ - 2; i += 3) {
-       if ((hhdr -> hb_marks[i] | ~pat1) != ONES) {
-           if (++misses > FULL_THRESHOLD) return FALSE;
-       }
-       if ((hhdr -> hb_marks[i+1] | ~pat2) != ONES) {
-           if (++misses > FULL_THRESHOLD) return FALSE;
-       }
-       if ((hhdr -> hb_marks[i+2] | ~pat3) != ONES) {
-           if (++misses > FULL_THRESHOLD) return FALSE;
-       }
-    }
-    return TRUE;
+    return (hhdr -> hb_n_marks > 7 * HBLK_OBJS(hhdr -> hb_sz)/8);
 }
 
-/* Check whether a small object block is nearly full by looking at only */
-/* the mark bits.                                                      */
-/* We manually precomputed the mark bit patterns that need to be       */
-/* checked for, and we give up on the ones that are unlikely to occur, */
-/* or have period > 3.                                                 */
-/* This would be a lot easier with a mark bit per object instead of per        */
-/* word, but that would rewuire computing object numbers in the mark   */
-/* loop, which would require different data structures ...             */
-GC_bool GC_block_nearly_full(hhdr)
-hdr *hhdr;
-{
-    int sz = hhdr -> hb_sz;
+/* FIXME: This should perhaps again be specialized for USE_MARK_BYTES  */
+/* and USE_MARK_BITS cases.                                            */
 
-#   if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
-      return DONT_KNOW;        /* Shouldn't be used in any standard config.    */
-#   endif
-#   if CPP_WORDSZ == 32
-      switch(sz) {
-        case 1:
-         return GC_block_nearly_full1(hhdr, 0xffffffffl);
-       case 2:
-         return GC_block_nearly_full1(hhdr, 0x55555555l);
-       case 4:
-         return GC_block_nearly_full1(hhdr, 0x11111111l);
-       case 6:
-         return GC_block_nearly_full3(hhdr, 0x41041041l,
-                                             0x10410410l,
-                                              0x04104104l);
-       case 8:
-         return GC_block_nearly_full1(hhdr, 0x01010101l);
-       case 12:
-         return GC_block_nearly_full3(hhdr, 0x01001001l,
-                                             0x10010010l,
-                                              0x00100100l);
-       case 16:
-         return GC_block_nearly_full1(hhdr, 0x00010001l);
-       case 32:
-         return GC_block_nearly_full1(hhdr, 0x00000001l);
-       default:
-         return DONT_KNOW;
-      }
-#   endif
-#   if CPP_WORDSZ == 64
-      switch(sz) {
-        case 1:
-         return GC_block_nearly_full1(hhdr, 0xffffffffffffffffl);
-       case 2:
-         return GC_block_nearly_full1(hhdr, 0x5555555555555555l);
-       case 4:
-         return GC_block_nearly_full1(hhdr, 0x1111111111111111l);
-       case 6:
-         return GC_block_nearly_full3(hhdr, 0x1041041041041041l,
-                                              0x4104104104104104l,
-                                                0x0410410410410410l);
-       case 8:
-         return GC_block_nearly_full1(hhdr, 0x0101010101010101l);
-       case 12:
-         return GC_block_nearly_full3(hhdr, 0x1001001001001001l,
-                                              0x0100100100100100l,
-                                                0x0010010010010010l);
-       case 16:
-         return GC_block_nearly_full1(hhdr, 0x0001000100010001l);
-       case 32:
-         return GC_block_nearly_full1(hhdr, 0x0000000100000001l);
-       default:
-         return DONT_KNOW;
-      }
-#   endif
-}
-#endif /* !SMALL_CONFIG  && !USE_MARK_BYTES */
-
-/* We keep track of reclaimed memory if we are either asked to, or     */
-/* we are using the parallel marker.  In the latter case, we assume    */
-/* that most allocation goes through GC_malloc_many for scalability.   */
-/* GC_malloc_many needs the count anyway.                              */
-# if defined(GATHERSTATS) || defined(PARALLEL_MARK)
-#   define INCR_WORDS(sz) n_words_found += (sz)
-#   define COUNT_PARAM , count
-#   define COUNT_ARG , count
-#   define COUNT_DECL signed_word * count;
-#   define NWORDS_DECL signed_word n_words_found = 0;
-#   define COUNT_UPDATE *count += n_words_found;
-#   define MEM_FOUND_ADDR , &GC_mem_found
-# else
-#   define INCR_WORDS(sz)
-#   define COUNT_PARAM
-#   define COUNT_ARG
-#   define COUNT_DECL
-#   define NWORDS_DECL
-#   define COUNT_UPDATE
-#   define MEM_FOUND_ADDR
-# endif
 /*
  * Restore unmarked small objects in h of size sz to the object
  * free list.  Returns the new list.
- * Clears unmarked objects.
+ * Clears unmarked objects.  Sz is in bytes.
  */
 /*ARGSUSED*/
-ptr_t GC_reclaim_clear(hbp, hhdr, sz, list COUNT_PARAM)
-register struct hblk *hbp;     /* ptr to current heap block            */
-register hdr * hhdr;
-register ptr_t list;
-register word sz;
-COUNT_DECL
+ptr_t GC_reclaim_clear(struct hblk *hbp, hdr *hhdr, size_t sz,
+                      ptr_t list, signed_word *count)
 {
-    register int word_no;
-    register word *p, *q, *plim;
-    NWORDS_DECL
+    word bit_no = 0;
+    word *p, *q, *plim;
+    signed_word n_bytes_found = 0;
     
     GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp));
+    GC_ASSERT(sz == hhdr -> hb_sz);
+    GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0);
     p = (word *)(hbp->hb_body);
-    word_no = 0;
-    plim = (word *)((((word)hbp) + HBLKSIZE)
-                  - WORDS_TO_BYTES(sz));
+    plim = (word *)(hbp->hb_body + HBLKSIZE - sz);
 
     /* go through all words in block */
        while( p <= plim )  {
-           if( mark_bit_from_hdr(hhdr, word_no) ) {
-               p += sz;
+           if( mark_bit_from_hdr(hhdr, bit_no) ) {
+               p = (word *)((ptr_t)p + sz);
            } else {
-               INCR_WORDS(sz);
+               n_bytes_found += sz;
                /* object is available - put on list */
                    obj_link(p) = list;
                    list = ((ptr_t)p);
                /* Clear object, advance p to next object in the process */
-                   q = p + sz;
+                   q = (word *)((ptr_t)p + sz);
 #                  ifdef USE_MARK_BYTES
                      GC_ASSERT(!(sz & 1)
                                && !((word)p & (2 * sizeof(word) - 1)));
@@ -353,362 +151,79 @@ COUNT_DECL
                      }
 #                  endif
            }
-           word_no += sz;
-       }
-    COUNT_UPDATE
-    return(list);
-}
-
-#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
-
-/*
- * A special case for 2 word composite objects (e.g. cons cells):
- */
-/*ARGSUSED*/
-ptr_t GC_reclaim_clear2(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp;     /* ptr to current heap block            */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
-{
-    register word * mark_word_addr = &(hhdr->hb_marks[0]);
-    register word *p, *plim;
-    register word mark_word;
-    register int i;
-    NWORDS_DECL
-#   define DO_OBJ(start_displ) \
-       if (!(mark_word & ((word)1 << start_displ))) { \
-           p[start_displ] = (word)list; \
-           list = (ptr_t)(p+start_displ); \
-           p[start_displ+1] = 0; \
-           INCR_WORDS(2); \
-       }
-    
-    p = (word *)(hbp->hb_body);
-    plim = (word *)(((word)hbp) + HBLKSIZE);
-
-    /* go through all words in block */
-       while( p < plim )  {
-           mark_word = *mark_word_addr++;
-           for (i = 0; i < WORDSZ; i += 8) {
-               DO_OBJ(0);
-               DO_OBJ(2);
-               DO_OBJ(4);
-               DO_OBJ(6);
-               p += 8;
-               mark_word >>= 8;
-           }
-       }               
-    COUNT_UPDATE
-    return(list);
-#   undef DO_OBJ
-}
-
-/*
- * Another special case for 4 word composite objects:
- */
-/*ARGSUSED*/
-ptr_t GC_reclaim_clear4(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp;     /* ptr to current heap block            */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
-{
-    register word * mark_word_addr = &(hhdr->hb_marks[0]);
-    register word *p, *plim;
-    register word mark_word;
-    NWORDS_DECL
-#   define DO_OBJ(start_displ) \
-       if (!(mark_word & ((word)1 << start_displ))) { \
-           p[start_displ] = (word)list; \
-           list = (ptr_t)(p+start_displ); \
-           p[start_displ+1] = 0; \
-           CLEAR_DOUBLE(p + start_displ + 2); \
-           INCR_WORDS(4); \
+           bit_no += MARK_BIT_OFFSET(sz);
        }
-    
-    p = (word *)(hbp->hb_body);
-    plim = (word *)(((word)hbp) + HBLKSIZE);
-
-    /* go through all words in block */
-       while( p < plim )  {
-           mark_word = *mark_word_addr++;
-           DO_OBJ(0);
-           DO_OBJ(4);
-           DO_OBJ(8);
-           DO_OBJ(12);
-           DO_OBJ(16);
-           DO_OBJ(20);
-           DO_OBJ(24);
-           DO_OBJ(28);
-#          if CPP_WORDSZ == 64
-             DO_OBJ(32);
-             DO_OBJ(36);
-             DO_OBJ(40);
-             DO_OBJ(44);
-             DO_OBJ(48);
-             DO_OBJ(52);
-             DO_OBJ(56);
-             DO_OBJ(60);
-#          endif
-           p += WORDSZ;
-       }               
-    COUNT_UPDATE
+    *count += n_bytes_found;
     return(list);
-#   undef DO_OBJ
 }
 
-#endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
-
 /* The same thing, but don't clear objects: */
 /*ARGSUSED*/
-ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_PARAM)
-register struct hblk *hbp;     /* ptr to current heap block            */
-register hdr * hhdr;
-register ptr_t list;
-register word sz;
-COUNT_DECL
+ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, size_t sz,
+                       ptr_t list, signed_word *count)
 {
-    register int word_no = 0;
-    register word *p, *plim;
-    NWORDS_DECL
+    word bit_no = 0;
+    word *p, *plim;
+    signed_word n_bytes_found = 0;
     
+    GC_ASSERT(sz == hhdr -> hb_sz);
     p = (word *)(hbp->hb_body);
-    plim = (word *)((((word)hbp) + HBLKSIZE)
-                  - WORDS_TO_BYTES(sz));
+    plim = (word *)((ptr_t)hbp + HBLKSIZE - sz);
 
     /* go through all words in block */
        while( p <= plim )  {
-           if( !mark_bit_from_hdr(hhdr, word_no) ) {
-               INCR_WORDS(sz);
+           if( !mark_bit_from_hdr(hhdr, bit_no) ) {
+               n_bytes_found += sz;
                /* object is available - put on list */
                    obj_link(p) = list;
                    list = ((ptr_t)p);
            }
-           p += sz;
-           word_no += sz;
+           p = (word *)((ptr_t)p + sz);
+           bit_no += MARK_BIT_OFFSET(sz);
        }
-    COUNT_UPDATE
+    *count += n_bytes_found;
     return(list);
 }
 
 /* Don't really reclaim objects, just check for unmarked ones: */
 /*ARGSUSED*/
-void GC_reclaim_check(hbp, hhdr, sz)
-register struct hblk *hbp;     /* ptr to current heap block            */
-register hdr * hhdr;
-register word sz;
+void GC_reclaim_check(struct hblk *hbp, hdr *hhdr, word sz)
 {
-    register int word_no = 0;
-    register word *p, *plim;
-#   ifdef GATHERSTATS
-        register int n_words_found = 0;
-#   endif
+    word bit_no = 0;
+    ptr_t p, plim;
     
-    p = (word *)(hbp->hb_body);
-    plim = (word *)((((word)hbp) + HBLKSIZE)
-                  - WORDS_TO_BYTES(sz));
+    GC_ASSERT(sz == hhdr -> hb_sz);
+    p = hbp->hb_body;
+    plim = p + HBLKSIZE - sz;
 
     /* go through all words in block */
        while( p <= plim )  {
-           if( !mark_bit_from_hdr(hhdr, word_no) ) {
-               FOUND_FREE(hbp, word_no);
+           if( !mark_bit_from_hdr(hhdr, bit_no) ) {
+               GC_add_leaked(p);
            }
            p += sz;
-           word_no += sz;
-       }
-}
-
-#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
-/*
- * Another special case for 2 word atomic objects:
- */
-/*ARGSUSED*/
-ptr_t GC_reclaim_uninit2(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp;     /* ptr to current heap block            */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
-{
-    register word * mark_word_addr = &(hhdr->hb_marks[0]);
-    register word *p, *plim;
-    register word mark_word;
-    register int i;
-    NWORDS_DECL
-#   define DO_OBJ(start_displ) \
-       if (!(mark_word & ((word)1 << start_displ))) { \
-           p[start_displ] = (word)list; \
-           list = (ptr_t)(p+start_displ); \
-           INCR_WORDS(2); \
-       }
-    
-    p = (word *)(hbp->hb_body);
-    plim = (word *)(((word)hbp) + HBLKSIZE);
-
-    /* go through all words in block */
-       while( p < plim )  {
-           mark_word = *mark_word_addr++;
-           for (i = 0; i < WORDSZ; i += 8) {
-               DO_OBJ(0);
-               DO_OBJ(2);
-               DO_OBJ(4);
-               DO_OBJ(6);
-               p += 8;
-               mark_word >>= 8;
-           }
-       }               
-    COUNT_UPDATE
-    return(list);
-#   undef DO_OBJ
-}
-
-/*
- * Another special case for 4 word atomic objects:
- */
-/*ARGSUSED*/
-ptr_t GC_reclaim_uninit4(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp;     /* ptr to current heap block            */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
-{
-    register word * mark_word_addr = &(hhdr->hb_marks[0]);
-    register word *p, *plim;
-    register word mark_word;
-    NWORDS_DECL
-#   define DO_OBJ(start_displ) \
-       if (!(mark_word & ((word)1 << start_displ))) { \
-           p[start_displ] = (word)list; \
-           list = (ptr_t)(p+start_displ); \
-           INCR_WORDS(4); \
-       }
-    
-    p = (word *)(hbp->hb_body);
-    plim = (word *)(((word)hbp) + HBLKSIZE);
-
-    /* go through all words in block */
-       while( p < plim )  {
-           mark_word = *mark_word_addr++;
-           DO_OBJ(0);
-           DO_OBJ(4);
-           DO_OBJ(8);
-           DO_OBJ(12);
-           DO_OBJ(16);
-           DO_OBJ(20);
-           DO_OBJ(24);
-           DO_OBJ(28);
-#          if CPP_WORDSZ == 64
-             DO_OBJ(32);
-             DO_OBJ(36);
-             DO_OBJ(40);
-             DO_OBJ(44);
-             DO_OBJ(48);
-             DO_OBJ(52);
-             DO_OBJ(56);
-             DO_OBJ(60);
-#          endif
-           p += WORDSZ;
-       }               
-    COUNT_UPDATE
-    return(list);
-#   undef DO_OBJ
-}
-
-/* Finally the one word case, which never requires any clearing: */
-/*ARGSUSED*/
-ptr_t GC_reclaim1(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp;     /* ptr to current heap block            */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
-{
-    register word * mark_word_addr = &(hhdr->hb_marks[0]);
-    register word *p, *plim;
-    register word mark_word;
-    register int i;
-    NWORDS_DECL
-#   define DO_OBJ(start_displ) \
-       if (!(mark_word & ((word)1 << start_displ))) { \
-           p[start_displ] = (word)list; \
-           list = (ptr_t)(p+start_displ); \
-           INCR_WORDS(1); \
+           bit_no += MARK_BIT_OFFSET(sz);
        }
-    
-    p = (word *)(hbp->hb_body);
-    plim = (word *)(((word)hbp) + HBLKSIZE);
-
-    /* go through all words in block */
-       while( p < plim )  {
-           mark_word = *mark_word_addr++;
-           for (i = 0; i < WORDSZ; i += 4) {
-               DO_OBJ(0);
-               DO_OBJ(1);
-               DO_OBJ(2);
-               DO_OBJ(3);
-               p += 4;
-               mark_word >>= 4;
-           }
-       }               
-    COUNT_UPDATE
-    return(list);
-#   undef DO_OBJ
 }
 
-#endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
 
 /*
  * Generic procedure to rebuild a free list in hbp.
  * Also called directly from GC_malloc_many.
+ * Sz is now in bytes.
  */
-ptr_t GC_reclaim_generic(hbp, hhdr, sz, init, list COUNT_PARAM)
-struct hblk *hbp;      /* ptr to current heap block            */
-hdr * hhdr;
-GC_bool init;
-ptr_t list;
-word sz;
-COUNT_DECL
+ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
+                        GC_bool init, ptr_t list, signed_word *count)
 {
     ptr_t result = list;
 
     GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr);
     GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */);
     if (init) {
-      switch(sz) {
-#      if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
-        case 1:
-           /* We now issue the hint even if GC_nearly_full returned    */
-           /* DONT_KNOW.                                               */
-            result = GC_reclaim1(hbp, hhdr, list COUNT_ARG);
-            break;
-        case 2:
-            result = GC_reclaim_clear2(hbp, hhdr, list COUNT_ARG);
-            break;
-        case 4:
-            result = GC_reclaim_clear4(hbp, hhdr, list COUNT_ARG);
-            break;
-#      endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
-        default:
-            result = GC_reclaim_clear(hbp, hhdr, sz, list COUNT_ARG);
-            break;
-      }
+      result = GC_reclaim_clear(hbp, hhdr, sz, list, count);
     } else {
       GC_ASSERT((hhdr)->hb_descr == 0 /* Pointer-free block */);
-      switch(sz) {
-#      if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
-        case 1:
-            result = GC_reclaim1(hbp, hhdr, list COUNT_ARG);
-            break;
-        case 2:
-            result = GC_reclaim_uninit2(hbp, hhdr, list COUNT_ARG);
-            break;
-        case 4:
-            result = GC_reclaim_uninit4(hbp, hhdr, list COUNT_ARG);
-            break;
-#      endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
-        default:
-            result = GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_ARG);
-            break;
-      }
+      result = GC_reclaim_uninit(hbp, hhdr, sz, list, count);
     } 
     if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr);
     return result;
@@ -720,16 +235,14 @@ COUNT_DECL
  * If entirely empty blocks are to be completely deallocated, then
  * caller should perform that check.
  */
-void GC_reclaim_small_nonempty_block(hbp, report_if_found COUNT_PARAM)
-register struct hblk *hbp;     /* ptr to current heap block            */
-int report_if_found;           /* Abort if a reclaimable object is found */
-COUNT_DECL
+void GC_reclaim_small_nonempty_block(struct hblk *hbp,
+                                    int report_if_found, signed_word *count)
 {
     hdr *hhdr = HDR(hbp);
-    word sz = hhdr -> hb_sz;
+    size_t sz = hhdr -> hb_sz;
     int kind = hhdr -> hb_obj_kind;
     struct obj_kind * ok = &GC_obj_kinds[kind];
-    ptr_t * flh = &(ok -> ok_freelist[sz]);
+    void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
     
     hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
 
@@ -738,7 +251,7 @@ COUNT_DECL
     } else {
         *flh = GC_reclaim_generic(hbp, hhdr, sz,
                                  (ok -> ok_init || GC_debugging_started),
-                                 *flh MEM_FOUND_ADDR);
+                                 *flh, &GC_bytes_found);
     }
 }
 
@@ -750,51 +263,59 @@ COUNT_DECL
  * If report_if_found is TRUE, then process any block immediately, and
  * simply report free objects; do not actually reclaim them.
  */
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_reclaim_block(register struct hblk *hbp, word report_if_found)
-# else
-    void GC_reclaim_block(hbp, report_if_found)
-    register struct hblk *hbp; /* ptr to current heap block            */
-    word report_if_found;      /* Abort if a reclaimable object is found */
-# endif
+void GC_reclaim_block(struct hblk *hbp, word report_if_found)
 {
-    register hdr * hhdr;
-    register word sz;          /* size of objects in current block     */
-    register struct obj_kind * ok;
+    hdr * hhdr = HDR(hbp);
+    size_t sz = hhdr -> hb_sz; /* size of objects in current block     */
+    struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
     struct hblk ** rlh;
 
-    hhdr = HDR(hbp);
-    sz = hhdr -> hb_sz;
-    ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
-
-    if( sz > MAXOBJSZ ) {  /* 1 big object */
+    if( sz > MAXOBJBYTES ) {  /* 1 big object */
         if( !mark_bit_from_hdr(hhdr, 0) ) {
            if (report_if_found) {
-             FOUND_FREE(hbp, 0);
+             GC_add_leaked((ptr_t)hbp);
            } else {
-             word blocks = OBJ_SZ_TO_BLOCKS(sz);
+             size_t blocks = OBJ_SZ_TO_BLOCKS(sz);
              if (blocks > 1) {
                GC_large_allocd_bytes -= blocks * HBLKSIZE;
              }
-#            ifdef GATHERSTATS
-               GC_mem_found += sz;
-#            endif
+             GC_bytes_found += sz;
              GC_freehblk(hbp);
            }
+       } else {
+           if (hhdr -> hb_descr != 0) {
+             GC_composite_in_use += sz;
+           } else {
+             GC_atomic_in_use += sz;
+           }
        }
     } else {
         GC_bool empty = GC_block_empty(hhdr);
+#      ifdef PARALLEL_MARK
+         /* Count can be low or one too high because we sometimes      */
+         /* have to ignore decrements.  Objects can also potentially   */
+         /* be repeatedly marked by each marker.                       */
+         /* Here we assume two markers, but this is extremely          */
+         /* unlikely to fail spuriously with more.  And if it does, it */
+         /* should be looked at.                                       */
+         GC_ASSERT(hhdr -> hb_n_marks <= 2 * (HBLKSIZE/sz + 1) + 16);
+#      else
+         GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE);
+#      endif
+       if (hhdr -> hb_descr != 0) {
+         GC_composite_in_use += sz * hhdr -> hb_n_marks;
+       } else {
+         GC_atomic_in_use += sz * hhdr -> hb_n_marks;
+       }
         if (report_if_found) {
-         GC_reclaim_small_nonempty_block(hbp, (int)report_if_found
-                                         MEM_FOUND_ADDR);
+         GC_reclaim_small_nonempty_block(hbp, (int)report_if_found,
+                                         &GC_bytes_found);
         } else if (empty) {
-#        ifdef GATHERSTATS
-            GC_mem_found += BYTES_TO_WORDS(HBLKSIZE);
-#        endif
+          GC_bytes_found += HBLKSIZE;
           GC_freehblk(hbp);
         } else if (TRUE != GC_block_nearly_full(hhdr)){
           /* group of smaller objects, enqueue the real work */
-          rlh = &(ok -> ok_reclaim_list[sz]);
+          rlh = &(ok -> ok_reclaim_list[BYTES_TO_GRANULES(sz)]);
           hhdr -> hb_next = *rlh;
           *rlh = hbp;
         } /* else not worth salvaging. */
@@ -819,26 +340,28 @@ struct Print_stats
 #ifdef USE_MARK_BYTES
 
 /* Return the number of set mark bits in the given header      */
-int GC_n_set_marks(hhdr)
-hdr * hhdr;
+int GC_n_set_marks(hdr *hhdr)
 {
-    register int result = 0;
-    register int i;
-    
-    for (i = 0; i < MARK_BITS_SZ; i++) {
+    int result = 0;
+    int i;
+    size_t sz = hhdr -> hb_sz;
+    int offset = MARK_BIT_OFFSET(sz);
+    int limit = FINAL_MARK_BIT(sz);
+
+    for (i = 0; i < limit; i += offset) {
         result += hhdr -> hb_marks[i];
     }
+    GC_ASSERT(hhdr -> hb_marks[limit]);
     return(result);
 }
 
 #else
 
 /* Number of set bits in a word.  Not performance critical.    */
-static int set_bits(n)
-word n;
+static int set_bits(word n)
 {
-    register word m = n;
-    register int result = 0;
+    word m = n;
+    int result = 0;
     
     while (m > 0) {
        if (m & 1) result++;
@@ -848,40 +371,53 @@ word n;
 }
 
 /* Return the number of set mark bits in the given header      */
-int GC_n_set_marks(hhdr)
-hdr * hhdr;
+int GC_n_set_marks(hdr *hhdr)
 {
-    register int result = 0;
-    register int i;
+    int result = 0;
+    int i;
+    int n_mark_words;
+#   ifdef MARK_BIT_PER_OBJ
+      int n_objs = HBLK_OBJS(hhdr -> hb_sz);
     
-    for (i = 0; i < MARK_BITS_SZ; i++) {
+      if (0 == n_objs) n_objs = 1;
+      n_mark_words = divWORDSZ(n_objs + WORDSZ - 1);
+#   else /* MARK_BIT_PER_GRANULE */
+      n_mark_words = MARK_BITS_SZ;
+#   endif
+    for (i = 0; i < n_mark_words - 1; i++) {
         result += set_bits(hhdr -> hb_marks[i]);
     }
-    return(result);
+#   ifdef MARK_BIT_PER_OBJ
+      result += set_bits((hhdr -> hb_marks[n_mark_words - 1])
+                        << (n_mark_words * WORDSZ - n_objs));
+#   else
+      result += set_bits(hhdr -> hb_marks[n_mark_words - 1]);
+#   endif
+    return(result - 1);
 }
 
 #endif /* !USE_MARK_BYTES  */
 
 /*ARGSUSED*/
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_print_block_descr(struct hblk *h, word dummy)
-# else
-    void GC_print_block_descr(h, dummy)
-    struct hblk *h;
-    word dummy;
-# endif
+void GC_print_block_descr(struct hblk *h, word /* struct PrintStats */ raw_ps)
 {
-    register hdr * hhdr = HDR(h);
-    register size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz);
+    hdr * hhdr = HDR(h);
+    size_t bytes = hhdr -> hb_sz;
     struct Print_stats *ps;
+    unsigned n_marks = GC_n_set_marks(hhdr);
     
-    GC_printf3("(%lu:%lu,%lu)", (unsigned long)(hhdr -> hb_obj_kind),
-                               (unsigned long)bytes,
-                               (unsigned long)(GC_n_set_marks(hhdr)));
+    if (hhdr -> hb_n_marks != n_marks) {
+      GC_printf("(%u:%u,%u!=%u)", hhdr -> hb_obj_kind,
+                                 bytes,
+                                 hhdr -> hb_n_marks, n_marks);
+    } else {
+      GC_printf("(%u:%u,%u)", hhdr -> hb_obj_kind,
+                             bytes, n_marks);
+    }
     bytes += HBLKSIZE-1;
     bytes &= ~(HBLKSIZE-1);
 
-    ps = (struct Print_stats *)dummy;
+    ps = (struct Print_stats *)raw_ps;
     ps->total_bytes += bytes;
     ps->number_of_blocks++;
 }
@@ -890,13 +426,32 @@ void GC_print_block_list()
 {
     struct Print_stats pstats;
 
-    GC_printf1("(kind(0=ptrfree,1=normal,2=unc.,%lu=stubborn):size_in_bytes, #_marks_set)\n", STUBBORN);
+    GC_printf("(kind(0=ptrfree,1=normal,2=unc.):size_in_bytes, #_marks_set)\n");
     pstats.number_of_blocks = 0;
     pstats.total_bytes = 0;
     GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
-    GC_printf2("\nblocks = %lu, bytes = %lu\n",
-              (unsigned long)pstats.number_of_blocks,
-              (unsigned long)pstats.total_bytes);
+    GC_printf("\nblocks = %lu, bytes = %lu\n",
+             (unsigned long)pstats.number_of_blocks,
+             (unsigned long)pstats.total_bytes);
+}
+
+/* Currently for debugger use only: */
+void GC_print_free_list(int kind, size_t sz_in_granules)
+{
+    struct obj_kind * ok = &GC_obj_kinds[kind];
+    ptr_t flh = ok -> ok_freelist[sz_in_granules];
+    struct hblk *lastBlock = 0;
+    int n = 0;
+
+    while (flh){
+        struct hblk *block = HBLKPTR(flh);
+        if (block != lastBlock){
+            GC_printf("\nIn heap block at 0x%x:\n\t", block);
+            lastBlock = block;
+        }
+        GC_printf("%d: 0x%x;", ++n, flh);
+        flh = obj_link(flh);
+    }
 }
 
 #endif /* NO_DEBUGGING */
@@ -908,10 +463,9 @@ void GC_print_block_list()
  * since may otherwise end up with dangling "descriptor" pointers.
  * It may help for other pointer-containing objects.
  */
-void GC_clear_fl_links(flp)
-ptr_t *flp;
+void GC_clear_fl_links(void **flp)
 {
-    ptr_t next = *flp;
+    void *next = *flp;
 
     while (0 != next) {
        *flp = 0;
@@ -924,18 +478,20 @@ ptr_t *flp;
  * Perform GC_reclaim_block on the entire heap, after first clearing
  * small object free lists (if we are not just looking for leaks).
  */
-void GC_start_reclaim(report_if_found)
-int report_if_found;           /* Abort if a GC_reclaimable object is found */
+void GC_start_reclaim(GC_bool report_if_found)
 {
-    int kind;
+    unsigned kind;
     
 #   if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
       GC_ASSERT(0 == GC_fl_builder_count);
 #   endif
+    /* Reset in use counters.  GC_reclaim_block recomputes them. */
+      GC_composite_in_use = 0;
+      GC_atomic_in_use = 0;
     /* Clear reclaim- and free-lists */
       for (kind = 0; kind < GC_n_kinds; kind++) {
-        ptr_t *fop;
-        ptr_t *lim;
+        void **fop;
+        void **lim;
         struct hblk ** rlp;
         struct hblk ** rlim;
         struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
@@ -943,7 +499,7 @@ int report_if_found;                /* Abort if a GC_reclaimable object is found */
         
         if (rlist == 0) continue;      /* This kind not used.  */
         if (!report_if_found) {
-            lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]);
+            lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJGRANULES+1]);
            for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) {
              if (*fop != 0) {
                if (should_clobber) {
@@ -955,16 +511,12 @@ int report_if_found;              /* Abort if a GC_reclaimable object is found */
            }
        } /* otherwise free list objects are marked,    */
          /* and its safe to leave them                 */
-       rlim = rlist + MAXOBJSZ+1;
+       rlim = rlist + MAXOBJGRANULES+1;
        for( rlp = rlist; rlp < rlim; rlp++ ) {
            *rlp = 0;
        }
       }
     
-#   ifdef PRINTBLOCKS
-        GC_printf0("GC_reclaim: current block sizes:\n");
-        GC_print_block_list();
-#   endif
 
   /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */
   /* or enqueue the block for later processing.                                   */
@@ -986,22 +538,20 @@ int report_if_found;              /* Abort if a GC_reclaimable object is found */
  * appropriate free list is nonempty, or there are no more blocks to
  * sweep.
  */
-void GC_continue_reclaim(sz, kind)
-word sz;       /* words */
-int kind;
+void GC_continue_reclaim(size_t sz /* granules */, int kind)
 {
-    register hdr * hhdr;
-    register struct hblk * hbp;
-    register struct obj_kind * ok = &(GC_obj_kinds[kind]);
+    hdr * hhdr;
+    struct hblk * hbp;
+    struct obj_kind * ok = &(GC_obj_kinds[kind]);
     struct hblk ** rlh = ok -> ok_reclaim_list;
-    ptr_t *flh = &(ok -> ok_freelist[sz]);
+    void **flh = &(ok -> ok_freelist[sz]);
     
     if (rlh == 0) return;      /* No blocks of this kind.      */
     rlh += sz;
     while ((hbp = *rlh) != 0) {
         hhdr = HDR(hbp);
         *rlh = hhdr -> hb_next;
-        GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR);
+        GC_reclaim_small_nonempty_block(hbp, FALSE, &GC_bytes_found);
         if (*flh != 0) break;
     }
 }
@@ -1015,29 +565,26 @@ int kind;
  * recently reclaimed, and discard the rest.
  * Stop_func may be 0.
  */
-GC_bool GC_reclaim_all(stop_func, ignore_old)
-GC_stop_func stop_func;
-GC_bool ignore_old;
+GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
 {
-    register word sz;
-    register int kind;
-    register hdr * hhdr;
-    register struct hblk * hbp;
-    register struct obj_kind * ok;
+    word sz;
+    unsigned kind;
+    hdr * hhdr;
+    struct hblk * hbp;
+    struct obj_kind * ok;
     struct hblk ** rlp;
     struct hblk ** rlh;
-#   ifdef PRINTTIMES
-       CLOCK_TYPE start_time;
-       CLOCK_TYPE done_time;
+    CLOCK_TYPE start_time;
+    CLOCK_TYPE done_time;
        
+    if (GC_print_stats == VERBOSE)
        GET_TIME(start_time);
-#   endif
     
     for (kind = 0; kind < GC_n_kinds; kind++) {
        ok = &(GC_obj_kinds[kind]);
        rlp = ok -> ok_reclaim_list;
        if (rlp == 0) continue;
-       for (sz = 1; sz <= MAXOBJSZ; sz++) {
+       for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
            rlh = rlp + sz;
            while ((hbp = *rlh) != 0) {
                if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
@@ -1049,15 +596,15 @@ GC_bool ignore_old;
                    /* It's likely we'll need it this time, too */
                    /* It's been touched recently, so this      */
                    /* shouldn't trigger paging.                */
-                   GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR);
+                   GC_reclaim_small_nonempty_block(hbp, FALSE, &GC_bytes_found);
                }
             }
         }
     }
-#   ifdef PRINTTIMES
+    if (GC_print_stats == VERBOSE) {
        GET_TIME(done_time);
-       GC_printf1("Disposing of reclaim lists took %lu msecs\n",
-                  MS_TIME_DIFF(done_time,start_time));
-#   endif
+       GC_log_printf("Disposing of reclaim lists took %lu msecs\n",
+                 MS_TIME_DIFF(done_time,start_time));
+    }
     return(TRUE);
 }
index 07686ef0808db48d17858c6930fc2b5da53e5f95..5a171df0cba5f7f728e0ec143377b9302419bbd2 100644 (file)
@@ -24,7 +24,7 @@
 #include <stdio.h>
 #include <setjmp.h>
 #include <string.h>
-#include "private/gcconfig.h"
+#include "private/gc_priv.h"
 
 #ifdef OS2
 /* GETPAGESIZE() is set to getpagesize() by default, but that  */
@@ -57,7 +57,7 @@ int * nested_sp()
     return(&dummy);
 }
 
-main()
+int main()
 {
        int dummy;
        long ps = GETPAGESIZE();
@@ -82,6 +82,9 @@ main()
        printf("A good guess for ALIGNMENT on this machine is %ld.\n",
               (unsigned long)(&(a.a_b))-(unsigned long)(&a));
        
+       printf("The following is a very dubious test of one root marking"
+              " strategy.\n");
+       printf("Results may not be accurate/useful:\n");
        /* Encourage the compiler to keep x in a callee-save register */
        x = 2*x-1;
        printf("");
@@ -89,21 +92,39 @@ main()
        setjmp(b);
        if (y == 1) {
            if (x == 2) {
-               printf("Generic mark_regs code probably wont work\n");
-#              if defined(SPARC) || defined(RS6000) || defined(VAX) || defined(MIPS) || defined(M68K) || defined(I386) || defined(NS32K) || defined(RT)
-                   printf("Assembly code supplied\n");
-#              else
-                   printf("Need assembly code\n");
-#              endif
+               printf("Setjmp-based generic mark_regs code probably wont work.\n");
+               printf("But we rarely try that anymore.  If you have getcontect()\n");
+               printf("this probably doesn't matter.\n");
            } else if (x == 1) {
-               printf("Generic mark_regs code may work\n");
+               printf("Setjmp-based register marking code may work.\n");
            } else {
-               printf("Very strange setjmp implementation\n");
+               printf("Very strange setjmp implementation.\n");
            }
        }
        y++;
        x = 2;
        if (y == 1) longjmp(b,1);
+       printf("Some GC internal configuration stuff: \n");
+       printf("\tWORDSZ = %d, ALIGNMENT = %d, GC_GRANULE_BYTES = %d\n",
+              WORDSZ, ALIGNMENT, GC_GRANULE_BYTES);
+       printf("\tUsing one mark ");
+#       if defined(USE_MARK_BYTES)
+         printf("byte");
+#      elif defined(USE_MARK_BITS)
+         printf("bit");
+#       endif
+       printf(" per ");
+#       if defined(MARK_BIT_PER_OBJ)
+         printf("object.\n");
+#      elif defined(MARK_BIT_PER_GRANULE)
+         printf("granule.\n");
+#      endif
+#      ifdef THREAD_LOCAL_ALLOC
+         printf("Thread local allocation enabled.\n");
+#      endif
+#      ifdef PARALLEL_MARK
+         printf("Parallel marking enabled.\n");
+#      endif
        return(0);
 }
 
diff --git a/src/mm/boehm-gc/solaris_pthreads.c b/src/mm/boehm-gc/solaris_pthreads.c
deleted file mode 100644 (file)
index 3dfcc03..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/* 
- * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose,  provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/*
- * Support code for Solaris threads.  Provides functionality we wish Sun
- * had provided.  Relies on some information we probably shouldn't rely on.
- * Modified by Peter C. for Solaris Posix Threads.
- */
-
-#include "config.h"
-
-# include "private/gc_priv.h"
-
-# if defined(GC_SOLARIS_PTHREADS)
-# include <pthread.h>
-# include <thread.h>
-# include <signal.h>
-# include <fcntl.h>
-# include <sys/types.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-# include <sys/resource.h>
-# include <sys/stat.h>
-# include <sys/syscall.h>
-# include <sys/procfs.h>
-# include <sys/lwp.h>
-# include <sys/reg.h>
-# define _CLASSIC_XOPEN_TYPES
-# include <unistd.h>
-# include <errno.h>
-# include "private/solaris_threads.h"
-# include <stdio.h>
-
-#undef pthread_join
-#undef pthread_create
-
-pthread_cond_t GC_prom_join_cv;                /* Broadcast when any thread terminates */
-pthread_cond_t GC_create_cv;           /* Signalled when a new undetached      */
-                               /* thread starts.                       */
-                               
-extern GC_bool GC_multithreaded;
-
-/* We use the allocation lock to protect thread-related data structures. */
-
-/* We stop the world using /proc primitives.  This makes some  */
-/* minimal assumptions about the threads implementation.       */
-/* We don't play by the rules, since the rules make this       */
-/* impossible (as of Solaris 2.3).  Also note that as of       */
-/* Solaris 2.3 the various thread and lwp suspension           */
-/* primitives failed to stop threads by the time the request   */
-/* is completed.                                               */
-
-
-
-int GC_pthread_join(pthread_t wait_for, void **status)
-{
-       return GC_thr_join((thread_t)wait_for, NULL, status);
-}
-
-
-int
-GC_pthread_create(pthread_t *new_thread,
-          const pthread_attr_t *attr_in,
-          void * (*thread_execp)(void *), void *arg)
-{
-    int result;
-    GC_thread t;
-    pthread_t my_new_thread;
-    pthread_attr_t  attr;
-    word my_flags = 0;
-    int  flag;
-    void * stack = 0;
-    size_t stack_size = 0;
-    int    n;
-    struct sched_param schedparam;
-   
-    (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_is_initialized) {
-           GC_init_inner();
-    }
-    GC_multithreaded++;
-           
-    if (stack == 0) {
-       if (stack_size == 0)
-               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();
-
-       stack = (void *)GC_stack_alloc(&stack_size);
-       if (stack == 0) {
-           GC_multithreaded--;
-           UNLOCK();
-           errno = ENOMEM;
-           return -1;
-       }
-    } else {
-       my_flags |= CLIENT_OWNS_STACK;
-    }
-    (void)pthread_attr_setstacksize(&attr, stack_size);
-    (void)pthread_attr_setstackaddr(&attr, stack);
-    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);
-    }
-    /*
-     * thr_create can call malloc(), which if redirected will
-     * attempt to acquire the allocation lock.
-     * Unlock here to prevent deadlock.
-     */
-
-
-#if 0
-#ifdef I386
-    UNLOCK();
-#endif
-#endif
-    result = 
-           pthread_create(&my_new_thread, &attr, thread_execp, arg);
-#if 0
-#ifdef I386
-    LOCK();
-#endif
-#endif
-    if (result == 0) {
-        t = GC_new_thread(my_new_thread);
-        t -> flags = my_flags;
-        if (!(my_flags & DETACHED)) cond_init(&(t->join_cv), USYNC_THREAD, 0);
-        t -> stack = stack;
-        t -> stack_size = stack_size;
-        if (new_thread != 0) *new_thread = my_new_thread;
-        pthread_cond_signal(&GC_create_cv);
-    } else {
-           if (!(my_flags & CLIENT_OWNS_STACK)) {
-                   GC_stack_free(stack, stack_size);
-           }        
-           GC_multithreaded--;
-    }
-    UNLOCK();
-    pthread_attr_destroy(&attr);
-    return(result);
-}
-
-# else
-
-#ifndef LINT
-  int GC_no_sunOS_pthreads;
-#endif
-
-# endif /* GC_SOLARIS_PTHREADS */
-
diff --git a/src/mm/boehm-gc/solaris_threads.c b/src/mm/boehm-gc/solaris_threads.c
deleted file mode 100644 (file)
index 8650f7b..0000000
+++ /dev/null
@@ -1,961 +0,0 @@
-/* 
- * Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose,  provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/*
- * Support code for Solaris threads.  Provides functionality we wish Sun
- * had provided.  Relies on some information we probably shouldn't rely on.
- */
-/* Boehm, September 14, 1994 4:44 pm PDT */
-
-#include "config.h"
-
-# include "private/gc_priv.h"
-
-# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS)
-# include "private/solaris_threads.h"
-# include <thread.h>
-# include <synch.h>
-# include <signal.h>
-# include <fcntl.h>
-# include <sys/types.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-# include <sys/resource.h>
-# include <sys/stat.h>
-# include <sys/syscall.h>
-# include <sys/procfs.h>
-# include <sys/lwp.h>
-# include <sys/reg.h>
-# define _CLASSIC_XOPEN_TYPES
-# include <unistd.h>
-# include <errno.h>
-
-#ifdef HANDLE_FORK
-  --> Not yet supported.  Try porting the code from linux_threads.c.
-#endif
-
-/*
- * This is the default size of the LWP arrays. If there are more LWPs
- * than this when a stop-the-world GC happens, set_max_lwps will be
- * called to cope.
- * This must be higher than the number of LWPs at startup time.
- * The threads library creates a thread early on, so the min. is 3
- */
-# define DEFAULT_MAX_LWPS      4
-
-#undef thr_join
-#undef thr_create
-#undef thr_suspend
-#undef thr_continue
-
-cond_t GC_prom_join_cv;                /* Broadcast when any thread terminates */
-cond_t GC_create_cv;           /* Signalled when a new undetached      */
-                               /* thread starts.                       */
-                               
-
-#ifdef MMAP_STACKS
-static int GC_zfd;
-#endif /* MMAP_STACKS */
-
-/* We use the allocation lock to protect thread-related data structures. */
-
-/* We stop the world using /proc primitives.  This makes some  */
-/* minimal assumptions about the threads implementation.       */
-/* We don't play by the rules, since the rules make this       */
-/* impossible (as of Solaris 2.3).  Also note that as of       */
-/* Solaris 2.3 the various thread and lwp suspension           */
-/* primitives failed to stop threads by the time the request   */
-/* is completed.                                               */
-
-
-static sigset_t old_mask;
-
-/* Sleep for n milliseconds, n < 1000  */
-void GC_msec_sleep(int n)
-{
-    struct timespec ts;
-                            
-    ts.tv_sec = 0;
-    ts.tv_nsec = 1000000*n;
-    if (syscall(SYS_nanosleep, &ts, 0) < 0) {
-       ABORT("nanosleep failed");
-    }
-}
-/* Turn off preemption;  gross but effective.                  */
-/* Caller has allocation lock.                         */
-/* Actually this is not needed under Solaris 2.3 and   */
-/* 2.4, but hopefully that'll change.                  */
-void preempt_off()
-{
-    sigset_t set;
-
-    (void)sigfillset(&set);
-    sigdelset(&set, SIGABRT);
-    syscall(SYS_sigprocmask, SIG_SETMASK, &set, &old_mask);
-}
-
-void preempt_on()
-{
-    syscall(SYS_sigprocmask, SIG_SETMASK, &old_mask, NULL);
-}
-
-int GC_main_proc_fd = -1;
-
-
-struct lwp_cache_entry {
-    lwpid_t lc_id;
-    int lc_descr;      /* /proc file descriptor.       */
-}  GC_lwp_cache_default[DEFAULT_MAX_LWPS];
-
-static int max_lwps = DEFAULT_MAX_LWPS;
-static struct lwp_cache_entry *GC_lwp_cache = GC_lwp_cache_default;
-
-static prgregset_t GC_lwp_registers_default[DEFAULT_MAX_LWPS];
-static prgregset_t *GC_lwp_registers = GC_lwp_registers_default;
-
-/* Return a file descriptor for the /proc entry corresponding  */
-/* to the given lwp.  The file descriptor may be stale if the  */
-/* lwp exited and a new one was forked.                                */
-static int open_lwp(lwpid_t id)
-{
-    int result;
-    static int next_victim = 0;
-    register int i;
-    
-    for (i = 0; i < max_lwps; i++) {
-       if (GC_lwp_cache[i].lc_id == id) return(GC_lwp_cache[i].lc_descr);
-    }
-    result = syscall(SYS_ioctl, GC_main_proc_fd, PIOCOPENLWP, &id);
-    /*
-     * If PIOCOPENLWP fails, try closing fds in the cache until it succeeds.
-     */
-    if (result < 0 && errno == EMFILE) {
-           for (i = 0; i < max_lwps; i++) {
-               if (GC_lwp_cache[i].lc_id != 0) {
-                       (void)syscall(SYS_close, GC_lwp_cache[i].lc_descr);
-                       result = syscall(SYS_ioctl, GC_main_proc_fd, PIOCOPENLWP, &id);
-                       if (result >= 0 || (result < 0 && errno != EMFILE))
-                               break;
-               }
-           }
-    }
-    if (result < 0) {
-       if (errno == EMFILE) {
-               ABORT("Too many open files");
-       }
-        return(-1) /* exited? */;
-    }
-    if (GC_lwp_cache[next_victim].lc_id != 0)
-        (void)syscall(SYS_close, GC_lwp_cache[next_victim].lc_descr);
-    GC_lwp_cache[next_victim].lc_id = id;
-    GC_lwp_cache[next_victim].lc_descr = result;
-    if (++next_victim >= max_lwps)
-       next_victim = 0;
-    return(result);
-}
-
-static void uncache_lwp(lwpid_t id)
-{
-    register int i;
-    
-    for (i = 0; i < max_lwps; i++) {
-       if (GC_lwp_cache[i].lc_id == id) {
-           (void)syscall(SYS_close, GC_lwp_cache[id].lc_descr);
-           GC_lwp_cache[i].lc_id = 0;
-           break;
-       }
-    }
-}
-       /* Sequence of current lwp ids  */
-static lwpid_t GC_current_ids_default[DEFAULT_MAX_LWPS + 1];
-static lwpid_t *GC_current_ids = GC_current_ids_default;
-
-       /* Temporary used below (can be big if large number of LWPs) */
-static lwpid_t last_ids_default[DEFAULT_MAX_LWPS + 1];
-static lwpid_t *last_ids = last_ids_default;
-
-
-#define ROUNDUP(n)    WORDS_TO_BYTES(ROUNDED_UP_WORDS(n))
-
-static void set_max_lwps(GC_word n)
-{
-    char *mem;
-    char *oldmem;
-    int required_bytes = ROUNDUP(n * sizeof(struct lwp_cache_entry))
-       + ROUNDUP(n * sizeof(prgregset_t))
-       + ROUNDUP((n + 1) * sizeof(lwpid_t))
-       + ROUNDUP((n + 1) * sizeof(lwpid_t));
-
-    GC_expand_hp_inner(divHBLKSZ((word)required_bytes));
-    oldmem = mem = GC_scratch_alloc(required_bytes);
-    if (0 == mem) ABORT("No space for lwp data structures");
-
-    /*
-     * We can either flush the old lwp cache or copy it over. Do the latter.
-     */
-    memcpy(mem, GC_lwp_cache, max_lwps * sizeof(struct lwp_cache_entry));
-    GC_lwp_cache = (struct lwp_cache_entry*)mem;
-    mem += ROUNDUP(n * sizeof(struct lwp_cache_entry));
-
-    BZERO(GC_lwp_registers, max_lwps * sizeof(GC_lwp_registers[0]));
-    GC_lwp_registers = (prgregset_t *)mem;
-    mem += ROUNDUP(n * sizeof(prgregset_t));
-
-
-    GC_current_ids = (lwpid_t *)mem;
-    mem += ROUNDUP((n + 1) * sizeof(lwpid_t));
-
-    last_ids = (lwpid_t *)mem;
-    mem += ROUNDUP((n + 1)* sizeof(lwpid_t));
-
-    if (mem > oldmem + required_bytes)
-       ABORT("set_max_lwps buffer overflow");
-
-    max_lwps = n;
-}
-
-
-/* Stop all lwps in process.  Assumes preemption is off.       */
-/* Caller has allocation lock (and any other locks he may      */
-/* need).                                                      */
-static void stop_all_lwps()
-{
-    int lwp_fd;
-    char buf[30];
-    prstatus_t status;
-    register int i;
-    GC_bool changed;
-    lwpid_t me = _lwp_self();
-
-    if (GC_main_proc_fd == -1) {
-       sprintf(buf, "/proc/%d", getpid());
-       GC_main_proc_fd = syscall(SYS_open, buf, O_RDONLY);
-        if (GC_main_proc_fd < 0) {
-               if (errno == EMFILE)
-                       ABORT("/proc open failed: too many open files");
-               GC_printf1("/proc open failed: errno %d", errno);
-               abort();
-        }
-    }
-    BZERO(GC_lwp_registers, sizeof (prgregset_t) * max_lwps);
-    for (i = 0; i < max_lwps; i++)
-       last_ids[i] = 0;
-    for (;;) {
-        if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0)
-           ABORT("Main PIOCSTATUS failed");
-       if (status.pr_nlwp < 1)
-               ABORT("Invalid number of lwps returned by PIOCSTATUS");
-       if (status.pr_nlwp >= max_lwps) {
-               set_max_lwps(status.pr_nlwp*2 + 10);
-               /*
-                * The data in the old GC_current_ids and
-                * GC_lwp_registers has been trashed. Cleaning out last_ids
-                * will make sure every LWP gets re-examined.
-                */
-               for (i = 0; i < max_lwps; i++)
-                       last_ids[i] = 0;
-               continue;
-       }
-        if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCLWPIDS, GC_current_ids) < 0)
-            ABORT("PIOCLWPIDS failed");
-        changed = FALSE;
-        for (i = 0; GC_current_ids[i] != 0 && i < max_lwps; i++) {
-            if (GC_current_ids[i] != last_ids[i]) {
-                changed = TRUE;
-                if (GC_current_ids[i] != me) {
-                   /* PIOCSTOP doesn't work without a writable         */
-                   /* descriptor.  And that makes the process          */
-                   /* undebuggable.                                    */
-                    if (_lwp_suspend(GC_current_ids[i]) < 0) {
-                        /* Could happen if the lwp exited */
-                        uncache_lwp(GC_current_ids[i]);
-                        GC_current_ids[i] = me; /* ignore */
-                    }
-                }
-            }
-        }
-        /*
-         * In the unlikely event something does a fork between the
-        * PIOCSTATUS and the PIOCLWPIDS. 
-         */
-        if (i >= max_lwps)
-               continue;
-        /* All lwps in GC_current_ids != me have been suspended.  Note */
-        /* that _lwp_suspend is idempotent.                            */
-        for (i = 0; GC_current_ids[i] != 0; i++) {
-            if (GC_current_ids[i] != last_ids[i]) {
-                if (GC_current_ids[i] != me) {
-                    lwp_fd = open_lwp(GC_current_ids[i]);
-                   if (lwp_fd == -1)
-                   {
-                           GC_current_ids[i] = me;
-                           continue;
-                   }
-                   /* LWP should be stopped.  Empirically it sometimes */
-                   /* isn't, and more frequently the PR_STOPPED flag   */
-                   /* is not set.  Wait for PR_STOPPED.                */
-                    if (syscall(SYS_ioctl, lwp_fd,
-                                PIOCSTATUS, &status) < 0) {
-                       /* Possible if the descriptor was stale, or */
-                       /* we encountered the 2.3 _lwp_suspend bug. */
-                       uncache_lwp(GC_current_ids[i]);
-                        GC_current_ids[i] = me; /* handle next time. */
-                    } else {
-                        while (!(status.pr_flags & PR_STOPPED)) {
-                            GC_msec_sleep(1);
-                           if (syscall(SYS_ioctl, lwp_fd,
-                                       PIOCSTATUS, &status) < 0) {
-                               ABORT("Repeated PIOCSTATUS failed");
-                           }
-                           if (status.pr_flags & PR_STOPPED) break;
-                           
-                           GC_msec_sleep(20);
-                           if (syscall(SYS_ioctl, lwp_fd,
-                                       PIOCSTATUS, &status) < 0) {
-                               ABORT("Repeated PIOCSTATUS failed");
-                           }
-                        }
-                        if (status.pr_who !=  GC_current_ids[i]) {
-                               /* can happen if thread was on death row */
-                               uncache_lwp(GC_current_ids[i]);
-                               GC_current_ids[i] = me; /* handle next time. */
-                               continue;       
-                        }
-                        /* Save registers where collector can */
-                       /* find them.                     */
-                           BCOPY(status.pr_reg, GC_lwp_registers[i],
-                                 sizeof (prgregset_t));
-                    }
-                }
-            }
-        }
-        if (!changed) break;
-        for (i = 0; i < max_lwps; i++) last_ids[i] = GC_current_ids[i];
-    }
-}
-
-/* Restart all lwps in process.  Assumes preemption is off.    */
-static void restart_all_lwps()
-{
-    int lwp_fd;
-    register int i;
-    GC_bool changed;
-    lwpid_t me = _lwp_self();
-#   define PARANOID
-
-    for (i = 0; GC_current_ids[i] != 0; i++) {
-#      ifdef PARANOID
-         if (GC_current_ids[i] != me) {
-           int lwp_fd = open_lwp(GC_current_ids[i]);
-           prstatus_t status;
-           
-           if (lwp_fd < 0) ABORT("open_lwp failed");
-           if (syscall(SYS_ioctl, lwp_fd,
-                       PIOCSTATUS, &status) < 0) {
-                ABORT("PIOCSTATUS failed in restart_all_lwps");
-           }
-           if (memcmp(status.pr_reg, GC_lwp_registers[i],
-                      sizeof (prgregset_t)) != 0) {
-                   int j;
-
-                   for(j = 0; j < NPRGREG; j++)
-                   {
-                           GC_printf3("%i: %x -> %x\n", j,
-                                      GC_lwp_registers[i][j],
-                                      status.pr_reg[j]);
-                   }
-               ABORT("Register contents changed");
-           }
-           if (!status.pr_flags & PR_STOPPED) {
-               ABORT("lwp no longer stopped");
-           }
-#ifdef SPARC
-           {
-                   gwindows_t windows;
-             if (syscall(SYS_ioctl, lwp_fd,
-                       PIOCGWIN, &windows) < 0) {
-                ABORT("PIOCSTATUS failed in restart_all_lwps");
-             }
-             if (windows.wbcnt > 0) ABORT("unsaved register windows");
-           }
-#endif
-         }
-#      endif /* PARANOID */
-       if (GC_current_ids[i] == me) continue;
-        if (_lwp_continue(GC_current_ids[i]) < 0) {
-            ABORT("Failed to restart lwp");
-        }
-    }
-    if (i >= max_lwps) ABORT("Too many lwps");
-}
-
-GC_bool GC_multithreaded = 0;
-
-void GC_stop_world()
-{
-    preempt_off();
-    if (GC_multithreaded)
-        stop_all_lwps();
-}
-
-void GC_start_world()
-{
-    if (GC_multithreaded)
-        restart_all_lwps();
-    preempt_on();
-}
-
-void GC_thr_init(void);
-
-GC_bool GC_thr_initialized = FALSE;
-
-size_t GC_min_stack_sz;
-
-
-/*
- * stack_head is stored at the top of free stacks
- */
-struct stack_head {
-       struct stack_head       *next;
-       ptr_t                   base;
-       thread_t                owner;
-};
-
-# define N_FREE_LISTS 25
-struct stack_head *GC_stack_free_lists[N_FREE_LISTS] = { 0 };
-               /* GC_stack_free_lists[i] is free list for stacks of    */
-               /* size GC_min_stack_sz*2**i.                           */
-               /* Free lists are linked through stack_head stored      */                      /* at top of stack.                                     */
-
-/* Return a stack of size at least *stack_size.  *stack_size is        */
-/* replaced by the actual stack size.                          */
-/* Caller holds allocation lock.                               */
-ptr_t GC_stack_alloc(size_t * stack_size)
-{
-    register size_t requested_sz = *stack_size;
-    register size_t search_sz = GC_min_stack_sz;
-    register int index = 0;    /* = log2(search_sz/GC_min_stack_sz) */
-    register ptr_t base;
-    register struct stack_head *result;
-    
-    while (search_sz < requested_sz) {
-        search_sz *= 2;
-        index++;
-    }
-    if ((result = GC_stack_free_lists[index]) == 0
-        && (result = GC_stack_free_lists[index+1]) != 0) {
-        /* Try next size up. */
-        search_sz *= 2; index++;
-    }
-    if (result != 0) {
-        base =  GC_stack_free_lists[index]->base;
-        GC_stack_free_lists[index] = GC_stack_free_lists[index]->next;
-    } else {
-#ifdef MMAP_STACKS
-        base = (ptr_t)mmap(0, search_sz + GC_page_size,
-                            PROT_READ|PROT_WRITE, MAP_PRIVATE |MAP_NORESERVE,
-                            GC_zfd, 0);
-       if (base == (ptr_t)-1)
-       {
-               *stack_size = 0;
-               return NULL;
-       }
-
-       mprotect(base, GC_page_size, PROT_NONE);
-       /* Should this use divHBLKSZ(search_sz + GC_page_size) ? -- cf */
-       GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz));
-       base += GC_page_size;
-
-#else
-        base = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_size);
-       if (base == NULL)
-       {
-               *stack_size = 0;
-               return NULL;
-       }
-
-        base = (ptr_t)(((word)base + GC_page_size) & ~(GC_page_size - 1));
-        /* Protect hottest page to detect overflow. */
-#      ifdef SOLARIS23_MPROTECT_BUG_FIXED
-            mprotect(base, GC_page_size, PROT_NONE);
-#      endif
-        GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz));
-
-        base += GC_page_size;
-#endif
-    }
-    *stack_size = search_sz;
-    return(base);
-}
-
-/* Caller holds  allocationlock.                                       */
-void GC_stack_free(ptr_t stack, size_t size)
-{
-    register int index = 0;
-    register size_t search_sz = GC_min_stack_sz;
-    register struct stack_head *head;
-    
-#ifdef MMAP_STACKS
-    /* Zero pointers */
-    mmap(stack, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_NORESERVE|MAP_FIXED,
-        GC_zfd, 0);
-#endif
-    while (search_sz < size) {
-        search_sz *= 2;
-        index++;
-    }
-    if (search_sz != size) ABORT("Bad stack size");
-
-    head = (struct stack_head *)(stack + search_sz - sizeof(struct stack_head));
-    head->next = GC_stack_free_lists[index];
-    head->base = stack;
-    GC_stack_free_lists[index] = head;
-}
-
-void GC_my_stack_limits();
-
-/* Notify virtual dirty bit implementation that known empty parts of   */
-/* stacks do not contain useful data.                                  */ 
-/* Caller holds allocation lock.                                       */
-void GC_old_stacks_are_fresh()
-{
-/* No point in doing this for MMAP stacks - and pointers are zero'd out */
-/* by the mmap in GC_stack_free */
-#ifndef MMAP_STACKS
-    register int i;
-    register struct stack_head *s;
-    register ptr_t p;
-    register size_t sz;
-    register struct hblk * h;
-    int dummy;
-    
-    for (i = 0, sz= GC_min_stack_sz; i < N_FREE_LISTS;
-         i++, sz *= 2) {
-         for (s = GC_stack_free_lists[i]; s != 0; s = s->next) {
-             p = s->base;
-             h = (struct hblk *)(((word)p + HBLKSIZE-1) & ~(HBLKSIZE-1));
-             if ((ptr_t)h == p) {
-                 GC_is_fresh((struct hblk *)p, divHBLKSZ(sz));
-             } else {
-                 GC_is_fresh((struct hblk *)p, divHBLKSZ(sz) - 1);
-                 BZERO(p, (ptr_t)h - p);
-             }
-         }
-    }
-#endif /* MMAP_STACKS */
-    GC_my_stack_limits();
-}
-
-/* The set of all known threads.  We intercept thread creation and     */
-/* joins.  We never actually create detached threads.  We allocate all         */
-/* new thread stacks ourselves.  These allow us to maintain this       */
-/* data structure.                                                     */
-
-# define THREAD_TABLE_SZ 128   /* Must be power of 2   */
-volatile GC_thread GC_threads[THREAD_TABLE_SZ];
-
-void GC_push_thread_structures GC_PROTO((void))
-{
-    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
-}
-
-/* Add a thread to GC_threads.  We assume it wasn't already there.     */
-/* Caller holds allocation lock.                                       */
-GC_thread GC_new_thread(thread_t id)
-{
-    int hv = ((word)id) % THREAD_TABLE_SZ;
-    GC_thread result;
-    static struct GC_Thread_Rep first_thread;
-    static GC_bool first_thread_used = FALSE;
-    
-    if (!first_thread_used) {
-       result = &first_thread;
-       first_thread_used = TRUE;
-       /* Dont acquire allocation lock, since we may already hold it. */
-    } else {
-        result = (struct GC_Thread_Rep *)
-                GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
-    }
-    if (result == 0) return(0);
-    result -> id = id;
-    result -> next = GC_threads[hv];
-    GC_threads[hv] = result;
-    /* result -> finished = 0; */
-    (void) cond_init(&(result->join_cv), USYNC_THREAD, 0);
-    return(result);
-}
-
-/* Delete a thread from GC_threads.  We assume it is there.    */
-/* (The code intentionally traps if it wasn't.)                        */
-/* Caller holds allocation lock.                               */
-void GC_delete_thread(thread_t id)
-{
-    int hv = ((word)id) % THREAD_TABLE_SZ;
-    register GC_thread p = GC_threads[hv];
-    register GC_thread prev = 0;
-    
-    while (p -> id != id) {
-        prev = p;
-        p = p -> next;
-    }
-    if (prev == 0) {
-        GC_threads[hv] = p -> next;
-    } else {
-        prev -> next = p -> next;
-    }
-}
-
-/* Return the GC_thread correpsonding to a given thread_t.     */
-/* Returns 0 if it's not there.                                        */
-/* Caller holds  allocation lock.                              */
-GC_thread GC_lookup_thread(thread_t id)
-{
-    int hv = ((word)id) % THREAD_TABLE_SZ;
-    register GC_thread p = GC_threads[hv];
-    
-    while (p != 0 && p -> id != id) p = p -> next;
-    return(p);
-}
-
-/* Solaris 2/Intel uses an initial stack size limit slightly bigger than the
-   SPARC default of 8 MB.  Account for this to warn only if the user has
-   raised the limit beyond the default.
-
-   This is identical to DFLSSIZ defined in <sys/vm_machparam.h>.  This file
-   is installed in /usr/platform/`uname -m`/include, which is not in the
-   default include directory list, so copy the definition here.  */
-#ifdef I386
-# define MAX_ORIG_STACK_SIZE (8 * 1024 * 1024 + ((USRSTACK) & 0x3FFFFF))
-#else
-# define MAX_ORIG_STACK_SIZE (8 * 1024 * 1024)
-#endif
-
-word GC_get_orig_stack_size() {
-    struct rlimit rl;
-    static int warned = 0;
-    int result;
-
-    if (getrlimit(RLIMIT_STACK, &rl) != 0) ABORT("getrlimit failed");
-    result = (word)rl.rlim_cur & ~(HBLKSIZE-1);
-    if (result > MAX_ORIG_STACK_SIZE) {
-       if (!warned) {
-           WARN("Large stack limit(%ld): only scanning 8 MB\n", result);
-           warned = 1;
-       }
-       result = MAX_ORIG_STACK_SIZE;
-    }
-    return result;
-}
-
-/* Notify dirty bit implementation of unused parts of my stack. */
-/* Caller holds allocation lock.                               */
-void GC_my_stack_limits()
-{
-    int dummy;
-    register ptr_t hottest = (ptr_t)((word)(&dummy) & ~(HBLKSIZE-1));
-    register GC_thread me = GC_lookup_thread(thr_self());
-    register size_t stack_size = me -> stack_size;
-    register ptr_t stack;
-    
-    if (stack_size == 0) {
-      /* original thread */
-        /* Empirically, what should be the stack page with lowest      */
-        /* address is actually inaccessible.                           */
-        stack_size = GC_get_orig_stack_size() - GC_page_size;
-        stack = GC_stackbottom - stack_size + GC_page_size;
-    } else {
-        stack = me -> stack;
-    }
-    if (stack > hottest || stack + stack_size < hottest) {
-       ABORT("sp out of bounds");
-    }
-    GC_is_fresh((struct hblk *)stack, divHBLKSZ(hottest - stack));
-}
-
-
-/* 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 bottom, top;
-    struct rlimit rl;
-    
-#   define PUSH(bottom,top) \
-      if (GC_dirty_maintained) { \
-       GC_push_selected((bottom), (top), GC_page_was_ever_dirty, \
-                     GC_push_all_stack); \
-      } else { \
-        GC_push_all_stack((bottom), (top)); \
-      }
-    GC_push_all_stack((ptr_t)GC_lwp_registers,
-                     (ptr_t)GC_lwp_registers
-                     + max_lwps * sizeof(GC_lwp_registers[0]));
-    for (i = 0; i < THREAD_TABLE_SZ; i++) {
-      for (p = GC_threads[i]; p != 0; p = p -> next) {
-        if (p -> stack_size != 0) {
-            bottom = p -> stack;
-            top = p -> stack + p -> stack_size;
-        } else {
-            /* The original stack. */
-            bottom = GC_stackbottom - GC_get_orig_stack_size() + GC_page_size;
-            top = GC_stackbottom;
-        }
-        if ((word)sp > (word)bottom && (word)sp < (word)top) bottom = sp;
-        PUSH(bottom, top);
-      }
-    }
-}
-
-
-int GC_is_thread_stack(ptr_t addr)
-{
-    register int i;
-    register GC_thread p;
-    register ptr_t bottom, top;
-    
-    for (i = 0; i < THREAD_TABLE_SZ; i++) {
-      for (p = GC_threads[i]; p != 0; p = p -> next) {
-        if (p -> stack_size != 0) {
-            if (p -> stack <= addr &&
-               addr < p -> stack + p -> stack_size)
-                   return 1;
-       }
-      }
-    }
-    return 0;
-}
-
-/* The only thread that ever really performs a thr_join.       */
-void * GC_thr_daemon(void * dummy)
-{
-    void *status;
-    thread_t departed;
-    register GC_thread t;
-    register int i;
-    register int result;
-    
-    for(;;) {
-      start:
-        result = thr_join((thread_t)0, &departed, &status);
-       LOCK();
-       if (result != 0) {
-           /* No more threads; wait for create. */
-           for (i = 0; i < THREAD_TABLE_SZ; i++) {
-               for (t = GC_threads[i]; t != 0; t = t -> next) {
-                    if (!(t -> flags & (DETACHED | FINISHED))) {
-                      UNLOCK();
-                      goto start; /* Thread started just before we */
-                                 /* acquired the lock.            */
-                    }
-                }
-            }
-            cond_wait(&GC_create_cv, &GC_allocate_ml);
-            UNLOCK();
-       } else {
-           t = GC_lookup_thread(departed);
-           GC_multithreaded--;
-           if (!(t -> flags & CLIENT_OWNS_STACK)) {
-               GC_stack_free(t -> stack, t -> stack_size);
-           }
-           if (t -> flags & DETACHED) {
-               GC_delete_thread(departed);
-           } else {
-               t -> status = status;
-               t -> flags |= FINISHED;
-               cond_signal(&(t -> join_cv));
-               cond_broadcast(&GC_prom_join_cv);
-           }
-           UNLOCK();
-       }
-    }
-}
-
-/* We hold the allocation lock, or caller ensures that 2 instances     */
-/* cannot be invoked concurrently.                                     */
-void GC_thr_init(void)
-{
-    GC_thread t;
-    thread_t tid;
-    int ret;
-
-    if (GC_thr_initialized)
-           return;
-    GC_thr_initialized = TRUE;
-    GC_min_stack_sz = ((thr_min_stack() + 32*1024 + HBLKSIZE-1)
-                      & ~(HBLKSIZE - 1));
-#ifdef MMAP_STACKS
-    GC_zfd = open("/dev/zero", O_RDONLY);
-    if (GC_zfd == -1)
-           ABORT("Can't open /dev/zero");
-#endif /* MMAP_STACKS */
-    cond_init(&GC_prom_join_cv, USYNC_THREAD, 0);
-    cond_init(&GC_create_cv, USYNC_THREAD, 0);
-    /* Add the initial thread, so we can stop it.      */
-      t = GC_new_thread(thr_self());
-      t -> stack_size = 0;
-      t -> flags = DETACHED | CLIENT_OWNS_STACK;
-    ret = thr_create(0 /* stack */, 0 /* stack_size */, GC_thr_daemon,
-                    0 /* arg */, THR_DETACHED | THR_DAEMON,
-                    &tid /* thread_id */);
-    if (ret != 0) {
-       GC_err_printf1("Thr_create returned %ld\n", ret);
-       ABORT("Cant fork daemon");
-    }
-    thr_setprio(tid, 126);
-}
-
-/* We acquire the allocation lock to prevent races with        */
-/* stopping/starting world.                                    */
-/* This is no more correct than the underlying Solaris 2.X     */
-/* implementation.  Under 2.3 THIS IS BROKEN.                  */
-int GC_thr_suspend(thread_t target_thread)
-{
-    GC_thread t;
-    int result;
-    
-    LOCK();
-    result = thr_suspend(target_thread);
-    if (result == 0) {
-       t = GC_lookup_thread(target_thread);
-       if (t == 0) ABORT("thread unknown to GC");
-        t -> flags |= SUSPNDED;
-    }
-    UNLOCK();
-    return(result);
-}
-
-int GC_thr_continue(thread_t target_thread)
-{
-    GC_thread t;
-    int result;
-    
-    LOCK();
-    result = thr_continue(target_thread);
-    if (result == 0) {
-       t = GC_lookup_thread(target_thread);
-       if (t == 0) ABORT("thread unknown to GC");
-        t -> flags &= ~SUSPNDED;
-    }
-    UNLOCK();
-    return(result);
-}
-
-int GC_thr_join(thread_t wait_for, thread_t *departed, void **status)
-{
-    register GC_thread t;
-    int result = 0;
-    
-    LOCK();
-    if (wait_for == 0) {
-        register int i;
-        register GC_bool thread_exists;
-    
-       for (;;) {
-         thread_exists = FALSE;
-         for (i = 0; i < THREAD_TABLE_SZ; i++) {
-           for (t = GC_threads[i]; t != 0; t = t -> next) {
-              if (!(t -> flags & DETACHED)) {
-                if (t -> flags & FINISHED) {
-                  goto found;
-                }
-                thread_exists = TRUE;
-              }
-            }
-          }
-          if (!thread_exists) {
-              result = ESRCH;
-             goto out;
-          }
-          cond_wait(&GC_prom_join_cv, &GC_allocate_ml);
-        }
-    } else {
-        t = GC_lookup_thread(wait_for);
-       if (t == 0 || t -> flags & DETACHED) {
-           result = ESRCH;
-           goto out;
-       }
-       if (wait_for == thr_self()) {
-           result = EDEADLK;
-           goto out;
-       }
-       while (!(t -> flags & FINISHED)) {
-            cond_wait(&(t -> join_cv), &GC_allocate_ml);
-       }
-       
-    }
-  found:
-    if (status) *status = t -> status;
-    if (departed) *departed = t -> id;
-    cond_destroy(&(t -> join_cv));
-    GC_delete_thread(t -> id);
-  out:
-    UNLOCK();
-    return(result);
-}
-
-
-int
-GC_thr_create(void *stack_base, size_t stack_size,
-              void *(*start_routine)(void *), void *arg, long flags,
-              thread_t *new_thread)
-{
-    int result;
-    GC_thread t;
-    thread_t my_new_thread;
-    word my_flags = 0;
-    void * stack = stack_base;
-   
-    LOCK();
-    if (!GC_is_initialized) GC_init_inner();
-    GC_multithreaded++;
-    if (stack == 0) {
-       if (stack_size == 0) stack_size = 1024*1024;
-       stack = (void *)GC_stack_alloc(&stack_size);
-       if (stack == 0) {
-           GC_multithreaded--;
-           UNLOCK();
-           return(ENOMEM);
-       }
-    } else {
-       my_flags |= CLIENT_OWNS_STACK;
-    }
-    if (flags & THR_DETACHED) my_flags |= DETACHED;
-    if (flags & THR_SUSPENDED) my_flags |= SUSPNDED;
-    result = thr_create(stack, stack_size, start_routine,
-                       arg, flags & ~THR_DETACHED, &my_new_thread);
-    if (result == 0) {
-        t = GC_new_thread(my_new_thread);
-        t -> flags = my_flags;
-        if (!(my_flags & DETACHED)) cond_init(&(t -> join_cv), USYNC_THREAD, 0);
-        t -> stack = stack;
-        t -> stack_size = stack_size;
-        if (new_thread != 0) *new_thread = my_new_thread;
-        cond_signal(&GC_create_cv);
-    } else {
-       GC_multithreaded--;
-        if (!(my_flags & CLIENT_OWNS_STACK)) {
-           GC_stack_free(stack, stack_size);
-       }
-    }        
-    UNLOCK();  
-    return(result);
-}
-
-# else /* !GC_SOLARIS_THREADS */
-
-#ifndef LINT
-  int GC_no_sunOS_threads;
-#endif
-#endif
index 06a0f3b4673a01a91cf1a4c4c3a49e032c6088dd..e8ad6556f9dc9f7fb9c4543d9fdca190f2010b7b 100644 (file)
@@ -8,7 +8,6 @@
        .globl  GC_save_regs_in_stack
        .globl  GC_push_regs
 GC_save_regs_in_stack:
-GC_push_regs:
 #if defined(__arch64__) || defined(__sparcv9)
        save    %sp,-128,%sp
        flushw
@@ -24,6 +23,10 @@ GC_push_regs:
        .size GC_save_regs_in_stack,.GC_save_regs_in_stack_end-GC_save_regs_in_stack
        
 
+! GC_clear_stack_inner(arg, limit) clears stack area up to limit and
+! returns arg.  Stack clearing is crucial on SPARC, so we supply
+! an assembly version that s more careful.  Assumes limit is hotter
+! than sp, and limit is 8 byte aligned.        
        .globl  GC_clear_stack_inner
 GC_clear_stack_inner:
 #if defined(__arch64__) || defined(__sparcv9)
index e924a7f372b33717b2f67be5c7cd2fc390e8f19e..821dc02e0f7aeedc0547d8f8d948434e80b572ba 100644 (file)
 
 #include "config.h"
 
-#include "private/gc_priv.h" /* For GC_compare_and_exchange, GC_memory_barrier */
+#include "private/gc_priv.h"   /* For configuration, pthreads.h. */
+#include "private/thread_local_alloc.h"
+                               /* To determine type of tsd impl. */
+                               /* Includes private/specific.h    */
+                               /* if needed.                     */
 
-#if defined(GC_LINUX_THREADS)
+#if defined(USE_CUSTOM_SPECIFIC)
 
-#include "private/specific.h"
+#include "atomic_ops.h"
 
 static tse invalid_tse = {INVALID_QTID, 0, 0, INVALID_THREADID};
-                       /* A thread-specific data entry which will never        */
-                       /* appear valid to a reader.  Used to fill in empty     */
-                       /* cache entries to avoid a check for 0.                */
+                       /* A thread-specific data entry which will never    */
+                       /* appear valid to a reader.  Used to fill in empty */
+                       /* cache entries to avoid a check for 0.            */
 
 int PREFIXED(key_create) (tsd ** key_ptr, void (* destructor)(void *)) {
     int i;
@@ -59,7 +63,7 @@ int PREFIXED(setspecific) (tsd * key, void * value) {
     GC_ASSERT(entry -> qtid == INVALID_QTID);
     /* There can only be one writer at a time, but this needs to be    */
     /* atomic with respect to concurrent readers.                      */ 
-    *(volatile tse **)(key -> hash + hash_val) = entry;
+    AO_store_release((volatile AO_t *)(key -> hash + hash_val), (AO_t)entry);
     pthread_mutex_unlock(&(key -> lock));
     return 0;
 }
@@ -127,4 +131,37 @@ void *  PREFIXED(slow_getspecific) (tsd * key, unsigned long qtid,
     return entry -> value;
 }
 
-#endif /* GC_LINUX_THREADS */
+#ifdef GC_ASSERTIONS
+
+/* Check that that all elements of the data structure associated       */
+/* with key are marked.                                                        */
+void PREFIXED(check_tsd_marks) (tsd *key)
+{
+    int i;
+    tse *p;
+
+    if (!GC_is_marked(GC_base(key))) {
+       ABORT("Unmarked thread-specific-data table");
+    }
+    for (i = 0; i < TS_HASH_SIZE; ++i) {
+        for (p = key -> hash[i]; p != 0; p = p -> next) {
+           if (!GC_is_marked(GC_base(p))) {
+               GC_err_printf(
+                       "Thread-specific-data entry at %p not marked\n",p);
+               ABORT("Unmarked tse");
+           }
+       }
+    }
+    for (i = 0; i < TS_CACHE_SIZE; ++i) {
+        p = key -> cache[i];
+       if (p != &invalid_tse && !GC_is_marked(GC_base(p))) {
+           GC_err_printf(
+               "Cached thread-specific-data entry at %p not marked\n",p);
+           ABORT("Unmarked cached tse");
+       }
+    }
+}
+
+#endif
+
+#endif /* USE_CUSTOM_SPECIFIC */
index 6d6e1b6cd1d92a472f20ebc9d54582db4a85d0de..aeaf3cc7a6aecae01fa87208ea3a3d7d8223136c 100644 (file)
 
 #include "private/gc_priv.h"
 
-# ifdef STUBBORN_ALLOC
+#if defined(MANUAL_VDB)
 /* Stubborn object (hard to change, nearly immutable) allocation. */
-
-extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
-
-#define GENERAL_MALLOC(lb,k) \
-    (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
-
-/* Data structure representing immutable objects that  */
-/* are still being initialized.                                */
-/* This is a bit baroque in order to avoid acquiring   */
-/* the lock twice for a typical allocation.            */
-
-GC_PTR * GC_changing_list_start;
-
-void GC_push_stubborn_structures GC_PROTO((void))
-{
-    GC_push_all((ptr_t)(&GC_changing_list_start),
-               (ptr_t)(&GC_changing_list_start) + sizeof(GC_PTR *));
-}
-
-# ifdef THREADS
-  VOLATILE GC_PTR * VOLATILE GC_changing_list_current;
-# else
-  GC_PTR * GC_changing_list_current;
-# endif
-       /* Points at last added element.  Also (ab)used for             */
-       /* synchronization.  Updates and reads are assumed atomic.      */
-
-GC_PTR * GC_changing_list_limit;
-       /* Points at the last word of the buffer, which is always 0     */
-       /* All entries in (GC_changing_list_current,                    */
-       /* GC_changing_list_limit] are 0                                */
-
-
-void GC_stubborn_init()
-{
-#   define INIT_SIZE 10
-
-    GC_changing_list_start = (GC_PTR *)
-                       GC_INTERNAL_MALLOC(
-                               (word)(INIT_SIZE * sizeof(GC_PTR)),
-                               PTRFREE);
-    BZERO(GC_changing_list_start,
-         INIT_SIZE * sizeof(GC_PTR));
-    if (GC_changing_list_start == 0) {
-        GC_err_printf0("Insufficient space to start up\n");
-        ABORT("GC_stubborn_init: put of space");
-    }
-    GC_changing_list_current = GC_changing_list_start;
-    GC_changing_list_limit = GC_changing_list_start + INIT_SIZE - 1;
-    * GC_changing_list_limit = 0;
-}
-
-/* Compact and possibly grow GC_uninit_list.  The old copy is          */
-/* left alone. Lock must be held.                                      */
-/* When called GC_changing_list_current == GC_changing_list_limit      */
-/* which is one past the current element.                              */
-/* When we finish GC_changing_list_current again points one past last  */
-/* element.                                                            */
-/* Invariant while this is running: GC_changing_list_current           */
-/* points at a word containing 0.                                      */
-/* Returns FALSE on failure.                                           */
-GC_bool GC_compact_changing_list()
-{
-    register GC_PTR *p, *q;
-    register word count = 0;
-    word old_size = (char **)GC_changing_list_limit
-                   - (char **)GC_changing_list_start+1;
-                   /* The casts are needed as a workaround for an Amiga bug */
-    register word new_size = old_size;
-    GC_PTR * new_list;
-    
-    for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
-        if (*p != 0) count++;
-    }
-    if (2 * count > old_size) new_size = 2 * count;
-    new_list = (GC_PTR *)
-               GC_INTERNAL_MALLOC(
-                               new_size * sizeof(GC_PTR), PTRFREE);
-               /* PTRFREE is a lie.  But we don't want the collector to  */
-               /* consider these.  We do want the list itself to be      */
-               /* collectable.                                           */
-    if (new_list == 0) return(FALSE);
-    BZERO(new_list, new_size * sizeof(GC_PTR));
-    q = new_list;
-    for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
-        if (*p != 0) *q++ = *p;
-    }
-    GC_changing_list_start = new_list;
-    GC_changing_list_limit = new_list + new_size - 1;
-    GC_changing_list_current = q;
-    return(TRUE);
-}
-
-/* Add p to changing list.  Clear p on failure.        */
-# define ADD_CHANGING(p) \
-       {       \
-           register struct hblk * h = HBLKPTR(p);      \
-           register word index = PHT_HASH(h);  \
-           \
-           set_pht_entry_from_index(GC_changed_pages, index);  \
-       }       \
-       if (*GC_changing_list_current != 0 \
-           && ++GC_changing_list_current == GC_changing_list_limit) { \
-           if (!GC_compact_changing_list()) (p) = 0; \
-       } \
-       *GC_changing_list_current = p;
-
-void GC_change_stubborn(p)
-GC_PTR p;
-{
-    DCL_LOCK_STATE;
-    
-    DISABLE_SIGNALS();
-    LOCK();
-    ADD_CHANGING(p);
-    UNLOCK();
-    ENABLE_SIGNALS();
-}
-
-void GC_end_stubborn_change(p)
-GC_PTR p;
-{
-#   ifdef THREADS
-      register VOLATILE GC_PTR * my_current = GC_changing_list_current;
-#   else
-      register GC_PTR * my_current = GC_changing_list_current;
-#   endif
-    register GC_bool tried_quick;
-    DCL_LOCK_STATE;
-    
-    if (*my_current == p) {
-        /* Hopefully the normal case.                                  */
-        /* Compaction could not have been running when we started.     */
-        *my_current = 0;
-#      ifdef THREADS
-          if (my_current == GC_changing_list_current) {
-            /* Compaction can't have run in the interim.       */
-            /* We got away with the quick and dirty approach.   */
-            return;
-          }
-          tried_quick = TRUE;
-#      else
-         return;
-#      endif
-    } else {
-        tried_quick = FALSE;
-    }
-    DISABLE_SIGNALS();
-    LOCK();
-    my_current = GC_changing_list_current;
-    for (; my_current >= GC_changing_list_start; my_current--) {
-        if (*my_current == p) {
-            *my_current = 0;
-            UNLOCK();
-            ENABLE_SIGNALS();
-            return;
-        }
-    }
-    if (!tried_quick) {
-        GC_err_printf1("Bad arg to GC_end_stubborn_change: 0x%lx\n",
-                      (unsigned long)p);
-        ABORT("Bad arg to GC_end_stubborn_change");
-    }
-    UNLOCK();
-    ENABLE_SIGNALS();
-}
-
-/* Allocate lb bytes of composite (pointerful) data    */
-/* No pointer fields may be changed after a call to    */
-/* GC_end_stubborn_change(p) where p is the value      */
-/* returned by GC_malloc_stubborn.                     */
-# ifdef __STDC__
-    GC_PTR GC_malloc_stubborn(size_t lb)
-# else
-    GC_PTR GC_malloc_stubborn(lb)
-    size_t lb;
-# endif
-{
-register ptr_t op;
-register ptr_t *opp;
-register word lw;
-ptr_t result;
-DCL_LOCK_STATE;
-
-    if( SMALL_OBJ(lb) ) {
-#       ifdef MERGE_SIZES
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_sobjfreelist[lw]);
-       FASTLOCK();
-        if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
-            FASTUNLOCK();
-            result = GC_generic_malloc((word)lb, STUBBORN);
-            goto record;
-        }
-        *opp = obj_link(op);
-        obj_link(op) = 0;
-        GC_words_allocd += lw;
-        result = (GC_PTR) op;
-        ADD_CHANGING(result);
-        FASTUNLOCK();
-        return((GC_PTR)result);
-   } else {
-       result = (GC_PTR)
-               GC_generic_malloc((word)lb, STUBBORN);
-   }
-record:
-   DISABLE_SIGNALS();
-   LOCK();
-   ADD_CHANGING(result);
-   UNLOCK();
-   ENABLE_SIGNALS();
-   return((GC_PTR)GC_clear_stack(result));
-}
-
-
-/* Functions analogous to GC_read_dirty and GC_page_was_dirty. */
-/* Report pages on which stubborn objects were changed.                */
-void GC_read_changed()
+/* This interface is deprecated.  We mostly emulate it using     */
+/* MANUAL_VDB.  But that imposes the additional constraint that          */
+/* written, but not yet GC_dirty()ed objects must be referenced          */
+/* by a stack.                                                   */
+void * GC_malloc_stubborn(size_t lb)
 {
-    register GC_PTR * p = GC_changing_list_start;
-    register GC_PTR q;
-    register struct hblk * h;
-    register word index;
-    
-    if (p == 0) /* initializing */ return;
-    BCOPY(GC_changed_pages, GC_prev_changed_pages,
-          (sizeof GC_changed_pages));
-    BZERO(GC_changed_pages, (sizeof GC_changed_pages));
-    for (; p <= GC_changing_list_current; p++) {
-        if ((q = *p) != 0) {
-            h = HBLKPTR(q);
-            index = PHT_HASH(h);
-            set_pht_entry_from_index(GC_changed_pages, index);
-        }
-    }
+    return(GC_malloc(lb));
 }
 
-GC_bool GC_page_was_changed(h)
-struct hblk * h;
+/*ARGSUSED*/
+void GC_end_stubborn_change(void *p)
 {
-    register word index = PHT_HASH(h);
-    
-    return(get_pht_entry_from_index(GC_prev_changed_pages, index));
+    GC_dirty(p);
 }
 
-/* Remove unreachable entries from changed list. Should only be        */
-/* called with mark bits consistent and lock held.             */
-void GC_clean_changing_list()
+/*ARGSUSED*/
+void GC_change_stubborn(void *p)
 {
-    register GC_PTR * p = GC_changing_list_start;
-    register GC_PTR q;
-    register ptr_t r;
-    register unsigned long count = 0;
-    register unsigned long dropped_count = 0;
-    
-    if (p == 0) /* initializing */ return;
-    for (; p <= GC_changing_list_current; p++) {
-        if ((q = *p) != 0) {
-            count++;
-            r = (ptr_t)GC_base(q);
-            if (r == 0 || !GC_is_marked(r)) {
-                *p = 0;
-                dropped_count++;
-           }
-        }
-    }
-#   ifdef PRINTSTATS
-      if (count > 0) {
-        GC_printf2("%lu entries in changing list: reclaimed %lu\n",
-                  (unsigned long)count, (unsigned long)dropped_count);
-      }
-#   endif
 }
 
-#else /* !STUBBORN_ALLOC */
+#else /* !MANUAL_VDB */
 
-# ifdef __STDC__
-    GC_PTR GC_malloc_stubborn(size_t lb)
-# else
-    GC_PTR GC_malloc_stubborn(lb)
-    size_t lb;
-# endif
+void * GC_malloc_stubborn(size_t lb)
 {
     return(GC_malloc(lb));
 }
 
 /*ARGSUSED*/
-void GC_end_stubborn_change(p)
-GC_PTR p;
+void GC_end_stubborn_change(void *p)
 {
 }
 
 /*ARGSUSED*/
-void GC_change_stubborn(p)
-GC_PTR p;
-{
-}
-
-void GC_push_stubborn_structures GC_PROTO((void))
+void GC_change_stubborn(void *p)
 {
 }
 
-#endif
+#endif /* !MANUAL_VDB */
index 421d0c6cd4a6f9ec5544285a18797c5dc2147b85..d6a60d47a7e49c8cc85c7bcbaf9ad6219296a1c3 100644 (file)
@@ -5,6 +5,9 @@ main() {
     int i;
     GC_find_leak = 1; /* for new collect versions not compiled  */
     /* with -DFIND_LEAK.                                        */
+
+    GC_INIT(); /* Needed if thread-local allocation is enabled.        */
+               /* FIXME: This is not ideal.                            */
     for (i = 0; i < 10; ++i) {
         p[i] = malloc(sizeof(int)+i);
     }
@@ -18,4 +21,5 @@ main() {
     CHECK_LEAKS();
     CHECK_LEAKS();
     CHECK_LEAKS();
+    return 0;
 }       
diff --git a/src/mm/boehm-gc/tests/middle.c b/src/mm/boehm-gc/tests/middle.c
new file mode 100644 (file)
index 0000000..ebb348c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Test at the boundary between small and large objects.
+ * Inspired by a test case from Zoltan Varga.
+ */
+#include <gc.h>
+#include <stdio.h>
+
+int main ()
+{
+        int i;
+
+        GC_all_interior_pointers = 0;
+       GC_INIT();
+
+        for (i = 0; i < 20000; ++i) {
+                GC_malloc_atomic (4096);
+                GC_malloc (4096);
+       }
+        for (i = 0; i < 20000; ++i) {
+                GC_malloc_atomic (2048);
+                GC_malloc (2048);
+       }
+       printf("Final heap size is %ld\n", GC_get_heap_size());
+       return 0;
+}
+
index f44317393827c2be0851fc8f4ee0d8234751d255..a7a7cd013d761529e7788d12bb99b28fe8d838d6 100644 (file)
@@ -20,6 +20,8 @@
 
 # undef GC_BUILD
 
+#include "config.h"
+
 #if defined(DBG_HDRS_ALL) || defined(MAKE_BACK_GRAPH)
 #  define GC_DEBUG
 #endif
 # else
 #   include <assert.h>        /* Not normally used, but handy for debugging. */
 # endif
-# include <assert.h>   /* Not normally used, but handy for debugging. */
 # include "gc.h"
 # include "gc_typed.h"
-# ifdef THREAD_LOCAL_ALLOC
-#   include "gc_local_alloc.h"
-# endif
 # include "private/gc_priv.h"  /* For output, locking, MIN_WORDS,      */
-                               /* and some statistics.                 */
-# include "private/gcconfig.h"
+                               /* and some statistics, and gcconfig.h. */
 
 # if defined(MSWIN32) || defined(MSWINCE)
 #   include <windows.h>
 # ifdef PCR
 #   include "th/PCR_ThCrSec.h"
 #   include "th/PCR_Th.h"
-#   undef GC_printf0
-#   define GC_printf0 printf
-#   undef GC_printf1
-#   define GC_printf1 printf
-# endif
-
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-#   include <thread.h>
-#   include <synch.h>
+#   define GC_printf printf
 # endif
 
 # if defined(GC_PTHREADS)
@@ -97,8 +86,8 @@ int realloc_count = 0;
              ret=GC_malloc_explicitly_typed(lb,d);
                }
       if(ret==NULL){
-        GC_printf0("Out of memory, (typed allocations are not directly "
-                  "supported with the GC_AMIGA_FASTALLOC option.)\n");
+        GC_printf("Out of memory, (typed allocations are not directly "
+                 "supported with the GC_AMIGA_FASTALLOC option.)\n");
         FAIL;
       }
     }
@@ -112,8 +101,8 @@ int realloc_count = 0;
              ret=GC_calloc_explicitly_typed(a,lb,d);
                }
       if(ret==NULL){
-        GC_printf0("Out of memory, (typed allocations are not directly "
-                  "supported with the GC_AMIGA_FASTALLOC option.)\n");
+        GC_printf("Out of memory, (typed allocations are not directly "
+                 "supported with the GC_AMIGA_FASTALLOC option.)\n");
         FAIL;
       }
     }
@@ -150,7 +139,8 @@ struct SEXPR {
 
 typedef struct SEXPR * sexpr;
 
-# define INT_TO_SEXPR(x) ((sexpr)(unsigned long)(x))
+# define INT_TO_SEXPR(x) ((sexpr)(GC_word)(x))
+# define SEXPR_TO_INT(x) ((int)(GC_word)(x))
 
 # undef nil
 # define nil (INT_TO_SEXPR(0))
@@ -166,28 +156,25 @@ int extra_count = 0;        /* Amount of space wasted in cons node */
 # ifdef VERY_SMALL_CONFIG
 #   define cons small_cons
 # else
-sexpr cons (x, y)
-sexpr x;
-sexpr y;
+sexpr cons (sexpr x, sexpr y)
 {
-    register sexpr r;
-    register int *p;
-    register int my_extra = extra_count;
+    sexpr r;
+    int *p;
+    int my_extra = extra_count;
     
     stubborn_count++;
     r = (sexpr) GC_MALLOC_STUBBORN(sizeof(struct SEXPR) + my_extra);
     if (r == 0) {
-        (void)GC_printf0("Out of memory\n");
+        (void)GC_printf("Out of memory\n");
         exit(1);
     }
     for (p = (int *)r;
          ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
        if (*p) {
-           (void)GC_printf1("Found nonzero at 0x%lx - allocator is broken\n",
-                            (unsigned long)p);
+           (void)GC_printf("Found nonzero at %p - allocator is broken\n", p);
            FAIL;
         }
-        *p = 13;
+        *p = (int)((13 << 12) + ((p - (int *)r) & 0xfff));
     }
 #   ifdef AT_END
        r = (sexpr)((char *)r + (my_extra & ~7));
@@ -236,74 +223,25 @@ struct GC_ms_entry * fake_gcj_mark_proc(word * addr,
     }
     x = (sexpr)(addr + 1); /* Skip the vtable pointer. */
     mark_stack_ptr = GC_MARK_AND_PUSH(
-                             (GC_PTR)(x -> sexpr_cdr), mark_stack_ptr,
-                             mark_stack_limit, (GC_PTR *)&(x -> sexpr_cdr));
+                             (void *)(x -> sexpr_cdr), mark_stack_ptr,
+                             mark_stack_limit, (void * *)&(x -> sexpr_cdr));
     mark_stack_ptr = GC_MARK_AND_PUSH(
-                             (GC_PTR)(x -> sexpr_car), mark_stack_ptr,
-                             mark_stack_limit, (GC_PTR *)&(x -> sexpr_car));
+                             (void *)(x -> sexpr_car), mark_stack_ptr,
+                             mark_stack_limit, (void * *)&(x -> sexpr_car));
     return(mark_stack_ptr);
 }
 
 #endif /* GC_GCJ_SUPPORT */
 
-#ifdef THREAD_LOCAL_ALLOC
-
-#undef GC_REDIRECT_TO_LOCAL
-#include "gc_local_alloc.h"
 
-sexpr local_cons (x, y)
-sexpr x;
-sexpr y;
+sexpr small_cons (sexpr x, sexpr y)
 {
-    register sexpr r;
-    register int *p;
-    register int my_extra = extra_count;
-    static int my_random = 0;
-    
-    collectable_count++;
-    r = (sexpr) GC_LOCAL_MALLOC(sizeof(struct SEXPR) + my_extra);
-#   ifdef GC_GCJ_SUPPORT
-      if (collectable_count % 2 == 0) {
-        r = (sexpr) GC_LOCAL_GCJ_MALLOC(sizeof(struct SEXPR) + sizeof(GC_word) + my_extra,
-                                       &gcj_class_struct1);
-        r = (sexpr) ((GC_word *)r + 1);
-      }
-#   endif
-    if (r == 0) {
-        (void)GC_printf0("Out of memory\n");
-        exit(1);
-    }
-    for (p = (int *)r;
-         ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
-       if (*p) {
-           (void)GC_printf1("Found nonzero at 0x%lx (local) - allocator is broken\n",
-                            (unsigned long)p);
-           FAIL;
-        }
-        *p = 13;
-    }
-    r -> sexpr_car = x;
-    r -> sexpr_cdr = y;
-    my_extra++;
-    if ( my_extra >= 5000 || my_extra == 200 && ++my_random % 37 != 0) {
-        extra_count = 0;
-    } else {
-        extra_count = my_extra;
-    }
-    return(r);
-}
-#endif /* THREAD_LOCAL_ALLOC */
-
-sexpr small_cons (x, y)
-sexpr x;
-sexpr y;
-{
-    register sexpr r;
+    sexpr r;
     
     collectable_count++;
     r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
     if (r == 0) {
-        (void)GC_printf0("Out of memory\n");
+        (void)GC_printf("Out of memory\n");
         exit(1);
     }
     r -> sexpr_car = x;
@@ -311,47 +249,35 @@ sexpr y;
     return(r);
 }
 
-sexpr small_cons_uncollectable (x, y)
-sexpr x;
-sexpr y;
+sexpr small_cons_uncollectable (sexpr x, sexpr y)
 {
-    register sexpr r;
+    sexpr r;
     
     uncollectable_count++;
     r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
     if (r == 0) {
-        (void)GC_printf0("Out of memory\n");
+        (void)GC_printf("Out of memory\n");
         exit(1);
     }
     r -> sexpr_car = x;
-    r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
+    r -> sexpr_cdr = (sexpr)(~(GC_word)y);
     return(r);
 }
 
 #ifdef GC_GCJ_SUPPORT
 
 
-sexpr gcj_cons(x, y)
-sexpr x;
-sexpr y;
+sexpr gcj_cons(sexpr x, sexpr y)
 {
     GC_word * r;
     sexpr result;
     static int count = 0;
     
-    if (++count & 1) {
-#     ifdef USE_MARK_BYTES
-        r = (GC_word *) GC_GCJ_FAST_MALLOC(4, &gcj_class_struct1);
-#     else
-        r = (GC_word *) GC_GCJ_FAST_MALLOC(3, &gcj_class_struct1);
-#     endif
-    } else {
-        r = (GC_word *) GC_GCJ_MALLOC(sizeof(struct SEXPR)
-                                     + sizeof(struct fake_vtable*),
-                                     &gcj_class_struct2);
-    }
+    r = (GC_word *) GC_GCJ_MALLOC(sizeof(struct SEXPR)
+                                 + sizeof(struct fake_vtable*),
+                                  &gcj_class_struct2);
     if (r == 0) {
-        (void)GC_printf0("Out of memory\n");
+        (void)GC_printf("Out of memory\n");
         exit(1);
     }
     result = (sexpr)(r + 1);
@@ -362,8 +288,7 @@ sexpr y;
 #endif
 
 /* Return reverse(x) concatenated with y */
-sexpr reverse1(x, y)
-sexpr x, y;
+sexpr reverse1(sexpr x, sexpr y)
 {
     if (is_nil(x)) {
         return(y);
@@ -372,8 +297,7 @@ sexpr x, y;
     }
 }
 
-sexpr reverse(x)
-sexpr x;
+sexpr reverse(sexpr x)
 {
 #   ifdef TEST_WITH_SYSTEM_MALLOC
       malloc(100000);
@@ -381,8 +305,7 @@ sexpr x;
     return( reverse1(x, nil) );
 }
 
-sexpr ints(low, up)
-int low, up;
+sexpr ints(int low, int up)
 {
     if (low > up) {
        return(nil);
@@ -393,8 +316,7 @@ int low, up;
 
 #ifdef GC_GCJ_SUPPORT
 /* Return reverse(x) concatenated with y */
-sexpr gcj_reverse1(x, y)
-sexpr x, y;
+sexpr gcj_reverse1(sexpr x, sexpr y)
 {
     if (is_nil(x)) {
         return(y);
@@ -403,14 +325,12 @@ sexpr x, y;
     }
 }
 
-sexpr gcj_reverse(x)
-sexpr x;
+sexpr gcj_reverse(sexpr x)
 {
     return( gcj_reverse1(x, nil) );
 }
 
-sexpr gcj_ints(low, up)
-int low, up;
+sexpr gcj_ints(int low, int up)
 {
     if (low > up) {
        return(nil);
@@ -420,39 +340,9 @@ int low, up;
 }
 #endif /* GC_GCJ_SUPPORT */
 
-#ifdef THREAD_LOCAL_ALLOC
-/* Return reverse(x) concatenated with y */
-sexpr local_reverse1(x, y)
-sexpr x, y;
-{
-    if (is_nil(x)) {
-        return(y);
-    } else {
-        return( local_reverse1(cdr(x), local_cons(car(x), y)) );
-    }
-}
-
-sexpr local_reverse(x)
-sexpr x;
-{
-    return( local_reverse1(x, nil) );
-}
-
-sexpr local_ints(low, up)
-int low, up;
-{
-    if (low > up) {
-       return(nil);
-    } else {
-        return(local_cons(local_cons(INT_TO_SEXPR(low), nil), local_ints(low+1, up)));
-    }
-}
-#endif /* THREAD_LOCAL_ALLOC */
-
 /* To check uncollectable allocation we build lists with disguised cdr */
 /* pointers, and make sure they don't go away.                         */
-sexpr uncollectable_ints(low, up)
-int low, up;
+sexpr uncollectable_ints(int low, int up)
 {
     if (low > up) {
        return(nil);
@@ -462,18 +352,16 @@ int low, up;
     }
 }
 
-void check_ints(list, low, up)
-sexpr list;
-int low, up;
+void check_ints(sexpr list, int low, int up)
 {
-    if ((int)(GC_word)(car(car(list))) != low) {
-        (void)GC_printf0(
+    if (SEXPR_TO_INT(car(car(list))) != low) {
+        (void)GC_printf(
            "List reversal produced incorrect list - collector is broken\n");
         FAIL;
     }
     if (low == up) {
         if (cdr(list) != nil) {
-           (void)GC_printf0("List too long - collector is broken\n");
+           (void)GC_printf("List too long - collector is broken\n");
            FAIL;
         }
     } else {
@@ -481,20 +369,18 @@ int low, up;
     }
 }
 
-# define UNCOLLECTABLE_CDR(x) (sexpr)(~(unsigned long)(cdr(x)))
+# define UNCOLLECTABLE_CDR(x) (sexpr)(~(GC_word)(cdr(x)))
 
-void check_uncollectable_ints(list, low, up)
-sexpr list;
-int low, up;
+void check_uncollectable_ints(sexpr list, int low, int up)
 {
-    if ((int)(GC_word)(car(car(list))) != low) {
-        (void)GC_printf0(
+    if (SEXPR_TO_INT(car(car(list))) != low) {
+        (void)GC_printf(
            "Uncollectable list corrupted - collector is broken\n");
         FAIL;
     }
     if (low == up) {
         if (UNCOLLECTABLE_CDR(list) != nil) {
-           (void)GC_printf0("Uncollectable list too long - collector is broken\n");
+           (void)GC_printf("Uncollectable list too long - collector is broken\n");
            FAIL;
         }
     } else {
@@ -503,18 +389,38 @@ int low, up;
 }
 
 /* Not used, but useful for debugging: */
-void print_int_list(x)
-sexpr x;
+void print_int_list(sexpr x)
 {
     if (is_nil(x)) {
-        (void)GC_printf0("NIL\n");
+        (void)GC_printf("NIL\n");
     } else {
-        (void)GC_printf1("(%ld)", (long)(car(car(x))));
+        (void)GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
         if (!is_nil(cdr(x))) {
-            (void)GC_printf0(", ");
+            (void)GC_printf(", ");
             (void)print_int_list(cdr(x));
         } else {
-            (void)GC_printf0("\n");
+            (void)GC_printf("\n");
+        }
+    }
+}
+
+/* ditto: */
+void check_marks_int_list(sexpr x)
+{
+    if (!GC_is_marked((ptr_t)x))
+       GC_printf("[unm:%p]", x);
+    else
+       GC_printf("[mkd:%p]", x);
+    if (is_nil(x)) {
+        (void)GC_printf("NIL\n");
+    } else {
+        if (!GC_is_marked((ptr_t)car(x))) GC_printf("[unm car:%p]", car(x));
+        (void)GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
+        if (!is_nil(cdr(x))) {
+            (void)GC_printf(", ");
+            (void)check_marks_int_list(cdr(x));
+        } else {
+            (void)GC_printf("\n");
         }
     }
 }
@@ -524,7 +430,7 @@ sexpr x;
  */
 #ifdef THREADS
 
-# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
+# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
     DWORD  __stdcall tiny_reverse_test(void * arg)
 # else
     void * tiny_reverse_test(void * arg)
@@ -533,9 +439,6 @@ sexpr x;
     int i;
     for (i = 0; i < 5; ++i) {
       check_ints(reverse(reverse(ints(1,10))), 1, 10);
-#     ifdef THREAD_LOCAL_ALLOC
-        check_ints(local_reverse(local_reverse(local_ints(1,10))), 1, 10);
-#     endif
     }
     return 0;
 }
@@ -546,13 +449,11 @@ sexpr x;
       pthread_t t;
       int code;
       if ((code = pthread_create(&t, 0, tiny_reverse_test, 0)) != 0) {
-       (void)GC_printf1("Small thread creation failed %lu\n",
-                        (unsigned long)code);
+       (void)GC_printf("Small thread creation failed %d\n", code);
        FAIL;
       }
       if ((code = pthread_join(t, 0)) != 0) {
-        (void)GC_printf1("Small thread join failed %lu\n",
-       (unsigned long)code);
+        (void)GC_printf("Small thread join failed %d\n", code);
         FAIL;
       }
     }
@@ -564,19 +465,17 @@ sexpr x;
        HANDLE h;
        h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
         if (h == (HANDLE)NULL) {
-            (void)GC_printf1("Small thread creation failed %lu\n",
-                            (unsigned long)GetLastError());
+            (void)GC_printf("Small thread creation failed %d\n",
+                           GetLastError());
            FAIL;
         }
        if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
-           (void)GC_printf1("Small thread wait failed %lu\n",
-                            (unsigned long)GetLastError());
+           (void)GC_printf("Small thread wait failed %d\n",
+                           GetLastError());
            FAIL;
        }
     }
 
-/* # elif defined(GC_SOLARIS_THREADS) */
-
 # else
 
 #   define fork_a_thread()
@@ -640,17 +539,17 @@ void reverse_test()
     collectable_count++;
     f = (sexpr *)GC_MALLOC(4 * sizeof(sexpr));
     realloc_count++;
-    f = (sexpr *)GC_REALLOC((GC_PTR)f, 6 * sizeof(sexpr));
+    f = (sexpr *)GC_REALLOC((void *)f, 6 * sizeof(sexpr));
     f[5] = ints(1,17);
     collectable_count++;
     g = (sexpr *)GC_MALLOC(513 * sizeof(sexpr));
     realloc_count++;
-    g = (sexpr *)GC_REALLOC((GC_PTR)g, 800 * sizeof(sexpr));
+    g = (sexpr *)GC_REALLOC((void *)g, 800 * sizeof(sexpr));
     g[799] = ints(1,18);
     collectable_count++;
     h = (sexpr *)GC_MALLOC(1025 * sizeof(sexpr));
     realloc_count++;
-    h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr));
+    h = (sexpr *)GC_REALLOC((void *)h, 2000 * sizeof(sexpr));
 #   ifdef GC_GCJ_SUPPORT
       h[1999] = gcj_ints(1,200);
       for (i = 0; i < 51; ++i) 
@@ -686,15 +585,12 @@ void reverse_test()
        /* 49 integers.  Thus this is thread safe without locks,          */
        /* assuming atomic pointer assignments.                           */
         a = reverse(reverse(a));
-#       ifdef THREAD_LOCAL_ALLOC
-         a = local_reverse(local_reverse(a));
-#      endif
 #      if !defined(AT_END) && !defined(THREADS)
          /* This is not thread safe, since realloc explicitly deallocates */
           if (i & 1) {
-            a = (sexpr)GC_REALLOC((GC_PTR)a, 500);
+            a = (sexpr)GC_REALLOC((void *)a, 500);
           } else {
-            a = (sexpr)GC_REALLOC((GC_PTR)a, 8200);
+            a = (sexpr)GC_REALLOC((void *)a, 8200);
           }
 #      endif
     }
@@ -730,7 +626,7 @@ typedef struct treenode {
 
 int finalizable_count = 0;
 int finalized_count = 0;
-VOLATILE int dropped_something = 0;
+volatile int dropped_something = 0;
 
 # ifdef __STDC__
   void finalizer(void * obj, void * client_data)
@@ -745,20 +641,14 @@ VOLATILE int dropped_something = 0;
 # ifdef PCR
      PCR_ThCrSec_EnterSys();
 # endif
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-    static mutex_t incr_lock;
-    mutex_lock(&incr_lock);
-# endif
-# if  defined(GC_PTHREADS)
+# if defined(GC_PTHREADS)
     static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
     pthread_mutex_lock(&incr_lock);
-# else
-#   ifdef GC_WIN32_THREADS
-      EnterCriticalSection(&incr_cs);
-#   endif
+# elif defined(GC_WIN32_THREADS)
+    EnterCriticalSection(&incr_cs);
 # endif
   if ((int)(GC_word)client_data != t -> level) {
-     (void)GC_printf0("Wrong finalization data - collector is broken\n");
+     (void)GC_printf("Wrong finalization data - collector is broken\n");
      FAIL;
   }
   finalized_count++;
@@ -766,15 +656,10 @@ VOLATILE int dropped_something = 0;
 # ifdef PCR
     PCR_ThCrSec_ExitSys();
 # endif
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-    mutex_unlock(&incr_lock);
-# endif
 # if defined(GC_PTHREADS)
     pthread_mutex_unlock(&incr_lock);
-# else
-#   ifdef GC_WIN32_THREADS
-      LeaveCriticalSection(&incr_cs);
-#   endif
+# elif defined(GC_WIN32_THREADS)
+    LeaveCriticalSection(&incr_cs);
 # endif
 }
 
@@ -791,36 +676,24 @@ size_t counter = 0;
 
 int live_indicators_count = 0;
 
-tn * mktree(n)
-int n;
+tn * mktree(int n)
 {
-#   ifdef THREAD_LOCAL_ALLOC
-      tn * result = (tn *)GC_LOCAL_MALLOC(sizeof(tn));
-#   else
-      tn * result = (tn *)GC_MALLOC(sizeof(tn));
-#   endif
+    tn * result = (tn *)GC_MALLOC(sizeof(tn));
     
     collectable_count++;
-#   ifdef THREAD_LOCAL_ALLOC
-       /* Minimally exercise thread local allocation */
-       {
-         char * result = (char *)GC_LOCAL_MALLOC_ATOMIC(17);
-        memset(result, 'a', 17);
-       }
-#   endif /* THREAD_LOCAL_ALLOC */
 #   if defined(MACOS)
        /* get around static data limitations. */
        if (!live_indicators)
                live_indicators =
                    (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
        if (!live_indicators) {
-          (void)GC_printf0("Out of memory\n");
+          (void)GC_printf("Out of memory\n");
           exit(1);
         }
 #   endif
     if (n == 0) return(0);
     if (result == 0) {
-        (void)GC_printf0("Out of memory\n");
+        (void)GC_printf("Out of memory\n");
         exit(1);
     }
     result -> level = n;
@@ -839,17 +712,11 @@ int n;
 #        ifdef PCR
            PCR_ThCrSec_EnterSys();
 #        endif
-#        if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-           static mutex_t incr_lock;
-           mutex_lock(&incr_lock);
-#        endif
 #         if defined(GC_PTHREADS)
             static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
             pthread_mutex_lock(&incr_lock);
-#         else
-#           ifdef GC_WIN32_THREADS
-              EnterCriticalSection(&incr_cs);
-#           endif
+#         elif defined(GC_WIN32_THREADS)
+            EnterCriticalSection(&incr_cs);
 #         endif
                /* Losing a count here causes erroneous report of failure. */
           finalizable_count++;
@@ -857,59 +724,52 @@ int n;
 #        ifdef PCR
            PCR_ThCrSec_ExitSys();
 #        endif
-#        if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-           mutex_unlock(&incr_lock);
-#        endif
 #        if defined(GC_PTHREADS)
            pthread_mutex_unlock(&incr_lock);
-#        else
-#           ifdef GC_WIN32_THREADS
-              LeaveCriticalSection(&incr_cs);
-#           endif
+#        elif defined(GC_WIN32_THREADS)
+            LeaveCriticalSection(&incr_cs);
 #         endif
        }
 
-        GC_REGISTER_FINALIZER((GC_PTR)result, finalizer, (GC_PTR)(GC_word)n,
-                             (GC_finalization_proc *)0, (GC_PTR *)0);
+        GC_REGISTER_FINALIZER((void *)result, finalizer, (void *)(GC_word)n,
+                             (GC_finalization_proc *)0, (void * *)0);
         if (my_index >= MAX_FINALIZED) {
-               GC_printf0("live_indicators overflowed\n");
+               GC_printf("live_indicators overflowed\n");
                FAIL;
        }
         live_indicators[my_index] = 13;
         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
-               (GC_PTR *)(&(live_indicators[my_index])),
-               (GC_PTR)result) != 0) {
-               GC_printf0("GC_general_register_disappearing_link failed\n");
+               (void * *)(&(live_indicators[my_index])),
+               (void *)result) != 0) {
+               GC_printf("GC_general_register_disappearing_link failed\n");
                FAIL;
         }
         if (GC_unregister_disappearing_link(
-               (GC_PTR *)
+               (void * *)
                   (&(live_indicators[my_index]))) == 0) {
-               GC_printf0("GC_unregister_disappearing_link failed\n");
+               GC_printf("GC_unregister_disappearing_link failed\n");
                FAIL;
         }
         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
-               (GC_PTR *)(&(live_indicators[my_index])),
-               (GC_PTR)result) != 0) {
-               GC_printf0("GC_general_register_disappearing_link failed 2\n");
+               (void * *)(&(live_indicators[my_index])),
+               (void *)result) != 0) {
+               GC_printf("GC_general_register_disappearing_link failed 2\n");
                FAIL;
         }
+       GC_reachable_here(result);
     }
     return(result);
 }
 
-void chktree(t,n)
-tn *t;
-int n;
+void chktree(tn *t, int n)
 {
     if (n == 0 && t != 0) {
-        (void)GC_printf0("Clobbered a leaf - collector is broken\n");
+        (void)GC_printf("Clobbered a leaf - collector is broken\n");
         FAIL;
     }
     if (n == 0) return;
     if (t -> level != n) {
-        (void)GC_printf1("Lost a node at level %lu - collector is broken\n",
-                        (unsigned long)n);
+        (void)GC_printf("Lost a node at level %d - collector is broken\n", n);
         FAIL;
     }
     if (counter++ % 373 == 0) {
@@ -924,48 +784,8 @@ int n;
     chktree(t -> rchild, n-1);
 }
 
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-thread_key_t fl_key;
 
-void * alloc8bytes()
-{
-# if defined(SMALL_CONFIG) || defined(GC_DEBUG)
-    collectable_count++;
-    return(GC_MALLOC(8));
-# else
-    void ** my_free_list_ptr;
-    void * my_free_list;
-    
-    if (thr_getspecific(fl_key, (void **)(&my_free_list_ptr)) != 0) {
-       (void)GC_printf0("thr_getspecific failed\n");
-       FAIL;
-    }
-    if (my_free_list_ptr == 0) {
-        uncollectable_count++;
-        my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
-        if (thr_setspecific(fl_key, my_free_list_ptr) != 0) {
-           (void)GC_printf0("thr_setspecific failed\n");
-           FAIL;
-        }
-    }
-    my_free_list = *my_free_list_ptr;
-    if (my_free_list == 0) {
-        collectable_count++;
-        my_free_list = GC_malloc_many(8);
-        if (my_free_list == 0) {
-            (void)GC_printf0("alloc8bytes out of memory\n");
-           FAIL;
-        }
-    }
-    *my_free_list_ptr = GC_NEXT(my_free_list);
-    GC_NEXT(my_free_list) = 0;
-    return(my_free_list);
-# endif
-}
-
-#else
-
-# if defined(GC_PTHREADS)
+#if defined(GC_PTHREADS)
 pthread_key_t fl_key;
 
 void * alloc8bytes()
@@ -982,7 +802,7 @@ void * alloc8bytes()
         uncollectable_count++;
         my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
         if (pthread_setspecific(fl_key, my_free_list_ptr) != 0) {
-           (void)GC_printf0("pthread_setspecific failed\n");
+           (void)GC_printf("pthread_setspecific failed\n");
            FAIL;
         }
     }
@@ -990,7 +810,7 @@ void * alloc8bytes()
     if (my_free_list == 0) {
         my_free_list = GC_malloc_many(8);
         if (my_free_list == 0) {
-            (void)GC_printf0("alloc8bytes out of memory\n");
+            (void)GC_printf("alloc8bytes out of memory\n");
            FAIL;
         }
     }
@@ -1001,20 +821,18 @@ void * alloc8bytes()
 # endif
 }
 
-# else
+#else
 #   define alloc8bytes() GC_MALLOC_ATOMIC(8)
-# endif
 #endif
 
-void alloc_small(n)
-int n;
+void alloc_small(int n)
 {
-    register int i;
+    int i;
     
     for (i = 0; i < n; i += 8) {
         atomic_count++;
         if (alloc8bytes() == 0) {
-            (void)GC_printf0("Out of memory\n");
+            (void)GC_printf("Out of memory\n");
             FAIL;
         }
     }
@@ -1036,7 +854,7 @@ int n;
 void tree_test()
 {
     tn * root;
-    register int i;
+    int i;
     
     root = mktree(TREE_HEIGHT);
 #   ifndef VERY_SMALL_CONFIG
@@ -1044,7 +862,7 @@ void tree_test()
 #   endif
     chktree(root, TREE_HEIGHT);
     if (finalized_count && ! dropped_something) {
-        (void)GC_printf0("Premature finalization - collector is broken\n");
+        (void)GC_printf("Premature finalization - collector is broken\n");
         FAIL;
     }
     dropped_something = 1;
@@ -1085,21 +903,21 @@ void typed_test()
     GC_word bm_large = 0xf7ff7fff;
     GC_descr d1 = GC_make_descriptor(&bm3, 2);
     GC_descr d2 = GC_make_descriptor(&bm2, 2);
-#   ifndef LINT
-      GC_descr dummy = GC_make_descriptor(&bm_large, 32);
-#   endif
     GC_descr d3 = GC_make_descriptor(&bm_large, 32);
     GC_descr d4 = GC_make_descriptor(bm_huge, 320);
     GC_word * x = (GC_word *)GC_malloc_explicitly_typed(2000, d4);
-    register int i;
+    int i;
     
+#   ifndef LINT
+      (void)GC_make_descriptor(&bm_large, 32);
+#   endif
     collectable_count++;
     old = 0;
     for (i = 0; i < 4000; i++) {
        collectable_count++;
         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1);
         if (0 != new[0] || 0 != new[1]) {
-           GC_printf0("Bad initialization by GC_malloc_explicitly_typed\n");
+           GC_printf("Bad initialization by GC_malloc_explicitly_typed\n");
            FAIL;
        }
         new[0] = 17;
@@ -1130,7 +948,7 @@ void typed_test()
                                                       3 * sizeof(GC_word),
                                                       d2);
           if (0 != new[0] || 0 != new[1]) {
-           GC_printf0("Bad initialization by GC_malloc_explicitly_typed\n");
+           GC_printf("Bad initialization by GC_malloc_explicitly_typed\n");
            FAIL;
          }
         }
@@ -1140,8 +958,8 @@ void typed_test()
     }
     for (i = 0; i < 20000; i++) {
         if (new[0] != 17) {
-            (void)GC_printf1("typed alloc failed at %lu\n",
-                            (unsigned long)i);
+            (void)GC_printf("typed alloc failed at %lu\n",
+                           (unsigned long)i);
             FAIL;
         }
         new[0] = 0;
@@ -1157,7 +975,7 @@ int fail_count = 0;
 #ifndef __STDC__
 /*ARGSUSED*/
 void fail_proc1(x)
-GC_PTR x;
+void * x;
 {
     fail_count++;
 }
@@ -1165,7 +983,7 @@ GC_PTR x;
 #else
 
 /*ARGSUSED*/
-void fail_proc1(GC_PTR x)
+void fail_proc1(void * x)
 {
     fail_count++;
 }   
@@ -1181,8 +999,8 @@ static void uniq(void *p, ...) {
   for (i=0; i<n; i++)
     for (j=0; j<i; j++)
       if (q[i] == q[j]) {
-        GC_printf0(
-              "Apparently failed to mark form some function arguments.\n"
+        GC_printf(
+              "Apparently failed to mark from some function arguments.\n"
               "Perhaps GC_push_regs was configured incorrectly?\n"
         );
        FAIL;
@@ -1208,28 +1026,28 @@ void run_one_test()
     DCL_LOCK_STATE;
     
 #   ifdef FIND_LEAK
-       (void)GC_printf0(
+       (void)GC_printf(
                "This test program is not designed for leak detection mode\n");
-       (void)GC_printf0("Expect lots of problems.\n");
+       (void)GC_printf("Expect lots of problems.\n");
 #   endif
     GC_FREE(0);
 #   ifndef DBG_HDRS_ALL
       collectable_count += 3;
-      if (GC_size(GC_malloc(7)) != 8 &&
-         GC_size(GC_malloc(7)) != MIN_WORDS * sizeof(GC_word)
+      if ((GC_size(GC_malloc(7)) != 8 &&
+          GC_size(GC_malloc(7)) != MIN_WORDS * sizeof(GC_word))
        || GC_size(GC_malloc(15)) != 16) {
-           (void)GC_printf0("GC_size produced unexpected results\n");
+           (void)GC_printf("GC_size produced unexpected results\n");
            FAIL;
       }
       collectable_count += 1;
       if (GC_size(GC_malloc(0)) != MIN_WORDS * sizeof(GC_word)) {
-       (void)GC_printf1("GC_malloc(0) failed: GC_size returns %ld\n",
-                        GC_size(GC_malloc(0)));
+       (void)GC_printf("GC_malloc(0) failed: GC_size returns %ld\n",
+                       (unsigned long)GC_size(GC_malloc(0)));
            FAIL;
       }
       collectable_count += 1;
       if (GC_size(GC_malloc_uncollectable(0)) != MIN_WORDS * sizeof(GC_word)) {
-       (void)GC_printf0("GC_malloc_uncollectable(0) failed\n");
+       (void)GC_printf("GC_malloc_uncollectable(0) failed\n");
            FAIL;
       }
       GC_is_valid_displacement_print_proc = fail_proc1;
@@ -1237,21 +1055,21 @@ void run_one_test()
       collectable_count += 1;
       x = GC_malloc(16);
       if (GC_base(x + 13) != x) {
-       (void)GC_printf0("GC_base(heap ptr) produced incorrect result\n");
+       (void)GC_printf("GC_base(heap ptr) produced incorrect result\n");
        FAIL;
       }
 #     ifndef PCR
         if (GC_base(y) != 0) {
-         (void)GC_printf0("GC_base(fn_ptr) produced incorrect result\n");
+         (void)GC_printf("GC_base(fn_ptr) produced incorrect result\n");
          FAIL;
         }
 #     endif
       if (GC_same_obj(x+5, x) != x + 5) {
-       (void)GC_printf0("GC_same_obj produced incorrect result\n");
+       (void)GC_printf("GC_same_obj produced incorrect result\n");
        FAIL;
       }
       if (GC_is_visible(y) != y || GC_is_visible(x) != x) {
-       (void)GC_printf0("GC_is_visible produced incorrect result\n");
+       (void)GC_printf("GC_is_visible produced incorrect result\n");
        FAIL;
       }
       if (!TEST_FAIL_COUNT(1)) {
@@ -1260,14 +1078,14 @@ void run_one_test()
          /* data segment, so there should have been no failures.       */
          /* The same applies to IA64.  Something similar seems to      */
          /* be going on with NetBSD/M68K.                              */
-         (void)GC_printf0("GC_is_visible produced wrong failure indication\n");
+         (void)GC_printf("GC_is_visible produced wrong failure indication\n");
          FAIL;
 #      endif
       }
       if (GC_is_valid_displacement(y) != y
         || GC_is_valid_displacement(x) != x
         || GC_is_valid_displacement(x + 3) != x + 3) {
-       (void)GC_printf0(
+       (void)GC_printf(
                "GC_is_valid_displacement produced incorrect result\n");
        FAIL;
       }
@@ -1291,7 +1109,7 @@ void run_one_test()
         if (GC_all_interior_pointers && !TEST_FAIL_COUNT(1)
            || !GC_all_interior_pointers && !TEST_FAIL_COUNT(2)) {
 #      endif
-         (void)GC_printf0("GC_is_valid_displacement produced wrong failure indication\n");
+         (void)GC_printf("GC_is_valid_displacement produced wrong failure indication\n");
          FAIL;
         }
 #     endif
@@ -1319,15 +1137,20 @@ void run_one_test()
        (GC_gcollect(),GC_malloc(12)),
         (void *)0);
 #   endif
+    /* GC_malloc(0) must return NULL or something we can deallocate. */
+        GC_free(GC_malloc(0));
+        GC_free(GC_malloc_atomic(0));
+        GC_free(GC_malloc(0));
+        GC_free(GC_malloc_atomic(0));
     /* Repeated list reversal test. */
        reverse_test();
 #   ifdef PRINTSTATS
-       GC_printf0("-------------Finished reverse_test\n");
+       GC_printf("-------------Finished reverse_test\n");
 #   endif
 #   ifndef DBG_HDRS_ALL
       typed_test();
 #     ifdef PRINTSTATS
-       GC_printf0("-------------Finished typed_test\n");
+       GC_printf("-------------Finished typed_test\n");
 #     endif
 #   endif /* DBG_HDRS_ALL */
     tree_test();
@@ -1339,17 +1162,17 @@ void run_one_test()
        GC_gcollect();
        tiny_reverse_test(0);
        GC_gcollect();
-       GC_printf0("Finished a child process\n");
+       GC_printf("Finished a child process\n");
        exit(0);
       }
 #   endif
-    /* GC_printf1("Finished %x\n", pthread_self()); */
+    /* GC_printf("Finished %x\n", pthread_self()); */
 }
 
 void check_heap_stats()
 {
-    unsigned long max_heap_sz;
-    register int i;
+    size_t max_heap_sz;
+    int i;
     int still_live;
     int late_finalize_count = 0;
     
@@ -1367,10 +1190,6 @@ void check_heap_stats()
        max_heap_sz = 11000000;
     }
 #   endif
-#   ifndef ALIGN_DOUBLE
-        /* We end up needing more small object pages. */
-        max_heap_sz += 2000000;
-#   endif
 #   ifdef GC_DEBUG
        max_heap_sz *= 2;
 #       ifdef SAVE_CALL_CHAIN
@@ -1387,26 +1206,26 @@ void check_heap_stats()
         GC_gcollect();
         late_finalize_count += GC_invoke_finalizers();
       }
-    (void)GC_printf1("Completed %lu tests\n", (unsigned long)n_tests);
-    (void)GC_printf1("Allocated %lu collectable objects\n", (unsigned long)collectable_count);
-    (void)GC_printf1("Allocated %lu uncollectable objects\n", (unsigned long)uncollectable_count);
-    (void)GC_printf1("Allocated %lu atomic objects\n", (unsigned long)atomic_count);
-    (void)GC_printf1("Allocated %lu stubborn objects\n", (unsigned long)stubborn_count);
-    (void)GC_printf2("Finalized %lu/%lu objects - ",
-                    (unsigned long)finalized_count,
-                    (unsigned long)finalizable_count);
+    (void)GC_printf("Completed %u tests\n", n_tests);
+    (void)GC_printf("Allocated %d collectable objects\n", collectable_count);
+    (void)GC_printf("Allocated %d uncollectable objects\n",
+                   uncollectable_count);
+    (void)GC_printf("Allocated %d atomic objects\n", atomic_count);
+    (void)GC_printf("Allocated %d stubborn objects\n", stubborn_count);
+    (void)GC_printf("Finalized %d/%d objects - ",
+                   finalized_count, finalizable_count);
 #   ifdef FINALIZE_ON_DEMAND
        if (finalized_count != late_finalize_count) {
-            (void)GC_printf0("Demand finalization error\n");
+            (void)GC_printf("Demand finalization error\n");
            FAIL;
        }
 #   endif
     if (finalized_count > finalizable_count
         || finalized_count < finalizable_count/2) {
-        (void)GC_printf0("finalization is probably broken\n");
+        (void)GC_printf("finalization is probably broken\n");
         FAIL;
     } else {
-        (void)GC_printf0("finalization is probably ok\n");
+        (void)GC_printf("finalization is probably ok\n");
     }
     still_live = 0;
     for (i = 0; i < MAX_FINALIZED; i++) {
@@ -1416,34 +1235,33 @@ void check_heap_stats()
     }
     i = finalizable_count - finalized_count - still_live;
     if (0 != i) {
-        (void)GC_printf2
-            ("%lu disappearing links remain and %ld more objects were not finalized\n",
-             (unsigned long) still_live, (long)i);
+        GC_printf("%d disappearing links remain and %d more objects "
+                 "were not finalized\n", still_live, i);
         if (i > 10) {
-           GC_printf0("\tVery suspicious!\n");
+           GC_printf("\tVery suspicious!\n");
        } else {
-           GC_printf0("\tSlightly suspicious, but probably OK.\n");
+           GC_printf("\tSlightly suspicious, but probably OK.\n");
        }
     }
-    (void)GC_printf1("Total number of bytes allocated is %lu\n",
+    (void)GC_printf("Total number of bytes allocated is %lu\n",
                (unsigned long)
-                  WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc));
-    (void)GC_printf1("Final heap size is %lu bytes\n",
-                    (unsigned long)GC_get_heap_size());
-    if (WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc)
+                  (GC_bytes_allocd + GC_bytes_allocd_before_gc));
+    (void)GC_printf("Final heap size is %lu bytes\n",
+                   (unsigned long)GC_get_heap_size());
+    if (GC_bytes_allocd + GC_bytes_allocd_before_gc
 #   ifdef VERY_SMALL_CONFIG
         < 2700000*n_tests) {
 #   else
         < 33500000*n_tests) {
 #   endif
-        (void)GC_printf0("Incorrect execution - missed some allocations\n");
+        (void)GC_printf("Incorrect execution - missed some allocations\n");
         FAIL;
     }
     if (GC_get_heap_size() > max_heap_sz*n_tests) {
-        (void)GC_printf0("Unexpected heap growth - collector may be broken\n");
+        (void)GC_printf("Unexpected heap growth - collector may be broken\n");
         FAIL;
     }
-    (void)GC_printf0("Collector appears to work\n");
+    (void)GC_printf("Collector appears to work\n");
 }
 
 #if defined(MACOS)
@@ -1472,12 +1290,12 @@ void SetMinimumStack(long minSize)
     GC_word p;
 #endif
 {
-    GC_printf1(msg, (unsigned long)p);
+    GC_printf(msg, (unsigned long)p);
     /*FAIL;*/
 }
 
 
-#if !defined(PCR) && !defined(GC_SOLARIS_THREADS) \
+#if !defined(PCR) \
     && !defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) \
     || defined(LINT)
 #if defined(MSWIN32) && !defined(__MINGW32__)
@@ -1494,7 +1312,7 @@ void SetMinimumStack(long minSize)
 #   if defined(DJGPP)
        /* No good way to determine stack base from library; do it */
        /* manually on this platform.                              */
-       GC_stackbottom = (GC_PTR)(&dummy);
+       GC_stackbottom = (void *)(&dummy);
 #   endif
 #   if defined(MACOS)
        /* Make sure we have lots and lots of stack space.      */
@@ -1504,17 +1322,17 @@ void SetMinimumStack(long minSize)
 #   endif
     GC_INIT(); /* Only needed on a few platforms.      */
     (void) GC_set_warn_proc(warn_proc);
-#   if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
-          && !defined(MAKE_BACK_GRAPH)
+#   if (defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(GWW_VDB)) \
+          && !defined(MAKE_BACK_GRAPH) && !defined(NO_INCREMENTAL)
       GC_enable_incremental();
-      (void) GC_printf0("Switched to incremental mode\n");
+      (void) GC_printf("Switched to incremental mode\n");
 #     if defined(MPROTECT_VDB)
-       (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
+       (void)GC_printf("Emulating dirty bits with mprotect/signals\n");
 #     else
 #       ifdef PROC_VDB
-       (void)GC_printf0("Reading dirty bits from /proc\n");
+       (void)GC_printf("Reading dirty bits from /proc\n");
 #       else
-    (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
+    (void)GC_printf("Using DEFAULT_VDB dirty bit implementation\n");
 #       endif
 #      endif
 #   endif
@@ -1547,7 +1365,7 @@ void SetMinimumStack(long minSize)
 }
 # endif
 
-#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
+#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
 
 DWORD __stdcall thr_run_one_test(void *arg)
 {
@@ -1564,11 +1382,11 @@ LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   LRESULT ret = 0;
   switch (uMsg) {
     case WM_HIBERNATE:
-      GC_printf0("Received WM_HIBERNATE, calling GC_gcollect\n");
+      GC_printf("Received WM_HIBERNATE, calling GC_gcollect\n");
       GC_gcollect();
       break;
     case WM_CLOSE:
-      GC_printf0("Received WM_CLOSE, closing window\n");
+      GC_printf("Received WM_CLOSE, closing window\n");
       DestroyWindow(hwnd);
       break;
     case WM_DESTROY:
@@ -1644,21 +1462,26 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
     HANDLE win_thr_h;
 # endif
   DWORD thread_id;
-# if 0
+
+# ifdef GC_DLL
+    GC_use_DllMain();  /* Test with implicit thread registration if possible. */
+    GC_printf("Using DllMain to track threads\n");
+# endif
+  GC_INIT();
+# ifndef NO_INCREMENTAL
     GC_enable_incremental();
 # endif
-  GC_init();
   InitializeCriticalSection(&incr_cs);
   (void) GC_set_warn_proc(warn_proc);
 # ifdef MSWINCE
     win_created_h = CreateEvent(NULL, FALSE, FALSE, NULL);
     if (win_created_h == (HANDLE)NULL) {
-      (void)GC_printf1("Event creation failed %lu\n", (unsigned long)GetLastError());
+      (void)GC_printf("Event creation failed %\n", GetLastError());
       FAIL;
     }
     win_thr_h = GC_CreateThread(NULL, 0, thr_window, 0, 0, &thread_id);
     if (win_thr_h == (HANDLE)NULL) {
-      (void)GC_printf1("Thread creation failed %lu\n", (unsigned long)GetLastError());
+      (void)GC_printf("Thread creation failed %d\n", GetLastError());
       FAIL;
     }
     if (WaitForSingleObject(win_created_h, INFINITE) != WAIT_OBJECT_0)
@@ -1669,7 +1492,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
    for (i = 0; i < NTEST; i++) {
     h[i] = GC_CreateThread(NULL, 0, thr_run_one_test, 0, 0, &thread_id);
     if (h[i] == (HANDLE)NULL) {
-      (void)GC_printf1("Thread creation failed %lu\n", (unsigned long)GetLastError());
+      (void)GC_printf("Thread creation failed %d\n", GetLastError());
       FAIL;
     }
    }
@@ -1678,7 +1501,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
 # if NTEST > 0
    for (i = 0; i < NTEST; i++) {
     if (WaitForSingleObject(h[i], INFINITE) != WAIT_OBJECT_0) {
-      (void)GC_printf1("Thread wait failed %lu\n", (unsigned long)GetLastError());
+      (void)GC_printf("Thread wait failed %d\n", GetLastError());
       FAIL;
     }
    }
@@ -1710,18 +1533,18 @@ test()
     run_one_test();
     if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
         != PCR_ERes_okay || code != 0) {
-        (void)GC_printf0("Thread 1 failed\n");
+        (void)GC_printf("Thread 1 failed\n");
     }
     if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
         != PCR_ERes_okay || code != 0) {
-        (void)GC_printf0("Thread 2 failed\n");
+        (void)GC_printf("Thread 2 failed\n");
     }
     check_heap_stats();
     return(0);
 }
 #endif
 
-#if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS)
+#if defined(GC_PTHREADS)
 void * thr_run_one_test(void * arg)
 {
     run_one_test();
@@ -1732,57 +1555,12 @@ void * thr_run_one_test(void * arg)
 #  define GC_free GC_debug_free
 #endif
 
-#if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-main()
-{
-    thread_t th1;
-    thread_t th2;
-    int code;
-
-    n_tests = 0;
-    GC_INIT(); /* Only needed if gc is dynamic library.        */
-#   ifndef MAKE_BACK_GRAPH
-      GC_enable_incremental();
-#   endif
-    (void) GC_set_warn_proc(warn_proc);
-    if (thr_keycreate(&fl_key, GC_free) != 0) {
-        (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
-       FAIL;
-    }
-    if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, 0, &th1)) != 0) {
-       (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
-       FAIL;
-    }
-    if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, THR_NEW_LWP, &th2)) != 0) {
-       (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
-       FAIL;
-    }
-    run_one_test();
-    if ((code = thr_join(th1, 0, 0)) != 0) {
-        (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
-        FAIL;
-    }
-    if (thr_join(th2, 0, 0) != 0) {
-        (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
-        FAIL;
-    }
-    check_heap_stats();
-    (void)fflush(stdout);
-    return(0);
-}
-#else /* pthreads */
-
-#ifndef GC_PTHREADS
-  --> bad news
-#endif
-
-main()
+int main()
 {
     pthread_t th1;
     pthread_t th2;
     pthread_attr_t attr;
     int code;
-
 #   ifdef GC_IRIX_THREADS
        /* Force a larger stack to be preallocated      */
        /* Since the initial cant always grow later.    */
@@ -1792,9 +1570,13 @@ main()
        /* Default stack size is too small, especially with the 64 bit ABI */
        /* Increase it.                                                    */
        if (pthread_default_stacksize_np(1024*1024, 0) != 0) {
-          (void)GC_printf0("pthread_default_stacksize_np failed.\n");
+          (void)GC_printf("pthread_default_stacksize_np failed.\n");
        }
 #   endif      /* GC_HPUX_THREADS */
+#   ifdef PTW32_STATIC_LIB
+       pthread_win32_process_attach_np ();
+       pthread_win32_thread_attach_np ();
+#   endif
     GC_INIT();
 
     pthread_attr_init(&attr);
@@ -1805,46 +1587,50 @@ main()
     n_tests = 0;
 #   if (defined(MPROTECT_VDB)) \
             && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) \
-            && !defined(MAKE_BACK_GRAPH)
+            && !defined(MAKE_BACK_GRAPH) && !defined(USE_PROC_FOR_LIBRARIES) \
+           && !defined(NO_INCREMENTAL)
        GC_enable_incremental();
-        (void) GC_printf0("Switched to incremental mode\n");
+        (void) GC_printf("Switched to incremental mode\n");
 #     if defined(MPROTECT_VDB)
-        (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
+        (void)GC_printf("Emulating dirty bits with mprotect/signals\n");
 #     else
 #       ifdef PROC_VDB
-            (void)GC_printf0("Reading dirty bits from /proc\n");
+            (void)GC_printf("Reading dirty bits from /proc\n");
 #       else
-            (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
+            (void)GC_printf("Using DEFAULT_VDB dirty bit implementation\n");
 #       endif
 #     endif
 #   endif
     (void) GC_set_warn_proc(warn_proc);
     if ((code = pthread_key_create(&fl_key, 0)) != 0) {
-        (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
+        (void)GC_printf("Key creation failed %d\n", code);
        FAIL;
     }
     if ((code = pthread_create(&th1, &attr, thr_run_one_test, 0)) != 0) {
-       (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
+       (void)GC_printf("Thread 1 creation failed %d\n", code);
        FAIL;
     }
     if ((code = pthread_create(&th2, &attr, thr_run_one_test, 0)) != 0) {
-       (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
+       (void)GC_printf("Thread 2 creation failed %d\n", code);
        FAIL;
     }
     run_one_test();
     if ((code = pthread_join(th1, 0)) != 0) {
-        (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
+        (void)GC_printf("Thread 1 failed %d\n", code);
         FAIL;
     }
     if (pthread_join(th2, 0) != 0) {
-        (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
+        (void)GC_printf("Thread 2 failed %d\n", code);
         FAIL;
     }
     check_heap_stats();
     (void)fflush(stdout);
     pthread_attr_destroy(&attr);
-    GC_printf1("Completed %d collections\n", GC_gc_no);
+    GC_printf("Completed %d collections\n", GC_gc_no);
+#   ifdef PTW32_STATIC_LIB
+       pthread_win32_thread_detach_np ();
+       pthread_win32_process_detach_np ();
+#   endif
     return(0);
 }
 #endif /* GC_PTHREADS */
-#endif /* GC_SOLARIS_THREADS || GC_PTHREADS */
index 6661e411927fba49ccc3d45dac85756ad4ad2d21..9bf53de811ec88b9c7dd031178cad0d9705354fd 100644 (file)
@@ -37,7 +37,11 @@ few minutes to complete.
 #   include "gc_alloc.h"
 #endif
 extern "C" {
-#include "private/gc_priv.h"
+# include "private/gcconfig.h"
+  GC_API void GC_printf(const char *format, ...);
+  /* Use GC private output to reach the same log file.  */
+  /* Don't include gc_priv.h, since that may include Windows system    */
+  /* header files that don't take kindly to this context.              */
 }
 #ifdef MSWIN32
 #   include <windows.h>
@@ -52,7 +56,7 @@ extern "C" {
 
 #define my_assert( e ) \
     if (! (e)) { \
-        GC_printf1( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
+        GC_printf( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
                     __LINE__ ); \
         exit( 1 ); }
 
@@ -119,7 +123,7 @@ class D: public gc {public:
     static void CleanUp( void* obj, void* data ) {
         D* self = (D*) obj;
         nFreed++;
-        my_assert( self->i == (int) (long) data );}
+        my_assert( self->i == (int) (GC_word) data );}
     static void Test() {
         my_assert( nFreed >= .8 * nAllocated );}
        
@@ -166,10 +170,10 @@ int F::nFreed = 0;
 int F::nAllocated = 0;
    
 
-long Disguise( void* p ) {
-    return ~ (long) p;}
+GC_word Disguise( void* p ) {
+    return ~ (GC_word) p;}
 
-void* Undisguise( long i ) {
+void* Undisguise( GC_word i ) {
     return (void*) ~ i;}
 
 
@@ -216,17 +220,17 @@ int APIENTRY WinMain(
       x = 0;
 #   endif
     if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
-        GC_printf0( "usage: test_cpp number-of-iterations\nAssuming 10 iters\n" );
+        GC_printf( "usage: test_cpp number-of-iterations\nAssuming 10 iters\n" );
         n = 10;}
         
     for (iters = 1; iters <= n; iters++) {
-        GC_printf1( "Starting iteration %d\n", iters );
+        GC_printf( "Starting iteration %d\n", iters );
 
             /* Allocate some uncollectable As and disguise their pointers.
             Later we'll check to see if the objects are still there.  We're
             checking to make sure these objects really are uncollectable. */
-        long as[ 1000 ];
-        long bs[ 1000 ];
+        GC_word as[ 1000 ];
+        GC_word bs[ 1000 ];
         for (i = 0; i < 1000; i++) {
             as[ i ] = Disguise( new (NoGC) A( i ) );
             bs[ i ] = Disguise( new (NoGC) B( i ) );}
@@ -236,7 +240,7 @@ int APIENTRY WinMain(
         for (i = 0; i < 1000; i++) {
             C* c = new C( 2 );
             C c1( 2 );           /* stack allocation should work too */
-            D* d = ::new (USE_GC, D::CleanUp, (void*)(long)i) D( i );
+            D* d = ::new (USE_GC, D::CleanUp, (void*)(GC_word)i) D( i );
             F* f = new F;
             if (0 == i % 10) delete c;}
 
@@ -282,7 +286,7 @@ int APIENTRY WinMain(
       x = *xptr;
 #   endif
     my_assert (29 == x[0]);
-    GC_printf0( "The test appears to have succeeded.\n" );
+    GC_printf( "The test appears to have succeeded.\n" );
     return( 0 );}
     
 
diff --git a/src/mm/boehm-gc/tests/tests.am b/src/mm/boehm-gc/tests/tests.am
new file mode 100644 (file)
index 0000000..aedac1f
--- /dev/null
@@ -0,0 +1,57 @@
+#
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program
+# for any purpose,  provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+
+
+## FIXME: trace_test don't works on macosx 10.3 
+## gcc -g -O2 -o .libs/tracetest trace_test.o  ../.libs/libgc.dylib -lpthread
+## ld: Undefined symbols:
+## _GC_generate_random_backtrace
+
+
+# Common libs to _LDADD for all tests.
+test_ldadd = $(top_builddir)/libgc.la $(EXTRA_TEST_LIBS)
+
+
+TESTS += gctest$(EXEEXT)
+check_PROGRAMS += gctest
+gctest_SOURCES = tests/test.c
+gctest_LDADD = $(test_ldadd)
+gctest_DEPENDENCIES = $(top_builddir)/libgc.la
+
+TESTS += leaktest$(EXEEXT)
+check_PROGRAMS += leaktest
+leaktest_SOURCES = tests/leak_test.c
+leaktest_LDADD = $(test_ldadd)
+
+TESTS += middletest$(EXEEXT)
+check_PROGRAMS += middletest
+middletest_SOURCES = tests/middle.c
+middletest_LDADD = $(test_ldadd)
+
+#TESTS += tracetest$(EXEEXT)
+#check_PROGRAMS += tracetest
+#tracetest_SOURCES = tests/trace_test.c
+#tracetest_LDADD = $(test_ldadd)
+
+if THREADS
+TESTS += threadleaktest$(EXEEXT)
+check_PROGRAMS += threadleaktest
+threadleaktest_SOURCES = tests/thread_leak_test.c
+threadleaktest_LDADD = $(test_ldadd)
+endif
+
+if CPLUSPLUS
+TESTS += test_cpp$(EXEEXT)
+check_PROGRAMS += test_cpp
+test_cpp_SOURCES = tests/test_cpp.cc
+test_cpp_LDADD = libgccpp.la $(test_ldadd)
+endif
+
index 1174705e45e9b7e81f32737b6bc757a2149126af..f2c15e967133d4e42a1c93d96ef0f2c3306978dc 100644 (file)
@@ -1,4 +1,6 @@
-#define GC_LINUX_THREADS
+#ifndef GC_THREADS
+#  define GC_THREADS
+#endif /* GC_THREADS */
 #include "leak_detector.h"
 #include <pthread.h>
 #include <stdio.h>
@@ -15,6 +17,7 @@ void * test(void * arg) {
     for (i = 1; i < 10; ++i) {
         free(p[i]);
     }
+    return 0;
 }       
 
 #define NTHREADS 5
@@ -24,6 +27,7 @@ main() {
     pthread_t t[NTHREADS];
     int code;
 
+    GC_INIT();
     for (i = 0; i < NTHREADS; ++i) {
        if ((code = pthread_create(t + i, 0, test, 0)) != 0) {
            printf("Thread creation failed %d\n", code);
@@ -37,4 +41,5 @@ main() {
     CHECK_LEAKS();
     CHECK_LEAKS();
     CHECK_LEAKS();
+    return 0;
 }
diff --git a/src/mm/boehm-gc/tests/trace_test.c b/src/mm/boehm-gc/tests/trace_test.c
deleted file mode 100644 (file)
index 870e387..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <stdio.h>
-#define GC_DEBUG
-#include "gc.h"
-
-struct treenode {
-    struct treenode *x;
-    struct treenode *y;
-} * root[10];
-
-struct treenode * mktree(int i) {
-  struct treenode * r = GC_MALLOC(sizeof(struct treenode));
-  if (0 == i) return 0;
-  if (1 == i) r = GC_MALLOC_ATOMIC(sizeof(struct treenode));
-  r -> x = mktree(i-1);
-  r -> y = mktree(i-1);
-  return r;
-}
-
-main()
-{
-  int i;
-  for (i = 0; i < 10; ++i) {
-    root[i] = mktree(12);
-  }
-  GC_generate_random_backtrace();
-  GC_generate_random_backtrace();
-  GC_generate_random_backtrace();
-  GC_generate_random_backtrace();
-}
diff --git a/src/mm/boehm-gc/thread_local_alloc.c b/src/mm/boehm-gc/thread_local_alloc.c
new file mode 100644 (file)
index 0000000..d134602
--- /dev/null
@@ -0,0 +1,313 @@
+/* 
+ * Copyright (c) 2000-2005 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.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#include "config.h"
+
+#include "private/gc_priv.h"
+
+# if defined(THREAD_LOCAL_ALLOC)
+
+#include "private/thread_local_alloc.h"
+#include "gc_inline.h"
+
+# include <stdlib.h>
+
+#if defined(USE_COMPILER_TLS)
+  __thread
+#elif defined(USE_WIN32_COMPILER_TLS)
+  __declspec(thread)
+#endif
+GC_key_t GC_thread_key;
+
+static GC_bool keys_initialized;
+
+/* Return a single nonempty freelist fl to the global one pointed to   */
+/* by gfl.     */
+
+static void return_single_freelist(void *fl, void **gfl)
+{
+    void *q, **qptr;
+
+    if (*gfl == 0) {
+      *gfl = fl;
+    } else {
+      GC_ASSERT(GC_size(fl) == GC_size(*gfl));
+      /* Concatenate: */
+       for (qptr = &(obj_link(fl)), q = *qptr;
+            (word)q >= HBLKSIZE; qptr = &(obj_link(q)), q = *qptr);
+       GC_ASSERT(0 == q);
+       *qptr = *gfl;
+       *gfl = fl;
+    }
+}
+
+/* Recover the contents of the freelist array fl into the global one gfl.*/
+/* We hold the allocator lock.                                         */
+static void return_freelists(void **fl, void **gfl)
+{
+    int i;
+
+    for (i = 1; i < TINY_FREELISTS; ++i) {
+       if ((word)(fl[i]) >= HBLKSIZE) {
+         return_single_freelist(fl[i], gfl+i);
+       }
+       /* Clear fl[i], since the thread structure may hang around.     */
+       /* Do it in a way that is likely to trap if we access it.       */
+       fl[i] = (ptr_t)HBLKSIZE;
+    }
+    /* The 0 granule freelist really contains 1 granule objects.       */
+#   ifdef GC_GCJ_SUPPORT
+      if (fl[0] == ERROR_FL) return;
+#   endif
+    if ((word)(fl[0]) >= HBLKSIZE) {
+        return_single_freelist(fl[0], gfl+1);
+    }
+}
+
+/* Each thread structure must be initialized.  */
+/* This call must be made from the new thread. */
+/* Caller holds allocation lock.               */
+void GC_init_thread_local(GC_tlfs p)
+{
+    int i;
+
+    if (!keys_initialized) {
+       if (0 != GC_key_create(&GC_thread_key, 0)) {
+           ABORT("Failed to create key for local allocator");
+        }
+       keys_initialized = TRUE;
+    }
+    if (0 != GC_setspecific(GC_thread_key, p)) {
+       ABORT("Failed to set thread specific allocation pointers");
+    }
+    for (i = 1; i < TINY_FREELISTS; ++i) {
+       p -> ptrfree_freelists[i] = (void *)1;
+       p -> normal_freelists[i] = (void *)1;
+#      ifdef GC_GCJ_SUPPORT
+         p -> gcj_freelists[i] = (void *)1;
+#      endif
+    }   
+    /* Set up the size 0 free lists.   */
+    /* We now handle most of them like regular free lists, to ensure   */
+    /* That explicit deallocation works.  However, allocation of a     */
+    /* size 0 "gcj" object is always an error.                         */
+    p -> ptrfree_freelists[0] = (void *)1;
+    p -> normal_freelists[0] = (void *)1;
+#   ifdef GC_GCJ_SUPPORT
+        p -> gcj_freelists[0] = ERROR_FL;
+#   endif
+}
+
+#ifdef GC_GCJ_SUPPORT
+  extern void ** GC_gcjobjfreelist;
+#endif
+
+/* We hold the allocator lock. */
+void GC_destroy_thread_local(GC_tlfs p)
+{
+    /* We currently only do this from the thread itself or from        */
+    /* the fork handler for a child process.                   */
+#   ifndef HANDLE_FORK
+      GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
+#   endif
+    return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
+    return_freelists(p -> normal_freelists, GC_objfreelist);
+#   ifdef GC_GCJ_SUPPORT
+       return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
+#   endif
+}
+
+#if defined(GC_ASSERTIONS) && defined(GC_PTHREADS) && !defined(CYGWIN32) \
+    && !defined(GC_WIN32_PTHREADS)
+# include <pthread.h>
+  extern char * GC_lookup_thread(pthread_t id);
+#endif
+
+#if defined(GC_ASSERTIONS) && defined(GC_WIN32_THREADS)
+  extern char * GC_lookup_thread(int id);
+#endif
+
+void * GC_malloc(size_t bytes)
+{
+    size_t granules = ROUNDED_UP_GRANULES(bytes);
+    void *tsd;
+    void *result;
+    void **tiny_fl;
+
+#   if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
+      GC_key_t k = GC_thread_key;
+      if (EXPECT(0 == k, 0)) {
+       /* We haven't yet run GC_init_parallel.  That means     */
+       /* we also aren't locking, so this is fairly cheap.     */
+       return GC_core_malloc(bytes);
+      }
+      tsd = GC_getspecific(k);
+#   else
+      GC_ASSERT(GC_is_initialized);
+      tsd = GC_getspecific(GC_thread_key);
+#   endif
+#   if defined(REDIRECT_MALLOC) && defined(USE_PTHREAD_SPECIFIC)
+      if (EXPECT(NULL == tsd, 0)) {
+       return GC_core_malloc(bytes);
+      }
+#   endif
+#   ifdef GC_ASSERTIONS
+      /* We can't check tsd correctly, since we don't have access to   */
+      /* the right declarations.  But we can check that it's close.    */
+      LOCK();
+      {
+#      if defined(GC_WIN32_THREADS)
+         char * me = (char *)GC_lookup_thread_inner(GetCurrentThreadId());
+#       else
+         char * me = GC_lookup_thread(pthread_self());
+#      endif
+        GC_ASSERT((char *)tsd > me && (char *)tsd < me + 1000);
+      }
+      UNLOCK();
+#   endif
+    tiny_fl = ((GC_tlfs)tsd) -> normal_freelists;
+    GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
+                        NORMAL, GC_core_malloc(bytes), obj_link(result)=0);
+    return result;
+}
+
+void * GC_malloc_atomic(size_t bytes)
+{
+    size_t granules = ROUNDED_UP_GRANULES(bytes);
+    void *result;
+    void **tiny_fl;
+
+    GC_ASSERT(GC_is_initialized);
+    tiny_fl = ((GC_tlfs)GC_getspecific(GC_thread_key))
+                                       -> ptrfree_freelists;
+    GC_FAST_MALLOC_GRANS(result, bytes, tiny_fl, DIRECT_GRANULES,
+                        PTRFREE, GC_core_malloc_atomic(bytes), 0/* no init */);
+    return result;
+}
+
+#ifdef GC_GCJ_SUPPORT
+
+#include "include/gc_gcj.h"
+
+#ifdef GC_ASSERTIONS
+  extern GC_bool GC_gcj_malloc_initialized;
+#endif
+
+extern int GC_gcj_kind;
+
+/* Gcj-style allocation without locks is extremely tricky.  The        */
+/* fundamental issue is that we may end up marking a free list, which  */
+/* has freelist links instead of "vtable" pointers.  That is usually   */
+/* OK, since the next object on the free list will be cleared, and     */
+/* will thus be interpreted as containg a zero descriptor.  That's fine        */
+/* if the object has not yet been initialized.  But there are          */
+/* interesting potential races.                                                */
+/* In the case of incremental collection, this seems hopeless, since   */
+/* the marker may run asynchronously, and may pick up the pointer to   */
+/* the next freelist entry (which it thinks is a vtable pointer), get  */
+/* suspended for a while, and then see an allocated object instead     */
+/* of the vtable.  This made be avoidable with either a handshake with */
+/* the collector or, probably more easily, by moving the free list     */
+/* links to the second word of each object.  The latter isn't a                */
+/* universal win, since on architecture like Itanium, nonzero offsets  */
+/* are not necessarily free.  And there may be cache fill order issues.        */
+/* For now, we punt with incremental GC.  This probably means that     */
+/* incremental GC should be enabled before we fork a second thread.    */
+void * GC_gcj_malloc(size_t bytes,
+                    void * ptr_to_struct_containing_descr)
+{
+  if (GC_EXPECT(GC_incremental, 0)) {
+    return GC_core_gcj_malloc(bytes, ptr_to_struct_containing_descr);
+  } else {
+    size_t granules = ROUNDED_UP_GRANULES(bytes);
+    void *result;
+    void **tiny_fl = ((GC_tlfs)GC_getspecific(GC_thread_key))
+                                       -> gcj_freelists;
+    GC_ASSERT(GC_gcj_malloc_initialized);
+    GC_FAST_MALLOC_GRANS(result, bytes, tiny_fl, DIRECT_GRANULES,
+                        GC_gcj_kind,
+                        GC_core_gcj_malloc(bytes,
+                                           ptr_to_struct_containing_descr),
+                        {AO_compiler_barrier();
+                         *(void **)result = ptr_to_struct_containing_descr;});
+       /* This forces the initialization of the "method ptr".          */
+        /* This is necessary to ensure some very subtle properties     */
+       /* required if a GC is run in the middle of such an allocation. */
+       /* Here we implicitly also assume atomicity for the free list.  */
+        /* and method pointer assignments.                             */
+       /* We must update the freelist before we store the pointer.     */
+       /* Otherwise a GC at this point would see a corrupted           */
+       /* free list.                                                   */
+       /* A real memory barrier is not needed, since the               */
+       /* action of stopping this thread will cause prior writes       */
+       /* to complete.                                                 */
+       /* We assert that any concurrent marker will stop us.           */
+       /* Thus it is impossible for a mark procedure to see the        */
+       /* allocation of the next object, but to see this object        */
+       /* still containing a free list pointer.  Otherwise the         */
+       /* marker, by misinterpreting the freelist link as a vtable     */
+        /* pointer, might find a random "mark descriptor" in the next  */
+        /* object.                                                     */
+    return result;
+  }
+}
+
+#endif /* GC_GCJ_SUPPORT */
+
+/* The thread support layer must arrange to mark thread-local  */
+/* free lists explicitly, since the link field is often        */
+/* invisible to the marker.  It knows hoe to find all threads; */
+/* we take care of an individual thread freelist structure.    */
+void GC_mark_thread_local_fls_for(GC_tlfs p)
+{
+    ptr_t q;
+    int j;
+    
+    for (j = 1; j < TINY_FREELISTS; ++j) {
+      q = p -> ptrfree_freelists[j];
+      if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
+      q = p -> normal_freelists[j];
+      if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
+#     ifdef GC_GCJ_SUPPORT
+        q = p -> gcj_freelists[j];
+        if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
+#     endif /* GC_GCJ_SUPPORT */
+    }
+}
+
+#if defined(GC_ASSERTIONS)
+    /* Check that all thread-local free-lists in p are completely marked.      */
+    void GC_check_tls_for(GC_tlfs p)
+    {
+       ptr_t q;
+       int j;
+       
+       for (j = 1; j < TINY_FREELISTS; ++j) {
+         q = p -> ptrfree_freelists[j];
+         if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
+         q = p -> normal_freelists[j];
+         if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
+#        ifdef GC_GCJ_SUPPORT
+           q = p -> gcj_freelists[j];
+           if ((word)q > HBLKSIZE) GC_check_fl_marks(q);
+#        endif /* GC_GCJ_SUPPORT */
+       }
+    }
+#endif /* GC_ASSERTIONS */
+
+# else  /* !THREAD_LOCAL_ALLOC  */
+
+#   define GC_destroy_thread_local(t)
+
+# endif /* !THREAD_LOCAL_ALLOC */
+
index 396c3d35a700730112f5b5d12085d4a24b4d0e61..6bf73e58fc7bac01bed6f4ed0733b1a303e4d5dc 100644 (file)
@@ -13,11 +13,17 @@ int main()
               "-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
 #   endif
 #   if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
-       || defined(GC_SOLARIS_PTHREADS) \
-       || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
+       || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS) \
+       || defined(GC_GNU_THREADS)
+#       ifdef GC_USE_DLOPEN_WRAP
+         printf("-ldl ");
+#      endif
         printf("-lpthread\n");
 #   endif
 #   if defined(GC_FREEBSD_THREADS)
+#       ifdef GC_USE_DLOPEN_WRAP
+         printf("-ldl ");
+#      endif
 #       if (__FREEBSD_version >= 500000)
           printf("-lpthread\n");
 #       else
@@ -31,12 +37,21 @@ int main()
 #   if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
        printf("-lpthread -lrt\n");
 #   endif
-#   if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-        printf("-lthread -ldl\n");
+#   if defined(GC_SOLARIS_THREADS)
+        printf("-lthread -lposix4\n");
+               /* Is this right for recent versions? */
 #   endif
 #   if defined(GC_WIN32_THREADS) && defined(CYGWIN32)
         printf("-lpthread\n");
 #   endif
+#   if defined(GC_WIN32_PTHREADS)
+#      ifdef PTW32_STATIC_LIB
+        /* assume suffix s for static version of the win32 pthread library */
+         printf("-lpthreadGC2s -lws2_32\n");
+#      else
+         printf("-lpthreadGC2\n");
+#      endif
+#   endif
 #   if defined(GC_OSF1_THREADS)
        printf("-pthread -lrt"); /* DOB: must be -pthread, not -lpthread */
 #   endif
index 9e53966c6b75d501ea0fc06bbb1df11c399b1e48..23a13f5ff37a00b89e59d679558c453c4b213223 100644 (file)
@@ -67,16 +67,16 @@ typedef union ComplexDescriptor {
     struct LeafDescriptor {    /* Describes simple array       */
         word ld_tag;
 #      define LEAF_TAG 1
-       word ld_size;           /* bytes per element    */
+       size_t ld_size;         /* bytes per element    */
                                /* multiple of ALIGNMENT        */
-       word ld_nelements;      /* Number of elements.  */
+       size_t ld_nelements;    /* Number of elements.  */
        GC_descr ld_descriptor; /* A simple length, bitmap,     */
                                /* or procedure descriptor.     */
     } ld;
     struct ComplexArrayDescriptor {
         word ad_tag;
 #      define ARRAY_TAG 2
-       word ad_nelements;
+       size_t ad_nelements;
        union ComplexDescriptor * ad_element_descr;
     } ad;
     struct SequenceDescriptor {
@@ -91,10 +91,10 @@ typedef union ComplexDescriptor {
 ext_descr * GC_ext_descriptors;        /* Points to array of extended  */
                                /* descriptors.                 */
 
-word GC_ed_size = 0;   /* Current size of above arrays.        */
+size_t GC_ed_size = 0; /* Current size of above arrays.        */
 # define ED_INITIAL_SIZE 100;
 
-word GC_avail_descr = 0;       /* Next available slot.         */
+size_t GC_avail_descr = 0;     /* Next available slot.         */
 
 int GC_typed_mark_proc_index;  /* Indices of my mark           */
 int GC_array_mark_proc_index;  /* procedures.                  */
@@ -103,18 +103,15 @@ int GC_array_mark_proc_index;     /* procedures.                  */
 /* starting index.                                             */
 /* Returns -1 on failure.                                      */
 /* Caller does not hold allocation lock.                       */
-signed_word GC_add_ext_descriptor(bm, nbits)
-GC_bitmap bm;
-word nbits;
+signed_word GC_add_ext_descriptor(GC_bitmap bm, word nbits)
 {
-    register size_t nwords = divWORDSZ(nbits + WORDSZ-1);
-    register signed_word result;
-    register word i;
-    register word last_part;
-    register int extra_bits;
+    size_t nwords = divWORDSZ(nbits + WORDSZ-1);
+    signed_word result;
+    size_t i;
+    word last_part;
+    size_t extra_bits;
     DCL_LOCK_STATE;
 
-    DISABLE_SIGNALS();
     LOCK();
     while (GC_avail_descr + nwords >= GC_ed_size) {
        ext_descr * new;
@@ -122,7 +119,6 @@ word nbits;
        word ed_size = GC_ed_size;
        
        UNLOCK();
-        ENABLE_SIGNALS();
        if (ed_size == 0) {
            new_size = ED_INITIAL_SIZE;
        } else {
@@ -131,7 +127,6 @@ word nbits;
        } 
        new = (ext_descr *) GC_malloc_atomic(new_size * sizeof(ext_descr));
        if (new == 0) return(-1);
-       DISABLE_SIGNALS();
         LOCK();
         if (ed_size == GC_ed_size) {
             if (GC_avail_descr != 0) {
@@ -156,7 +151,6 @@ word nbits;
     GC_ext_descriptors[result + i].ed_continued = FALSE;
     GC_avail_descr += nwords;
     UNLOCK();
-    ENABLE_SIGNALS();
     return(result);
 }
 
@@ -168,9 +162,7 @@ GC_descr GC_bm_table[WORDSZ/2];
 /* The result is known to be short enough to fit into a bitmap         */
 /* descriptor.                                                         */
 /* Descriptor is a GC_DS_LENGTH or GC_DS_BITMAP descriptor.            */
-GC_descr GC_double_descr(descriptor, nwords)
-register GC_descr descriptor;
-register word nwords;
+GC_descr GC_double_descr(GC_descr descriptor, word nwords)
 {
     if ((descriptor & GC_DS_TAGS) == GC_DS_LENGTH) {
         descriptor = GC_bm_table[BYTES_TO_WORDS((word)descriptor)];
@@ -200,21 +192,17 @@ complex_descriptor * GC_make_sequence_descriptor();
 # define LEAF 1
 # define SIMPLE 0
 # define NO_MEM (-1)
-int GC_make_array_descriptor(nelements, size, descriptor,
-                            simple_d, complex_d, leaf)
-word size;
-word nelements;
-GC_descr descriptor;
-GC_descr *simple_d;
-complex_descriptor **complex_d;
-struct LeafDescriptor * leaf;
+int GC_make_array_descriptor(size_t nelements, size_t size, GC_descr descriptor,
+                            GC_descr *simple_d,
+                            complex_descriptor **complex_d,
+                            struct LeafDescriptor * leaf)
 {
 #   define OPT_THRESHOLD 50
        /* For larger arrays, we try to combine descriptors of adjacent */
        /* descriptors to speed up marking, and to reduce the amount    */
        /* of space needed on the mark stack.                           */
     if ((descriptor & GC_DS_TAGS) == GC_DS_LENGTH) {
-      if ((word)descriptor == size) {
+      if (descriptor == (GC_descr)size) {
        *simple_d = nelements * descriptor;
        return(SIMPLE);
       } else if ((word)descriptor == 0) {
@@ -300,9 +288,8 @@ struct LeafDescriptor * leaf;
     }
 }
 
-complex_descriptor * GC_make_sequence_descriptor(first, second)
-complex_descriptor * first;
-complex_descriptor * second;
+complex_descriptor * GC_make_sequence_descriptor(complex_descriptor *first,
+                                                complex_descriptor *second)
 {
     struct SequenceDescriptor * result =
         (struct SequenceDescriptor *)
@@ -319,9 +306,8 @@ complex_descriptor * second;
 }
 
 #ifdef UNDEFINED
-complex_descriptor * GC_make_complex_array_descriptor(nelements, descr)
-word nelements;
-complex_descriptor * descr;
+complex_descriptor * GC_make_complex_array_descriptor(word nelements,
+                                                     complex_descriptor *descr)
 {
     struct ComplexArrayDescriptor * result =
         (struct ComplexArrayDescriptor *)
@@ -340,32 +326,24 @@ ptr_t * GC_eobjfreelist;
 
 ptr_t * GC_arobjfreelist;
 
-mse * GC_typed_mark_proc GC_PROTO((register word * addr,
-                                  register mse * mark_stack_ptr,
-                                  mse * mark_stack_limit,
-                                  word env));
+mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
+                        mse * mark_stack_limit, word env);
 
-mse * GC_array_mark_proc GC_PROTO((register word * addr,
-                                  register mse * mark_stack_ptr,
-                                  mse * mark_stack_limit,
-                                  word env));
+mse * GC_array_mark_proc(word * addr, mse * mark_stack_ptr,
+                        mse * mark_stack_limit, word env);
 
 /* Caller does not hold allocation lock. */
-void GC_init_explicit_typing()
+void GC_init_explicit_typing(void)
 {
     register int i;
     DCL_LOCK_STATE;
 
     
-#   ifdef PRINTSTATS
-       if (sizeof(struct LeafDescriptor) % sizeof(word) != 0)
-           ABORT("Bad leaf descriptor size");
-#   endif
-    DISABLE_SIGNALS();
+    /* Ignore gcc "no effect" warning. */
+    GC_STATIC_ASSERT(sizeof(struct LeafDescriptor) % sizeof(word) == 0);
     LOCK();
     if (GC_explicit_typing_initialized) {
       UNLOCK();
-      ENABLE_SIGNALS();
       return;
     }
     GC_explicit_typing_initialized = TRUE;
@@ -390,28 +368,19 @@ void GC_init_explicit_typing()
           GC_bm_table[i] = d;
       }
     UNLOCK();
-    ENABLE_SIGNALS();
 }
 
-# if defined(__STDC__) || defined(__cplusplus)
-    mse * GC_typed_mark_proc(register word * addr,
-                            register mse * mark_stack_ptr,
-                            mse * mark_stack_limit,
-                            word env)
-# else
-    mse * GC_typed_mark_proc(addr, mark_stack_ptr, mark_stack_limit, env)
-    register word * addr;
-    register mse * mark_stack_ptr;
-    mse * mark_stack_limit;
-    word env;
-# endif
+mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
+                        mse * mark_stack_limit, word env)
 {
-    register word bm = GC_ext_descriptors[env].ed_bitmap;
-    register word * current_p = addr;
-    register word current;
-    register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
-    register ptr_t least_ha = GC_least_plausible_heap_addr;
-    
+    word bm = GC_ext_descriptors[env].ed_bitmap;
+    word * current_p = addr;
+    word current;
+    ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+    ptr_t least_ha = GC_least_plausible_heap_addr;
+    DECLARE_HDR_CACHE;
+
+    INIT_HDR_CACHE;
     for (; bm != 0; bm >>= 1, current_p++) {
        if (bm & 1) {
            current = *current_p;
@@ -431,7 +400,7 @@ void GC_init_explicit_typing()
         if (mark_stack_ptr >= mark_stack_limit) {
             mark_stack_ptr = GC_signal_mark_stack_overflow(mark_stack_ptr);
         }
-        mark_stack_ptr -> mse_start = addr + WORDSZ;
+        mark_stack_ptr -> mse_start = (ptr_t)(addr + WORDSZ);
         mark_stack_ptr -> mse_descr =
                GC_MAKE_PROC(GC_typed_mark_proc_index, env+1);
     }
@@ -441,8 +410,7 @@ void GC_init_explicit_typing()
 /* Return the size of the object described by d.  It would be faster to        */
 /* store this directly, or to compute it as part of                    */
 /* GC_push_complex_descriptor, but hopefully it doesn't matter.                */
-word GC_descr_obj_size(d)
-register complex_descriptor *d;
+word GC_descr_obj_size(complex_descriptor *d)
 {
     switch(d -> TAG) {
       case LEAF_TAG:
@@ -461,11 +429,8 @@ register complex_descriptor *d;
 
 /* Push descriptors for the object at addr with complex descriptor d   */
 /* onto the mark stack.  Return 0 if the mark stack overflowed.        */
-mse * GC_push_complex_descriptor(addr, d, msp, msl)
-word * addr;
-register complex_descriptor *d;
-register mse * msp;
-mse * msl;
+mse * GC_push_complex_descriptor(word *addr, complex_descriptor *d,
+                                mse *msp, mse *msl)
 {
     register ptr_t current = (ptr_t) addr;
     register word nelements;
@@ -482,7 +447,7 @@ mse * msl;
           sz = d -> ld.ld_size;
           for (i = 0; i < nelements; i++) {
               msp++;
-              msp -> mse_start = (word *)current;
+              msp -> mse_start = current;
               msp -> mse_descr = descr;
               current += sz;
           }
@@ -520,22 +485,13 @@ mse * msl;
 }
 
 /*ARGSUSED*/
-# if defined(__STDC__) || defined(__cplusplus)
-    mse * GC_array_mark_proc(register word * addr,
-                            register mse * mark_stack_ptr,
-                            mse * mark_stack_limit,
-                            word env)
-# else
-    mse * GC_array_mark_proc(addr, mark_stack_ptr, mark_stack_limit, env)
-    register word * addr;
-    register mse * mark_stack_ptr;
-    mse * mark_stack_limit;
-    word env;
-# endif
+mse * GC_array_mark_proc(word * addr, mse * mark_stack_ptr,
+                        mse * mark_stack_limit, word env)
 {
-    register hdr * hhdr = HDR(addr);
-    register word sz = hhdr -> hb_sz;
-    register complex_descriptor * descr = (complex_descriptor *)(addr[sz-1]);
+    hdr * hhdr = HDR(addr);
+    size_t sz = hhdr -> hb_sz;
+    size_t nwords = BYTES_TO_WORDS(sz);
+    complex_descriptor * descr = (complex_descriptor *)(addr[nwords-1]);
     mse * orig_mark_stack_ptr = mark_stack_ptr;
     mse * new_mark_stack_ptr;
     
@@ -556,28 +512,22 @@ mse * msl;
        /* the original array entry.                                    */
        GC_mark_stack_too_small = TRUE;
        new_mark_stack_ptr = orig_mark_stack_ptr + 1;
-       new_mark_stack_ptr -> mse_start = addr;
-       new_mark_stack_ptr -> mse_descr = WORDS_TO_BYTES(sz) | GC_DS_LENGTH;
+       new_mark_stack_ptr -> mse_start = (ptr_t)addr;
+       new_mark_stack_ptr -> mse_descr = sz | GC_DS_LENGTH;
     } else {
         /* Push descriptor itself */
         new_mark_stack_ptr++;
-        new_mark_stack_ptr -> mse_start = addr + sz - 1;
+        new_mark_stack_ptr -> mse_start = (ptr_t)(addr + nwords - 1);
         new_mark_stack_ptr -> mse_descr = sizeof(word) | GC_DS_LENGTH;
     }
-    return(new_mark_stack_ptr);
+    return new_mark_stack_ptr;
 }
 
-#if defined(__STDC__) || defined(__cplusplus)
-  GC_descr GC_make_descriptor(GC_bitmap bm, size_t len)
-#else
-  GC_descr GC_make_descriptor(bm, len)
-  GC_bitmap bm;
-  size_t len;
-#endif
+GC_descr GC_make_descriptor(GC_bitmap bm, size_t len)
 {
-    register signed_word last_set_bit = len - 1;
-    register word result;
-    register int i;
+    signed_word last_set_bit = len - 1;
+    GC_descr result;
+    signed_word i;
 #   define HIGH_BIT (((word)1) << (WORDSZ - 1))
     
     if (!GC_explicit_typing_initialized) GC_init_explicit_typing();
@@ -594,7 +544,7 @@ mse * msl;
       }
       if (all_bits_set) {
        /* An initial section contains all pointers.  Use length descriptor. */
-        return(WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
+        return (WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
       }
     }
 #   endif
@@ -616,121 +566,88 @@ mse * msl;
                                /* Out of memory: use conservative      */
                                /* approximation.                       */
        result = GC_MAKE_PROC(GC_typed_mark_proc_index, (word)index);
-       return(result);
+       return result;
     }
 }
 
 ptr_t GC_clear_stack();
 
 #define GENERAL_MALLOC(lb,k) \
-    (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
+    (void *)GC_clear_stack(GC_generic_malloc((word)lb, k))
     
 #define GENERAL_MALLOC_IOP(lb,k) \
-    (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page(lb, k))
-
-#if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_explicitly_typed(size_t lb, GC_descr d)
-#else
-  char * GC_malloc_explicitly_typed(lb, d)
-  size_t lb;
-  GC_descr d;
-#endif
+    (void *)GC_clear_stack(GC_generic_malloc_ignore_off_page(lb, k))
+
+void * GC_malloc_explicitly_typed(size_t lb, GC_descr d)
 {
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-DCL_LOCK_STATE;
+    ptr_t op;
+    ptr_t * opp;
+    size_t lg;
+    DCL_LOCK_STATE;
 
     lb += TYPD_EXTRA_BYTES;
-    if( SMALL_OBJ(lb) ) {
-#       ifdef MERGE_SIZES
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_eobjfreelist[lw]);
-       FASTLOCK();
-        if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
-            FASTUNLOCK();
+    if(SMALL_OBJ(lb)) {
+       lg = GC_size_map[lb];
+       opp = &(GC_eobjfreelist[lg]);
+       LOCK();
+        if( (op = *opp) == 0 ) {
+            UNLOCK();
             op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
            if (0 == op) return 0;
-#          ifdef MERGE_SIZES
-               lw = GC_size_map[lb];   /* May have been uninitialized. */
-#          endif
+           lg = GC_size_map[lb];       /* May have been uninitialized. */
         } else {
             *opp = obj_link(op);
            obj_link(op) = 0;
-            GC_words_allocd += lw;
-            FASTUNLOCK();
+            GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+            UNLOCK();
         }
    } else {
        op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
        if (op != NULL)
-           lw = BYTES_TO_WORDS(GC_size(op));
+           lg = BYTES_TO_GRANULES(GC_size(op));
    }
    if (op != NULL)
-       ((word *)op)[lw - 1] = d;
-   return((GC_PTR) op);
+       ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
+   return((void *) op);
 }
 
-#if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_explicitly_typed_ignore_off_page(size_t lb, GC_descr d)
-#else
-  char * GC_malloc_explicitly_typed_ignore_off_page(lb, d)
-  size_t lb;
-  GC_descr d;
-#endif
+void * GC_malloc_explicitly_typed_ignore_off_page(size_t lb, GC_descr d)
 {
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
+ptr_t op;
+ptr_t * opp;
+size_t lg;
 DCL_LOCK_STATE;
 
     lb += TYPD_EXTRA_BYTES;
     if( SMALL_OBJ(lb) ) {
-#       ifdef MERGE_SIZES
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_eobjfreelist[lw]);
-       FASTLOCK();
-        if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
-            FASTUNLOCK();
+       lg = GC_size_map[lb];
+       opp = &(GC_eobjfreelist[lg]);
+       LOCK();
+        if( (op = *opp) == 0 ) {
+            UNLOCK();
             op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
-#          ifdef MERGE_SIZES
-               lw = GC_size_map[lb];   /* May have been uninitialized. */
-#          endif
+           lg = GC_size_map[lb];       /* May have been uninitialized. */
         } else {
             *opp = obj_link(op);
            obj_link(op) = 0;
-            GC_words_allocd += lw;
-            FASTUNLOCK();
+            GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+            UNLOCK();
         }
    } else {
        op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
        if (op != NULL)
-       lw = BYTES_TO_WORDS(GC_size(op));
+         lg = BYTES_TO_WORDS(GC_size(op));
    }
    if (op != NULL)
-       ((word *)op)[lw - 1] = d;
-   return((GC_PTR) op);
+       ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
+   return((void *) op);
 }
 
-#if defined(__STDC__) || defined(__cplusplus)
-  void * GC_calloc_explicitly_typed(size_t n,
-                                   size_t lb,
-                                   GC_descr d)
-#else
-  char * GC_calloc_explicitly_typed(n, lb, d)
-  size_t n;
-  size_t lb;
-  GC_descr d;
-#endif
+void * GC_calloc_explicitly_typed(size_t n, size_t lb, GC_descr d)
 {
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
+ptr_t op;
+ptr_t * opp;
+size_t lg;
 GC_descr simple_descr;
 complex_descriptor *complex_descr;
 register int descr_type;
@@ -752,54 +669,50 @@ DCL_LOCK_STATE;
            break;
     }
     if( SMALL_OBJ(lb) ) {
-#       ifdef MERGE_SIZES
-         lw = GC_size_map[lb];
-#      else
-         lw = ALIGNED_WORDS(lb);
-#       endif
-       opp = &(GC_arobjfreelist[lw]);
-       FASTLOCK();
-        if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
-            FASTUNLOCK();
+       lg = GC_size_map[lb];
+       opp = &(GC_arobjfreelist[lg]);
+       LOCK();
+        if( (op = *opp) == 0 ) {
+            UNLOCK();
             op = (ptr_t)GENERAL_MALLOC((word)lb, GC_array_kind);
            if (0 == op) return(0);
-#          ifdef MERGE_SIZES
-               lw = GC_size_map[lb];   /* May have been uninitialized. */            
-#          endif
+           lg = GC_size_map[lb];       /* May have been uninitialized. */            
         } else {
             *opp = obj_link(op);
            obj_link(op) = 0;
-            GC_words_allocd += lw;
-            FASTUNLOCK();
+            GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+            UNLOCK();
         }
    } else {
        op = (ptr_t)GENERAL_MALLOC((word)lb, GC_array_kind);
        if (0 == op) return(0);
-       lw = BYTES_TO_WORDS(GC_size(op));
+       lg = BYTES_TO_GRANULES(GC_size(op));
    }
    if (descr_type == LEAF) {
        /* Set up the descriptor inside the object itself. */
-       VOLATILE struct LeafDescriptor * lp =
+       volatile struct LeafDescriptor * lp =
            (struct LeafDescriptor *)
                ((word *)op
-                + lw - (BYTES_TO_WORDS(sizeof(struct LeafDescriptor)) + 1));
+                + GRANULES_TO_WORDS(lg)
+               - (BYTES_TO_WORDS(sizeof(struct LeafDescriptor)) + 1));
                 
        lp -> ld_tag = LEAF_TAG;
        lp -> ld_size = leaf.ld_size;
        lp -> ld_nelements = leaf.ld_nelements;
        lp -> ld_descriptor = leaf.ld_descriptor;
-       ((VOLATILE word *)op)[lw - 1] = (word)lp;
+       ((volatile word *)op)[GRANULES_TO_WORDS(lg) - 1] = (word)lp;
    } else {
        extern unsigned GC_finalization_failures;
        unsigned ff = GC_finalization_failures;
+       size_t lw = GRANULES_TO_WORDS(lg);
        
        ((word *)op)[lw - 1] = (word)complex_descr;
        /* Make sure the descriptor is cleared once there is any danger */
        /* it may have been collected.                                  */
        (void)
-         GC_general_register_disappearing_link((GC_PTR *)
+         GC_general_register_disappearing_link((void * *)
                                                  ((word *)op+lw-1),
-                                                         (GC_PTR) op);
+                                                         (void *) op);
        if (ff != GC_finalization_failures) {
           /* Couldn't register it due to lack of memory.  Punt.        */
           /* This will probably fail too, but gives the recovery code  */
@@ -807,5 +720,5 @@ DCL_LOCK_STATE;
           return(GC_malloc(n*lb));
        }                                 
    }
-   return((GC_PTR) op);
+   return((void *) op);
 }
index f8f025dd7166c6e6e1d919b8c0e36aeed2fee738..112dec30ea9882dcb6bfa089889b01f6fc35b032 100644 (file)
@@ -1,8 +1,8 @@
-/* The version here should match that in configure/configure.in        */
+/* The version here should match that in configure/configure.ac        */
 /* Eventually this one may become unnecessary.  For now we need        */
 /* it to keep the old-style build process working.             */
-#define GC_TMP_VERSION_MAJOR 6
-#define GC_TMP_VERSION_MINOR 8
+#define GC_TMP_VERSION_MAJOR 7
+#define GC_TMP_VERSION_MINOR 0
 #define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA
 
 #ifndef GC_NOT_ALPHA
@@ -14,7 +14,7 @@
      GC_TMP_VERSION_MINOR != GC_VERSION_MINOR || \
      defined(GC_ALPHA_VERSION) != (GC_TMP_ALPHA_VERSION != GC_NOT_ALPHA) || \
      defined(GC_ALPHA_VERSION) && GC_TMP_ALPHA_VERSION != GC_ALPHA_VERSION
-#   error Inconsistent version info.  Check README, version.h, and configure.in.
+#   error Inconsistent version info.  Check README, version.h, and configure.ac.
 # endif
 #else
 # define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
old mode 100644 (file)
new mode 100755 (executable)
index 5a714f5..520e971
@@ -1,13 +1,39 @@
 #include "config.h"
 #include "private/gc_priv.h"
 
-#if defined(GC_WIN32_THREADS) 
+#if defined(GC_WIN32_THREADS)
 
 #include <windows.h>
 
-#ifdef CYGWIN32
+#ifdef THREAD_LOCAL_ALLOC
+# include "private/thread_local_alloc.h"
+#endif /* THREAD_LOCAL_ALLOC */
+
+/* Allocation lock declarations.       */
+#if !defined(USE_PTHREAD_LOCKS)
+# if defined(GC_DLL)
+    __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
+# else
+    CRITICAL_SECTION GC_allocate_ml;
+# endif
+  DWORD GC_lock_holder = NO_THREAD;
+       /* Thread id for current holder of allocation lock */
+#else
+  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
+  unsigned long GC_lock_holder = NO_THREAD;
+#endif
+
+#ifdef GC_PTHREADS
 # include <errno.h>
 
+/* GC_DLL should not normally be defined, especially since we often do turn */
+/* on THREAD_LOCAL_ALLOC, which is currently incompatible.                 */
+/* It might be possible to get GC_DLL and DllMain-based        thread registration */
+/* to work with Cygwin, but if you try you are on your own.                */
+#ifdef GC_DLL
+# error GC_DLL untested with Cygwin
+#endif
+
  /* Cygwin-specific forward decls */
 # undef pthread_create 
 # undef pthread_sigmask 
 # undef pthread_detach
 # undef dlopen 
 
-# define DEBUG_CYGWIN_THREADS 0
+# ifdef DEBUG_THREADS
+#   ifdef CYGWIN32
+#     define DEBUG_CYGWIN_THREADS 1
+#     define DEBUG_WIN32_PTHREADS 0
+#   else
+#     define DEBUG_WIN32_PTHREADS 1
+#     define DEBUG_CYGWIN_THREADS 0
+#   endif
+# else
+#   define DEBUG_CYGWIN_THREADS 0
+#   define DEBUG_WIN32_PTHREADS 0
+# endif
 
-  void * GC_start_routine(void * arg);
+  void * GC_pthread_start(void * arg);
   void GC_thread_exit_proc(void *arg);
 
+# include <pthread.h>
+
+#else
+
+# ifdef DEBUG_THREADS
+#   define DEBUG_WIN32_THREADS 1
+# else
+#   define DEBUG_WIN32_THREADS 0
+# endif
+
+# undef CreateThread
+# undef ExitThread
+# undef _beginthreadex
+# undef _endthreadex
+# undef _beginthread
+# ifdef DEBUG_THREADS
+#   define DEBUG_WIN32_THREADS 1
+# else
+#   define DEBUG_WIN32_THREADS 0
+# endif
+
+# include <process.h>  /* For _beginthreadex, _endthreadex */
+
+#endif
+
+#if defined(GC_DLL) && !defined(MSWINCE)
+  static GC_bool GC_win32_dll_threads = FALSE;
+  /* This code operates in two distinct modes, depending on    */
+  /* the setting of GC_win32_dll_threads.  If                  */
+  /* GC_win32_dll_threads is set, all threads in the process   */
+  /* are implicitly registered with the GC by DllMain.                 */
+  /* No explicit registration is required, and attempts at     */
+  /* explicit registration are ignored.  This mode is          */
+  /* very different from the Posix operation of the collector. */
+  /* In this mode access to the thread table is lock-free.     */
+  /* Hence there is a static limit on the number of threads.   */
+  
+  /* If GC_win32_dll_threads is FALSE, or the collector is     */
+  /* built without GC_DLL defined, things operate in a way     */
+  /* that is very similar to Posix platforms, and new threads  */
+  /* must be registered with the collector, e.g. by using      */
+  /* preprocessor-based interception of the thread primitives. */
+  /* In this case, we use a real data structure for the thread */
+  /* table.  Note that there is no equivalent of linker-based  */
+  /* call interception, since we don't have ELF-like           */
+  /* facilities.  The Windows analog appears to be "API                */
+  /* hooking", which really seems to be a standard way to      */
+  /* do minor binary rewriting (?).  I'd prefer not to have    */
+  /* the basic collector rely on such facilities, but an       */
+  /* optional package that intercepts thread calls this way    */
+  /* would probably be nice.                                   */
+
+  /* GC_win32_dll_threads must be set at initialization time,  */
+  /* i.e. before any collector or thread calls.  We make it a  */
+  /* "dynamic" option only to avoid multiple library versions. */
+#else
+# define GC_win32_dll_threads FALSE
 #endif
 
+/* We have two versions of the thread table.  Which one        */
+/* we us depends on whether or not GC_win32_dll_threads */
+/* is set.  Note that before initialization, we don't  */
+/* add any entries to either table, even if DllMain is */
+/* called.  The main thread will be added on           */
+/* initialization.                                     */
+
 /* The type of the first argument to InterlockedExchange.      */
 /* Documented to be LONG volatile *, but at least gcc likes    */
 /* this better.                                                        */
 typedef LONG * IE_t;
 
-#ifndef MAX_THREADS
-# define MAX_THREADS 256
-    /* FIXME:                                                  */
-    /* Things may get quite slow for large numbers of threads, */
-    /* since we look them up with sequential search.           */
-#endif
-
 GC_bool GC_thr_initialized = FALSE;
 
+GC_bool GC_need_to_lock = FALSE;
+
+static GC_bool parallel_initialized = FALSE;
+
+void GC_init_parallel(void);
+
+#ifdef GC_DLL
+  /* Turn on GC_win32_dll_threads      */
+  GC_API void GC_use_DllMain(void)
+  {
+#     ifdef THREAD_LOCAL_ALLOC
+         ABORT("Cannot use thread local allocation with DllMain-based "
+               "thread registration.");
+         /* Thread-local allocation really wants to lock at thread     */
+         /* entry and exit.                                            */
+#     endif
+      GC_ASSERT(!parallel_initialized);
+      GC_win32_dll_threads = TRUE;
+  }
+#else
+  GC_API void GC_use_DllMain(void)
+  {
+      ABORT("GC not configured as DLL");
+  }
+#endif
+
 DWORD GC_main_thread = 0;
 
-struct GC_thread_Rep {
-  LONG in_use; /* Updated without lock.        */
-                       /* We assert that unused        */
-                       /* entries have invalid ids of  */
-                       /* zero and zero stack fields.  */
+struct GC_Thread_Rep {
+  union {
+    AO_t tm_in_use;    /* Updated without lock.                */
+                       /* We assert that unused                */
+                       /* entries have invalid ids of          */
+                       /* zero and zero stack fields.          */
+                       /* Used only with GC_win32_dll_threads. */
+    struct GC_Thread_Rep * tm_next;
+                       /* Hash table link without              */
+                       /* GC_win32_dll_threads.                */
+                       /* More recently allocated threads      */
+                       /* with a given pthread id come         */
+                       /* first.  (All but the first are       */
+                       /* guaranteed to be dead, but we may    */
+                       /* not yet have registered the join.)   */
+  } table_management;
+# define in_use table_management.tm_in_use
+# define next table_management.tm_next
   DWORD id;
   HANDLE handle;
   ptr_t stack_base;    /* The cold end of the stack.   */
@@ -50,101 +183,235 @@ struct GC_thread_Rep {
                        /* !in_use ==> stack_base == 0  */
   GC_bool suspended;
 
-# ifdef CYGWIN32
+# ifdef GC_PTHREADS
     void *status; /* hold exit value until join in case it's a pointer */
     pthread_t pthread_id;
     short flags;               /* Protected by GC lock.        */
 #      define FINISHED 1       /* Thread has exited.   */
 #      define DETACHED 2       /* Thread is intended to be detached.   */
+#   define KNOWN_FINISHED(t) (((t) -> flags) & FINISHED)
+# else
+#   define KNOWN_FINISHED(t) 0
+# endif
+# ifdef THREAD_LOCAL_ALLOC
+    struct thread_local_freelists tlfs;
 # endif
 };
 
-typedef volatile struct GC_thread_Rep * GC_thread;
+typedef struct GC_Thread_Rep * GC_thread;
+typedef volatile struct GC_Thread_Rep * GC_vthread;
 
 /*
- * We generally assume that volatile ==> memory ordering, at least among
- * volatiles.
+ * We assumed that volatile ==> memory ordering, at least among
+ * volatiles.  This code should consistently use atomic_ops.
  */
 
 volatile GC_bool GC_please_stop = FALSE;
 
-volatile struct GC_thread_Rep thread_table[MAX_THREADS];
+/*
+ * We track thread attachments while the world is supposed to be stopped.
+ * Unfortunately, we can't stop them from starting, since blocking in
+ * DllMain seems to cause the world to deadlock.  Thus we have to recover
+ * If we notice this in the middle of marking.
+ */
+
+AO_t GC_attached_thread = FALSE;
+/* Return TRUE if an thread was attached since we last asked or        */
+/* since GC_attached_thread was explicitly reset.              */
+GC_bool GC_started_thread_while_stopped(void)
+{
+  AO_t result;
+
+  if (GC_win32_dll_threads) {
+    AO_nop_full();     /* Prior heap reads need to complete earlier. */
+    result = AO_load(&GC_attached_thread);
+    if (result) {
+      AO_store(&GC_attached_thread, FALSE);
+    }
+    return ((GC_bool)result);
+  } else {
+    return FALSE;
+  }
+}
+
+/* Thread table used if GC_win32_dll_threads is set.   */
+/* This is a fixed size array.                         */
+/* Since we use runtime conditionals, both versions    */
+/* are always defined.                                 */
+# ifndef MAX_THREADS
+#   define MAX_THREADS 512
+#  endif
+  /* Things may get quite slow for large numbers of threads,   */
+  /* since we look them up with sequential search.             */
+
+  volatile struct GC_Thread_Rep dll_thread_table[MAX_THREADS];
+
+  volatile LONG GC_max_thread_index = 0;
+                       /* Largest index in dll_thread_table    */
+                       /* that was ever used.                  */
+
+/* And now the version used if GC_win32_dll_threads is not set.        */
+/* This is a chained hash table, with much of the code borrowed        */
+/* From the Posix implementation.                              */
+# define THREAD_TABLE_SZ 256   /* Must be power of 2   */
+  GC_thread GC_threads[THREAD_TABLE_SZ];
+  
 
-volatile LONG GC_max_thread_index = 0; /* Largest index in thread_table        */
-                                      /* that was ever used.           */
+/* Add a thread to GC_threads.  We assume it wasn't already there.     */
+/* Caller holds allocation lock.                                       */
+/* Unlike the pthreads version, the id field is set by the caller.     */
+GC_thread GC_new_thread(DWORD id)
+{
+    word hv = ((word)id) % THREAD_TABLE_SZ;
+    GC_thread result;
+    /* It may not be safe to allocate when we register the first thread. */
+    static struct GC_Thread_Rep first_thread;
+    static GC_bool first_thread_used = FALSE;
+    
+    GC_ASSERT(I_HOLD_LOCK());
+    if (!first_thread_used) {
+       result = &first_thread;
+       first_thread_used = TRUE;
+    } else {
+        GC_ASSERT(!GC_win32_dll_threads);
+        result = (struct GC_Thread_Rep *)
+                GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
+#       ifdef GC_PTHREADS
+         /* result can be NULL -> segfault */
+         GC_ASSERT(result -> flags == 0);
+#       endif
+    }
+    if (result == 0) return(0);
+    /* result -> id = id; Done by caller.      */
+    result -> next = GC_threads[hv];
+    GC_threads[hv] = result;
+#   ifdef GC_PTHREADS
+      GC_ASSERT(result -> flags == 0 /* && result -> thread_blocked == 0 */);
+#   endif
+    return(result);
+}
 
 extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
 
+#if defined(GWW_VDB) && defined(MPROTECT_VDB)
+  extern GC_bool GC_gww_dirty_init(void);
+  /* Defined in os_dep.c.  Returns TRUE if GetWriteWatch is available.         */
+  /* may be called repeatedly.                                         */
+#endif
+
+GC_bool GC_in_thread_creation = FALSE;  /* Protected by allocation lock. */
+
 /*
  * This may be called from DllMain, and hence operates under unusual
- * constraints.
+ * constraints.  In particular, it must be lock-free if GC_win32_dll_threads
+ * is set.  Always called from the thread being added.
+ * If GC_win32_dll_threads is not set, we already hold the allocation lock,
+ * except possibly during single-threaded start-up code.
  */
-static GC_thread GC_new_thread(void) {
-  int i;
-  /* It appears to be unsafe to acquire a lock here, since this        */
-  /* code is apparently not preeemptible on some systems.      */
-  /* (This is based on complaints, not on Microsoft's official */
-  /* documentation, which says this should perform "only simple        */
-  /* initialization tasks".)                                   */
-  /* Hence we make do with nonblocking synchronization.                */
+static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,
+                                            DWORD thread_id)
+{
+  GC_vthread me;
 
   /* The following should be a noop according to the win32     */
   /* documentation.  There is empirical evidence that it       */
   /* isn't.            - HB                                    */
 # if defined(MPROTECT_VDB)
-   if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
+#   if defined(GWW_VDB)
+      if (GC_incremental && !GC_gww_dirty_init())
+       SetUnhandledExceptionFilter(GC_write_fault_handler);
+#   else
+      if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
+#   endif
 # endif
+
+  if (GC_win32_dll_threads) {
+    int i;
+    /* It appears to be unsafe to acquire a lock here, since this      */
+    /* code is apparently not preeemptible on some systems.            */
+    /* (This is based on complaints, not on Microsoft's official       */
+    /* documentation, which says this should perform "only simple      */
+    /* initialization tasks".)                                         */
+    /* Hence we make do with nonblocking synchronization.              */
+    /* It has been claimed that DllMain is really only executed with   */
+    /* a particular system lock held, and thus careful use of locking  */
+    /* around code that doesn't call back into the system libraries    */
+    /* might be OK.  But this hasn't been tested across all win32      */
+    /* variants.                                                       */
                 /* cast away volatile qualifier */
-  for (i = 0; InterlockedExchange((IE_t)&thread_table[i].in_use,1) != 0; i++) {
-    /* Compare-and-swap would make this cleaner, but that's not        */
-    /* supported before Windows 98 and NT 4.0.  In Windows 2000,       */
-    /* InterlockedExchange is supposed to be replaced by               */
-    /* InterlockedExchangePointer, but that's not really what I                */
-    /* want here.                                                      */
-    if (i == MAX_THREADS - 1)
-      ABORT("too many threads");
-  }
-  /* Update GC_max_thread_index if necessary.  The following is safe,  */
-  /* and unlike CompareExchange-based solutions seems to work on all   */
-  /* Windows95 and later platforms.                                    */
-  /* Unfortunately, GC_max_thread_index may be temporarily out of      */
-  /* bounds, so readers have to compensate.                            */
-  while (i > GC_max_thread_index) {
-    InterlockedIncrement((IE_t)&GC_max_thread_index);
-  }
-  if (GC_max_thread_index >= MAX_THREADS) {
-    /* We overshot due to simultaneous increments.     */
-    /* Setting it to MAX_THREADS-1 is always safe.     */
-    GC_max_thread_index = MAX_THREADS - 1;
+    for (i = 0; InterlockedExchange((IE_t)&dll_thread_table[i].in_use,1) != 0;
+        i++) {
+      /* Compare-and-swap would make this cleaner, but that's not      */
+      /* supported before Windows 98 and NT 4.0.  In Windows 2000,     */
+      /* InterlockedExchange is supposed to be replaced by             */
+      /* InterlockedExchangePointer, but that's not really what I      */
+      /* want here.                                                    */
+      /* FIXME: We should eventually declare Win95 dead and use AO_    */
+      /* primitives here.                                              */
+      if (i == MAX_THREADS - 1)
+        ABORT("too many threads");
+    }
+    /* Update GC_max_thread_index if necessary.  The following is safe,        */
+    /* and unlike CompareExchange-based solutions seems to work on all */
+    /* Windows95 and later platforms.                                  */
+    /* Unfortunately, GC_max_thread_index may be temporarily out of    */
+    /* bounds, so readers have to compensate.                          */
+    while (i > GC_max_thread_index) {
+      InterlockedIncrement((IE_t)&GC_max_thread_index);
+    }
+    if (GC_max_thread_index >= MAX_THREADS) {
+      /* We overshot due to simultaneous increments.   */
+      /* Setting it to MAX_THREADS-1 is always safe.   */
+      GC_max_thread_index = MAX_THREADS - 1;
+    }
+    me = dll_thread_table + i;
+  } else /* Not using DllMain */ {
+    GC_ASSERT(I_HOLD_LOCK());
+    GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
+    me = GC_new_thread(thread_id);
+    GC_in_thread_creation = FALSE;
   }
-  
-# ifdef CYGWIN32
-    thread_table[i].pthread_id = pthread_self();
+# ifdef GC_PTHREADS
+    /* me can be NULL -> segfault */
+    me -> pthread_id = pthread_self();
 # endif
+
   if (!DuplicateHandle(GetCurrentProcess(),
-                      GetCurrentThread(),
-                      GetCurrentProcess(),
-                      (HANDLE*)&thread_table[i].handle,
-                      0,
-                      0,
-                      DUPLICATE_SAME_ACCESS)) {
+                       GetCurrentThread(),
+                       GetCurrentProcess(),
+                       (HANDLE*)&(me -> handle),
+                       0,
+                       0,
+                       DUPLICATE_SAME_ACCESS)) {
        DWORD last_error = GetLastError();
-       GC_printf1("Last error code: %lx\n", last_error);
+       GC_err_printf("Last error code: %d\n", last_error);
        ABORT("DuplicateHandle failed");
   }
-  thread_table[i].stack_base = GC_get_stack_base();
+  me -> stack_base = sb -> mem_base;
   /* Up until this point, GC_push_all_stacks considers this thread     */
   /* invalid.                                                          */
-  if (thread_table[i].stack_base == NULL) 
-    ABORT("Failed to find stack base in GC_new_thread");
   /* Up until this point, this entry is viewed as reserved but invalid */
   /* by GC_delete_thread.                                              */
-  thread_table[i].id = GetCurrentThreadId();
-  /* If this thread is being created while we are trying to stop       */
-  /* the world, wait here.  Hopefully this can't happen on any */
-  /* systems that don't allow us to block here.                        */
-  while (GC_please_stop) Sleep(20);
-  return thread_table + i;
+  me -> id = thread_id;
+# if defined(THREAD_LOCAL_ALLOC)
+      GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
+# endif
+  if (me -> stack_base == NULL) 
+      ABORT("Bad stack base in GC_register_my_thread_inner");
+  if (GC_win32_dll_threads) {
+    if (GC_please_stop) {
+      AO_store(&GC_attached_thread, TRUE);
+      AO_nop_full();  // Later updates must become visible after this.
+    }
+    /* We'd like to wait here, but can't, since waiting in DllMain     */
+    /* provokes deadlocks.                                             */
+    /* Thus we force marking to be restarted instead.                  */
+  } else {
+    GC_ASSERT(!GC_please_stop);
+       /* Otherwise both we and the thread stopping code would be      */
+       /* holding the allocation lock.                                 */
+  }
+  return (GC_thread)(me);
 }
 
 /*
@@ -162,160 +429,376 @@ LONG GC_get_max_thread_index()
   return my_max;
 }
 
-/* This is intended to be lock-free, though that                       */
-/* assumes that the CloseHandle becomes visible before the             */
-/* in_use assignment.                                                  */
-static void GC_delete_gc_thread(GC_thread thr)
+/* Return the GC_thread corresponding to a thread id.  May be called   */
+/* without a lock, but should be called in contexts in which the       */
+/* requested thread cannot be asynchronously deleted, e.g. from the    */
+/* thread itself.                                                      */
+/* This version assumes that either GC_win32_dll_threads is set, or    */
+/* we hold the allocator lock.                                         */
+/* Also used (for assertion checking only) from thread_local_alloc.c.  */
+GC_thread GC_lookup_thread_inner(DWORD thread_id) {
+  if (GC_win32_dll_threads) {
+    int i;
+    LONG my_max = GC_get_max_thread_index();
+    for (i = 0;
+       i <= my_max &&
+       (!AO_load_acquire(&(dll_thread_table[i].in_use))
+       || dll_thread_table[i].id != thread_id);
+       /* Must still be in_use, since nobody else can store our thread_id. */
+       i++) {}
+    if (i > my_max) {
+      return 0;
+    } else {
+      return (GC_thread)(dll_thread_table + i);
+    }
+  } else {
+    word hv = ((word)thread_id) % THREAD_TABLE_SZ;
+    register GC_thread p = GC_threads[hv];
+    
+    GC_ASSERT(I_HOLD_LOCK());
+    while (p != 0 && p -> id != thread_id) p = p -> next;
+    return(p);
+  }
+}
+
+/* A version of the above that acquires the lock if necessary.  Note   */
+/* that the identically named function for pthreads is different, and  */
+/* just assumes we hold the lock.                                      */
+/* Also used (for assertion checking only) from thread_local_alloc.c.  */
+static GC_thread GC_lookup_thread(DWORD thread_id)
 {
-    CloseHandle(thr->handle);
-      /* cast away volatile qualifier */
-    thr->stack_base = 0;
-    thr->id = 0;
+  if (GC_win32_dll_threads) {
+    return GC_lookup_thread_inner(thread_id);
+  } else {
+    GC_thread result;
+    LOCK();
+    result = GC_lookup_thread_inner(thread_id);
+    UNLOCK();
+    return result;
+  }
+}
+
+/* If a thread has been joined, but we have not yet            */
+/* been notified, then there may be more than one thread       */
+/* in the table with the same win32 id.                                */
+/* This is OK, but we need a way to delete a specific one.     */
+/* Assumes we hold the allocation lock unless                  */
+/* GC_win32_dll_threads is set.                                        */
+/* If GC_win32_dll_threads is set it should be called from the */
+/* thread being deleted.                                       */
+void GC_delete_gc_thread(GC_vthread gc_id)
+{
+  if (GC_win32_dll_threads) {
+    /* This is intended to be lock-free.                               */
+    /* It is either called synchronously from the thread being deleted,        */
+    /* or by the joining thread.                                       */
+    /* In this branch asynchronosu changes to *gc_id are possible.     */
+    CloseHandle(gc_id->handle);
+    gc_id -> stack_base = 0;
+    gc_id -> id = 0;
 #   ifdef CYGWIN32
-      thr->pthread_id = 0;
+      gc_id -> pthread_id = 0;
 #   endif /* CYGWIN32 */
-    thr->in_use = FALSE;
+#   ifdef GC_WIN32_PTHREADS
+      gc_id -> pthread_id.p = NULL;
+#   endif /* GC_WIN32_PTHREADS */
+    AO_store_release(&(gc_id->in_use), FALSE);
+  } else {
+    /* Cast away volatile qualifier, since we have lock. */
+    GC_thread gc_nvid = (GC_thread)gc_id;
+    DWORD id = gc_nvid -> id;
+    word hv = ((word)id) % THREAD_TABLE_SZ;
+    register GC_thread p = GC_threads[hv];
+    register GC_thread prev = 0;
+
+    GC_ASSERT(I_HOLD_LOCK());
+    while (p != gc_nvid) {
+        prev = p;
+        p = p -> next;
+    }
+    if (prev == 0) {
+        GC_threads[hv] = p -> next;
+    } else {
+        prev -> next = p -> next;
+    }
+    GC_INTERNAL_FREE(p);
+  }
 }
 
-static void GC_delete_thread(DWORD thread_id) {
-  int i;
-  LONG my_max = GC_get_max_thread_index();
+/* Delete a thread from GC_threads.  We assume it is there.    */
+/* (The code intentionally traps if it wasn't.)                        */
+/* Assumes we hold the allocation lock unless                  */
+/* GC_win32_dll_threads is set.                                        */
+/* If GC_win32_dll_threads is set it should be called from the */
+/* thread being deleted.                                       */
+void GC_delete_thread(DWORD id)
+{
+  if (GC_win32_dll_threads) {
+    GC_thread t = GC_lookup_thread_inner(id);
 
-  for (i = 0;
-       i <= my_max &&
-       (!thread_table[i].in_use || thread_table[i].id != thread_id);
-       /* Must still be in_use, since nobody else can store our thread_id. */
-       i++) {}
-  if (i > my_max) {
-    WARN("Removing nonexistent thread %ld\n", (GC_word)thread_id);
+    if (0 == t) {
+      WARN("Removing nonexistent thread %ld\n", (GC_word)id);
+    } else {
+      GC_delete_gc_thread(t);
+    }
+  } else {
+    word hv = ((word)id) % THREAD_TABLE_SZ;
+    register GC_thread p = GC_threads[hv];
+    register GC_thread prev = 0;
+    
+    GC_ASSERT(I_HOLD_LOCK());
+    while (p -> id != id) {
+        prev = p;
+        p = p -> next;
+    }
+    if (prev == 0) {
+        GC_threads[hv] = p -> next;
+    } else {
+        prev -> next = p -> next;
+    }
+    GC_INTERNAL_FREE(p);
+  }
+}
+
+int GC_register_my_thread(struct GC_stack_base *sb) {
+  DWORD t = GetCurrentThreadId();
+
+  if (0 == GC_lookup_thread(t)) {
+    /* We lock here, since we want to wait for an ongoing GC.  */
+    LOCK();
+    GC_register_my_thread_inner(sb, t);
+    UNLOCK();
+    return GC_SUCCESS;
   } else {
-    GC_delete_gc_thread(thread_table+i);
+    return GC_DUPLICATE;
   }
 }
 
+int GC_unregister_my_thread(void)
+{
+    DWORD t = GetCurrentThreadId();
+
+#   if defined(THREAD_LOCAL_ALLOC)
+      LOCK();
+      {
+       GC_thread me = GC_lookup_thread_inner(t);
+        GC_destroy_thread_local(&(me->tlfs));
+      }
+      UNLOCK();
+#   endif
+    if (GC_win32_dll_threads) {
+      /* Should we just ignore this? */
+      GC_delete_thread(t);
+    } else {
+      LOCK();
+      GC_delete_thread(t);
+      UNLOCK();
+    }
+    return GC_SUCCESS;
+}
+
+
+#ifdef GC_PTHREADS
 
-#ifdef CYGWIN32
+/* A quick-and-dirty cache of the mapping between pthread_t    */
+/* and win32 thread id.                                                */
+#define PTHREAD_MAP_SIZE 512
+DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE];
+#define HASH(pthread_id) ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)
+       /* It appears pthread_t is really a pointer type ... */
+#define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \
+       GC_pthread_map_cache[HASH(pthread_id)] = (win32_id);
+#define GET_PTHREAD_MAP_CACHE(pthread_id) \
+       GC_pthread_map_cache[HASH(pthread_id)]
 
 /* Return a GC_thread corresponding to a given pthread_t.      */
 /* Returns 0 if it's not there.                                        */
 /* We assume that this is only called for pthread ids that     */
-/* have not yet terminated or are still joinable.              */
-static GC_thread GC_lookup_thread(pthread_t id)
+/* have not yet terminated or are still joinable, and          */
+/* cannot be concurrently terminated.                          */
+/* Assumes we do NOT hold the allocation lock.                 */
+static GC_thread GC_lookup_pthread(pthread_t id)
 {
-  int i;
-  LONG my_max = GC_get_max_thread_index();
+  if (GC_win32_dll_threads) {
+    int i;
+    LONG my_max = GC_get_max_thread_index();
 
-  for (i = 0;
-       i <= my_max &&
-       (!thread_table[i].in_use || thread_table[i].pthread_id != id
-       || !thread_table[i].in_use);
+    for (i = 0;
+         i <= my_max &&
+         (!AO_load_acquire(&(dll_thread_table[i].in_use))
+         || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));
        /* Must still be in_use, since nobody else can store our thread_id. */
        i++);
-  if (i > my_max) return 0;
-  return thread_table + i;
+    if (i > my_max) return 0;
+    return (GC_thread)(dll_thread_table + i);
+  } else {
+    /* We first try the cache.  If that fails, we use a very slow      */
+    /* approach.                                                       */
+    int hv_guess = GET_PTHREAD_MAP_CACHE(id) % THREAD_TABLE_SZ;
+    int hv;
+    GC_thread p;
+
+    LOCK();
+    for (p = GC_threads[hv_guess]; 0 != p; p = p -> next) {
+      if (THREAD_EQUAL(p -> pthread_id, id))
+       goto foundit; 
+    }
+    for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
+      for (p = GC_threads[hv]; 0 != p; p = p -> next) {
+        if (THREAD_EQUAL(p -> pthread_id, id))
+         goto foundit; 
+      }
+    }
+    p = 0;
+   foundit:
+    UNLOCK();
+    return p;
+  }
 }
 
-#endif /* CYGWIN32 */
+#endif /* GC_PTHREADS */
 
-void GC_push_thread_structures GC_PROTO((void))
+void GC_push_thread_structures(void)
 {
+  GC_ASSERT(I_HOLD_LOCK());
+  if (GC_win32_dll_threads) {
     /* Unlike the other threads implementations, the thread table here */
     /* contains no pointers to the collectable heap.  Thus we have     */
     /* no private structures we need to preserve.                      */
-# ifdef CYGWIN32
-  { int i; /* pthreads may keep a pointer in the thread exit value */
-    LONG my_max = GC_get_max_thread_index();
-
-    for (i = 0; i <= my_max; i++)
-      if (thread_table[i].in_use)
-       GC_push_all((ptr_t)&(thread_table[i].status),
-                    (ptr_t)(&(thread_table[i].status)+1));
+#   ifdef GC_PTHREADS 
+    { int i; /* pthreads may keep a pointer in the thread exit value */
+      LONG my_max = GC_get_max_thread_index();
+
+      for (i = 0; i <= my_max; i++)
+        if (dll_thread_table[i].in_use)
+         GC_push_all((ptr_t)&(dll_thread_table[i].status),
+                      (ptr_t)(&(dll_thread_table[i].status)+1));
+    }
+#   endif
+  } else {
+    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
   }
+# if defined(THREAD_LOCAL_ALLOC)
+    GC_push_all((ptr_t)(&GC_thread_key),
+      (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
+    /* Just in case we ever use our own TLS implementation.    */
+# endif
+}
+
+/* Suspend the given thread, if it's still active.     */
+void GC_suspend(GC_thread t)
+{
+# ifdef MSWINCE
+    /* SuspendThread will fail if thread is running kernel code */
+      while (SuspendThread(t -> handle) == (DWORD)-1)
+       Sleep(10);
+# else
+    /* Apparently the Windows 95 GetOpenFileName call creates  */
+    /* a thread that does not properly get cleaned up, and             */
+    /* SuspendThread on its descriptor may provoke a crash.            */
+    /* This reduces the probability of that event, though it still     */
+    /* appears there's a race here.                                    */
+    DWORD exitCode; 
+    if (GetExitCodeThread(t -> handle, &exitCode) &&
+        exitCode != STILL_ACTIVE) {
+      t -> stack_base = 0; /* prevent stack from being pushed */
+#     ifndef GC_PTHREADS
+        /* this breaks pthread_join on Cygwin, which is guaranteed to  */
+        /* only see user pthreads                                     */
+        AO_store(&(t -> in_use), FALSE);
+        CloseHandle(t -> handle);
+#     endif
+      return;
+    }
+    if (SuspendThread(t -> handle) == (DWORD)-1)
+      ABORT("SuspendThread failed");
 # endif
+   t -> suspended = TRUE;
 }
 
 /* Defined in misc.c */
-extern CRITICAL_SECTION GC_write_cs;
+#ifndef CYGWIN32
+  extern CRITICAL_SECTION GC_write_cs;
+#endif
 
-void GC_stop_world()
+void GC_stop_world(void)
 {
   DWORD thread_id = GetCurrentThreadId();
   int i;
 
   if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
+  GC_ASSERT(I_HOLD_LOCK());
 
   GC_please_stop = TRUE;
 # ifndef CYGWIN32
     EnterCriticalSection(&GC_write_cs);
-# endif /* !CYGWIN32 */
-  for (i = 0; i <= GC_get_max_thread_index(); i++)
-    if (thread_table[i].stack_base != 0
-       && thread_table[i].id != thread_id) {
-#     ifdef MSWINCE
-        /* SuspendThread will fail if thread is running kernel code */
-       while (SuspendThread(thread_table[i].handle) == (DWORD)-1)
-         Sleep(10);
-#     else
-       /* Apparently the Windows 95 GetOpenFileName call creates       */
-       /* a thread that does not properly get cleaned up, and          */
-       /* SuspendThread on its descriptor may provoke a crash.         */
-       /* This reduces the probability of that event, though it still  */
-       /* appears there's a race here.                                 */
-       DWORD exitCode; 
-       if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
-            exitCode != STILL_ACTIVE) {
-          thread_table[i].stack_base = 0; /* prevent stack from being pushed */
-#         ifndef CYGWIN32
-            /* this breaks pthread_join on Cygwin, which is guaranteed to  */
-           /* only see user pthreads                                      */
-           thread_table[i].in_use = FALSE;
-           CloseHandle(thread_table[i].handle);
-#         endif
-         continue;
-       }
-       if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
-         ABORT("SuspendThread failed");
-#     endif
-      thread_table[i].suspended = TRUE;
+# endif
+  if (GC_win32_dll_threads) {
+    /* Any threads being created during this loop will end up setting   */
+    /* GC_attached_thread when they start.  This will force marking to  */
+    /* restart.                                                                */
+    /* This is not ideal, but hopefully correct.                       */
+    GC_attached_thread = FALSE;
+    for (i = 0; i <= GC_get_max_thread_index(); i++) {
+      GC_vthread t = dll_thread_table + i;
+      if (t -> stack_base != 0
+         && t -> id != thread_id) {
+         GC_suspend((GC_thread)t);
+      }
     }
+  } else {
+      GC_thread t;
+      int i;
+
+      for (i = 0; i < THREAD_TABLE_SZ; i++) {
+        for (t = GC_threads[i]; t != 0; t = t -> next) {
+         if (t -> stack_base != 0
+         && !KNOWN_FINISHED(t)
+         && t -> id != thread_id) {
+           GC_suspend(t);
+         }
+       }
+      }
+  }
 # ifndef CYGWIN32
     LeaveCriticalSection(&GC_write_cs);
-# endif /* !CYGWIN32 */
+# endif    
 }
 
-void GC_start_world()
+void GC_start_world(void)
 {
   DWORD thread_id = GetCurrentThreadId();
   int i;
   LONG my_max = GC_get_max_thread_index();
 
-  for (i = 0; i <= my_max; i++)
-    if (thread_table[i].stack_base != 0 && thread_table[i].suspended
-       && thread_table[i].id != thread_id) {
-      if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
-       ABORT("ResumeThread failed");
-      thread_table[i].suspended = FALSE;
+  GC_ASSERT(I_HOLD_LOCK());
+  if (GC_win32_dll_threads) {
+    for (i = 0; i <= my_max; i++) {
+      GC_thread t = (GC_thread)(dll_thread_table + i);
+      if (t -> stack_base != 0 && t -> suspended
+         && t -> id != thread_id) {
+        if (ResumeThread(t -> handle) == (DWORD)-1)
+         ABORT("ResumeThread failed");
+        t -> suspended = FALSE;
+      }
     }
-  GC_please_stop = FALSE;
-}
-
-# ifdef _MSC_VER
-#   pragma warning(disable:4715)
-# endif
-ptr_t GC_current_stackbottom()
-{
-  DWORD thread_id = GetCurrentThreadId();
-  int i;
-  LONG my_max = GC_get_max_thread_index();
+  } else {
+    GC_thread t;
+    int i;
 
-  for (i = 0; i <= my_max; i++)
-    if (thread_table[i].stack_base && thread_table[i].id == thread_id)
-      return thread_table[i].stack_base;
-  ABORT("no thread table entry for current thread");
+    for (i = 0; i < THREAD_TABLE_SZ; i++) {
+      for (t = GC_threads[i]; t != 0; t = t -> next) {
+        if (t -> stack_base != 0 && t -> suspended
+           && t -> id != thread_id) {
+          if (ResumeThread(t -> handle) == (DWORD)-1)
+           ABORT("ResumeThread failed");
+          t -> suspended = FALSE;
+        }
+      }
+    }
+  }
+  GC_please_stop = FALSE;
 }
-# ifdef _MSC_VER
-#   pragma warning(default:4715)
-# endif
 
 # ifdef MSWINCE
     /* The VirtualQuery calls below won't work properly on WinCE, but  */
@@ -338,26 +821,19 @@ ptr_t GC_current_stackbottom()
     }
 # endif
 
-void GC_push_all_stacks()
+void GC_push_stack_for(GC_thread thread)
 {
-  DWORD thread_id = GetCurrentThreadId();
-  GC_bool found_me = FALSE;
-  int i;
-  int dummy;
-  ptr_t sp, stack_min;
-  GC_thread thread;
-  LONG my_max = GC_get_max_thread_index();
-  
-  for (i = 0; i <= my_max; i++) {
-    thread = thread_table + i;
-    if (thread -> in_use && thread -> stack_base) {
-      if (thread -> id == thread_id) {
+    int dummy;
+    ptr_t sp, stack_min;
+    DWORD me = GetCurrentThreadId();
+
+    if (thread -> stack_base) {
+      if (thread -> id == me) {
        sp = (ptr_t) &dummy;
-       found_me = TRUE;
       } else {
         CONTEXT context;
         context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
-        if (!GetThreadContext(thread_table[i].handle, &context))
+        if (!GetThreadContext(thread -> handle, &context))
          ABORT("GetThreadContext failed");
 
         /* Push all registers that might point into the heap.  Frame   */
@@ -369,6 +845,10 @@ void GC_push_all_stacks()
 #       if defined(I386)
           PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
          sp = (ptr_t)context.Esp;
+#      elif defined(X86_64)
+         PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
+         PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
+         sp = (ptr_t)context.Rsp;
 #       elif defined(ARM32)
          PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12);
          sp = (ptr_t)context.Sp;
@@ -397,20 +877,65 @@ void GC_push_all_stacks()
 #       else
 #         error "architecture is not supported"
 #       endif
-      }
+      } /* ! current thread */
 
       stack_min = GC_get_stack_min(thread->stack_base);
 
-      if (sp >= stack_min && sp < thread->stack_base)
+      if (sp >= stack_min && sp < thread->stack_base) {
+#       if DEBUG_WIN32_PTHREADS || DEBUG_WIN32_THREADS \
+           || DEBUG_CYGWIN_THREADS
+         GC_printf("Pushing thread from %p to %p for 0x%x from 0x%x\n",
+                   sp, thread -> stack_base, thread -> id, me);
+#       endif
         GC_push_all_stack(sp, thread->stack_base);
-      else {
+      else {
         WARN("Thread stack pointer 0x%lx out of range, pushing everything\n",
-            (unsigned long)sp);
+            (unsigned long)(size_t)sp);
         GC_push_all_stack(stack_min, thread->stack_base);
       }
+    } /* thread looks live */
+}
+
+void GC_push_all_stacks(void)
+{
+  DWORD me = GetCurrentThreadId();
+  GC_bool found_me = FALSE;
+  size_t nthreads = 0;
+  
+  if (GC_win32_dll_threads) {
+    int i;
+    LONG my_max = GC_get_max_thread_index();
+
+    for (i = 0; i <= my_max; i++) {
+      GC_thread t = (GC_thread)(dll_thread_table + i);
+      if (t -> in_use) {
+        ++nthreads;
+        GC_push_stack_for(t);
+        if (t -> id == me) found_me = TRUE;
+      }
+    }
+  } else {
+    GC_thread t;
+    int i;
+
+    for (i = 0; i < THREAD_TABLE_SZ; i++) {
+      for (t = GC_threads[i]; t != 0; t = t -> next) {
+        ++nthreads;
+        if (!KNOWN_FINISHED(t)) GC_push_stack_for(t);
+        if (t -> id == me) found_me = TRUE;
+      }
+    }
+  }
+  if (GC_print_stats == VERBOSE) {
+    GC_log_printf("Pushed %d thread stacks ", nthreads);
+    if (GC_win32_dll_threads) {
+       GC_log_printf("based on DllMain thread tracking\n");
+    } else {
+       GC_log_printf("\n");
     }
   }
-  if (!found_me) ABORT("Collecting from unknown thread.");
+  if (!found_me && !GC_in_thread_creation)
+    ABORT("Collecting from unknown thread.");
 }
 
 void GC_get_next_stack(char *start, char **lo, char **hi)
@@ -418,14 +943,29 @@ void GC_get_next_stack(char *start, char **lo, char **hi)
     int i;
 #   define ADDR_LIMIT (char *)(-1L)
     char * current_min = ADDR_LIMIT;
-    LONG my_max = GC_get_max_thread_index();
+
+    if (GC_win32_dll_threads) {
+      LONG my_max = GC_get_max_thread_index();
   
-    for (i = 0; i <= my_max; i++) {
-       char * s = (char *)thread_table[i].stack_base;
+      for (i = 0; i <= my_max; i++) {
+       ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
 
        if (0 != s && s > start && s < current_min) {
            current_min = s;
        }
+      }
+    } else {
+      for (i = 0; i < THREAD_TABLE_SZ; i++) {
+       GC_thread t;
+
+        for (t = GC_threads[i]; t != 0; t = t -> next) {
+         ptr_t s = (ptr_t)(t -> stack_base);
+
+         if (0 != s && s > start && s < current_min) {
+           current_min = s;
+         }
+        }
+      }
     }
     *hi = current_min;
     if (current_min == ADDR_LIMIT) {
@@ -436,22 +976,7 @@ void GC_get_next_stack(char *start, char **lo, char **hi)
     if (*lo < start) *lo = start;
 }
 
-#if !defined(CYGWIN32)
-
-#if !defined(MSWINCE) && defined(GC_DLL)
-
-/* We register threads from DllMain */
-
-GC_API HANDLE WINAPI GC_CreateThread(
-    LPSECURITY_ATTRIBUTES lpThreadAttributes, 
-    DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, 
-    LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
-{
-    return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
-                        lpParameter, dwCreationFlags, lpThreadId);
-}
-
-#else /* defined(MSWINCE) || !defined(GC_DLL))  */
+#ifndef GC_PTHREADS
 
 /* We have no DllMain to take care of new threads.  Thus we    */
 /* must properly intercept thread creation.                    */
@@ -463,6 +988,45 @@ typedef struct {
 
 static DWORD WINAPI thread_start(LPVOID arg);
 
+void * GC_win32_start_inner(struct GC_stack_base *sb, LPVOID arg)
+{
+    void * ret;
+    thread_args *args = (thread_args *)arg;
+
+#   if DEBUG_WIN32_THREADS
+      GC_printf("thread 0x%x starting...\n", GetCurrentThreadId());
+#   endif
+
+    GC_register_my_thread(sb); /* This waits for an in-progress GC. */
+
+    /* Clear the thread entry even if we exit with an exception.       */
+    /* This is probably pointless, since an uncaught exception is      */
+    /* supposed to result in the process being killed.                 */
+#ifndef __GNUC__
+    __try {
+#endif /* __GNUC__ */
+       ret = (void *)(size_t)args->start (args->param);
+#ifndef __GNUC__
+    } __finally {
+#endif /* __GNUC__ */
+       GC_unregister_my_thread();
+       GC_free(args);
+#ifndef __GNUC__
+    }
+#endif /* __GNUC__ */
+
+#   if DEBUG_WIN32_THREADS
+      GC_printf("thread 0x%x returned from start routine.\n",
+               GetCurrentThreadId());
+#   endif
+    return ret;
+}
+
+DWORD WINAPI GC_win32_start(LPVOID arg)
+{
+    return (DWORD)(size_t)GC_call_with_stack_base(GC_win32_start_inner, arg);
+}
+
 GC_API HANDLE WINAPI GC_CreateThread(
     LPSECURITY_ATTRIBUTES lpThreadAttributes, 
     DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, 
@@ -472,56 +1036,91 @@ GC_API HANDLE WINAPI GC_CreateThread(
 
     thread_args *args;
 
-    if (!GC_is_initialized) GC_init();
-               /* make sure GC is initialized (i.e. main thread is attached) */
-    
-    args = GC_malloc_uncollectable(sizeof(thread_args)); 
+    if (!parallel_initialized) GC_init_parallel();
+               /* make sure GC is initialized (i.e. main thread is attached,
+                  tls initialized) */
+
+#   if DEBUG_WIN32_THREADS
+      GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());
+#   endif
+    if (GC_win32_dll_threads) {
+      return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
+                        lpParameter, dwCreationFlags, lpThreadId);
+    } else {
+      args = GC_malloc_uncollectable(sizeof(thread_args)); 
        /* Handed off to and deallocated by child thread.       */
-    if (0 == args) {
+      if (0 == args) {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return NULL;
-    }
+      }
 
-    /* set up thread arguments */
+      /* set up thread arguments */
        args -> start = lpStartAddress;
        args -> param = lpParameter;
 
-    thread_h = CreateThread(lpThreadAttributes,
-                           dwStackSize, thread_start,
-                           args, dwCreationFlags,
-                           lpThreadId);
+      GC_need_to_lock = TRUE;
+      thread_h = CreateThread(lpThreadAttributes,
+                             dwStackSize, GC_win32_start,
+                             args, dwCreationFlags,
+                             lpThreadId);
+      if( thread_h == 0 ) GC_free( args );
+      return thread_h;
+    }
+}
 
-    return thread_h;
+void WINAPI GC_ExitThread(DWORD dwExitCode)
+{
+  GC_unregister_my_thread();
+  ExitThread(dwExitCode);
 }
 
-static DWORD WINAPI thread_start(LPVOID arg)
+uintptr_t GC_beginthreadex(
+    void *security, unsigned stack_size,
+    unsigned ( __stdcall *start_address )( void * ),
+    void *arglist, unsigned initflag, unsigned *thrdaddr)
 {
-    DWORD ret = 0;
-    thread_args *args = (thread_args *)arg;
+    uintptr_t thread_h = -1L;
 
-    GC_new_thread();
+    thread_args *args;
 
-    /* Clear the thread entry even if we exit with an exception.       */
-    /* This is probably pointless, since an uncaught exception is      */
-    /* supposed to result in the process being killed.                 */
-#ifndef __GNUC__
-    __try {
-#endif /* __GNUC__ */
-       ret = args->start (args->param);
-#ifndef __GNUC__
-    } __finally {
-#endif /* __GNUC__ */
-       GC_free(args);
-       GC_delete_thread(GetCurrentThreadId());
-#ifndef __GNUC__
+    if (!parallel_initialized) GC_init_parallel();
+               /* make sure GC is initialized (i.e. main thread is attached,
+                  tls initialized) */
+#   if DEBUG_WIN32_THREADS
+      GC_printf("About to create a thread from 0x%x\n", GetCurrentThreadId());
+#   endif
+
+    if (GC_win32_dll_threads) {
+      return _beginthreadex(security, stack_size, start_address,
+                            arglist, initflag, thrdaddr);
+    } else {
+      args = GC_malloc_uncollectable(sizeof(thread_args)); 
+       /* Handed off to and deallocated by child thread.       */
+      if (0 == args) {
+       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return (uintptr_t)(-1);
+      }
+
+      /* set up thread arguments */
+       args -> start = (LPTHREAD_START_ROUTINE)start_address;
+       args -> param = arglist;
+
+      GC_need_to_lock = TRUE;
+      thread_h = _beginthreadex(security, stack_size,
+                (unsigned (__stdcall *) (void *))GC_win32_start,
+                                args, initflag, thrdaddr);
+      if( thread_h == 0 ) GC_free( args );
+      return thread_h;
     }
-#endif /* __GNUC__ */
+}
 
-    return ret;
+void GC_endthreadex(unsigned retval)
+{
+  GC_unregister_my_thread();
+  _endthreadex(retval);
 }
-#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))  */
 
-#endif /* !CYGWIN32 */
+#endif /* !GC_PTHREADS */
 
 #ifdef MSWINCE
 
@@ -576,16 +1175,22 @@ DWORD WINAPI main_thread_start(LPVOID arg)
 # else /* !MSWINCE */
 
 /* Called by GC_init() - we hold the allocation lock.  */
-void GC_thr_init() {
+void GC_thr_init(void) {
+    struct GC_stack_base sb;
+    int sb_result;
+
+    GC_ASSERT(I_HOLD_LOCK());
     if (GC_thr_initialized) return;
     GC_main_thread = GetCurrentThreadId();
     GC_thr_initialized = TRUE;
 
     /* Add the initial thread, so we can stop it.      */
-    GC_new_thread();
+    sb_result = GC_get_stack_base(&sb);
+    GC_ASSERT(sb_result == GC_SUCCESS);
+    GC_register_my_thread(&sb);
 }
 
-#ifdef CYGWIN32
+#ifdef GC_PTHREADS
 
 struct start_info {
     void *(*start_routine)(void *);
@@ -596,28 +1201,48 @@ struct start_info {
 int GC_pthread_join(pthread_t pthread_id, void **retval) {
     int result;
     int i;
-    GC_thread me;
+    GC_thread joinee;
 
 #   if DEBUG_CYGWIN_THREADS
-      GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",
-                (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
+      GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
+               (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
+#   endif
+#   if DEBUG_WIN32_PTHREADS
+      GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n",
+               (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
 #   endif
 
+    if (!parallel_initialized) GC_init_parallel();
     /* Thread being joined might not have registered itself yet. */
     /* After the join,thread id may have been recycled.                 */
     /* FIXME: It would be better if this worked more like       */
     /* pthread_support.c.                                       */
 
-    while ((me = GC_lookup_thread(pthread_id)) == 0) Sleep(10);
+    #ifndef GC_WIN32_PTHREADS
+      while ((joinee = GC_lookup_pthread(pthread_id)) == 0) Sleep(10);
+    #endif
 
     result = pthread_join(pthread_id, retval);
 
-    GC_delete_gc_thread(me);
+    #ifdef GC_WIN32_PTHREADS
+      /* win32_pthreads id are unique */
+      joinee = GC_lookup_pthread(pthread_id);
+    #endif
+
+    if (!GC_win32_dll_threads) {
+      LOCK();
+      GC_delete_gc_thread(joinee);
+      UNLOCK();
+    } /* otherwise dllmain handles it. */
 
 #   if DEBUG_CYGWIN_THREADS
-      GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
+      GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
                 (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
 #   endif
+#   if DEBUG_WIN32_PTHREADS
+      GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
+               (int)(pthread_self()).p, GetCurrentThreadId(), pthread_id.p);
+#   endif
 
     return result;
 }
@@ -633,8 +1258,11 @@ GC_pthread_create(pthread_t *new_thread,
     int result;
     struct start_info * si;
 
-    if (!GC_is_initialized) GC_init();
+    if (!parallel_initialized) GC_init_parallel();
                /* make sure GC is initialized (i.e. main thread is attached) */
+    if (GC_win32_dll_threads) {
+      return pthread_create(new_thread, attr, start_routine, arg);
+    }
     
     /* This is otherwise saved only in an area mmapped by the thread */
     /* library, which isn't visible to the collector.           */
@@ -650,10 +1278,15 @@ GC_pthread_create(pthread_t *new_thread,
     }
 
 #   if DEBUG_CYGWIN_THREADS
-      GC_printf2("About to create a thread from 0x%x(0x%x)\n",
-                (int)pthread_self(), GetCurrentThreadId);
+      GC_printf("About to create a thread from 0x%x(0x%x)\n",
+               (int)pthread_self(), GetCurrentThreadId);
+#   endif
+#   if DEBUG_WIN32_PTHREADS
+      GC_printf("About to create a thread from 0x%x(0x%x)\n",
+               (int)(pthread_self()).p, GetCurrentThreadId());
 #   endif
-    result = pthread_create(new_thread, attr, GC_start_routine, si); 
+    GC_need_to_lock = TRUE;
+    result = pthread_create(new_thread, attr, GC_pthread_start, si); 
 
     if (result) { /* failure */
        GC_free(si);
@@ -662,22 +1295,28 @@ GC_pthread_create(pthread_t *new_thread,
     return(result);
 }
 
-void * GC_start_routine(void * arg)
+void * GC_pthread_start_inner(struct GC_stack_base *sb, void * arg)
 {
     struct start_info * si = arg;
     void * result;
     void *(*start)(void *);
     void *start_arg;
-    pthread_t pthread_id;
+    DWORD thread_id = GetCurrentThreadId();
+    pthread_t pthread_id = pthread_self();
     GC_thread me;
     GC_bool detached;
     int i;
 
 #   if DEBUG_CYGWIN_THREADS
-      GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(),
-                                                  GetCurrentThreadId());
+      GC_printf("thread 0x%x(0x%x) starting...\n",(int)pthread_id,
+                                                 thread_id);
+#   endif
+#   if DEBUG_WIN32_PTHREADS
+      GC_printf("thread 0x%x(0x%x) starting...\n",(int) pthread_id.p,
+                                                 thread_id);
 #   endif
 
+    GC_ASSERT(!GC_win32_dll_threads);
     /* If a GC occurs before the thread is registered, that GC will    */
     /* ignore this thread.  That's fine, since it will block trying to  */
     /* acquire the allocation lock, and won't yet hold interesting     */
@@ -685,40 +1324,58 @@ void * GC_start_routine(void * arg)
     LOCK();
     /* We register the thread here instead of in the parent, so that   */
     /* we don't need to hold the allocation lock during pthread_create. */
-    me = GC_new_thread();
+    me = GC_register_my_thread_inner(sb, thread_id);
+    SET_PTHREAD_MAP_CACHE(pthread_id, thread_id);
     UNLOCK();
 
     start = si -> start_routine;
     start_arg = si -> arg;
     if (si-> detached) me -> flags |= DETACHED;
-    me -> pthread_id = pthread_id = pthread_self();
+    me -> pthread_id = pthread_id;
 
     GC_free(si); /* was allocated uncollectable */
 
     pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
     result = (*start)(start_arg);
     me -> status = result;
-    pthread_cleanup_pop(0);
+    pthread_cleanup_pop(1);
 
 #   if DEBUG_CYGWIN_THREADS
-      GC_printf2("thread 0x%x(0x%x) returned from start routine.\n",
-                (int)pthread_self(),GetCurrentThreadId());
+      GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
+               (int)pthread_self(),GetCurrentThreadId());
+#   endif
+#   if DEBUG_WIN32_PTHREADS
+      GC_printf("thread 0x%x(0x%x) returned from start routine.\n",
+               (int)(pthread_self()).p, GetCurrentThreadId());
 #   endif
 
     return(result);
 }
 
+void * GC_pthread_start(void * arg)
+{
+    return GC_call_with_stack_base(GC_pthread_start_inner, arg);
+}
+
 void GC_thread_exit_proc(void *arg)
 {
     GC_thread me = (GC_thread)arg;
     int i;
 
+    GC_ASSERT(!GC_win32_dll_threads);
 #   if DEBUG_CYGWIN_THREADS
-      GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
-                (int)pthread_self(),GetCurrentThreadId());
+      GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
+               (int)pthread_self(),GetCurrentThreadId());
+#   endif
+#   if DEBUG_WIN32_PTHREADS
+      GC_printf("thread 0x%x(0x%x) called pthread_exit().\n",
+               (int)(pthread_self()).p,GetCurrentThreadId());
 #   endif
 
     LOCK();
+#   if defined(THREAD_LOCAL_ALLOC)
+      GC_destroy_thread_local(&(me->tlfs));
+#   endif
     if (me -> flags & DETACHED) {
       GC_delete_thread(GetCurrentThreadId());
     } else {
@@ -728,18 +1385,23 @@ void GC_thread_exit_proc(void *arg)
     UNLOCK();
 }
 
+#ifndef GC_WIN32_PTHREADS
+/* win32 pthread does not support sigmask */
 /* nothing required here... */
 int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
+  if (!parallel_initialized) GC_init_parallel();
   return pthread_sigmask(how, set, oset);
 }
+#endif
 
 int GC_pthread_detach(pthread_t thread)
 {
     int result;
     GC_thread thread_gc_id;
     
+    if (!parallel_initialized) GC_init_parallel();
     LOCK();
-    thread_gc_id = GC_lookup_thread(thread);
+    thread_gc_id = GC_lookup_pthread(thread);
     UNLOCK();
     result = pthread_detach(thread);
     if (result == 0) {
@@ -754,41 +1416,61 @@ int GC_pthread_detach(pthread_t thread)
     return result;
 }
 
-#else /* !CYGWIN32 */
+#else /* !GC_PTHREADS */
 
 /*
  * We avoid acquiring locks here, since this doesn't seem to be preemptable.
- * Pontus Rydin suggests wrapping the thread start routine instead.
+ * This may run with an uninitialized collector, in which case we don't do much.
+ * This implies that no threads other than the main one should be created
+ * with an uninitialized collector.  (The alternative of initializing
+ * the collector here seems dangerous, since DllMain is limited in what it
+ * can do.)
  */
 #ifdef GC_DLL
-BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
+GC_API BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
 {
+  struct GC_stack_base sb;
+  DWORD thread_id;
+  int sb_result;
+  static int entry_count = 0;
+
+  if (parallel_initialized && !GC_win32_dll_threads) return TRUE;
+
   switch (reason) {
-  case DLL_PROCESS_ATTACH:
-    GC_init(); /* Force initialization before thread attach.   */
-    /* fall through */
-  case DLL_THREAD_ATTACH:
-    GC_ASSERT(GC_thr_initialized);
-    if (GC_main_thread != GetCurrentThreadId()) {
-        GC_new_thread();
+   case DLL_THREAD_ATTACH:
+    GC_ASSERT(entry_count == 0 || parallel_initialized);
+    ++entry_count; /* and fall through: */
+   case DLL_PROCESS_ATTACH:
+    /* This may run with the collector uninitialized. */
+    thread_id = GetCurrentThreadId();
+    if (parallel_initialized && GC_main_thread != thread_id) {
+       /* Don't lock here.     */
+        sb_result = GC_get_stack_base(&sb);
+        GC_ASSERT(sb_result == GC_SUCCESS);
+#       ifdef THREAD_LOCAL_ALLOC
+         ABORT("Cannot initialize thread local cache from DllMain");
+#       endif
+       GC_register_my_thread_inner(&sb, thread_id);
     } /* o.w. we already did it during GC_thr_init(), called by GC_init() */
     break;
 
-  case DLL_THREAD_DETACH:
+   case DLL_THREAD_DETACH:
+    /* We are hopefully running in the context of the exiting thread.  */
+    GC_ASSERT(parallel_initialized);
+    if (!GC_win32_dll_threads) return TRUE;
     GC_delete_thread(GetCurrentThreadId());
     break;
 
-  case DLL_PROCESS_DETACH:
+   case DLL_PROCESS_DETACH:
     {
       int i;
 
-      LOCK();
+      if (!GC_win32_dll_threads) return TRUE;
       for (i = 0; i <= GC_get_max_thread_index(); ++i)
       {
-          if (thread_table[i].in_use)
-           GC_delete_gc_thread(thread_table + i);
+          if (AO_load(&(dll_thread_table[i].in_use)))
+           GC_delete_gc_thread(dll_thread_table + i);
       }
-      UNLOCK();
 
       GC_deinit();
       DeleteCriticalSection(&GC_allocate_ml);
@@ -799,8 +1481,91 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
   return TRUE;
 }
 #endif /* GC_DLL */
-#endif /* !CYGWIN32 */
+#endif /* !GC_PTHREADS */
 
 # endif /* !MSWINCE */
 
+/* Perform all initializations, including those that   */
+/* may require allocation.                             */
+/* Called without allocation lock.                     */
+/* Must be called before a second thread is created.   */
+void GC_init_parallel(void)
+{
+    if (parallel_initialized) return;
+    parallel_initialized = TRUE;
+    /* GC_init() calls us back, so set flag first.     */
+    
+    if (!GC_is_initialized) GC_init();
+    if (GC_win32_dll_threads) {
+      GC_need_to_lock = TRUE;
+       /* Cannot intercept thread creation.  Hence we don't know if other      */
+       /* threads exist.  However, client is not allowed to create other       */
+       /* threads before collector initialization.  Thus it's OK not to        */
+       /* lock before this.                                                    */
+    }
+    /* Initialize thread local free lists if used.     */
+#   if defined(THREAD_LOCAL_ALLOC)
+      LOCK();
+      GC_init_thread_local(&(GC_lookup_thread(GetCurrentThreadId())->tlfs));
+      UNLOCK();
+#   endif
+}
+
+#if defined(USE_PTHREAD_LOCKS)
+  /* Support for pthread locking code.         */
+  /* Pthread_mutex_try_lock may not win here,  */
+  /* due to builtinsupport for spinning first? */
+
+volatile GC_bool GC_collecting = 0;
+                       /* A hint that we're in the collector and       */
+                        /* holding the allocation lock for an           */
+                        /* extended period.                             */
+
+void GC_lock(void)
+{
+    pthread_mutex_lock(&GC_allocate_ml);
+}
+#endif /* USE_PTHREAD ... */
+
+# if defined(THREAD_LOCAL_ALLOC)
+
+/* Add thread-local allocation support.  Microsoft uses __declspec(thread) */
+
+/* We must explicitly mark ptrfree and gcj free lists, since the free  */
+/* list links wouldn't otherwise be found.  We also set them in the    */
+/* normal free lists, since that involves touching less memory than if */
+/* we scanned them normally.                                           */
+void GC_mark_thread_local_free_lists(void)
+{
+    int i;
+    GC_thread p;
+    
+    for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+      for (p = GC_threads[i]; 0 != p; p = p -> next) {
+       GC_mark_thread_local_fls_for(&(p->tlfs));
+      }
+    }
+}
+
+#if defined(GC_ASSERTIONS)
+    /* Check that all thread-local free-lists are completely marked.   */
+    /* also check that thread-specific-data structures are marked.     */
+    void GC_check_tls(void) {
+       int i;
+       GC_thread p;
+       
+       for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+         for (p = GC_threads[i]; 0 != p; p = p -> next) {
+           GC_check_tls_for(&(p->tlfs));
+         }
+       }
+#       if defined(USE_CUSTOM_SPECIFIC)
+         if (GC_thread_key != 0)
+           GC_check_tsd_marks(GC_thread_key);
+#      endif 
+    }
+#endif /* GC_ASSERTIONS */
+
+#endif /* THREAD_LOCAL_ALLOC ... */
+
 #endif /* GC_WIN32_THREADS */
index 7d53fec3768e67b4c6b7592dcabb85b57fde77cc..abbce3317e4ea5b9aa4978cfaf764e3e5e5d2ce8 100644 (file)
 #endif
 
 #if !defined(__DARWIN__)
+# include <semaphore.h>
+#endif
 # if defined(__LINUX__)
 #  define GC_LINUX_THREADS
 # elif defined(__IRIX__)
 #  define GC_IRIX_THREADS
+# elif defined(__DARWIN__)
+#  define GC_DARWIN_THREADS
 # endif
-# include <semaphore.h>
 # if defined(ENABLE_GC_BOEHM)
 #  include "mm/boehm-gc/include/gc.h"
 # endif
-#endif
 
 #if defined(ENABLE_JVMTI)
 #include "native/jvmti/cacaodbg.h"