* Imported Boehm-GC 7.1.
authorChristian Thalinger <twisti@complang.tuwien.ac.at>
Thu, 5 Jun 2008 11:59:30 +0000 (13:59 +0200)
committerChristian Thalinger <twisti@complang.tuwien.ac.at>
Thu, 5 Jun 2008 11:59:30 +0000 (13:59 +0200)
--HG--
branch : gc7-branch

60 files changed:
src/mm/boehm-gc/ChangeLog
src/mm/boehm-gc/Makefile.am
src/mm/boehm-gc/Makefile.direct
src/mm/boehm-gc/Makefile.dj
src/mm/boehm-gc/NT_X64_STATIC_THREADS_MAKEFILE
src/mm/boehm-gc/add_gc_prefix.c
src/mm/boehm-gc/allchblk.c
src/mm/boehm-gc/alloc.c
src/mm/boehm-gc/backgraph.c
src/mm/boehm-gc/configure.ac
src/mm/boehm-gc/darwin_stop_world.c
src/mm/boehm-gc/dbg_mlc.c
src/mm/boehm-gc/doc/README
src/mm/boehm-gc/doc/README.macros
src/mm/boehm-gc/doc/README.win32
src/mm/boehm-gc/doc/README.win64
src/mm/boehm-gc/doc/gcinterface.html
src/mm/boehm-gc/doc/scale.html
src/mm/boehm-gc/dyn_load.c
src/mm/boehm-gc/finalize.c
src/mm/boehm-gc/gc_cpp.cc
src/mm/boehm-gc/gcname.c
src/mm/boehm-gc/headers.c
src/mm/boehm-gc/include/gc.h
src/mm/boehm-gc/include/gc_cpp.h
src/mm/boehm-gc/include/gc_inline.h
src/mm/boehm-gc/include/gc_tiny_fl.h
src/mm/boehm-gc/include/include.am
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/thread_local_alloc.h
src/mm/boehm-gc/libatomic_ops-1.2/ChangeLog
src/mm/boehm-gc/libatomic_ops-1.2/doc/README.txt
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops.h
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/generalize.h
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/arm.h
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/powerpc.h
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/x86.h
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/x86_64.h
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc/x86.h
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc/x86_64.h
src/mm/boehm-gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/standard_ao_double_t.h
src/mm/boehm-gc/mach_dep.c
src/mm/boehm-gc/malloc.c
src/mm/boehm-gc/mark.c
src/mm/boehm-gc/mark_rts.c
src/mm/boehm-gc/misc.c
src/mm/boehm-gc/msvc_dbg.c
src/mm/boehm-gc/obj_map.c
src/mm/boehm-gc/os_dep.c
src/mm/boehm-gc/pthread_stop_world.c
src/mm/boehm-gc/pthread_support.c
src/mm/boehm-gc/reclaim.c
src/mm/boehm-gc/tests/test.c
src/mm/boehm-gc/tests/tests.am
src/mm/boehm-gc/thread_local_alloc.c
src/mm/boehm-gc/typd_mlc.c
src/mm/boehm-gc/win32_threads.c

index 96bf3171e9042525533b89edec5cc9e25b1a674d..c2238ab89f97cf67efa1bec09bda2e1fc3741924 100644 (file)
@@ -1,9 +1,357 @@
+2008-05-03  Hans Boehm <Hans.Boehm@hp.com>
+
+       * doc/gcinterface.html: Improve C++ interface documentation.
+
+2008-03-10  Hans Boehm <Hans.Boehm@hp.com>
+
+       * allchblk.c (GC_allochblk): Check for overflow during size
+       rounding.
+       * tests/huge_test.c: New.
+       * Makefile.direct, tests/tests.am: Add huge_test.c
+       * Makefile.in: Regenerate.
+
+2008-02-29  Hans Boehm <Hans.Boehm@hp.com>
+
+       * pthread_support.c: Fix typo in comment.
+       * os_dep.c (GC_win32_get_mem): Add heap section only if
+       allocation succeeded.
+
+2008-02-28  Hans Boehm <Hans.Boehm@hp.com>
+
+       * malloc.c: (free replacement) Fix caller address space check.
+
+2008-02-25  Hans Boehm <Hans.Boehm@hp.com>
+
+       * finalize.c (GC_grow_table): Dereference table in null-check.
+
+2008-02-24  Hans Boehm <Hans.Boehm@hp.com>
+
+       * win32_threads.c (GC_delete_gc_thread, GC_delete_thread):
+       Consistently call CloseHandle. (GC_suspend): Call
+       GC_delete_gc_thread.
+       * tests/test.c: Don't reference GC_print_stats if not exported.
+
+2008-02-20  Hans Boehm <Hans.Boehm@hp.com>
+
+       * tests/test.c (run_one_test): Don't mention pthread_self().
+       * misc.c: Declare GC_thr_init().
+
+2008-02-20  Hans Boehm <Hans.Boehm@hp.com>
+
+       * allchblk.c (add_to_fl): disable assertions with USE_MUNMAP,
+       and refine assertions to handle huge unmergable blocks.
+       (GC_allochblk_nth): Add comment.
+
+2008-02-20  Hans Boehm <Hans.Boehm@hp.com>
+
+       * include/private/gcconfig.h: Add misssing FREEBSD macro
+       consistency test.
+
+2008-02-20  Hans Boehm <Hans.Boehm@hp.com>
+
+       * allchblk.c (GC_enough_large_bytes_left): No longer take
+       parameters; return free list index bound.
+       (GC_merge_unmapped): Don't access nexthdr until after null test.
+       (Fixes bug in 1/29/08 check-in.)  (GC_allochblk): Calculate
+       when splitting is allowable only once here, not when considering each
+       block. (GC_allchblk_nth): Accept new may_split parameter.
+       Avoid some redundant tests for exact size matches.
+       * alloc.c (GC_should_collect): Cache min_bytes_allocd.
+       (GC_maybe_gc): Make locking assertion testable.
+       * mark_rts.c: Fix indentation.
+       * pthread_stop_world.c: Replace old GC_err_printf1 reference.
+       * tests/test.c: Remove (void) casts.  Optionally print some
+       timing information.
+
+2008-02-15  Hans Boehm <Hans.Boehm@hp.com>
+
+       * windows-untested/gc.def: Remove CreateThread line.
+       * windows-untested/README: New file.
+       * win32_threads.c (GC_use_DllMain): Force collector initialization.
+       (GC_init_parallel): Reformat comment.
+       * include/gc.h (GC_use_DllMain): Clarify usage rules in comment.
+       * mark.c (GC_mark_from): Slightly simplify GC_DS_PER_OBJECT code.
+       * include/gc_cpp.h: Add matching placement delete overloads
+       everywhere.
+       * include/private/gc_locks.h (NO_THREAD): Add cast.
+       * include/private/gcconfig.h: Add test for __HP_aCC.
+       * configure.ac, tests/tests.am:  Avoid libgccpp on HP/UX.
+       * Makefile.in, configure: Regenerate.
+
+2008-02-11  Hans Boehm <Hans.Boehm@hp.com> (partly David Leonard)
+
+       * doc/README.win32: Fix typo.
+       * configure.ac: Fix printing of enable-shared result.
+       * configure: Regenerate.
+
+2008-02-08  Hans Boehm <Hans.Boehm@hp.com>
+
+       * misc.c (GC_init_inner): Assert !GC_need_to_lock only when
+       defined.  (GC_call_with_stack_base): Add GC_API.
+       * os_dep.c (GC_get_stack_base): Add GC_API.
+       * win32_threads.c: (GC_register_my_thread, GC_unregister_my_thread):
+       Add GC_API.
+       * include/gc.h: Add GC_API annotations.
+       * include/private/gc_locks.h: Define UNCOND_LOCK etc. also for
+       PCR.
+       * include/private/gc_pmark.h: Fix comments.
+
+2008-02-06  Hans Boehm <Hans.Boehm@hp.com> (mostly from Henning Makholm)
+
+       * include/private/gc_priv.h, mark_rts.c, typd_mlc.c:
+       Add GC_push_typed_structures() to push GC_ext_descriptors.
+
+2008-01-31  Hans Boehm <Hans.Boehm@hp.com> (mostly from Andreas Tobler)
+
+       * tests/test.c: Call GC_INIT for DARWIN; test system type using
+       gcconfig.h-defined macros.
+
+2008-01-29  Hans Boehm <Hans.Boehm@hp.com>
+
+       * allchblk.c (GC_merge_unmapped, GC_freehblk): Refuse to create
+       blocks large enough that their size, when interpreted as a signed
+       value, would be negative.
+       * include/private/gc_priv.h: Comment hb_sz range limit.
+
+2008-01-29  Hans Boehm <Hans.Boehm@hp.com>  (with help from Manuel Serrano)
+       
+       * mark.c (GC_push_next_marked): correct comment.
+       * Makefile.direct: document NO_PROC_STAT.
+       * include/private/gcconfig.h: Accomodate NO_PROC_STAT.
+
+2008-01-10  Hans Boehm <Hans.Boehm@hp.com>
+       
+       * include/gc_version.h, configure.ac, doc/README:
+       Change to version 7.1alpha3.
+       * configure: Regenerate.
+
+[7.1alpha2]
+
+2008-01-10  Hans Boehm <Hans.Boehm@hp.com>
+       
+       * include/gc_version.h, configure.ac, doc/README:
+       Change to version 7.1alpha2.
+       * configure: Regenerate.
+
+2008-01-10  Hans Boehm <Hans.Boehm@hp.com>
+       
+       * Makefile.am: Mention atomic_ops.c and atomic_ops_sysdeps.S
+       again.  Refer to build directory as ".".
+       * Makefile.in: Regenerate.
+       
+2008-01-10  Hans Boehm <Hans.Boehm@hp.com>
+
+       * configure.ac: Ignore --enable-parallel-mark on Darwin for now.
+       * configure: Regenerate.
+       * darwin_stop_world.c: Add FIXME comment for parallel marker.
+
+2008-01-09  Hans Boehm <Hans.Boehm@hp.com>
+
+       * include/private/gc_priv.h: Update MAX_ROOT_SETS
+       and LOG_PHT_ENTRIES to handle larger heaps.
+
+2008-01-03  Hans Boehm <Hans.Boehm@hp.com>
+
+       * include/gc.h (GC_INIT,GC_init): Update comments.
+
+2008-01-03  Hans Boehm <Hans.Boehm@hp.com> (based on a patch from
+       John Bowman, and an ancient patch from Fergus Henderson)
+
+       * allchblk.c, alloc.c, include/private/gc_priv.h:
+       Track GC_bytes_dropped and use in GC triggering decisions.
+       * alloc.c (min_bytes_allocd): Weight atomic blocks less.
+
+2008-01-02  Hans Boehm <Hans.Boehm@hp.com>
+
+       * alloc.c (GC_add_to_heap): Call GC_install_header(p) AFTER
+       adjusting p.
+
+2007-12-23  Hans Boehm <Hans.Boehm@hp.com>
+
+       * Makefile.am: Add NT_X64_THREADS_MAKEFILE.
+2007-12-23  Hans Boehm <Hans.Boehm@hp.com> (Really mostly Friedrich Dominicus)
+
+       * NT_X64_STATIC_THREADS_MAKEFILE: Clean up obsolete comment.
+       * alloc.c: Add declaration for GC_add_current_malloc_heap.
+       * win32_threads.c (GC_beginthreadex): Clean up error
+       return code.
+       * doc/README.win64, NT_X64_THREADS_MAKEFILE, Makefile.direct:
+       Add NT_X64_THREADS_MAKEFILE.
+
+2007-12-21  Hans Boehm <Hans.Boehm@hp.com>
+
+       * alloc.c: Define GC_version instead of in version.h.
+       * version.h: Remove.
+       * include/gc_version.h: Move most of version.h here.
+       * include/gc.h: Include gc_version.h.
+       * gcname.c, add_gc_prefix.c: include gc.h instead of version.h.
+       * Makefile.direct, Makefile.dj, Makefile.am, include/include.am:
+       Adjust for version.h rename.
+       * Makefile.in: Regenerate.
+
+2007-12-21  Hans Boehm <Hans.Boehm@hp.com> (Really mostly russ sludge dot net)
+
+       * configure.ac: Put libatomic_ops links in build directory.
+       * configure: Regenerate.
+       * Makefile.am: Dont mention atomic_ops.c and atomic_ops_sysdeps.S
+       as nodist sources.
+
+2007-12-20  Hans Boehm <Hans.Boehm@hp.com>
+
+       * include/gc.h, doc/README.macros: Add GC_NO_THREAD_REDIRECTS,
+       GC_NO_THREAD_DECLS, don't test explicitly for GC_SOLARIS_THREADS.
+
+2007-12-20  Hans Boehm <Hans.Boehm@hp.com>
+       
+       * alloc.c: Deal correctly with address wrapping for 
+       GC_greatest_plausible_heap_addr and GC_least_plausible_heap_addr.
+       * finalize.c, include/gc.h (GC_register_disappearing_link,
+       GC_register_finalizer_inner): Improve out-of-memory handling.
+       * include/private/gc_pmark.h: Fix comment spelling.
+
+2007-12-18  Hans Boehm <Hans.Boehm@hp.com> (really mainly Peter Wang)
+
+       * include/gc_inline.h, include/gc_tiny_fl.h: cleanups to make usable
+       in other contexts.
+
+2007-12-18  Hans Boehm <Hans.Boehm@hp.com> (really Radek Polak)
+
+       * include/gc.h: Don't define GC_HAVE_BUILTIN_BACKTRACE for uclibc.
+
+2007-12-18  Hans Boehm <Hans.Boehm@hp.com>
+
+       * gc_cpp.cc: Don't include gc_cpp.h from local directory.
+
+2007-12-18  Hans Boehm <Hans.Boehm@hp.com> (really Adam Megacz)
+
+       * allchblk.c, configure.ac (add --enable-munmap)
+       * configure: Regenerate.
+
+2007-12-10  Andreas Tobler  <a.tobler@schweiz.org>
+
+       * dyn_load.c (GC_dyld_image_add): Remove ifdef clause and use the macro
+       GC_GETSECTBYNAME instead.
+       * include/private/gc_priv.h: Define GC_GETSECTBYNAME according to the
+       architecture (Darwin).
+
+2007-10-24  Hans Boehm <Hans.Boehm@hp.com>
+
+       * reclaim.c (GC_bytes_found): Expand comment.
+       * thread_local_alloc.c (GC_malloc_atomic, GC_gcj_malloc): Pass
+       granules, not bytes, to GC_FAST_MALLOC_GRANS.
+       * include/gc.h: Never include gc_local_alloc.h.
+       * tests/test.c: Add size zero allocation tests.
+
+2007-10-23  Hans Boehm <Hans.Boehm@hp.com>
+
+       * malloc.c: Update GC_large_allocd_bytes on explicit deallocation.
+       * allchblk.c: Sanity check GC_max_large_allocd_bytes.
+
+2007-10-23  Hans Boehm <Hans.Boehm@hp.com> (Really Manuel Serrano)
+
+       * Makefile.direct: Invoke $(MAKE) instead of make.
+
+2007-10-23  Hans Boehm <Hans.Boehm@hp.com>
+
+       * doc/scale.html: Reflect gc7 thread local allocation behavior.
+
+2007-10-23  Hans Boehm <Hans.Boehm@hp.com> (really Petter Urkedal)
+
+       * include/extra/gc.h, include/extra/gc_cpp.h: New.
+       * include/include.am: Install gc.h and gc_cpp.h in $(prefix)/include
+       again.
+       * Makefile.in: Regenerate.
+
+2007-08-15  Hans Boehm <Hans.Boehm@hp.com> (really Samuel Thibault)
+       
+       * pthread_support.c (GC_thr_init): Use sysconf(_SC_NPROCESSORS_ONLN)
+       for HURD.
+
+2007-08-14  Hans Boehm <Hans.Boehm@hp.com> (really David Daney)
+
+       * include/private/gcconfig.h: Add Linux/mips-64 support.
+
+2007-08-14  Hans Boehm <Hans.Boehm@hp.com> (really mostly Samuel Thibault)
+
+       * dbg_mlc.c: Use random() on all glibc systems.
+       * mach_dep.c (GC_with_callee_saves_pushed): Don't use getcontext() on
+       HURD.  Add comment.
+       * pthread_stop_world.c (GC_suspend_handler, GC_stop_init): Accomodate
+       systems without SA_SIGINFO.
+
+2007-08-14  Hans Boehm <Hans.Boehm@hp.com> (partly really Henrik Theiling)
+
+       * include/gc.h (GC_PTR_STORE): Fix non-DEBUG parentheses.
+       * tests/test.c (run_one_test): Add GC_PTR_STORE test.
+       No longer test for RS6000.
+
+2007-08-03  Hans Boehm <Hans.Boehm@hp.com>
+       
+       * alloc.c, backgraph.c, headers.c, include/private/gc_priv.h:
+       Maintain GC_our_memory and GC_n_memory.
+       * dbg_mlc.c (GC_print_smashed_obj): Improve message.
+       (GC_print_all_smashed_proc): Pass client object address instead of
+       base.
+       * dyn_load.c (sort_heap_sects): New.  (GC_register_map_entries):
+       Register sections that are contiguous and merged with our heap.
+       * malloc.c, os_dep.c (GC_text_mapping): Check for just base name
+       of libraries.
+       * malloc.c (calloc): Check for special callers even with
+       USE_PROC_FOR_LIBRARIES. Move assertion.  Add rudimentary
+       malloc/free tracing.
+       * misc.c: No longer call GC_init_lib_bounds explicitly.
+       * thread_local_alloc.c (GC_malloc, GC_malloc_atomic): Always
+       initialize on demand.
+       * tests/test.c: Call GC_INIT only when required.
+
+2007-08-03  Hans Boehm <Hans.Boehm@hp.com>
+
+       * Makefile.direct: Remove comment fragment.
+       * tests/tests.am: Add smashtest.
+       * Makefile.in: Regenerate.
+       * configure.ac: Define GC_USE_DLOPEN_WRAP with redirect-malloc.
+       * configure: Regenerate.
+       * pthread_support.c: Fix comment spelling.
+       * include/private/gcconfig.h: Define USE_PROC_FOR_LIBRARIES with
+       GC_LINUX_THREADS and REDIRECT_MALLOC.
+       * tests/smash_test.c: Initial check-in.
+       * obj_map.c: Print log entry to correct file.
+       * include/private/thread_local_alloc.h: Add TlsAlloc error check.
+
+2007-07-23  Hans Boehm <Hans.Boehm@hp.com>
+
+       * alloc.c (GC_stopped_mark): Call GC_add_current_malloc_heap()
+       while world is still running.
+       * os_dep.c (GC_is_heap_base): Don't call GC_add_current_malloc_heap()
+       with world stopped.
+       * include/gc.h (GC_INIT for cygwin): Always call GC_add_roots.
+       * misc.c (GC_init/GC_init_inner): Perform all work in
+       GC_init_inner.
+       * Makefile.direct: Expand -DUSE_MUNMAP comment.
+
+2007-07-23  Hans Boehm <Hans.Boehm@hp.com> (really Jim Marshall)
+
+       * include/gc.h: Define uintptr_t explicitly for VC++6.
+       * msvc_dbg.c (GetModuleBase): Revert to strcat if strcat_s doesn't
+       exist.
+
+2007-07-02  Hans Boehm <Hans.Boehm@hp.com>
+       
+       * version.h, configure.ac, doc/README: Change to version 7.1alpha1.
+       * configure: Regenerate.
+
+2007-07-02  Hans Boehm <Hans.Boehm@hp.com>
+       
+       * version.h, configure.ac, doc/README: Change to version 7.0.
+       * configure: Regenerate.
+
 2007-07-02  Hans Boehm <Hans.Boehm@hp.com>
 
-       * gc_config_macros.h: Also check for IA64 when setting
+       * include/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
+       * include/gc_pthread_redirects.h: Remove obsolete Solaris threads
        (as opposed to pthreads) support.
 
 2007-07-02  Hans Boehm <Hans.Boehm@hp.com>
index 6ef2a774deba5d9d0502dbff9cf1e61e69099e6c..89298b010f4fa5955165ad39df34133e7a4c6406 100644 (file)
@@ -71,12 +71,12 @@ if WIN32_THREADS
 libgc_la_SOURCES += win32_threads.c
 endif
 
-if USE_INTERNAL_LIBATOMIC_OPS
-nodist_libgc_la_SOURCES = atomic_ops.c
-endif
-
-if NEED_ATOMIC_OPS_ASM
-nodist_libgc_la_SOURCES = atomic_ops_sysdeps.S
+if USE_INTERNAL_LIBATOMIC_OPS   
+nodist_libgc_la_SOURCES = ./atomic_ops.c        
+endif   
+        
+if NEED_ATOMIC_OPS_ASM          
+nodist_libgc_la_SOURCES = ./atomic_ops_sysdeps.S        
 endif
 
 # Include THREADDLLIBS here to ensure that the correct versions of
@@ -98,7 +98,7 @@ if CPLUSPLUS
 noinst_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_LIBADD = ./libgc.la
 libgccpp_la_LDFLAGS = -version-info 1:3:0 -no-undefined
 endif
 
@@ -155,7 +155,6 @@ dist_noinst_SCRIPTS = callprocs configure.host
 # headers which are not installed
 # (see include/include.am for more)
 #
-dist_noinst_HEADERS += version.h
 
 # documentation which is not installed
 #
@@ -167,7 +166,8 @@ 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 configure_atomic_ops.sh \
-    NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE
+    NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE \
+    NT_X64_THREADS_MAKEFILE
 
 # files used by makefiles other than Makefile.am
 #
index 40195a56255e8fe108dc2c9654ec00d0832f6ab7..23b0ab36dbf9d3fe42eef02314751d1f21ec325b 100644 (file)
@@ -183,7 +183,8 @@ HOSTCFLAGS=$(CFLAGS)
 # -DUSE_MUNMAP causes memory to be returned to the OS under the right
 #   circumstances.  This currently disables VM-based incremental collection.
 #   This is currently experimental, and works only under some Unix,
-#   Linux and Windows versions.
+#   Linux and Windows versions.  Requires -DUSE_MMAP, even under Windows,
+#   where USE_MMAP doesn't do anything.
 # -DMMAP_STACKS (for Solaris threads) Use mmap from /dev/zero rather than
 #   GC_scratch_alloc() to get stack memory.
 # -DPRINT_BLACK_LIST Whenever a black list entry is added, i.e. whenever
@@ -213,8 +214,6 @@ HOSTCFLAGS=$(CFLAGS)
 #   the GC_debug_ functions, or through the macros that expand to these,
 #   or by redirecting malloc to GC_debug_malloc_replacement.
 #   (Also eliminates the field for the requested object size.)
-#   occasionally be useful for debugging of client code.  Slows down the
-#   collector somewhat, but not drastically.
 # -DSAVE_CALL_COUNT=<n> Set the number of call frames saved with objects
 #   allocated through the debugging interface.  Affects the amount of
 #   information generated in leak reports.  Only matters on platforms
@@ -319,6 +318,8 @@ HOSTCFLAGS=$(CFLAGS)
 #   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.
+# -DNO_PROC_STAT Causes the collector to avoid relying on Linux'
+#   /proc/self/stat.
 #
 
 CXXFLAGS= $(CFLAGS) 
@@ -345,7 +346,7 @@ 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 include/gc_tiny_fl.h \
-    include/private/gc_hdrs.h include/private/gc_priv.h \
+    include/gc_version.h include/private/gc_hdrs.h include/private/gc_priv.h \
     include/private/gcconfig.h include/private/gc_pmark.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 \
@@ -378,7 +379,8 @@ DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
        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
+       tests/leak_test.c tests/thread_leak_test.c tests/middle.c \
+       tests/smash_test.c tests/huge_test.c
 
 GNU_BUILD_FILES= configure.ac Makefile.am configure acinclude.m4 \
                 libtool.m4 install-sh configure.host Makefile.in \
@@ -392,7 +394,8 @@ 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 \
-                NT_X64_STATIC_THREADS_MAKEFILE configure_atomic_ops.sh
+                NT_X64_STATIC_THREADS_MAKEFILE NT_X64_THREADS_MAKEFILE \
+                configure_atomic_ops.sh
 #      Makefile and Makefile.direct are copies of each other.
 
 OTHER_FILES= Makefile setjmp_t.c callprocs \
@@ -400,7 +403,7 @@ OTHER_FILES= Makefile setjmp_t.c callprocs \
            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 mscvc_dbg.c include/private/msvc_dbg.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 \
@@ -428,7 +431,7 @@ all: gc.a gctest
 # 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
+       cd $(AO_SRC_DIR); $(MAKE) CC=$(CC) install
 
 LEAKFLAGS=$(CFLAGS) -DFIND_LEAK
 
@@ -592,7 +595,7 @@ mark_rts.o: $(srcdir)/mark_rts.c $(UTILS)
 #      Work-around for DEC optimizer tail recursion elimination bug.
 #  The ALPHA-specific line should be removed if gcc is used.
 
-alloc.o: version.h
+alloc.o: include/gc_version.h
 
 cord:
        mkdir cord
@@ -665,10 +668,10 @@ KandRtest: setjmp_test gctest
        ./setjmp_test
        ./gctest
 
-add_gc_prefix: $(srcdir)/add_gc_prefix.c $(srcdir)/version.h
+add_gc_prefix: $(srcdir)/add_gc_prefix.c $(srcdir)/include/gc_version.h
        $(CC) -o add_gc_prefix $(srcdir)/add_gc_prefix.c
 
-gcname: $(srcdir)/gcname.c $(srcdir)/version.h
+gcname: $(srcdir)/gcname.c $(srcdir)/include/gc_version.h
        $(CC) -o gcname $(srcdir)/gcname.c
 
 #We assume this is being done from source directory.
@@ -676,7 +679,7 @@ 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
+       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 ; \
index 4618eb84562260a3ff7734cf71a290927de2ecdd..c56ea7b03f60ddd44845fe380ba5aa6a792179ab 100644 (file)
@@ -165,7 +165,7 @@ CORD_SRCS=  cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordt
 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_version.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_inline.h gc.man \
@@ -189,7 +189,7 @@ OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
            Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
            add_gc_prefix.c README.solaris2 README.sgi README.hp README.uts \
           win32_threads.c NT_THREADS_MAKEFILE gc.mak README.dj Makefile.dj \
-          README.alpha README.linux README.MacOSX version.h Makefile.DLLs \
+          README.alpha README.linux README.MacOSX Makefile.DLLs \
           WCC_MAKEFILE nursery.c include/gc_nursery.h include/gc_copy_descr.h
 
 CORD_INCLUDE_FILES= $(srcdir)/include/gc.h $(srcdir)/include/cord.h \
@@ -302,7 +302,7 @@ mark_rts.o: $(srcdir)/mark_rts.c if_mach if_not_there $(UTILS)
 #      Work-around for DEC optimizer tail recursion elimination bug.
 #  The ALPHA-specific line should be removed if gcc is used.
 
-alloc.o: version.h
+alloc.o: include/gc_version.h
 
 cord/cordbscs.o: $(srcdir)/cord/cordbscs.c $(CORD_INCLUDE_FILES)
        $(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordbscs.c
index 91a0f60efc1044a1180990bc1e927ac13453426f..d0264b6074053067f8d123bd97026ae7058f3e5e 100644 (file)
@@ -1,5 +1,5 @@
 # Makefile for Windows NT.  Assumes Microsoft compiler.
-# DLLs are included in the root set under NT, but not under win32S.
+# DLLs are included in the root set.
 # Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
 
 MY_CPU=AMD64
index 11a90e1037a70d2998f3b9acef8de1c689d77f4f..dee018d97f202b4cb1c5e1607371b9b12152ed59 100644 (file)
@@ -1,7 +1,7 @@
 #include "config.h"
 
 # include <stdio.h>
-# include "version.h"
+# include <gc.h>
  
 int main(argc, argv, envp)
 int argc;
index b91806f0c725f9edf603dfb083d9be67240e866b..995d6585f7b5c76190f30d72e4cb290bb384b363 100644 (file)
@@ -53,19 +53,24 @@ struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
   word GC_free_bytes[N_HBLK_FLS+1] = { 0 };
        /* Number of free bytes on each list.   */
 
-  /* Is bytes + the number of free bytes on lists n .. N_HBLK_FLS      */
-  /* > GC_max_large_allocd_bytes?                                      */
+  /* Return the largest n such that                                    */
+  /* Is GC_large_allocd_bytes + the number of free bytes on lists      */
+  /* n .. N_HBLK_FLS > GC_max_large_allocd_bytes.                      */
+  /* If there is no such n, return 0.                                  */
 # ifdef __GNUC__
   __inline__
 # endif
-  static GC_bool GC_enough_large_bytes_left(word bytes, int n)
+  static int GC_enough_large_bytes_left(void)
   {
-    int i;
-    for (i = N_HBLK_FLS; i >= n; --i) {
-       bytes += GC_free_bytes[i];
-       if (bytes > GC_max_large_allocd_bytes) return TRUE;
+    int n;
+    word bytes = GC_large_allocd_bytes;
+
+    GC_ASSERT(GC_max_large_allocd_bytes <= GC_heapsize);
+    for (n = N_HBLK_FLS; n >= 0; --n) {
+       bytes += GC_free_bytes[n];
+       if (bytes >= GC_max_large_allocd_bytes) return n;
     }
-    return FALSE;
+    return 0;
   }
 
 # define INCR_FREE_BYTES(n, b) GC_free_bytes[n] += (b);
@@ -360,13 +365,16 @@ 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];
     hdr * second_hdr;
-#   ifdef GC_ASSERTIONS
+#   if defined(GC_ASSERTIONS) && !defined(USE_MUNMAP)
       struct hblk *next = (struct hblk *)((word)h + hhdr -> hb_sz);
       hdr * nexthdr = HDR(next);
       struct hblk *prev = GC_free_block_ending_at(h);
       hdr * prevhdr = HDR(prev);
-      GC_ASSERT(nexthdr == 0 || !HBLK_IS_FREE(nexthdr) || !IS_MAPPED(nexthdr));
-      GC_ASSERT(prev == 0 || !HBLK_IS_FREE(prevhdr) || !IS_MAPPED(prevhdr));
+      GC_ASSERT(nexthdr == 0 || !HBLK_IS_FREE(nexthdr)
+                || (signed_word)GC_heapsize < 0);
+               /* In the last case, blocks may be too large to merge. */
+      GC_ASSERT(prev == 0 || !HBLK_IS_FREE(prevhdr)
+               || (signed_word)GC_heapsize < 0);
 #   endif
     GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
     GC_hblkfreelist[index] = h;
@@ -392,13 +400,15 @@ void GC_unmap_old(void)
     word sz;
     unsigned short last_rec, threshold;
     int i;
-#   define UNMAP_THRESHOLD 6
+#   ifndef MUNMAP_THRESHOLD
+#     define MUNMAP_THRESHOLD 6
+#   endif
     
     for (i = 0; i <= N_HBLK_FLS; ++i) {
       for (h = GC_hblkfreelist[i]; 0 != h; h = hhdr -> hb_next) {
         hhdr = HDR(h);
        if (!IS_MAPPED(hhdr)) continue;
-       threshold = (unsigned short)(GC_gc_no - UNMAP_THRESHOLD);
+       threshold = (unsigned short)(GC_gc_no - MUNMAP_THRESHOLD);
        last_rec = hhdr -> hb_last_reclaimed;
        if ((last_rec > GC_gc_no || last_rec < threshold)
            && threshold < GC_gc_no /* not recently wrapped */) {
@@ -428,8 +438,9 @@ void GC_merge_unmapped(void)
        next = (struct hblk *)((word)h + size);
        GET_HDR(next, nexthdr);
        /* Coalesce with successor, if possible */
-         if (0 != nexthdr && HBLK_IS_FREE(nexthdr)) {
-           nextsize = nexthdr -> hb_sz;
+         if (0 != nexthdr && HBLK_IS_FREE(nexthdr)
+             && (signed_word) (size + (nextsize = nexthdr->hb_sz)) > 0
+                /* no pot. overflow */) {
            if (IS_MAPPED(hhdr)) {
              GC_ASSERT(!IS_MAPPED(nexthdr));
              /* make both consistent, so that we can merge */
@@ -554,7 +565,8 @@ void GC_split_block(struct hblk *h, hdr *hhdr, struct hblk *n,
 }
        
 struct hblk *
-GC_allochblk_nth(size_t sz/* bytes */, int kind, unsigned flags, int n);
+GC_allochblk_nth(size_t sz/* bytes */, int kind, unsigned flags, int n,
+                GC_bool may_split);
 
 /*
  * Allocate (and return pointer to) a heap block
@@ -571,15 +583,52 @@ GC_allochblk(size_t sz, int kind, unsigned flags/* IGNORE_OFF_PAGE or 0 */)
     word blocks;
     int start_list;
     int i;
+    struct hblk *result;
+    int split_limit; /* Highest index of free list whose blocks we     */
+                    /* split.                                          */
 
     GC_ASSERT((sz & (GRANULE_BYTES - 1)) == 0);
     blocks = OBJ_SZ_TO_BLOCKS(sz);
+    if ((signed_word)(blocks * HBLKSIZE) < 0) {
+      return 0;
+    }
     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) {
-           return result;
+    /* Try for an exact match first. */
+    result = GC_allochblk_nth(sz, kind, flags, start_list, FALSE);
+    if (0 != result) return result;
+    if (GC_use_entire_heap || GC_dont_gc
+       || USED_HEAP_SIZE < GC_requested_heapsize
+        || TRUE_INCREMENTAL || !GC_should_collect()) {
+       /* Should use more of the heap, even if it requires splitting. */
+       split_limit = N_HBLK_FLS;
+    } else {
+#     ifdef USE_MUNMAP
+       /* avoid splitting, since that might require remapping */
+       split_limit = 0;
+#     else
+       if (GC_finalizer_bytes_freed > (GC_heapsize >> 4))  {
+         /* If we are deallocating lots of memory from         */
+         /* finalizers, fail and collect sooner rather         */
+         /* than later.                                        */
+         split_limit = 0;
+       } else {
+         /* If we have enough large blocks left to cover any   */
+         /* previous request for large blocks, we go ahead     */
+         /* and split.  Assuming a steady state, that should   */
+         /* be safe.  It means that we can use the full        */
+         /* heap if we allocate only small objects.            */
+          split_limit = GC_enough_large_bytes_left();
        }
+#     endif
+    }
+    if (start_list < UNIQUE_THRESHOLD) {
+      /* No reason to try start_list again, since all blocks are exact */
+      /* matches.                                                      */
+      ++start_list;
+    }
+    for (i = start_list; i <= split_limit; ++i) {
+       struct hblk * result = GC_allochblk_nth(sz, kind, flags, i, TRUE);
+       if (0 != result) return result;
     }
     return 0;
 }
@@ -587,9 +636,10 @@ GC_allochblk(size_t sz, int kind, 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.
+ * The may_split flag indicates whether it's OK to split larger blocks.
  */
 struct hblk *
-GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n)
+GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, GC_bool may_split)
 {
     struct hblk *hbp;
     hdr * hhdr;                /* Header corr. to hbp */
@@ -608,44 +658,21 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n)
            GET_HDR(hbp, hhdr);
            size_avail = hhdr->hb_sz;
            if (size_avail < size_needed) continue;
-           if (size_avail != size_needed
-               && !GC_use_entire_heap
-               && !GC_dont_gc
-               && USED_HEAP_SIZE >= GC_requested_heapsize
-               && !TRUE_INCREMENTAL && GC_should_collect()) {
-#              ifdef USE_MUNMAP
-                   continue;
-#              else
-                   /* If we have enough large blocks left to cover any */
-                   /* previous request for large blocks, we go ahead   */
-                   /* and split.  Assuming a steady state, that should */
-                   /* be safe.  It means that we can use the full      */
-                   /* heap if we allocate only small objects.          */
-                   if (!GC_enough_large_bytes_left(GC_large_allocd_bytes, n)) {
-                     continue;
-                   } 
-                   /* If we are deallocating lots of memory from       */
-                   /* finalizers, fail and collect sooner rather       */
-                   /* than later.                                      */
-                   if (GC_finalizer_bytes_freed > (GC_heapsize >> 4))  {
-                     continue;
-                   }
-#              endif /* !USE_MUNMAP */
-           }
-           /* If the next heap block is obviously better, go on.       */
-           /* This prevents us from disassembling a single large block */
-           /* to get tiny blocks.                                      */
-           {
+           if (size_avail != size_needed) {
              signed_word next_size;
-             
+
+             if (!may_split) continue;
+             /* If the next heap block is obviously better, go on.     */
+             /* This prevents us from disassembling a single large block */
+             /* to get tiny blocks.                                    */
              thishbp = hhdr -> hb_next;
              if (thishbp != 0) {
-               GET_HDR(thishbp, thishdr);
+               GET_HDR(thishbp, thishdr);
                next_size = (signed_word)(thishdr -> hb_sz);
                if (next_size < size_avail
-                 && next_size >= size_needed
-                 && !GC_is_black_listed(thishbp, (word)size_needed)) {
-                 continue;
+                   && next_size >= size_needed
+                   && !GC_is_black_listed(thishbp, (word)size_needed)) {
+                   continue;
                }
              }
            }
@@ -718,6 +745,7 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n)
                      struct hblk * prev = hhdr -> hb_prev;
                      
                      GC_large_free_bytes -= total_size;
+                     GC_bytes_dropped += total_size;
                      GC_remove_from_fl(hhdr, n);
                      for (h = hbp; h < limit; h++) {
                        if (h == hbp || 0 != (hhdr = GC_install_header(h))) {
@@ -733,7 +761,7 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n)
                    /* Restore hbp to point at free block */
                      hbp = prev;
                      if (0 == hbp) {
-                       return GC_allochblk_nth(sz, kind, flags, n);
+                       return GC_allochblk_nth(sz, kind, flags, n, may_split);
                      }
                      hhdr = HDR(hbp);
                  }
@@ -745,6 +773,7 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n)
                  if (!IS_MAPPED(hhdr)) {
                    GC_remap((ptr_t)hbp, hhdr -> hb_sz);
                    hhdr -> hb_flags &= ~WAS_UNMAPPED;
+                   /* Note: This may leave adjacent, mapped free blocks. */
                  }
 #              endif
                /* hbp may be on the wrong freelist; the parameter n    */
@@ -805,6 +834,11 @@ signed_word size;
     GET_HDR(hbp, hhdr);
     size = hhdr->hb_sz;
     size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size);
+    if (size <= 0)
+      ABORT("Deallocating excessively large block.  Too large an allocation?");
+      /* Probably possible if we try to allocate more than half the address */
+      /* space at once.  If we dont catch it here, strange things happen    */
+      /* later.                                                                    */
     GC_remove_counts(hbp, (word)size);
     hhdr->hb_sz = size;
 #   ifdef USE_MUNMAP
@@ -823,7 +857,9 @@ signed_word size;
     GET_HDR(next, nexthdr);
     prev = GC_free_block_ending_at(hbp);
     /* Coalesce with successor, if possible */
-      if(0 != nexthdr && HBLK_IS_FREE(nexthdr) && IS_MAPPED(nexthdr)) {
+      if(0 != nexthdr && HBLK_IS_FREE(nexthdr) && IS_MAPPED(nexthdr)
+         && (signed_word)(hhdr -> hb_sz + nexthdr -> hb_sz) > 0
+        /* no overflow */) {
        GC_remove_from_fl(nexthdr, FL_UNKNOWN);
        hhdr -> hb_sz += nexthdr -> hb_sz; 
        GC_remove_header(next);
@@ -831,7 +867,8 @@ signed_word size;
     /* Coalesce with predecessor, if possible. */
       if (0 != prev) {
        prevhdr = HDR(prev);
-       if (IS_MAPPED(prevhdr)) {
+       if (IS_MAPPED(prevhdr)
+           && (signed_word)(hhdr -> hb_sz + prevhdr -> hb_sz) > 0) {
          GC_remove_from_fl(prevhdr, FL_UNKNOWN);
          prevhdr -> hb_sz += hhdr -> hb_sz;
 #        ifdef USE_MUNMAP
index b0808d69c19260634a8b062e97c4c57a7e50ee9f..cb9a914b405921e0877592e54bff81c033553d71 100644 (file)
@@ -91,7 +91,14 @@ char * GC_copyright[] =
 " EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.",
 "See source code for details." };
 
-# include "version.h"
+/* Version macros are now defined in gc_version.h, which is included by        */
+/* gc.h, which is included by gc_priv.h".                              */
+
+#ifndef GC_NO_VERSION_VAR
+
+unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_TMP_ALPHA_VERSION);
+
+#endif /* GC_NO_VERSION_VAR */
 
 /* some more variables */
 
@@ -158,7 +165,7 @@ static word min_bytes_allocd()
     
     if (stack_size < 0) stack_size = -stack_size;
     total_root_size = 2 * stack_size + GC_root_size;
-    scan_size = 2 * GC_composite_in_use + GC_atomic_in_use
+    scan_size = 2 * GC_composite_in_use + GC_atomic_in_use/4
                + total_root_size;
     if (TRUE_INCREMENTAL) {
         return scan_size / (2 * GC_free_space_divisor);
@@ -182,6 +189,7 @@ word GC_adj_bytes_allocd(void)
     /* managed object should not alter result, assuming the client     */
     /* is playing by the rules.                                                */
     result = (signed_word)GC_bytes_allocd
+            + (signed_word)GC_bytes_dropped
             - (signed_word)GC_bytes_freed 
             + (signed_word)GC_finalizer_bytes_freed
             - expl_managed;
@@ -227,7 +235,13 @@ static word GC_collect_at_heapsize = (word)(-1);
 /* Have we allocated enough to amortize a collection? */
 GC_bool GC_should_collect(void)
 {
-    return(GC_adj_bytes_allocd() >= min_bytes_allocd()
+    static word last_min_bytes_allocd;
+    static word last_gc_no;
+    if (last_gc_no != GC_gc_no) {
+      last_gc_no = GC_gc_no;
+      last_min_bytes_allocd = min_bytes_allocd();
+    }
+    return(GC_adj_bytes_allocd() >= last_min_bytes_allocd
           || GC_heapsize >= GC_collect_at_heapsize);
 }
 
@@ -245,12 +259,12 @@ GC_bool GC_is_full_gc = FALSE;
  * Initiate a garbage collection if appropriate.
  * Choose judiciously
  * between partial, full, and stop-world collections.
- * Assumes lock held, signals disabled.
  */
 void GC_maybe_gc(void)
 {
     static int n_partial_gcs = 0;
 
+    GC_ASSERT(I_HOLD_LOCK());
     if (GC_should_collect()) {
         if (!GC_incremental) {
             GC_gcollect_inner();
@@ -434,6 +448,9 @@ int GC_collect_a_little(void)
     return(result);
 }
 
+# if !defined(REDIRECT_MALLOC) && (defined(MSWIN32) || defined(MSWINCE))
+  void GC_add_current_malloc_heap();
+# endif
 /*
  * Assumes lock is held, signals are disabled.
  * We stop the world.
@@ -449,6 +466,9 @@ GC_bool GC_stopped_mark(GC_stop_func stop_func)
     if (GC_print_stats)
        GET_TIME(start_time);
 
+#   if !defined(REDIRECT_MALLOC) && (defined(MSWIN32) || defined(MSWINCE))
+        GC_add_current_malloc_heap();
+#   endif
 #   if defined(REGISTER_LIBRARIES_EARLY)
         GC_cond_register_dynamic_libraries();
 #   endif
@@ -711,6 +731,7 @@ void GC_finish_collection()
       GC_bytes_allocd_before_gc += GC_bytes_allocd;
       GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
       GC_bytes_allocd = 0;
+      GC_bytes_dropped = 0;
       GC_bytes_freed = 0;
       GC_finalizer_bytes_freed = 0;
       
@@ -757,6 +778,22 @@ void GC_gcollect(void)
 
 word GC_n_heap_sects = 0;      /* Number of sections currently in heap. */
 
+#ifdef USE_PROC_FOR_LIBRARIES
+  word GC_n_memory = 0;                /* Number of GET_MEM allocated memory   */
+                               /* sections.                            */
+#endif
+
+#ifdef USE_PROC_FOR_LIBRARIES
+  /* Add HBLKSIZE aligned, GET_MEM-generated block to GC_our_memory. */
+  /* Defined to do nothing if USE_PROC_FOR_LIBRARIES not set.      */
+  void GC_add_to_our_memory(ptr_t p, size_t bytes)
+  {
+    if (0 == p) return;
+    GC_our_memory[GC_n_memory].hs_start = p;
+    GC_our_memory[GC_n_memory].hs_bytes = bytes;
+    GC_n_memory++;
+  }
+#endif
 /*
  * 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.
@@ -764,10 +801,24 @@ word GC_n_heap_sects = 0; /* Number of sections currently in heap. */
 void GC_add_to_heap(struct hblk *p, size_t bytes)
 {
     hdr * phdr;
+    word endp;
     
     if (GC_n_heap_sects >= MAX_HEAP_SECTS) {
        ABORT("Too many heap sections: Increase MAXHINCR or MAX_HEAP_SECTS");
     }
+    while ((word)p <= HBLKSIZE) {
+        /* Can't handle memory near address zero. */
+        ++p;
+       bytes -= HBLKSIZE;
+        if (0 == bytes) return;
+    }
+    endp = (word)p + bytes;
+    if (endp <= (word)p) {
+       /* Address wrapped. */
+       bytes -= HBLKSIZE;
+        if (0 == bytes) return;
+       endp -= HBLKSIZE;
+    }
     phdr = GC_install_header(p);
     if (0 == phdr) {
        /* This is extremely unlikely. Can't add it.  This will         */
@@ -775,6 +826,7 @@ void GC_add_to_heap(struct hblk *p, size_t bytes)
        /* which is entirely appropriate.                               */
        return;
     }
+    GC_ASSERT(endp > (word)p && endp == (word)p + 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++;
@@ -791,7 +843,7 @@ void GC_add_to_heap(struct hblk *p, size_t bytes)
                /* here.                                                */
     }
     if ((ptr_t)p + bytes >= (ptr_t)GC_greatest_plausible_heap_addr) {
-        GC_greatest_plausible_heap_addr = (void *)((ptr_t)p + bytes);
+        GC_greatest_plausible_heap_addr = (void *)endp;
     }
 }
 
@@ -821,12 +873,12 @@ void GC_print_heap_sects(void)
 void * GC_least_plausible_heap_addr = (void *)ONES;
 void * GC_greatest_plausible_heap_addr = 0;
 
-static INLINE ptr_t GC_max(ptr_t x, ptr_t y)
+static INLINE word GC_max(word x, word y)
 {
     return(x > y? x : y);
 }
 
-static INLINE ptr_t GC_min(ptr_t x, ptr_t y)
+static INLINE word GC_min(word x, word y)
 {
     return(x < y? x : y);
 }
@@ -871,6 +923,7 @@ GC_bool GC_expand_hp_inner(word n)
         return(FALSE);
     }
     space = GET_MEM(bytes);
+    GC_add_to_our_memory((ptr_t)space, bytes);
     if( space == 0 ) {
        if (GC_print_stats) {
            GC_log_printf("Failed to expand heap by %ld bytes\n",
@@ -883,27 +936,27 @@ GC_bool GC_expand_hp_inner(word n)
                      (unsigned long)bytes,
                      (unsigned long)GC_bytes_allocd);
     }
+    /* Adjust heap limits generously for blacklisting to work better.  */
+    /* GC_add_to_heap performs minimal adjustment need for correctness.        */
     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 =
-            (void *)GC_max((ptr_t)GC_greatest_plausible_heap_addr,
-                           (ptr_t)space + bytes + expansion_slop);
+       word new_limit = (word)space + bytes + expansion_slop;
+       if (new_limit > (word)space) {
+          GC_greatest_plausible_heap_addr =
+            (void *)GC_max((word)GC_greatest_plausible_heap_addr,
+                           (word)new_limit);
+       }
     } else {
         /* Heap is growing down */
-        GC_least_plausible_heap_addr =
-            (void *)GC_min((ptr_t)GC_least_plausible_heap_addr,
-                           (ptr_t)space - expansion_slop);
+       word new_limit = (word)space - expansion_slop;
+       if (new_limit < (word)space) {
+          GC_least_plausible_heap_addr =
+            (void *)GC_min((word)GC_least_plausible_heap_addr,
+                           (word)space - expansion_slop);
+       }
     }
-#   if defined(LARGE_CONFIG)
-      if (((ptr_t)GC_greatest_plausible_heap_addr <= (ptr_t)space + bytes
-           || (ptr_t)GC_least_plausible_heap_addr >= (ptr_t)space)
-         && GC_heapsize > 0) {
-       /* GC_add_to_heap will fix this, but ... */
-       WARN("Too close to address space limit: blacklisting ineffective\n", 0);
-      }
-#   endif
     GC_prev_heap_addr = GC_last_heap_addr;
     GC_last_heap_addr = (ptr_t)space;
     GC_add_to_heap(space, bytes);
index 9efe42bf63a0a35d54c037afea76a6407f08edb8..3abc6961957f53cf4efa7b7ebdc77b4eb504169a 100644 (file)
@@ -88,6 +88,8 @@ static back_edges * new_back_edges(void)
   if (0 == back_edge_space) {
     back_edge_space = (back_edges *)
                        GET_MEM(MAX_BACK_EDGE_STRUCTS*sizeof(back_edges));
+    GC_add_to_our_memory((ptr_t)back_edge_space,
+                        MAX_BACK_EDGE_STRUCTS*sizeof(back_edges));
   }
   if (0 != avail_back_edges) {
     back_edges * result = avail_back_edges;
@@ -127,11 +129,15 @@ static void push_in_progress(ptr_t p)
     if (in_progress_size == 0) {
       in_progress_size = INITIAL_IN_PROGRESS;
       in_progress_space = (ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t));
+      GC_add_to_our_memory((ptr_t)in_progress_space,
+                          in_progress_size * sizeof(ptr_t));
     } else {
       ptr_t * new_in_progress_space;
       in_progress_size *= 2;
       new_in_progress_space = (ptr_t *)
                                GET_MEM(in_progress_size * sizeof(ptr_t));
+      GC_add_to_our_memory((ptr_t)new_in_progress_space,
+                          in_progress_size * sizeof(ptr_t));
       BCOPY(in_progress_space, new_in_progress_space,
            n_in_progress * sizeof(ptr_t));
       in_progress_space = new_in_progress_space;
index 4cb639c05a039b093ce26ab126d07d10845486a3..40951cc5de916d7803867717920c9df52b50c035 100644 (file)
@@ -17,12 +17,12 @@ dnl Process this file with autoconf to produce configure.
 # Initialization
 # ==============
 
-AC_INIT(gc,7.0,Hans.Boehm@hp.com) 
+AC_INIT(gc,7.1,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 $)
+AC_REVISION($Revision: 1.35 $)
 GC_SET_VERSION
 AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects nostdinc])
 AM_MAINTAINER_MODE
@@ -170,6 +170,10 @@ case "$THREADS" in
        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.");
+        # Parallel-mark is currently unreliable on Darwin; ignore request
+        # if test "${enable_parallel_mark}" = yes; then
+        #   AC_DEFINE(PARALLEL_MARK)
+        # fi
        if test "${enable_parallel_mark}" = yes; then
          AC_DEFINE([PARALLEL_MARK], 1, [parallel mark])
        fi
@@ -309,6 +313,15 @@ case "$host" in
     ;;
 esac
 
+case "$host" in
+  *-*-hpux*)
+    avoid_cpp_lib=yes;;
+  *)
+    avoid_cpp_lib=no;
+    ;;
+esac
+AM_CONDITIONAL(AVOID_CPP_LIB,test $avoid_cpp_lib = yes)
+
 # extra LD Flags which are required for targets
 case "${host}" in
   *-*-darwin*)
@@ -360,13 +373,13 @@ AC_ENABLE_SHARED
 case "$host" in
  alpha-*-openbsd*)
      enable_shared=no
-     AC_MSG_RESULT(no)
      ;;
  *)
-     AC_MSG_RESULT(yes)
      ;;
 esac
 
+AC_MSG_RESULT($enable_shared)
+
 # Configuration of machine-dependent code
 #
 AC_MSG_CHECKING(which machine-dependent code should be used) 
@@ -546,6 +559,7 @@ if test "${enable_redirect_malloc}" = yes; then
     else
        AC_DEFINE([REDIRECT_MALLOC], GC_malloc, [redirect malloc])
     fi
+    AC_DEFINE(GC_USE_DLOPEN_WRAP)
 fi
 
 AC_ARG_ENABLE(large-config,
@@ -607,6 +621,25 @@ if test "${enable_gc_assertions}" = yes; then
     AC_DEFINE([GC_ASSERTIONS], 1, [gc assertions])
 fi
 
+AC_ARG_ENABLE(munmap,
+    [AC_HELP_STRING([--enable-munmap=N],
+       [return page to the os if empty for N collections])],
+  MUNMAP_THRESHOLD=$enableval;
+   [case "$MMAP" in
+      no)
+        AC_MSG_ERROR([--enable-munmap requires --enable-mmap])
+        ;;
+    esac]
+   )
+if test "${enable_munmap}" != ""; then
+    AC_DEFINE(USE_MMAP)
+    AC_DEFINE(USE_MUNMAP)
+    if test "${MUNMAP_THRESHOLD}" = "yes"; then
+      MUNMAP_THRESHOLD=6
+    fi
+    AC_DEFINE_UNQUOTED(MUNMAP_THRESHOLD, ${MUNMAP_THRESHOLD})
+fi
+
 AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
 
 
@@ -638,22 +671,22 @@ AC_CHECK_HEADER(atomic_ops.h,
     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
+    test -e libatomic_ops \
+       || ln -s ${ao_dir} 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 atomic_ops.c \
+       || ln -s libatomic_ops/src/atomic_ops.c \
+                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
+    test -e atomic_ops_sysdeps.S \
+       || ln -s libatomic_ops/src/atomic_ops_sysdeps.S \
+                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"
+    GC_CFLAGS="${GC_CFLAGS} -I libatomic_ops/src"
     maybe_libatomic_ops="libatomic_ops"
   ])
 
index ba792acd5b6a95ae1d9b5d0730a622803418edb4..bb14c8749e782a7174480aeee84383577404b301 100644 (file)
@@ -478,6 +478,8 @@ void GC_stop_world()
        it created before stopping show up later.
     */
 
+    /* FIXME: This seems to erroneously stop the parallel marker threads? */
+
     changes = 1;
     prev_list = NULL;
     prevcount = 0;
index 3fbd60aec4d8af6bc02c82dae8abbc36e0cdd4cc..699376c4c9a43644b53de2f659c4b6c334164eef 100644 (file)
@@ -63,7 +63,7 @@ GC_bool GC_has_other_debug_info(ptr_t p)
 
 # include <stdlib.h>
 
-# if defined(LINUX) || defined(SOLARIS) \
+# if defined(__GLIBC__) || defined(SOLARIS) \
      || defined(HPUX) || defined(IRIX5) || defined(OSF1)
 #   define RANDOM() random()
 # else
@@ -404,12 +404,15 @@ void GC_debug_print_heap_obj_proc(ptr_t p)
 }
 
 #ifndef SHORT_DBG_HDRS
+/* Use GC_err_printf and friends to print a description of the object  */
+/* whose client-visible address is p, and which was smashed at         */
+/* clobbered_addr.                                                     */
 void GC_print_smashed_obj(ptr_t p, ptr_t clobbered_addr)
 {
     register oh * ohdr = (oh *)GC_base(p);
     
     GC_ASSERT(I_DONT_HOLD_LOCK());
-    GC_err_printf("%p in object at %p(", clobbered_addr, p);
+    GC_err_printf("%p in or near object at %p(", clobbered_addr, p);
     if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
         || ohdr -> oh_string == 0) {
         GC_err_printf("<smashed>, appr. sz = %ld)\n",
@@ -844,7 +847,8 @@ void GC_print_all_smashed_proc(void)
     if (GC_n_smashed == 0) return;
     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_print_smashed_obj((ptr_t)GC_base(GC_smashed[i]) + sizeof(oh),
+                            GC_smashed[i]);
        GC_smashed[i] = 0;
     }
     GC_n_smashed = 0;
index 33a6740bcc361f48da5753b617085608b057006f..d9d49e827f4b8ba64d63d0174f7e50be42307d26 100644 (file)
@@ -31,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 7.0 of a conservative garbage collector for C and C++.
+This is version 7.1 of a conservative garbage collector for C and C++.
 
 You might find a more recent version of this at
 
index 6a9a1fdcb372f092179f5cf139f2fff200415acc..1481c375cdb51bbcfea1b2909718ef1f7c0f0ae7 100644 (file)
@@ -27,6 +27,16 @@ this.  This is a work in progress)
 MACRO          EXPLANATION
 -----          -----------
 
+GC_DEBUG       Tested by gc.h.  Causes all-upper-case macros to
+               expand to calls to debug versions of collector routines.
+
+GC_NO_THREAD_REDIRECTS Tested by gc.h.  Prevents redirection of thread
+               creation routines etc. to GC_ versions.  Requires the
+               programmer to explicitly handle thread registration.
+
+GC_NO_THREAD_DECLS Tested by gc.h. MS Windows only.  Do not declare
+               Windows thread creation routines and do not include windows.h.  
+
 __DMC__        Always #define'd by the Digital Mars compiler. Expands
                to the compiler version number in hex, i.e. 0x810 is
                version 8.1b0
index 1dce2b9e78fdde024f1376274344b1fd2c369738..0cec9e9eb0b8610e26d8c4c8e0cb3376aa77aca7 100644 (file)
@@ -69,7 +69,7 @@ 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.
+Makefile, or possibly with the "configure --disable-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
index 9db0e78c618de259fa727bd2cf216176fc2c439a..2225fd4ca12810363676e03787432857715bd405 100644 (file)
@@ -1,9 +1,9 @@
 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.
+and later 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
+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
@@ -13,5 +13,10 @@ gctest.exe.log after a few seconds.
 This process is completely analogous to NT_STATIC_THREADS_MAKEFILE
 for the 32-bit version.
 
+A similar procedure using NT_X64_THREADS_MAKEFILE should be usable to
+build the dynamic library.  Test_cpp.exe did not seem to run correctly this
+way.  It seems that we're getting the wrong instances of operator new/delete
+in some cases.  The C tests seemed OK.
+
 Note that currently a few warnings are still generated by default,
 and a number of others have been explicitly turned off in the makefile.
index 74230aa6caee465d4e677511eaa4b6a557585834..312d37f417f9a8734fffe6870d18468daba50a05 100644 (file)
@@ -106,7 +106,7 @@ 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.  As of GC 7.0, it is required if
+on as many platforms as possible.  In GC 7.0, it was 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>
@@ -206,16 +206,18 @@ proper repair requires platform hooks.)
 The easiest way to ensure that collectable objects are properly referenced
 is to allocate only collectable objects.  This requires that every
 allocation go through one of the following interfaces, each one of
-which replaces a standard C++ allocation mechanism:
+which replaces a standard C++ allocation mechanism.  Note that
+this requires that all STL containers be explicitly instantiated with
+<TT>gc_allocator</tt>.
 <DL>
 <DT> <B> STL allocators </b>
 <DD>
 <P>
-Recent versions of the collector also include a more standard-conforming
+Recent versions of the collector include a hopefully standard-conforming
 allocator implementation in <TT>gc_allocator.h</tt>.  It defines
 <UL>
-<LI> traceable_allocator
-<LI> gc_allocator
+<LI> <TT>traceable_allocator</tt>
+<LI> <TT>gc_allocator</tt>
 </ul>
 which may be used either directly to allocate memory or to instantiate
 container templates. 
@@ -226,26 +228,26 @@ 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>
 or its derivatives (including most g++ versions)
-can alternatively include <TT>new_gc_alloc.h</tt> before including
-STL header files.
+may instead be able to include <TT>new_gc_alloc.h</tt> before including
+STL header files.  This is increasingly discouraged.
 (<TT>gc_alloc.h</tt> corresponds to now obsolete versions of the
 SGI STL.)  This interface is no longer recommended, but it has existed
 for much longer.
 <P>
 This defines SGI-style allocators
 <UL>
-<LI> alloc
-<LI> single_client_alloc
-<LI> gc_alloc
-<LI> single_client_gc_alloc
+<LI> <TT>alloc</tt>
+<LI> <TT>single_client_alloc</tt>
+<LI> <TT>gc_alloc</tt>
+<LI> <TT>single_client_gc_alloc</tt>
 </ul>
 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
+The <TT>single_client</tt> 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>.
-<DT> <B> Class inheritance based interface </b>
+<DT> <B> Class inheritance based interface for new-based allocation</b>
 <DD>
 Users may include gc_cpp.h and then cause members of classes to
 be allocated in garbage collectable memory by having those classes
index 2e70148dfb782fa877e75034368a8cbd3123c3b6..59da7bcf7d8c9f5d67871ff45303e12d29587b74 100644 (file)
@@ -52,9 +52,11 @@ implementation of <TT>GC_malloc_many</tt>, so that free lists can be
 built, and memory can be cleared, by more than one thread concurrently.
 <LI>
 Building the collector with -DTHREAD_LOCAL_ALLOC adds support for thread
-local allocation.  It does not, by itself, cause thread local allocation
-to be used.  It simply allows the use of the interface in 
-<TT>gc_local_alloc.h</tt>.
+local allocation.  Before GC version 7.0, it did not, by itself, cause
+thread local allocation to be used.  It simply allowed the use of the
+interface in <TT>gc_local_alloc.h</tt>.  Since version 7.0, this causes
+GC_malloc, GC_malloc_atomic, and GC_gcj_malloc to be redefined to perform
+thread-local allocation.
 <P>
 Memory returned from thread-local allocators is completely interchangeable
 with that returned by the standard allocators.  It may be used by other
@@ -72,7 +74,8 @@ used heavily, and thus the number of short-duration lock acquisitions
 is greatly reduced.
 </ul>
 <P>
-The easiest way to switch an application to thread-local allocation is to
+The easiest way to switch an application to thread-local allocation
+in a pre-version-7.0 collector was to
 <OL>
 <LI> Define the macro <TT>GC_REDIRECT_TO_LOCAL</tt>,
 and then include the <TT>gc.h</tt>
index 70fd0e0bc015fd40f98214138ff8fac9807e87a1..b0545cbc763e9901bbfb1ca7db050fcc56f2bef6 100644 (file)
@@ -242,6 +242,36 @@ char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
 char *GC_get_maps(void);
        /* From os_dep.c        */
 
+/* Sort an array of HeapSects by start address.                                */
+/* Unfortunately at least some versions of                             */
+/* Linux qsort end up calling malloc by way of sysconf, and hence can't */
+/* be used in the colector.  Hence we roll our own.  Should be         */
+/* reasonably fast if the array is already mostly sorted, as we expect */
+/* it to be.                                                           */
+void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
+{
+    signed_word n = (signed_word)number_of_elements;
+    signed_word nsorted = 1;
+    signed_word i;
+
+    while (nsorted < n) {
+      while (nsorted < n &&
+            base[nsorted-1].hs_start < base[nsorted].hs_start)
+          ++nsorted;
+      if (nsorted == n) break;
+      GC_ASSERT(base[nsorted-1].hs_start > base[nsorted].hs_start);
+      i = nsorted - 1;
+      while (i >= 0 && base[i].hs_start > base[i+1].hs_start) {
+        struct HeapSect tmp = base[i];
+       base[i] = base[i+1];
+       base[i+1] = tmp;
+       --i;
+      }
+      GC_ASSERT(base[nsorted-1].hs_start < base[nsorted].hs_start);
+      ++nsorted;
+    }
+}
+
 word GC_register_map_entries(char *maps)
 {
     char *prot;
@@ -253,18 +283,11 @@ word GC_register_map_entries(char *maps)
     unsigned i;
     ptr_t datastart = (ptr_t)(DATASTART);
 
-    /* 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) {
-           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 < (ptr_t)GC_scratch_last_end_ptr)
-           greatest_ha = (ptr_t)GC_scratch_last_end_ptr; 
+    GC_ASSERT(I_HOLD_LOCK());
+    sort_heap_sects(GC_our_memory, GC_n_memory);
+    least_ha = GC_our_memory[0].hs_start;
+    greatest_ha = GC_our_memory[GC_n_memory-1].hs_start
+                 + GC_our_memory[GC_n_memory-1].hs_bytes;
 
     for (;;) {
         buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot, &maj_dev, 0);
@@ -283,25 +306,53 @@ word GC_register_map_entries(char *maps)
              /* 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 */
+
+             /* FIXME: NPTL squirrels                                  */
+             /* away pointers in pieces of the stack segment that we   */
+             /* don't scan.  We work around this                       */
+             /* by treating anything allocated by libpthread as        */
+             /* uncollectable, as we do in some other cases.           */
+             /* A specifically identified 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   */
+             /* They may not be marked if the thread is still live.    */
+             /* This specific instance should be addressed by          */
+             /* INCLUDE_LINUX_THREAD_DESCR, but that doesn't quite     */
+             /* seem to suffice.                                       */
+             /* We currently trace entire thread stacks, if they are   */
+             /* are currently cached but unused.  This is              */
              /* very suboptimal for performance reasons.               */
 #          endif
            /* We no longer exclude the main data segment.              */
-           if (start < least_ha && end > least_ha) {
-               end = least_ha;
+           if (end <= least_ha || start >= greatest_ha) {
+             /* The easy case; just trace entire segment */
+             GC_add_roots_inner((char *)start, (char *)end, TRUE);
+             continue;
            }
-           if (start < greatest_ha && end > greatest_ha) {
-               start = greatest_ha;
-           }
-           if (start >= least_ha && end <= greatest_ha) continue;
-           GC_add_roots_inner((char *)start, (char *)end, TRUE);
+           /* Add sections that dont belong to us. */
+             i = 0;
+             while (GC_our_memory[i].hs_start + GC_our_memory[i].hs_bytes
+                    < start)
+                 ++i;
+             GC_ASSERT(i < GC_n_memory);
+             if (GC_our_memory[i].hs_start <= start) {
+                 start = GC_our_memory[i].hs_start
+                         + GC_our_memory[i].hs_bytes;
+                 ++i;
+             }
+             while (i < GC_n_memory && GC_our_memory[i].hs_start < end
+                    && start < end) {
+                 if ((char *)start < GC_our_memory[i].hs_start)
+                   GC_add_roots_inner((char *)start,
+                                      GC_our_memory[i].hs_start, TRUE);
+                 start = GC_our_memory[i].hs_start
+                         + GC_our_memory[i].hs_bytes;
+                 ++i;
+             }
+             if (start < end)
+                 GC_add_roots_inner((char *)start, (char *)end, TRUE);
        }
     }
     return 1;
@@ -1016,13 +1067,8 @@ static void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr, intptr_t slide)
     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++) {
-#   if defined (__LP64__)
-      sec = getsectbynamefromheader_64(
-#   else
-      sec = getsectbynamefromheader(
-#   endif
-                                   hdr, GC_dyld_sections[i].seg,
-                                   GC_dyld_sections[i].sect);
+      sec = GC_GETSECTBYNAME(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;
@@ -1044,13 +1090,8 @@ static void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
     unsigned long start,end,i;
     const struct GC_MACH_SECTION *sec;
     for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
-#   if defined (__LP64__)
-      sec = getsectbynamefromheader_64(
-#   else
-      sec = getsectbynamefromheader(
-#   endif
-                                   hdr, GC_dyld_sections[i].seg,
-                                   GC_dyld_sections[i].sect);
+      sec = GC_GETSECTBYNAME(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;
index fc11eaa9f78544d1506c8e0873c6d9f2d24e844f..5c2543e85371e75b1da811dd6f94eefc87ba2b65 100644 (file)
@@ -117,7 +117,7 @@ void GC_grow_table(struct hash_chain_entry ***table,
                (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
     
     if (new_table == 0) {
-       if (table == 0) {
+       if (*table == 0) {
            ABORT("Insufficient space for initial table allocation");
        } else {
            return;
@@ -191,7 +191,7 @@ int GC_general_register_disappearing_link(void * * link, void * obj)
              GC_oom_fn(sizeof(struct disappearing_link));
       if (0 == new_dl) {
        GC_finalization_failures++;
-       return(0);
+       return(2);
       }
       /* It's not likely we'll make it here, but ... */
 #     ifdef THREADS
@@ -395,7 +395,6 @@ GC_API void GC_register_finalizer_inner(void * obj,
     }
     new_fo = (struct finalizable_object *)
        GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
-    GC_ASSERT(GC_size(new_fo) >= sizeof(struct finalizable_object));
     if (EXPECT(0 == new_fo, FALSE)) {
 #     ifdef THREADS
        UNLOCK();
@@ -411,6 +410,7 @@ GC_API void GC_register_finalizer_inner(void * obj,
        LOCK();
 #     endif
     }
+    GC_ASSERT(GC_size(new_fo) >= sizeof(struct finalizable_object));
     new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
     new_fo -> fo_fn = fn;
     new_fo -> fo_client_data = (ptr_t)cd;
index c4dc4cd2562647f3d0549d3432f42180c512f138..47cff19e309c17be01fb9cc94253a9f6c00772cd 100644 (file)
@@ -22,9 +22,8 @@ built-in "new" and "delete".
 Authors: John R. Ellis and Jesse Hull
 
 **************************************************************************/
-/* Boehm, December 20, 1994 7:26 pm PST */
 
-#include "gc_cpp.h"
+#include <gc_cpp.h>
 
 void* operator new( size_t size ) {
     return GC_MALLOC_UNCOLLECTABLE( size );}
index 2165d30210826220f5c9d9d264856c0428860bf5..9d2212ee9fe9ce7b29300ef63b4aaccb14265033 100644 (file)
@@ -1,7 +1,7 @@
 #include "config.h"
 
 #include <stdio.h>
-#include "version.h"
+#include <gc.h>
 
 int main()
 {
index c9930d3a5483b21bec8eed0f55883dfbe1e31194..72b16e2b6e6d498782d8dbbfdc0b464b4107e5db 100644 (file)
@@ -134,11 +134,13 @@ ptr_t GC_scratch_alloc(size_t bytes)
                bytes_to_get &= ~(GC_page_size - 1);
 #          endif
            result = (ptr_t)GET_MEM(bytes_to_get);
+           GC_add_to_our_memory(result, bytes_to_get);
             scratch_free_ptr -= bytes;
            GC_scratch_last_end_ptr = result + bytes;
             return(result);
         }
         result = (ptr_t)GET_MEM(bytes_to_get);
+        GC_add_to_our_memory(result, bytes_to_get);
         if (result == 0) {
            if (GC_print_stats)
                 GC_printf("Out of memory - trying to allocate less\n");
@@ -148,7 +150,9 @@ ptr_t GC_scratch_alloc(size_t bytes)
                bytes_to_get += GC_page_size - 1;
                bytes_to_get &= ~(GC_page_size - 1);
 #          endif
-            return((ptr_t)GET_MEM(bytes_to_get));
+            result = (ptr_t)GET_MEM(bytes_to_get);
+            GC_add_to_our_memory(result, bytes_to_get);
+           return result;
         }
         scratch_free_ptr = result;
         GC_scratch_end_ptr = scratch_free_ptr + bytes_to_get;
index f4e5b5c50b1b710516ed71584ed8e82a55749f94..1dab4c214cc789b75b4e80ade73ef2f56750f505 100644 (file)
 
 # define _GC_H
 
+# include "gc_version.h"
+       /* Define version numbers here to allow test on build machine   */
+       /* for cross-builds.  Note that this defines the header         */
+       /* version number, which may or may not match that of the       */
+       /* dynamic library.  The GC_version variable can be used        */
+       /* to obtain the latter.                                        */
+
 # include "gc_config_macros.h"
 
 # ifdef __cplusplus
@@ -230,11 +237,8 @@ GC_API unsigned long GC_time_limit;
 
 /* Public procedures */
 
-/* Initialize the collector.  This is only required when using thread-local
- * allocation, since unlike the regular allocation routines, GC_local_malloc
- * is not self-initializing.  If you use GC_local_malloc you should arrange
- * to call this somehow (e.g. from a constructor) before doing any allocation.
- * For win32 threads, it needs to be called explicitly.
+/* Initialize the collector.  Portable clients should call GC_INIT() from
+ * the main program instead.
  */
 GC_API void GC_init(void);
 
@@ -469,7 +473,7 @@ GC_API void * GC_malloc_atomic_ignore_off_page(size_t lb);
 #if defined(__linux__) || defined(__GLIBC__)
 # include <features.h>
 # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
-     && !defined(__ia64__)
+     && !defined(__ia64__) && !defined(__UCLIBC__)
 #   ifndef GC_HAVE_BUILTIN_BACKTRACE
 /* #     define GC_HAVE_BUILTIN_BACKTRACE */
 #   endif
@@ -739,8 +743,9 @@ GC_API int GC_register_disappearing_link(void * * link );
        /* be allowed here, instead of just clearing a pointer. */
        /* But this causes problems if that action alters, or   */
        /* examines connectivity.                               */
-       /* Returns 1 if link was already registered, 0          */
-       /* otherwise.                                           */
+       /* Returns 1 if link was already registered, 0 if       */
+       /* registration succeeded, 2 if it failed for lack of   */
+       /* memory, and GC_oom_fn did not handle the problem.    */
        /* Only exists for backward compatibility.  See below:  */
        
 GC_API int GC_general_register_disappearing_link (void * * link, void * obj);
@@ -860,7 +865,7 @@ typedef void * (*GC_stack_base_func)(struct GC_stack_base *sb, void *arg);
 /* 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);
+GC_API 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       */
@@ -873,7 +878,7 @@ void * GC_call_with_stack_base(GC_stack_base_func fn, void *arg);
 #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 *);
+GC_API 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              */
@@ -882,7 +887,7 @@ int GC_register_my_thread(struct GC_stack_base *);
 /* 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);
+GC_API 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 */
@@ -890,7 +895,7 @@ int GC_unregister_my_thread(void);
 /* 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 *);
+GC_API 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.     */
@@ -969,7 +974,7 @@ void GC_dump(void);
 #   define GC_PTR_STORE(p, q) \
        (*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
 #else /* !GC_DEBUG */
-#   define GC_PTR_STORE(p, q) *((p) = (q))
+#   define GC_PTR_STORE(p, q) (*(p) = (q))
 #endif
 
 /* Functions called to report pointer checking errors */
@@ -983,8 +988,8 @@ GC_API void (*GC_is_visible_print_proc) (void * p);
 /* For pthread support, we generally need to intercept a number of     */
 /* thread library calls.  We do that here by macro defining them.      */
 
-#if !defined(GC_USE_LD_WRAP) && \
-    (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS))
+#if !defined(GC_USE_LD_WRAP) && !defined(GC_NO_THREAD_REDIRECTS) \
+    && defined(GC_PTHREADS)
 # include "gc_pthread_redirects.h"
 #endif
 
@@ -999,7 +1004,6 @@ GC_API void (*GC_is_visible_print_proc) (void * p);
 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(void); /* Needed for Solaris/X86 ??    */
 
 #endif /* THREADS */
 
@@ -1021,6 +1025,7 @@ GC_register_has_static_roots_callback
     }  /* Including windows.h in an extern "C" context no longer works. */
 #endif
 
+#ifndef GC_NO_THREAD_DECLS
 # include <windows.h>
 
 #ifdef __cplusplus
@@ -1046,6 +1051,9 @@ GC_register_has_static_roots_callback
       DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
       LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
 
+#  if defined(_MSC_VER) && _MSC_VER >= 1200 && !defined(_UINTPTR_T_DEFINED)
+     typedef unsigned long uintptr_t;
+#  endif
 
    GC_API uintptr_t GC_beginthreadex(
      void *security, unsigned stack_size,
@@ -1070,17 +1078,23 @@ GC_register_has_static_roots_callback
 #    define WinMain GC_WinMain
 #  endif
 # endif /* defined(_WIN32_WCE) */
+#endif /* !GC_NO_THREAD_DECLS */
 
   /*
    * Use implicit thread registration via DllMain.
+   * Must be called before GC_INIT and other GC routines.
+   * Should be avoided if GC_beginthreadex and friends can be called
+   * instead.
    */
 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" < }
+# ifndef GC_NO_THREAD_REDIRECTS
+#   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 /* !GC_NO_THREAD_REDIRECTS */
 
 #endif /* defined(GC_WIN32_THREADS)  && !cygwin */
 
@@ -1090,7 +1104,8 @@ GC_API void GC_use_DllMain(void);
   * 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().
+  * defined and the initial allocation call is not to GC_malloc() or
+  * GC_malloc_atomic().
   */
 #if defined(__CYGWIN32__) || defined (_AIX)
     /*
@@ -1106,13 +1121,9 @@ GC_API void GC_use_DllMain(void);
 #     define GC_MIN(x,y) ((x) < (y) ? (x) : (y))
 #     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); \
+#     define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); \
                           GC_gcollect(); /* For blacklisting. */}
-#     else
-       /* Main program init not required  */
-#       define GC_INIT() { GC_init(); }
-#     endif
+       /* Required at least if GC is in dll.  And doesn't hurt. */
 #   endif
 #   if defined(_AIX)
       extern int _data[], _end[];
@@ -1137,8 +1148,8 @@ GC_API void GC_use_DllMain(void);
 # include "gc_amiga_redirects.h"
 #endif
 
-#if defined(GC_REDIRECT_TO_LOCAL) && !defined(GC_LOCAL_ALLOC_H)
-#  include  "gc_local_alloc.h"
+#if defined(GC_REDIRECT_TO_LOCAL)
+  /* Now redundant; that's the default with THREAD_LOCAL_ALLOC */
 #endif
 
 #ifdef __cplusplus
index d3df21121038b4b6e66000f49a475d98ab2c67ea..2a69f0528f43a83532399b0aea8058666e693fa6 100644 (file)
@@ -177,7 +177,9 @@ class gc {public:
        /* Must be redefined here, since the other overloadings */
        /* hide the global definition.                          */
     inline void operator delete( void* obj );
-#   ifdef GC_PLACEMENT_DELETE  
+#   ifdef GC_PLACEMENT_DELETE
+      inline void operator delete( void*, GCPlacement );
+       /* called if construction fails.        */
       inline void operator delete( void*, void* );
 #   endif
 
@@ -187,6 +189,7 @@ class gc {public:
     inline void* operator new[]( size_t size, void *p );
     inline void operator delete[]( void* obj );
 #   ifdef GC_PLACEMENT_DELETE
+      inline void operator delete[]( void*, GCPlacement );
       inline void operator delete[]( void*, void* );
 #   endif
 #endif /* GC_OPERATOR_NEW_ARRAY */
@@ -235,12 +238,15 @@ inline void* operator new(
     classes derived from "gc_cleanup" or containing members derived
     from "gc_cleanup". */
 
+#   ifdef GC_PLACEMENT_DELETE
+      inline void operator delete( void*, GCPlacement, GCCleanUpFunc, void * );
+#   endif
 
 #ifdef _MSC_VER
  /** This ensures that the system default operator new[] doesn't get
   *  undefined, which is what seems to happen on VC++ 6 for some reason
   *  if we define a multi-argument operator new[].
-  *  There seems to be really redirect new in this environment without
+  *  There seems to be no way to redirect new in this environment without
   *  including this everywhere. 
   */
  void *operator new[]( size_t size );
@@ -296,6 +302,10 @@ inline void gc::operator delete( void* obj ) {
     
 #ifdef GC_PLACEMENT_DELETE
   inline void gc::operator delete( void*, void* ) {}
+
+  inline void gc::operator delete( void* p, GCPlacement gcp ) {
+    GC_FREE(p);
+  }
 #endif
 
 #ifdef GC_OPERATOR_NEW_ARRAY
@@ -314,6 +324,10 @@ inline void gc::operator delete[]( void* obj ) {
 
 #ifdef GC_PLACEMENT_DELETE
   inline void gc::operator delete[]( void*, void* ) {}
+
+  inline void gc::operator delete[]( void* p, GCPlacement gcp ) {
+    gc::operator delete(p); }
+
 #endif
     
 #endif /* GC_OPERATOR_NEW_ARRAY */
@@ -356,6 +370,16 @@ inline void* operator new(
         obj = GC_MALLOC_UNCOLLECTABLE( size );};
     return obj;}
         
+# ifdef GC_PLACEMENT_DELETE
+inline void operator delete ( 
+    void *p, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup,
+    void* clientData )
+{
+    GC_FREE(p);
+}
+# endif
 
 #ifdef GC_OPERATOR_NEW_ARRAY
 
index da7e2e91f020e8d120506f42c5493cf1e6f1734b..ffc5b3ea1ccc8ad6119dfaae818c50d6ffc5d3a9 100644 (file)
@@ -34,9 +34,9 @@
 #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            */
+/* of size granules, 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 granules 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.    */
@@ -47,7 +47,7 @@
 /* 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     */
+/* Particularly if granules 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) \
            /* 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; \
+                *my_fl = (char *)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)), \
+                                         GC_RAW_BYTES_FROM_INDEX(granules)), \
                                       kind, my_fl); \
                my_entry = *my_fl; \
                 if (my_entry == 0) { \
-                   result = GC_oom_fn(bytes); \
+                   result = GC_oom_fn(granules*GC_GRANULE_BYTES); \
                    goto out; \
                } \
            } \
@@ -84,7 +84,7 @@
         *my_fl = next; \
        init; \
         PREFETCH_FOR_WRITE(next); \
-        GC_ASSERT(GC_size(result) >= bytes + EXTRA_BYTES); \
+        GC_ASSERT(GC_size(result) >= granules*GC_GRANULE_BYTES); \
         GC_ASSERT((kind) == PTRFREE || ((GC_word *)result)[1] == 0); \
       out: ; \
    } \
 /* a global array.                                                     */
 # define GC_MALLOC_WORDS(result,n,tiny_fl) \
 {      \
-    size_t grans = WORDS_TO_WHOLE_GRANULES(n); \
+    size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
     GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
-                        NORMAL, GC_malloc(grans*GRANULE_BYTES), \
+                        NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
                         *(void **)result = 0); \
 }
 
 # define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
 {      \
-    size_t grans = WORDS_TO_WHOLE_GRANULES(n); \
+    size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
     GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
-                        PTRFREE, GC_malloc_atomic(grans*GRANULE_BYTES), \
+                        PTRFREE, GC_malloc_atomic(grans*GC_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); \
+    size_t grans = GC_WORDS_TO_WHOLE_GRANULES(2); \
     GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
-                        NORMAL, GC_malloc(grans*GRANULE_BYTES), \
+                        NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
                         *(void **)result = (void *)(first)); \
     ((void **)(result))[1] = (void *)(second); \
 }
index 52b6864b6b1bfb67e136f97d84b37bf0353d3665..91b77fdf2277fac468d994fd909d06412c18cc45 100644 (file)
@@ -27,7 +27,7 @@
  */
 
 /*
- * We always set GRANULE_BYTES to twice the length of a pointer.
+ * We always set GC_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
@@ -61,7 +61,7 @@
 #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)
+#  define GC_WORDS_TO_GRANULES(n) ((n)*sizeof(void *)/GC_GRANULE_BYTES)
 #endif
 
 /* A "tiny" free list header contains TINY_FREELISTS pointers to       */
@@ -76,7 +76,7 @@
 # endif
 #endif /* !GC_TINY_FREELISTS */
 
-/* The ith free list corresponds to size i*GRANULE_BYTES       */
+/* The ith free list corresponds to size i*GC_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.    */
@@ -84,6 +84,6 @@
 /* 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)
+#define GC_RAW_BYTES_FROM_INDEX(i) ((i) * GC_GRANULE_BYTES)
 
 #endif /* GC_TINY_FL_H */
index c0f28414c3083349ef86c6aa6692ac8b6a3bbc62..991a07990ff756fa76ad26399e836de6ec439650 100644 (file)
@@ -31,7 +31,8 @@ dist_noinst_HEADERS += \
        include/gc_amiga_redirects.h \
        include/gc_pthread_redirects.h \
        include/gc_config_macros.h \
-       include/gc_tiny_fl.h
+       include/gc_tiny_fl.h \
+       include/gc_version.h
 
 # headers which are not installed
 #
@@ -52,3 +53,8 @@ dist_noinst_HEADERS += \
        include/cord.h \
        include/ec.h \
        include/javaxfc.h 
+
+# unprefixed header
+include_HEADERS += \
+        include/extra/gc.h \
+        include/extra/gc_cpp.h
index d7c83b07b9129ea6ab604a456df04a83479a867c..d11044b3eb3481b858768a9822c2d34aabb53f08 100644 (file)
@@ -36,8 +36,8 @@
      extern PCR_Th_ML GC_allocate_ml;
 #    define DCL_LOCK_STATE \
         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 UNCOND_LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
+#    define UNCOND_UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
 #  endif
 
 #  if !defined(AO_HAVE_test_and_set_acquire) && defined(GC_PTHREADS)
 #        undef NUMERIC_THREAD_ID_UNIQUE
 #      endif
 #    endif
-#    define NO_THREAD (-1l)
+#    define NO_THREAD ((unsigned long)(-1l))
                /* != NUMERIC_THREAD_ID(pthread_self()) for any thread */
 
 #    if !defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_LOCKS)
index 36083970acdcba98cd3a03d2943d8bd68085f4ce..81c260be31be01655129ede82e986ef90879f198 100644 (file)
@@ -60,10 +60,9 @@ extern unsigned GC_n_mark_procs;
 #define GC_MARK_STACK_DISCARDS (INITIAL_MARK_STACK_SIZE/8)
 
 typedef struct GC_ms_entry {
-    ptr_t mse_start;   /* First word of object */
+    ptr_t mse_start;   /* First word of object, word aligned  */
     GC_word mse_descr; /* Descriptor; low order two bits are tags,     */
-                       /* identifying the upper 30 bits as one of the  */
-                       /* following:                                   */
+                       /* as described in gc_mark.h.                   */
 } mse;
 
 extern size_t GC_mark_stack_size;
@@ -244,10 +243,10 @@ exit_label: ; \
 /* 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      */
+/* first 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    */
+/* here.  Note in particular that the "displ" value is the displacement        */
+/* from the beginning 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, \
index ec93ffea9c979ce1d104be22bf9e60d38e401b7f..1d96d87c85812c28770364e44b4a9cb45b6a2443 100644 (file)
@@ -375,12 +375,14 @@ extern GC_warn_proc GC_current_warn_proc;
 #                define GC_MACH_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
 #                define GC_MACH_HEADER mach_header
 #                define GC_MACH_SECTION section
+#                 define GC_GETSECTBYNAME getsectbynamefromheader
 #              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
+#                 define GC_GETSECTBYNAME getsectbynamefromheader_64
 #              endif
 #      elif defined(I386) || defined(X86_64)
 #               if CPP_WORDSZ == 32
@@ -389,12 +391,14 @@ extern GC_warn_proc GC_current_warn_proc;
 #                define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
 #                define GC_MACH_HEADER mach_header
 #                define GC_MACH_SECTION section
+#                 define GC_GETSECTBYNAME getsectbynamefromheader
 #               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
+#                 define GC_GETSECTBYNAME getsectbynamefromheader_64
 #               endif
 #      else
 #              error define GC_THREAD_STATE_T
@@ -486,17 +490,22 @@ extern GC_warn_proc GC_current_warn_proc;
 /*                   */
 /*********************/
 
-/*  heap block size, bytes. Should be power of 2 */
+/*  Heap block size, bytes. Should be power of 2.              */
+/* Incremental GC with MPROTECT_VDB currently requires the     */
+/* page size to be a multiple of HBLKSIZE.  Since most modern  */
+/* architectures support variable page sizes down to 4K, and   */
+/* X86 is generally 4K, we now default to 4K, except for       */
+/*   Alpha: Seems to be used with 8K pages.                    */
+/*   SMALL_CONFIG: Want less block-level fragmentation.                */
 
 #ifndef HBLKSIZE
 # ifdef SMALL_CONFIG
 #   define CPP_LOG_HBLKSIZE 10
 # else
-#   if (CPP_WORDSZ == 32) || (defined(HPUX) && defined(HP_PA))
-      /* HPUX/PA seems to use 4K pages with the 64 bit ABI */
-#     define CPP_LOG_HBLKSIZE 12
-#   else
+#   if defined(ALPHA)
 #     define CPP_LOG_HBLKSIZE 13
+#   else
+#     define CPP_LOG_HBLKSIZE 12
 #   endif
 # endif
 #else
@@ -523,6 +532,7 @@ extern GC_warn_proc GC_current_warn_proc;
 # endif
 # undef HBLKSIZE
 #endif
+
 # define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
 # define LOG_HBLKSIZE   ((size_t)CPP_LOG_HBLKSIZE)
 # define HBLKSIZE ((size_t)CPP_HBLKSIZE)
@@ -585,19 +595,26 @@ extern GC_warn_proc GC_current_warn_proc;
  */
  
 # ifdef LARGE_CONFIG
-#   define LOG_PHT_ENTRIES  20  /* Collisions likely at 1M blocks,     */
+#   if CPP_WORDSZ == 32
+#    define LOG_PHT_ENTRIES  20 /* Collisions likely at 1M blocks,     */
                                /* which is >= 4GB.  Each table takes   */
                                /* 128KB, some of which may never be    */
                                /* touched.                             */
+#   else
+#    define LOG_PHT_ENTRIES  21 /* Collisions likely at 2M blocks,     */
+                               /* which is >= 8GB.  Each table takes   */
+                               /* 256KB, some of which may never be    */
+                               /* touched.                             */
+#   endif
 # else
 #   ifdef SMALL_CONFIG
-#     define LOG_PHT_ENTRIES  14 /* Collisions are likely if heap grows        */
-                                /* to more than 16K hblks = 64MB.      */
-                                /* Each hash table occupies 2K bytes.   */
+#     define LOG_PHT_ENTRIES  15 /* Collisions are likely if heap grows        */
+                                /* to more than 32K hblks = 128MB.     */
+                                /* Each hash table occupies 4K bytes.  */
 #   else /* default "medium" configuration */
-#     define LOG_PHT_ENTRIES  16 /* Collisions are likely if heap grows        */
-                                /* to more than 64K hblks >= 256MB.    */
-                                /* Each hash table occupies 8K bytes.  */
+#     define LOG_PHT_ENTRIES  18 /* Collisions are likely if heap grows        */
+                                /* to more than 256K hblks >= 1GB.     */
+                                /* Each hash table occupies 32K bytes. */
                                 /* Even for somewhat smaller heaps,    */
                                 /* say half that, collisions may be an */
                                 /* issue because we blacklist          */
@@ -694,6 +711,9 @@ struct hblkhdr {
                                /* 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      */
+                  /* We assume that this is convertible to signed_word  */
+                  /* without generating a negative result.  We avoid    */
+                  /* generating free blocks larger than that.           */
     word hb_descr;             /* object descriptor for marking.  See  */
                                /* mark.h.                              */
 #   ifdef MARK_BIT_PER_OBJ
@@ -776,11 +796,13 @@ struct hblk {
 /* MAX_ROOT_SETS is the maximum number of ranges that can be   */
 /* registered as static roots.                                         */
 # ifdef LARGE_CONFIG
-#   define MAX_ROOT_SETS 4096
+#   define MAX_ROOT_SETS 8192
 # else
-    /* GCJ LOCAL: MAX_ROOT_SETS increased to permit more shared */
-    /* libraries to be loaded.                                  */ 
-#   define MAX_ROOT_SETS 1024
+#   ifdef SMALL_CONFIG
+#     define MAX_ROOT_SETS 512
+#   else
+#     define MAX_ROOT_SETS 2048
+#   endif
 # endif
 
 # define MAX_EXCLUSIONS (MAX_ROOT_SETS/4)
@@ -858,6 +880,11 @@ struct _GC_arrays {
     word _bytes_allocd;
        /* Number of words allocated during this collection cycle */
 # endif
+  word _bytes_dropped;
+       /* Number of black-listed bytes dropped during GC cycle */
+       /* as a result of repeated scanning during allocation   */
+       /* attempts.  These are treated largely as allocated,   */
+       /* even though they are not useful to the client.       */
   word _bytes_finalized;
        /* Approximate number of bytes in objects (and headers) */
        /* That became ready for finalization in the last       */
@@ -972,7 +999,14 @@ struct _GC_arrays {
 # endif
   struct HeapSect {
       ptr_t hs_start; size_t hs_bytes;
-  } _heap_sects[MAX_HEAP_SECTS];
+  } _heap_sects[MAX_HEAP_SECTS];       /* Heap segments potentially    */
+                                       /* client objects.              */
+# if defined(USE_PROC_FOR_LIBRARIES)
+     struct HeapSect _our_memory[MAX_HEAP_SECTS];
+                                       /* All GET_MEM allocated        */
+                                       /* memory.  Includes block      */
+                                       /* headers and the like.        */
+# endif
 # if defined(MSWIN32) || defined(MSWINCE)
     ptr_t _heap_bases[MAX_HEAP_SECTS];
                /* Start address of memory regions obtained from kernel. */
@@ -1028,6 +1062,7 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
 # 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_bytes_dropped GC_arrays._bytes_dropped
 # define GC_bytes_finalized GC_arrays._bytes_finalized
 # define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
 # define GC_bytes_freed GC_arrays._bytes_freed
@@ -1040,6 +1075,9 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
 # define GC_requested_heapsize GC_arrays._requested_heapsize
 # define GC_bytes_allocd_before_gc GC_arrays._bytes_allocd_before_gc
 # define GC_heap_sects GC_arrays._heap_sects
+# ifdef USE_PROC_FOR_LIBRARIES
+#   define GC_our_memory GC_arrays._our_memory
+# endif
 # define GC_last_stack GC_arrays._last_stack
 #ifdef ENABLE_TRACE
 #define GC_trace_addr GC_arrays._trace_addr
@@ -1139,6 +1177,11 @@ GC_API word GC_fo_entries;
 extern word GC_n_heap_sects;   /* Number of separately added heap      */
                                /* sections.                            */
 
+#ifdef USE_PROC_FOR_LIBRARIES
+  extern word GC_n_memory;     /* Number of GET_MEM allocated memory   */
+                               /* sections.                            */
+#endif
+
 extern word GC_page_size;
 
 # if defined(MSWIN32) || defined(MSWINCE)
@@ -1360,6 +1403,9 @@ extern void GC_push_gc_structures(void);
 #      ifdef THREADS
          extern void GC_push_thread_structures (void);
 #      endif
+       extern void (*GC_push_typed_structures) (void);
+                       /* A pointer such that we can avoid linking in  */
+                       /* the typed allocation support if unused.      */
 extern void (*GC_start_call_back) (void);
                        /* Called at start of full collections.         */
                        /* Not called if 0.  Called with allocation     */
@@ -1713,6 +1759,14 @@ GC_API void GC_debug_invoke_finalizer(void * obj, void * data);
                        
 void GC_add_to_heap(struct hblk *p, size_t bytes);
                        /* Add a HBLKSIZE aligned chunk to the heap.    */
+
+#ifdef USE_PROC_FOR_LIBRARIES
+  void GC_add_to_our_memory(ptr_t p, size_t bytes);
+                       /* Add a chunk to GC_our_memory.        */
+                       /* If p == 0, do nothing.               */
+#else
+# define GC_add_to_our_memory(p, bytes)
+#endif
   
 void GC_print_obj(ptr_t p);
                        /* P points to somewhere inside an object with  */
index 532ff8c7119a34fcb7c59d18c9e6a9d2bc117d03..6168e3d6534ca2f0571ac4732ff5f3c24043260d 100644 (file)
 #   endif
 #   define mach_type_known
 # endif
-# if defined(__ia64) && defined(_HPUX_SOURCE)
+# if defined(__ia64) && (defined(_HPUX_SOURCE) || defined(__HP_aCC))
 #   define IA64
 #   ifndef HPUX
 #     define HPUX
  * If STACKBOTTOM is defined, then it's value will be used directly as the
  * stack base.  If LINUX_STACKBOTTOM is defined, then it will be determined
  * with a method appropriate for most Linux systems.  Currently we look
- * first for __libc_stack_end, and if that fails read it from /proc.
+ * first for __libc_stack_end (currently only id USE_LIBC_PRIVATES is
+ * defined), and if that fails read it from /proc.  (If USE_LIBC_PRIVATES
+ * is not defined and NO_PROC_STAT is defined, we revert to HEURISTIC2.)
  * If either of the last two macros are defined, then STACKBOTTOM is computed
  * during collector startup using one of the following two heuristics:
  * HEURISTIC1:  Take an address inside GC_init's frame, and round it up to
 #     define DATAEND (_end)
       extern int __data_start[];
 #     define DATASTART ((ptr_t)(__data_start))
-#     define ALIGNMENT 4
+#     ifdef _MIPS_SZPTR
+#      define CPP_WORDSZ _MIPS_SZPTR
+#      define ALIGNMENT (_MIPS_SZPTR/8)
+#     else
+#      define ALIGNMENT 4
+#     endif
 #     if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2
 #        define LINUX_STACKBOTTOM
 #     else
 #   endif
 # endif
 
+#if defined(LINUX_STACKBOTTOM) && defined(NO_PROC_STAT) \
+    && !defined(USE_LIBC_PRIVATES)
+    /* This combination will fail, since we have no way to get */
+    /* the stack base. Use HEURISTIC2 instead.                 */
+#   undef LINUX_STACKBOTTOM
+#   define HEURISTIC2
+    /* This may still fail on some architectures like IA64.    */
+    /* We tried ...                                            */
+#endif
+
 #if defined(LINUX) && defined(USE_MMAP)
     /* The kernel may do a somewhat better job merging mappings etc.   */
     /* with anonymous mappings.                                                */
     /* 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:                                  */
+    /* This should be avoidable 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.*/
+    /* - Have calloc look at its callers.                              */
     /*   In spite of the fact that it is gross and disgusting.         */
-/* #   define USE_PROC_FOR_LIBRARIES */
+    /* In fact neither seems to suffice, probably in part because      */
+    /* even with USE_PROC_FOR_LIBRARIES, we don't scan parts of stack  */
+    /* segments that appear to be out of bounds.  Thus we actually     */
+    /* do both, which seems to yield the best results.                 */
+
+#   define USE_PROC_FOR_LIBRARIES
 #endif
 
 # ifndef STACK_GROWS_UP
 # if defined(GC_NETBSD_THREADS) && !defined(NETBSD)
        --> inconsistent configuration
 # endif
+# if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD)
+       --> inconsistent configuration
+# endif
 # if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS)
        --> inconsistent configuration
 # endif
index 4c2c5362fbcf422bdf0db0afdcc83dfe12fb35ae..90a246a0eaed384cf3e768f58a6fa5be91152bcc 100644 (file)
@@ -109,7 +109,9 @@ typedef struct thread_local_freelists {
        /* 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))
+                : ((*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES? \
+                      (ABORT("Out of tls"), 0): \
+                      0))
 #   define GC_remove_specific(key)  /* No need for cleanup on thread exit. */
        /* Need TlsFree on process exit/detach ? */
     typedef DWORD GC_key_t;
index 9ff108788d95efd03779497d21cab024aadad119..e68ab4cb11efa41a85f05eb1b96e208443b24a65 100644 (file)
@@ -1,3 +1,47 @@
+2008-02-11 Hans Boehm <Hans.Boehm@hp.com>
+          (Really Ian Wienand & Debian maintainers)
+       * src/atomic_ops/sysdeps/gcc/x86.h
+       (AO_compare_double_and_swap_double_full): Correctly account for
+       ebx usage with PIC.
+
+2008-01-09 Hans Boehm <Hans.Boehm@hp.com>
+       * src/atomic_ops/sysdeps/standard_ao_double_t.h: Let
+       double_ptr_storage default to long long; define everywhere.
+
+2008-01-08 Hans Boehm <Hans.Boehm@hp.com> (Really mostly Joerg Wagner)
+       * src/atomic_ops/sysdeps/msftc/x86.h: Conditionally add
+       compare_double_and_swap_double.
+
+2008-01-06 Hans Boehm <Hans.Boehm@hp.com> (Really mostly Joerg Wagner)
+       * src/atomic_ops/generalize.h: Add test_and_set generalizations,
+       Add AO_double_compare_and_swap generalizations.
+       * src/atomic_ops/sysdeps/armcc/arm_v6.h: New file.
+       * src/atomic_ops/sysdeps/gcc/arm.h: Handle V6 and V7.
+       * src/atomic_ops/sysdeps/gcc/x86.h,
+       src/atomic_ops/sysdeps/{gcc,msftc}/x86_64.h: Conditionally add
+       compare_double_and_swap_double, commented out for msftc.
+       * src/atomic_ops/sysdeps/standard_ao_double_t.h:  Add
+       double_ptr_storage field.
+
+2008-01-03 Hans Boehm <Hans.Boehm@hp.com>
+       (Merge from separate atomic_ops tree)
+       * src/atomic_ops/sysdeps/gcc/x86.h: Define correct macro for
+       double-width cas, and fix its implementation.
+       * doc/README.txt: Clarify use of _full.  Add more warnings about
+       data dependencies.
+
+2008-01-02 Hans Boehm <Hans.Boehm@hp.com>
+       * src/atomic_ops/sysdeps/gcc/powerpc.h (AO_load_acquire): Add
+       %X1 modifier to support indexed addressing.
+
+2007-07-23 Hans Boehm <Hans.Boehm@hp.com> (really Jim Marshall)
+       * src/atomic_ops/sysdeps/msftc/x86.h (_InterlockedExchangeAdd): Define
+       for VC++6.
+
+2007-07-05  Andreas Tobler  <a.tobler@schweiz.org>
+       * src/atomic_ops.h: Check for __powerpc64__ and __ppc64__ to include
+       powerpc.h.
+
 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.
index fa8f07edbf5d75440eac065997a4317c57208f28..e7c2f0d1c5bd4900d727b31dc4c5e8961d6f6d0b 100644 (file)
@@ -154,6 +154,8 @@ _read: Subsequent reads must become visible after reads included in
 _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.
+       AO_store_full or AO_nop_full are the normal ways to force a store
+       to be ordered with respect to a later load.
 _release_write: Ordered with respect to earlier writes.  This is
                normally implemented as either a _write or _release
                barrier.
@@ -163,7 +165,11 @@ _dd_acquire_read: Ordered with respect to later reads that are data
               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.)
+              hard to define precisely.  It should probably be avoided.
+              A major problem is that optimizers tend to try to
+              eliminate dependencies from the generated code, since
+              dependencies force the hardware to execute the code
+              serially.)
 _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
index d27ec7bfdc7f4db5947a5ae6f3bea12db31f25a6..e1b40ca8838824815187b689d6d5b62cb6d6f7a2 100755 (executable)
 # if defined(__m68k__)
 #   include "atomic_ops/sysdeps/gcc/m68k.h"
 # endif /* __m68k__ */
-# if defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)
+# if defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \
+     || defined(__powerpc64__) || defined(__ppc64__)
 #   include "atomic_ops/sysdeps/gcc/powerpc.h"
 # endif /* __powerpc__ */
 # if defined(__arm__) && !defined(AO_USE_PTHREAD_DEFS)
index 0f42b328d1bd6e24176d9b8451b586fd1f2c6102..bfcf2d7ba227a9ee6f47932e82a36a7874bc90c1 100644 (file)
 #  define AO_HAVE_store_full
 #endif
 
+/* NEC LE-IT: Test and set */
+#if defined(AO_HAVE_test_and_set) && \
+       defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_test_and_set_release)
+#      define AO_test_and_set_release(addr) \
+       (AO_nop_full(), AO_test_and_set(addr))
+#  define AO_HAVE_test_and_set_release
+#endif
+
+#if defined(AO_HAVE_test_and_set) && \
+       defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_test_and_set_acquire)
+AO_INLINE AO_TS_t
+AO_test_and_set_acquire(volatile AO_TS_t *addr)
+{
+       AO_TS_t res = AO_test_and_set(addr);
+       AO_nop_full();
+       return res; 
+}  
+#  define AO_HAVE_test_and_set_acquire
+#endif
+
   
 /* Fetch_and_add */
 /* We first try to implement fetch_and_add variants in terms   */
 #    define AO_HAVE_compare_and_swap_double_dd_acquire_read
 #  endif
 #endif
+
+/* NEC LE-IT: Convenience functions for AO_double compare and swap which */
+/* types and reads easier in code                                       */
+#if defined(AO_HAVE_compare_double_and_swap_double_release) && \
+    !defined(AO_HAVE_double_compare_and_swap_release)
+AO_INLINE int
+AO_double_compare_and_swap_release(volatile AO_double_t *addr,
+                                  AO_double_t old_val, AO_double_t new_val) 
+{
+       return AO_compare_double_and_swap_double_release(addr,
+                                                        old_val.AO_val1, old_val.AO_val2,
+                                                        new_val.AO_val1, new_val.AO_val2);
+}
+#define AO_HAVE_double_compare_and_swap_release
+#endif
+
+#if defined(AO_HAVE_compare_double_and_swap_double_acquire) && \
+    !defined(AO_HAVE_double_compare_and_swap_acquire)
+AO_INLINE int
+AO_double_compare_and_swap_acquire(volatile AO_double_t *addr,
+                                  AO_double_t old_val, AO_double_t new_val) 
+{
+       return AO_compare_double_and_swap_double_acquire(addr,
+                                                        old_val.AO_val1, old_val.AO_val2,
+                                                        new_val.AO_val1, new_val.AO_val2);
+}
+#define AO_HAVE_double_compare_and_swap_acquire
+#endif
+
+#if defined(AO_HAVE_compare_double_and_swap_double_full) && \
+    !defined(AO_HAVE_double_compare_and_swap_full)
+AO_INLINE int
+AO_double_compare_and_swap_full(volatile AO_double_t *addr,
+                                        AO_double_t old_val, AO_double_t new_val) 
+{
+       return AO_compare_double_and_swap_double_full(addr,
+                                                     old_val.AO_val1, old_val.AO_val2,
+                                                     new_val.AO_val1, new_val.AO_val2);
+}
+#define AO_HAVE_double_compare_and_swap_full
+#endif
index d1a323216db1c6b7538f9d25b0589f9f664217d3..c502d4d4405367eb9ec917bb485924a2b97cb34f 100644 (file)
  *
  */
 
-/* There exist multiprocessor SoC ARM processors, so this matters.     */
-/* This needs to be augmented for later ARM (e.g. V7) procesors.       */
+#include "../read_ordered.h"
+
+#include "../test_and_set_t_is_ao_t.h" /* Probably suboptimal */
+
+/* NEC LE-IT: ARMv6 is the first architecture providing support for simple LL/SC
+ * A data memory barrier must be raised via CP15 command (see documentation).  
+ *                                                                                                                                                             
+ * ARMv7 is compatible to ARMv6 but has a simpler command for issuing a                
+ * memory barrier (DMB). Raising it via CP15 should still work as told me by the
+ * support engineers. If it turns out to be much quicker than we should implement
+ * custom code for ARMv7 using the asm { dmb } command.                                                                                                                
+ *
+ * If only a single processor is used, we can define AO_UNIPROCESSOR
+ * and do not need to access CP15 for ensuring a DMB  
+*/
+
+/* NEC LE-IT: gcc has no way to easily check the arm architecture
+ * but defines only one of __ARM_ARCH_x__ to be true                   */
+#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_7__)  
+AO_INLINE void
+AO_nop_full()
+{
+#ifndef AO_UNIPROCESSOR
+       /* issue an data memory barrier (keeps ordering of memory transactions  */
+       /* before and after this operation)                                     */
+       unsigned int dest=0;
+       __asm__ __volatile__("mcr p15,0,%0,c7,c10,5" :"=&r"(dest) : : "memory");
+#endif
+}
+
+#define AO_HAVE_nop_full
+
+/* NEC LE-IT: AO_t load is simple reading */
+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
+
+/* NEC LE-IT: atomic "store" - according to ARM documentation this is
+ * the only safe way to set variables also used in LL/SC environment.
+ * A direct write won't be recognized by the LL/SC construct on the _same_ CPU.
+ * Support engineers response for behaviour of ARMv6:
+ * 
+   Core1        Core2          SUCCESS
+   ===================================
+   LDREX(x)
+   STREX(x)                    Yes
+   -----------------------------------
+   LDREX(x)
+                STR(x)
+   STREX(x)                    No
+   -----------------------------------
+   LDREX(x)
+   STR(x)
+   STREX(x)                    Yes
+   -----------------------------------
+   
+ * ARMv7 behaves similar, see documentation CortexA8 TRM, point 8.5  
+ *
+ * HB: I think this is only a problem if interrupt handlers do not clear
+ * the reservation, as they almost certainly should.  Probably change this back
+ * in a while?
+*/
+AO_INLINE void AO_store(volatile AO_t *addr, AO_t value)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__("@AO_store\n"
+"1:    ldrex   %0, [%1]\n"
+"      strex   %0, %2, [%1]\n"
+"      teq     %0, #0\n"
+"      bne     1b"
+       : "=&r"(tmp)
+       : "r" (addr), "r"(value)
+       : "cc","memory");
+}
+#define AO_HAVE_store
+
+/* NEC LE-IT: replace the SWAP as recommended by ARM:
+
+   "Applies to: ARM11 Cores
+       Though the SWP instruction will still work with ARM V6 cores, it is
+       recommended     to use the new V6 synchronization instructions. The SWP
+       instruction produces â€˜locked’ read and write accesses which are atomic,
+       i.e. another operation cannot be done between these locked accesses which
+       ties up external bus (AHB,AXI) bandwidth and can increase worst case 
+       interrupt latencies. LDREX,STREX are more flexible, other instructions can
+       be done between the LDREX and STREX accesses. 
+   "
+*/
+AO_INLINE AO_TS_t
+AO_test_and_set(volatile AO_TS_t *addr) {
+       
+       AO_TS_t oldval;
+       unsigned long tmp;
+
+       __asm__ __volatile__("@AO_test_and_set\n"
+"1:    ldrex   %0, [%2]\n"
+"      strex   %1, %3, [%2]\n"
+"      teq     %1, #0\n"
+"      bne     1b\n"
+       : "=&r"(oldval),"=&r"(tmp)
+       : "r"(addr), "r"(1)
+       : "memory","cc");
+
+       return oldval;
+}
+
+#define AO_HAVE_test_and_set
+
+/* NEC LE-IT: fetch and add for ARMv6 */
+AO_INLINE AO_t
+AO_fetch_and_add(volatile AO_t *p, AO_t incr)
+{
+       unsigned long tmp,tmp2;
+       AO_t result;
+
+       __asm__ __volatile__("@AO_fetch_and_add\n"
+"1:    ldrex   %0, [%4]\n"                     /* get original                   */
+"      add     %2, %3, %0\n"           /* sum up */
+"      strex   %1, %2, [%4]\n"         /* store them */
+"      teq     %1, #0\n"
+"      bne     1b\n"
+       : "=&r"(result),"=&r"(tmp),"=&r"(tmp2)
+       : "r"(incr), "r"(p)
+       : "cc","memory");
+
+       return result;
+}
+
+#define AO_HAVE_fetch_and_add
+
+/* NEC LE-IT: fetch and add1 for ARMv6 */
+AO_INLINE AO_t
+AO_fetch_and_add1(volatile AO_t *p)
+{
+       unsigned long tmp,tmp2;
+       AO_t result;
+
+       __asm__ __volatile__("@AO_fetch_and_add1\n"
+"1:    ldrex   %0, [%3]\n"                     /* get original   */
+"      add     %1, %0, #1\n"           /* increment */
+"      strex   %2, %1, [%3]\n"         /* store them */
+"      teq     %2, #0\n"
+"      bne     1b\n"
+       : "=&r"(result), "=&r"(tmp), "=&r"(tmp2)
+       : "r"(p)
+       : "cc","memory");
+
+       return result;
+}
+
+#define AO_HAVE_fetch_and_add1
+
+/* NEC LE-IT: fetch and sub for ARMv6 */
+AO_INLINE AO_t
+AO_fetch_and_sub1(volatile AO_t *p)
+{
+       unsigned long tmp,tmp2;
+       AO_t result;
+
+       __asm__ __volatile__("@ AO_fetch_and_sub1\n"
+"1:    ldrex   %0, [%3]\n"                     /* get original   */
+"      sub     %1, %0, #1\n"           /* increment */
+"      strex   %2, %1, [%3]\n"         /* store them */
+"      teq     %2, #0\n"
+"      bne     1b\n"
+       : "=&r"(result), "=&r"(tmp), "=&r"(tmp2)
+       : "r"(p)
+       : "cc","memory");
+
+       return result;
+}
+
+#define AO_HAVE_fetch_and_sub1
 
+/* NEC LE-IT: compare and swap */
+/* Returns nonzero if the comparison succeeded. */
+AO_INLINE int
+AO_compare_and_swap(volatile AO_t *addr,
+                               AO_t old_val, AO_t new_val) 
+{
+        AO_t result,tmp;
+
+       __asm__ __volatile__("@ AO_compare_and_swap\n"
+"1:    ldrex   %1, [%2]\n"                     /* get original */
+"      mov             %0, #2\n"                       /* store a flag */
+"      teq             %1, %3\n"                       /* see if match */
+"      strexeq %0, %4, [%2]\n"         /* store new one if matched */
+"      teq             %0, #1\n"
+"      beq             1b\n"                           /* if update failed, repeat */
+"      eor             %0, %0, #2\n"           /* if succeded, return 2, else 0 */
+       : "=&r"(result), "=&r"(tmp)
+       : "r"(addr), "r"(old_val), "r"(new_val)
+       : "cc","memory");
+
+       return (result>>1);
+}
+#define AO_HAVE_compare_and_swap
+
+#else
+/* pre ARMv6 architecures ... */
 /* 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;
@@ -48,5 +247,4 @@ AO_test_and_set_full(volatile AO_TS_t *addr) {
 
 #define AO_HAVE_test_and_set_full
 
-
-
+#endif // __ARM_ARCH_x
index a014a7b5248e472f0e468b3c8ad527eb1de6344f..799722aa37c8ee888a6a5380b70fa447c7a3e356 100644 (file)
@@ -92,7 +92,7 @@ AO_load_acquire(volatile AO_t *addr)
   /* registers.  I always got "impossible constraint" when I   */
   /* tried the "y" constraint.                                 */
   __asm__ __volatile__ (
-    "lwz %0,%1\n"
+    "lwz%X1 %0,%1\n"
     "cmpw cr7,%0,%0\n"
     "bne- cr7,1f\n"
     "1: isync\n"
index 27e047e580231adfb5666b89f66b2109c1bafd16..96fd2cb66dd2c77bf43e4784cf50b00610360441 100644 (file)
@@ -141,13 +141,30 @@ AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
                                       AO_t new_val1, AO_t new_val2) 
 {
   char result;
-  __asm__ __volatile__("lock; cmpxchg8b %0; setz %1"
+  #if __PIC__
+  /* If PIC is turned on, we can't use %ebx as it is reserved for the
+     GOT poiner.  We can save and restore %ebx because GCC won't be
+     using it for anything else (such as any of the m operands) */
+  __asm__ __volatile__("pushl %%ebx;"   /* save ebx used for PIC GOT ptr */
+                      "movl %6,%%ebx;" /* move new_val2 to %ebx */
+                      "lock; cmpxchg8b %0; setz %1;"
+                      "pop %%ebx;"     /* restore %ebx */
+                      : "=m"(*addr), "=q"(result)
+                      : "m"(*addr), "d" (old_val2), "a" (old_val1),
+                        "c" (new_val2), "m" (new_val1) : "memory");
+  #else
+  /* We can't just do the same thing in non-PIC mode, because GCC
+   * might be using %ebx as the memory operand.  We could have ifdef'd
+   * in a clobber, but there's no point doing the push/pop if we don't
+   * have to. */
+  __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");
+                      : "m"(*addr), "d" (old_val2), "a" (old_val1),
+                        "c" (new_val2), "b" (new_val1) : "memory");
+  #endif
   return (int) result;
 }
 
-#define AO_HAVE_double_compare_and_swap_full
+#define AO_HAVE_compare_double_and_swap_double_full
 
 #include "../ao_t_is_int.h"
index 75c2448cf1a2846dcad370b3d9c2032a7bede39d..91e99e62040394e7fa122f55fc1e3c579c8530e0 100644 (file)
@@ -34,6 +34,8 @@
 
 #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()
@@ -133,7 +135,7 @@ AO_test_and_set_full(volatile AO_TS_t *addr)
 /* 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) 
+                        AO_t old, AO_t new_val) 
 {
   char result;
   __asm__ __volatile__("lock; cmpxchgq %3, %0; setz %1"
@@ -144,4 +146,50 @@ AO_compare_and_swap_full(volatile AO_t *addr,
 
 #define AO_HAVE_compare_and_swap_full
 
-/* FIXME: The Intel version has a 16byte CAS instruction.      */
+#ifdef AO_CMPXCHG16B_AVAILABLE
+/* NEC LE-IT: older AMD Opterons are missing this instruction.
+ * On these machines SIGILL will be thrown. Define AO_CASDOUBLE_MISSING
+ * to have an emulated (lock based) version available */ 
+/* HB: Changed this to not define either by default.  There are
+ * enough machines and tool chains around on which cmpxchg16b
+ * doesn't work.  And the emulation is unsafe by our usual rules.
+ * Hoewever both are clearly useful in certain cases.
+ */
+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; cmpxchg16b %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_compare_double_and_swap_double_full
+#else
+/* this one provides spinlock based emulation of CAS implemented in    */
+/* atomic_ops.c.  We probably do not want to do this here, since it is  */
+/* not attomic with respect to other kinds of updates of *addr.  On the */
+/* other hand, this may be a useful facility on occasion.              */
+#ifdef AO_WEAK_DOUBLE_CAS_EMULATION
+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_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)
+{
+       return AO_compare_double_and_swap_double_emulation(addr,
+                                                          old_val1, old_val2,
+                                                          new_val1, new_val2);
+}
+#define AO_HAVE_compare_double_and_swap_double_full
+#endif /* AO_WEAK_DOUBLE_CAS_EMULATION */
+#endif /* AO_CMPXCHG16B_AVAILABLE */
index ad444580f1eeb645800e25e4eb58fd9cac6ea2be..81c67a115932fb717e083fa5e3c26c30d5a83ca1 100644 (file)
  * SOFTWARE. 
  */
 
-/* The following really assume we have a 486 or better. */
+/* The following really assume we have a 486 or better.                */
 /* If ASSUME_WINDOWS98 is defined, we assume Windows 98 or newer.      */
+/* If ASSUME_VISTA is defined, we assume Windows Server 2003, Vista    */
+/* or later.                                                           */
 
 #include "../all_aligned_atomic_load_store.h"
 
@@ -45,6 +47,7 @@
 #define _InterlockedIncrement       InterlockedIncrement
 #define _InterlockedDecrement       InterlockedDecrement
 #define _InterlockedExchange        InterlockedExchange 
+#define _InterlockedExchangeAdd     InterlockedExchangeAdd
 #define _InterlockedCompareExchange InterlockedCompareExchange
 
 #else
@@ -159,4 +162,36 @@ AO_compare_and_swap_full(volatile AO_t *addr,
 #  error wrong architecture
 #endif
 
+#ifdef ASSUME_VISTA
+/* NEC LE-IT: whenever we run on a pentium class machine we have that
+ * certain function */
+
+#include "../standard_ao_double_t.h"
+#pragma intrinsic (_InterlockedCompareExchange64)
+/* Returns nonzero if the comparison succeeded. */
+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) 
+{
+    __int64 oldv = (__int64)old_val2 | ((__int64)old_val1 << 32);
+    __int64 newv = (__int64)new_val2 | ((__int64)new_val1 << 32);
+    return _InterlockedCompareExchange64((__int64 volatile *)addr,
+                                       newv, oldv) == oldv;
+}
+#define AO_HAVE_compare_double_and_swap_double_full
+
+#ifdef __cplusplus
+AO_INLINE int
+AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
+                                      AO_double_t old_val,
+                                      AO_double_t new_val) 
+{
+    return _InterlockedCompareExchange64((__int64 volatile *)addr,
+               new_val.AO_whole, old_val.AO_whole) == old_val.AO_whole;
+}
+#define AO_HAVE_double_compare_and_swap_full
+#endif // __cplusplus
+#endif /* ASSUME_VISTA */
+
 #include "../ao_t_is_int.h"
index 7f0b647269467dfae9e84b69ebb19a6cd93b78b1..ca1a682e1e64eb7a6cbcbb0e2f464b26586e59a6 100644 (file)
@@ -152,5 +152,35 @@ AO_test_and_set_full(volatile AO_TS_t *addr)
 }
 
 #define AO_HAVE_test_and_set_full
-#endif
+
+FIXME: (__asm not supported)
+NEC LE-IT: Don't have a working Win64 environment here at the moment.
+AO_compare_double_and_swap_double_full needs implementation for Win64
+But there is no _InterlockedCompareExchange128 in the WinAPI, so we
+need basically whats given below.
+Also see gcc/x86_64.h for partial old opteron workaround:
+
+#ifndef AO_CASDOUBLE_MISSING
+
+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
+       {
+               mov     rdx,QWORD PTR [old_val]
+               mov     rax,QWORD PTR [old_val + 8]
+               mov     rcx,QWORD PTR [new_val]
+               mov     rbx,QWORD PTR [new_val + 8]
+               lock cmpxchg16b [addr]
+               setz result;
+       }
+       return result;
+}
+#endif // AO_CASDOUBLE_MISSING
+#define AO_HAVE_compare_double_and_swap_double_full
+
+#endif /* 0 */
 
index 1d08fc7fd390dcbb8cd20a71961be15fd5b5a04b..22e8160c86358714a8fe32494a08edb241dd6722 100644 (file)
@@ -1,8 +1,36 @@
+/* NEC LE-IT: For 64Bit OS we extend the double type to hold two int64's
+*      
+*  x86-64: __m128 serves as placeholder which also requires the compiler
+*         to align     it on 16 byte boundary (as required by cmpxchg16.
+* Similar things could be done for PowerPC 64bit using a VMX data type...      */
+
+#if defined(__GNUC__)
+# if defined(__x86_64__)
+# include<xmmintrin.h>
+   typedef __m128 double_ptr_storage;
+#  define AO_HAVE_DOUBLE_PTR_STORAGE
+# endif /* __x86_64__ */
+#endif
+
+#ifdef _MSC_VER
+# ifdef _WIN64
+   typedef __m128 double_ptr_storage;
+#  define AO_HAVE_DOUBLE_PTR_STORAGE
+# elif _WIN32
+   typedef unsigned __int64 double_ptr_storage;
+#  define AO_HAVE_DOUBLE_PTR_STORAGE
+# endif
+#endif
+
+#ifndef AO_HAVE_DOUBLE_PTR_STORAGE
+   typedef unsigned long long double_ptr_storage;
+#endif
+
 typedef union {
-    unsigned long long AO_whole;
+    double_ptr_storage 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
-
index 247afb3ad6df7298670f16445ac5362695262d8f..b9a4d1f12ca670b972fdf845ed81e5837e626257 100644 (file)
@@ -177,7 +177,8 @@ void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
 
 #   if defined(HAVE_PUSH_REGS)
       GC_push_regs();
-#   elif defined(UNIX_LIKE) && !defined(DARWIN) && !defined(ARM32)
+#   elif defined(UNIX_LIKE) && !defined(DARWIN) && !defined(ARM32) && \
+        !defined(HURD)
       /* Older versions of Darwin seem to lack getcontext(). */
       /* ARM Linux often doesn't support a real getcontext(). */
       ucontext_t ctxt;
@@ -222,6 +223,8 @@ void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
          /* _setjmp won't, but is less portable.               */
 #       endif
 #   endif /* !HAVE_PUSH_REGS ... */
+    /* FIXME: context here is sometimes just zero.  At the moment the callees  */
+    /* don't really need it.                                                   */
     fn(arg, context);
     /* Strongly discourage the compiler from treating the above        */
     /* as a tail-call, since that would pop the register       */
index a6baa6342b2c397998cc04dee6caef40b1de132f..0469f3bf0b9e0174cefd217dd6560d5775c8367a 100644 (file)
@@ -320,7 +320,7 @@ void * malloc(size_t lb)
     return((void *)REDIRECT_MALLOC(lb));
   }
 
-#ifdef GC_LINUX_THREADS
+#if defined(GC_LINUX_THREADS) /* && !defined(USE_PROC_FOR_LIBRARIES) */
   static ptr_t GC_libpthread_start = 0;
   static ptr_t GC_libpthread_end = 0;
   static ptr_t GC_libld_start = 0;
@@ -331,17 +331,15 @@ void * malloc(size_t lb)
   void GC_init_lib_bounds(void)
   {
     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)) {
+    if (!GC_text_mapping("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)) {
+    if (!GC_text_mapping("ld-", &GC_libld_start, &GC_libld_end)) {
        WARN("Failed to find ld.so text mapping: Expect crash\n", 0);
     }
   }
@@ -349,7 +347,7 @@ void * malloc(size_t lb)
 
 void * calloc(size_t n, size_t lb)
 {
-#   if defined(GC_LINUX_THREADS) && !defined(USE_PROC_FOR_LIBRARIES)
+#   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.      */
        {
@@ -407,11 +405,13 @@ void GC_free(void * p)
 
     if (p == 0) return;
        /* Required by ANSI.  It's not my fault ...     */
+#   ifdef LOG_ALLOCS
+      GC_err_printf("GC_free(%p): %d\n", p, GC_gc_no);
+#   endif
     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(MSWIN32))
@@ -421,6 +421,7 @@ void GC_free(void * p)
        /* Don't try to deallocate that memory.                         */
        if (0 == hhdr) return;
 #   endif
+    GC_ASSERT(GC_base(p) == p);
     knd = hhdr -> hb_obj_kind;
     ok = &GC_obj_kinds[knd];
     if (EXPECT((ngranules <= MAXOBJGRANULES), 1)) {
@@ -438,9 +439,13 @@ void GC_free(void * p)
        *flh = (ptr_t)p;
        UNLOCK();
     } else {
+        size_t nblocks = OBJ_SZ_TO_BLOCKS(sz);
         LOCK();
         GC_bytes_freed += sz;
        if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
+       if (nblocks > 1) {
+         GC_large_allocd_bytes -= nblocks * HBLKSIZE;
+       }  
         GC_freehblk(h);
         UNLOCK();
     }
@@ -477,8 +482,12 @@ void GC_free_inner(void * p)
        obj_link(p) = *flh;
        *flh = (ptr_t)p;
     } else {
+        size_t nblocks = OBJ_SZ_TO_BLOCKS(sz);
         GC_bytes_freed += sz;
        if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
+       if (nblocks > 1) {
+         GC_large_allocd_bytes -= nblocks * HBLKSIZE;
+       }
         GC_freehblk(h);
     }
 }
@@ -498,7 +507,8 @@ void GC_free_inner(void * p)
          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) {
+         if (caller >= GC_libpthread_start && caller < GC_libpthread_end
+             || (caller >= GC_libld_start && caller < GC_libld_end)) {
            GC_free(p);
            return;
          }
index 838fef1fca6fdd6e818ef151ab45666aefc1b9fc..a34c941e12c8cb8b948645291146da6ed7e6e863 100644 (file)
@@ -753,8 +753,8 @@ mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack, mse *mark_stack_limit)
                continue;
            }
             descr = *(word *)(type_descr
-                             - (descr - (GC_DS_PER_OBJECT
-                                         - GC_INDIR_PER_OBJ_BIAS)));
+                             - (descr + (GC_INDIR_PER_OBJ_BIAS
+                                         - GC_DS_PER_OBJECT)));
          }
          if (0 == descr) {
              /* Can happen either because we generated a 0 descriptor  */
@@ -1799,7 +1799,8 @@ GC_bool GC_block_was_dirty(struct hblk *h, hdr *hhdr)
 }
 #endif /* SMALL_CONFIG */
 
-/* Similar to GC_push_next_marked, but return address of next block    */
+/* Similar to GC_push_marked, but skip over unallocated blocks */
+/* and return address of next plausible block.                 */
 struct hblk * GC_push_next_marked(struct hblk *h)
 {
     hdr * hhdr = HDR(h);
index c85d931ff86becf2dcf492d66252cedd88ddf9dc..7cdaf37ab6baff73a10a9ca323fad2905c1c6c11 100644 (file)
@@ -299,7 +299,7 @@ void GC_remove_tmp_roots(void)
             GC_remove_root_at_pos(i);
        } else {
            i++;
-    }
+       }
     }
     #if !defined(MSWIN32) && !defined(MSWINCE)
     GC_rebuild_root_index();
@@ -514,6 +514,8 @@ void GC_push_current_stack(ptr_t cold_gc_frame, void * context)
 #   endif /* !THREADS */
 }
 
+void (*GC_push_typed_structures) (void) = NULL;
+
 /*
  * Push GC internal roots.  Only called if there is some reason to believe
  * these would not otherwise get registered.
@@ -524,6 +526,8 @@ void GC_push_gc_structures(void)
 #   if defined(THREADS)
       GC_push_thread_structures();
 #   endif
+    if( GC_push_typed_structures )
+      GC_push_typed_structures();
 }
 
 #ifdef THREAD_LOCAL_ALLOC
index a556f9573cc9edc8fa7082052a9849eff31dd2c4..70ea201843719342d975d81dae82e9477b7eab7c 100755 (executable)
@@ -406,46 +406,12 @@ GC_bool GC_is_initialized = FALSE;
   extern void GC_init_parallel(void);
 # endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
 
+/* FIXME: The GC_init/GC_init_inner distinction should go away. */
 void GC_init(void)
 {
-    DCL_LOCK_STATE;
-    
-#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
-    if (!GC_is_initialized) {
-      BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
-      HMODULE hK32 = GetModuleHandleA("kernel32.dll");
-      if (hK32)
-         pfn = (BOOL (WINAPI *) (LPCRITICAL_SECTION, DWORD))
-               GetProcAddress (hK32,
-                               "InitializeCriticalSectionAndSpinCount");
-      if (pfn)
-          pfn(&GC_allocate_ml, 4000);
-      else
-         InitializeCriticalSection (&GC_allocate_ml);
-    }
-#endif /* MSWIN32 */
-
-    LOCK();
+    /* LOCK(); -- no longer does anything this early. */
     GC_init_inner();
-    UNLOCK();
-
-#   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();                       */
-        {
-         GC_init_parallel();
-       }
-#   endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
-
-#   if defined(DYNAMIC_LOADING) && defined(DARWIN)
-    {
-        /* This must be called WITHOUT the allocation lock held
-        and before any threads are created */
-        extern void GC_init_dyld();
-        GC_init_dyld();
-    }
-#   endif
+    /* UNLOCK(); */
 }
 
 #if defined(MSWIN32) || defined(MSWINCE)
@@ -458,7 +424,6 @@ void GC_init(void)
 
 extern void GC_setpagesize();
 
-
 #ifdef MSWIN32
 extern GC_bool GC_no_win32_dlls;
 #else
@@ -503,6 +468,10 @@ static void maybe_install_looping_handler()
 
 #endif
 
+#if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
+  void GC_thr_init(void);
+#endif
+
 void GC_init_inner()
 {
 #   if !defined(THREADS) && defined(GC_ASSERTIONS)
@@ -511,6 +480,30 @@ void GC_init_inner()
     word initial_heap_sz = (word)MINHINCR;
     
     if (GC_is_initialized) return;
+
+    /* Note that although we are nominally called with the */
+    /* allocation lock held, the allocation lock is now           */
+    /* only really acquired once a second thread is forked.*/
+    /* And the initialization code needs to run before     */
+    /* then.  Thus we really don't hold any locks, and can */
+    /* in fact safely initialize them here.               */
+#   ifdef THREADS
+      GC_ASSERT(!GC_need_to_lock);
+#   endif
+#   if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
+      if (!GC_is_initialized) {
+        BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
+        HMODULE hK32 = GetModuleHandleA("kernel32.dll");
+        if (hK32)
+         pfn = (BOOL (WINAPI *) (LPCRITICAL_SECTION, DWORD))
+               GetProcAddress (hK32,
+                               "InitializeCriticalSectionAndSpinCount");
+        if (pfn)
+            pfn(&GC_allocate_ml, 4000);
+        else
+         InitializeCriticalSection (&GC_allocate_ml);
+      }
+#endif /* MSWIN32 */
 #   if defined(MSWIN32) || defined(MSWINCE)
       InitializeCriticalSection(&GC_write_cs);
 #   endif
@@ -743,12 +736,6 @@ void GC_init_inner()
       if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
 #   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
@@ -766,6 +753,26 @@ void GC_init_inner()
                   GC_register_finalizer_no_order);
       }
 #   endif
+
+    /* The rest of this again assumes we don't really hold     */
+    /* the allocation lock.                                    */
+#   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();                       */
+        {
+         GC_init_parallel();
+       }
+#   endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
+
+#   if defined(DYNAMIC_LOADING) && defined(DARWIN)
+    {
+        /* This must be called WITHOUT the allocation lock held
+        and before any threads are created */
+        extern void GC_init_dyld();
+        GC_init_dyld();
+    }
+#   endif
 }
 
 void GC_enable_incremental(void)
@@ -1145,7 +1152,7 @@ unsigned GC_new_proc(GC_mark_proc proc)
     return result;
 }
 
-void * GC_call_with_stack_base(GC_stack_base_func fn, void *arg)
+GC_API void * GC_call_with_stack_base(GC_stack_base_func fn, void *arg)
 {
     int dummy;
     struct GC_stack_base base;
index b172025ba532ec202f8f02589f404a883090e919..2420a44b87f54f7a99fbca1e837df48ca9000af2 100644 (file)
@@ -77,7 +77,12 @@ static ULONG_ADDR CALLBACK GetModuleBase(HANDLE hProcess, ULONG_ADDR dwAddress)
                // Save and restore current directory around SymLoadModule, see KB article Q189780
                GetCurrentDirectoryA(sizeof(curDir), curDir);
                GetModuleFileNameA(NULL, exePath, sizeof(exePath));
+#if defined(_MSC_VER) && _MSC_VER == 1200
+               /* use strcat for VC6 */
+               strcat(exePath, "\\..");
+#else
                strcat_s(exePath, sizeof(exePath), "\\..");
+#endif /* _MSC_VER >= 1200 */
                SetCurrentDirectoryA(exePath);
 #ifdef _DEBUG
                GetCurrentDirectoryA(sizeof(exePath), exePath);
index 080f16a263ae127d7e3fab9470daf0296c1a449f..65fbcaf7bf80ededa6e37367f7b3a63da29ee272 100644 (file)
@@ -62,7 +62,7 @@ GC_bool GC_add_map_entry(size_t granules)
     new_map = (short *)GC_scratch_alloc(MAP_LEN * sizeof(short));
     if (new_map == 0) return(FALSE);
     if (GC_print_stats)
-        GC_printf("Adding block map for size of %u granules (%u bytes)\n",
+        GC_log_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++) {
index 7d9c721367ce6efb3ca5fbc2a9d879039c76af68..5aa41f3e7186e44fab9e249b976c1a5dbc4c5852 100644 (file)
@@ -375,7 +375,9 @@ GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp)
   return FALSE;
 }
 
-/* Find the text(code) mapping for the library whose name starts with nm. */
+#if defined(REDIRECT_MALLOC)
+/* Find the text(code) mapping for the library whose name, after       */
+/* stripping the directory part, starts with nm.                       */
 GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp)
 {
   size_t nm_len = strlen(nm);
@@ -392,15 +394,22 @@ GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp)
                                 &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) {
+    if (prot[0] == 'r' && prot[1] == '-' && prot[2] == 'x') {
+       char *p = map_path;
+       /* Set p to point just past last slash, if any. */
+         while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t') ++p;
+         while (*p != '/' && p >= map_path) --p;
+         ++p;
+       if (strncmp(nm, p, nm_len) == 0) {
          *startp = my_start;
          *endp = my_end;
          return TRUE;
+       }
     }
   }
   return FALSE;
 }
+#endif /* REDIRECT_MALLOC */
 
 #ifdef IA64
 static ptr_t backing_store_base_from_proc(void)
@@ -745,7 +754,7 @@ word GC_get_writable_length(ptr_t p, ptr_t *base)
     return(buf.RegionSize);
 }
 
-int GC_get_stack_base(struct GC_stack_base *sb)
+GC_API int GC_get_stack_base(struct GC_stack_base *sb)
 {
     int dummy;
     ptr_t sp = (ptr_t)(&dummy);
@@ -1530,12 +1539,6 @@ void GC_register_data_segments(void)
      unsigned i;
      
 #    ifndef REDIRECT_MALLOC
-       static word last_gc_no = (word)(-1);
-     
-       if (last_gc_no != GC_gc_no) {
-        GC_add_current_malloc_heap();
-        last_gc_no = GC_gc_no;
-       }
        if (GC_root_size > GC_max_root_size) GC_max_root_size = GC_root_size;
        if (GC_is_malloc_heap_base(p)) return TRUE;
 #    endif
@@ -1952,7 +1955,7 @@ ptr_t GC_win32_get_mem(word bytes)
        /* If I read the documentation correctly, this can      */
        /* only happen if HBLKSIZE > 64k or not a power of 2.   */
     if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
-    GC_heap_bases[GC_n_heap_bases++] = result;
+    if (0 != result) GC_heap_bases[GC_n_heap_bases++] = result;
     return(result);                      
 }
 
index 546dc0cc15f9580fb04ee4969a59d532f9efd5a2..85fa531cb193f6b1f53d2bc0fa6a60792641d5d8 100644 (file)
@@ -119,7 +119,11 @@ void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
 /* int cacao_suspendhandler(void *); */
 
 #if defined(IA64) || defined(HP_PA) || defined(M68K)
+#ifdef SA_SIGINFO
 void GC_suspend_handler(int sig, siginfo_t *info, void *context)
+#else
+void GC_suspend_handler(int sig)
+#endif
 {
   int old_errno = errno;
   GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
@@ -128,9 +132,16 @@ void GC_suspend_handler(int sig, siginfo_t *info, void *context)
 #else
 /* We believe that in all other cases the full context is already      */
 /* in the signal handler frame.                                                */
+#ifdef SA_SIGINFO
 void GC_suspend_handler(int sig, siginfo_t *info, void *context)
+#else
+void GC_suspend_handler(int sig)
+#endif
 {
   int old_errno = errno;
+# ifndef SA_SIGINFO
+    void *context = 0;
+# endif
   GC_suspend_handler_inner((ptr_t)(word)sig, context);
   errno = old_errno;
 }
@@ -484,8 +495,8 @@ void GC_start_world()
       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_printf("sem_wait() returned %d\n",
+                              code);
                ABORT("sem_wait() for restart handler failed");
            }
 #    endif
@@ -504,19 +515,29 @@ void GC_stop_init() {
        ABORT("sem_init failed");
 #   endif
 
-    act.sa_flags = SA_RESTART | SA_SIGINFO;
+    act.sa_flags = SA_RESTART
+#   ifdef SA_SIGINFO
+       | SA_SIGINFO
+#   endif
+       ;
     if (sigfillset(&act.sa_mask) != 0) {
        ABORT("sigfillset() failed");
     }
     GC_remove_allowed_signals(&act.sa_mask);
     /* SIG_THR_RESTART is set in the resulting mask.           */
     /* It is unmasked by the handler when necessary.           */
+#   ifdef SA_SIGINFO
     act.sa_sigaction = GC_suspend_handler;
+#   else
+    act.sa_handler = GC_suspend_handler;
+#   endif
     if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
        ABORT("Cannot set SIG_SUSPEND handler");
     }
 
+#   ifdef SA_SIGINFO
     act.sa_flags &= ~ SA_SIGINFO;
+#   endif
     act.sa_handler = GC_restart_handler;
     if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
        ABORT("Cannot set SIG_THR_RESTART handler");
index 098a3c1880fc185209cb5883f6767bd447b68cf0..497defac85abf9fa56a59dc0907017f2f224eb51 100644 (file)
@@ -155,7 +155,7 @@ unsigned long GC_lock_holder = NO_THREAD;
 #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.   */
+/* generate references 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);
@@ -730,7 +730,7 @@ void GC_thr_init(void)
 #   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      */
+      /* of a thread local variable.  This should include thread       */
       /* locals for the main thread, except for those allocated                */
       /* in response to dlopen calls.                                  */  
        {
@@ -765,7 +765,7 @@ void GC_thr_init(void)
          GC_nprocs = pthread_num_processors_np();
 #       endif
 #      if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \
-          || defined(GC_SOLARIS_THREADS)
+          || defined(GC_SOLARIS_THREADS) || defined(GC_GNU_THREADS)
          GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
          if (GC_nprocs <= 0) GC_nprocs = 1;
 #      endif
@@ -785,9 +785,6 @@ void GC_thr_init(void)
 #      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);
index dd3645dd47c79b29ebc3245dd90bb047ba5a12f9..8d679d440cf5bcc1bff39277b1a9a2e7ae8d6493 100644 (file)
@@ -21,6 +21,8 @@
 
 signed_word GC_bytes_found = 0;
                        /* Number of bytes of memory reclaimed     */
+                       /* minus the number of bytes originally    */
+                       /* on free lists which we had to drop.     */
 
 #if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
   word GC_fl_builder_count = 0;
index a7a7cd013d761529e7788d12bb99b28fe8d838d6..8b188085c2cf1b3c3d73ec8b5e4ab5d105827840 100644 (file)
 
 # if defined(MSWIN32) || defined(MSWINCE)
 #   include <windows.h>
+#   ifdef GC_DLL
+#     define GC_print_stats 0   /* Not exported from DLL */
+                               /* Redefine to 1 to generate output. */
+#   endif
 # endif
 
 # ifdef PCR
 # include <stdarg.h>
 #endif
 
+/* Call GC_INIT only on platforms on which we think we really need it, */
+/* so that we can test automatic initialization on the rest.           */
+#if defined(CYGWIN32) || defined (AIX) || defined(DARWIN)
+#  define GC_COND_INIT() GC_INIT()
+#else
+#  define GC_COND_INIT()
+#endif
 
 /* Allocation Statistics */
 int stubborn_count = 0;
@@ -1018,17 +1029,23 @@ static void uniq(void *p, ...) {
 void run_one_test()
 {
     char *x;
+    char **z;
 #   ifdef LINT
        char *y = 0;
 #   else
        char *y = (char *)(size_t)fail_proc1;
 #   endif
+    CLOCK_TYPE start_time;
+    CLOCK_TYPE reverse_time;
+    CLOCK_TYPE typed_time;
+    CLOCK_TYPE tree_time;
+    unsigned long time_diff;
     DCL_LOCK_STATE;
     
 #   ifdef FIND_LEAK
-       (void)GC_printf(
+       GC_printf(
                "This test program is not designed for leak detection mode\n");
-       (void)GC_printf("Expect lots of problems.\n");
+       GC_printf("Expect lots of problems.\n");
 #   endif
     GC_FREE(0);
 #   ifndef DBG_HDRS_ALL
@@ -1036,56 +1053,62 @@ void run_one_test()
       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_printf("GC_size produced unexpected results\n");
+           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_printf("GC_malloc(0) failed: GC_size returns %ld\n",
+       GC_printf("GC_malloc(0) failed: GC_size returns %ld\n",
                        (unsigned long)GC_size(GC_malloc(0)));
-           FAIL;
+       FAIL;
       }
       collectable_count += 1;
       if (GC_size(GC_malloc_uncollectable(0)) != MIN_WORDS * sizeof(GC_word)) {
-       (void)GC_printf("GC_malloc_uncollectable(0) failed\n");
-           FAIL;
+       GC_printf("GC_malloc_uncollectable(0) failed\n");
+       FAIL;
       }
       GC_is_valid_displacement_print_proc = fail_proc1;
       GC_is_visible_print_proc = fail_proc1;
       collectable_count += 1;
       x = GC_malloc(16);
       if (GC_base(x + 13) != x) {
-       (void)GC_printf("GC_base(heap ptr) produced incorrect result\n");
+       GC_printf("GC_base(heap ptr) produced incorrect result\n");
        FAIL;
       }
 #     ifndef PCR
         if (GC_base(y) != 0) {
-         (void)GC_printf("GC_base(fn_ptr) produced incorrect result\n");
+         GC_printf("GC_base(fn_ptr) produced incorrect result\n");
          FAIL;
         }
 #     endif
       if (GC_same_obj(x+5, x) != x + 5) {
-       (void)GC_printf("GC_same_obj produced incorrect result\n");
+       GC_printf("GC_same_obj produced incorrect result\n");
        FAIL;
       }
       if (GC_is_visible(y) != y || GC_is_visible(x) != x) {
-       (void)GC_printf("GC_is_visible produced incorrect result\n");
+       GC_printf("GC_is_visible produced incorrect result\n");
        FAIL;
       }
+      z = GC_malloc(8);
+      GC_PTR_STORE(z, x);
+      if (*z != x) {
+        GC_printf("GC_PTR_STORE failed: %p != %p\n", *z, x);
+        FAIL;
+      }
       if (!TEST_FAIL_COUNT(1)) {
-#      if!(defined(RS6000) || defined(POWERPC) || defined(IA64)) || defined(M68K)
-         /* ON RS6000s function pointers point to a descriptor in the  */
+#      if!(defined(POWERPC) || defined(IA64)) || defined(M68K)
+         /* On POWERPCs function pointers point to a descriptor in the */
          /* 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_printf("GC_is_visible produced wrong failure indication\n");
+         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_printf(
+       GC_printf(
                "GC_is_valid_displacement produced incorrect result\n");
        FAIL;
       }
@@ -1109,15 +1132,25 @@ void run_one_test()
         if (GC_all_interior_pointers && !TEST_FAIL_COUNT(1)
            || !GC_all_interior_pointers && !TEST_FAIL_COUNT(2)) {
 #      endif
-         (void)GC_printf("GC_is_valid_displacement produced wrong failure indication\n");
+         GC_printf("GC_is_valid_displacement produced wrong failure indication\n");
          FAIL;
         }
 #     endif
 #   endif /* DBG_HDRS_ALL */
     /* Test floating point alignment */
-   collectable_count += 2;
+        collectable_count += 2;
        *(double *)GC_MALLOC(sizeof(double)) = 1.0;
        *(double *)GC_MALLOC(sizeof(double)) = 1.0;
+    /* Test size 0 allocation a bit more */
+       {
+          size_t i;
+          for (i = 0; i < 10000; ++i) {
+            GC_MALLOC(0);
+            GC_FREE(GC_MALLOC(0));
+            GC_MALLOC_ATOMIC(0);
+            GC_FREE(GC_MALLOC_ATOMIC(0));
+          }
+        }
 #   ifdef GC_GCJ_SUPPORT
       GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *));
       GC_init_gcj_malloc(0, (void *)fake_gcj_mark_proc);
@@ -1143,17 +1176,30 @@ void run_one_test()
         GC_free(GC_malloc(0));
         GC_free(GC_malloc_atomic(0));
     /* Repeated list reversal test. */
+        GET_TIME(start_time);
        reverse_test();
-#   ifdef PRINTSTATS
-       GC_printf("-------------Finished reverse_test\n");
-#   endif
+       if (GC_print_stats) {
+          GET_TIME(reverse_time);
+          time_diff = MS_TIME_DIFF(reverse_time, start_time);
+         GC_log_printf("-------------Finished reverse_test at time %u (%p)\n",
+                       (unsigned) time_diff, &start_time);
+       }
 #   ifndef DBG_HDRS_ALL
       typed_test();
-#     ifdef PRINTSTATS
-       GC_printf("-------------Finished typed_test\n");
-#     endif
+      if (GC_print_stats) {
+        GET_TIME(typed_time);
+        time_diff = MS_TIME_DIFF(typed_time, start_time);
+       GC_log_printf("-------------Finished typed_test at time %u (%p)\n",
+                     (unsigned) time_diff, &start_time);
+      }
 #   endif /* DBG_HDRS_ALL */
     tree_test();
+    if (GC_print_stats) {
+      GET_TIME(tree_time);
+      time_diff = MS_TIME_DIFF(tree_time, start_time);
+      GC_log_printf("-------------Finished tree_test at time %u (%p)\n",
+                     (unsigned) time_diff, &start_time);
+    }
     LOCK();
     n_tests++;
     UNLOCK();
@@ -1162,11 +1208,13 @@ void run_one_test()
        GC_gcollect();
        tiny_reverse_test(0);
        GC_gcollect();
-       GC_printf("Finished a child process\n");
+        if (GC_print_stats)
+         GC_log_printf("Finished a child process\n");
        exit(0);
       }
 #   endif
-    /* GC_printf("Finished %x\n", pthread_self()); */
+    if (GC_print_stats)
+      GC_log_printf("Finished %p\n", &start_time);
 }
 
 void check_heap_stats()
@@ -1320,26 +1368,26 @@ void SetMinimumStack(long minSize)
        /* Cheat and let stdio initialize toolbox for us.       */
        printf("Testing GC Macintosh port.\n");
 #   endif
-    GC_INIT(); /* Only needed on a few platforms.      */
-    (void) GC_set_warn_proc(warn_proc);
+    GC_COND_INIT();
+    GC_set_warn_proc(warn_proc);
 #   if (defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(GWW_VDB)) \
           && !defined(MAKE_BACK_GRAPH) && !defined(NO_INCREMENTAL)
       GC_enable_incremental();
-      (void) GC_printf("Switched to incremental mode\n");
+      GC_printf("Switched to incremental mode\n");
 #     if defined(MPROTECT_VDB)
-       (void)GC_printf("Emulating dirty bits with mprotect/signals\n");
+       GC_printf("Emulating dirty bits with mprotect/signals\n");
 #     else
 #       ifdef PROC_VDB
-       (void)GC_printf("Reading dirty bits from /proc\n");
+         GC_printf("Reading dirty bits from /proc\n");
 #       else
-    (void)GC_printf("Using DEFAULT_VDB dirty bit implementation\n");
+         GC_printf("Using DEFAULT_VDB dirty bit implementation\n");
 #       endif
 #      endif
 #   endif
     run_one_test();
     check_heap_stats();
 #   ifndef MSWINCE
-    (void)fflush(stdout);
+      fflush(stdout);
 #   endif
 #   ifdef LINT
        /* Entry points we should be testing, but aren't.                  */
@@ -1467,7 +1515,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
     GC_use_DllMain();  /* Test with implicit thread registration if possible. */
     GC_printf("Using DllMain to track threads\n");
 # endif
-  GC_INIT();
+  GC_COND_INIT();
 # ifndef NO_INCREMENTAL
     GC_enable_incremental();
 # endif
@@ -1577,7 +1625,7 @@ int main()
        pthread_win32_process_attach_np ();
        pthread_win32_thread_attach_np ();
 #   endif
-    GC_INIT();
+    GC_COND_INIT();
 
     pthread_attr_init(&attr);
 #   if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
index aedac1fa67441ec375f41713dbd6110326a3ef29..a9c0e73fb112593561c2babe4a9415ee46a4f6e4 100644 (file)
@@ -10,7 +10,7 @@
 # modified is included with the above copyright notice.
 
 
-## FIXME: trace_test don't works on macosx 10.3 
+## FIXME: trace_test doesn't work on macosx 10.3 
 ## gcc -g -O2 -o .libs/tracetest trace_test.o  ../.libs/libgc.dylib -lpthread
 ## ld: Undefined symbols:
 ## _GC_generate_random_backtrace
@@ -36,6 +36,16 @@ check_PROGRAMS += middletest
 middletest_SOURCES = tests/middle.c
 middletest_LDADD = $(test_ldadd)
 
+TESTS += smashtest$(EXEEXT)
+check_PROGRAMS += smashtest
+smashtest_SOURCES = tests/smash_test.c
+smashtest_LDADD = $(test_ldadd)
+
+TESTS += hugetest$(EXEEXT)
+check_PROGRAMS += hugetest
+hugetest_SOURCES = tests/huge_test.c
+hugetest_LDADD = $(test_ldadd)
+
 #TESTS += tracetest$(EXEEXT)
 #check_PROGRAMS += tracetest
 #tracetest_SOURCES = tests/trace_test.c
@@ -52,6 +62,10 @@ if CPLUSPLUS
 TESTS += test_cpp$(EXEEXT)
 check_PROGRAMS += test_cpp
 test_cpp_SOURCES = tests/test_cpp.cc
+if AVOID_CPP_LIB
+test_cpp_LDADD = gc_cpp.o $(test_ldadd)
+else
 test_cpp_LDADD = libgccpp.la $(test_ldadd)
 endif
+endif
 
index d1346028cfa4ada3e3b33289b2428c16516308b9..6cbbad4c61eb6e9d01751ef768155723db392010 100644 (file)
@@ -76,11 +76,11 @@ static void return_freelists(void **fl, void **gfl)
 
 /* 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;
 
+    GC_ASSERT(I_HOLD_LOCK());
     if (!keys_initialized) {
        if (0 != GC_key_create(&GC_thread_key, 0)) {
            ABORT("Failed to create key for local allocator");
@@ -144,7 +144,7 @@ void * GC_malloc(size_t bytes)
     void *result;
     void **tiny_fl;
 
-#   if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
+#   if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC)
       GC_key_t k = GC_thread_key;
       if (EXPECT(0 == k, 0)) {
        /* We haven't yet run GC_init_parallel.  That means     */
@@ -153,14 +153,14 @@ void * GC_malloc(size_t 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)) {
+#   if defined(USE_PTHREAD_SPECIFIC) || defined(USE_WIN32_SPECIFIC)
+      if (EXPECT(0 == tsd, 0)) {
        return GC_core_malloc(bytes);
       }
 #   endif
+    GC_ASSERT(GC_is_initialized);
 #   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.    */
@@ -178,19 +178,38 @@ void * GC_malloc(size_t bytes)
     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);
+#   ifdef LOG_ALLOCS
+      GC_err_printf("GC_malloc(%d) = %p : %d\n", bytes, result, GC_gc_no);
+#   endif
     return result;
 }
 
 void * GC_malloc_atomic(size_t bytes)
 {
     size_t granules = ROUNDED_UP_GRANULES(bytes);
+    void *tsd;
     void *result;
     void **tiny_fl;
 
+#   if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_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
+      tsd = GC_getspecific(GC_thread_key);
+#   endif
+#   if defined(USE_PTHREAD_SPECIFIC) || defined(USE_WIN32_SPECIFIC)
+      if (EXPECT(0 == tsd, 0)) {
+       return GC_core_malloc(bytes);
+      }
+#   endif
     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,
+    tiny_fl = ((GC_tlfs)tsd) -> ptrfree_freelists;
+    GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
                         PTRFREE, GC_core_malloc_atomic(bytes), 0/* no init */);
     return result;
 }
@@ -223,6 +242,8 @@ extern int GC_gcj_kind;
 /* 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.    */
+/* Unlike the other thread local allocation calls, we assume that the  */
+/* collector has been explicitly initialized.                          */
 void * GC_gcj_malloc(size_t bytes,
                     void * ptr_to_struct_containing_descr)
 {
@@ -234,7 +255,7 @@ void * GC_gcj_malloc(size_t bytes,
     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_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
                         GC_gcj_kind,
                         GC_core_gcj_malloc(bytes,
                                            ptr_to_struct_containing_descr),
index 23a13f5ff37a00b89e59d679558c453c4b213223..91465822a6293730ef786a85269c6d814512c6a4 100644 (file)
@@ -99,6 +99,11 @@ 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.                  */
 
+static void GC_push_typed_structures_proc (void)
+{
+  GC_push_all((ptr_t)&GC_ext_descriptors, (ptr_t)&GC_ext_descriptors + sizeof(word));
+}
+
 /* Add a multiword bitmap to GC_ext_descriptors arrays.  Return        */
 /* starting index.                                             */
 /* Returns -1 on failure.                                      */
@@ -118,10 +123,12 @@ signed_word GC_add_ext_descriptor(GC_bitmap bm, word nbits)
        size_t new_size;
        word ed_size = GC_ed_size;
        
-       UNLOCK();
        if (ed_size == 0) {
+           GC_push_typed_structures = GC_push_typed_structures_proc;
+           UNLOCK();
            new_size = ED_INITIAL_SIZE;
        } else {
+           UNLOCK();
            new_size = 2 * ed_size;
            if (new_size > MAX_ENV) return(-1);
        } 
index 520e9714b71b3ca6f20f557c7f800f4a8d6d328b..e422e66ff0f0c7f49bee3bb41ca8be634c403b0b 100755 (executable)
@@ -148,6 +148,7 @@ void GC_init_parallel(void);
 #     endif
       GC_ASSERT(!parallel_initialized);
       GC_win32_dll_threads = TRUE;
+      GC_init_parallel();
   }
 #else
   GC_API void GC_use_DllMain(void)
@@ -488,12 +489,12 @@ static GC_thread GC_lookup_thread(DWORD thread_id)
 /* thread being deleted.                                       */
 void GC_delete_gc_thread(GC_vthread gc_id)
 {
+  CloseHandle(gc_id->handle);
   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
@@ -551,6 +552,7 @@ void GC_delete_thread(DWORD id)
         prev = p;
         p = p -> next;
     }
+    CloseHandle(p->handle);
     if (prev == 0) {
         GC_threads[hv] = p -> next;
     } else {
@@ -560,7 +562,7 @@ void GC_delete_thread(DWORD id)
   }
 }
 
-int GC_register_my_thread(struct GC_stack_base *sb) {
+GC_API int GC_register_my_thread(struct GC_stack_base *sb) {
   DWORD t = GetCurrentThreadId();
 
   if (0 == GC_lookup_thread(t)) {
@@ -574,7 +576,7 @@ int GC_register_my_thread(struct GC_stack_base *sb) {
   }
 }
 
-int GC_unregister_my_thread(void)
+GC_API int GC_unregister_my_thread(void)
 {
     DWORD t = GetCurrentThreadId();
 
@@ -705,8 +707,8 @@ void GC_suspend(GC_thread t)
 #     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);
+       GC_ASSERT(GC_win32_dll_threads);
+       GC_delete_gc_thread(t);
 #     endif
       return;
     }
@@ -1079,7 +1081,7 @@ uintptr_t GC_beginthreadex(
     unsigned ( __stdcall *start_address )( void * ),
     void *arglist, unsigned initflag, unsigned *thrdaddr)
 {
-    uintptr_t thread_h = -1L;
+    uintptr_t thread_h;
 
     thread_args *args;
 
@@ -1098,7 +1100,7 @@ uintptr_t GC_beginthreadex(
        /* Handed off to and deallocated by child thread.       */
       if (0 == args) {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return (uintptr_t)(-1);
+        return (uintptr_t)(-1L);
       }
 
       /* set up thread arguments */
@@ -1498,10 +1500,10 @@ void GC_init_parallel(void)
     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.                                                    */
+       /* 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)