aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Klose <doko@gcc.gnu.org>2012-12-01 21:32:56 +0000
committerMatthias Klose <doko@gcc.gnu.org>2012-12-01 21:32:56 +0000
commit1e2f2f74c0dcb772b8184fba8b3665703e4d027d (patch)
tree83ace3f0691c7281d1fbb321faa32860d6095ba1
parent4e638f718c43d7525f7d833b52e9702e5b6dc0ed (diff)
Import boehm-gc snapshot, taken fromboehm
https://github.com/ivmai/bdwgc 9178e2b8f10eab0ac54c504c85022d0ea8ded36b git-svn-id: https://gcc.gnu.org/svn/gcc/branches/boehm@194030 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--boehm-gc/AUTHORS330
-rw-r--r--boehm-gc/BCC_MAKEFILE21
-rw-r--r--boehm-gc/CMakeLists.txt230
-rw-r--r--boehm-gc/ChangeLog8275
-rw-r--r--boehm-gc/EMX_MAKEFILE47
-rw-r--r--boehm-gc/MacProjects.sit.hqx886
-rw-r--r--boehm-gc/Mac_files/MacOS_Test_config.h91
-rw-r--r--boehm-gc/Mac_files/MacOS_config.h89
-rw-r--r--boehm-gc/Makefile680
-rw-r--r--boehm-gc/Makefile.DLLs107
-rw-r--r--boehm-gc/Makefile.am260
-rw-r--r--boehm-gc/Makefile.direct567
-rw-r--r--boehm-gc/Makefile.dj263
-rw-r--r--boehm-gc/Makefile.in921
-rw-r--r--boehm-gc/NT_MAKEFILE37
-rw-r--r--boehm-gc/NT_STATIC_THREADS_MAKEFILE71
-rw-r--r--boehm-gc/NT_THREADS_MAKEFILE2158
-rw-r--r--boehm-gc/NT_X64_STATIC_THREADS_MAKEFILE70
-rw-r--r--boehm-gc/NT_X64_THREADS_MAKEFILE87
-rw-r--r--boehm-gc/OS2_MAKEFILE14
-rw-r--r--boehm-gc/PCR-Makefile31
-rw-r--r--boehm-gc/README (renamed from boehm-gc/doc/README)257
-rw-r--r--boehm-gc/README.QUICK61
-rw-r--r--boehm-gc/SMakefile.amiga22
-rw-r--r--boehm-gc/TODO75
-rw-r--r--boehm-gc/WCC_MAKEFILE20
-rw-r--r--boehm-gc/aclocal.m44369
-rw-r--r--boehm-gc/add_gc_prefix.c20
-rw-r--r--boehm-gc/allchblk.c1147
-rw-r--r--boehm-gc/alloc.c1608
-rw-r--r--boehm-gc/alpha_mach_dep.s87
-rwxr-xr-xboehm-gc/autogen.sh18
-rw-r--r--boehm-gc/backgraph.c475
-rw-r--r--boehm-gc/bdw-gc.pc.in10
-rw-r--r--boehm-gc/blacklst.c299
-rw-r--r--boehm-gc/build/s60v3/bld.inf11
-rw-r--r--boehm-gc/build/s60v3/libgc.mmp77
-rwxr-xr-xboehm-gc/build_atomic_ops.sh5
-rwxr-xr-xboehm-gc/build_atomic_ops.sh.cygwin14
-rw-r--r--boehm-gc/checksums.c243
-rwxr-xr-xboehm-gc/config.guess1321
-rwxr-xr-xboehm-gc/config.sub1443
-rwxr-xr-xboehm-gc/configure10039
-rw-r--r--boehm-gc/configure.ac915
-rw-r--r--boehm-gc/configure.host61
-rw-r--r--boehm-gc/configure.in455
-rw-r--r--boehm-gc/cord/cord.am25
-rw-r--r--boehm-gc/cord/cordbscs.c740
-rw-r--r--boehm-gc/cord/cordprnt.c524
-rw-r--r--boehm-gc/cord/cordxtra.c270
-rw-r--r--boehm-gc/cord/de_win.ICObin766 -> 0 bytes
-rw-r--r--boehm-gc/cord/de_win.h103
-rw-r--r--boehm-gc/cord/tests/cordtest.c (renamed from boehm-gc/cord/cordtest.c)127
-rw-r--r--boehm-gc/cord/tests/de.c (renamed from boehm-gc/cord/de.c)393
-rw-r--r--boehm-gc/cord/tests/de_cmds.h (renamed from boehm-gc/cord/de_cmds.h)26
-rw-r--r--boehm-gc/cord/tests/de_win.c (renamed from boehm-gc/cord/de_win.c)289
-rw-r--r--boehm-gc/cord/tests/de_win.h101
-rw-r--r--boehm-gc/cord/tests/de_win.rc (renamed from boehm-gc/cord/de_win.RC)15
-rw-r--r--boehm-gc/darwin_stop_world.c666
-rw-r--r--boehm-gc/dbg_mlc.c1489
-rw-r--r--boehm-gc/digimars.mak6
-rw-r--r--boehm-gc/doc/README.DGUX38645
-rw-r--r--boehm-gc/doc/README.Mac68
-rw-r--r--boehm-gc/doc/README.MacOSX1
-rw-r--r--boehm-gc/doc/README.amiga41
-rw-r--r--boehm-gc/doc/README.arm.cross62
-rw-r--r--boehm-gc/doc/README.autoconf14
-rw-r--r--boehm-gc/doc/README.changes2134
-rw-r--r--boehm-gc/doc/README.cmake50
-rw-r--r--boehm-gc/doc/README.contributors57
-rw-r--r--boehm-gc/doc/README.cords6
-rw-r--r--boehm-gc/doc/README.darwin144
-rw-r--r--boehm-gc/doc/README.dj5
-rw-r--r--boehm-gc/doc/README.environment267
-rw-r--r--boehm-gc/doc/README.ews480080
-rw-r--r--boehm-gc/doc/README.linux41
-rw-r--r--boehm-gc/doc/README.macros618
-rw-r--r--boehm-gc/doc/README.sgi3
-rw-r--r--boehm-gc/doc/README.solaris250
-rw-r--r--boehm-gc/doc/README.symbian13
-rw-r--r--boehm-gc/doc/README.win32189
-rw-r--r--boehm-gc/doc/README.win6426
-rw-r--r--boehm-gc/doc/barrett_diagram94
-rw-r--r--boehm-gc/doc/debugging.html17
-rw-r--r--boehm-gc/doc/doc.am51
-rw-r--r--boehm-gc/doc/finalization.html190
-rw-r--r--boehm-gc/doc/gc.man10
-rw-r--r--boehm-gc/doc/gcdescr.html96
-rw-r--r--boehm-gc/doc/gcinterface.html283
-rw-r--r--boehm-gc/doc/leak.html208
-rw-r--r--boehm-gc/doc/overview.html446
-rw-r--r--boehm-gc/doc/porting.html333
-rw-r--r--boehm-gc/doc/scale.html210
-rw-r--r--boehm-gc/doc/simple_example.html229
-rw-r--r--boehm-gc/doc/tree.html94
-rw-r--r--boehm-gc/dyn_load.c1715
-rw-r--r--boehm-gc/extra/AmigaOS.c (renamed from boehm-gc/AmigaOS.c)8
-rw-r--r--boehm-gc/extra/MacOS.c (renamed from boehm-gc/MacOS.c)24
-rw-r--r--boehm-gc/extra/Mac_files/MacOS_config.h28
-rw-r--r--boehm-gc/extra/Mac_files/dataend.c (renamed from boehm-gc/Mac_files/dataend.c)4
-rw-r--r--boehm-gc/extra/Mac_files/datastart.c (renamed from boehm-gc/Mac_files/datastart.c)4
-rw-r--r--boehm-gc/extra/gc.c83
-rw-r--r--boehm-gc/extra/msvc_dbg.c381
-rw-r--r--boehm-gc/extra/symbian.cpp55
-rw-r--r--boehm-gc/extra/symbian/global_end.cpp16
-rw-r--r--boehm-gc/extra/symbian/global_start.cpp16
-rw-r--r--boehm-gc/extra/symbian/init_global_static_roots.cpp33
-rw-r--r--boehm-gc/finalize.c1224
-rw-r--r--boehm-gc/fnlz_mlc.c172
-rw-r--r--boehm-gc/gc.mak617
-rw-r--r--boehm-gc/gc_cpp.cc105
-rw-r--r--boehm-gc/gc_dlopen.c119
-rw-r--r--boehm-gc/gcc_support.c516
-rw-r--r--boehm-gc/gcj_mlc.c381
-rw-r--r--boehm-gc/gcname.c13
-rw-r--r--boehm-gc/headers.c308
-rw-r--r--boehm-gc/hpux_test_and_clear.s21
-rw-r--r--boehm-gc/include/cord.h511
-rw-r--r--boehm-gc/include/cord_pos.h120
-rw-r--r--boehm-gc/include/ec.h58
-rw-r--r--boehm-gc/include/extra/gc.h2
-rw-r--r--boehm-gc/include/extra/gc_cpp.h2
-rw-r--r--boehm-gc/include/gc.h2528
-rw-r--r--boehm-gc/include/gc_alloc.h383
-rw-r--r--boehm-gc/include/gc_allocator.h325
-rw-r--r--boehm-gc/include/gc_amiga_redirects.h30
-rw-r--r--boehm-gc/include/gc_backptr.h79
-rw-r--r--boehm-gc/include/gc_config_macros.h379
-rw-r--r--boehm-gc/include/gc_cpp.h309
-rw-r--r--boehm-gc/include/gc_disclaim.h55
-rw-r--r--boehm-gc/include/gc_gcj.h155
-rw-r--r--boehm-gc/include/gc_inl.h107
-rw-r--r--boehm-gc/include/gc_inline.h147
-rw-r--r--boehm-gc/include/gc_local_alloc.h89
-rw-r--r--boehm-gc/include/gc_mark.h373
-rw-r--r--boehm-gc/include/gc_pthread_redirects.h139
-rw-r--r--boehm-gc/include/gc_tiny_fl.h90
-rw-r--r--boehm-gc/include/gc_typed.h144
-rw-r--r--boehm-gc/include/gc_version.h45
-rw-r--r--boehm-gc/include/include.am54
-rw-r--r--boehm-gc/include/javaxfc.h40
-rw-r--r--boehm-gc/include/leak_detector.h67
-rw-r--r--boehm-gc/include/new_gc_alloc.h374
-rw-r--r--boehm-gc/include/private/cord_pos.h118
-rw-r--r--boehm-gc/include/private/darwin_semaphore.h85
-rw-r--r--boehm-gc/include/private/darwin_stop_world.h46
-rw-r--r--boehm-gc/include/private/dbg_mlc.h233
-rw-r--r--boehm-gc/include/private/gc_hdrs.h331
-rw-r--r--boehm-gc/include/private/gc_locks.h745
-rw-r--r--boehm-gc/include/private/gc_pmark.h602
-rw-r--r--boehm-gc/include/private/gc_priv.h3481
-rw-r--r--boehm-gc/include/private/gcconfig.h2978
-rw-r--r--boehm-gc/include/private/msvc_dbg.h69
-rw-r--r--boehm-gc/include/private/pthread_stop_world.h44
-rw-r--r--boehm-gc/include/private/pthread_support.h146
-rw-r--r--boehm-gc/include/private/solaris_threads.h37
-rw-r--r--boehm-gc/include/private/specific.h117
-rw-r--r--boehm-gc/include/private/thread_local_alloc.h166
-rw-r--r--boehm-gc/include/weakpointer.h10
-rwxr-xr-xboehm-gc/install-sh251
-rw-r--r--boehm-gc/irix_threads.c726
-rw-r--r--boehm-gc/libtool.m43573
-rw-r--r--boehm-gc/linux_threads.c1728
-rwxr-xr-xboehm-gc/ltconfig3
-rw-r--r--boehm-gc/ltmain.sh4984
-rw-r--r--boehm-gc/m4/gc_set_version.m4 (renamed from boehm-gc/acinclude.m4)24
-rw-r--r--boehm-gc/mach_dep.c789
-rw-r--r--boehm-gc/malloc.c799
-rw-r--r--boehm-gc/mallocx.c936
-rw-r--r--boehm-gc/mark.c2437
-rw-r--r--boehm-gc/mark_rts.c884
-rw-r--r--boehm-gc/mips_sgi_mach_dep.s46
-rw-r--r--boehm-gc/mips_ultrix_mach_dep.s26
-rw-r--r--boehm-gc/misc.c2553
-rwxr-xr-xboehm-gc/mkinstalldirs101
-rw-r--r--boehm-gc/new_hblk.c253
-rw-r--r--boehm-gc/obj_map.c143
-rw-r--r--boehm-gc/os_dep.c6438
-rw-r--r--boehm-gc/pc_excludes21
-rw-r--r--boehm-gc/pcr_interface.c71
-rw-r--r--boehm-gc/powerpc_macosx_mach_dep.s95
-rw-r--r--boehm-gc/pthread_start.c69
-rw-r--r--boehm-gc/pthread_stop_world.c923
-rw-r--r--boehm-gc/pthread_support.c2048
-rw-r--r--boehm-gc/ptr_chck.c408
-rw-r--r--boehm-gc/real_malloc.c23
-rw-r--r--boehm-gc/reclaim.c1320
-rw-r--r--boehm-gc/rs6000_mach_dep.s114
-rw-r--r--boehm-gc/setjmp_t.c114
-rw-r--r--boehm-gc/solaris_pthreads.c180
-rw-r--r--boehm-gc/solaris_threads.c962
-rw-r--r--boehm-gc/specific.c163
-rw-r--r--boehm-gc/src/ia64_save_regs_in_stack.s (renamed from boehm-gc/ia64_save_regs_in_stack.s)1
-rw-r--r--boehm-gc/src/sparc_mach_dep.S61
-rw-r--r--boehm-gc/src/sparc_netbsd_mach_dep.s (renamed from boehm-gc/sparc_netbsd_mach_dep.s)2
-rw-r--r--boehm-gc/src/sparc_sunos4_mach_dep.s (renamed from boehm-gc/sparc_sunos4_mach_dep.s)8
-rw-r--r--boehm-gc/stubborn.c330
-rw-r--r--boehm-gc/tests/CMakeLists.txt19
-rw-r--r--boehm-gc/tests/disclaim_bench.c142
-rw-r--r--boehm-gc/tests/disclaim_test.c224
-rw-r--r--boehm-gc/tests/huge_test.c52
-rw-r--r--boehm-gc/tests/initsecondarythread.c100
-rw-r--r--boehm-gc/tests/leak_test.c12
-rw-r--r--boehm-gc/tests/middle.c25
-rw-r--r--boehm-gc/tests/realloc_test.c34
-rw-r--r--boehm-gc/tests/smash_test.c28
-rw-r--r--boehm-gc/tests/staticrootslib.c33
-rw-r--r--boehm-gc/tests/staticrootstest.c79
-rw-r--r--boehm-gc/tests/subthread_create.c145
-rw-r--r--boehm-gc/tests/test.c1801
-rw-r--r--boehm-gc/tests/test_cpp.cc192
-rw-r--r--boehm-gc/tests/tests.am104
-rw-r--r--boehm-gc/tests/thread_leak_test.c72
-rw-r--r--boehm-gc/tests/threadkey_test.c100
-rw-r--r--boehm-gc/tests/trace_test.c16
-rw-r--r--boehm-gc/thread_local_alloc.c328
-rw-r--r--boehm-gc/threadlibs.c37
-rw-r--r--boehm-gc/tools/add_gc_prefix.c21
-rwxr-xr-xboehm-gc/tools/callprocs.sh (renamed from boehm-gc/callprocs)0
-rw-r--r--boehm-gc/tools/gcname.c17
-rw-r--r--boehm-gc/tools/if_mach.c (renamed from boehm-gc/if_mach.c)12
-rw-r--r--boehm-gc/tools/if_not_there.c (renamed from boehm-gc/if_not_there.c)17
-rw-r--r--boehm-gc/tools/setjmp_t.c145
-rw-r--r--boehm-gc/tools/threadlibs.c82
-rw-r--r--boehm-gc/typd_mlc.c830
-rw-r--r--boehm-gc/version.h30
-rw-r--r--boehm-gc/win32_threads.c3271
-rw-r--r--boehm-gc/windows-untested/README4
-rw-r--r--boehm-gc/windows-untested/gc.def2
-rw-r--r--boehm-gc/windows-untested/gc.rc1
-rw-r--r--boehm-gc/windows-untested/gc.ver86
-rw-r--r--boehm-gc/windows-untested/stdafx.c1
-rw-r--r--boehm-gc/windows-untested/stdafx.h15
-rw-r--r--boehm-gc/windows-untested/vc60/all.dsp63
-rw-r--r--boehm-gc/windows-untested/vc60/gc.dsp332
-rw-r--r--boehm-gc/windows-untested/vc60/gc.dsw194
-rw-r--r--boehm-gc/windows-untested/vc60/libgc.dsp269
-rw-r--r--boehm-gc/windows-untested/vc60/libgcmt.dsp225
-rw-r--r--boehm-gc/windows-untested/vc60/test.dsp63
-rw-r--r--boehm-gc/windows-untested/vc60/test_gc.dsp93
-rw-r--r--boehm-gc/windows-untested/vc60/test_leak_gc.dsp93
-rw-r--r--boehm-gc/windows-untested/vc60/test_leak_libgc.dsp93
-rw-r--r--boehm-gc/windows-untested/vc60/test_leak_libgcmt.dsp93
-rw-r--r--boehm-gc/windows-untested/vc60/test_libgc.dsp93
-rw-r--r--boehm-gc/windows-untested/vc60/test_libgcmt.dsp93
-rwxr-xr-xboehm-gc/windows-untested/vc60/vc60crlf.cmd15
-rw-r--r--boehm-gc/windows-untested/vc70/all.vcproj49
-rw-r--r--boehm-gc/windows-untested/vc70/gc.sln96
-rw-r--r--boehm-gc/windows-untested/vc70/gc.vcproj347
-rw-r--r--boehm-gc/windows-untested/vc70/libgc.vcproj258
-rw-r--r--boehm-gc/windows-untested/vc70/libgcmt.vcproj225
-rw-r--r--boehm-gc/windows-untested/vc70/test.vcproj49
-rw-r--r--boehm-gc/windows-untested/vc70/test_gc.vcproj127
-rw-r--r--boehm-gc/windows-untested/vc70/test_leak_gc.vcproj127
-rw-r--r--boehm-gc/windows-untested/vc70/test_leak_libgc.vcproj127
-rw-r--r--boehm-gc/windows-untested/vc70/test_leak_libgcmt.vcproj127
-rw-r--r--boehm-gc/windows-untested/vc70/test_libgc.vcproj127
-rw-r--r--boehm-gc/windows-untested/vc70/test_libgcmt.vcproj127
-rw-r--r--boehm-gc/windows-untested/vc71/all.vcproj57
-rw-r--r--boehm-gc/windows-untested/vc71/gc.sln116
-rw-r--r--boehm-gc/windows-untested/vc71/gc.vcproj869
-rw-r--r--boehm-gc/windows-untested/vc71/libgc.vcproj776
-rw-r--r--boehm-gc/windows-untested/vc71/libgcmt.vcproj743
-rw-r--r--boehm-gc/windows-untested/vc71/test.vcproj57
-rw-r--r--boehm-gc/windows-untested/vc71/test_gc.vcproj161
-rw-r--r--boehm-gc/windows-untested/vc71/test_leak_gc.vcproj161
-rw-r--r--boehm-gc/windows-untested/vc71/test_leak_libgc.vcproj161
-rw-r--r--boehm-gc/windows-untested/vc71/test_leak_libgcmt.vcproj161
-rw-r--r--boehm-gc/windows-untested/vc71/test_libgc.vcproj161
-rw-r--r--boehm-gc/windows-untested/vc71/test_libgcmt.vcproj161
270 files changed, 57243 insertions, 62422 deletions
diff --git a/boehm-gc/AUTHORS b/boehm-gc/AUTHORS
new file mode 100644
index 00000000000..7a7f21201da
--- /dev/null
+++ b/boehm-gc/AUTHORS
@@ -0,0 +1,330 @@
+This is an attempt to acknowledge early contributions to the garbage
+collector. Later contributions should be also mentioned in "git log".
+
+HISTORY -
+
+ Early versions of this collector were developed as a part of research
+projects supported in part by the National Science Foundation
+and the Defense Advance Research Projects Agency.
+
+The garbage collector originated as part of the run-time system for
+the Russell programming language implementation. The first version of the
+garbage collector was written primarily by Al Demers. It was then refined
+and mostly rewritten, primarily by Hans-J. Boehm, at Cornell U.,
+the University of Washington, Rice University (where it was first used for
+C and assembly code), Xerox PARC, SGI, and HP Labs. However, significant
+contributions have also been made by many others.
+
+Other contributors (my apologies for any omissions):
+
+Adam Megacz <adam@megac.com>
+Adnan Ali
+Adrian Bunk
+Akira Tagoh
+Alain Novak
+Alan Dosser <dosser@src.dec.com>
+Alan J. Demers <ademers@cs.cornell.edu>
+Aleksey Demakov
+Alexander Belchenko <bialix@ukr.net>
+Alexander Gavrilov <angavrilov@gmail.com>
+Alexander Herz <alexander.herz@mytum.de>
+Alexandr Petrosian
+Alexandr Shadchin <ShadchinAV@mail.ru>
+Alistair G. Crooks <agc@uts.amdahl.com>
+Allan Hsu <allan@counterpop.net>
+Andre Leiradella
+Andreas Farber <afaerber@mono-cvs.ximian.com>
+Andreas Jaeger
+Andreas Tobler <a.tobler@schweiz.org>
+Andrei Polushin
+Andrej Cedilnik <acedil1@csee.umbc.edu>
+Andrew Begel
+Andrew Haley
+Andrew Pinski
+Andrew Stitcher
+Andrew Stone
+Andy Wingo <wingo@pobox.com>
+Anselm Baird-Smith <Anselm.BairdSmith@inria.fr>
+Anthony Green
+Ari Huttunen <Ari.Huttunen@hut.fi>
+Arrigo Triulzi <arrigo@ic.ac.uk>
+Ashley Bone
+Assar Westerlund <assar@sics.se>
+Barry DeFreese
+Ben A. Mesander <ben@piglet.cr.usgs.gov>
+Ben Cottrell
+Ben Hutchings
+Ben Maurer <benm@mono-cvs.ximian.com>
+Bernie Solomon
+Bill Janssen <janssen@parc.xerox.com>
+Bo Thorsen
+Bradley D. LaRonde <brad@ltc.com>
+Bradley Smith <brad@brad-smith.co.uk>
+Brent Benson <brent@jade.ssd.csd.harris.com>
+Brian Alliet <brian@brianweb.net>
+Brian Beuning
+Brian Burton
+Brian D. Carlstrom <bdc@clark.lcs.mit.edu>
+Brian F. Dennis <xjam@cork.cs.berkeley.edu>
+Brian Lewis <btlewis@eng.sun.com>
+Bruce Mitchener <bruce.mitchener@gmail.com>
+Bryce McKinley
+Burkhard Linke <blinke@cebitec.uni-bielefeld.de>
+Cesar Eduardo Barros
+Charles Mills
+Chris Dodd
+Chris Lingard
+Christian Joensson
+Christian Limpach
+Christian Thalinger
+Christoffe Raffali
+Clay Spence <cds@peanut.sarnoff.com>
+Colin LeMahieu <clemahieu@gmail.com>
+Craig McDaniel
+Dai Sato
+Dan Bonachea
+Dan Fandrich
+Dan Sullivan
+Daniel R. Grayson <dan@math.uiuc.edu>
+Danny Smith
+Darrell Schiebel
+Dave Barrett <barrett@asgard.cs.colorado.edu>
+Dave Detlefs <detlefs@src.dec.com>
+Dave Grove
+Dave Korn <dave.korn.cygwin@googlemail.com>
+Dave Love
+David Ayers
+David Daney <ddaney@avtrex.com>
+David Leonard
+David Miller
+David Mossberger
+David Peroutka
+David Pickens
+David Stes
+Davide Angelocola
+Dick Porter
+Dietmar Planitzer <dave.pl@ping.at>
+Dimitris Vyzovitis
+Dimitry Andric
+Djamel Magri <djamel.magri@googlemail.com>
+Doug Kaufman
+Douglas Steel <doug@wg.icl.co.uk>
+Elijah Taylor <elijahtaylor@google.com>
+Elvenlord Elrond <elrond@samba-tng.org>
+Emmanual Stumpf
+Eric Holk <eric.holk@gmail.com>
+Fabian Thylman
+Fergus Henderson
+Franklin Chen <chen@adi.com>
+Fred Stearns
+Friedrich Dominicus <friedrichdominicus@googlemail.com>
+Gary Leavens <leavens@eecs.ucf.edu>
+Geoff Norton <grompf@sublimeintervention.com>
+George Talbot <Gtalbot@ansarisbio.com>
+Gerard A Allan
+Glauco Masotti
+Gonzalo Paniagua Javier <gonzalo.mono@gmail.com>
+Grzegorz Jakacki <jakacki@acm.org>
+Gustavo Rodriguez-Rivera
+H.J. Lu <hjl.tools@gmail.com>
+Hanno Boeck
+Hans Boehm <hans.boehm@hp.com>
+Hans-Peter Nilsson <hp@gcc.gnu.org>
+Harris NightHawk
+Henning Makholm <Henning@octoshape.com>
+Henrik Theiling
+Hironori Sakamoto <hsaka@mth.biglobe.ne.jp>
+Hiroshi Kawashima
+Iain Sandoe <developer@sandoe-acoustics.co.uk>
+Ian Piumarta
+Ian Searle
+Igor Khavkine
+Ivan Demakov <ivan@tgrad.nsk.su>
+Ivan Maidanski <ivmai@mail.ru>
+Jaap Boender
+Jack Andrews <effbiae@gmail.com>
+Jack Howarth <howarth@bromo.med.uc.edu>
+Jacob Navia
+Jakub Jelinek
+James Clark <jjc@jclark.com>
+James Dominy
+Jan Wielemaker <J.Wielemaker@cs.vu.nl>
+Jani Kajala
+Jean-Baptiste Nivois
+Jean-Claude Beaudoin <jean.claude.beaudoin@gmail.com>
+Jean-Daniel Fekete
+Jeff Sturm
+Jeffrey Hsu <hsu@soda.berkeley.edu>
+Jeffrey Mark Siskind
+Jeffrey Stedfast <fejj@gnome.org>
+Jeremy Fitzhardinge
+Jesper Peterson <jep@mtiame.mtia.oz.au>
+Jesse Hull
+Jesse Jones
+Jesse Rosenstock
+Ji-Yong Chung
+Jie Liu <lj8175@gmail.com>
+Jim Marshall <jim.marshall@wbemsolutions.com>
+Jim Meyering <jim@meyering.net>
+Joerg Sonnenberger
+Johannes Schmidt
+Johannes Totz <jtotz@ic.ac.uk>
+John Bowman
+John Clements
+John Ellis
+John Merryweather Cooper
+Jon Moore
+Jonathan Bachrach <jonathan@harlequin.com>
+Jonathan Chambers <joncham@gmail.com>
+Jonathan Clark
+Jonathan Pryor <jpryor@novell.com>
+Juan Jose Garcia-Ripoll <juanjose.garciaripoll@googlemail.com>
+Kai Tietz <ktietz70@googlemail.com>
+Kazu Hirata
+Kazuhiro Inaoka
+Keith Seitz <keiths@redhat.com>
+Kenjiro Taura
+Kenneth Schalk
+Kevin Kenny <kenny@m.cs.uiuc.edu>
+Kjetil S. Matheussen <ksvalast@ifi.uio.no>
+Klaus Treichel <ktreichel@web.de>
+Knut Tvedten <knuttv@ifi.uio.no>
+Kornel Pal <kornelpal@gmail.com>
+Koushik Dutta <koushd@gmail.com>
+Krister Walfridsson
+Kristian Kristensen
+Lars Farm <lars.farm@ite.mh.se>
+Laurent Morichetti
+Linas Vepstas <linasvepstas@gmail.com>
+Loren J. Rittle <rittle@latour.labs.mot.com>
+Louis Zhuang <louis.zhuang@acm.org>
+Ludovic Courtes <ludo@gnu.org>
+Manuel Serrano <serrano@cornas.inria.fr>
+Marc Recht
+Marco Maggi
+Marcos Dione
+Marcus Herbert
+Marek Safar <marek.safar@gmail.com>
+Margaret Fleck <mfleck@illinois.edu>
+Mark Boulter <mboulter@vnet.ibm.com>
+Mark Mitchell
+Mark Probst <mark.probst@gmail.com>
+Mark Reichert
+Mark Sibly
+Mark Weiser <weiser@ubiq.com>
+Martin Baulig <martin@novell.com>
+Martin Tauchmann <martintauchmann@bigfoot.com>
+Massimiliano Mantione <massi@mono-cvs.ximian.com>
+Matt Austern
+Matthew Flatt
+Matthias Andree
+Matthias Drochner
+Maurizio Vairani
+Michael Arnoldus <chime@proinf.dk>
+Michael Smith
+Michael Spertus
+Michel Schinz <schinz@alphanet.ch>
+Miguel de Icaza <miguel@gnome.org>
+Mike Gran <spk121@yahoo.com>
+Mike Stump <mrs@windriver.com>
+Mitch Harris <maharri@uiuc.edu>
+Mohan Embar
+Nathanael Nerode
+Neale Ferguson <neale@mono-cvs.ximian.com>
+Neil Sharman <neil@cs.mu.oz.au>
+Nicolas Cannasse
+Niibe Yutaka <gniibe@fsij.org>
+Niklas Therning <niklas@therning.org>
+Noah Lavine <noah.b.lavine@gmail.com>
+Oliver Kurth <oliver.kurth@innominate.com>
+Paolo Molaro <lupus@ximian.com>
+Parag Patel <parag@netcom.com>
+Patrick Bridges
+Patrick C. Beard <beard@netscape.com>
+Patrick Doyle
+Patrick Marlier <patrick.marlier@gmail.com>
+Paul Brook
+Peter Chubb
+Peter Colson
+Peter Housel
+Peter Monks
+Peter Ross
+Peter Seebach <seebs@taniemarie.solon.com>
+Peter Wang
+Petr Krajca <krajcap@inf.upol.cz>
+Petr Salinger
+Petter Urkedal <paurkedal@gmail.com>
+Philipp Tomsich
+Philippe Queinnec
+Phillip Musumeci
+Philp Brown
+Pierre de Rop
+Radek Polak
+Rainer Orth <ro@cebitec.uni-bielefeld.de>
+Raja R Harinath <harinath@hurrynot.org>
+Rauli Ruohonen
+Regis Cridlig <Regis.Cridlig@cl.cam.ac.uk>
+Rene Girard
+Rex Dieter <rdieter@math.unl.edu>
+Reza Shahidi
+Richard Earnshaw
+Richard Sandiford <rsandifo@nildram.co.uk>
+Rob Haack <rhaack@polaris.unm.edu>
+Robert Brazile <brazile@diamond.bbn.com>
+Robert Jordan <robertj@gmx.net>
+Robert Nagy <robert@openbsd.org>
+Rodrigo Kumpera <kumpera@gmail.com>
+Roger Sayle
+Roman Hodek
+Romano Paolo Tenca <rotenca@telvia.it>
+Russell Ruby <russ@sludge.net>
+Rutger Ovidus
+Ryan Murray
+Salvador Eduardo Tropea
+Samuel Thibault
+Scott Ananian
+Scott Schwartz <schwartz@groucho.cse.psu.edu>
+Sebastien Pouliot <sebastien@ximian.com>
+Shawn Wagner
+Simon Posnjak
+Slava Sysoltev
+Stefan Ring
+Stefano Rivera <stefano@rivera.za.net>
+Sugioka Toshinobu
+Suzuki Toshiya
+Sven Hartrumpf
+Sven Verdoolaege
+Tagliapietra Tommaso
+Takis Psarogiannakopoulos <takis@xfree86.org>
+Tatsuya Bizenn
+Thiemo Seufer <ths@networkno.de>
+Thomas Funke <thf@zelator.in-berlin.de>
+Thomas Klausner <tk@giga.or.at>
+Thomas Maier
+Thorsten Glaser <tg@debian.org>
+Tilman Vogel <Tilman.Vogel@web.de>
+Tim Bingham
+Timothy N. Newsham
+Todd Berman <tberman@mono-cvs.ximian.com>
+Tom Tromey <tromey@cygnus.com>
+Toralf Foerster
+Toshio Endo
+Tsugutomo Enami <tsugutomo.enami@jp.sony.com>
+Tum Nguyen
+Tyson Dowd
+Uchiyama Yasushi
+Ulrich Drepper
+Ulrich Weigand
+Uros Bizjak <ubizjak@gmail.com>
+Victor Ivrii
+Vladimir Tsichevski
+Walter Bright
+Walter Underwood
+Wilson Ho
+Wink Saville
+Xi Wang <xi.wang@gmail.com>
+Xiaokun Zhu <xiaokun@aero.gla.ac.uk>
+Yannis Bres
+Zach Saw <zach.saw@gmail.com>
+Zhong Shao
+Zoltan Varga <vargaz@gmail.com>
diff --git a/boehm-gc/BCC_MAKEFILE b/boehm-gc/BCC_MAKEFILE
index e21bc3d8dfe..4e45334606a 100644
--- a/boehm-gc/BCC_MAKEFILE
+++ b/boehm-gc/BCC_MAKEFILE
@@ -14,9 +14,8 @@ rc= $(bcbin)\brc32
lib= $(bcbin)\tlib
link= $(bcbin)\ilink32
cflags= -O2 -R -v- -vi -H -H=gc.csm -I$(bcinclude);$(gcinclude1);$(gcinclude2) -L$(bclib) \
- -w-pro -w-aus -w-par -w-ccc -w-rch -a4 -D__STDC__=0
-#defines= -DSILENT
-defines= -DSILENT -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY
+ -w-pro -w-aus -w-par -w-ccc -w-rch -a4
+defines= -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY
.c.obj:
$(cc) @&&|
@@ -35,7 +34,8 @@ XXXOBJS= XXXalloc.obj XXXreclaim.obj XXXallchblk.obj XXXmisc.obj \
XXXmach_dep.obj XXXos_dep.obj XXXmark_rts.obj XXXheaders.obj XXXmark.obj \
XXXobj_map.obj XXXblacklst.obj XXXfinalize.obj XXXnew_hblk.obj \
XXXdbg_mlc.obj XXXmalloc.obj XXXstubborn.obj XXXdyn_load.obj \
- XXXtypd_mlc.obj XXXptr_chck.obj XXXgc_cpp.obj XXXmallocx.obj
+ XXXtypd_mlc.obj XXXptr_chck.obj XXXgc_cpp.obj XXXmallocx.obj \
+ XXXfnlz_mlc.obj
OBJS= $(XXXOBJS:XXX=)
@@ -54,16 +54,16 @@ gctest.exe: tests\test.obj gc.lib
$(cflags) -W -e$* tests\test.obj gc.lib
|
-cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h \
- cord\de_cmds.h
+cord\tests\de.obj cord\tests\de_win.obj: include\cord.h \
+ include\cord_pos.h cord\tests\de_win.h cord\tests\de_cmds.h
-cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj \
- cord\de_win.res gc.lib
+cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj \
+ cord\tests\de_win.obj cord\tests\de_win.res gc.lib
$(cc) @&&|
$(cflags) -W -e$* cord\cordbscs.obj cord\cordxtra.obj \
- cord\de.obj cord\de_win.obj gc.lib
+ cord\tests\de.obj cord\tests\de_win.obj gc.lib
|
- $(rc) cord\de_win.res cord\de.exe
+ $(rc) cord\tests\de_win.res cord\de.exe
gc_cpp.obj: include\gc_cpp.h include\gc.h
@@ -85,4 +85,3 @@ clean:
del gc.lib
del *.obj
del tests\test.obj
-
diff --git a/boehm-gc/CMakeLists.txt b/boehm-gc/CMakeLists.txt
new file mode 100644
index 00000000000..d537b8a8465
--- /dev/null
+++ b/boehm-gc/CMakeLists.txt
@@ -0,0 +1,230 @@
+#
+# Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+# Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+# Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+# Copyright (c) 2000-2010 by Hewlett-Packard Company. All rights reserved.
+##
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+##
+# Permission is hereby granted to use or copy this program
+# for any purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+##
+
+#
+# get cmake and run:
+# cmake -G "Visual Studio 8 2005"
+# in the same dir as this file
+# this will generate gc.sln
+#
+
+SET(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required
+
+PROJECT(gc)
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+ADD_DEFINITIONS("-D_CRT_SECURE_NO_DEPRECATE
+ -DALL_INTERIOR_POINTERS
+ -DGC_BUILD
+")
+
+IF(APPLE)
+ SET(CMAKE_OSX_ARCHITECTURES "ppc;i386;x86_64" CACHE STRING "Build architectures for Mac OS X" FORCE)
+ENDIF(APPLE)
+
+#LIBATOMIC #TODO
+#ADD_LIBRARY(atomic_ops STATIC )
+#SET_TARGET_PROPERTIES(atomic_ops PROPERTIES COMPILE_FLAGS -DNO_DEBUGGING)
+
+
+#LIBGC
+
+INCLUDE_DIRECTORIES(include)
+INCLUDE_DIRECTORIES(libatomic_ops/src)
+
+SET(SRC alloc.c reclaim.c allchblk.c misc.c mach_dep.c os_dep.c
+ mark_rts.c headers.c mark.c obj_map.c blacklst.c finalize.c
+ new_hblk.c dbg_mlc.c malloc.c stubborn.c dyn_load.c
+ typd_mlc.c ptr_chck.c gc_cpp.cc mallocx.c checksums.c
+ thread_local_alloc.c)
+SET(LIBS)
+OPTION(enable_threads "TODO" NO)
+IF(enable_threads)
+ FIND_PACKAGE(Threads REQUIRED)
+ MESSAGE("Thread Model: ${CMAKE_THREAD_LIBS_INIT}" )
+ INCLUDE_DIRECTORIES(${Threads_INCLUDE_DIR})
+ SET(LIBS ${LIBS} ${Threads_LIBRARIES})
+ENDIF(enable_threads)
+
+OPTION(enable_parallel_mark "Parallelize marking and free list construction" NO)
+
+#IF(Threads_FOUND)
+# ADD_DEFINITIONS("")
+#ELSE
+# MESSAGE("Parallel mark requires enable_threads ON" )
+#ENDIF(Threads_FOUND)
+
+IF(enable_parallel_mark)
+ENDIF(enable_parallel_mark)
+
+OPTION(enable_cplusplus "install C++ support" NO)
+
+SET(_HOST ${CMAKE_HOST_SYSTEM_PROCESSOR}--${CMAKE_SYSTEM}) #FIXME missing the vendor field.Use lowercase
+
+STRING(TOLOWER ${_HOST} HOST)
+MESSAGE("HOST = ${HOST}")
+
+#Thread Detection. Relying on cmake for lib an includes.
+#TODO check cmake detection
+IF(CMAKE_USE_PTHREADS_INIT)
+ SET(SRC ${SRC} pthread_start.c pthread_support.c pthread_stop_world.c)
+ IF( "HOST" MATCHES x86-.*-linux.*|ia64-.*-linux.*|i586-.*-linux.*|i686-.*-linux.*|x86_64-.*-linux.*|alpha-.*-linux.*|sparc.*-.*-linux.*)
+ ADD_DEFINITIONS("-DGC_LINUX_THREADS")
+ ADD_DEFINITIONS("-D_REENTRANT")
+ IF (${enable_parallel_mark})
+ ADD_DEFINITIONS("-DPARALLEL_MARK")
+ ENDIF()
+ ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
+ MESSAGE("Explicit GC_INIT() calls may be required.")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-linux.*)
+ ADD_DEFINITIONS("-DGC_LINUX_THREADS")
+ ADD_DEFINITIONS("-D_REENTRANT")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-aix.*)
+ ADD_DEFINITIONS("-DGC_AIX_THREADS")
+ ADD_DEFINITIONS("-D_REENTRANT")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-hpux11.*)
+ MESSAGE("Only HP/UX 11 POSIX threads are supported.")
+ ADD_DEFINITIONS("-DGC_HPUX_THREADS")
+ ADD_DEFINITIONS("-D_POSIX_C_SOURCE=199506L") #TODO test -DVAR=value. Alternative is COMPILE_DEFINITIONS property
+ IF (${enable_parallel_mark})
+ ADD_DEFINITIONS("-DPARALLEL_MARK")
+ ENDIF()
+ MESSAGE("Explicit GC_INIT() calls may be required.")
+ ADD_DEFINITIONS("-D_REENTRANT") #TODO
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-hpux10.*)
+ MESSAGE("Only HP/UX 11 POSIX threads are supported.")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-openbsd.*)
+ ADD_DEFINITIONS("-DGC_OPENBSD_THREADS")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-freebsd.*)
+ MESSAGE("FreeBSD does not yet fully support threads with Boehm GC.")
+ ADD_DEFINITIONS("-DGC_FREEBSD_THREADS")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-kfreebsd.*-gnu)
+ ADD_DEFINITIONS("-DGC_FREEBSD_THREADS")
+ ADD_DEFINITIONS("-D_REENTRANT")
+ IF (${enable_parallel_mark})
+ ADD_DEFINITIONS("-DPARALLEL_MARK")
+ ENDIF()
+ ADD_DEFINITIONS(THREAD_LOCAL_ALLOC")
+ ADD_DEFINITIONS(USE_COMPILER_TLS")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-gnu.*)
+ ADD_DEFINITIONS("-DGC_GNU_THREADS")
+ ADD_DEFINITIONS("-D_REENTRANT")
+ ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-netbsd.*)
+ MESSAGE("Only on NetBSD 2.0 or later.")
+ ADD_DEFINITIONS("-DGC_NETBSD_THREADS")
+ ADD_DEFINITIONS("-D_REENTRANT")
+ ADD_DEFINITIONS("-D_PTHREADS")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-solaris.*)
+ ADD_DEFINITIONS("-DGC_SOLARIS_THREADS")
+ ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
+#TODO
+# if test "$GCC" != yes; then
+# CFLAGS="$CFLAGS -O"
+# need_atomic_ops_asm=true
+# fi
+
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-irix.*)
+ ADD_DEFINITIONS("-DGC_IRIX_THREADS")
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-cygwin.*)
+ ADD_DEFINITIONS("-DGC_THREADS")
+ IF (${enable_parallel_mark})
+ ADD_DEFINITIONS("-DPARALLEL_MARK")
+ ENDIF()
+ ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
+
+#TODO
+# win32_threads=true
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-darwin.*)
+ ADD_DEFINITIONS("-DGC_DARWIN_THREADS")
+ ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
+ MESSAGE("Explicit GC_INIT() calls may be required.")
+ SET(SRC ${SRC} darwin_stop_world.c)
+ IF (${enable_parallel_mark})
+ ADD_DEFINITIONS("-DPARALLEL_MARK")
+ ENDIF()
+ #TODO
+ #darwin_threads=true
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-osf*)
+ ADD_DEFINITIONS("-DGC_OSF1_THREADS")
+ IF (${enable_parallel_mark})
+ ADD_DEFINITIONS("-DPARALLEL_MARK")
+ ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
+ MESSAGE("Explicit GC_INIT() calls may be required.")
+ # May want to enable it in other cases, too.
+ # Measurements haven't yet been done.
+ ENDIF()
+ ENDIF()
+ IF ( "HOST" MATCHES .*-.*-linux.*)
+ ADD_DEFINITIONS("-DGC_LINUX_THREADS")
+ ADD_DEFINITIONS("-D_REENTRANT")
+ ENDIF()
+ENDIF(CMAKE_USE_PTHREADS_INIT)
+
+IF(CMAKE_USE_WIN32_THREADS_INIT)
+ ADD_DEFINITIONS("-DGC_THREADS")
+ #win32_threads=true TODO
+ IF (${enable_parallel_mark})
+ ADD_DEFINITIONS("-DPARALLEL_MARK")
+ ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
+ ENDIF()
+ ADD_DEFINITIONS("-DEMPTY_GETENV_RESULTS") #TODO test
+ SET(SRC ${SRC} win32_threads.c)
+ENDIF(CMAKE_USE_WIN32_THREADS_INIT)
+
+OPTION(enable_gcj_support "Support for gcj" NO)
+IF(enable_gcj_support)
+ ADD_DEFINITIONS("-DGC_GCJ_SUPPORT")
+ENDIF(enable_gcj_support)
+
+
+ADD_LIBRARY( gc-lib STATIC ${SRC})
+SET_TARGET_PROPERTIES(gc-lib PROPERTIES
+ COMPILE_DEFINITIONS GC_NOT_DLL)
+#TODO TARGET_LINK_LIBRARIES(... ... ${LIBS})
+
+ADD_LIBRARY( gcmt-lib STATIC ${SRC})
+SET_TARGET_PROPERTIES(gcmt-lib PROPERTIES
+ COMPILE_DEFINITIONS GC_NOT_DLL)
+
+ADD_LIBRARY( gcmt-dll SHARED ${SRC})
+
+IF(WIN32)
+ ADD_EXECUTABLE(cord cord/cordbscs.c cord/cordxtra.c
+ cord/tests/de.c cord/tests/de_win.c)
+ SET_TARGET_PROPERTIES(cord PROPERTIES WIN32_EXECUTABLE TRUE)
+ SET_TARGET_PROPERTIES(cord PROPERTIES
+ COMPILE_DEFINITIONS GC_NOT_DLL)
+ TARGET_LINK_LIBRARIES(cord gc-lib)
+ TARGET_LINK_LIBRARIES(cord gdi32)
+ENDIF(WIN32)
+
+ADD_SUBDIRECTORY(tests)
diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
new file mode 100644
index 00000000000..b2a241e2d6f
--- /dev/null
+++ b/boehm-gc/ChangeLog
@@ -0,0 +1,8275 @@
+
+== [7.3alpha4] (development) ==
+
+* Add GC_push_all/conditional() to GC public API.
+* Add note about 'pkg-config' solving problem with autoconf 2.68 or older.
+* Add public GC_set/get_abort_func to replace default GC_on_abort.
+* Add public setter and getter for GC_push_other_roots.
+* Add thread suspend/resume signals public setters (POSIX threads).
+* Call GC_on_abort (with NULL argument) on exit(1).
+* Check GC_base result in GC_print_all_smashed_proc.
+* Check traceable_allocator.allocate result before dereference in test_cpp.
+* Code refactoring of GC_x_printf (move shared code to macro).
+* Define old_bus_handler static variable only if used (Unix).
+* Disable find-leak GC_gcollect on GC abnormal EXIT.
+* Do not define _setjmp/_longjmp macros in mach_dep.c.
+* Elaborate comment on dependencies in autogen.sh.
+* Eliminate 'cast from int to pointer' warning in GC_exclude_static_roots.
+* Eliminate 'missing exception specification' warning in gc_cpp.cc (Clang).
+* Eliminate 'uninitialized variable use' warning in test_printf (cord).
+* Eliminate 'unused result' compiler warning in main() of test_cpp.
+* Eliminate 'unused value' compiler warning in GC_stop_world (Pthreads).
+* Eliminate Clang warning for GC_pthread_exit attribute.
+* Eliminate GCC warning in GC_get_main_stack_base (OpenBSD).
+* Eliminate GCC warnings in setjmp_t.c, test_cpp and cord 'de' app.
+* Eliminate SIGBUS-related dead code in GC_write_fault_handler (Linux).
+* Eliminate warning and simplify expression in GC_init_explicit_typing.
+* Enable 'force GC at every GC_malloc' debug-related functionality.
+* Fix GC_CreateThread and GC_beginthreadex definition for Cygwin.
+* Improve staticrootstest checks (tests).
+* Include "config.h" instead of "private/config.h" on HAVE_CONFIG_H.
+* Include proper header file in 'tools' for configuration macros.
+* Include pthread_np.h from pthread_stop_world.c on OpenBSD.
+* Log error messages to stderr instead of stdout in tests.
+* Minimize code duplication in GC_mark_and_push.
+* Move 'include setjmp.h' from mach_dep.c to gc_priv.h.
+* Move GC_get_suspend/thr_restart_signal to misc.c for NaCl and OpenBSD.
+* Port BDWGC to Android/x86.
+* Postpone the suspend signal in GC_dirty_init only if used to stop world.
+* Put gc_cpp symbols into 'boehmgc' namespace if GC_NAMESPACE defined.
+* Recognize GC_DONT_GC macro in gc.h (causes GC_INIT to turn off GC).
+* Recognize GC_SIG_SUSPEND and GC_SIG_THR_RESTART tuning macros in gc.h.
+* Remove nested EXPECT in GC_core_finalized_malloc.
+* Remove nested always-false ifdef for HPUX and FREEBSD.
+* Replace SIG_SUSPEND/THR_RESTART macros to variables in pthread_stop_world.
+* Replace sprintf with defensive snprintf.
+* Replace var-args GC_noop with GC_noop6 (to eliminate Clang warning).
+* Specify GC_malloc result is unused in some tests.
+* Specify GC_pthread_join result is unused in threadkey_test.
+* Turn off GC_LOOP_ON_ABORT functionality if GC compiled with NO_DEBUGGING.
+* Use memcpy (BCOPY) instead of strcpy (to suppress GCC warning).
+
+
+== [7.3alpha2] 2012-05-11 ==
+
+* Add 'const' qualifier to pointer argument of some API functions.
+* Add GC_UNDERSCORE_STDCALL, UNICODE macro templates to configure (Win32).
+* Add GC_get_thr_restart_signal, GC_thread_is_registered to GC API.
+* Add GC_is_heap_ptr, GC_move_disappearing_link to GC API.
+* Add SHORT_DBG_HDRS macro template to configure.
+* Add Symbian port to mainline.
+* Add TODO file.
+* Add assertion ensuring proper alignment of 'pushed' GC symbols.
+* Add assertion in GC_getspecific on qtid.
+* Add assertion to GC_incremental_protection_needs, refine documentation.
+* Add assertion to check GC_large_free_bytes by GC_finish_collection.
+* Add configure option to compile all library .c files into single gc.o.
+* Add cordtest to make check.
+* Add disclaim callbacks for efficient finalization (ENABLE_DISCLAIM).
+* Add finalization.html to 'doc' folder.
+* Add javaxfc.h to the installation set of GC header files (configure).
+* Add on-heap-resize event notification to API.
+* Adjust GC_log_printf format specifiers (regarding signed/unsigned long).
+* Adjust GC_requested_heapsize on GC_init if GC_INITIAL_HEAP_SIZE given.
+* Allow GC_exclude_static_roots() region start to be unaligned.
+* Allow Win32 DllMain chaining on the client side.
+* Allow to exclude finalization support by GC_NO_FINALIZATION macro.
+* Allow to get memory via Win32 VirtualAlloc (USE_WINALLOC) on Cygwin.
+* Avoid unnecessary GC_find_limit invocation if GC_no_dls.
+* Avoid use of deprecated GC_dont_gc and GC_stackbottom in gctest.
+* Cast pointers to word (instead of unsigned long) in specific.h.
+* Changed the order in autogen.sh so ltmain exists in time for automake.
+* Declare privately and use handy GC_base_C() for constant object pointers.
+* Define GC_DLL if DLL_EXPORT at GC build (for Cygwin/MinGW).
+* Define GC_READ_ENV_FILE in configure for WinCE unless gc-debug is off.
+* Do not compile backgraph.c unless configure '--enable-gc-debug'.
+* Do not compile pthread_stop_world.c for Cygwin/Darwin (configure).
+* Do not install ancient new_gc_alloc.h broken for modern STL (configure).
+* Enable GC_MIN_MARKERS to set minimal number of pthread-based markers.
+* Enable PARALLEL_MARK and THREAD_LOCAL_ALLOC for FreeBSD in configure.
+* Enable parallel mark by default in configure (Darwin/Linux/Solaris/Win32).
+* Export GC_is_marked, GC_clear/set_mark_bit (for mark-bit manipulation).
+* Extend thread-related debug messages.
+* Fix 'configure --enable-cplusplus' for Cygwin/MinGW.
+* Fix DATASTART (and other minor improvements) for NaCl target.
+* Fix GC_setspecific to prevent garbage collection inside.
+* Fix compiler warning in cordtest.
+* Fix minor warnings reported by GCC with '-pedantic' option.
+* Fix static data roots registration on Android (if GC is shared).
+* Implement GC_get_stack_base for Darwin for single-threaded mode.
+* Improve GC_allochblk algorithm of block splitting when unmapping enabled.
+* Improve GC_collect_or_expand algorithm for many finalizers registered case.
+* In tests, print a message in case a test is a no-op.
+* Instruct configure to hide internal libgc.so symbols if supported by GCC.
+* Log amount of unmapped memory (if enabled) on marking-for-collection.
+* Make __data_start a weak symbol to allow loading modules on mips.
+* Move "cord" library tests to "cord/tests" folder.
+* Move asm machine-dependent files to "src" folder.
+* Move build tools sources to "tools" folder.
+* Move cord_pos.h to public headers folder.
+* Open log file in APPEND mode on Win32 (similar that on Unix/Cygwin).
+* Optimize some functions by moving pthread_self calls out of LOCK section.
+* Place only major per-release changes description to ChangeLog (this file).
+* Prevent compiler warnings in GC_FindTopOfStack and GC_ports (Darwin).
+* Recognize GC_LOG_TO_FILE_ALWAYS macro to log to 'gc.log' by default.
+* Remove all auto-generated files from the repo.
+* Remove binary icon file for de_win.
+* Remove cordtest from "cord" library.
+* Remove duplicate MacOS_Test_config.h file.
+* Remove gc_amiga_redirects.h (included internally) from public headers.
+* Remove obsolete Makefile.DLL (superseded by Cygwin/MinGW configure).
+* Remove obsolete unused asm files for ALPHA, HPUX, SGI, RS6000, ULTRIX.
+* Remove unsupported MMAP_STACKS (specific to Solaris threads).
+* Remove unused ancient SILENT, __STDC__, NO_SIGNALS macros.
+* Replace ARGSUSED comment-based annotation with GCC 'unused' attribute.
+* Replace GC_ms_entry declaration with opaque definition for public API.
+* Replace long GC_markers global variable with int GC_markers_m1.
+* Replace pointer relational comparisons with non-pointer ones.
+* Replace printf PRIxMAX specifier with '%p' for thread id debug output.
+* Require autoconf 2.61 instead of v2.64.
+* Simplify autogen.sh (use autoreconf).
+* Split GC_abort with GC_on_abort and abort() invoked from ABORT.
+* Support GC_ATTR_MALLOC for MS VisualStudio.
+* Tag auxiliary malloc-like API functions with 'malloc' attribute.
+* Tag deprecated variables in GC API.
+* Tag must-be-non-null arguments of GC API functions.
+* Turn on "extra" GCC warnings.
+* Turn on unused-parameter checking for GCC.
+* Update AUTHORS file.
+* Use EXPECT for checking various 'initialized' boolean variables.
+* Use USE_COMPILER_TLS on Cygwin.
+* Use pthread_key for thread-local storage on FreeBSD.
+* Use union of AO_t and word to favor strict-aliasing compiler optimization.
+
+
+== [7.2e] (candidate) ==
+
+* Fix GC_clear_stack by declaring 'dummy' local array as volatile.
+* Fix GC_get_stack_base assembly code (Cygwin/Clang).
+* Fix GC_unix_mmap_get_mem for open of /dev/zero failure.
+* Fix min_bytes_allocd preventing potential infinite loop in GC_allocobj.
+* Fix null-pointer dereference in CORD_substr_closure.
+* Fix potential double fclose in test_extras (cordtest).
+* Fix pthread_attr_t resource leak in pthread_create.
+* Fix sizeof in GC_push_thread_structures.
+* Fix unportable '==' test operators in configure.
+* Fix vsprintf_args cleanup in CORD_vsprintf.
+
+
+== [7.2d] 2012-08-09 ==
+
+* Fix GC_call_with_stack_base to prevent its tail-call optimization.
+* Fix all address-of-dummy operations by using GC_approx_sp() instead.
+* Fix stop_info.stack_ptr assignment in GC_suspend_all for OpenBSD.
+* Fix test_cpp (ensure the collector recognizes pointers to interiors).
+* Fix thread-related tests for pthreads-w32.
+* test_cpp: Fix WinMain to prevent SEGV if zero arguments passed (MinGW).
+
+
+== [7.2c] 2012-06-11 ==
+
+* Fix CORD_cat_char_star to prevent SEGV in case of out-of-memory.
+* Fix GC_FirstDLOpenedLinkMap() for NetBSD 6 release.
+* Fix GC_scratch_alloc and GC_get_maps invocations to prevent SEGV.
+* Fix visibility of GC_clear/set_mark_bit (unhide symbols).
+* Fix visibility of GC_push_all/conditional, GC_push_other_roots symbols.
+
+
+== [7.2b] 2012-05-23 ==
+
+* Fix assertion in GC_malloc_[atomic_]uncollectable (THREADS case only).
+
+
+== [7.2] 2012-05-11 ==
+
+* Abort in GC_thr_init on pthread_atfork failure (POSIX threads).
+* Add GC_WIN32_PTHREADS target in configure.
+* Add GC_is_disabled new function to GC API.
+* Add info that getcontext() resets FPE mask no longer on Linux/x86_64.
+* Add public GC_set_handle_fork to control forked child handling support.
+* Add realloc_test.c test.
+* Add support for Hexagon target.
+* Add thread-safe GC_get_heap_usage_safe to GC API.
+* Change GC_check_fl_marks prototype and implementation.
+* Check pthread_create/join result in test.
+* Define GC_DLL (in configure) if building only dynamic libraries.
+* Define NO_DEBUGGING (in configure) if "--disable-gc-debug" is set.
+* Disable incremental mode on Darwin if fork handling requested.
+* Enable parallel marker in configure for Solaris.
+* Fix "comparison of signed and unsigned values" compiler warnings.
+* Fix 'volatile' keyword placement in GC_SysVGetDataStart.
+* Fix ALIGNMENT, CPP_WORDSZ, GC_GRANULE_BYTES/WORDS for x32 target.
+* Fix GC_READ_ENV_FILE code for Cygwin.
+* Fix GC_add_roots_inner for Mac OS X (align segment start).
+* Fix GC_check_fl_marks regarding concurrent access.
+* Fix GC_finalizer_nested size to workaround alignment problem in Watcom.
+* Fix GC_find_limit_with_bound to always reset fault handler on return.
+* Fix GC_init static assertion for clang/x64 (Darwin).
+* Fix GC_init[_lib_bounds] and GC_get_main_stack_base for malloc redirection.
+* Fix GC_push_all/selected boundaries check.
+* Fix GC_register_my_thread marking thread as detached (Cygwin/pthreads-w32).
+* Fix GC_remove_all_threads_but_me to cleanup thread-specific data storage.
+* Fix GC_restart_handler to preserve errno if needed.
+* Fix GC_root_size update in GC_add_roots_inner (Win32).
+* Fix GC_unregister_my_thread to ensure no ongoing incremental GC (Win32).
+* Fix GC_with_callee_saves_pushed for clang (disable __builtin_unwind_init).
+* Fix calloc, GC_generic_malloc to check for allocation size overflows.
+* Fix compiler warning in GC_dyld_image_add/remove (Darwin).
+* Fix configure --enable-cplusplus make install.
+* Fix configure to disable GCC aliasing optimization unless forced to.
+* Fix duplicate definitions in gcconfig.h for NetBSD.
+* Fix fork() support on Cygwin and Darwin targets.
+* Fix gc.h compatibility regression regarding GC_PTR, GC_I_HIDE_POINTERS.
+* Fix gc_cpp.cc for Cygwin (remove duplicate function definition).
+* Fix gcconfig.h to define USE_GET_STACKBASE_FOR_MAIN for Android.
+* Fix gcconfig.h to handle mips64-linux target.
+* Fix gctest (for Win32) to avoid GC_print_stats internal variable usage.
+* Fix mach_dep.c to include sys/ucontext.h on Mac OS X 10.6.
+* Fix tests to check GC_malloc result for NULL (out-of-memory).
+* Fix thread model in configure for MinGW ("win32" instead of "posix").
+* Fix various warnings reported by LINT-like tools.
+* Fix visibility of some GC internal symbols used by GNU GCJ currently.
+* Port some thread tests to Win32.
+* Refine API GC setters and getter comments regarding locking.
+* Refine GC_stackbottom description in gc.h.
+* Remove duplicate calls in GC_register_dynamic_libraries.
+* Remove locking in API GC_get_bytes_since_gc and friends.
+* Remove newly-added GC_get_heap_size/free_bytes_inner from API.
+* Remove some local variables that are unused.
+* Support multi-threading for RTEMS target.
+* Use global GC_noop_sink variable in GC_noop1 to suppress compiler warning.
+* Use pkg-config to pick up libatomic_ops, etc.
+* Workaround some Linux/arm kernels bug to get correct GC_nprocs value.
+
+
+== [7.2alpha6] 2011-06-14 ==
+
+* configure_atomic_ops.sh: Remove.
+* Makefile.direct (dist gc.tar): Remove configure_atomic_ops.sh.
+* Makefile.am (EXTRA_DIST): Add autogen.sh.
+
+* NT_STATIC_THREADS_MAKEFILE (.cpp.obj): Remove duplicate .cpp
+filename passed.
+* NT_X64_THREADS_MAKEFILE (.cpp.obj): Use lowercase file
+extension.
+* NT_X64_STATIC_THREADS_MAKEFILE (.cpp.obj): Likewise.
+* NT_MAKEFILE (.cpp.obj): Likewise.
+
+* alloc.c (GC_add_current_malloc_heap, GC_build_back_graph,
+GC_traverse_back_graph): Move prototype to gc_priv.h.
+* checksums.c (GC_page_was_ever_dirty): Likewise.
+* dbg_mlc.c (GC_default_print_heap_obj_proc): Likewise.
+* dyn_load.c (GC_parse_map_entry, GC_get_maps,
+GC_segment_is_thread_stack, GC_roots_present, GC_is_heap_base,
+GC_get_next_stack): Likewise.
+* finalize.c (GC_reset_finalizer_nested,
+GC_check_finalizer_nested): Likewise.
+* gcj_mlc.c (GC_start_debugging, GC_store_debug_info): Likewise.
+* malloc.c (GC_extend_size_map, GC_text_mapping): Likewise.
+* mark_rts.c (GC_mark_thread_local_free_lists): Likewise.
+* misc.c (GC_register_main_static_data, GC_init_win32,
+GC_setpagesize, GC_init_linux_data_start,
+GC_set_and_save_fault_handler, GC_init_dyld, GC_init_netbsd_elf,
+GC_initialize_offsets, GC_bl_init, GC_do_blocking_inner,
+GC_bl_init_no_interiors): Likewise.
+* os_dep.c (GC_greatest_stack_base_below, GC_push_all_stacks):
+Likewise.
+* reclaim.c (GC_check_leaked): Likewise.
+* win32_threads.c (GC_gww_dirty_init): Likewise.
+* darwin_stop_world.c (GC_is_mach_marker, GC_mprotect_stop,
+GC_mprotect_resume): Move prototype to darwin_stop_world.h.
+* pthread_support.c (GC_FindTopOfStack): Likewise.
+* dyn_load.c (GC_cond_add_roots): Merge adjacent definitions.
+* mark.c (GC_page_was_ever_dirty): Remove (as already declared).
+* mark_rts.c (GC_roots_present): Change return type to void
+pointer (to match the prototype); return NULL instead of FALSE.
+* mark_rts.c (GC_add_roots_inner): Cast GC_roots_present() result.
+* os_dep.c (NEED_PROC_MAPS): Move definition to gcconfig.h.
+* os_dep.c (GC_write_fault_handler): Make STATIC.
+* os_dep.c (GC_set_write_fault_handler): New function (only if
+GC_WIN32_THREADS).
+* pthread_start.c (GC_start_rtn_prepare_thread,
+GC_thread_exit_proc): Move prototype to pthread_support.h.
+* pthread_support.c (GC_nacl_initialize_gc_thread,
+GC_nacl_shutdown_gc_thread, GC_unblock_gc_signals):
+Likewise.
+* pthread_support.c (GC_stop_init): Move prototype to
+pthread_stop_world.h.
+* win32_threads.c (GC_write_fault_handler): Remove prototype.
+* win32_threads.c (GC_register_my_thread_inner): Call
+GC_set_write_fault_handler instead of SetUnhandledExceptionFilter
+(only if MPROTECT_VDB).
+* doc/README.win32: Add information about DMC.
+* include/private/gc_priv.h (GC_set_write_fault_handler): New
+prototype (only if GC_WIN32_THREADS and MPROTECT_VDB).
+
+* misc.c (vsnprintf): Redirect to vsprintf() if NO_VSNPRINTF.
+
+* win32_threads.c (GC_unregister_my_thread): Use KNOWN_FINISHED()
+instead of FINISHED macro.
+* tests/test.c (check_heap_stats): Round up max_heap_sz value for
+Win32 (same as for USE_MMAP).
+
+* tests/test.c (check_heap_stats): Adjust printf format specifier
+for max_heap_sz; cast max_heap_sz accordingly.
+
+* doc/README.solaris2: Add note.
+
+* configure.ac (SOLARIS25_PROC_VDB_BUG_FIXED): Don't define for
+Solaris/x86 2.10+.
+
+* tests/threadkey_test.c (SKIP_THREADKEY_TEST): Skip the test if
+defined; explicitly define for some targets.
+
+* mark.c (GC_dirty): Add prototype (only if MANUAL_VDB).
+* stubborn.c (GC_dirty): Likewise.
+* include/private/gcconfig.h (GWW_VDB, MPROTECT_VDB, PCR_VDB,
+PROC_VDB): Undefine if MANUAL_VDB.
+* include/private/gcconfig.h (DEFAULT_VDB): Don't define if
+MANUAL_VDB.
+* os_dep.c (async_set_pht_entry_from_index): Define for
+MANUAL_VDB.
+* os_dep.c (GC_read_dirty): Set GC_dirty_maintained only if
+success; if ioctl() failed then just print warning instead of
+aborting.
+
+* include/private/gc_priv.h (GC_ASSERT): Use "%d" (instead of %ld)
+for line number printing.
+
+* os_dep.c (GC_read_dirty): Add debug logging if DEBUG_DIRTY_BITS
+(for PROC_VDB only); print errors via GC_err_printf; rename "ps"
+and "np" local variables to npages and pagesize, respectively;
+remove "current_addr" local variable.
+
+* os_dep.c (GC_get_main_stack_base): Convert to GC_get_stack_base
+for BeOS and OS/2; define HAVE_GET_STACK_BASE.
+* os_dep.c (GET_MAIN_STACKBASE_SPECIAL): Define when a specific
+GC_get_main_stack_base implementation is defined.
+* os_dep.c (GC_get_main_stack_base): Define that based on
+GC_get_stack_base() in a single place (only if
+GET_MAIN_STACKBASE_SPECIAL is unset); check GC_get_stack_base()
+result.
+
+* mark.c (GC_push_selected): Remove "push_fn" argument (use
+GC_push_all directly); update the documentation.
+* mark.c (GC_push_conditional): Simplify the code (for better
+readability).
+
+* mark.c (alloc_mark_stack): Use FALSE/TRUE (instead of 0/1) for
+boolean local variables.
+* doc/README.macros (GC_PREFER_MPROTECT_VDB): Update.
+* os_dep.c (GC_page_was_dirty, GC_page_was_ever_dirty,
+GC_remove_protection): Define for GWW_VDB and PROC_VDB in a single
+place.
+* os_dep.c (GC_page_was_dirty, GC_page_was_ever_dirty): Compute
+PHT_HASH(h) only once (store result to a local variable).
+
+* doc/README.solaris2: Update.
+
+* include/private/gcconfig.h (end, InitStackBottom): Declare
+extern variable for RTEMS.
+* include/private/gcconfig.h (DATASTART, DATAEND, STACKBOTTOM):
+Update (for RTEMS).
+* include/private/gcconfig.h (DATAEND): Fix a typo in the macro
+name (for RTEMS).
+* tests/test.c (CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER):
+Replace with CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER (for RTEMS).
+
+* include/private/gcconfig.h (MPROTECT_VDB): Enable for Solaris in
+single-threaded environment.
+
+* include/private/gcconfig.h (MPROTECT_VDB): Undefine if PROC_VDB.
+* tests/test.c (NUMBER_ROUND_UP): New macro.
+* tests/test.c (check_heap_stats): Round up total expected heap
+size to the nearest 4 MiB bound.
+* tests/test.c (check_heap_stats): Print the current and expected
+heap sizes in case of failure.
+
+* checksums.c (GC_check_blocks, GC_check_dirty): Do log printing
+only if GC_print_stats; print errors using GC_err_printf.
+* checksums.c (GC_check_blocks): Join adjacent printf() calls into
+a single one.
+
+* pthread_support.c (pthread_join): Add assertion (check thread is
+finished).
+* pthread_support.c (GC_register_my_thread): Don't detach the
+thread if invoked from the thread destructor.
+* win32_threads.c (GC_register_my_thread): Likewise.
+* win32_threads.c (GC_unregister_my_thread): Don't delete the
+thread (just set FINISHED) if the thread is not detached (only if
+GC_PTHREADS); add assertion (check the thread is not finished).
+* tests/threadkey_test.c (main): Join some created threads.
+
+* pthread_support.c (GC_delete_gc_thread): Rename "gc_id" local
+variable to "t".
+* win32_threads.c (GC_delete_gc_thread): Likewise.
+* pthread_support.c (pthread_join, pthread_detach,
+pthread_cancel): Rename "thread_gc_id" local variable to "t".
+* win32_threads.c (GC_pthread_detach): Likewise.
+* win32_threads.c (GC_delete_gc_thread): Remove "gc_nvid" local
+variable.
+* win32_threads.c (GC_pthread_join): Rename "joinee" local
+variable to "t".
+
+* pthread_stop_world.c (pthread_sigmask): Undefine even if not
+DEBUG_THREADS.
+* pthread_stop_world.c (GC_unblock_gc_signals): New function (only
+if GC_EXPLICIT_SIGNALS_UNBLOCK).
+* pthread_support.c (GC_unblock_gc_signals): New prototype.
+* pthread_support.c (GC_register_my_thread_inner,
+GC_register_my_thread): Call GC_unblock_gc_signals (only if
+GC_EXPLICIT_SIGNALS_UNBLOCK); add comment.
+* include/private/gcconfig.h (GC_EXPLICIT_SIGNALS_UNBLOCK): New
+macro.
+
+* pthread_stop_world.c (GC_suspend_handler_inner): Remove "dummy",
+"sig" local variables; rename my_thread local variable to "self".
+
+* tests/threadkey_test.c (LIMIT): Use smaller value (don't create
+more than 30 in parallel by default).
+
+* tests/threadkey_test.c (key_once, main): Work around for Solaris
+PTHREAD_ONCE_INIT.
+* tests/threadkey_test.c (LIMIT): Use smaller value for Solaris.
+
+* dyn_load.c (GC_FirstDLOpenedLinkMap): Remove unused "r" local
+variable.
+* pthread_support.c (GC_unregister_my_thread_inner): Revert back
+GC_remove_specific invocation; add a comment.
+* include/private/thread_local_alloc.h (GC_remove_specific):
+Revert back.
+* specific.c (slow_getspecific): Cast qtid to AO_t.
+* include/private/specific.h (key_create, setspecific,
+remove_specific): Remove "extern" keyword.
+* include/private/specific.h (getspecific): Change type of "qtid"
+local variable to unsigned long.
+
+* pthread_support.c (GC_check_tls): Fix "#endif" comment.
+* include/gc.h (GC_REDIRECT_TO_LOCAL): Remove deprecated comment.
+* include/private/thread_local_alloc.h (THREAD_LOCAL_ALLOC):
+Remove redundant test of the macro.
+
+* backgraph.c (add_edge): Recognize DEBUG_PRINT_BIG_N_EDGES macro.
+* os_dep.c (GC_set_and_save_fault_handler): Recognize
+SIGACTION_FLAGS_NODEFER_HACK macro.
+* pthread_support.c (mark_mutex): Recognize GLIBC_2_1_MUTEX_HACK
+macro.
+* pthread_support.c (GC_acquire_mark_lock): Remove commented out
+code.
+* include/private/gc_priv.h (SUNOS5SIGS): Don't include
+sys/siginfo.h on Linux.
+* include/private/gcconfig.h (FORCE_WRITE_PREFETCH): New macro
+recognized, force PREFETCH_FOR_WRITE to be defined on x86.
+* include/private/gcconfig.h (USE_HPUX_FIXED_STACKBOTTOM): New
+macro recognized (for HP/UX).
+
+* os_dep.c (GC_gww_page_was_ever_dirty): Fix comment (for
+GWW_VDB).
+* os_dep.c (GC_dirty_init): Use memset() for GC_written_pages
+resetting (for PROC_VDB).
+
+* tests/threadkey_test.c: New file.
+* tests/tests.am (TESTS, check_PROGRAMS): Add 'threadkey_test'.
+* tests/tests.am (threadkey_test_SOURCES, threadkey_test_LDADD):
+New variable.
+
+* pthread_support.c (GC_unregister_my_thread_inner): Don't call
+GC_remove_specific.
+* include/private/thread_local_alloc.h (GC_remove_specific):
+Remove (since it is empty for all targets).
+* pthread_support.c (GC_record_stack_base): New inline function.
+* win32_threads.c (GC_record_stack_base): Likewise.
+* pthread_support.c (GC_register_my_thread_inner): Invoke
+GC_record_stack_base.
+* win32_threads.c (GC_register_my_thread_inner): Likewise.
+* pthread_support.c (GC_register_my_thread): If thread is FINISHED
+then call GC_record_stack_base, clear FINISHED, initialize
+thread-local list and return success.
+* win32_threads.c (GC_register_my_thread): Likewise.
+* include/gc.h (GC_register_my_thread): Update documentation.
+* include/private/thread_local_alloc.h (GC_thread_key): Likewise.
+
+* thread_local_alloc.c (GC_malloc, GC_malloc_atomic): Join
+adjacent "#ifdef".
+* thread_local_alloc.c (GC_malloc_atomic): Call
+GC_core_malloc_atomic (instead of GC_core_malloc).
+
+* pthread_start.c (GC_start_rtn_prepare_thread): Change return
+type to GC_thread.
+* pthread_start.c (GC_inner_start_routine): Pass the current
+thread descriptor to pthread_cleanup_push (same as in
+win32_threads.c).
+* pthread_stop_world.c (GC_push_all_stacks): Rename "me" local
+variable to "self".
+* win32_threads.c (GC_push_all_stacks): Likewise.
+* pthread_stop_world.c (GC_suspend_all, GC_start_world): Rename
+"my_thread" local variable to "self".
+* pthread_support.c (GC_unregister_my_thread_inner): New static
+function.
+* pthread_support.c (GC_unregister_my_thread,
+GC_thread_exit_proc): Use GC_unregister_my_thread_inner.
+* win32_threads.c (GC_register_my_thread, GC_unregister_my_thread,
+GC_do_blocking_inner): Rename "t" local variable to "thread_id".
+* win32_threads.c (GC_wait_marker, GC_notify_all_marker): Rename
+"id" local variable to "thread_id".
+
+* pthread_support.c (GC_unregister_my_thread): Call pthread_self
+only once.
+* win32_threads.c (GC_pthread_start_inner): Likewise.
+* pthread_support.c (GC_unregister_my_thread): Add debug output.
+* win32_threads.c (GC_unregister_my_thread): Likewise.
+* pthread_support.c (GC_register_my_thread,
+GC_start_rtn_prepare_thread): Rename "my_pthread" local variable
+to "self".
+
+* include/gc.h (GC_HIDE_POINTER, GC_REVEAL_POINTER): Define
+unconditionally (do not test GC_I_HIDE_POINTERS); update the
+comment.
+* include/gc.h (HIDE_POINTER, REVEAL_POINTER): Define as alias to
+GC_HIDE/REVEAL_POINTER, respectively.
+* include/private/gc_pmark.h (GC_I_HIDE_POINTERS): Do not define.
+* include/private/gc_priv.h (GC_I_HIDE_POINTERS): Likewise.
+
+* include/gc.h (GC_register_my_thread): Refine the comment.
+
+* include/gc_inline.h (GC_MALLOC_WORDS, GC_CONS): Add missing
+parentheses.
+* include/gc_typed.h (GC_get_bit, GC_set_bit,
+GC_CALLOC_EXPLICITLY_TYPED): Likewise.
+
+* include/private/gcconfig.h (NO_GETCONTEXT): Add missing ')'.
+
+* include/private/gcconfig.h (NO_GETCONTEXT): Do not use
+getcontext(2) on m68k because it is not implemented there.
+
+* alloc.c (GC_clear_a_few_frames): Use BZERO().
+* mark_rts.c (GC_clear_roots, GC_rebuild_root_index): Likewise.
+* reclaim.c (GC_start_reclaim): Likewise.
+* blacklst.c (total_stack_black_listed): Remove "len" local
+variable.
+* dbg_mlc.c (GC_generate_random_valid_address): Replace "for"
+statement with "do-while" one.
+* dyn_load.c (GC_register_dynamic_libraries,
+GC_register_dynlib_callback): Remove redundant parentheses.
+
+* cord/cordxtra.c (CORD_from_file_lazy_inner): Suppress
+"unused result" compiler warning for fread().
+
+* os_dep.c (GC_write_fault_handler): Break when in_allocd_block
+is set to true.
+
+* dbg_mlc.c (GC_has_other_debug_info): Change return type to int;
+return -1 if the object has (or had) debugging info but was
+marked deallocated.
+* include/private/dbg_mlc.h (GC_has_other_debug_info): Likewise.
+* dbg_mlc.c (GC_has_other_debug_info): Update documentation;
+remove "ohdr" local variable.
+* dbg_mlc.c (GC_debug_free): Don't call GC_free if the object has
+probably been deallocated.
+* dbg_mlc.c (GC_debug_free): Don't actually free the object even
+in the leak-finding mode if GC_findleak_delay_free.
+* dbg_mlc.c (GC_check_leaked): New function (only unless
+SHORT_DBG_HDRS).
+* doc/README.environment (GC_FINDLEAK_DELAY_FREE): Document.
+* doc/README.macros (GC_FINDLEAK_DELAY_FREE): Likewise.
+* include/private/dbg_mlc.h (START_FLAG, END_FLAG): Use GC_WORD_C
+on 64-bit architectures.
+* include/private/dbg_mlc.h (NOT_MARKED): Remove redundant
+parentheses.
+* include/private/dbg_mlc.h (GC_HAS_DEBUG_INFO): Update (due to
+GC_has_other_debug_info change).
+* include/private/gc_priv.h (GC_findleak_delay_free): New global
+variable declaration (unless SHORT_DBG_HDRS).
+* misc.c (GC_findleak_delay_free): New global variable; recognize
+GC_FINDLEAK_DELAY_FREE.
+* misc.c (GC_init): Recognize GC_FINDLEAK_DELAY_FREE environment
+variable (unless SHORT_DBG_HDRS).
+* reclaim.c (GC_check_leaked): Declare (unless SHORT_DBG_HDRS).
+* reclaim.c (GC_add_leaked): Don't add the object to leaked list
+if marked as deallocated.
+
+* dbg_mlc.c (GC_has_other_debug_info): Fix punctuation in the
+comment.
+* dbg_mlc.c (GC_FREED_MEM_MARKER): New macro.
+* dbg_mlc.c (GC_debug_free): Use GC_FREED_MEM_MARKER.
+* dbg_mlc.c (GC_smashed): Refine documentation.
+* mark.c (GC_push_selected): Change dirty_fn return type to
+GC_bool.
+* os_dep.c (GC_page_was_ever_dirty): Make GC_INNER.
+* reclaim.c (GC_reclaim_small_nonempty_block): Remove "kind"
+local variable.
+* reclaim.c (GC_reclaim_block): Pass true constant to
+GC_reclaim_small_nonempty_block (instead of report_if_found).
+* doc/README.autoconf: Update; fix a typo.
+* include/private/gcconfig.h (GC_WORD_C): New macro.
+
+* dbg_mlc.c (GC_store_debug_info_inner): Cast "linenum".
+* dbg_mlc.c (GC_check_annotated_obj): Fix punctuation in the
+comment.
+* dbg_mlc.c (GC_print_smashed_obj): Add (and print) "msg"
+argument.
+* dbg_mlc.c (GC_debug_free, GC_print_all_smashed_proc): Pass
+message to GC_print_smashed_obj.
+* dbg_mlc.c (GC_debug_free): Call GC_size once.
+* dbg_mlc.c (GC_debug_realloc): Calculate old_sz only if
+allocation succeeded; remove unnecessary check for object is
+smashed (since this is done in GC_debug_free); remove "clobbered"
+local variable.
+
+* dbg_mlc.c (GC_store_debug_info_inner, GC_store_debug_info):
+Rename "integer" argument to "linenum"; change the type of the
+argument to int.
+* gcj_mlc.c (GC_store_debug_info): Likewise.
+* dbg_mlc.c (GET_OH_LINENUM): New macro.
+* dbg_mlc.c (GC_print_obj, GC_print_smashed_obj): Use
+GET_OH_LINENUM; adjust print format specifier.
+* dbg_mlc.c (GC_debug_malloc, GC_debug_malloc_ignore_off_page,
+GC_debug_malloc_atomic_ignore_off_page,
+GC_debug_generic_malloc_inner,
+GC_debug_generic_malloc_inner_ignore_off_page,
+GC_debug_malloc_stubborn, GC_debug_malloc_atomic,
+GC_debug_malloc_uncollectable,
+GC_debug_malloc_atomic_uncollectable): Remove unnecessary cast of
+"i".
+* gcj_mlc.c (GC_debug_gcj_malloc): Likewise.
+
+* os_dep.c (GC_linux_stack_base): Rename to
+GC_linux_main_stack_base.
+* os_dep.c (GC_freebsd_stack_base): Rename to
+GC_freebsd_main_stack_base; adjust error message.
+* pthread_stop_world.c (GC_stop_init): Use GC_SEM_INIT_PSHARED
+as an argument for sem_init().
+* pthread_support.c (pthread_create): Likewise.
+* pthread_support.c (pthread_create): Abort in case sem_init()
+fails.
+* include/private/gc_priv.h (GC_SEM_INIT_PSHARED): Define.
+* tests/initsecondarythread.c: Include gcconfig.h; call GC_INIT
+from main() if it should be done from the primordial thread only.
+
+* alloc.c: Don't include sys/types.h for ArmCC.
+* dyn_load.c: Likewise.
+* os_dep.c: Likewise.
+* mach_dep.c (_setjmp, _longjmp): Redirect to setjmp/longjmp for
+ArmCC.
+* mark.c (GC_noop): Define specially for ArmCC.
+* include/private/gc_priv.h (GC_noop): Likewise.
+* misc.c (GC_init): Don't test pointers comparison for ArmCC.
+* misc.c: Don't include unistd.h for ArmCC.
+* os_dep.c (pages_executable): Rename to GC_pages_executable;
+make STATIC.
+* os_dep.c (GC_unix_mmap_get_mem): Don't define for ArmCC.
+* ptr_chck.c (GC_is_visible): Explicitly cast
+(GC_DS_PER_OBJECT-GC_INDIR_PER_OBJ_BIAS) to word (to suppress
+a compiler warning).
+* include/private/gcconfig.h: Recognize __arm.
+* include/private/gcconfig.h (HBLKPTR): Define for ArmCC.
+* include/private/gcconfig.h (HBLKPTR): Add parentheses for
+"bytes" argument.
+
+* pthread_support.c (GC_get_nprocs): Don't define for Android.
+* pthread_support.c (GC_dummy_thread_local): Don't test
+GC_LINUX_THREADS.
+* include/gc_config_macros.h (GC_ADD_CALLER, GC_RETURN_ADDR):
+Define for Android.
+
+* mach_dep.c (NO_GETCONTEXT): Move to gcconfig.h.
+* os_dep.c (GC_write_fault_handler): Don't include ucontext.h if
+NO_GETCONTEXT.
+* include/private/gcconfig.h (GETPAGESIZE): Define as a sysconf
+call for Android.
+
+* include/private/gc_locks.h (WIN32_LEAN_AND_MEAN, NOSERVICE):
+Define before including windows.h.
+* include/private/gc_priv.h (WIN32_LEAN_AND_MEAN, NOSERVICE):
+Likewise.
+* include/private/thread_local_alloc.h (WIN32_LEAN_AND_MEAN,
+NOSERVICE): Likewise.
+* include/private/gc_priv.h (MS_TIME_DIFF): Avoid floating-point
+arithmetics; add a comment.
+
+* mark.c (GC_clear_hdr_marks): Don't test USE_MARK_BYTES.
+* extra/setjmp_t.c (main): Don't test USE_MARK_BITS.
+* include/private/gc_pmark.h (SET_MARK_BIT_EXIT_IF_SET): Likewise.
+* include/private/gc_pmark.h (SET_MARK_BIT_EXIT_IF_SET): Remove
+"mark_byte" local variable.
+* include/private/gc_pmark.h (OR_WORD_EXIT_IF_SET): Add a comment
+about that AO_or() is not used by GC unless USE_MARK_BITS
+explicitly set.
+* include/private/gc_priv.h (OR_WORD): Likewise.
+* include/private/gc_pmark.h (INCR_MARKS): Remove trailing ';',
+add parentheses.
+* include/private/gc_priv.h (ONES): Define before use by
+MAKE_COOLER.
+* include/private/gc_priv.h (MARK_BITS_SZ): Define where used.
+* include/private/gc_priv.h (OR_WORD): Don't define if
+USE_MARK_BYTES.
+* include/private/gcconfig.h (USE_MARK_BYTES); Remove duplicate
+definition; simplify expression.
+
+* os_dep.c (GC_get_maps): Always close the file.
+* pthread_support.c (GC_get_nprocs): Likewise.
+* os_dep.c (READ): Define similarly across the file (without
+parameters).
+* pthread_support.c (GC_get_nprocs): Use signed int type for "i"
+and "len" local variables (since read() may return -1).
+* include/private/gc_pmark.h (LONG_MULT): Add prefix/suffix
+double underscore; add "volatile" for asm.
+* include/private/gc_pmark.h (LONG_MULT): Add missing
+parentheses.
+* include/private/gc_priv.h (OR_WORD): Likewise.
+* include/private/gc_priv.h (OR_WORD): Remove unnecessary brackets
+and ';' symbol.
+
+* os_dep.c (GC_get_stack_base): Implement for Android (same as
+for Linux).
+* pthread_support.c (GC_get_nprocs): Return 1 (instead of -1) if
+failed to open "stat" file (not to issue a warning twice); update
+the comment.
+* pthread_support.c (GC_thr_init): Call sysconf() on Android to
+get the number of CPUs.
+
+* include/private/gc_priv.h (_GNU_SOURCE): Revert one of the
+recent patches regarding this macro as the macro should be set
+(to 1) before including any other system header.
+
+* doc/README.environment (GC_INITIAL_HEAP_SIZE,
+GC_MAXIMUM_HEAP_SIZE): Update.
+
+* misc.c (GC_parse_mem_size_arg): Allow 'k', 'M', 'G' suffixes in
+heap size specifier; return 0 if not a valid one.
+* include/gc_cpp.h: Explicitly define inline one-argument delete
+operator for Cygwin (as a workaround).
+* tests/test_cpp.cc (main): Suppress compiler warnings about
+"assigned value is unused".
+
+* misc.c (GC_parse_mem_size_arg): New function.
+* misc.c (GC_init): Use GC_parse_mem_size_arg().
+* pthread_stop_world.c (tkill): Declare for Android.
+
+* include/private/gc_priv.h (_GNU_SOURCE): Include features.h
+first (except for NaCl) and then define the macro to 1 if not yet.
+
+* tests/tests.am (TESTS, check_PROGRAMS): Add
+'initsecondarythread'.
+* tests/tests.am (initsecondarythread_SOURCES,
+initsecondarythread_LDADD): New variable.
+
+* dbg_mlc.c (GC_store_debug_info_inner): Always define; add
+"const" to its string argument.
+* dbg_mlc.c (GC_store_debug_info): Call GC_store_debug_info_inner.
+* dbg_mlc.c (GC_debug_free): Set GC_have_errors in case of
+smashed or previously deallocated found.
+* dbg_mlc.c (GC_check_heap_block): Replace while loop with a for
+one.
+* reclaim.c (GC_reclaim_check): Likewise.
+* dbg_mlc.c (GC_check_heap_proc): Remove redundant cast to word.
+* os_dep.c (GC_get_stack_base): Don't initialize
+stackbase_main_self/ss_sp on Solaris if thr_main() is zero (thus
+calling GC_INIT() from a non-primordial thread is possible now).
+* reclaim.c (GC_add_leaked): Turn into an inline one.
+* reclaim.c (GC_reclaim_small_nonempty_block):
+Change report_if_found type from int/word to boolean.
+* include/private/gc_priv.h (GC_start_reclaim): Likewise.
+* include/private/gc_priv.h (set_mark_bit_from_hdr,
+clear_mark_bit_from_hdr): Place closing parenthesis properly.
+
+* os_dep.c (GC_get_main_stack_base): Try to use
+pthread_attr_getstack first for Linux if THREADS.
+* doc/README.macros (USE_GET_STACKBASE_FOR_MAIN): Adjust text
+alignment.
+
+* dbg_mlc.c (GC_generate_random_backtrace_no_gc): Fix a message
+typo.
+* dbg_mlc.c (GC_debug_malloc): Add a comment (about zero size).
+* dbg_mlc.c (GC_strdup): Call GC_err_printf instead of WARN (in
+case of NULL argument).
+* dbg_mlc.c (GC_free): In case of NULL argument, just return
+(without any warning printed); eliminate "uncollectable" local
+variable.
+
+* configure.ac (THREADDLLIBS): Use alternate thread library on
+Solaris 8.
+* configure.ac (need_atomic_ops_asm): Set to true only for Sparc
+Solaris.
+* configure.ac: Don't use libdl on mips-sgi-irix6.
+
+* mach_dep.c (NO_GETCONTEXT); Define for RTEMS.
+* mach_dep.c (GC_with_callee_saves_pushed): Don't call
+__builtin_unwind_init() for RTEMS; use setjmp() without the
+leading underscore (for RTEMS).
+* tests/test.c (BIG): Use smaller value for RTEMS.
+* tests/test.c (main): Customize for RTEMS.
+
+* configure.host: Remove doubled words in comments.
+* os_dep.c: Likewise.
+* doc/README: Likewise.
+* extra/setjmp_t.c: Likewise.
+* tests/huge_test.c: Likewise.
+* extra/setjmp_t.c (getpagesize, nested_sp, main, g): Replace the
+K&R-style function definition with the ANSI C one.
+* extra/setjmp_t.c (nested_sp): Implement in the same way as
+GC_approx_sp.
+
+* dyn_load.c (GC_dyld_sections): Add more sctions.
+* dyn_load.c (GC_dyld_add_sect_fmts): New static varaible.
+* dyn_load.c (L2_MAX_OFILE_ALIGNMENT): New macro.
+* dyn_load.c (GC_dyld_image_add, GC_dyld_image_remove): Improve
+logging; add support for on-demand sections.
+
+* gcj_mlc.c (GC_gcj_malloc_initialized): Use STATIC unless
+GC_ASSERTIONS.
+* include/private/gc_priv.h (GC_gcj_malloc_initialized): Don't
+declare (as external) unless GC_ASSERTIONS.
+* os_dep.c (GC_win32_free_heap): Clear GC_heap_bases[] also for
+Cygwin; add FIXME.
+* include/private/gcconfig.h: Include <sys/unistd.h> for RTEMS.
+* include/private/gcconfig.h: Add "#error" for every "-->" mark.
+* include/private/gcconfig.h (CLEAR_DOUBLE): Turn the code into
+an expression.
+* include/private/pthread_support.h (SUSPENDED_EXT): Add new flag
+(which existed previously as SUSPENDED and still exists in GCJ).
+* include/private/pthread_support.h (DISABLED_GC): Change the
+value (as it is already used by SUSPENDED_EXT).
+
+* tests/test.c (reverse_test): Modify count (BIG) for
+ppc64-darwin.
+
+* reclaim.c (GC_print_all_errors): Recognize new GC_ABORT_ON_LEAK
+macro and environment variable; abort if any error has been
+printed provided the environment variable (or macro) is set.
+* doc/README.environment (GC_ABORT_ON_LEAK): Document.
+* doc/README.macros (GC_ABORT_ON_LEAK): Likewise.
+
+* os_dep.c (GC_unix_sbrk_get_mem, GC_unix_get_mem): Don't define
+for RTEMS.
+* include/private/gcconfig.h (RTEMS): Add support for.
+* include/private/gcconfig.h (GET_MEM): Use calloc() for RTEMS.
+
+* mallocx.c (GC_malloc_uncollectable): Move to malloc.c (since
+it is used internally in some places).
+
+* dbg_mlc.c (GC_register_finalizer_no_order): Remove redundant
+declaration.
+* dbg_mlc.c (GC_debug_malloc_replacement,
+GC_debug_realloc_replacement): Rename RA to GC_DBG_RA.
+* malloc.c (GC_debug_malloc_replacement): Likewise.
+* mallocx.c (GC_debug_realloc_replacement): Likewise.
+* dbg_mlc.c (GC_store_debug_info): Move proto from dbg_mlc.h.
+* malloc.c (GC_strdup, GC_strndup, GC_wcsdup): Move to mallocx.c.
+* malloc.c: Include errno.h only REDIRECT_MALLOC; remove redundant
+includes of string.h.
+* mallocx.c: Include string.h (for GC_strdup).
+* include/private/dbg_mlc.h (GC_store_debug_info): Move declaration
+to dbg_mlc.c.
+* include/private/gc_locks.h (UNCOND_LOCK, UNCOND_UNLOCK): Remove
+redundant trailing ';'.
+* include/private/gc_priv.h (START_WORLD, COND_DUMP): Likewise.
+* include/private/gc_locks.h (LOCK, UNLOCK): Place opening '{'
+properly.
+* include/private/gc_priv.h (GC_DBG_RA): Move from dbg_mlc.c,
+malloc.c, mallocx.c.
+
+* alloc.c (GC_check_heap, GC_print_all_smashed): Move the
+definition from misc.c.
+* dbg_mlc.c (GC_debug_malloc_atomic_uncollectable): Define as
+public.
+* include/gc.h (GC_debug_malloc_atomic_uncollectable): Declare.
+* include/gc.h (GC_MALLOC_ATOMIC_UNCOLLECTABLE): Define new public
+macro.
+* dbg_mlc.c (MAX_SMASHED): Don't define if already set.
+* reclaim.c (MAX_LEAKED): Likewise.
+* dbg_mlc.c (GC_add_smashed): Add FIXME about the concurrent
+access to the global array.
+* reclaim.c (GC_add_leaked): Likewise.
+* misc.c (GC_print_back_height): Set on if GC_PRINT_BACK_HEIGHT
+(new macro) is defined.
+* doc/README.macros (GC_PRINT_BACK_HEIGHT): Document.
+* misc.c (GC_dump_regularly, GC_init): Replace 0/1 for
+GC_dump_regularly and GC_print_back_height variables with
+FALSE/TRUE.
+* reclaim.c (GC_print_all_errors): Refine the comment.
+
+* tests/test.c (reverse_test_inner): Undo one of the previous
+patches which shifts "c" and "d" pointers only if
+ALL_INTERIOR_POINTERS (since interior pointers are always
+recognized in stacks).
+
+* misc.c (GC_stdout, GC_stderr): Move the definition to the place
+where GC_log is defined (Unix only).
+* misc.c (GC_init): Recognize "GC_ONLY_LOG_TO_FILE" environment
+variable and the similar macro; redirect GC_stdout and GC_stderr
+to GC_log if "GC_LOG_FILE" environment variable is set unless
+prohibited by GC_ONLY_LOG_TO_FILE (Unix only).
+* doc/README.environment (GC_ONLY_LOG_TO_FILE): Document.
+* doc/README.macros (GC_ONLY_LOG_TO_FILE): Likewise.
+
+* misc.c (GC_stdout, GC_write): Rename GC_stdout to GC_log (Win32
+only).
+* misc.c (GC_write): Add for MacOS (and OS/2); change WRITE()
+accordingly.
+* misc.c (GC_printf): Check GC_quiet before va_start().
+
+* allchblk.c (GC_freehblk): Use GC_log_printf instead of GC_printf
+inside "if (GC_print_stats)" branch.
+* alloc.c (GC_collect_or_expand): Likewise.
+* dyn_load.c (GC_register_dynamic_libraries): Likewise.
+* headers.c (GC_scratch_alloc): Likewise.
+* os_dep.c (GC_get_maps, GC_remap, PROTECT,
+GC_write_fault_handler, GC_dirty_init, GC_mprotect_thread): Likewise.
+* alloc.c (min_bytes_allocd): Use GC_log_printf instead of
+GC_printf for DEBUG_THREADS output.
+* darwin_stop_world.c (GC_stack_range_for, GC_suspend_thread_list,
+GC_stop_world, GC_thread_resume, GC_start_world): Likewise.
+* pthread_start.c (GC_inner_start_routine): Likewise.
+* pthread_stop_world.c (GC_suspend_handler, GC_restart_handler,
+GC_push_all_stacks, GC_suspend_all, GC_stop_world,
+GC_start_world): Likewise.
+* pthread_support.c (GC_mark_thread, GC_get_nprocs,
+GC_start_rtn_prepare_thread, pthread_create): Likewise.
+* checksums.c (GC_update_check_page): Use GC_printf() instead of
+GC_err_printf() for error printing.
+* checksums.c (GC_check_blocks, GC_check_dirty): Use GC_log_printf
+instead of GC_printf for logging purposes.
+* dyn_load.c (sys_errlist, sys_nerr, errno): Move declaration of
+external variable outside from GC_register_dynamic_libraries.
+* dyn_load.c (GC_register_dynamic_libraries): Don't use
+sys_errlist value if errno equals to sys_nerr.
+* dyn_load.c (GC_register_dynamic_libraries): Use GC_log_printf
+instead of GC_printf for DL_VERBOSE output.
+* dyn_load.c (GC_dyld_image_add, GC_dyld_image_remove,
+GC_init_dyld): Use GC_log_printf instead of GC_printf for
+DARWIN_DEBUG output.
+* os_dep.c (catch_exception_raise): Use GC_log_printf
+instead of GC_printf for DEBUG_EXCEPTION_HANDLING output.
+* reclaim.c (GC_print_free_list): Move "n" increment out of
+GC_printf() call.
+
+* win32_threads.c (DEBUG_CYGWIN_THREADS, DEBUG_WIN32_PTHREADS,
+DEBUG_WIN32_THREADS): Remove.
+* win32_threads.c (GC_register_my_thread_inner,
+GC_win32_start_inner): Use GC_log_printf instead of GC_printf
+inside "if (GC_print_stats)" branch.
+* win32_threads.c (GC_PTHREAD_PTRVAL): New macro (defined only if
+GC_PTHREADS).
+* win32_threads.c (GC_delete_gc_thread, NUMERIC_THREAD_ID,
+GC_pthread_join, GC_pthread_create): Use GC_PTHREAD_PTRVAL
+macro.
+* win32_threads.c (GC_push_stack_for, GC_mark_thread,
+GC_CreateThread, GC_beginthreadex, GC_pthread_join,
+GC_pthread_create, GC_pthread_start_inner, GC_thread_exit_proc,
+GC_mark_thread_local_free_lists): Use GC_log_printf instead of
+GC_printf for DEBUG_THREADS output.
+* win32_threads.c (GC_win32_start_inner, GC_CreateThread,
+GC_beginthreadex, GC_pthread_join, GC_pthread_create,
+GC_pthread_start_inner, GC_thread_exit_proc): Cast
+GetCurrentThreadId result to long; don't cast value of pthread_t
+type to int; adjust printf format specifiers.
+* doc/README.win32 (DEBUG_WIN32_PTHREADS): Remove obsolete
+information.
+
+* tests/test.c (cons, small_cons, gcj_cons, check_ints,
+check_uncollectable_ints, print_int_list, check_marks_int_list,
+fork_a_thread, finalizer, mktree, chktree, alloc8bytes,
+alloc_small, tree_test, typed_test, check_heap_stats, WinMain,
+test, main): Remove unnecessary casts of GC_printf calls to void.
+
+* allchblk.c (GC_print_hblkfreelist): Adjust (make uniform across
+BDWGC) printed message (adjust letters case, terminating dot and
+new line symbols).
+* alloc.c (GC_check_fl_marks): Likewise.
+* backgraph.c (new_back_edges): Likewise.
+* checksums.c (GC_check_dirty): Likewise.
+* darwin_stop_world.c (GC_push_all_stacks,
+GC_suspend_thread_list): Likewise.
+* dbg_mlc.c (GC_print_type, GC_debug_free, GC_debug_realloc,
+store_old): Likewise.
+* dyn_load.c (GC_register_dynamic_libraries): Likewise.
+* mark.c (GC_initiate_gc, GC_mark_some, GC_mark_from, GC_push_all,
+GC_push_selected, GC_push_next_marked_dirty): Likewise.
+* mark_rts.c (GC_exclude_static_roots_inner): Likewise.
+* os_dep.c (GC_remap, GC_default_push_other_roots,
+GC_push_thread_structures, GC_dirty_init, GC_read_dirty,
+catch_exception_raise_state, catch_exception_raise_state_identity,
+GC_mprotect_thread_notify, GC_mprotect_thread,
+catch_exception_raise): Likewise.
+* pthread_stop_world.c (GC_print_sig_mask, GC_push_all_stacks,
+GC_stop_world, GC_stop_init): Likewise.
+* pthread_support.c (GC_thr_init, GC_register_my_thread_inner,
+GC_start_routine): Likewise.
+* win32_threads.c (GC_register_my_thread_inner,
+GC_push_all_stacks, GC_win32_start_inner, GC_pthread_join,
+GC_pthread_start_inner): Likewise.
+* alloc.c (GC_expand_hp_inner): Realign the code.
+* mark.c (GC_mark_from, GC_mark_local, GC_do_parallel_mark):
+Likewise.
+* misc.c (GC_init): Likewise.
+* os_dep.c (GC_dirty_init, GC_read_dirty): Likewise.
+* include/private/gc_pmark.h (PUSH_CONTENTS_HDR): Likewise.
+* tests/test.c (run_one_test): Likewise.
+* misc.c (GC_err_puts): Document.
+* misc.c (GC_err_write): Remove.
+* os_dep.c (dump_maps): Likewise.
+* include/private/gc_priv.h (GC_err_write): Likewise.
+* os_dep.c (GC_print_address_map): Call GC_err_puts() instead of
+dump_maps() and GC_err_write().
+* os_dep.c (GC_read_dirty): Remove redundant brackets.
+
+* tests/test.c (reverse_test_inner): Test interior pointer
+recognition only if ALL_INTERIOR_POINTERS.
+* tests/test.c (run_one_test): Replace GC_all_interior_pointers
+with GC_get_all_interior_pointers(); simplify the expression.
+* tests/test.c (check_heap_stats): Replace GC_bytes_allocd and
+GC_bytes_allocd_before_gc with GC_get_total_bytes().
+* tests/test.c (main): Replace GC_gc_no with GC_get_gc_no().
+
+* dbg_mlc.c (GC_debug_strdup, GC_debug_free): Output a portability
+warning if the argument is NULL and GC is in leaks detection mode.
+* dbg_mlc.c (GC_debug_strndup, GC_debug_wcsdup): New public
+function definition.
+* malloc.c (GC_strndup, GC_wcsdup, strndup): Likewise.
+* mallocx.c (GC_posix_memalign): Likewise.
+* malloc.c (strdup): Fix string size value; rename "len" to "lb".
+* mallocx.c: Include errno.h unless WinCE (otherwise include
+windows.h for Win32 error constants).
+* win32_threads.c: Define WIN32_LEAN_AND_MEAN and NOSERVICE before
+windows.h inclusion.
+* misc.c (GC_init): Register at-exit callback if GC_find_leak
+(even if GC_FIND_LEAK macro is unset).
+* pthread_stop_world.c (NACL_STORE_REGS,
+__nacl_suspend_thread_if_needed, GC_nacl_initialize_gc_thread):
+Use BCOPY() instead of memcpy().
+* pthread_support.c (GC_init_real_syms): Likewise.
+* doc/README.macros (GC_DEBUG_REPLACEMENT, GC_REQUIRE_WCSDUP):
+Document new macro.
+* doc/README.macros (REDIRECT_MALLOC): Update documentation.
+* include/gc.h (GC_strndup, GC_posix_memalign, GC_debug_strndup):
+New API function prototype.
+* include/gc.h (GC_MALLOC, GC_REALLOC): Redirect to
+GC_debug_malloc/realloc_replacement() if GC_DEBUG_REPLACEMENT.
+* include/gc.h (GC_STRDUP): Remove redundant parentheses.
+* include/leak_detector.h (realloc, strdup): Likewise.
+* include/gc.h (GC_STRNDUP): New API macro.
+* include/gc.h (GC_NEW, GC_NEW_ATOMIC, GC_NEW_STUBBORN,
+GC_NEW_UNCOLLECTABLE): Add missing parentheses.
+* include/gc.h (GC_wcsdup, GC_debug_wcsdup): New API function
+prototype (only if GC_REQUIRE_WCSDUP).
+* include/gc.h (GC_WCSDUP): New API macro (only if
+GC_REQUIRE_WCSDUP).
+* include/leak_detector.h: Include stdlib.h and string.h after gc.h (unless
+GC_DONT_INCLUDE_STDLIB).
+* include/leak_detector.h (malloc, calloc, free, realloc):
+Undefine symbol before its redefinition.
+* include/leak_detector.h (strndup, memalign, posix_memalign):
+Redefine to the corresponding GC function.
+* include/leak_detector.h (wcsdup): Redefine to GC_WCSDUP (only
+if GC_REQUIRE_WCSDUP).
+* include/leak_detector.h (CHECK_LEAKS): Add comment; don't define
+the macro if already defined.
+
+* misc.c (GC_abort): Use _exit() (instead of DebugBreak) on Win32
+when doing code static analysis (to inform the tool that the
+function is a no-return one).
+* os_dep.c (GC_linux_stack_base): Remove a duplicate validation
+of the length of "stat" file; use signed int type for "i",
+"buf_offset" and "len" local variables (since read() may
+return -1).
+
+* blacklst.c (GC_bl_init_no_interiors): New function (the code
+moved from GC_bl_init).
+* blacklst.c (GC_bl_init): Invoke GC_bl_init_no_interiors unless
+GC_all_interior_pointers mode; remove unnecessarily parameter cast
+for GC_scratch_alloc call.
+* include/private/gc_priv.h (GC_bl_init): Move the function
+declaration to misc.c file.
+* misc.c (GC_bl_init_no_interiors): Add a prototype.
+* misc.c (GC_set_all_interior_pointers): Allow values other than 0
+and 1; allow altering GC_set_all_interior_pointers value even
+after GC initialization.
+* obj_map.c (GC_initialize_offsets): Clear GC_valid_offsets and
+GC_modws_valid_offsets if GC_all_interior_pointers is off.
+* misc.c (GC_init): Don't call GC_initialize_offsets() unless
+GC_all_interior_pointers mode.
+
+* alloc.c (GC_finish_collection): Remove redundant brackets;
+adjust code indentation.
+* blacklst.c (GC_add_to_black_list_normal): Simplify expression
+(to improve code readability).
+* blacklst.c (GC_is_black_listed): Join nested "if" (into a single
+conditional expression); initialize "nblocks" just before the loop
+beginning.
+* misc.c (GC_init): Don't compute initial_heap_sz if GC is already
+initialized.
+* include/private/gc_priv.h (GC_initialize_offsets): Move the
+function declaration to misc.c file.
+* obj_map.c (GC_initialize_offsets): Remove offsets_initialized
+static variable since the function is called only once.
+* tests/middle.c (main): Use setter for GC_all_interior_pointers;
+adjust printf format specifier (and cast the value passed to).
+
+* doc/README.macros (SMALL_CONFIG, LARGE_CONFIG): Refine the
+documentation.
+* include/private/gc_hdrs.h (LOG_BOTTOM_SZ): Ignore SMALL_CONFIG
+if LARGE_CONFIG is defined.
+* include/private/gc_priv.h (CPP_LOG_HBLKSIZE): Likewise.
+
+* alloc.c (GC_finish_collection): Replace "#else #ifdef" with
+"#elif".
+* include/private/gc_priv.h (CPP_LOG_HBLKSIZE, LOG_PHT_ENTRIES,
+MAX_ROOT_SETS, MAX_HEAP_SECTS): Likewise.
+* alloc.c (GC_expand_hp_inner): Check for GC_collect_at_heapsize
+overflow even if not LARGE_CONFIG.
+* dbg_mlc.c (GC_check_heap_proc): Check "oh" size even if
+SMALL_CONFIG.
+* finalize.c (GC_print_finalization_stats): Fix "#endif" comment.
+* doc/README.environment (GC_LOG_FILE, GC_PRINT_VERBOSE_STATS,
+GC_FULL_FREQUENCY): Refine the documentation.
+
+* extra/msvc_dbg.c: Test _MSC_VER macro; include "gc.h" (for
+GC_word).
+* extra/msvc_dbg.c (ULONG_PTR): Replace with GC_ULONG_PTR; define
+as word.
+
+* dbg_mlc.c (GC_get_back_ptr_info, GC_print_obj,
+GC_print_smashed_obj, GC_debug_free_inner): Add a code for a
+LINT-like tool to instruct it that the function is invoked only
+with valid parameters (otherwise a SEGV is ok); recognize LINT2
+new macro.
+* misc.c (GC_abort): Instruct a LINT-like tool that the function
+never returns in fact.
+* os_dep.c (GC_linux_stack_base): Check for read buffer overflow;
+close the file immediately after read; use STRTOULL() instead of
+decoding the address number manually.
+* include/private/gc_priv.h (EXPECT): Don't specify outcome for a
+LINT-like tool.
+* include/private/gc_priv.h (GC_all_interior_pointers): Instruct a
+LINT-like tool that the value is restricted to zero and one only
+(required since the variable is global and its value is used as a
+part of array index expression is some places).
+
+* dbg_mlc.c (GC_make_closure): Fix SEGV in case GC_malloc returns
+NULL.
+* dbg_mlc.c (GC_debug_register_finalizer,
+GC_debug_register_finalizer_no_order,
+GC_debug_register_finalizer_unreachable,
+GC_debug_register_finalizer_ignore_self): Handle out of memory
+case properly (similar to GC_register_finalizer_inner).
+* headers.c (GC_install_header): Handle the case when alloc_hdr()
+returns NULL.
+* os_dep.c (GC_get_maps_len): Defend against missing "maps" file.
+* pthread_support.c (GC_mark_thread): Place a dummy return
+statement (which uses "id" argument) before the actual use of "id"
+as an array index (to suppress a warning produced by some static
+code analysis tools).
+* win32_threads.c (GC_mark_thread): Likewise.
+* pthread_support.c (GC_thr_init): Abort (with the appropriate
+message) if out of memory.
+
+* finalize.c (GC_register_finalizer_inner): Fix a typo in a
+comment.
+*include/private/gcconfig.h (STACKBOTTOM): Likewise.
+* gcj_mlc.c (GC_core_gcj_malloc): Replace 0/1 with TRUE/FALSE in
+EXPECT (the 2nd argument).
+* malloc.c (GC_core_malloc_atomic, GC_core_malloc, GC_free):
+Likewise.
+* mark.c (GC_mark_and_push, GC_mark_and_push_stack): Likewise.
+* thread_local_alloc.c (GC_malloc, GC_malloc_atomic): Likewise.
+* include/private/gc_hdrs.h (HC_GET_HDR): Likewise.
+* include/private/gc_priv.h (SMALL_OBJ): Likewise.
+* include/private/specific.h (getspecific): Likewise.
+* pthread_support.c (LOCK_STATS): Add a comment.
+
+* include/gc_pthread_redirects.h (GC_NO_DLOPEN,
+GC_NO_PTHREAD_SIGMASK, GC_PTHREAD_CREATE_CONST,
+GC_PTHREAD_EXIT_ATTRIBUTE, GC_NO_PTHREAD_CANCEL): Move the
+definition to gc_config_macros.
+
+* pthread_support.c (pthread_cancel, GC_pthread_cancel_t,
+GC_pthread_cancel): Test GC_NO_PTHREAD_CANCEL (instead of NACL and
+GC_PTHREAD_EXIT_ATTRIBUTE).
+* include/gc_pthread_redirects.h (GC_pthread_cancel,
+pthread_cancel): Likewise.
+* pthread_support.c (GC_pthread_create, GC_pthread_sigmask,
+GC_pthread_join, GC_pthread_detach, GC_pthread_cancel): Realign
+code.
+* include/gc_pthread_redirects.h (GC_PTHREAD_EXIT_ATTRIBUTE):
+Define as empty for NaCl.
+* include/gc_pthread_redirects.h (GC_NO_PTHREAD_CANCEL): New macro
+defined.
+
+* dyn_load.c (GC_init_dyld): Do not invoke
+_dyld_bind_fully_image_containing_address() if GC_no_dls (as it is
+not required to register the main data segment in that case).
+* include/gc.h (GC_no_dls): Adjust the comment.
+
+* dyn_load.c (GC_MUST_RESTORE_REDEFINED_DLOPEN): Test
+GC_NO_DLOPEN.
+* gc_dlopen.c: Likewise.
+* include/gc_pthread_redirects.h (GC_dlopen, dlopen): Likewise.
+* gc_dlopen.c: Don't include dlfcn.h (as it is included in
+gc_pthread_redirects.h).
+* pthread_support.c (pthread_sigmask, GC_pthread_sigmask_t,
+GC_pthread_sigmask): Test GC_NO_PTHREAD_SIGMASK (instead of
+GC_DARWIN_THREADS, GC_OPENBSD_THREADS and NACL).
+* include/gc_pthread_redirects.h (GC_pthread_sigmask,
+pthread_sigmask): Likewise.
+* win32_threads.c (pthread_sigmask, GC_pthread_sigmask): Test
+GC_NO_PTHREAD_SIGMASK (instead of GC_WIN32_PTHREADS).
+* pthread_support.c (pthread_create, GC_pthread_create_t,
+GC_pthread_create): Rename GC_PTHREAD_CONST to
+GC_PTHREAD_CREATE_CONST.
+* win32_threads.c (GC_pthread_create): Likewise.
+* include/gc_pthread_redirects.h: Likewise.
+* include/gc_pthread_redirects.h (GC_NO_DLOPEN,
+GC_NO_PTHREAD_SIGMASK): New macro defined.
+* include/gc_pthread_redirects.h (GC_PTHREAD_CREATE_CONST): Set to
+empty for NaCl.
+* include/gc_pthread_redirects.h (GC_PTHREAD_EXIT_ATTRIBUTE): Do
+not define for Android (as CANCEL_SAFE is not defined).
+
+* include/gc.h (GC_ADD_CALLER, GC_RETURN_ADDR,
+GC_HAVE_BUILTIN_BACKTRACE, GC_CAN_SAVE_CALL_STACKS): Move
+definition to gc_config_macros.h file.
+* include/gc_config_macros.h: Check the file is included from gc.h
+file.
+* include/gc_version.h: Likewise.
+
+* gc_dlopen.c: Empty unit for NaCl.
+* os_dep.c: Include fcntl.h for NaCl.
+* os_dep.c (GC_get_main_stack_base): Ignore
+USE_GET_STACKBASE_FOR_MAIN macro for NaCl.
+* os_dep.c (GC_get_stack_base): Return GC_UNIMPLEMENTED for NaCl.
+* os_dep.c (GC_remap): Use mmap (instead of mprotect) for NaCl.
+* pthread_start.c (GC_inner_start_routine): Don't invoke
+pthread_cleanup_push/pop for NaCl.
+* pthread_stop_world.c (GC_nacl_num_gc_threads,
+GC_nacl_thread_idx, GC_nacl_park_threads_now,
+GC_nacl_thread_parker, GC_nacl_gc_thread_self,
+GC_nacl_thread_parked, GC_nacl_thread_used,
+GC_nacl_thread_parking_inited, GC_nacl_thread_alloc_lock): New
+variable (fo NaCl only).
+* pthread_stop_world.c (GC_remove_allowed_signals,
+suspend_handler_mask, GC_stop_count, GC_world_is_stopped,
+GC_retry_signals, SIG_THR_RESTART, GC_suspend_ack_sem,
+GC_restart_ack_sem, GC_suspend_handler_inner, GC_suspend_handler,
+GC_restart_handler): Don't define for NaCl.
+* pthread_support.c (GC_get_nprocs): Likewise.
+* include/private/gc_priv.h (SIG_SUSPEND): Likewise.
+* include/private/gcconfig.h (LINUX): Likewise.
+* pthread_stop_world.c (GC_push_all_stacks): Push register storage
+for NaCl.
+* pthread_stop_world.c (GC_suspend_all, GC_stop_world,
+GC_start_world): Implement for NaCl.
+* pthread_stop_world.c (GC_stop_world): Don't define unused "i"
+local variable for OpenBSD (and NaCl).
+* pthread_stop_world.c (NACL_STORE_REGS): New macro definition for
+NaCl.
+* pthread_stop_world.c (nacl_pre_syscall_hook,
+__nacl_suspend_thread_if_needed, nacl_post_syscall_hook,
+GC_nacl_initialize_gc_thread, GC_nacl_shutdown_gc_thread): New
+function (for NaCl only).
+* pthread_stop_world.c (GC_stop_init): Empty for NaCl.
+* pthread_support.c (pthread_cancel, pthread_sigmask): Don't
+redirect for NaCl.
+* include/gc_pthread_redirects.h (pthread_cancel,
+pthread_sigmask): Likewise.
+* pthread_support.c (GC_nacl_initialize_gc_thread,
+GC_nacl_shutdown_gc_thread): New internal prototype (NaCl only).
+* pthread_support.c (GC_new_thread, GC_delete_thread): Initialize
+and shutdown thread for NaCl.
+* pthread_support.c (GC_thr_init): Call sysconf for NaCl.
+* pthread_support.c (GC_pthread_exit): Call GC_thread_exit_proc
+for NaCl.
+* include/gc.h: Don't include features.h for NaCl.
+* include/gc_pthread_redirects.h (GC_PTHREAD_CONST): New macro.
+* include/gc_pthread_redirects.h (GC_pthread_create): Use
+GC_PTHREAD_CONST instead of const.
+* win32_threads.c (GC_pthread_create): Likewise.
+* pthread_support.c (GC_pthread_create_t, GC_pthread_create,
+pthread_create): Likewise.
+* include/private/gcconfig.h (NACL): Recognize NaCl.
+* include/private/gcconfig.h (GC_LINUX_THREADS): Valid for NaCl.
+* include/private/pthread_stop_world.h (thread_stop_info): Add
+reg_storage member; define NACL_GC_REG_STORAGE_SIZE macro (for
+NaCl only).
+* include/private/pthread_support.h (GC_nacl_gc_thread_self):
+Declare internal variable (for NaCl only).
+
+* mach_dep.c (GC_with_callee_saves_pushed): Fix FE_ALL_EXCEPT
+macro.
+
+* mark.c (GC_mark_some): Prefix and suffix "asm" and "volatile"
+keywords with double underscore.
+* os_dep.c (catch_exception_raise, catch_exception_raise_state,
+catch_exception_raise_state_identity): Add GC_API_OSCALL to
+function definition.
+* os_dep.c (catch_exception_raise_state,
+catch_exception_raise_state_identity): Move definition to be
+before GC_ports.
+* os_dep.c (catch_exception_raise): Declare to have the symbol
+defined before GC_ports.
+* os_dep.c (GC_ports): Store references to catch_exception_raise,
+catch_exception_raise_state, catch_exception_raise_state_identity
+(to prevent stripping these symbols as dead).
+* os_dep.c (catch_exception_raise, catch_exception_raise_state,
+catch_exception_raise_state_identity): Mark these symbols as
+"referenced dynamically" via an assembler directive (unless
+NO_DESC_CATCH_EXCEPTION_RAISE).
+* include/private/gc_priv.h (GC_API_OSCALL): New macro (defined
+similar to GC_API but as if GC_DLL is always defined).
+
+* os_dep.c: Don't include signal.h for GC_write_fault_handler on
+Win32.
+* os_dep.c (SIG_OK): Don't return true unless SIGSEGV or SIGBUS on
+FreeBSD.
+* os_dep.c (CODE_OK): Use SEGV_ACCERR on FreeBSD (define
+SEGV_ACCERR for older FreeBSD releases).
+
+* dyn_load.c (GC_register_map_entries,
+GC_register_dynamic_libraries_dl_iterate_phdr): Calculate
+DATASTART only once if DATASTART_IS_FUNC.
+* dyn_load.c (GC_register_dynamic_libraries_dl_iterate_phdr):
+Calculate DATAEND only once if DATAEND_IS_FUNC.
+* dyn_load.c: Add comment to some endif; realign some code.
+* dyn_load.c (GC_init_dyld): Don't use
+_dyld_bind_fully_image_containing_address if
+NO_DYLD_BIND_FULLY_IMAGE defined; add FIXME.
+* include/private/gcconfig.h (GC_data_start, GC_find_limit):
+Declare if used by DATASTART/DATAEND, respectively.
+* include/private/gcconfig.h (DATASTART_IS_FUNC, DATAEND_IS_FUNC):
+Define if DATASTART/DATAEND is a function, respectively.
+* include/private/gcconfig.h (GETPAGESIZE, NO_PTHREAD_TRYLOCK,
+NO_DYLD_BIND_FULLY_IMAGE): Define for Darwin/arm as well; include
+unistd.h.
+
+* os_dep.c (GC_setpagesize, GC_task_self, PROTECT, UNPROTECT):
+Reorder to remove redundant ifdef for Win32.
+* os_dep.c: Add comment to some endif.
+* os_dep.c: Include pthread.h (for Linux even if single-threaded)
+if USE_GET_STACKBASE_FOR_MAIN; also include it for Darwin.
+* os_dep.c (STACKBOTTOM): Redefine for Darwin (unless prohibited
+for some reason).
+* os_dep.c (GC_get_main_stack_base): Allow
+USE_GET_STACKBASE_FOR_MAIN for Linux even if single-threaded; add
+assertion for the returned result.
+* os_dep.c (GC_get_stack_base): Define for Darwin if
+multi-threaded.
+* os_dep.c (SIG_OK, CODE_OK): Add comment (for FreeBSD).
+* os_dep.c (ID_STOP, ID_RESUME): Define only if threads.
+* os_dep.c (catch_exception_raise): Remove redundant parentheses;
+refine the documentation.
+
+* NT_MAKEFILE: Define _CRT_SECURE_NO_DEPRECATE for C++ files as
+well.
+* NT_STATIC_THREADS_MAKEFILE: Likewise.
+* doc/README.macros (USE_GET_STACKBASE_FOR_MAIN): Refine.
+* include/gc.h (GC_INIT): Document.
+* include/private/gc_priv.h (GC_MACH_HEADER, GC_MACH_SECTION,
+GC_GETSECTBYNAME): Define depending only on the word size (i.e.,
+define these macros also for ARM).
+* tests/test.c (check_heap_stats): Print main thread stack bottom
+as well (only if verbose mode is on).
+
+* mach_dep.c (GC_with_callee_saves_pushed): Fix and improve code
+introduced by the previous patch (if GETCONTEXT_FPU_EXCMASK_BUG
+and X86_64).
+
+* darwin_stop_world.c (GC_FindTopOfStack): Prefix and suffix
+"volatile" keyword with double underscore.
+* mach_dep.c (GETCONTEXT_FPU_EXCMASK_BUG): Recognize new macro and
+include fenv.h if defined (unless NO_GETCONTEXT or HAVE_PUSH_REGS).
+* mach_dep.c (GC_with_callee_saves_pushed): Restore FPU exception
+mask corrupted by getcontext if GETCONTEXT_FPU_EXCMASK_BUG.
+* include/private/gcconfig.h (GETCONTEXT_FPU_EXCMASK_BUG): Define
+for Linux/amd64 (since its GLibc getcontext currently has the bug).
+
+* allchblk.c (GC_use_entire_heap): Change type to int (as declared
+in gc.h); set the default value depending on new GC_USE_ENTIRE_HEAP
+macro.
+* misc.c (GC_init): Test GC_USE_ENTIRE_HEAP environment variable to
+alter the default value of GC_use_entire_heap.
+* doc/README.environment (GC_USE_ENTIRE_HEAP): Document.
+* doc/README.macros (GC_USE_ENTIRE_HEAP): Likewise.
+
+* include/private/gcconfig.h (PARALLEL_MARK): Do not make it cause
+MPROTECT_VDB undefining.
+
+* include/private/gcconfig.h (DYNAMIC_LOADING): Fix filename in
+the comment.
+
+* include/private/gc_priv.h (_GC_arrays): Move the conditional
+macro definitions (shortcuts for GC_arrays members) into the
+structure body.
+
+* darwin_stop_world.c (GC_mach_handler_thread,
+GC_use_mach_handler_thread,
+GC_darwin_register_mach_handler_thread): Define only if
+MPROTECT_VDB.
+* darwin_stop_world.c (GC_suspend_thread_list): Use
+GC_mach_handler_thread and GC_use_mach_handler_thread only if
+MPROTECT_VDB.
+* darwin_stop_world.c (GC_stop_world): Reset GC_mach_threads_count
+only if defined (i.e. unless GC_NO_THREADS_DISCOVERY).
+* misc.c (GC_init): Fix comment for GWW_VDB.
+* os_dep.c (DARWIN_EXC_STATE, DARWIN_EXC_STATE_COUNT,
+DARWIN_EXC_STATE_T, DARWIN_EXC_STATE_DAR): New macros.
+* os_dep.c (catch_exception_raise): Use DARWIN_EXC_STATE,
+DARWIN_EXC_STATE_COUNT, DARWIN_EXC_STATE_T, DARWIN_EXC_STATE_DAR.
+* pthread_support.c (GC_thr_init): Define "dummy" local variable
+only unless GC_DARWIN_THREADS.
+* include/private/gcconfig.h (MPROTECT_VDB): Define for Darwin
+even in the single-threaded mode; define for iPhone/iPad.
+* include/private/gcconfig.h (IA64): Remove unnecessary "ifdef"
+around "undef".
+* include/private/gcconfig.h (HEURISTIC1): Remove unused for
+Cygwin.
+* include/private/gcconfig.h (STACKBOTTOM): Use fixed address for
+Darwin/arm (instead of HEURISTIC1).
+
+* misc.c (GC_write): Replace multiple "ifdef/endif" with "elif"
+(for ECOS and NOSYS).
+* os_dep.c (GC_get_main_stack_base): Likewise.
+* os_dep.c (GC_get_main_stack_base): Check
+USE_GET_STACKBASE_FOR_MAIN macro before checking STACKBOTTOM one;
+remove "dummy" variable (use result one instead).
+* doc/README.macros (SN_TARGET_PS3): Document.
+* extra/threadlibs.c (main): Don't output "-lpthread" (and "-ldl")
+for Android.
+* include/private/pthread_support.h: Fix comment for "endif".
+
+* misc.c (GC_allocate_ml): Define global variable if SN_TARGET_PS3.
+* misc.c (GC_init): Initialize GC_allocate_ml if SN_TARGET_PS3.
+* os_dep.c (SIGSEGV): Define to dummy zero if SN_TARGET_PS3.
+* os_dep.c (GC_unix_mmap_get_mem): Don't define if SN_TARGET_PS3.
+* os_dep.c (GC_default_push_other_roots,
+GC_push_thread_structures): Define for SN_TARGET_PS3.
+* include/private/gc_locks.h (GC_allocate_ml, LOCK, UNLOCK): Define
+for SN_TARGET_PS3.
+* include/private/gcconfig.h (SN_TARGET_PS3): Recognize new macro
+(Sony PS/3 target).
+* include/private/gcconfig.h (THREADS): Define unconditionally if
+SN_TARGET_PS3.
+* include/private/gcconfig.h (GET_MEM): Define for SN_TARGET_PS3.
+
+* alloc.c (GC_collect_or_expand): Replace NIL with NULL in message.
+* dbg_mlc.c (GC_debug_malloc, GC_debug_malloc_ignore_off_page,
+GC_debug_malloc_atomic_ignore_off_page,
+GC_debug_generic_malloc_inner,
+GC_generic_malloc_inner_ignore_off_page, GC_debug_malloc_stubborn,
+GC_debug_malloc_atomic, GC_debug_malloc_uncollectable,
+GC_debug_malloc_atomic_uncollectable): Likewise.
+* gcj_mlc.c (GC_debug_gcj_malloc): Likewise.
+* dbg_mlc.c (GC_check_annotated_obj): Replace NIL with NULL in a
+comment.
+* dyn_load.c (GC_FirstDLOpenedLinkMap): Likewise.
+* mark_rts.c (GC_roots_present): Likewise.
+* doc/README: Likewise.
+* include/private/gc_hdrs.h (IS_FORWARDING_ADDR_OR_NIL): Likewise.
+* include/private/gc_priv.h (_GC_arrays): Likewise.
+
+* configure.ac: Use AC_CHECK_LIB() to check for pthread instead of
+just blindly linking to -lpthread, as Android includes pthread
+support within libc and does not provide a separate libpthread.
+* dyn_load.c (GC_register_dynamic_libraries): Skip current link map
+entry if l_addr is NULL (Android/bionic only).
+* pthread_stop_world.c (android_thread_kill): New internal function
+(Android only).
+* pthread_stop_world.c (GC_suspend_all, GC_start_world): Call
+android_thread_kill (based on tkill) instead of pthread_kill on
+Android (since pthread_kill cannot be used safely on the platform).
+* pthread_support.c (GC_new_thread): Store thread Id (obtained from
+gettid) for use by android_thread_kill (Android only).
+* include/private/pthread_support.h (GC_Thread_Rep): Add kernel_id
+structure member (Android only).
+* include/private/gcconfig.h: Recognize __x86_64 macro as a synonym
+of __x86_64__ (Darwin); define __environ macro (Android on M68K).
+
+* allchblk.c (GC_freehblk): Print extended error message (done via
+GC_printf() before aborting with a short message) only if
+GC_print_stats.
+* dyn_load.c (GC_register_dynamic_libraries): Likewise.
+* os_dep.c (GC_get_maps, GC_register_data_segments, GC_remap,
+PROTECT, GC_write_fault_handler, GC_mprotect_thread): Likewise.
+* pthread_stop_world.c (GC_start_world): Likewise.
+* win32_threads.c (GC_register_my_thread_inner): Likewise.
+* os_dep.c (GC_get_main_stack_base, GC_register_data_segments,
+GC_dirty_init): Remove redundant print of an error message before
+aborting with the same message.
+* os_dep.c (GC_register_data_segments): Remove format specifier
+from the string passed to GC_err_puts(); use ABORT instead of EXIT
+(if invalid executable type).
+* os_dep.c (GC_remap): Adjust printf format specifier (for long
+type).
+* os_dep.c (GC_dirty_init): Print a message about SIG_IGN detected
+(for SIGSEGV/BUS) only if GC_print_stats.
+* os_dep.c (catch_exception_raise): Join 2 adjacent GC_err_printf
+calls.
+
+* tests/test.c (main): Print the relevant message if GWW_VDB.
+* include/private/gcconfig.h: Don't define MPROTECT_VDB for Win32
+on x64 if compiled by GCC.
+
+* tests/staticrootstest.c: Include string.h for memset() prototype.
+* tests/thread_leak_test.c (main): Fix printf() format specifiers.
+
+* CMakeLists.txt: Check enable_parallel_mark on Darwin.
+* configure.ac: Likewise.
+* darwin_stop_world.c (DARWIN_SUSPEND_GC_THREADS,
+DARWIN_QUERY_TASK_THREADS): Rename to GC_NO_THREADS_DISCOVERY and
+GC_DISCOVER_TASK_THREADS, respectively.
+* os_dep.c (DARWIN_SUSPEND_GC_THREADS): Likewise.
+* pthread_support.c (DARWIN_SUSPEND_GC_THREADS): Likewise.
+* darwin_stop_world.c (DARWIN_QUERY_TASK_THREADS): Don't define
+(and remove FIXME).
+* darwin_stop_world.c (GC_use_threads_discovery): Add GC_API;
+comment; remove FIXME.
+* win32_threads.c (GC_NO_DLLMAIN): Rename to
+GC_NO_THREADS_DISCOVERY.
+* tests/test.c (GC_NO_DLLMAIN): Likewise.
+* doc/README.macros (GC_NO_DLLMAIN): Likewise.
+* doc/README.win32 (GC_NO_DLLMAIN): Likewise.
+* doc/README.macros (GC_NO_THREADS_DISCOVERY): Update the comment.
+* win32_threads.c (GC_win32_dll_threads): Define as macro to true
+if GC_DISCOVER_TASK_THREADS (and not GC_NO_THREADS_DISCOVERY);
+update the comment.
+* win32_threads.c (GC_use_DllMain): Rename to
+GC_use_threads_discovery; do not set GC_win32_dll_threads if
+GC_DISCOVER_TASK_THREADS.
+* win32_threads.c (GC_started_thread_while_stopped,
+GC_lookup_thread_inner, UNPROTECT_THREAD, GC_lookup_pthread,
+GC_thr_init, GC_pthread_create, DllMain): Rewrite some expressions
+which use GC_win32_dll_threads to minimize the possibility of
+an "unreachable code" compiler warning when GC_win32_dll_threads
+is defined as a macro.
+* win32_threads.c (GC_unregister_my_thread): Don't call
+GC_delete_thread() if GC_win32_dll_threads and THREAD_LOCAL_ALLOC
+(since can't happen); use "t" local variable only if not
+GC_win32_dll_threads.
+* doc/README.macros (GC_DISCOVER_TASK_THREADS): Document.
+* include/gc.h (GC_use_DllMain): Rename to
+GC_use_threads_discovery but keep old name as a macro definition.
+* include/gc.h (GC_use_threads_discovery): Declare also for
+Darwin; update the comment.
+* tests/test.c (main): Call GC_use_threads_discovery for Darwin
+(to test the mode if possible).
+
+* darwin_stop_world.c (DARWIN_SUSPEND_GC_THREADS,
+DARWIN_QUERY_TASK_THREADS): New macro recognized.
+* darwin_stop_world.c (GC_query_task_threads): add STATIC;
+initialize to false; define as macro if DARWIN_SUSPEND_GC_THREADS
+or DARWIN_QUERY_TASK_THREADS; remove FIXME.
+* darwin_stop_world.c (GC_use_threads_discovery): New function
+(for setting GC_query_task_threads value).
+* darwin_stop_world.c (GC_mach_handler_thread,
+GC_use_mach_handler_thread, GC_mach_thread, GC_MAX_MACH_THREADS,
+GC_mach_threads, GC_mach_threads_count, GC_suspend_thread_list,
+GC_darwin_register_mach_handler_thread): Define only if not
+DARWIN_SUSPEND_GC_THREADS.
+* darwin_stop_world.c (GC_stop_world, GC_start_world): Exclude
+the code for GC_query_task_threads case from compilation unless
+DARWIN_SUSPEND_GC_THREADS.
+* os_dep.c (GC_darwin_register_mach_handler_thread): Declared only
+if Darwin threads and not DARWIN_SUSPEND_GC_THREADS.
+* os_dep.c (GC_mprotect_thread): Call
+GC_darwin_register_mach_handler_thread only if THREADS and not
+DARWIN_SUSPEND_GC_THREADS.
+* pthread_support.c (marker_mach_threads): Don't define if
+DARWIN_SUSPEND_GC_THREADS.
+* pthread_support.c (GC_mark_thread): Don't fill in
+marker_mach_threads if DARWIN_SUSPEND_GC_THREADS.
+* include/private/gc_locks.h (GC_need_to_lock): Always declare for
+THREADS case.
+
+* darwin_stop_world.c (GC_query_task_threads): Don't define to
+false for DARWIN_DONT_PARSE_STACK case; unconditionally initialize
+the variable to false (for now).
+* darwin_stop_world.c (GC_push_all_stacks): Call task_threads()
+only if not DARWIN_DONT_PARSE_STACK.
+* darwin_stop_world.c (GC_stop_world, GC_start_world): Use the
+approach based on task_threads() only if GC_query_task_threads
+else use GC_threads table.
+
+* darwin_stop_world.c (GC_mach_threads): Remove static qualifier.
+* darwin_stop_world.c (GC_stop_init): Remove (as we do not need to
+really clear GC_mach_threads[]).
+* darwin_stop_world.c (GC_stop_world): Reset GC_mach_threads_count
+(instead of calling GC_stop_init).
+* include/private/pthread_support.h (GC_stop_init): Remove proto.
+* pthread_support.c (GC_stop_init): Add proto (unless Darwin).
+* pthread_support.c (GC_thr_init): Don't call GC_stop_init() if
+GC_DARWIN_THREADS.
+
+* darwin_stop_world.c (GC_stack_range_for): New static function
+(move the code from GC_push_all_stacks).
+* darwin_stop_world.c (GC_push_all_stacks): Call
+GC_stack_range_for(); rename kern_return local variable to
+kern_result.
+* darwin_stop_world.c (GC_is_mach_marker): Change argument type
+from mach_port_t to thread_act_t.
+* pthread_support.c (GC_is_mach_marker): Likewise.
+
+* darwin_stop_world.c (GC_push_all_stacks): Fix "my_task" local
+variable initialization (always call current_task()).
+* pthread_support.c (GC_thr_init, GC_register_my_thread_inner):
+Don't set thread's stop_info.stack_ptr value for Darwin.
+* include/private/darwin_stop_world.h (thread_stop_info): Update
+the comment for stack_ptr.
+
+* darwin_stop_world.c (GC_push_all_stacks): Rename "r", "me" local
+variables to "kern_return" and "my_thread" ones, respectively;
+call mach_port_deallocate() unconditionally.
+* darwin_stop_world.c (GC_stop_world): Don't call mach_thread_self
+if DEBUG_THREADS.
+
+* darwin_stop_world.c (GC_mach_thread): Move from
+darwin_stop_world.h.
+* include/private/darwin_stop_world.h (GC_mach_thread): Remove.
+* win32_threads.c (GC_start_world): Define "thread_id" local
+variable only if GC_ASSERTIONS; decide whether to resume a thread
+based on its "suspended" field value; assert that suspended thread
+stack_base is non-zero and the thread is not our one.
+
+* darwin_stop_world.c (GC_thread_resume): New inline function
+(move code from GC_thread_resume).
+* darwin_stop_world.c (GC_start_world): Check result of
+task_threads(); call GC_thread_resume().
+* os_dep.c (GC_malloc_heap_l, GC_is_malloc_heap_base): Define
+only if not CYGWIN32.
+* os_dep.c (GC_is_heap_base): Call GC_is_malloc_heap_base() only
+if not CYGWIN32.
+
+* darwin_stop_world.c (FindTopOfStack): Change return type to
+ptr_t (from long); make GC_INNER; add GC_ prefix.
+* darwin_stop_world.c (GC_push_all_stacks): Add thread_blocked
+local variable (initialized from the corresponding GC_thread
+field unless GC_query_task_threads); add assertion that our
+thread is not blocked; prefix FindTopOfStack with GC_ and remove
+no longer needed cast to ptr_t of the result; handle thread
+blocked case (and remove FIXME); use GC_push_all_stack_sections
+unless GC_query_task_threads (and remove FIXME).
+* pthread_support.c (GC_FindTopOfStack): Declare (if needed).
+* pthread_support.c (GC_do_blocking_inner): Call
+GC_save_regs_in_stack (if needed) before acquiring the lock.
+* win32_threads.c (GC_do_blocking_inner): Likewise.
+* pthread_support.c (GC_do_blocking_inner): Set/clear topOfStack
+field of GC_thread (Darwin only).
+* include/private/pthread_support.h (GC_thread): Add topOfStack
+field for Darwin (unless DARWIN_DONT_PARSE_STACK).
+
+* finalize.c (GC_check_finalizer_nested): Change return type to
+char pointer (instead of int pointer); use explicit cast for
+GC_finalizer_nested assignment.
+* pthread_support.c (GC_check_finalizer_nested): Likewise.
+* win32_threads.c (GC_check_finalizer_nested): Likewise.
+* finalize.c (GC_finalizer_nested): Change type to unsigned char.
+* finalize.c (GC_notify_or_invoke_finalizers): Change type of
+"pnested" local variable to char pointer.
+* pthread_support.c (GC_do_blocking_inner,
+GC_call_with_gc_active): Use explicit cast for "thread_blocked"
+field assignment.
+* win32_threads.c (GC_lookup_pthread): Use explicit cast for
+"suspended" field assignment.
+* win32_threads.c (GC_Thread_Rep): Use short type for
+finalizer_skipped; use char type for finalizer_nested and flags
+fields and reorder some fields (to minimize GC_Thread_Rep
+structure size).
+* include/private/pthread_support.h (GC_Thread_Rep): Likewise.
+* win32_threads.c (GC_Thread_Rep): Use char type for suspended
+field (instead of GC_bool).
+* include/private/pthread_support.h (GC_Thread_Rep): Use char type
+for thread_blocked field (instead of short).
+
+* darwin_stop_world.c (GC_query_task_threads): New variable (or
+macro).
+* darwin_stop_world.c (GC_push_all_stacks): Use
+GC_query_task_threads (to choose between algorithms based on
+kernel task_threads and based on GC_threads table); update FIXME;
+remove commented out GC_push_one statements.
+* pthread_support.c (GC_thr_init, GC_do_blocking_inner,
+GC_call_with_gc_active, GC_register_my_thread_inner): Initialize
+stack_ptr field for all platforms.
+* pthread_support.c (GC_call_with_gc_active): Initialize
+saved_stack_ptr field for all platforms.
+* include/private/darwin_stop_world.h (thread_stop_info): Add
+stack_ptr field; change type of already_suspended from int to
+GC_bool.
+
+* darwin_stop_world.c (GC_MAX_MACH_THREADS): New macro.
+* darwin_stop_world.c (GC_mach_threads, GC_stop_init): Use
+GC_MAX_MACH_THREADS instead of THREAD_TABLE_SZ.
+* darwin_stop_world.c (GC_mach_threads): Add FIXME.
+* darwin_stop_world.c (GC_stop_init, GC_suspend_thread_list,
+GC_stop_world): Use FALSE and TRUE for already_suspended field and
+"changed", "found" variables.
+* darwin_stop_world.c (GC_is_mach_marker): New prototype (only if
+PARALLEL_MARK).
+* darwin_stop_world.c (GC_suspend_thread_list): Change return type
+to GC_bool; change type of "changed", "found" to GC_bool; make
+"my_thread" as an argument (instead of acquiring/deallocating it
+locally); do not add my_thread, GC_mach_handler_thread and marker
+threads to GC_mach_threads table; check for overflow of
+GC_mach_threads table; increase GC_mach_threads_count if "found"
+is true and info.suspend_count is non-zero.
+* darwin_stop_world.c (GC_suspend_thread_list, GC_start_world):
+Adjust "thread" format specifiers for GC_printf(); search thread
+in "old_list" starting from the previous found one.
+* darwin_stop_world.c (GC_stop_world): Rename "changes" to
+"changed" local variable; remove "result" variable; adjust
+GC_printf debugging message.
+* darwin_stop_world.c (GC_start_world): Do not check for
+my_thread and GC_use_mach_handler_thread (since they are not added
+to GC_mach_threads table); call thread_info() only if
+DEBUG_THREADS or GC_ASSERTIONS.
+* pthread_support.c (marker_mach_threads): New static variable (if
+Darwin).
+* pthread_support.c (GC_is_mach_marker): New function (if Darwin).
+* pthread_support.c (GC_mark_thread): Fill in marker_mach_threads
+table (if Darwin).
+
+* alloc.c (GC_parallel): Define only if THREADS.
+* misc.c (GC_get_parallel): Likewise.
+* include/gc.h (GC_parallel, GC_get_parallel,
+GC_get_suspend_signal, GC_allow_register_threads,
+GC_register_my_thread, GC_unregister_my_thread): Define only if
+GC_THREADS.
+* include/gc.h (GC_get_heap_size): Fix a typo in a comment.
+
+* configure.ac: Use `AC_C_INLINE'.
+* include/private/gc_priv.h (GC_INLINE): Use "inline" keyword
+(determined by configure AC_C_INLINE) if HAVE_CONFIG_H is defined.
+
+* dyn_load.c (DL_ITERATE_PHDR_STRONG): New macro (define for
+FreeBSD).
+* dyn_load.c (GC_register_main_static_data): Move the definition
+above GC_register_dynamic_libraries_dl_iterate_phdr one (FreeBSD
+case); unconditionally return FALSE if DL_ITERATE_PHDR_STRONG.
+* dyn_load.c (GC_register_dynamic_libraries_dl_iterate_phdr): Test
+GC_register_main_static_data() result (instead of direct testing
+of dl_iterate_phdr (to prevent a compiler warning).
+* os_dep.c (CODE_OK): Test si_code also for the value of 2
+(FreeBSD case; required for FreeBSD v7+).
+* os_dep.c (CODE_OK): Properly use parentheses (HPUX case).
+* include/private/gcconfig.h (DATASTART): Cast etext argument in
+GC_FreeBSDGetDataStart() call; remove unnecessary "&" (FreeBSD
+case).
+
+* include/private/specific.h (quick_thread_id): Define thru
+GC_approx_sp(); define as a macro.
+* include/private/specific.h (getspecific): Use GC_INLINE instead
+of __inline__ (to work around Sun CC which does not recognize
+inline keyword surrounded with underscores).
+
+* darwin_stop_world.c (FindTopOfStack): Simplify condition
+expressions.
+* darwin_stop_world.c (GC_push_all_stacks): Merge two variants
+of this function (DARWIN_DONT_PARSE_STACK).
+* darwin_stop_world.c (GC_push_all_stacks): Add a check for our
+thread is found (same as in pthread_stop_world.c).
+* darwin_stop_world.c (GC_push_all_stacks): Print the number of
+scanned threads if verbose (same as in pthread_stop_world.c).
+
+* darwin_stop_world.c (GC_push_all_stacks): Reset
+thread_state_count value before every thread_get_state call;
+refine the comment for thread_state_count.
+* darwin_stop_world.c (GC_push_all_stacks): Ignore rsp, rip/eip,
+rflags, cs, fs, gs, ss, ds, es, __pc registers; uncomment ebp
+register pushing.
+* darwin_stop_world.c (GC_push_all_stacks): Set outCount to
+GC_MACH_THREAD_STATE_COUNT (instead of THREAD_STATE_MAX).
+* darwin_stop_world.c (GC_push_all_stacks): Remove FIXME and WARN
+for i386.
+
+* doc/README.macros (DARWIN_DONT_PARSE_STACK): Fix a typo.
+* darwin_stop_world.c (GC_use_mach_handler_thread): Change type
+to GC_bool.
+* darwin_stop_world.c (GC_suspend_thread_list, GC_start_world):
+Simplify the expressions involving GC_use_mach_handler_thread.
+* darwin_stop_world.c (GC_darwin_register_mach_handler_thread):
+Initialize GC_use_mach_handler_thread to TRUE (instead of 1).
+
+* include/gc_pthread_redirects.h (GC_pthread_sigmask, GC_dlopen,
+pthread_sigmask, dlopen): Don't define for Win32 pthreads (and
+don't include signal.h and dlfcn.h).
+
+* dyn_load.c (GC_register_dynlib_callback): Add FIXME.
+
+* include/private/gcconfig.h: Add support for FreeBSD on ppc64.
+
+* os_dep.c (PROTECT, UNPROTECT): Correct VM_PROT_EXEC to
+VM_PROT_EXECUTE.
+
+* os_dep.c (os2_alloc): Don't set PAG_EXECUTE unless
+pages_executable is on.
+* os_dep.c (os2_alloc): Add FIXME (for recursion).
+* os_dep.c (UNPROTECT): Abort with a more informative message if
+pages_executable is on ("mprotect" case).
+* os_dep.c (PROTECT, UNPROTECT): Set VM_PROT_EXEC if
+pages_executable is on (Darwin case).
+* pthread_support.c (GC_init_real_syms): Abort with an informative
+message if libgc is linked after libpthread.
+
+* dyn_load.c (GC_register_dynlib_callback): Adjust "start" pointer
+for 64-bit targets.
+* pthread_support.c (start_mark_threads): Expand PTHREAD_CREATE
+macro.
+* pthread_support.c (start_mark_threads): Call INIT_REAL_SYMS()
+since REAL(pthread_create) is used.
+* pthread_support.c (PTHREAD_CREATE): Remove unused.
+
+* extra/threadlibs.c (main): Remove --wrap for "read" (since not
+wrapped anymore).
+* doc/README.linux (GC_USE_LD_WRAP): Likewise.
+* os_dep.c (__wrap_read): Likewise.
+
+* include/gc_pthread_redirects.h: Test GC_PTHREADS and GC_H at the
+beginning of the file.
+* include/gc_pthread_redirects.h (GC_PTHREAD_EXIT_ATTRIBUTE): New
+macro (defined only for Linux and Solaris).
+* include/gc_pthread_redirects.h (GC_pthread_cancel,
+GC_pthread_exit): Declare new API function (only if
+GC_PTHREAD_EXIT_ATTRIBUTE).
+* include/gc_pthread_redirects.h (pthread_cancel, pthread_exit):
+Redirect (if GC_PTHREAD_EXIT_ATTRIBUTE).
+* include/private/pthread_support.h (DISABLED_GC): New macro.
+* pthread_support.c (pthread_cancel, pthread_exit): Restore
+original definition or declare "real" function (if needed and
+GC_PTHREAD_EXIT_ATTRIBUTE).
+* pthread_support.c (GC_pthread_cancel_t, GC_pthread_exit_t):
+Declare new types if needed.
+* pthread_support.c (GC_pthread_cancel, GC_pthread_exit): New
+function definition (only if GC_PTHREAD_EXIT_ATTRIBUTE).
+* pthread_support.c (GC_init_real_syms): Initialize pointers to
+the "real" pthread_cancel and pthread_exit (only if
+GC_PTHREAD_EXIT_ATTRIBUTE).
+* pthread_support.c (GC_unregister_my_thread): Enable collections
+if DISABLED_GC was set (only if GC_PTHREAD_EXIT_ATTRIBUTE).
+* pthread_support.c (pthread_cancel, pthread_exit): New wrapped
+function definition (only if GC_PTHREAD_EXIT_ATTRIBUTE defined).
+* pthread_support.c (GC_start_routine): Refine the comment.
+* extra/threadlibs.c (main): Adjust --wrap (add "read",
+"pthread_exit", "pthread_cancel" but remove "sleep").
+* doc/README.linux (GC_USE_LD_WRAP): Likewise.
+
+* include/gc.h (GC_MALLOC_STUBBORN): Remove trailing ';' in the
+macro definition.
+* include/gc.h (GC_reachable_here): Likewise.
+* include/gc.h (GC_reachable_here): Prefix and postfix "volatile"
+with double '_'.
+
+* pthread_start.c: New file.
+* CMakeLists.txt (SRC): Add pthread_start.c.
+* Makefile.am (libgc_la_SOURCES): Likewise.
+* Makefile.direct (CSRCS): Likewise.
+* Makefile.direct (OBJS): Add pthread_start.obj.
+* extra/gc.c: Add a comment; include pthread_start.c.
+* pthread_support.c (start_info): Move the struct definition down
+closer to its usage.
+* pthread_support.c (GC_thread_exit_proc): Replace STATIC with
+GC_INNER.
+* pthread_support.c (GC_inner_start_routine): Move to the
+definition to pthread_start.c; leave only the prototype; remove
+STATIC.
+* pthread_support.c (GC_start_rtn_prepare_thread): New function
+(contains parts of the original GC_inner_start_routine).
+
+* configure.ac (NO_EXECUTE_PERMISSION): Add comment.
+* doc/README.macros (NO_EXECUTE_PERMISSION): Update the
+documentation.
+* include/gc.h (GC_set_pages_executable, GC_get_pages_executable):
+New API function declaration.
+* os_dep.c (OPT_PROT_EXEC): Remove (superseded by
+pages_executable).
+* os_dep.c (pages_executable): New static variable.
+* os_dep.c (IGNORE_PAGES_EXECUTABLE): New macro (used by
+GC_get_pages_executable only).
+* os_dep.c (GC_unix_mmap_get_mem, GC_remap, PROTECT, UNPROTECT):
+Replace OPT_PROT_EXEC with pages_executable.
+* os_dep.c (GC_unix_mmap_get_mem, GC_remap, GC_win32_get_mem,
+GC_wince_get_mem, UNPROTECT): Undefine IGNORE_PAGES_EXECUTABLE.
+* os_dep.c (GC_win32_get_mem, GC_wince_get_mem, GC_remap, PROTECT,
+UNPROTECT): Use PAGE_EXECUTE_... only if pages_executable is on.
+* os_dep.c (GC_set_pages_executable, GC_get_pages_executable): New
+API function definition.
+
+* tests/test.c (check_heap_stats): Increase max_heap_sz by 20% for
+64-bit CPUs (to prevent "Unexpected heap growth" failure on Win64,
+at least).
+
+* tests/test.c (check_heap_stats): Increase max_heap_sz by 25% for
+32-bit CPUs (to prevent "Unexpected heap growth" failure).
+
+* gc_dlopen.c (dlopen): Prototype REAL_DLFUNC if GC_USE_LD_WRAP.
+* pthread_support.c (pthread_create, pthread_join, pthread_detach,
+pthread_sigmask): Likewise.
+* gc_dlopen.c (dlopen): Remove cast (redundant since the prototype
+is added).
+* gc_dlopen.c (GC_dlopen): Fix return type.
+* pthread_support.c (GC_init_real_syms): Don't define
+LIBPTHREAD_NAME, LIBPTHREAD_NAME_LEN, len, namebuf and
+libpthread_name if RTLD_NEXT.
+
+* gc_dlopen.c (disable_gc_for_dlopen): Update the comment.
+* gc_dlopen.c (dlopen): Likewise.
+* include/gc.h (GC_enable_incremental): Refine the comment.
+* include/gc.h (DECLSPEC_NORETURN): Define macro as empty if
+missing (only for Win32).
+* include/gc.h (GC_ExitThread): Use DECLSPEC_NORETURN.
+* win32_threads.c (GC_ExitThread): Likewise.
+* include/gc.h (GC_endthreadex): Add a comment.
+
+* include/cord.h: Fix typos.
+
+* Makefile.am (EXTRA_DIST): Add "CMakeLists.txt" and
+"tests/CMakeLists.txt".
+* doc/doc.am (dist_pkgdata_DATA): Add "doc/README.cmake".
+
+* mach_dep.c (NO_GETCONTEXT): Also define if AVR32.
+* include/private/gcconfig.h (AVR32): New macro (also define the
+supplementary macros for the target).
+* include/private/thread_local_alloc (USE_COMPILER_TLS): Don't
+define for AVR32.
+
+* tests/leak_test.c (main): Explicitly define as returning int
+(to prevent a spurious test failure on some Linux/alpha targets).
+* tests/thread_leak_test.c (main): Likewise.
+* tests/thread_leak_test.c: Initialize GC_find_leak in the main
+thread (before GC_INIT) only.
+* tests/leak_test.c (main): Use GC_set_find_leak() instead of
+accessing GC_find_leak directly.
+* tests/thread_leak_test.c (main): Likewise.
+
+* include/gc.h (GC_find_leak, GC_finalize_on_demand,
+GC_java_finalization, GC_dont_expand, GC_no_dls,
+GC_dont_precollect): Simplify the comment (remove the information
+about data races since the value is boolean).
+
+* os_dep.c (GC_get_stack_base, GC_get_main_stack_base): New
+Solaris-specific implementation (based on thr_stksegment).
+* os_dep.c (stackbase_main_self, stackbase_main_ss_sp): New static
+variable used by the Solaris-specific GC_get_stack_base().
+
+* pthread_support.c (GC_mark_thread_local_free_lists,
+GC_check_tls): Mark (and check) only for live threads (in case of
+GC_destroy_thread_local() is called already but GC_delete_thread()
+is not yet).
+* win32_threads.c (GC_mark_thread_local_free_lists, GC_check_tls):
+Likewise.
+
+* NT_MAKEFILE: Remove the comment about DLL and Win32S.
+* NT_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_MAKEFILE: Add ".SUFFIXES" directive (to handle gc_cpp.cc
+properly on VS 2005+).
+* NT_MAKEFILE: Update GC log file name in comments.
+* NT_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_THREADS_MAKEFILE: Likewise.
+* doc/README.win32: Likewise.
+* NT_MAKEFILE: Remove ":full" for "-debug" option (since no
+longer supported by VS).
+* NT_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_MAKEFILE: Commented out copying of gc_cpp.cc to gc_cpp.cpp.
+* NT_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_THREADS_MAKEFILE: Likewise.
+* NT_STATIC_THREADS_MAKEFILE: Add -D PARALLEL_MARK option.
+* NT_STATIC_THREADS_MAKEFILE: Increase stack size for gctest.exe.
+* NT_X64_STATIC_THREADS_MAKEFILE: Remove "-stack" option (use the
+default stack size limit).
+* NT_X64_THREADS_MAKEFILE: Rename "gc64_dll.dll" to "gc64.dll".
+* win32_threads.c (GC_get_next_stack): Always define (since it is
+also used for Cygwin now).
+
+* alloc.c (GC_maybe_gc): Move GC_notify_full_gc() call upper to
+be just before GC_clear_marks() call.
+* include/gc_mark.h (GC_start_callback_proc): Refine the comment.
+
+* Makefile.am (check_LTLIBRARIES): Initialize to empty.
+* tests/tests.am (TESTS, check_PROGRAMS): Add staticrootstest.
+* tests/tests.am (staticrootstest_SOURCES, staticrootstest_LDADD,
+libstaticrootslib_la_SOURCES, libstaticrootslib_la_LIBADD,
+libstaticrootslib_la_LDFLAGS, libstaticrootslib_la_DEPENDENCIES):
+Define.
+* tests/tests.am (check_LTLIBRARIES): Add libstaticrootslib.la.
+
+* tests/staticrootstest.c: New file.
+* tests/staticrootslib.c: Likewise.
+
+* dyn_load.c (GC_get_next_stack, GC_cond_add_roots): Define for
+Cygwin as well as other win32 targets.
+* dyn_load.c (GC_wnt): Define to constant true.
+* dyn_load.c (GC_register_dynamic_libraries): Define for Cygwin as
+well as other win32 targets.
+* mark_rts.c (rt_hash, GC_roots_present, add_roots_to_index):
+Don't define for Cygwin, as on other win32.
+* mark_rts.c (GC_add_roots_inner, GC_clear_roots): Handle on
+Cygwin as for other win32 targets.
+* mark_rts.c (GC_rebuild_root_index): Don't declare on Cygwin, as
+other win32.
+* mark_rts.c (GC_remove_tmp_roots): Do declare on Cygwin as on
+other win32.
+* mark_rts.c (GC_remove_roots, GC_remove_roots_inner): Don't
+declare on Cygwin as on other win32.
+* mark_rts.c (GC_is_tmp_root): Do declare on Cygwin when
+!NO_DEBUGGING, as on other win32 targets.
+* mark_rts.c (GC_cond_register_dynamic_libraries): Handle on
+Cygwin as for other win32 targets.
+* os_dep.c (GC_setpagesize): Handle on Cygwin as on other win32.
+* os_dep.c (GC_get_main_stack_base): Don't declare on Cygwin, as
+other win32.
+* os_dep.c (GC_sysinfo): Declare on Cygwin, as other win32.
+* os_dep.c (GC_win32_get_mem): Declare on Cygwin, as on other
+Win32, but call GC_unix_get_mem instead of GlobalAlloc.
+* os_dep.c (GC_win32_free_heap): Declare on Cygwin (as empty).
+* ptr_chck.c (GC_is_visible): Register dynamic libraries on Cygwin
+as on other win32 platforms.
+* win32_threads.c (GC_get_next_stack): Define on Cygwin as well as
+for dynamic loading targets.
+* include/private/gc_priv.h (GC_INNER): Don't try to use
+visibility on Cygwin which does not support it.
+* include/private/gc_priv.h (struct roots): Don't declare r_next
+member on Cygwin as on other windows hosts.
+* include/private/gc_priv.h (LOG_RT_SIZE, RT_SIZE): Don't define
+likewise.
+* include/private/gc_priv.h (struct _GC_arrays): Do declare
+_heap_bases[] member and don't declare _root_index likewise.
+* include/private/gc_priv.h (GC_heap_bases): Do define likewise.
+* include/private/gc_priv.h (_SYSTEM_INFO): Do forward-declare
+likewise.
+* include/private/gc_priv.h (GC_sysinfo): Do declare extern
+likewise.
+* include/private/gcconfig.h (GC_win32_get_mem, GET_MEM): Do
+prototype on Cygwin as other win32 platforms.
+
+* os_dep.c (GC_get_main_stack_base): Use pthread_getattr_np() and
+pthread_attr_getstack() instead of GC_get_stack_base() (and check
+returned stackaddr for NULL); output a warning on failure.
+
+* alloc.c (GC_start_call_back): Replace the definition type to
+GC_start_callback_proc.
+* alloc.c (GC_set_start_callback, GC_get_start_callback): New
+setter/getter function.
+* alloc.c (GC_try_to_collect_inner): Call GC_notify_full_gc()
+unconditionally (because GC_try_to_collect_inner always does full
+GC).
+* include/gc_mark.h (GC_start_callback_proc): New type.
+* include/gc_mark.h (GC_set_start_callback,
+GC_get_start_callback): New API function declaration.
+
+* doc/README.macros (USE_GET_STACKBASE_FOR_MAIN): Document.
+* os_dep.c (GC_get_main_stack_base): Recognize
+USE_GET_STACKBASE_FOR_MAIN (only if THREADS and LINUX_STACKBOTTOM)
+and use GC_get_stack_base() in this case.
+
+* os_dep.c (GC_get_stack_base): Add LOCK/UNLOCK() (since
+GC_find_limit_with_bound() should be called with the lock held).
+* backgraph.c (FOR_EACH_PRED): Fix a typo.
+
+* alloc.c (GC_set_stop_func, GC_get_stop_func): Add
+DCL_LOCK_STATE.
+* finalize.c (GC_notify_or_invoke_finalizers): Likewise.
+* gc_dlopen.c (disable_gc_for_dlopen): Likewise.
+* gcj_mlc.c (maybe_finalize, GC_debug_gcj_malloc): Likewise.
+* mark.c (GC_print_trace): Likewise.
+* misc.c (GC_set_warn_proc, GC_get_warn_proc, GC_enable,
+GC_disable, GC_new_free_list, GC_new_kind, GC_new_proc,
+GC_set_oom_fn, GC_get_oom_fn, GC_set_finalizer_notifier,
+GC_get_finalizer_notifier): Likewise.
+* os_dep.c (GC_get_stack_base, GC_print_callers): Likewise.
+* pthread_support.c (GC_is_thread_tsd_valid,
+GC_wait_for_gc_completion, GC_init_parallel, GC_do_blocking_inner,
+GC_call_with_gc_active, GC_unregister_my_thread, pthread_join,
+pthread_detach, GC_register_my_thread, GC_inner_start_routine,
+pthread_create): Likewise.
+* reclaim.c (GC_print_all_errors): Likewise.
+* win32_threads.c (GC_is_thread_tsd_valid, GC_register_my_thread,
+GC_unregister_my_thread, GC_do_blocking_inner,
+GC_call_with_gc_active, GC_lookup_pthread, GC_pthread_join,
+GC_pthread_start_inner, GC_thread_exit_proc, GC_pthread_detach,
+GC_init_parallel): Likewise.
+
+* doc/README.darwin: Update.
+
+* CMakeLists.txt: Adjust INCLUDE_DIRECTORIES and SRC (to make it
+usable on Mac OS X).
+* doc/README.cmake: Update.
+
+* CMakeLists.txt: New file (adding CMake support).
+* tests/CMakeLists.txt: Likewise.
+* doc/README.cmake: Likewise.
+
+* configure.ac (darwin): Don't define HAS_PPC_THREAD_STATE...
+macros.
+* include/private/gc_priv.h (THREAD_FLD): Recognize
+__DARWIN_UNIX03 instead of HAS_PPC_THREAD_STATE... macros.
+
+* pthread_support.c: Include <sys/param.h> and <sys/sysctl.h> for
+OpenBSD.
+* pthread_support.c (get_ncpu): Define also for Darwin, NetBSD and
+OpenBSD.
+* pthread_support.c (GC_thr_init): Use get_ncpu() for Darwin,
+NetBSD and OpenBSD.
+
+* mallocx.c (GC_generic_malloc_many, GC_malloc_many): Define even
+if THREADS is undefined.
+* include/gc.h (GC_malloc_many): Update the comment.
+
+* include/gc_cpp.h (GC_PLACEMENT_DELETE): Define for Embarcadero
+(formerly known as Borland) C++ compiler v6.21+.
+* include/gc_cpp.h (GC_NO_OPERATOR_NEW_ARRAY): Define for ancient
+VC++ compilers.
+
+* win32_threads.c (GC_register_my_thread_inner,
+GC_pthread_start_inner): Undo the previous commit changes for
+the thread flags and DETACHED state (since the state is only
+tested in GC_thread_exit_proc).
+
+* include/gc.h (GC_unregister_my_thread): Fix a typo; update the
+comment.
+* pthread_support.c (GC_delete_thread): Allow to delete the main
+thread (don't call GC_INTERNAL_FREE for it); update the comment.
+* win32_threads.c (GC_delete_thread): Likewise.
+* pthread_support.c (GC_unregister_my_thread): Add an assertion
+for FINISHED flag is unset.
+* tests/test.c (check_heap_stats): Test the main thread
+unregistering (only if THREADS).
+* win32_threads.c (GC_register_my_thread_inner): Set flags to
+DETACHED (only if GC_PTHREADS).
+* win32_threads.c (GC_unregister_my_thread): Add FIXME (for
+GC_wait_for_gc_completion).
+* win32_threads.c (GC_pthread_start_inner): Clear flags detached
+state if needed; set pthread_id and flags while holding the lock.
+
+* include/private/gc_priv.h (SIG_SUSPEND): Don't define for
+OpenBSD and Darwin.
+
+* include/gc.h: Recognize _M_X64 (as an alias for _AMD64_).
+
+* test.c (main, WinMain): Consistently don't invoke
+GC_enable_incremental() if MAKE_BACKGRAPH is defined, but
+do invoke it even if parallel marking is enabled.
+
+* tests/test.c (reverse_test): Comment out a check for MSWIN32
+(when determing BIG value) assuming outdated win32S.
+* tests/test.c (reverse_test): Rename to reverse_test_inner;
+change the declaration (to be of GC_fn_type); call itself thru
+GC_call_with_gc_active() if the argument is zero.
+* tests/test.c (reverse_test): New function added calling
+reverse_test_inner thru GC_do_blocking (to test GC_do_blocking and
+GC_call_with_gc_active).
+
+* doc/README.macros (IGNORE_DYNAMIC_LOADING, PLATFORM_ANDROID):
+Document.
+* dyn_load.c: Don't include <elf.h> if PLATFORM_ANDROID.
+* dyn_load.c: Include bionic <linker.h> (instead of <link.h>) if
+PLATFORM_ANDROID.
+* include/private/gcconfig.h (LINUX): Define also if
+PLATFORM_ANDROID (for the windows-based toolkit).
+* include/private/gcconfig.h (SEARCH_FOR_DATA_START): Explicitly
+define for Android/x86 platform.
+* include/private/gcconfig.h (IGNORE_DYNAMIC_LOADING): Recognize
+new macro (undefine DYNAMIC_LOADING in this case).
+* include/private/gcconfig.h (CANCEL_SAFE): Don't define if
+PLATFORM_ANDROID.
+* include/private/gcconfig.h (IF_CANCEL): Fix definition for the
+explicitly defined CANCEL_SAFE.
+
+* allchblk.c (GC_allochblk_nth): Don't call GC_remove_protection()
+if GC_DISABLE_INCREMENTAL.
+* reclaim.c (GC_reclaim_generic): Likewise.
+* checksums.c (GC_page_was_ever_dirty): Add prototype.
+* include/private/gc_locks.h (GC_mark_lock_holder): Don't declare
+unless PARALLEL_MARK.
+* include/private/gc_priv.h (GC_dirty_maintained,
+GC_page_was_dirty, GC_remove_protection, GC_dirty_init): Don't
+declare if GC_DISABLE_INCREMENTAL.
+* include/private/gc_priv.h (GC_print_finalization_stats): Don't
+declare if SMALL_CONFIG.
+* include/private/gcconfig.h (CHECKSUMS): Explicitly undefine if
+GC_DISABLE_INCREMENTAL (since nothing to check).
+* include/private/gcconfig.h (DEFAULT_VDB): Don't define if
+GC_DISABLE_INCREMENTAL.
+* os_dep.c (GC_dirty_maintained): Likewise.
+* mark.c (GC_initiate_gc): Don't call GC_read_dirty() if
+GC_DISABLE_INCREMENTAL.
+* os_dep.c (GC_gww_page_was_ever_dirty, GC_page_was_ever_dirty):
+Uncomment; define only if CHECKSUMS.
+
+* darwin_stop_world.c (GC_push_all_stacks): Fix a bug (call
+GC_push_all_stack() instead of GC_push_all_stack_frames()).
+* include/private/gc_priv.h (GC_push_all_stack_frames,
+GC_push_all_register_frames): Rename to
+GC_push_all_stack_sections and GC_push_all_register_sections,
+respectively.
+* mark_rts.c (GC_push_all_stack_frames,
+GC_push_all_register_frames, GC_push_all_stack_part_eager_frames,
+GC_push_current_stack): Likewise.
+* pthread_stop_world.c (GC_push_all_stacks): Likewise.
+* win32_threads.c (GC_push_stack_for): Likewise.
+* misc.c (GC_call_with_gc_active): Rename "frame" local variable
+to "stacksect".
+* pthread_support.c (GC_call_with_gc_active): Likewise.
+* win32_threads.c (GC_call_with_gc_active): Likewise.
+* pthread_support.c (GC_call_with_gc_active): Update FIXME for
+Darwin.
+* win32_threads.c (GC_Thread_Rep): Update the comment for
+traced_stack_sect.
+
+* darwin_stop_world.c (GC_push_all_stacks): Rename
+activation_frame to traced_stack_sect.
+* include/private/gc_priv.h (GC_push_all_stack_frames,
+GC_push_all_register_frames): Likewise.
+* include/private/pthread_support.h (GC_Thread_Rep): Likewise.
+* mark_rts.c (GC_push_all_register_frames,
+GC_push_all_stack_frames, GC_push_all_stack_part_eager_frames,
+GC_push_current_stack): Likewise.
+* pthread_stop_world.c (GC_push_all_stacks): Likewise.
+* pthread_support.c (GC_call_with_gc_active): Likewise.
+* win32_threads.c (GC_Thread_Rep, GC_call_with_gc_active,
+GC_push_stack_for): Likewise.
+* include/private/gc_priv.h (GC_activation_frame_s): Rename to
+GC_traced_stack_sect_s.
+* include/private/gc_priv.h (GC_activation_frame): Rename to
+GC_traced_stack_sect.
+* misc.c (GC_activation_frame, GC_call_with_gc_active): Likewise.
+* doc/README.macros (UNICODE): Document.
+
+* doc/README.macros (GC_READ_ENV_FILE): Document (new macro).
+* include/private/gc_priv.h (GETENV): Recognize GC_READ_ENV_FILE;
+declare and use GC_envfile_getenv().
+* misc.c (GC_envfile_content, GC_envfile_length): New static
+variable (only if GC_READ_ENV_FILE).
+* misc.c (GC_ENVFILE_MAXLEN): New macro (used in GC_envfile_init).
+* misc.c (GC_envfile_init, GC_envfile_getenv): New function (only
+if GC_READ_ENV_FILE).
+* misc.c (GC_init): Call GC_envfile_init() (before using GETENV)
+if GC_READ_ENV_FILE.
+* misc.c (GC_init): Move GC_setpagesize() and GC_init_win32()
+calls to be just before GC_envfile_init() one (since the latter
+uses GET_MEM).
+* misc.c (GC_abort): use ExitProcess() (instead of DebugBreak) for
+WinCE if NO_DEBUGGING; add a comment for DebugBreak() (for WinCE).
+* mark_rts.c (GC_add_roots_inner): Remove redundant trailing '\n'
+from the ABORT message.
+* misc.c (GC_init): Likewise.
+* os_dep.c (GC_get_main_stack_base, GC_register_data_segments):
+Likewise.
+* pthread_stop_world.c (GC_push_all_stacks): Likewise.
+* pthread_support.c (GC_init_real_syms, start_mark_threads):
+Likewise.
+
+* win32_threads.c (GC_get_next_stack): Don't define for Cygwin
+(since unused for now).
+
+* dyn_load.c (HAVE_REGISTER_MAIN_STATIC_DATA): Don't define unless
+GC_register_main_static_data() is defined.
+* dyn_load.c (GC_register_dynamic_libraries): Define only if used
+(if DYNAMIC_LOADING or PCR or Win32/CE).
+* dyn_load.c (GC_register_main_static_data): Define the default
+one only if DYNAMIC_LOADING.
+* include/private/gc_priv.h (GC_register_dynamic_libraries):
+Declare only if used (to prevent compiler warning).
+
+* mark_rts.c (GC_approx_sp): Add a comment (for GCC).
+
+
+== [7.2alpha4] 2009-12-01 ==
+
+* configure.ac (AC_CONFIG_COMMANDS): Quote srcdir value.
+
+* include/gc.h (GC_get_suspend_signal): New function declaration.
+* misc.c (GC_get_suspend_signal): New API function (only if
+THREADS).
+
+* alloc.c (min_bytes_allocd): Multiply GC_free_space_divisor by
+two if GC_incremental (instead of TRUE_INCREMENTAL).
+
+* sparc_mach_dep.S (GC_push_regs): Remove the reference.
+
+* os_dep.c (SIZE_T, PULONG_PTR): Remove.
+* os_dep.c (ULONG_PTR): Replace with GC_ULONG_PTR (defined as GC
+"word"); add the comment.
+* os_dep.c (GetWriteWatch_type, detect_GetWriteWatch,
+GC_gww_read_dirty): Prefix ULONG_PTR with "GC_".
+
+* win32_threads.c (THREAD_TABLE_SZ): Change back to a power-of-two
+const value (for speed).
+* win32_threads.c (THREAD_TABLE_INDEX): New macro.
+* win32_threads.c (GC_new_thread, GC_lookup_thread_inner,
+GC_delete_gc_thread, GC_delete_thread, GC_lookup_pthread): Use
+THREAD_TABLE_INDEX instead of THREAD_TABLE_SZ.
+* win32_threads.c (PTHREAD_MAP_HASH): Rename to PTHREAD_MAP_INDEX.
+
+* win32_threads.c (THREAD_TABLE_SZ): Make the const value prime.
+
+* backgraph.c: Remove apostrophe char from "#error".
+
+* doc/README.macros (GC_DISABLE_INCREMENTAL): Document.
+* include/private/gcconfig.h (GC_DISABLE_INCREMENTAL): Recognize
+new macro; implicitly define it if SMALL_CONFIG.
+* alloc.c (GC_incremental, GC_timeout_stop_func): Check for
+GC_DISABLE_INCREMENTAL instead of SMALL_CONFIG.
+* include/private/gc_priv.h (GC_incremental, TRUE_INCREMENTAL,
+GC_push_conditional): Likewise.
+* mark.c (GC_push_next_marked_dirty, GC_push_selected,
+GC_push_conditional, GC_block_was_dirty): Likewise.
+* misc.c (GC_enable_incremental): Likewise.
+* misc.c (GC_init): Likewise.
+
+* dyn_load.c (WIN32_LEAN_AND_MEAN): Guard with ifndef.
+* misc.c (WIN32_LEAN_AND_MEAN): Likewise.
+* os_dep.c (WIN32_LEAN_AND_MEAN): Likewise.
+* allchblk.c (GC_allochblk_nth): Fix a minor typo (don't/doesn't)
+in a comment.
+* backgraph.c: Likewise.
+* dyn_load.c (GC_register_dynamic_libraries): Likewise.
+* extra/threadlibs.c (main): Likewise.
+* pthread_support.c (pthread_join): Likewise.
+* tests/test.c (main): Likewise.
+
+* mach_dep.c (GC_push_regs): Remove STATIC (just to catch
+a duplicate symbol definition linker error).
+* misc.c (GC_clear_stack_inner): Likewise.
+* sparc_mach_dep.S (GC_push_regs): Comment out the reference.
+
+* include/private/gc_priv.h (GC_write_disabled): New variable
+declaration (only if GC_ASSERTIONS and Win32 threads).
+* misc.c (GC_write): Add assertion for GC_write_disabled value is
+not on (only if THREADS).
+* win32_threads.c (GC_write_disabled): New variable (only if
+GC_ASSERTIONS and not Cygwin).
+* win32_threads.c (GC_stop_world): Set and clear GC_write_disabled
+(while holding GC_write_cs).
+
+* win32_threads.c (GC_please_stop): If DllMain-based thread
+registration is not compiled in then define GC_please_stop as
+a non-volatile variable for assertion only.
+* win32_threads.c (GC_stop_world): Set and clear only if defined.
+* win32_threads.c (GC_stop_world): Add the comment for GC_printf()
+usage (while holding GC_write_cs).
+* win32_threads.c (GC_delete_gc_thread): Likewise.
+* os_dep.c (GC_remove_protection): Likewise.
+
+* pthread_support.c (GC_inner_start_routine): Join 3 sequential
+GC_printf() calls into a single one (for DEBUG_THREADS).
+
+* include/private/gc_priv.h (GC_total_stacksize): New variable
+declaration (only if THREADS).
+* alloc.c (GC_total_stacksize): New variable (only if THREADS).
+* alloc.c (min_bytes_allocd): Calculate stack_size using
+GC_stackbottom only in the single-threaded case; otherwise use
+GC_total_stacksize; print GC_total_stacksize value if
+DEBUG_THREADS.
+* darwin_stop_world.c (GC_push_all_stacks): Use "%p" printf type
+specifier for lo/hi values (instead of "%lx").
+* darwin_stop_world.c (GC_push_all_stacks): Use
+GC_push_all_stack_frames() instead of GC_push_all_stack().
+* darwin_stop_world.c (GC_push_all_stacks): Recalculate
+GC_total_stacksize value.
+* pthread_stop_world.c (GC_push_all_stacks): Likewise.
+* win32_threads.c (GC_push_all_stacks): Likewise.
+* win32_threads.c (GC_push_stack_for): Pass "me" argument; return
+stack size; don't check for non-zero value of thread->stack_base.
+* win32_threads.c (GC_push_all_stacks): Don't call
+GC_push_stack_for() and don't check for "t->id == me" if
+thread->stack_base is zero.
+
+* dyn_load.c (GC_dump_meminfo): Prefix "%lx" printf type specifier
+with "0x".
+* os_dep.c (PROTECT): Likewise.
+* win32_threads.c (GC_mark_thread_local_free_lists): Cast p->id to
+int (to match printf type specifier).
+
+* tests/test.c (check_heap_stats): Take into account the unmapped
+memory size when checking for "Unexpected heap growth"; remove
+FIXME.
+
+* alloc.c: Revert last change.
+
+* include/private/gcconfig.h (STACKBOTTOM): Add a presence check
+for eCos/NOSYS.
+* misc.c (GC_write): Comment out _Jv_diag_write() call (since no
+longer defined in GCJ).
+
+* os_dep.c (brk): Rename to ecos_gc_brk.
+
+* alloc.c (min_bytes_allocd): Use GC_stackbottom value to compute
+stack_size even if THREADS.
+* doc/README.macros (DEBUG_THREADS): Document.
+* pthread_support.c (DEBUG_THREADS): Remove the commented out
+definition.
+* win32_threads.c (DEBUG_WIN32_THREADS): Remove duplicate
+definition.
+* win32_threads.c: Include errno.h (except for WinCE).
+* win32_threads.c (GC_win32_start_inner): Copy "start" and "param"
+to local variables, and free "arg" parameter before "start"
+invocation.
+* win32_threads.c (GC_beginthreadex): Set errno to EAGAIN on error
+(instead of calling SetLastError(ERROR_NOT_ENOUGH_MEMORY)).
+* win32_threads.c (GC_beginthreadex): Return 0 on error (instead
+of -1).
+
+* darwin_stop_world.c (GC_darwin_register_mach_handler_thread):
+Use GC_INNER for the function definition.
+* include/private/darwin_stop_world.h
+(GC_darwin_register_mach_handler_thread): Remove the prototype.
+* os_dep.c (GC_darwin_register_mach_handler_thread): Use GC_INNER
+for the function prototype.
+* include/private/gc_priv.h (NDEBUG): Explicitly define if
+NO_DEBUGGING and not GC_ASSERTIONS (before the standard headers
+inclusion).
+
+* include/private/gcconfig.h: Move DebugBreak() workaround (for
+x86mingw32ce toolchain) to gc_priv.h (after windows.h inclusion).
+
+* allchblk.c (GC_unmap_old, GC_merge_unmapped, GC_allochblk,
+GC_freehblk): Use GC_INNER for the function definition.
+* alloc.c (GC_never_stop_func, GC_should_collect,
+GC_try_to_collect_inner, GC_collect_a_little_inner,
+GC_set_fl_marks, GC_add_to_our_memory, GC_add_to_heap,
+GC_expand_hp_inner, GC_collect_or_expand, GC_allocobj): Likewise.
+* backgraph.c (GC_build_back_graph, GC_traverse_back_graph):
+Likewise.
+* blacklst.c (GC_default_print_heap_obj_proc, GC_bl_init,
+GC_promote_black_lists, GC_unpromote_black_lists,
+GC_add_to_black_list_normal, GC_add_to_black_list_stack,
+GC_is_black_listed): Likewise.
+* darwin_stop_world.c (GC_push_all_stacks, GC_push_all_stacks,
+GC_stop_init, GC_stop_world, GC_start_world): Likewise.
+* dbg_mlc.c (GC_has_other_debug_info, GC_store_back_pointer,
+GC_marked_for_finalization, GC_generate_random_backtrace_no_gc,
+GC_store_debug_info, GC_start_debugging,
+GC_debug_generic_malloc_inner,
+GC_debug_generic_malloc_inner_ignore_off_page,
+GC_debug_malloc_uncollectable, GC_debug_free_inner): Likewise.
+* dyn_load.c (GC_register_dynamic_libraries,
+GC_register_main_static_data, GC_init_dyld): Likewise.
+* finalize.c (GC_push_finalizer_structures, GC_finalize,
+GC_notify_or_invoke_finalizers, GC_print_finalization_stats):
+Likewise.
+* gcj_mlc.c (GC_core_gcj_malloc): Likewise.
+* headers.c (GC_find_header, GC_header_cache_miss,
+GC_scratch_alloc, GC_init_headers, GC_install_header,
+GC_install_counts, GC_remove_header, GC_remove_counts,
+GC_next_used_block, GC_prev_block): Likewise.
+* mach_dep.c (GC_with_callee_saves_pushed): Likewise.
+* malloc.c (GC_collect_or_expand, GC_alloc_large,
+GC_generic_malloc_inner, GC_generic_malloc_inner_ignore_off_page,
+GC_core_malloc_atomic, GC_core_malloc, GC_free_inner): Likewise.
+* mallocx.c (GC_generic_malloc_ignore_off_page): Likewise.
+* mark.c (GC_collection_in_progress, GC_clear_hdr_marks,
+GC_set_hdr_marks, GC_set_mark_bit, GC_clear_mark_bit,
+GC_clear_marks, GC_initiate_gc, GC_mark_some,
+GC_mark_stack_empty, GC_invalidate_mark_state,
+GC_signal_mark_stack_overflow, GC_mark_from, GC_help_marker,
+GC_mark_init, GC_push_all, GC_push_conditional,
+GC_mark_and_push_stack, GC_push_all_eager, GC_push_all_stack):
+Likewise.
+* mark_rts.c (GC_is_static_root, GC_roots_present, GC_approx_sp,
+GC_exclude_static_roots_inner, GC_push_all_register_frames,
+GC_push_all_stack_frames, GC_cond_register_dynamic_libraries,
+GC_push_roots): Likewise.
+* misc.c (GC_extend_size_map, GC_clear_stack, GC_err_write):
+Likewise.
+* new_hblk.c (GC_build_fl, GC_new_hblk): Likewise.
+* obj_map.c (GC_register_displacement_inner, GC_add_map_entry,
+GC_initialize_offsets): Likewise.
+* os_dep.c (GC_get_maps, GC_parse_map_entry, GC_text_mapping,
+GC_init_linux_data_start, GC_init_netbsd_elf, GC_setpagesize,
+GC_set_and_save_fault_handler, GC_setup_temporary_fault_handler,
+GC_reset_fault_handler, GC_get_register_stack_base, GC_init_win32,
+GC_add_current_malloc_heap, GC_is_heap_base, GC_unmap, GC_remap,
+GC_unmap_gap, GC_push_all_stacks, GC_gww_dirty_init,
+GC_dirty_init, GC_read_dirty, GC_page_was_dirty,
+GC_page_was_ever_dirty, GC_remove_protection,
+GC_write_fault_handler, GC_mprotect_stop, GC_mprotect_resume,
+GC_save_callers, GC_print_callers): Likewise.
+* pthread_stop_world.c (GC_push_all_stacks, GC_stop_world,
+GC_start_world, GC_stop_init): Likewise.
+* pthread_support.c (GC_mark_thread_local_free_lists,
+GC_lookup_thread, GC_reset_finalizer_nested,
+GC_check_finalizer_nested, GC_segment_is_thread_stack,
+GC_greatest_stack_base_below, GC_thr_init, GC_init_parallel,
+GC_do_blocking_inner, GC_lock, GC_acquire_mark_lock,
+GC_release_mark_lock, GC_wait_for_reclaim, GC_notify_all_builder,
+GC_wait_marker, GC_notify_all_marker): Likewise.
+* reclaim.c (GC_print_all_errors, GC_block_empty,
+GC_reclaim_generic, GC_start_reclaim, GC_continue_reclaim,
+GC_reclaim_all): Likewise.
+* thread_local_alloc.c (GC_init_thread_local,
+GC_destroy_thread_local, GC_mark_thread_local_fls_for): Likewise.
+* win32_threads.c (GC_reset_finalizer_nested,
+GC_check_finalizer_nested, GC_do_blocking_inner, GC_stop_world,
+GC_start_world, GC_push_all_stacks, GC_get_next_stack,
+GC_acquire_mark_lock, GC_release_mark_lock, GC_wait_for_reclaim,
+GC_notify_all_builder, GC_wait_marker, GC_notify_all_marker,
+GC_thr_init, GC_init_parallel, GC_lock,
+GC_mark_thread_local_free_lists): Likewise.
+* alloc.c (GC_add_current_malloc_heap, GC_build_back_graph,
+GC_traverse_back_graph): Use GC_INNER for the function prototype.
+* darwin_stop_world.c (GC_mprotect_stop, GC_mprotect_resume):
+Likewise.
+* dbg_mlc.c (GC_default_print_heap_obj_proc): Likewise.
+* dyn_load.c (GC_parse_map_entry, GC_get_maps,
+GC_segment_is_thread_stack, GC_roots_present, GC_is_heap_base,
+GC_get_next_stack): Likewise.
+* finalize.c (GC_reset_finalizer_nested,
+GC_check_finalizer_nested): Likewise.
+* gcj_mlc.c (GC_start_debugging): Likewise.
+* include/private/dbg_mlc.h (GC_save_callers, GC_print_callers,
+GC_has_other_debug_info, GC_store_debug_info): Likewise.
+* include/private/gc_hdrs.h (GC_header_cache_miss): Likewise.
+* include/private/gc_locks.h (GC_lock): Likewise.
+* include/private/gc_pmark.h (GC_signal_mark_stack_overflow,
+GC_mark_from): Likewise.
+* include/private/pthread_support.h (GC_lookup_thread,
+GC_stop_init): Likewise.
+* include/private/thread_local_alloc.h (GC_init_thread_local,
+GC_destroy_thread_local, GC_mark_thread_local_fls_for): Likewise.
+* malloc.c (GC_extend_size_map, GC_text_mapping): Likewise.
+* mark.c (GC_page_was_ever_dirty): Likewise.
+* mark_rts.c (GC_mark_thread_local_free_lists): Likewise.
+* misc.c (GC_register_main_static_data, GC_init_win32,
+GC_setpagesize, GC_init_linux_data_start,
+GC_set_and_save_fault_handler, GC_init_dyld, GC_init_netbsd_elf,
+GC_do_blocking_inner): Likewise.
+* os_dep.c (GC_greatest_stack_base_below): Likewise.
+* win32_threads.c (GC_write_fault_handler, GC_gww_dirty_init):
+Likewise.
+* include/private/gc_priv.h: Likewise.
+* include/private/gc_priv.h (GC_INNER): Update the comment.
+* doc/README.macros (GC_DLL): Update.
+
+* alloc.c (GC_collection_in_progress): Move the prototype to
+gc_priv.h.
+* gc_dlopen.c (GC_collection_in_progress): Likewise.
+* pthread_support.c (GC_collection_in_progress): Likewise.
+* misc.c (GC_init_parallel): Likewise.
+* pthread_support.c (GC_init_parallel): Likewise.
+* win32_threads.c (GC_init_parallel): Likewise.
+* darwin_stop_world.c (GC_thr_init): Likewise.
+* misc.c (GC_thr_init): Likewise.
+* pthread_stop_world.c (GC_thr_init): Likewise.
+* pthread_support.c (GC_thr_init): Likewise.
+* blacklst.c (GC_clear_bl, GC_copy_bl,
+GC_number_stack_black_listed): Make STATIC.
+* dbg_mlc.c (GC_print_obj, GC_make_closure,
+GC_debug_invoke_finalizer): Likewise.
+* malloc.c (GC_alloc_large_and_clear): Likewise.
+* mark.c (GC_push_selected, GC_push_marked1, GC_push_marked2,
+GC_push_marked4, GC_push_marked, GC_push_next_marked,
+GC_push_next_marked_dirty, GC_push_next_marked_uncollectable):
+Likewise.
+* misc.c (GC_clear_stack_inner): Likewise.
+* os_dep.c (GC_repeat_read, GC_default_push_other_roots): Likewise.
+* darwin_stop_world.c (FindTopOfStack): Make static; define only
+if not DARWIN_DONT_PARSE_STACK.
+* dbg_mlc.c (GC_debug_free_inner): Define only if DBG_HDRS_ALL.
+* dyn_load.c (GC_repeat_read): Remove unused prototype.
+* include/private/gc_pmark.h (GC_find_start): Likewise.
+* misc.c (GC_read, GC_register_finalizer_no_order): Likewise.
+* dyn_load.c (GC_segment_is_thread_stack): Add prototype (only if
+THREADS).
+* dyn_load.c (GC_register_main_static_data): Define only if
+DYNAMIC_LOADING.
+* finalize.c (GC_enqueue_all_finalizers): Remove unnecessary tail
+"return" statement.
+* gc_dlopen.c (GC_SOLARIS_THREADS): Don't recognize (since implies
+GC_PTHREADS).
+* include/gc.h: Fix a typo.
+* include/gc_inline.h (GC_ASSERT): Define (if not defined) since
+the header is public.
+* include/gc_inline.h (GC_generic_malloc_many): New public
+function declaration.
+* mallocx.c (GC_generic_malloc_many): Make public.
+* include/private/gc_priv.h (GC_INNER): Use visibility attribute
+(if available).
+* include/private/gc_priv.h (GC_EXTERN): Define using GC_INNER.
+* include/private/gc_priv.h: Include atomic_ops.h if THREADS and
+MPROTECT_VDB.
+* os_dep.c: Don't include atomic_ops.h
+* win32_threads.c: Likewise.
+* include/private/gc_priv.h (GC_push_selected, GC_push_regs,
+GC_push_marked, GC_number_stack_black_listed,
+GC_alloc_large_and_clear, GC_reclaim_or_delete_all,
+GC_generic_malloc_many, GC_make_closure,
+GC_debug_invoke_finalizer, GC_print_obj, GC_page_was_ever_dirty):
+Remove the prototype.
+* mark.c (GC_page_was_ever_dirty): Add prototype (only if
+PROC_VDB).
+* include/private/gc_priv.h (GC_push_next_marked_dirty,
+GC_push_next_marked, GC_push_next_marked_uncollectable): Move
+the prototype to mark.c.
+* include/private/gc_priv.h (GC_is_static_root): Declare only if
+not THREADS.
+* include/private/gc_priv.h (GC_free_inner): Declare only if
+THREADS.
+* include/private/gc_priv.h (GC_debug_free_inner): Declare only if
+THREADS and DBG_HDRS_ALL.
+* include/private/gc_priv.h (GC_markers): Declare GC_markers only
+if PARALLEL_MARK.
+* include/private/gc_priv.h (GC_register_main_static_data): Move
+the prototype to misc.c.
+* mach_dep.c (GC_push_regs): Make STATIC; define only along with
+HAVE_PUSH_REGS definition.
+* mach_dep.c (GC_clear_stack_inner): Replace K&R-style function
+definition with the ANSI C one.
+* mark.c (GC_started_thread_while_stopped): Declared only if not
+GNU C.
+* win32_threads.c (GC_started_thread_while_stopped): Don't define
+if GNU C.
+* mark.c (GC_mark_from): Avoid unbalanced brackets in
+#if-#else-#endif blocks.
+* mark_rts.c (GC_is_static_root): Define only if not THREADS.
+* os_dep.c (GC_get_stack_base): Make public (for OpenBSD).
+* os_dep.c (GC_page_was_ever_dirty): Comment out the function
+except for PROC_VDB.
+* tests/test.c (main): Don't reference GC_print_obj,
+GC_make_closure, GC_debug_invoke_finalizer,
+GC_page_was_ever_dirty, GC_is_fresh (in GC_noop).
+* thread_local_alloc.c: Don't include "gc_inline.h".
+* win32_threads.c (GC_write_fault_handler): Declare only if
+MPROTECT_VDB.
+
+* allchblk.c (DEBUG): Remove macro (since unused).
+* allchblk.c: Include private/gc_priv.h before other includes and
+definitions.
+* alloc.c: Likewise.
+* gc_dlopen.c: Likewise.
+* headers.c: Likewise.
+* mallocx.c: Likewise.
+* mark_rts.c: Likewise.
+* new_hblk.c: Likewise.
+* reclaim.c: Likewise.
+* mark.c: Include private/gc_pmark.h before other includes.
+* misc.c: Likewise.
+* dyn_load.c (_GNU_SOURCE): Move the definition to gc_priv.h.
+* pthread_support.c (_USING_POSIX4A_DRAFT10): Likewise.
+* pthread_support.c (_POSIX4A_DRAFT10_SOURCE): Remove (since
+already defined in gc_config_macros.h).
+* dyn_load.c (GC_init_dyld): Remove parameter cast for
+_dyld_register_func_for_add_image() and
+_dyld_register_func_for_remove_image(); add the comment about
+possible warnings; add FIXME for the deprecated
+_dyld_bind_fully_image_containing_address().
+* include/private/gc_priv.h: Include gc.h before the standard
+headers inclusion.
+* tests/test.c: Likewise.
+* include/private/gcconfig.h (DebugBreak): Update the comment.
+* typd_mlc.c (ED_INITIAL_SIZE): Remove ';'.
+
+* configure.ac (openbsd): Define GC_OPENBSD_THREADS.
+* configure.ac: Add AM_CONDITIONAL(OPENBSD_THREADS).
+* configure.ac: Add sparc-openbsd case.
+* doc/README.macros (GC_NETBSD_THREADS, GC_OPENBSD_THREADS):
+Document.
+* tests/test.c (main): Handle OpenBSD case.
+* include/private/pthread_stop_world.h: Likewise.
+* extra/threadlibs.c (main): Replace K&R-style function definition
+with the ANSI C one.
+* extra/threadlibs.c (main): Handle GC_OPENBSD_THREADS case.
+* dyn_load.c (OPENBSD): Recognize (similar to NETBSD).
+* include/gc_config_macros.h (GC_SOLARIS_THREADS): Recognize;
+define it for OpenBSD.
+* include/gc_pthread_redirects.h (GC_pthread_sigmask,
+pthread_sigmask): Don't declare and redefine for OpenBSD.
+* include/private/gcconfig.h: Handle OpenBSD (on arm, sh, i386,
+amd64, powerpc).
+* mach_dep.c (NO_GETCONTEXT): Likewise.
+* include/private/pthread_stop_world.h (thread_stop_info): Don't
+define last_stop_count field if OpenBSD.
+* misc.c (GC_init_dyld): Add declaration (if NetBSD).
+* misc.c (GC_init): Don't call GC_init_netbsd_elf() for OpenBSD.
+* os_dep.c (GC_init_netbsd_elf): Don't define for OpenBSD.
+* os_dep.c (old_segv_act, GC_jmp_buf_openbsd): New static variable
+(only if OpenBSD).
+* os_dep.c (GC_fault_handler_openbsd, GC_find_limit_openbsd,
+GC_skip_hole_openbsd): New static function (only if OpenBSD).
+* os_dep.c (GC_get_stack_base, GC_get_main_stack_base,
+GC_register_data_segments): Define specially for OpenBSD case.
+* os_dep.c (GC_fault_handler_lock): Initialize to
+AO_TS_INITIALIZER (instead of 0).
+* pthread_support.c (GC_allocate_lock): Likewise.
+* pthread_stop_world.c (NSIG, GC_print_sig_mask,
+GC_remove_allowed_signals, suspend_handler_mask, GC_stop_count,
+GC_world_is_stopped, GC_retry_signals, SIG_THR_RESTART,
+GC_suspend_ack_sem, GC_suspend_handler_inner, GC_suspend_handler,
+GC_restart_handler): Don't define and use if OpenBSD.
+* pthread_stop_world.c (GC_suspend_all, GC_stop_world,
+GC_start_world): Handle OpenBSD case.
+* pthread_stop_world.c (GC_stop_init): Define as empty if OpenBSD.
+* pthread_support.c (pthread_sigmask): Don't undefine the macro and
+don't define the wrapper function if OpenBSD.
+* pthread_support.c (GC_thr_init): Handle OpenBSD case.
+
+* dyn_load.c: Move the inclusion of private/gc_priv.h below
+definition of a feature macro (_GNU_SOURCE).
+
+* include/gc.h (REVEAL_POINTER): Remove redundant parentheses.
+* include/gc.h (GC_HIDE_POINTER, GC_REVEAL_POINTER): New macros
+(only if GC_I_HIDE_POINTERS).
+* backgraph.c (GET_OH_BG_PTR): Prefix REVEAL_POINTER() with "GC_".
+* dbg_mlc.c (GC_get_back_ptr_info): Likewise.
+* finalize.c (GC_grow_table, GC_dump_finalization, GC_finalize,
+GC_enqueue_all_finalizers): Likewise.
+* backgraph.c (SET_OH_BG_PTR): Prefix HIDE_POINTER() with "GC_".
+* finalize.c (GC_general_register_disappearing_link,
+GC_unregister_disappearing_link, GC_register_finalizer_inner,
+GC_finalize): Likewise.
+* include/private/dbg_mlc.h (HIDE_BACK_PTR): Likewise.
+* include/private/dbg_mlc.h (GC_I_HIDE_POINTERS): Define instead
+of I_HIDE_POINTERS.
+* include/private/gc_priv.h (GC_I_HIDE_POINTERS): Likewise.
+* include/gc.h (_GC_H): Strip leading underscore.
+* include/gc_backptr.h (_GC_H): Likewise.
+* include/gc_gcj.h (_GC_H): Likewise.
+* include/gc_mark.h (_GC_H): Likewise.
+* include/gc_typed.h (_GC_TYPED_H, _GC_H): Likewise.
+* include/javaxfc.h (_GC_H): Likewise.
+* include/new_gc_alloc.h (__GC_SPECIALIZE): Likewise.
+* include/private/dbg_mlc.h (_GC_H): Likewise.
+* include/private/gc_priv.h (_GC_H): Likewise.
+
+* gc_cpp.cc: Include "gc_cpp.h" instead of <gc_cpp.h>.
+
+* include/private/gc_priv.h (GC_INNER): New macro (for GC-scope
+variable definitions).
+* include/private/gc_priv.h (GC_EXTERN): Update the comment.
+* allchblk.c (GC_unmap_threshold): Define as GC_INNER.
+* alloc.c (GC_incremental, GC_world_stopped, GC_n_heap_sects,
+GC_n_memory, GC_fail_count): Likewise.
+* blacklst.c (GC_black_list_spacing, GC_print_heap_obj): Likewise.
+* gcj_mlc.c (GC_gcj_malloc_initialized, GC_gcjobjfreelist): Likewise.
+* mach_dep.c (GC_save_regs_ret_val): Likewise.
+* mark.c (GC_n_mark_procs, GC_obj_kinds, GC_n_kinds,
+GC_mark_stack, GC_mark_stack_limit, GC_mark_stack_size,
+GC_mark_stack_top, GC_mark_state, GC_mark_stack_too_small,
+GC_mark_no, GC_markers): Likewise.
+* mark_rts.c (GC_root_size, GC_push_typed_structures): Likewise.
+* misc.c (GC_allocate_ml, GC_debugging_started, GC_check_heap,
+GC_print_all_smashed, GC_print_back_height, GC_dump_regularly,
+GC_backtraces, GC_force_unmap_on_gcollect,
+GC_large_alloc_warn_interval, GC_is_initialized, GC_write_cs,
+GC_current_warn_proc, GC_blocked_sp, GC_activation_frame): Likewise.
+* os_dep.c (GC_page_size, GC_dont_query_stack_min,
+GC_no_win32_dlls, GC_wnt, GC_sysinfo, GC_push_other_roots,
+GC_dirty_maintained, GC_fault_handler_lock): Likewise.
+* pthread_support.c (GC_allocate_ml, GC_lock_holder,
+GC_need_to_lock, GC_thr_initialized, GC_threads,
+GC_in_thread_creation, GC_collecting, GC_allocate_lock,
+GC_mark_lock_holder): Likewise.
+* reclaim.c (GC_bytes_found, GC_fl_builder_count, GC_have_errors):
+Likewise.
+* win32_threads.c (GC_allocate_ml, GC_lock_holder,
+GC_need_to_lock, GC_mark_lock_holder, GC_collecting): Likewise.
+* extra/gc.c (GC_INNER, GC_EXTERN): Define as STATIC.
+* mach_dep.c (GC_with_callee_saves_pushed): Remove redundant {}.
+
+* include/private/gc_priv.h (GC_bytes_allocd, GC_objfreelist,
+GC_aobjfreelist): Replace GC_EXTERN to extern for SEPARATE_GLOBALS
+case (since they are not defined inside GC at present).
+* include/private/gc_priv.h (GC_objects_are_marked): Remove the
+declaration (since made static).
+* mark.c (GC_objects_are_marked): Define as STATIC.
+* win32_threads.c (GC_thr_initialized, GC_in_thread_creation):
+Likewise.
+* mark.c (GC_N_KINDS_INITIAL_VALUE): New macro (defined and used
+to initialize GC_n_kinds).
+* win32_threads.c (start_mark_threads): Adjust the comment.
+
+* alloc.c (GC_notify_full_gc): Use GC_INLINE for a tiny static
+function.
+* backgraph.c (pop_in_progress, GC_apply_to_each_object): Likewise.
+* mark_rts.c (add_roots_to_index): Likewise.
+
+* extra/gc.c: New file.
+* Makefile.am (EXTRA_DIST): Add "extra/gc.c".
+
+* misc.c (GC_log): Remove the declaration; move the definition (to
+the place where it is used); make STATIC.
+* misc.c (GC_init): Use GC_err_printf() instead of GC_log_printf()
+to print open log failure.
+* misc.c (GC_write): Don't abort on open log failure if the GC is
+compiled with GC_PRINT_VERBOSE_STATS (useful for WinCE).
+
+* include/private/gcconfig.h (USE_MMAP): Guard with ifndef.
+
+* allchblk.c (GC_fail_count, GC_large_alloc_warn_interval): Move
+the variable declaration to gc_priv.h.
+* alloc.c (GC_bytes_found, GC_unmap_threshold,
+GC_force_unmap_on_gcollect): Likewise.
+* dyn_load.c (GC_no_win32_dlls, GC_wnt): Likewise.
+* finalize.c (GC_fail_count): Likewise.
+* include/private/gc_locks.h (GC_allocate_ml, GC_lock_holder,
+GC_collecting, GC_mark_lock_holder, GC_need_to_lock): Likewise.
+* include/private/gc_pmark.h (GC_n_mark_procs, GC_mark_stack_size,
+GC_mark_stack_limit, GC_mark_stack_top, GC_mark_stack,
+GC_mark_stack_too_small, GC_mark_state): Likewise.
+* include/private/pthread_support.h (GC_threads,
+GC_thr_initialized, GC_in_thread_creation): Likewise.
+* mallocx.c (GC_bytes_found): Likewise.
+* mark_rts.c (GC_save_regs_ret_val, GC_world_stopped): Likewise.
+* misc.c (GC_unmap_threshold): Likewise.
+* os_dep.c (GC_unmap_threshold): Likewise.
+* pthread_support.c (GC_markers): Likewise.
+* thread_local_alloc.c (GC_gcjobjfreelist,
+GC_gcj_malloc_initialized, GC_gcj_kind): Likewise.
+* win32_threads.c (GC_fault_handler_lock, GC_write_cs,
+GC_dont_query_stack_min, GC_markers, GC_wnt): Likewise.
+* include/private/gc_priv.h (GC_EXTERN): New macro (used mostly as
+a tag for now); defined after "gcconfig.h" inclusion.
+* include/private/gc_priv.h: Use GC_EXTERN instead of "extern"
+keyword for most global variables.
+* alloc.c (GC_copyright): Add the comment about the symbol
+visibility.
+* finalize.c (GC_fo_entries): Likewise.
+* include/private/gc_priv.h (GC_print_stats): Likewise.
+* misc.c (GC_quiet): Likewise.
+* mallocx.c (GC_bytes_allocd_tmp): Make the volatile variable
+STATIC.
+* pthread_support.c (GC_threads): Add explicit zero initializer
+(to make the variable definition differ from the declaration).
+
+* backgraph.c (GC_quiet): Remove the declaration (not needed
+anymore since gc_priv.h is always included).
+* checksums.c (GC_quiet): Likewise.
+* gcj_mlc.c (GC_quiet): Likewise.
+* headers.c (GC_hdr_cache_hits, GC_hdr_cache_misses): Add the
+comment.
+* include/private/gc_hdrs.h (GC_hdr_cache_hits,
+GC_hdr_cache_misses): Likewise.
+* mark.c (GC_first_nonempty): Make the volatile variable STATIC.
+* pthread_stop_world.c (GC_stop_count, GC_world_is_stopped):
+Likewise.
+* win32_threads.c (GC_please_stop, GC_max_thread_index,
+GC_mark_mutex_waitcnt): Likewise.
+
+* pthread_support.c (GC_USE_LD_WRAP): Fix a typo (swapped 'L' and
+'D') in the name.
+
+* gc_dlopen.c (GC_MUST_RESTORE_REDEFINED_DLOPEN): Define if dlopen
+redirection is turned off; turn it on later when dlopen real
+symbol is no longer needed (according to the comment and the same
+as in dyn_load.c).
+* gc_dlopen.c (WRAP_FUNC, REAL_FUNC): Rename to WRAP_DLFUNC and
+REAL_DLFUNC, respectively (to have unique names since the
+definitions may differ from that of the similar ones in
+pthread_support.c).
+* mark.c (source): Undefine the macro when no longer needed.
+* os_dep.c (handler): Rename the type to GC_fault_handler_t (to
+have the unique name across the project).
+* os_dep.c (STAT_BUF_SIZE, STAT_READ); Guard with ifndef; add the
+comment.
+* pthread_support.c (STAT_BUF_SIZE, STAT_READ): Likewise.
+* os_dep.c (sbrk): Undo sbrk() redirection (for ECOS) when no
+longer needed.
+
+* pthread_stop_world.c (pthread_sigmask): Undefine before using
+in GC_print_sig_mask() (only if DEBUG_THREADS); add the comment.
+* win32_threads.c (dlopen, _beginthread): Don't undefine (since
+neither redirected nor used here).
+* win32_threads.c (GC_Thread_Rep): Rename "table_management" to
+"tm" for short; remove "tm_" prefix.
+* win32_threads.c (in_use, next): Don't define the macros; use
+tm.in_use and tm.next fields, respectively (to ease debugging).
+* win32_threads.c (HASH): Rename to PTHREAD_MAP_HASH (to have
+unique name across the project).
+
+* include/private/gc_priv.h (I_HIDE_POINTERS): Define before gc.h
+inclusion.
+* include/private/gc_pmark.h (I_HIDE_POINTERS): Define if gc.h is
+not included yet.
+* finalize.c (I_HIDE_POINTERS): Don't define.
+* include/private/dbg_mlc.h (I_HIDE_POINTERS): Likewise.
+* misc.c (I_HIDE_POINTERS): Likewise.
+* include/private/dbg_mlc.h (HIDE_POINTER, REVEAL_POINTER,
+GC_hidden_pointer): Don't define if HIDE_POINTER is undefined.
+* include/private/gc_pmark.h: Remove the comment about gc_priv.h
+inclusion order.
+
+* dyn_load.c: Include gc_priv.h before using configuration
+information (MACOS).
+* dyn_load.c (GC_must_restore_redefined_dlopen): Rename to
+GC_MUST_RESTORE_REDEFINED_DLOPEN.
+
+* backgraph.c (SET_OH_BG_PTR): Place outermost parenthesis
+properly.
+* darwin_stop_world.c: Replace "if DEBUG_THREADS" with
+"ifdef DEBUG_THREADS".
+* pthread_stop_world.c: Likewise.
+* pthread_support.c: Likewise.
+* include/gc_inline.h: Guard with GC_INLINE_H.
+
+* alloc.c (GC_copyright): Define as const.
+* alloc.c (GC_collect_at_heapsize): Replace "static" with "STATIC"
+(since the name starts with "GC_" prefix).
+* dbg_mlc.c (GC_describe_type_fns): Likewise.
+* dyn_load.c (GC_FirstDLOpenedLinkMap,
+GC_register_dynlib_callback, GC_dyld_sections,
+GC_dyld_name_for_hdr, GC_dyld_image_add, GC_dyld_image_remove):
+Likewise.
+* malloc.c (GC_libpthread_start, GC_libpthread_end,
+GC_libld_start, GC_libld_end): Likewise.
+* mark_rts.c (GC_remove_root_at_pos, GC_rebuild_root_index):
+Likewise.
+* os_dep.c (GC_gww_read_dirty, GC_gww_page_was_dirty,
+GC_gww_page_was_ever_dirty, GC_mprotect_thread_notify,
+GC_mprotect_thread_reply, GC_mprotect_thread, GC_darwin_sigbus,
+GC_forward_exception): Likewise.
+* pthread_support.c (GC_syms_initialized): Likewise.
+* typd_mlc.c (GC_push_typed_structures_proc): Likewise.
+* win32_threads.c (GC_win32_dll_threads,
+GC_register_my_thread_inner, GC_lookup_pthread, GC_get_stack_min,
+GC_waitForSingleObjectInfinite): Likewise.
+* darwin_stop_world.c (GC_use_mach_handler_thread,
+GC_use_mach_handler_thread, GC_mach_threads_count): Replace
+"static" with "STATIC" and add zero initializer.
+* os_dep.c (GC_task_self, GC_ports, GC_mprotect_state,
+GC_sigbus_count): Likewise.
+* headers.c (free_hdr): Replace "static" with GC_INLINE.
+* misc.c (GC_tmp): Rename static variable to fwrite_gc_res.
+* os_dep.c (memory): Rename static variable to ecos_gc_memory.
+* os_dep.c (async_set_pht_entry_from_index): Make static (for
+MPROTECT_VDB case).
+* pthread_support.c (GC_real_pthread_create,
+GC_real_pthread_sigmask, GC_real_pthread_join,
+GC_real_pthread_detach, GC_init_real_syms): Use REAL_FUNC() macro
+for static GC_real_XXX symbols.
+* win32_threads.c (GC_may_be_in_stack): Remove "GC_" prefix.
+
+* alloc.c (GC_finish_collection): Replace getenv() with GETENV().
+* dyn_load.c (GC_init_dyld): Likewise.
+* os_dep.c (GC_print_callers): Likewise.
+* dyn_load.c (GC_dyld_name_for_hdr): Cast _dyld_get_image_name()
+result (since it's always of "struct mach_header" type).
+* dyn_load.c (GC_init_dyld): Cast GC_dyld_image_add and
+GC_dyld_image_remove (to always have the first argument of
+"struct mach_header" pointer type).
+
+* configure.ac: Add threads support for OpenBSD case (threads may
+not work correctly for it).
+
+* acinclude.m4: Rename to m4/gc_set_version.m4.
+* m4/libtool.m4: Delete the file.
+* m4/lt~obsolete.m4: Likewise.
+* m4/ltoptions.m4: Likewise.
+* m4/ltsugar.m4: Likewise.
+* m4/ltversion.m4: Likewise.
+
+* include/private/gcconfig.h: Define DebugBreak() as _exit(-1) for
+x86mingw32ce toolchain to workaround the incorrect DebugBreak()
+declaration in winbase.h (the workaround would turn into a no-op
+when DebugBreak() will be defined as a macro in the toolchain).
+
+* include/private/gcconfig.h: Recognize __i386__ if WinCE (for
+x86mingw32ce toolchain).
+* include/private/gcconfig.h (NO_GETENV): Don't define for CeGCC
+toolchain (or if already defined).
+* include/private/gcconfig.h (NO_GETENV_WIN32): New macro (always
+defined for WinCE or if NO_GETENV is defined).
+* misc.c (GC_CreateLogFile): Use NO_GETENV_WIN32 macro instead of
+NO_GETENV one.
+
+* configure.ac: Add AC_CONFIG_MACRO_DIR([m4]).
+* Makefile.am: Add "ACLOCAL_AMFLAGS = -I m4".
+* libtool.m4: Remove.
+* m4/libtool.m4: New file (generated).
+* m4/lt~obsolete.m4: Likewise.
+* m4/ltoptions.m4: Likewise.
+* m4/ltsugar.m4: Likewise.
+* m4/ltversion.m4: Likewise.
+
+* include/gc.h (GC_UNDERSCORE_STDCALL): Recognize new macro;
+prefix GC_CreateThread and GC_ExitThread with '_' if defined.
+* doc/README.macros (GC_UNDERSCORE_STDCALL): Document.
+
+* alloc.c (GC_collect_or_expand): Add "retry" argument; add the
+comments; don't use "default" stop_func on a retry if
+GC_dont_expand.
+* alloc.c (GC_allocobj): Pass "retry" argument to
+GC_collect_or_expand().
+* malloc.c (GC_alloc_large): Likewise.
+* include/private/gc_priv.h (GC_collect_or_expand): Move the
+declaration to malloc.c; add "retry" argument.
+
+* alloc.c (GC_start_call_back): Move the variable definition from
+misc.c.
+* include/private/gc_priv.h (GC_start_call_back): Remove the
+declaration.
+* alloc.c (GC_notify_full_gc): Remove unnecessary cast of 0.
+* alloc.c (GC_try_to_collect_inner): Also call stop_func at the
+beginning of the function.
+* include/gc.h (GC_try_to_collect): Refine the comment about
+stop_func.
+
+* alloc.c (GC_default_stop_func, GC_try_to_collect_general,
+GC_gcollect): Add the comment.
+* alloc.c (GC_try_to_collect_general): Move the assertion on
+stop_func != 0 to GC_try_to_collect().
+* alloc.c (GC_try_to_collect_general): If stop_func == 0 then use
+GC_default_stop_func instead (holding the lock).
+* alloc.c (GC_gcollect): Pass 0 as stop_func instead of
+GC_default_stop_func (to prevent data races).
+
+* Makefile.direct: Move "define arguments" documentation to
+doc/README.macros; add reference to doc/README.macros.
+* Makefile.dj: Change the documentation reference to
+doc/README.macros.
+* README.QUICK: Likewise.
+* configure.ac: Likewise.
+* allchblk.c: Remove unnecessary "-D" from the comment.
+* doc/README.macros: Likewise.
+* README.environment: Likewise.
+* include/gc.h: Likewise.
+* include/gc_inline.h: Likewise.
+* include/private/gcconfig.h: Likewise.
+* README.QUICK: Fix a typo.
+
+* misc.c (GC_CreateLogFile): Use FILE_ATTRIBUTE_NORMAL for
+CreateFile(); don't immediately flush every write if very verbose.
+
+* doc/README.win32: Replace ".exe.log" to ".gc.log".
+* doc/README.win64: Likewise.
+* doc/README.win64: Fix a typo.
+* misc.c (GC_CreateLogFile): Strip executable file extension for
+the log file; use ".gc.log" extension (instead of ".log").
+
+* include/gc_config_macros.h: Avoid the redefinition of
+GC_xxx_THREADS macros.
+
+* alloc.c (GC_try_to_collect_general): Change the type of "result"
+local variable to GC_bool.
+
+* include/gc_config_macros.h: Use old behavior for FreeBSD and
+NetBSD platform detection code (check that other GC_xxx_THREADS
+are undefined); add FIXME.
+
+* include/gc_config_macros.h: Rearrange the platform detection
+code (GC_WIN32_PTHREADS implies GC_WIN32_THREADS; define
+GC_THREADS first if GC_XXX_THREADS already set; define proper
+GC_XXX_THREADS if GC_THREADS; define GC_PTHREADS in a single
+place; define _REENTRANT if posix threads except for Win32).
+
+* alloc.c (GC_try_to_collect_general): New function (move the code
+from GC_try_to_collect, pass force_unmap argument).
+* alloc.c (GC_try_to_collect, GC_gcollect): Call
+GC_try_to_collect_general().
+* alloc.c (GC_gcollect_and_unmap): New public function.
+* include/gc.h (GC_gcollect_and_unmap): New function declaration.
+* tests/test.c (window_proc): Call GC_gcollect_and_unmap() on
+WM_HIBERNATE event (instead of GC_set_force_unmap_on_gcollect()
+and GC_gcollect()).
+
+* include/gc.h (GC_allow_register_threads, GC_register_my_thread,
+GC_unregister_my_thread, GC_malloc_many): Refine the comment.
+* include/gc.h (GC_malloc_many, GC_NEXT): Declare unconditionally
+(that is, don't depend on GC_THREADS macro).
+* include/gc.h: Don't check for __CYGWIN32__ and __CYGWIN__ along
+with a check for GC_PTHREADS (since the former implies the
+latter).
+
+* include/gc.h (GC_SOLARIS_THREADS): Don't check for.
+* include/gc.h (GC_MIN, GC_MAX): Don't define.
+* mallocx.c (GC_malloc_many): Add comment to #endif.
+
+* configure.ac: Drop the subdir-objects Automake option, since
+it's incompatible with picking source files from libatomic_ops.
+
+* allchblk.c (GC_fail_count, GC_large_alloc_warn_interval): Add
+"extern" keyword to a global variable declaration (some compilers
+require it).
+* alloc.c (GC_bytes_found, GC_unmap_threshold,
+GC_force_unmap_on_gcollect): Likewise.
+* dyn_load.c (GC_no_win32_dlls, GC_wnt): Likewise.
+* finalize.c (GC_fail_count): Likewise.
+* include/private/gc_hdrs.h (GC_hdr_cache_hits,
+GC_hdr_cache_misses): Likewise.
+* mallocx.c (GC_bytes_found): Likewise.
+* mark_rts.c (GC_save_regs_ret_val, GC_world_stopped): Likewise.
+* misc.c (GC_unmap_threshold): Likewise.
+* os_dep.c (GC_unmap_threshold, GC_old_allocator): Likewise.
+* pthread_support.c (GC_markers): Likewise.
+* thread_local_alloc.c (GC_gcjobjfreelist,
+GC_gcj_malloc_initialized, GC_gcj_kind): Likewise.
+* win32_threads.c (GC_fault_handler_lock, GC_write_cs,
+GC_dont_query_stack_min, GC_markers, GC_wnt): Likewise.
+
+* tests/huge_test.c: Define GC_IGNORE_WARN (if not defined) to
+suppress misleading GC "Out of Memory!" warning printed on every
+GC_MALLOC(LONG_MAX) call.
+* tests/huge_test.c: Include "gc.h" instead of <gc.h>.
+* tests/huge_test.c (main): Replace K&R-style function definition
+with the ANSI C one.
+
+* dyn_load.c (GC_register_dynamic_libraries): Always use
+lpMaximumApplicationAddress value for WinCE (even for old
+versions).
+* os_dep.c (VER_PLATFORM_WIN32_CE): Define if not in winbase.h.
+* os_dep.c (GC_dont_query_stack_min): New global variable (only if
+WinCE and THREADS).
+* os_dep.c (GC_setpagesize): Adjust lpMaximumApplicationAddress
+for WinCE (prior to version 6) if not _WIN32_WCE_EMULATION; set
+GC_dont_query_stack_min for older WinCE (prior to version 5).
+* win32_threads.c (GC_dont_query_stack_min): Declare.
+* win32_threads.c (GC_get_stack_min): Rename the macro to
+GC_wince_evaluate_stack_min for WinCE; update the comment.
+* win32_threads.c (GC_push_stack_for, GC_get_next_stack): Use
+GC_wince_evaluate_stack_min() instead of GC_get_stack_min() for
+WinCE and don't update thread's last_stack_min value (only if
+GC_dont_query_stack_min).
+* win32_threads.c (GC_push_stack_for): Skip assertion for WinCE if
+GC_dont_query_stack_min (since the evaluated stack_min value may
+be incorrect if the stack is bigger than 64 KiB).
+
+* gc_dlopen.c (GC_dlopen): Add function redirector (only if
+GC_USE_LD_WRAP).
+* include/gc.h: Include "gc_pthread_redirects.h" even if
+GC_USE_LD_WRAP or GC_NO_THREAD_REDIRECTS.
+* include/gc_pthread_redirects.h (GC_PTHREAD_REDIRECTS_H): Don't
+define and check for (since included only from gc.h).
+* include/gc_pthread_redirects.h: Declare "GC_" symbols even if
+GC_USE_LD_WRAP or GC_NO_THREAD_REDIRECTS.
+* include/gc_pthread_redirects.h: Include signal.h only to get
+sigset_t definition.
+
+* Makefile.direct: Document GC_REGISTER_MEM_PRIVATE.
+* mark_rts.c (GC_is_tmp_root): Define also for WinCE unless
+NO_DEBUGGING (that is, replace _WIN32_WCE_EMULATION with MSWINCE).
+* os_dep.c (GC_sysinfo): Remove explicit global variable
+initialization to "{0}" (revert back the previous change) since it
+might produce a warning.
+
+* allchblk.c (GC_large_alloc_warn_interval): Move declaration from
+gc_priv.h.
+* allchblk.c (GC_large_alloc_warn_suppressed): Move definition
+from misc.c; define as STATIC.
+* include/private/gc_priv.h (GC_large_alloc_warn_interval,
+GC_large_alloc_warn_suppressed): Remove declaration.
+* alloc.c (GC_bytes_found): Add "defined in" comment.
+* mallocx.c (GC_bytes_found): Likewise.
+* misc.c (GC_unmap_threshold): Likewise.
+* os_dep.c (GC_old_allocator): Likewise.
+* pthread_support.c (GC_markers): Likewise.
+* thread_local_alloc.c (GC_gcjobjfreelist,
+GC_gcj_malloc_initialized, GC_gcj_kind): Likewise.
+* win32_threads.c (GC_markers): Likewise.
+* alloc.c (GC_start_time): Explicitly initialize to 0 or NULL (to
+be distinctive from a variable declaration).
+* backgraph.c (GC_max_height, GC_deepest_obj): Likewise.
+* blacklst.c (GC_old_normal_bl, GC_incomplete_normal_bl,
+GC_old_stack_bl, GC_incomplete_stack_bl): Likewise.
+* checksums.c (GC_faulted, GC_n_dirty_errors,
+GC_n_faulted_dirty_errors, GC_n_changed_errors, GC_n_clean,
+GC_n_dirty, GC_bytes_in_used_blocks): Likewise.
+* dbg_mlc.c (GC_smashed): Likewise.
+* finalize.c (GC_old_dl_entries): Likewise.
+* gcj_mlc.c (GC_gcj_kind, GC_gcj_debug_kind, GC_gcjobjfreelist,
+GC_gcjdebugobjfreelist): Likewise.
+* mach_dep.c (GC_save_regs_ret_val): Likewise.
+* mark.c (GC_n_rescuing_pages, GC_mark_stack, GC_mark_stack_limit,
+GC_mark_stack_top): Likewise.
+* misc.c (GC_min_sp, GC_high_water, GC_bytes_allocd_at_reset):
+Likewise.
+* os_dep.c (GC_data_start, GC_page_size, GC_sysinfo,
+GC_old_segv_handler, GC_old_bus_handler,
+GC_old_bus_handler_used_si, GC_old_segv_handler_used_si,
+GC_proc_buf, GC_proc_fd, GC_vd_base): Likewise.
+* pthread_stop_world.c (GC_stop_count, GC_stopping_pid): Likewise.
+* reclaim.c (GC_leaked): Likewise.
+* typd_mlc.c (GC_explicit_kind, GC_array_kind, GC_ext_descriptors,
+GC_typed_mark_proc_index, GC_array_mark_proc_index,
+GC_eobjfreelist, GC_arobjfreelist): Likewise.
+* win32_threads.c (GC_pthread_map_cache, GC_marker_cv,
+GC_marker_Id): Likewise.
+* dbg_mlc.c (GC_smashed, GC_n_smashed): Define as STATIC.
+* gcj_mlc.c (GC_gcjdebugobjfreelist): Likewise.
+* os_dep.c (GC_vd_base): Likewise.
+* pthread_support.c (GC_mark_threads): Likewise.
+* reclaim.c (GC_leaked): Likewise.
+* typd_mlc.c (GC_bm_table): Likewise.
+* mark_rts.c (GC_save_regs_ret_val): Change declaration type to
+that of definition; add "defined in" comment.
+* mark_rts.c (GC_push_current_stack): Remove unnecessary cast for
+GC_save_regs_ret_val.
+* misc.c (GC_check_heap, GC_print_all_smashed,
+GC_start_call_back): Remove unnecessary cast (of 0).
+* misc.c (GC_LARGE_ALLOC_WARN_INTERVAL): New tuning macro.
+* misc.c (GC_large_alloc_warn_interval): Initialize to
+GC_LARGE_ALLOC_WARN_INTERVAL value.
+* misc.c (GC_tmp): Change to "static".
+* os_dep.c (GC_mprotect_state): Define as static.
+* pthread_support.c (dummy_thread_local): Prefix with "GC_".
+* win32_threads.c (WinMain): Remove FIXME for WinCE.
+
+* os_dep.c (PROTECT, UNPROTECT): Use distinct ABORT messages.
+
+* configure.ac: Rewrite the tests for external or internal
+libatomic_ops.
+* configure.ac: In particular, drop the symbolic links. Add option
+--with-libatomic-ops for forced selection.
+* Makefile.am: Adjust the path of source files from libatomic_ops
+to not use the links.
+* Makefile.am (libgc_la_LIBADD): Add $(ATOMIC_OPS_LIBS). This will
+be empty if we use the bundled AO sources.
+
+* Makefile.am: Strip version suffix for libatomic_ops directory.
+* build_atomic_ops.sh: Likewise.
+* build_atomic_ops.sh.cygwin: Likewise.
+* configure_atomic_ops.sh: Likewise.
+* Makefile.direct: Remove AO_VERSION definition; strip version
+suffix for libatomic_ops directory.
+* NT_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_THREADS_MAKEFILE: Likewise.
+* gc.mak: Likewise.
+
+* libatomic_ops: Rename from "libatomic_ops-1.2".
+
+* alloc.c (GC_version): Add "const" keyword.
+* alloc.c (GC_get_version): New public function.
+* include/gc.h (GC_get_version): New function declaration; update
+the comment for the GC version.
+
+* include/private/gc_locks.h (GC_allocate_ml, GC_lock_holder,
+GC_collecting, GC_mark_lock_holder, GC_need_to_lock): Use "extern"
+(for the global variable declaration) again.
+* include/private/gc_pmark.h (GC_n_mark_procs, GC_mark_stack_size,
+GC_mark_stack_limit, GC_mark_stack_top, GC_mark_stack,
+GC_mark_stack_too_small, GC_mark_state): Likewise.
+* include/private/gcconfig.h (GC_register_stackbottom): Likewise.
+* include/private/pthread_support.h (GC_threads,
+GC_thr_initialized, GC_in_thread_creation): Likewise.
+* include/private/gc_priv.h: Likewise.
+
+* real_malloc.c: Include private/config.h if HAVE_CONFIG_H.
+
+* allchblk.c (GC_hblkfreelist): Define as STATIC.
+* blacklst.c (GC_total_stack_black_listed): Likewise.
+* include/private/gc_priv.h (GC_hblkfreelist, GC_stopped_mark,
+GC_total_stack_black_listed, GC_push_stubborn_structures): Remove
+declaration.
+* mark_rts.c (GC_stopped_mark): Add declaration (only if
+THREAD_LOCAL_ALLOC).
+* allchblk.c (GC_fail_count): Move the declaration out of
+GC_allochblk_nth(); remove "extern".
+* alloc.c (IF_THREADS): Remove unused macro.
+* alloc.c (GC_world_stopped): Define only if THREAD_LOCAL_ALLOC.
+* alloc.c (GC_stopped_mark): Set GC_world_stopped value only if
+THREAD_LOCAL_ALLOC.
+* alloc.c (GC_bytes_found, GC_collection_in_progress,
+GC_check_tls, GC_unmap_threshold, GC_force_unmap_on_gcollect):
+Remove K&R-style "extern" for the declaration.
+* dbg_mlc.c (GC_free_inner): Likewise.
+* dyn_load.c (GC_repeat_read, GC_roots_present, GC_is_heap_base,
+GC_get_next_stack, GC_no_win32_dlls, GC_wnt): Likewise.
+* finalize.c (GC_fail_count): Likewise.
+* include/private/gc_hdrs.h (GC_hdr_cache_hits,
+GC_hdr_cache_misses): Likewise.
+* include/private/gc_locks.h (GC_allocate_ml, GC_lock_holder,
+GC_lock, GC_collecting, GC_mark_lock_holder, GC_need_to_lock):
+Likewise.
+* include/private/gc_pmark.h (GC_mark_procs, GC_n_mark_procs,
+GC_mark_stack_size, GC_mark_stack_limit, GC_mark_stack_top,
+GC_mark_stack, GC_mark_stack_too_small, GC_mark_state): Likewise.
+* include/private/gc_priv.h (GC_current_warn_proc, GC_obj_kinds,
+GC_n_kinds, GC_fo_entries, GC_n_heap_sects, GC_n_memory,
+GC_page_size, GC_sysinfo, GC_black_list_spacing,
+GC_objects_are_marked, GC_incremental, GC_dirty_maintained,
+GC_root_size, GC_debugging_started, GC_large_alloc_warn_interval,
+GC_large_alloc_warn_suppressed, GC_blocked_sp,
+GC_activation_frame, GC_push_other_roots,
+GC_push_finalizer_structures, GC_push_thread_structures,
+GC_push_typed_structures, GC_start_call_back, GC_is_initialized,
+GC_check_heap, GC_print_all_smashed, GC_print_all_errors,
+GC_print_heap_obj, GC_have_errors, GC_print_stats,
+GC_dump_regularly, GC_backtraces, GC_print_back_height,
+GC_debug_generic_malloc_inner,
+GC_debug_generic_malloc_inner_ignore_off_page,
+GC_fl_builder_count, GC_mark_no, GC_help_marker,
+GC_setup_temporary_fault_handler, GC_reset_fault_handler): Likewise.
+* include/private/gcconfig.h (GC_SysVGetDataStart,
+GC_FreeBSDGetDataStart, GC_register_stackbottom,
+GC_MacTemporaryNewPtr, GC_amiga_get_mem): Likewise.
+* include/private/pthread_support.h (GC_threads,
+GC_thr_initialized, GC_in_thread_creation): Likewise.
+* malloc.c (GC_text_mapping): Likewise.
+* mallocx.c (GC_bytes_found): Likewise.
+* mark.c (GC_check_dirty, GC_started_thread_while_stopped): Likewise.
+* mark_rts.c (GC_save_regs_ret_val): Likewise.
+* misc.c (GC_clear_stack_inner, GC_init_parallel, GC_init_win32,
+GC_setpagesize, GC_init_linux_data_start,
+GC_set_and_save_fault_handler, GC_unmap_threshold): Likewise.
+* os_dep.c (GC_unmap_threshold, GC_push_all_stacks,
+GC_darwin_register_mach_handler_thread): Likewise.
+* pthread_support.c (GC_markers, GC_collection_in_progress):
+Likewise.
+* tests/test.c (GC_amiga_free_all_mem): Likewise.
+* thread_local_alloc.c (GC_gcjobjfreelist,
+GC_gcj_malloc_initialized, GC_gcj_kind): Likewise.
+* win32_threads.c (GC_write_fault_handler, GC_gww_dirty_init,
+GC_fault_handler_lock, GC_write_cs, GC_markers): Likewise.
+* misc.c (GC_read, GC_register_finalizer_no_order, GC_init_dyld):
+Move the declaration out of GC_init(); remove "extern".
+* os_dep.c (GC_abort): Add the comment; add workaround to suppress
+compiler "unreachable code" warnings for ABORT callers (where
+ABORT is followed by a dummy return statement).
+* os_dep.c (GC_old_allocator): Move the declaration out of
+GC_default_push_other_roots(); remove "extern".
+* darwin_stop_world.c (GC_mprotect_stop, GC_mprotect_resume):
+Move the declaration out of GC_stop_world() and GC_start_world()
+(only if MPROTECT_VDB); remove "extern".
+
+* win32_threads.c (GC_get_stack_min, GC_push_stack_for,
+GC_get_next_stack): Recognize _WIN32_WCE_EMULATION macro (used for
+WinCE emulation and for custom WinCE 6 devices); add the comment.
+* win32_threads.c (GC_get_stack_min): Cast pointer to word instead
+of DWORD.
+* win32_threads.c (GC_get_next_stack): Don't use and maintain the
+latest known stack_min value for WinCE (if GC_get_stack_min is
+defined as a macro); update the comments.
+* win32_threads.c (GC_wnt): Don't declare for WinCE.
+
+* Makefile.direct: Document EMPTY_GETENV_RESULTS.
+* gcj_mlc.c (GC_clear_stack): Remove declaration.
+* malloc.c (GC_clear_stack): Likewise.
+* mallocx.c (GC_clear_stack): Likewise.
+* typd_mlc.c (GC_clear_stack): Likewise.
+* gcj_mlc.c (GENERAL_MALLOC, GENERAL_MALLOC_IOP): Rename to
+GENERAL_MALLOC_INNER and GENERAL_MALLOC_INNER_IOP, respectively;
+remove "lb" unnecessary cast to word.
+* include/private/gc_priv.h (GC_clear_stack): Add declaration.
+* include/private/gc_priv.h (GENERAL_MALLOC, GENERAL_MALLOC_IOP):
+Move common declaration from typd_mlc.c and malloc.c; remove
+unnecessary result and "lb" parameter casts.
+* include/private/thread_local_alloc.h: Guard against duplicate
+header file inclusion.
+* os_dep.c (USE_MUNMAP): Replace "-->" with an error directive for
+the case when USE_MMAP is not defined.
+* pthread_support.c (GC_is_thread_tsd_valid): New internal
+function (only if GC_ASSERTIONS and THREAD_LOCAL_ALLOC); move the
+code from thread-local GC_malloc(); add FIXME for the condition.
+* win32_threads.c (GC_is_thread_tsd_valid): Likewise.
+* thread_local_alloc.c (GC_gcjobjfreelist): Change the type (to
+match that of its definition).
+* thread_local_alloc.c (GC_destroy_thread_local): Add a cast for
+GC_gcjobjfreelist.
+* thread_local_alloc.c (GC_lookup_thread, GC_lookup_thread_inner):
+Remove unused declaration; don't include pthread.h.
+* thread_local_alloc.c (GC_is_thread_tsd_valid): New declaration
+(only if GC_ASSERTIONS).
+* thread_local_alloc.c (GC_malloc): Use GC_is_thread_tsd_valid()
+instead of GC_lookup_thread().
+* win32_threads.c (GC_lookup_thread_inner): Define as STATIC.
+* win32_threads.c (UNPROTECT): Rename to UNPROTECT_THREAD (to have
+id different from that in os_dep.c).
+
+* allchblk.c (GC_enough_large_bytes_left): Replace "inline static"
+with GC_INLINE.
+* include/private/gc_priv.h (fixed_getenv): Likewise.
+* alloc.c (GC_max, GC_min): Replace "static INLINE" with
+GC_INLINE.
+* mark_rts.c (rt_hash): Likewise.
+* win32_threads.c (GC_get_max_thread_index): Likewise.
+* include/private/gc_priv.h (INLINE): Prefix with "GC_"; include
+"static"; define for Sun CC; define for VC++ (and other
+compilers).
+* pthread_support.c: Don't define __inline__ for non-GNU compilers
+(not needed anymore).
+
+* NT_THREADS_MAKEFILE: Remove file (since it duplicates gc.mak).
+* Makefile.in: Remove reference to NT_THREADS_MAKEFILE.
+* Makefile.am: Likewise.
+* Makefile.dj: Likewise.
+* Makefile.direct: Likewise.
+* doc/README.win32: Add reference to gc.mak.
+* NT_X64_THREADS_MAKEFILE: Likewise.
+
+* Makefile.direct: Remove references to acinclude.m4, libtool.m4.
+
+* autogen.sh: Update.
+
+* Makefile.am: Don't add libtool.m4 to EXTRA_DIST.
+* acinclude.m4: Fix underquoting of GC_SET_VERSION.
+* README.QUICK: Update information for Makefile.
+* Makefile.am: Do not distribute the substituted bdw-gc.pc.
+* configure.ac: Add AM conditional analog to KEEP_BACK_PTRS.
+* tests/tests.am: Use it here to conditionally enable tracetest
+when possible.
+
+* dyn_load.c (GC_wnt): Update the comment.
+* dyn_load.c (GC_register_dynamic_libraries): Add the comment for
+_WIN32_WCE_EMULATION; recognize GC_REGISTER_MEM_PRIVATE (new
+macro); call GC_is_heap_base() only if check for Type succeeded.
+
+* mark_rts.c (GC_is_tmp_root): Don't define unless NO_DEBUGGING;
+update the comment.
+* include/private/gc_priv.h (GC_is_tmp_root): Remove declaration.
+
+* include/private/gcconfig.h (CANCEL_SAFE, IF_CANCEL): new macros.
+* include/private/gc_priv.h (DISABLE_CANCEL, RESTORE_CANCEL,
+ASSERT_CANCEL_DISABLED): New macros.
+* alloc.c (GC_maybe_gc): Assert cancellation disabled.
+(GC_collect_a_little_inner,GC_try_to_collect, GC_collect_or_expand):
+Disable cancellation.
+(GC_add_to_our_memory): Check for overflow.
+* misc.c (GC_cancel_disable_count): declare.
+(GC_init, GC_write): Disable cancellation.
+(GC_init): Remove redundant GC_is_initialized test.
+* os_dep.c (GC_repeat_read): Assert cancellation disabled.
+(GC_get_stack_base): Disable cancellation.
+* pthread_stop_world.c (GC_suspend_handler_inner): Disable
+cancellation.
+* pthread_support.c (GC_mark_thread): Permanently disable
+cancellation.
+(GC_wait_for_gc_completion, GC_wait_builder, GC_wait_marker):
+Assert cancellation disabled.
+(fork handling): Disable cancellation, fix comment.
+(GC_pthread_create): Disable cancellation.
+(GC_unregister_my_thread): Disable cancellation.
+* Makefile.direct: Document NO_CANCEL_SAFE.
+
+* Makefile: Remove outdated file (Makefile.direct should be used
+instead).
+
+* include/gc.h (GC_use_DllMain): Refine the comment.
+
+* configure.ac: Add documentation to AC_DEFINE for GC_THREADS and
+EMPTY_GETENV_RESULTS.
+* configure.ac: Fix a typo.
+* Makefile.am: Likewise.
+
+* checksums.c (GC_checksum, GC_update_check_page): Remove
+"register" keyword in local variable declarations (for the code
+used only for debugging or which is not time-critical).
+* dbg_mlc.c (GC_has_other_debug_info, GC_store_debug_info,
+GC_store_debug_info_inner, GC_check_annotated_obj, GC_print_obj,
+GC_print_smashed_obj, GC_debug_end_stubborn_change,
+GC_debug_invoke_finalizer): Likewise.
+* dyn_load.c (GC_register_dynamic_libraries): Likewise.
+* mallocx.c (GC_realloc): Likewise.
+* mark_rts.c (GC_print_static_roots, GC_is_static_root,
+GC_clear_roots): Likewise.
+* misc.c (GC_write): Likewise.
+* os_dep.c (GC_print_callers): Likewise.
+* dyn_load.c (GC_register_dynamic_libraries): Rename "i" local
+variable to "j" for the nested loop (just not to hide the similar
+variable in the outer one).
+* mark_rts.c (GC_print_static_roots): Output an error message
+using GC_err_printf() (instead of GC_printf()).
+
+* configure.ac: Move include flag from ${INCLUDE} ...
+* Makefile.am: ... to AM_CPPFLAGS and also add the build directory.
+* configure.ac: Call AM_CONFIG_HEADER([include/private/config.h]).
+* configure.ac: Add documentation to all AC_DEFINE either directly
+or using AH_TEMPLATE.
+
+* win32_threads.c (GC_waitForSingleObjectInfinite): New static
+function (only if GC_WINMAIN_REDIRECT).
+* win32_threads.c (WinMain): Call GC_waitForSingleObjectInfinite()
+thru GC_do_blocking() instead of calling WaitForSingleObject()
+directly.
+
+* pthread_support.c (start_mark_threads): Refine printed message.
+* win32_threads.c (GC_thr_init): Likewise.
+
+* Makefile.direct (GC_WINMAIN_REDIRECT): Add the comment for.
+* Makefile.direct (NO_GETENV): Update the comment.
+* include/gc.h (GC_WINMAIN_WINCE_LPTSTR): Remove macro.
+* include/gc.h (GC_WinMain): Remove declaration.
+* include/gc.h (WinMain): Define (as GC_WinMain) if and only if
+GC_WINMAIN_REDIRECT.
+* tests/test.c (GC_COND_INIT): Define as GC_INIT() also in case of
+WinCE target unless GC_WINMAIN_REDIRECT is defined.
+* tests/test.c (WINMAIN_LPTSTR): New macro.
+* tests/test.c (WinMain): Use WINMAIN_LPTSTR instead of LP[W]STR
+and GC_WINMAIN_WINCE_LPTSTR.
+* win32_threads.c (start_mark_threads): Add the comment for
+MARK_THREAD_STACK_SIZE.
+* win32_threads.c: Recognize new GC_WINMAIN_REDIRECT macro.
+* win32_threads.c (WINMAIN_LPTSTR, WINMAIN_THREAD_STACK_SIZE): New
+macro (only if GC_WINMAIN_REDIRECT).
+* win32_threads.c: Undefine WinMain macro if GC_WINMAIN_REDIRECT.
+* win32_threads.c (GC_WinMain): Add prototype (only if
+GC_WINMAIN_REDIRECT).
+* win32_threads.c (main_thread_args, WinMain): Rename
+GC_WINMAIN_WINCE_LPTSTR to WINMAIN_LPTSTR.
+* win32_threads.c (WinMain): Call GC_INIT() instead of GC_init();
+use WINMAIN_THREAD_STACK_SIZE.
+* win32_threads.c (WinMain): Call GC_deinit() and
+DeleteCriticalSection() only if WinCE; add FIXME.
+
+* os_dep.c (GC_get_main_stack_base): add assertion for mem_base
+value returned by GC_get_stack_base().
+
+* Makefile.direct (MUNMAP_THRESHOLD, GC_FORCE_UNMAP_ON_GCOLLECT):
+Add the comment for.
+* alloc.c (GC_unmap_threshold, GC_force_unmap_on_gcollect):
+Declare external variable (only if USE_MUNMAP).
+* alloc.c (GC_try_to_collect): Temporarily set GC_unmap_threshold
+value to 1 if GC_force_unmap_on_gcollect and restore it before
+unlocking (only if USE_MUNMAP).
+* doc/README.environment (GC_FORCE_UNMAP_ON_GCOLLECT): Add
+information for.
+* include/gc.h (GC_set_force_unmap_on_gcollect,
+GC_get_force_unmap_on_gcollect): New public function prototype.
+* include/gc.h (GC_FORCE_UNMAP_ON_GCOLLECT): New macro is
+recognized.
+* misc.c (GC_FORCE_UNMAP_ON_GCOLLECT): Likewise.
+* include/gc.h (GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT): New
+internal macro (used by GC_INIT only).
+* misc.c (GC_force_unmap_on_gcollect): New global variable.
+* misc.c (GC_init): Recognize new "GC_FORCE_UNMAP_ON_GCOLLECT"
+environment variable (and set GC_force_unmap_on_gcollect).
+* misc.c (GC_set_force_unmap_on_gcollect,
+GC_get_force_unmap_on_gcollect): New public function.
+* tests/test.c (window_proc): Call GC_set_force_unmap_on_gcollect
+to force the mode on if WM_HIBERNATE; restore the mode after
+GC_gcollect().
+
+* Makefile.direct (LARGE_CONFIG): Update information.
+* include/gc.h (GC_stop_func): Refine the comment.
+
+* configure.ac: Use EMPTY_GETENV_RESULTS instead of NO_GETENV for
+Win32 (workaround for Wine bug).
+
+* allchblk.c (GC_freehblk): Adjust local variables indentation.
+* mallocx.c (GC_generic_malloc_many): Likewise.
+* typd_mlc.c (GC_malloc_explicitly_typed_ignore_off_page,
+GC_calloc_explicitly_typed): Likewise.
+* typd_mlc.c (GC_make_array_descriptor): Remove unnecessary
+brackets.
+
+* configure.ac: Replace GC_WIN32_THREADS with GC_THREADS.
+* configure.ac: Process enable_parallel_mark option for Cygwin and
+Win32; define THREAD_LOCAL_ALLOC for Win32.
+
+* include/private/gc_priv.h: Define AO_ASSUME_WINDOWS98 if
+PARALLEL_MARK (required for VC++ x86).
+
+* dbg_mlc.c (GC_generate_random_backtrace): Call
+GC_try_to_collect(GC_never_stop_func) instead of GC_gcollect();
+if GC is disabled then print error message and return.
+* include/gc.h (GC_try_to_collect): Refine the comment.
+* include/private/gc_priv.h (GC_never_stop_func): Fix return type;
+refine the comment.
+
+* add_gc_prefix.c: Move the file to the new "extra" directory.
+* AmigaOS.c: Likewise.
+* gcname.c: Likewise.
+* if_mach.c: Likewise.
+* if_not_there.c: Likewise.
+* MacOS.c: Likewise.
+* msvc_dbg.c: Likewise.
+* setjmp_t.c: Likewise.
+* threadlibs.c: Likewise.
+* EMX_MAKEFILE: Prepend setjmp_t.c with "extra" directory.
+* Makefile: Prepend AmigaOS.c, MacOS.c, add_gc_prefix.c, gcname.c,
+if_mach.c, if_not_there.c, msvc_dbg.c, setjmp_t.c, threadlibs.c
+with "extra" directory.
+* Makefile.am: Likewise.
+* Makefile.direct: Likewise.
+* Makefile.dj: Likewise.
+* Makefile.in: Likewise.
+* NT_MAKEFILE: Prepend msvc_dbg.obj with "extra" directory.
+* NT_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_THREADS_MAKEFILE: Likewise.
+* NT_THREADS_MAKEFILE: Prepend msvc_dbg.c with "extra" directory.
+* gc.mak: Likewise.
+* PCR-Makefile: Prepend if_mach.c, if_not_there.c with "extra"
+directory.
+* SMakefile.amiga: Prepend AmigaOS.c, setjmp_t.c with "extra"
+directory.
+* doc/simple_example.html: Update for threadlibs.c.
+* os_dep.c: Prepend included AmigaOS.c with "extra" directory.
+
+* include/gc.h (GC_do_blocking, GC_call_with_gc_active): New
+function prototype.
+* include/private/gc_priv.h (STOP_WORLD): Replace a no-op (for the
+single-threaded case) with an assertion check for the state to be
+not a "do-blocking" one.
+* include/private/gc_priv.h (blocking_data): Move the structure
+definition from pthread_support.c; change "fn" return type to void
+pointer.
+* include/private/gc_priv.h (GC_activation_frame_s): New structure
+type.
+* include/private/gc_priv.h (GC_push_all_stack_frames): New
+function declaration (only if THREADS).
+* include/private/gc_priv.h (GC_world_stopped): Don't declare
+unless THREADS.
+* include/private/gc_priv.h (GC_blocked_sp,
+GC_activation_frame_s): New declaration (only if not THREADS).
+* include/private/gc_priv.h (GC_push_all_register_frames): New
+function declaration (only for IA-64).
+* include/private/gc_priv.h (NURSERY, GC_push_proc): Remove
+obsolete (unused) symbols.
+* include/private/gc_priv.h (GC_push_all_stack_partially_eager):
+Remove declaration (since it is static now).
+* mark_rts.c (GC_push_all_stack_partially_eager): Move from mark.c
+(for code locality) and make STATIC.
+* mark_rts.c (GC_push_all_register_frames): New function (only for
+IA-64).
+* mark_rts.c (GC_push_all_stack_frames): New function (only if
+THREADS).
+* mark_rts.c (GC_add_trace_entry): New function prototype (used by
+GC_push_all_stack_partially_eager(), only if TRACE_BUF).
+* mark_rts.c (GC_push_all_stack_part_eager_frames): New function.
+* mar_rts.c (GC_save_regs_ret_val): Move the declaration out of a
+function body (only for IA-64).
+* mark_rts.c (GC_push_current_stack): Call
+GC_push_all_stack_part_eager_frames() instead of
+GC_push_all_stack_partially_eager().
+* mark_rts.c (GC_push_current_stack): Call
+GC_push_all_register_frames() instead of GC_push_all_eager() for
+IA-64 backing store.
+* misc.c (GC_do_blocking_inner): Declare function (if THREADS
+only).
+* misc.c (GC_blocked_sp, GC_blocked_register_sp,
+GC_activation_frame): New global variables (only if not THREADS).
+* misc.c (GC_call_with_gc_active, GC_do_blocking_inner): New API
+function (only if not THREADS).
+* misc.c (GC_do_blocking): Move the function from
+pthread_support.c.
+* include/private/pthread_support.h (GC_Thread_Rep): Add
+"activation_frame" field.
+* pthread_stop_world.c (GC_push_all_stacks): Call
+GC_push_all_stack_frames() and GC_push_all_register_frames instead
+of GC_push_all_stack() and/or GC_push_all_eager(); don't check for
+STACK_GROWS_UP here.
+* pthread_support.c (GC_do_blocking_inner): Remove "static"; store
+"fn" result back to "client_data" field.
+* pthread_support.c (GC_call_with_gc_active): New API function.
+* win32_threads.c (GC_call_with_gc_active): Likewise.
+* win32_threads.c (GC_Thread_Rep): Add "thread_blocked_sp" and
+"activation_frame" fields.
+* win32_threads.c (GC_new_thread): Add assertion checking for
+thread_blocked_sp is NULL.
+* win32_threads.c (GC_do_blocking_inner): New function.
+* win32_threads.c (GC_stop_world): Don't suspend a thread if its
+thread_blocked_sp is non-NULL.
+* win32_threads.c (GC_push_stack_for): Use thread
+"activation_frame" (if non-NULL); use "thread_blocked_sp" if
+non-NULL (instead of calling GetThreadContext()); "UNPROTECT" the
+thread before modifying its last_stack_min; call
+GC_push_all_stack_frames() instead of GC_push_all_stack(); update
+the comments.
+
+* alloc.c (GC_default_stop_func): New static variable (initialized
+to GC_never_stop_func).
+* alloc.c (GC_set_stop_func, GC_get_stop_func): New function.
+* alloc.c (GC_timeout_stop_func): Define as GC_default_stop_func
+(instead of GC_never_stop_func) if SMALL_CONFIG (or NO_CLOCK),
+else call GC_default_stop_func() before getting "current_time".
+* alloc.c (GC_maybe_gc): Expand GC_gcollect_inner() macro (for
+FIXME comment).
+* alloc.c (GC_maybe_gc, GC_collect_a_little_inner): add FIXME for
+replacing GC_never_stop_func with GC_default_stop_func (if
+possible).
+* alloc.c (GC_gcollect): Use GC_default_stop_func.
+* alloc.c (GC_collect_or_expand): Use GC_default_stop_func
+(instead of GC_never_stop_func) unless it is trigged due to out of
+memory; don't increment GC_fail_count and don't output warning
+(before trying to collect again) in case the collection has been
+interrupted (by GC_default_stop_func) and the heap expansion has
+failed too.
+* include/gc.h (GC_set_stop_func, GC_get_stop_func): New function
+prototypes.
+
+* os_dep.c (GC_get_stack_base): Add FIXME; add assertion for
+GC_get_writable_length() result.
+
+* configure.ac: Don't use -lpthread -ldl for Cygwin.
+
+* NT_THREADS_MAKEFILE: Make it back equal to gc.mak.
+
+* include/private/gcconfig.h (GWW_VDB): Undefine if
+USE_GLOBAL_ALLOC (since incompatible).
+* os_dep.c (GetWriteWatch_alloc_flag): Define as 0 unless GWW_VDB
+is defined.
+* os_dep.c (GC_unmap_threshold): Declare (for use in
+GC_init_win32) if USE_MUNMAP.
+* os_dep.c (GC_init_win32): Turn off memory unmapping if
+GlobalAlloc() is used.
+* os_dep.c (GC_win32_get_mem): Define and use new
+VIRTUAL_ALLOC_PAD macro; don't waste a extra memory page unless
+MPROTECT_VDB is in use.
+
+* Makefile: Replace "version.h" with "include/gc_version.h".
+* include/gc_version.h: Likewise.
+
+* alloc.c (GC_collect_or_expand): Output heap size in WARN()
+(before returning FALSE) for convenience.
+
+* allchblk.c (GC_allochblk_nth): Use GC_PRIdPTR in WARN() format
+string.
+* pthread_support.c (start_mark_threads, GC_thr_init): Likewise.
+* win32_threads.c (GC_delete_thread): Likewise.
+* include/private/gc_priv.h (GC_PRIdPTR): New macro.
+* pthread_stop_world.c (GC_suspend_handler_inner): Remove
+unnecessary cast for WARN argument.
+* pthread_support.c (start_mark_threads): if pthread_create()
+failed then don't try to create other marker threads and (after
+printing a warning) adjust GC_markers and GC_parallel values; log
+GC_markers value (possibly adjusted) after that.
+
+* win32_threads.c (start_mark_threads): if pthread_create() is
+failed then don't try to create other marker threads and (after
+printing a warning) adjust GC_markers and GC_parallel values.
+* win32_threads.c (mark_mutex_event, builder_cv, mark_cv): Move
+the definition upper (to be visible in start_mark_threads()).
+* win32_threads.c (start_mark_threads): if CreateThread() or
+_beginthreadex() is failed then don't try to create other marker
+threads and (after printing a warning) adjust GC_markers,
+GC_parallel values, and destroy the event objects (either only
+some for the uncreated threads if DONT_USE_SIGNALANDWAIT or all if
+not a single thread is created).
+* win32_threads.c (GC_thr_init): Log GC_markers value (possibly
+adjusted) after start_mark_threads() call.
+
+* Makefile.am: Back remove "GC_" prefix for PTHREADS,
+DARWIN_THREADS, WIN32_THREADS (for configure.ac).
+
+* include/private/gc_priv.h: Change include of config.h to
+private/config.h.
+* include/private/gc_pmark.h: Likewise.
+* gc_cpp.cc: Likewise.
+* tests/test.c: Likewise.
+* tests/test_cpp.cc: Include private/config.h (if HAVE_CONFIG_H);
+undefine GC_BUILD.
+
+* finalize.c (GC_general_register_disappearing_link): Return
+GC_SUCCESS, GC_DUPLICATE, GC_NO_MEMORY (instead of 0, 1 and 2,
+respectively).
+* include/gc.h (GC_NO_MEMORY): New macro (defined as 2).
+* include/gc.h (GC_register_disappearing_link,
+GC_general_register_disappearing_link): Update the comment.
+* typd_mlc.c (GC_calloc_explicitly_typed): Use GC_NO_MEMORY macro.
+* finalize.c (GC_general_register_disappearing_link,
+GC_register_finalizer_inner): Recalculate the hash table index
+after GC_oom_fn succeeded (since the table may grow while not
+holding the lock) and check again that the entry is still not in
+the table (free the unused entry otherwise unless DBG_HDRS_ALL).
+* finalize.c (GC_register_finalizer_inner): Initialize "hhdr"
+local variable (to prevent a compiler warning).
+* finalize.c (GC_register_finalizer_inner): Don't modify the data
+pointed by "ocd" and "ofn" in GC_register_finalizer_inner() failed
+(due to out of memory).
+
+* alloc.c (GC_set_fl_marks, GC_clear_fl_marks): Transform loop to
+suppress compiler "variable might be uninitialized" warnings.
+
+* Makefile.direct (DONT_USE_SIGNALANDWAIT): Add the comment for.
+* win32_threads.c (DONT_USE_SIGNALANDWAIT): Always define for
+WinCE.
+* win32_threads.c (THREAD_HANDLE): Cast Id (of DWORD type) to
+HANDLE thru word type (to avoid a compiler warning) for WinCE.
+* win32_threads.c (GC_marker_cv, GC_marker_Id): New static array
+(only if DONT_USE_SIGNALANDWAIT).
+* win32_threads.c (start_mark_threads): Initialize GC_marker_Id
+and GC_marker_cv for each helper thread (only if
+DONT_USE_SIGNALANDWAIT).
+* win32_threads.c (GC_mark_mutex_state): New static variable (only
+if DONT_USE_SIGNALANDWAIT).
+* win32_threads.c (GC_mark_mutex_waitcnt,
+signalObjectAndWait_func): Don't define if DONT_USE_SIGNALANDWAIT.
+* win32_threads.c (GC_acquire_mark_lock, GC_release_mark_lock):
+Use InterlockedExchange() over GC_mark_mutex_state (instead of
+AO_fetch_and_add()) if DONT_USE_SIGNALANDWAIT.
+* win32_threads.c (GC_wait_marker, GC_notify_all_marker):
+Implement wait/broadcast primitives using Win32 multiple events
+(one for each marker thread) if DONT_USE_SIGNALANDWAIT (instead of
+using Win32 SignalObjectAndWait).
+* win32_threads.c (GC_thr_init): Don't declare hK32 local
+variable, don't check for GC_wnt, and don't initialize
+signalObjectAndWait_func if DONT_USE_SIGNALANDWAIT.
+
+* alloc.c (GC_finish_collection): Call GC_print_finalization_stats
+if GC_print_stats (after getting "done_time").
+* finalize.c (GC_old_dl_entries): New static variable (only if not
+SMALL_CONFIG).
+* finalize.c (GC_finalize): Save current GC_dl_entries value (only
+if not SMALL_CONFIG).
+* finalize.c (GC_print_finalization_stats): Define if and only if
+not SMALL_CONFIG; use GC_old_dl_entries value; use GC_log_printf()
+instead of GC_printf(); use "%lu" (instead of "%u") print format
+specifier; use unsigned long type for "ready" counter (for LP64
+targets).
+* misc.c (GC_dump): No longer call GC_print_finalization_stats()
+here (since it is called from GC_finish_collection()).
+* misc.c (STACKBASE): Remove unused macro undef (for NOSYS and
+ECOS).
+
+* alloc.c (GC_expand_hp): Replace GC_init_inner() call with
+GC_init() one.
+* malloc.c (GC_alloc_large, GC_generic_malloc_inner): Likewise.
+* mallocx.c (GC_generic_malloc_many): Likewise.
+* misc.c (GC_enable_incremental): Likewise.
+* alloc.c (GC_expand_hp): Update the comment.
+* mark.c (GC_obj_kinds): Likewise.
+* win32_threads.c (GC_allow_register_threads): Likewise.
+* private/gc_priv.h (GC_init_inner): Remove function declaration.
+* misc.c (GC_init_inner): Replace with public GC_init().
+
+* gcj_mlc.c (GC_gcj_fake_mark_proc): New static function.
+* gcj_mlc.c (GC_init_gcj_malloc): If mp is 0 then supply
+GC_gcj_fake_mark_proc (aborting with the appropriate message)
+instead.
+
+* os_dep.c (GC_wince_get_mem): If VirtualAlloc() returns NULL (due
+to out of memory) then don't increment GC_n_heap_bases and don't
+call VirtualAlloc() again (with MEM_COMMIT).
+* os_dep.c (GC_remap): Abort with a more informatory message if
+VirtualAlloc() fails due to out of memory; update FIXME.
+
+* Makefile: Fix typo for msvc_dbg.c.
+* Makefile.direct: Likewise.
+* Makefile.am: Prefix PTHREADS, DARWIN_THREADS, WIN32_THREADS with
+"GC_".
+* Makefile.dj: Don't reference remove files (nursery.c,
+gc_nursery.h, gc_copy_descr.h).
+* NT_MAKEFILE: Don't define __STDC__ macro (no longer used).
+* NT_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_THREADS_MAKEFILE: Likewise.
+* NT_X64_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_THREADS_MAKEFILE: Likewise.
+* gc.mak: Likewise.
+* NT_MAKEFILE: Remove unnecessary -DGC_BUILD (since it is always
+defined in the source files).
+* NT_THREADS_MAKEFILE: Likewise.
+* NT_X64_THREADS_MAKEFILE: Likewise.
+* gc.mak: Likewise.
+* NT_X64_THREADS_MAKEFILE: Fix typo for -DGC_NOT_DLL.
+* NT_STATIC_THREADS_MAKEFILE: Replace GC_WIN32_THREADS with
+GC_THREADS.
+* NT_THREADS_MAKEFILE: Likewise.
+* NT_X64_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_THREADS_MAKEFILE: Likewise.
+* gc.mak: Likewise.
+* NT_MAKEFILE: Define _CRT_SECURE_NO_DEPRECATE to suppress the
+compiler warnings.
+* NT_STATIC_THREADS_MAKEFILE: Likewise.
+* NT_X64_STATIC_THREADS_MAKEFILE: Place -D_CRT_SECURE_NO_DEPRECATE
+before "$*.C" (and "$*.CPP").
+* NT_X64_THREADS_MAKEFILE: Likewise.
+
+* doc/README.solaris2: Replace GC_SOLARIS_THREADS with GC_THREADS.
+* doc/README.win32: Replace GC_WIN32_THREADS with GC_THREADS.
+* doc/README.win64: Add info about mingw-w64; add note for VC++
+warnings suppression.
+
+* os_dep.c (GC_forward_exception): Fix logic in several places.
+(OSX-specific)
+
+* include/private/gc_priv.h (MAX_HEAP_SECTS): Guard with ifndef.
+
+* Makefile.direct: Copy missing information for -DSHORT_DBG_HDRS
+from Makefile.
+* Makefile: Remove the information about "define arguments" (which
+is incomplete and outdated compared to that in Makefile.direct);
+add help reference to Makefile.direct.
+* Makefile.dj: Likewise.
+
+* alloc.c (world_stopped_total_time, world_stopped_total_divisor):
+Replace "STATIC" with "static" in the definition (since the
+symbols aren't prefixed with "GC_").
+* win32_threads.c (marker_sp, marker_bsp, marker_last_stack_min,
+start_mark_threads, mark_mutex, builder_cv, mark_cv,
+mark_mutex_event, signalObjectAndWait_func, main_thread_start):
+Likewise.
+* pthread_support.c (GC_wait_builder): Define as STATIC.
+* win32_threads.c (GC_wait_builder): Likewise.
+
+* misc.c (GC_get_heap_size_inner, GC_get_free_bytes_inner): New
+API function.
+* include/gc_pmark.h (GC_get_heap_size_inner,
+GC_get_free_bytes_inner): New function declaration.
+
+* include/gc.h: Recognize __CEGCC__ (as a synonym for _WIN32_WCE).
+* include/gc_config_macros.h: Likewise.
+* include/gc.h (GC_MAXIMUM_HEAP_SIZE): Recognize new macro.
+* include/gc.h (GC_INIT_CONF_MAXIMUM_HEAP_SIZE): New macro (for
+internal use).
+* include/gc_config_macros.h: Always include stddef.h if GCC.
+* include/gc_config_macros.h (GC_API): Define for CeGCC in the
+same way as for MinGW.
+* include/gc_config_macros.h (GC_API): Group the definition for
+all cases together (check for GC_DLL only once).
+* include/gc_pthread_redirects.h: Group non-Darwin code together.
+* tests/test.c: Recognize GC_PRINT_VERBOSE_STATS (only if GC_DLL).
+
+* Makefile.direct (GC_PTHREADS_PARAMARK, GC_IGNORE_GCJ_INFO,
+GC_PRINT_VERBOSE_STATS, GC_DONT_EXPAND, GC_INITIAL_HEAP_SIZE,
+GC_FREE_SPACE_DIVISOR, GC_TIME_LIMIT, GC_FULL_FREQ): Add the
+comment for.
+* misc.c (GC_init_inner): Recognize GC_PRINT_VERBOSE_STATS (new
+macro).
+* dyn_load.c (GC_wnt): Change definition to TRUE for WinCE; add
+FIXME and the comment for WinCE.
+* gcj_mlc.c (GC_init_gcj_malloc): Recognize GC_IGNORE_GCJ_INFO
+(new macro).
+* include/gc.h (GC_HAVE_BUILTIN_BACKTRACE): Don't define for VC++
+WinCE (since backtrace() is unimplemented).
+* include/private/gc_priv.h (GC_n_heap_bases): Remove declaration
+(since static).
+* os_dep.c (GC_n_heap_bases): Define as STATIC; move the
+definition to be above GC_is_heap_base().
+* include/private/gcconfig.h: Don't define NOSYS for WinCE on ARM
+(both for MinGW and CeGCC toolchains).
+* include/private/gcconfig.h: Recognize __CEGCC__ and
+__MINGW32CE__ (as synonyms for __WIN32_WCE).
+* include/private/gcconfig.h: If SH4 then don't set config
+parameters for SH.
+* include/private/thread_local_alloc.h (GC_key_create): Don't
+abort on failures, just return -1 in these cases (this also
+prevents compilation error for targets where ABORT is defined
+indirectly as an inline assembler sequence).
+* mark.c (WRAP_MARK_SOME): Also define for WinCE; add FIXME for
+the GCC-based cross-compiler.
+* mark.c (ext_ex_regn, mark_ex_handler): Don't define unless
+WRAP_MARK_SOME is defined; define also for WinCE case; don't
+check for _WIN64 (since WRAP_MARK_SOME is undefined for it).
+* mark.c (GC_mark_some): Use __try/__except also for WinCE; update
+the comment.
+* misc.c: Include signal.h after gc_pmark.h included; check for
+MSWINCE instead of _WIN32_WCE.
+* misc.c (GC_init_inner): Remove duplicate GC_setpagesize() call.
+* misc.c: Don't include <crtdbg.h> for WinCE targets.
+* misc.c (GC_write): Define _MAX_PATH if undefined (workaround for
+CeGCC toolchain).
+* misc.c (GC_write): Use OutputDebugStringW() instead of
+_CrtDbgReport() for WinCE targets.
+* os_dep.c (GC_least_described_address): Define as STATIC.
+* os_dep.c (GC_register_data_segments): Fix code indentation.
+* os_dep.c (GC_wince_get_mem): Initialize "result" local variable
+(to prevent a compiler warning).
+* os_dep.c (GC_dirty_init): Add comment for WinCE target.
+* tests/test.c: Don't include winbase.h directly if GCC for WinCE,
+include assert.h instead.
+* tests/test.c (tiny_reverse_test): Define and use
+TINY_REVERSE_UPPER_VALUE macro (4 if VERY_SMALL_CONFIG else 10);
+useful for WinCE.
+* win32_threads.c (GC_Thread_Rep): Don't declare "handle" field
+for WinCE (since thread Id is used as a "real" thread handle).
+* win32_threads.c (THREAD_HANDLE): New macro.
+* win32_threads.c (GC_register_my_thread_inner): Don't recognize
+DONT_IMPORT_GETCURTHREAD anymore; don't record thread handle on
+WinCE.
+* Makefile.direct (DONT_IMPORT_GETCURTHREAD): Remove comment for.
+* win32_threads.c (UNPROTECT, GC_fault_handler_lock): Don't check
+for MSWINCE.
+* win32_threads.c (GC_delete_gc_thread, GC_delete_thread): Don't
+close thread handle on WinCE (since it's a thread Id).
+* win32_threads.c (GC_suspend): Don't check for MSWINCE in the
+MPROTECT-related code (for the case if MPROTECT_VDB would be
+implemented for WinCE).
+* win32_threads.c (GC_suspend, GC_start_world, GC_push_stack_for):
+Use THREAD_HANDLE(t) to obtain thread handle.
+* win32_threads.c (GC_PTHREADS_PARAMARK): New macro recognized;
+implicitly define GC_PTHREADS_PARAMARK if GC_PTHREADS; include
+pthread.h; define NUMERIC_THREAD_ID(id) if undefined yet; replace
+GC_PTHREADS with GC_PTHREADS_PARAMARK where appropriate (for the
+parallel mark support).
+* win32_threads.c (start_mark_threads): Use int type for "i" local
+variable (instead of "unsigned") to prevent a compiler warning.
+* win32_threads.c (start_mark_threads): Don't check CreateThread()
+result for -1; call CloseHandle() for the handle created by
+CreateThread() (on WinCE); don't use errno (since errno.h is
+missing on some targets like WinCE) when printing warning on a
+marker thread creation failure.
+* win32_threads.c (signalObjectAndWait_func): Define for WinCE.
+* win32_threads.c (GC_wait_marker): Remove unnecessary assertion
+for non-zero signalObjectAndWait_func (to make the code compilable
+for WinCE).
+* win32_threads.c (GC_thr_init): Allow PARALLEL_MARK for WinCE;
+use GC_sysinfo to get processors count if WinCE; don't check for
+SignalObjectAndWait() if WinCE; replace GC_PTHREADS with
+GC_PTHREADS_PARAMARK.
+* win32_threads.c (GC_thr_init): Recognize GC_MIN_MARKERS new
+macro (useful for testing parallel marking on WinCE).
+* win32_threads.c (GC_win32_start, main_thread_start): Define as
+STATIC.
+* win32_threads.c: Don't define main_thread_args,
+main_thread_start(), WinMain() for WinCE if GC_DLL.
+* win32_threads.c (WINCE_MAIN_STACK_SIZE): Remove useless macro
+(since the stack size parameter is ignored on WinCE).
+* win32_threads.c (main_thread_start): Remove forward declaration;
+place its definition before WinMain() one.
+* win32_threads.c (WinMain): Abort if GC_CreateThread() or
+WaitForSingleObject() failed (for the main thread).
+
+* allchblk.c (MUNMAP_THRESHOLD): Move macro definition out of
+a function.
+* allchblk.c (GC_unmap_threshold): New global variable definition
+(initialized to MUNMAP_THRESHOLD).
+* allchblk.c (GC_unmap_old): Use GC_unmap_threshold instead of
+MUNMAP_THRESHOLD; skip unmapping if GC_unmap_threshold is 0.
+* doc/README.environment (GC_UNMAP_THRESHOLD): Add information.
+* misc.c (GC_unmap_threshold): New variable declaration.
+* misc.c (GC_init_inner): Recognize "GC_UNMAP_THRESHOLD"
+environment variable to set GC_unmap_threshold value (only if
+USE_MUNMAP).
+
+* dbg_mlc.c (OFN_UNSET): New macro (to detect
+GC_register_finalizer() failures).
+* dbg_mlc.c (store_old): Add a check for register_finalizer()
+failure caused by an out-of-memory event (leave *ofn and *ocd
+unmodified in that case).
+* dbg_mlc.c (GC_debug_register_finalizer,
+GC_debug_register_finalizer_no_order,
+GC_debug_register_finalizer_unreachable,
+GC_debug_register_finalizer_ignore_self): Initialize my_old_fn
+to OFN_UNSET; clear *ocd and *ofn for non-heap objects (the same
+as in GC_register_finalizer_inner()).
+
+* Makefile.direct (GC_DLL): Add the comment for.
+* doc/README.macros: Fix a typo.
+* doc/README.macros (_DLL, GC_DLL, GC_NOT_DLL): Update info.
+* doc/README.macros (__STDC__): Remove info.
+* dbg_mlc.c (GC_get_back_ptr_info, GC_generate_random_heap_address,
+GC_generate_random_valid_address, GC_print_backtrace,
+GC_generate_random_backtrace, GC_register_describe_type_fn): Add
+GC_API and GC_CALL to function definition.
+* malloc.c (GC_generic_malloc): Likewise.
+* mallocx.c (GC_incr_bytes_allocd, GC_incr_bytes_freed): Likewise.
+* mark.c (GC_mark_and_push): Likewise.
+* misc.c (GC_new_free_list_inner, GC_new_free_list,
+GC_new_kind_inner, GC_new_kind, GC_new_proc_inner, GC_new_proc):
+Likewise.
+* include/gc_backptr.h (GC_get_back_ptr_info,
+GC_generate_random_heap_address, GC_generate_random_valid_address,
+GC_generate_random_backtrace, GC_print_backtrace): Add GC_API and
+GC_CALL to function prototype.
+* include/gc_mark.h (GC_mark_and_push, GC_new_free_list,
+GC_new_free_list_inner, GC_new_kind, GC_new_kind_inner,
+GC_new_proc, GC_new_proc_inner, GC_generic_malloc,
+GC_register_describe_type_fn): Likewise.
+* include/new_gc_alloc.h (GC_incr_bytes_allocd, GC_incr_mem_freed,
+GC_generic_malloc_words_small): Likewise.
+* gc_cpp.cc: Include "config.h" (if HAVE_CONFIG_H defined).
+* include/private/gc_pmark.h: Likewise.
+* include/private/gc_priv.h: Likewise.
+* tests/test.c: Likewise.
+* gc_cpp.cc: Define GC_BUILD.
+* include/private/gc_pmark.h: Likewise.
+* include/private/gc_priv.h: Likewise.
+* gc_dlopen.c (WRAP_FUNC, REAL_FUNC): New macro.
+* gc_dlopen.c (dlopen): Add GC_API to the wrapper function
+definition.
+* pthread_support.c (GC_pthread_create, GC_pthread_sigmask,
+GC_pthread_join, GC_pthread_detach, pthread_sigmask, pthread_join,
+pthread_detach, pthread_create): Likewise.
+* win32_threads.c (GC_pthread_join, GC_pthread_create,
+GC_pthread_sigmask, GC_pthread_detach): Likewise.
+* gc_dlopen.c (dlopen): Use WRAP_FUNC and REAL_FUNC macros.
+* include/gc_backptr.h: Include "gc.h".
+* include/gc_backptr.h: Use extern "C" for the exported functions.
+* include/gc_mark.h: Likewise.
+* include/gc_config_macros.h (GC_THREADS): Define the macro if any
+GC_XXX_THREADS is defined.
+* include/gc_config_macros.h (_PTHREADS, _POSIX4A_DRAFT10_SOURCE):
+Move the definitions below the place where GC_NETBSD_THREADS and
+GC_DGUX386_THREADS are defined.
+* include/gc_config_macros.h (GC_DLL): Don't define (even if _DLL
+is defined) for GCC.
+* include/gc_config_macros.h (GC_API): Define for Cygwin (in the
+same way as for VC++); define for GCC v4+ (other than already
+recognized MinGW/Cygwin) as a "default" visibility attribute if
+GC_DLL is defined.
+* include/gc_config_macros.h (GC_ATTR_MALLOC, GC_ATTR_ALLOC_SIZE):
+New macro.
+* include/gc.h (GC_malloc, GC_malloc_atomic, GC_strdup,
+GC_malloc_uncollectable, GC_malloc_stubborn, GC_memalign,
+GC_malloc_atomic_uncollectable, GC_malloc_ignore_off_page,
+GC_malloc_atomic_ignore_off_page, GC_debug_malloc,
+GC_debug_malloc_atomic, GC_debug_strdup,
+GC_debug_malloc_uncollectable, GC_debug_malloc_stubborn,
+GC_debug_malloc_ignore_off_page,
+GC_debug_malloc_atomic_ignore_off_page,
+GC_debug_malloc_replacement): Add GC_ATTR_MALLOC attribute.
+* include/gc_gcj.h (GC_gcj_malloc, GC_debug_gcj_malloc,
+GC_gcj_malloc_ignore_off_page): Likewise.
+* include/gc.h (GC_malloc, GC_malloc_atomic,
+GC_malloc_uncollectable, GC_malloc_stubborn,
+GC_malloc_atomic_uncollectable, GC_malloc_ignore_off_page,
+GC_malloc_atomic_ignore_off_page, GC_debug_malloc,
+GC_debug_malloc_atomic, GC_debug_malloc_uncollectable,
+GC_debug_malloc_stubborn, GC_debug_malloc_ignore_off_page,
+GC_debug_malloc_atomic_ignore_off_page,
+GC_debug_malloc_replacement: Add GC_ATTR_ALLOC_SIZE attribute
+(for the first argument).
+* include/gc_gcj.h (GC_gcj_malloc, GC_debug_gcj_malloc,
+GC_gcj_malloc_ignore_off_page): Likewise.
+* include/gc.h (GC_memalign, GC_realloc, GC_debug_realloc,
+GC_debug_realloc_replacement): Add GC_ATTR_ALLOC_SIZE attribute
+(for the second argument).
+* include/gc.h (GC_malloc, GC_malloc_atomic, GC_strdup,
+GC_malloc_uncollectable, GC_malloc_stubborn, GC_memalign,
+GC_malloc_atomic_uncollectable, GC_free, GC_base, GC_size,
+GC_realloc, GC_expand_hp, GC_set_max_heap_size,
+GC_exclude_static_roots, GC_add_roots, GC_remove_roots,
+GC_register_displacement, GC_debug_register_displacement,
+GC_try_to_collect, GC_malloc_ignore_off_page,
+GC_malloc_atomic_ignore_off_page, GC_debug_malloc,
+GC_debug_malloc_atomic, GC_debug_strdup,
+GC_debug_malloc_uncollectable, GC_debug_malloc_stubborn,
+GC_debug_malloc_ignore_off_page,
+GC_debug_malloc_atomic_ignore_off_page, GC_debug_free,
+GC_debug_realloc, GC_debug_malloc_replacement,
+GC_debug_realloc_replacement, GC_finalization_proc,
+GC_register_finalizer, GC_debug_register_finalizer,
+GC_register_finalizer_ignore_self,
+GC_debug_register_finalizer_ignore_self,
+GC_register_finalizer_no_order,
+GC_debug_register_finalizer_no_order,
+GC_register_finalizer_unreachable,
+GC_debug_register_finalizer_unreachable,
+GC_register_disappearing_link,
+GC_general_register_disappearing_link,
+GC_unregister_disappearing_link, GC_noop1, GC_warn_proc,
+GC_set_warn_proc, GC_ignore_warn_proc, GC_fn_type,
+GC_call_with_alloc_lock, GC_stack_base_func,
+GC_call_with_stack_base, GC_same_obj, GC_pre_incr, GC_post_incr,
+GC_is_visible, GC_is_valid_displacement, GC_same_obj_print_proc,
+GC_is_valid_displacement_print_proc, GC_is_visible_print_proc,
+GC_malloc_many, GC_CreateThread, GC_beginthreadex,
+GC_endthreadex): Comment out (or remove if single and meaningless)
+function argument names (to avoid identifiers out of the name
+space).
+* include/gc_gcj.h (GC_init_gcj_malloc, GC_gcj_malloc,
+GC_debug_gcj_malloc, GC_gcj_malloc_ignore_off_page): Likewise.
+* include/gc.h (GC_try_to_collect): Update the comment.
+* include/gc.h (GC_size, GC_register_my_thread): Add const
+qualifier for the argument referent.
+* misc.c (GC_size): Likewise.
+* pthread_support.c (GC_register_my_thread_inner,
+GC_register_my_thread): Likewise.
+* win32_threads.c (GC_register_my_thread_inner,
+GC_register_my_thread): Likewise.
+* include/gc.h (GC_INIT_CONF_ROOTS): New macro for internal use
+(define instead of GC_INIT() for Cygwin and AIX).
+* include/gc.h (GC_DONT_EXPAND, GC_MAX_RETRIES,
+GC_FREE_SPACE_DIVISOR, GC_FULL_FREQ, GC_TIME_LIMIT, GC_IGNORE_WARN,
+GC_INITIAL_HEAP_SIZE): Recognize new macro.
+* include/gc.h (GC_INIT_CONF_DONT_EXPAND, GC_INIT_CONF_MAX_RETRIES,
+GC_INIT_CONF_FREE_SPACE_DIVISOR, GC_INIT_CONF_FULL_FREQ,
+GC_INIT_CONF_TIME_LIMIT, GC_INIT_CONF_IGNORE_WARN,
+GC_INIT_CONF_INITIAL_HEAP_SIZE): New macro for internal use.
+* include/gc.h (GC_INIT): Use GC_INIT_CONF_XXX macros.
+* include/gc_mark.h: Prefix GC_H with '_'.
+* include/gc_mark.h (GC_least_plausible_heap_addr,
+GC_greatest_plausible_heap_addr, GC_debug_header_size): Use GC_API
+for the public variable declaration.
+* include/new_gc_alloc.h (GC_objfreelist_ptr, GC_aobjfreelist_ptr,
+GC_uobjfreelist_ptr, GC_auobjfreelist_ptr): Likewise.
+* include/gc_pthread_redirects.h (GC_pthread_create,
+GC_pthread_sigmask, GC_dlopen, GC_pthread_join, GC_pthread_detach):
+Use GC_API for the wrapper prototype.
+* include/gc_pthread_redirects.h (pthread_create, pthread_join,
+pthread_detach, pthread_sigmask, dlopen): Undefine unconditionally
+before redirecting.
+* include/new_gc_alloc.h: Replace GC_incr_mem_freed() with
+GC_incr_bytes_freed(); remove FIXME.
+* include/private/gc_priv.h (GC_make_closure,
+GC_debug_invoke_finalizer, GC_noop): Remove GC_API for the private
+function.
+* tests/test.c (GC_print_stats): Handle GC_DLL case regardless of
+the target.
+
+* finalize.c (GC_general_register_disappearing_link,
+GC_register_finalizer_inner): Remove unnecessary "ifdef THREADS"
+guard for LOCK/UNLOCK().
+* finalize.c (GC_general_register_disappearing_link,
+GC_register_finalizer_inner): Get GC_oom_fn value before releasing
+the lock (to prevent data races).
+* gcj_mlc.c (GC_gcj_malloc, GC_debug_gcj_malloc,
+GC_gcj_malloc_ignore_off_page): Likewise.
+* mallocx.c (GC_generic_malloc_ignore_off_page): Likewise.
+* include/gc_inline.h (GC_FAST_MALLOC_GRANS): Use GC_get_oom_fn()
+instead of GC_oom_fn (to prevent data races).
+* malloc.c (GC_generic_malloc): Likewise.
+* mallocx.c (GC_memalign): Likewise.
+* pthread_support.c (pthread_create): Likewise.
+* gcj_mlc.c (maybe_finalize): Acquire the lock before setting
+last_finalized_no value to prevent data races.
+* include/gc.h (GC_gc_no, GC_get_gc_no, GC_oom_fn, GC_set_oom_fn,
+GC_set_find_leak, GC_set_finalize_on_demand,
+GC_set_java_finalization, GC_set_finalizer_notifier,
+GC_set_dont_expand, GC_set_full_freq, GC_set_non_gc_bytes,
+GC_set_no_dls, GC_set_free_space_divisor, GC_set_max_retries,
+GC_set_dont_precollect, GC_set_time_limit, GC_warn_proc): Refine
+the comment.
+* misc.c (GC_set_oom_fn): Likewise.
+* include/gc.h (GC_general_register_disappearing_link): Refine the
+comment (replace "soft" word with "weak").
+* misc.c (GC_oom_fn, GC_get_gc_no, GC_get_parallel,
+GC_set_finalizer_notifier, GC_set_find_leak): Add the comment.
+* misc.c (GC_set_oom_fn, GC_get_oom_fn, GC_set_finalizer_notifier,
+GC_get_finalizer_notifier): Use LOCK/UNLOCK to prevent data races.
+
+* dbg_mlc.c: Guard include <errno.h> with ifndef MSWINCE; include
+"private/dbg_mlc.h" before it.
+* malloc.c: Likewise.
+* dbg_mlc.c (GC_debug_strdup): Use memcpy() instead of strcpy()
+for WinCE (since deprecated); evaluate strlen() only once; don't
+set errno for WinCE.
+* malloc.c (GC_strdup): Likewise.
+* dyn_load.c (GC_wnt): Define as macro (FALSE) for WinCE.
+* include/gc.h (GC_unregister_my_thread): Refine the comment.
+* include/gc.h (GC_uintptr_t, GC_beginthreadex, GC_endthreadex):
+Don't declare for WinCE.
+* include/gc.h (GC_WINMAIN_WINCE_LPTSTR): New macro (WinCE only).
+* include/gc.h (GC_WinMain): Remove GC_API.
+* include/gc.h (GC_WinMain): Use GC_WINMAIN_WINCE_LPTSTR for
+lpCmdLine.
+* tests/test.c (GC_WinMain): Likewise.
+* win32_threads.c (main_thread_args, GC_WinMain): Likewise.
+* include/gc_config_macros.h (ptrdiff_t): Guard with
+ifndef _PTRDIFF_T_DEFINED; define _PTRDIFF_T_DEFINED macro.
+* include/private/gc_locks.h: Guard include "atomic_ops.h" with
+ifdef GC_PTHREADS (and not GC_WIN32_THREADS).
+* mark.c: Include "atomic_ops.h" if PARALLEL_MARK.
+* thread_local_alloc.c: Include "atomic_ops.h" if GC_GCJ_SUPPORT.
+* win32_threads.c: Include "atomic_ops.h" if MPROTECT_VDB.
+* include/private/gc_locks.h: Use include "atomic_ops.h" instead
+of include <atomic_ops.h>.
+* include/private/gc_priv.h: Likewise.
+* include/private/gc_locks.h (GC_allocate_ml, GC_need_to_lock):
+Don't export (replace GC_API to "extern").
+* win32_threads.c (GC_allocate_ml): Don't export.
+* include/private/gc_priv.h (DebugBreak): Define as macro for
+WinCE (if not UNDER_CE and DebugBreak is not defined yet).
+* include/private/gc_priv.h (UNALIGNED): Rename to UNALIGNED_PTRS
+(since "UNALIGNED" is defined in winnt.h of WinCE).
+* mark.c (UNALIGNED): Likewise.
+* include/private/gcconfig.h (ARM32): Recognize _M_ARM and _ARM_.
+* include/private/gcconfig.h (ALIGNMENT): Check always defined.
+* include/private/gcconfig.h: Allow GC_WIN32_THREADS for WinCE.
+* include/private/thread_local_alloc.h: Define USE_WIN32_SPECIFIC
+for WinCE (since __declspec(thread) is unsupported).
+* include/private/thread_local_alloc.h (TLS_OUT_OF_INDEXES):
+Define for WinCE (if undefined).
+* malloc.c (GC_malloc): Remove outdated comment about disabling
+signals.
+* misc.c: Don't include <tchar.h> (since not used anymore and may
+break TEXT() macro defined in winnt.h).
+* misc.c (GC_init_inner): Don't use GetModuleHandle() and
+InitializeCriticalSectionAndSpinCount() for WinCE.
+* misc.c (GC_init_inner): Replace GetModuleHandleA() with
+GetModuleHandle() (and use TEXT() macro controlled by UNICODE).
+* misc.c (LOG_FILE): Remove unused macro; don't use _T() macro.
+* misc.c (GC_CreateLogFile): New static function (Win32/WinCE
+only); move the code from GC_write(); replace GETENV() with
+GetEnvironmentVariable(); replace CreateFileA() with
+CreateFile(); use TEXT() macro (for Unicode support); replace
+strcat() with memcpy() (since deprecated in WinCE).
+* misc.c (GC_write): Define as STATIC.
+* win32_threads.c (GC_attached_thread): Likewise.
+* misc.c (GC_write): Use GC_CreateLogFile().
+* misc.c: Define vsnprintf macro as StringCchVPrintfA for WinCE.
+* misc.c (GC_abort): Try to invoke MessageBoxA() dynamically
+(Win32 only) if DONT_USE_USER32_DLL is defined.
+* misc.c (GC_abort): Duplicate msg to GC log file (for Win32 and
+WinCE).
+* misc.c (GC_abort): Use a more user-friendly abort if
+NO_DEBUGGING (Win32 only).
+* os_dep.c: Include "atomic_ops.h" only if MPROTECT_VDB (and
+THREADS).
+* os_dep.c (detect_GetWriteWatch): Use TEXT() for GetModuleHandle
+(for Unicode support); check GetModuleHandle() result.
+* tests/test.c: Don't define assert for WinCE (since may be
+redefined by "assert.h" included from libatomic_ops).
+* tests/test.c (FAIL): Define as ABORT for all targets (except
+for PCR).
+* tests/test.c (n_tests): Don't use AO_t.
+* tests/test.c (check_heap_stats): Don't cast n_tests.
+* tests/test.c (inc_int_counter): New function (for n_tests atomic
+incrementation).
+* tests/test.c (run_one_test): Test GC_memalign() for all targets.
+* tests/test.c (run_one_test): Avoid unbalanced brackets in
+#if-#else-#endif blocks.
+* tests/test.c (run_one_test): Replace AO_fetch_and_add1() and
+private LOCK/UNLOCK with GC_call_with_alloc_lock(inc_int_counter).
+* tests/test.c (check_heap_stats): Replace
+"if (sizeof(char *) > 4)" with "#if CPP_WORDSZ == 64" to suppress
+"unreachable code" compiler warning.
+* tests/test.c (WinMain): Set cmd type to LPWSTR (for WinCE
+"UNDER_CE" mode); else use LPSTR type (for Win32 and WinCE).
+* tests/test.c (thr_window): Replace "L" string prefix with
+TEXT().
+* thread_local_alloc.c: Check THREADS is defined (to prevent other
+compiler errors and warnings otherwise).
+* tests/test.c (WinMain): Recognize GC_NO_DLLMAIN macro (for
+GC_use_DllMain()).
+* Makefile.direct (GC_NO_DLLMAIN, DONT_IMPORT_GETCURTHREAD): Add
+the comments for.
+* win32_threads.c (GC_register_my_thread_inner): Recognize
+DONT_IMPORT_GETCURTHREAD macro.
+* win32_threads.c: Recognize GC_NO_DLLMAIN macro (to exclude
+DllMain support if needed).
+* win32_threads.c (GC_NO_DLLMAIN): Define implicitly if DllMain
+thread registration is unsupported for a given configuration.
+* win32_threads.c (GC_use_DllMain): Update the comment; refine
+ABORT message.
+* win32_threads.c (GC_use_DllMain,
+GC_started_thread_while_stopped, GC_register_my_thread_inner,
+GC_lookup_thread_inner, GC_delete_gc_thread,
+GC_allow_register_threads, GC_lookup_pthread,
+GC_push_thread_structures, GC_stop_world, GC_push_all_stacks):
+Check for GC_NO_DLLMAIN.
+* win32_threads.c (GC_Thread_Rep.tm_in_use, GC_attached_thread,
+DllMain): Don't define if GC_NO_DLLMAIN.
+* win32_threads.c (GC_stop_world): Declare "i" and "max" local
+variables only if not GC_NO_DLLMAIN (to suppress compiler
+warning).
+* win32_threads.c (GC_mark_thread, start_mark_threads): Use
+CreateThread() instead of _beginthreadex() for WinCE.
+* win32_threads.c (MARK_THREAD_STACK_SIZE, WINCE_MAIN_STACK_SIZE):
+New macros defined (used by start_mark_threads(), WinMain()).
+* win32_threads.c (GC_thr_init): Exclude parallel-specific code on
+WinCE for now (since getenv(), GetProcessAffinityMask() and
+SignalObjectAndWait() are missing on WinCE).
+* win32_threads.c (GC_thr_init): replace GetModuleHandleA() with
+GetModuleHandle(); replace CreateEventA() with CreateEvent(); use
+TEXT() macro (for Unicode support).
+
+* include/gc.h (GC_has_static_roots_func): New typedef (user filter
+callback).
+* include/gc.h (GC_register_has_static_roots_callback): Use
+GC_has_static_roots_func type.
+* dyn_load.c (GC_has_static_roots,
+GC_register_has_static_roots_callback): Likewise.
+* dyn_load.c (GC_has_static_roots,
+GC_register_has_static_roots_callback): Define on all platforms.
+* dyn_load.c (GC_register_dynlib_callback,
+GC_register_dynamic_libraries, GC_init_dyld): Replace K&R-style
+functions definition with the ANSI C one.
+* dyn_load.c (GC_register_dynlib_callback): Use new local variable
+"callback" (initialized from GC_has_static_roots) to minimize data
+races.
+* dyn_load.c (GC_register_dynamic_libraries_dl_iterate_phdr,
+GC_cond_add_roots): Define as STATIC.
+* mark_rts.c (GC_remove_roots_inner): Likewise.
+* dyn_load.c (GC_dyld_image_add): Don't call GC_add_roots() for
+sections smaller than pointer size (just to avoid acquiring the
+lock unnecessarily).
+* dyn_load.c (GC_dyld_name_for_hdr): Define unconditionally (not
+only for DARWIN_DEBUG).
+* dyn_load.c (GC_dyld_image_add): Replace GC_add_roots() call with
+LOCK + GC_add_roots_inner() + UNLOCK.
+* dyn_load.c (GC_dyld_image_add): Call GC_has_static_roots() user
+callback (if set) holding the lock; if it returns 0 then don't call
+GC_add_roots_inner() for that region.
+* dyn_load.c (GC_register_has_static_roots_callback): Put
+"callback" value to GC_has_static_roots on all platforms.
+* dyn_load.c (GC_has_static_roots): Update the comments.
+* include/gc.h (GC_exclude_static_roots, GC_add_roots,
+GC_remove_roots, GC_register_has_static_roots_callback): Likewise.
+* include/private/gc_priv.h (struct roots): Likewise.
+* include/private/gc_priv.h (GC_remove_roots_inner): Move prototype
+to mark_rts.c and declare it as STATIC.
+* include/private/gc_priv.h (GC_exclude_static_roots_inner): New
+prototype.
+* dyn_load.c (GC_register_dynamic_libraries_dl_iterate_phdr): Use
+GC_exclude_static_roots_inner() instead of GC_exclude_static_roots.
+* misc.c (GC_init_inner): Likewise.
+* mark_rts.c (GC_exclude_static_roots_inner): New function (move
+all the code from GC_exclude_static_roots(); add the comment.
+* mark_rts.c (GC_add_roots_inner, GC_exclude_static_roots_inner):
+add alignment assertion for the lower bound; add assertion for the
+lower bound to be less than the upper one.
+* mark_rts.c (GC_add_roots_inner, GC_exclude_static_roots): Adjust
+the upper bound (round down to be of a pointer-aligned value);
+return in case of an empty range.
+* mark_rts.c (GC_exclude_static_roots): Acquire the lock and call
+GC_exclude_static_roots_inner().
+* mark_rts.c (GC_remove_roots): Quickly check the bounds and return
+in case of a do-nothing case (before acquiring the lock).
+
+* finalize.c (GC_fail_count): New external variable declaration.
+* finalize.c (GC_reset_finalizer_nested,
+GC_check_finalizer_nested): New function declarations (if THREADS
+only).
+* finalize.c (GC_finalizer_nested, GC_finalizer_skipped): New
+static global variables (used internally by GC_finalize() and
+GC_check_finalizer_nested()).
+* finalize.c (GC_check_finalizer_nested): New static function
+definition (only if not THREADS, used internally by
+GC_notify_or_invoke_finalizers() to minimize the probability of
+a deep recursion when a client finalizer tries to allocate GC
+memory).
+* finalize.c (GC_finalize): Reset GC_finalizer_nested value (or
+call GC_reset_finalizer_nested()) if last heap expansion failed.
+* finalize.c (GC_notify_or_invoke_finalizers): Access GC_gc_no,
+GC_finalizer_now, GC_finalize_on_demand, GC_finalizer_notifier,
+last_finalizer_notification variables holding the lock (to avoid
+data races).
+* finalize.c (GC_finalizer_notifier): Add comment.
+* finalize.c (GC_notify_or_invoke_finalizers): Add "quick" check
+for an empty finalization queue (only if THREADS and not
+KEEP_BACK_PTRS/MAKE_BACK_GRAPH).
+* finalize.c (GC_notify_or_invoke_finalizers): Call
+GC_check_finalizer_nested() and skip GC_invoke_finalizers() call
+if appropriate.
+* include/private/pthread_support.h (GC_Thread_Rep): Add unsigned
+finalizer_nested and finalizer_skipped fields (for internal use
+by the multi-threaded GC_check_finalizer_nested()).
+* win32_threads.c (GC_Thread_Rep): Likewise.
+* pthread_support.c (GC_reset_finalizer_nested,
+GC_check_finalizer_nested): New function definitions (the
+multi-threaded variants of that in finalize.c).
+* win32_threads.c (GC_reset_finalizer_nested,
+GC_check_finalizer_nested): Likewise.
+
+* alloc.c (GC_stopped_mark): Remove GC_log_printf("") (not needed
+anymore and GCC produces a warning for it).
+* alloc.c (GC_stopped_mark): Adjust printf argument type
+specifier.
+* backgraph.c: Include dbg_mlc.h before ifdef MAKE_BACK_GRAPH (for
+the case when the configuration information comes from aconfig
+file).
+* checksums.c: Likewise.
+* include/gc_allocator.h (GC_ATTR_UNUSED): Use "__unused__"
+keyword instead of "unused".
+* include/gc_allocator.h: Fix typos in comments.
+* thread_local_alloc.c: Likewise.
+* include/javaxfc.h (GC_finalize_all): Update comment.
+* include/private/gc_priv.h (GC_API_PRIV): New macro (defined as
+GC_API and serves only as a marker for the private but exported
+symbols used by test.c only).
+* include/private/gc_priv.h (GC_abort, GC_arrays, GC_is_marked,
+GC_printf, GC_err_printf, GC_log_printf): Replace GC_API decl with
+GC_API_PRIV one.
+* include/private/gc_priv.h (GC_fo_entries): Don't export it
+outside a DLL.
+* include/private/gc_priv.h (GC_ATTR_FORMAT_PRINTF): New macro
+designated to check the arguments correctness of printf-like
+functions (currently works only for GCC v3+).
+* include/private/gc_priv.h (GC_printf, GC_err_printf,
+GC_log_printf): Use GC_ATTR_FORMAT_PRINTF attribute.
+
+* dyn_load.c (HAVE_DL_ITERATE_PHDR): Break definition from use.
+Define for FreeBSD 7.0+.
+
+* mach_dep.c: Don't include ucontext.h with NO_GETCONTEXT.
+
+* include/gc_gcj.h (GC_init_gcj_malloc): Improve descriptive
+comment.
+
+* allchblk.c (GC_merge_unmapped): Don't assume that adjacent
+free blocks have different mapping status. Correctly handle gap
+between blocks.
+(GC_split_block): Remove dead code setting hb_flags. Add comment.
+(GC_allochblk): Split blocks also in generational-only mode.
+* os_dep.c (GC_unmap_gap): Don't really use munmap.
+
+* include/private/gc_priv.h (GC_unmapped_bytes): Define as 0 for
+not USE_MUNMAP case.
+
+* Makefile.direct (MARK_BIT_PER_OBJ, PRINT_BLACK_LIST,
+USE_PROC_FOR_LIBRARIES): Fix typo in the comments.
+* Makefile.direct (USE_MMAP, USE_MUNMAP, THREAD_LOCAL_ALLOC,
+PARALLEL_MARK, STATIC): Update the comments.
+* include/private/gcconfig.h (GC_PREFER_MPROTECT_VDB): New macro
+recognized (only if MPROTECT_VDB).
+* Makefile.direct (DONT_USE_USER32_DLL, GC_PREFER_MPROTECT_VDB):
+Add the comments for.
+* os_dep.c (detect_GetWriteWatch): Recognize "GC_USE_GETWRITEWATCH"
+environment variable (only if MPROTECT_VDB, if the variable is
+unset when GC_PREFER_MPROTECT_VDB macro controls the strategy).
+* doc/README.environment (GC_USE_GETWRITEWATCH): New variable.
+* include/private/gcconfig.h (MPROTECT_VDB): Add FIXME for
+USE_MUNMAP and PARALLEL_MARK cases (to relax the conditions in
+the future).
+* misc.c (GC_get_heap_size, GC_get_free_bytes): Ignore the memory
+space returned to OS (GC_unmapped_bytes).
+* include/gc.h (GC_get_heap_size, GC_get_free_bytes): Update the
+comments.
+* misc.c (GC_get_unmapped_bytes): New API function.
+* include/gc.h (GC_get_unmapped_bytes): New API prototype.
+* os_dep.c (GC_dirty_init): Move "ifdef GWW_VDB" block out of
+"ifdef MSWIN32" one (for Cygwin).
+
+* pthread_support.c (GC_allow_register_threads): New API function.
+* win32_threads.c (GC_allow_register_threads): Likewise.
+* include/gc.h (GC_allow_register_threads): New API prototype.
+* include/gc.h (GC_register_my_thread, GC_unregister_my_thread):
+Update the comments.
+* pthread_support.c (GC_register_my_thread): Check the collector
+is in the multi-threaded mode.
+* win32_threads.c (GC_register_my_thread): Likewise.
+
+* finalize.c (GC_finalize_all): Always call GC_invoke_finalizers
+instead, following Ivan's original patch.
+
+* allchblk.c (GC_allochblk_nth): Add assertion.
+* checksums.c: Add GC_record_fault, GC_was_faulted,
+CC_n_faulted_dirty_errors.
+(GC_check_dirty): Remove register declarations, print
+dirty bit errors on faulted pages.
+* os_dep.c (GC_write_fault_handler): Call GC_record_fault().
+* os_dep.c (GC_remove_protection): Compute index correctly.
+
+
+== [7.2alpha2] 2009-06-12 ==
+
+* dbg_mlc.c (GC_print_smashed_obj): Convert a group of printf()
+calls into a single one (for output atomicity).
+* typd_mlc.c (GC_calloc_explicitly_typed): Don't declare and use
+GC_finalization_failures variable; check the result of
+GC_general_register_disappearing_link() (for lack of memory)
+instead.
+* finalize.c (GC_finalization_failures): Remove unused global
+variable.
+* finalize.c (GC_general_register_disappearing_link,
+GC_general_register_disappearing_link): Don't update the value of
+GC_finalization_failures (since unused).
+* include/private/gc_pmark.h (PUSH_ONE_CHECKED_STACK,
+GC_PUSH_ONE_STACK, GC_PUSH_ONE_HEAP): The first parameter is of
+word type now (as FIXUP_POINTER requires numeric argument).
+* finalize.c (GC_ignore_self_finalize_mark_proc): GC_PUSH_ONE_HEAP
+requires the first parameter of word type.
+* mark.c (PUSH_GRANULE): Likewise.
+* mark.c (GC_push_one, GC_push_all_eager): Likewise.
+* finalize.c (GC_finalize_all): Call GC_invoke_finalizers() or
+GC_finalizer_notifier directly, instead
+of GC_INVOKE_FINALIZERS() to prevent infinite looping.
+* include/javaxfc.h: Clarify GC_finalize_all comment.
+* gcj_mlc.c: Include gc_pmark.h before "ifdef GC_GCJ_SUPPORT" (not
+after) for configuration information.
+* gcj_mlc.c (GC_gcj_malloc_ignore_off_page): Add comment.
+* gcj_mlc.c (GC_gcj_malloc_ignore_off_page): Check "op" local
+variable for NULL before dereferencing it, return GC_oom_fn() in
+this case.
+* typd_mlc.c (GC_malloc_explicitly_typed,
+GC_malloc_explicitly_typed_ignore_off_page): Transform the code to
+suppress compiler warning (for uninitialized "lg" variable).
+
+* win32_threads.c (GC_unregister_my_thread): add false assertion
+in unreachable code.
+
+* pthread_support.c (GC_inner_start_routine): Don't release the
+GC lock between GC_register_my_thread_inner() and
+GC_init_thread_local() calls (post the "registered" even after
+calling GC_init_thread_local()).
+* win32_threads.c (GC_register_my_thread, GC_unregister_my_thread):
+Use GC_lookup_thread_inner() instead of GC_lookup_thread() and
+acquire the GC lock only once.
+* win32_threads.c (GC_thr_init): Call GC_register_my_thread_inner()
+directly instead of GC_register_my_thread() since I_HOLD_LOCK
+and our (main) thread is not registered yet (add assertion for it).
+* win32_threads.c (GC_init_parallel): Call GC_lookup_thread_inner()
+directly instead of GC_lookup_thread() (since I_HOLD_LOCK).
+* win32_threads.c (GC_lookup_thread): Remove unused function.
+* win32_threads.c: Remove "#error GC_DLL untested with Cygwin".
+* win32_threads.c (GC_win32_dll_threads): Define as FALSE macro
+also if THREAD_LOCAL_ALLOC or GC_PTHREADS.
+* win32_threads.c (GC_use_DllMain): Call ABORT also if GC_PTHREADS
+(for Cygwin).
+* win32_threads.c (GC_push_stack_for): Add parentheses around "&&"
+(inside GC_ASSERT) to prevent compiler warning.
+* win32_threads.c (GC_push_all_stacks): Remove FIXME for
+PARALLEL_MARK.
+* win32_threads.c (MAX_MARKERS, GC_markers): Move the definitions
+to a place before GC_get_next_stack().
+* win32_threads.c (marker_sp, marker_bsp): New static arrays (same
+as in pthread_support.c).
+* win32_threads.c (marker_last_stack_min): New static arrays (the
+same semantics as for last_stack_min of GC_Thread_Rep).
+* win32_threads.c (GC_get_next_stack): Handle marker threads.
+* win32_threads.c (GC_mark_thread): Save the current stack pointer
+to marker_[b]sp.
+* win32_threads.c (start_mark_threads): Initialize
+marker_last_stack_min elements (to "unset" value).
+
+* misc.c (GC_set_oom_fn, GC_set_all_interior_pointers,
+GC_set_finalize_on_demand, GC_set_java_finalization,
+GC_set_finalizer_notifier, GC_set_dont_expand, GC_set_full_freq,
+GC_set_no_dls, GC_set_free_space_divisor, GC_set_max_retries,
+GC_set_dont_precollect, GC_set_time_limit, GC_set_warn_proc):
+Change return type to void (these API functions no longer return
+the old value).
+* include/gc.h: Likewise.
+* tests/test.c (main, WinMain, test): Remove explicit cast to void
+for GC_set_warn_proc().
+* misc.c (GC_get_oom_fn, GC_get_all_interior_pointers,
+GC_get_finalize_on_demand, GC_get_java_finalization,
+GC_get_finalizer_notifier, GC_get_dont_expand, GC_get_full_freq,
+GC_get_no_dls, GC_get_free_space_divisor, GC_get_max_retries,
+GC_get_dont_precollect, GC_get_time_limit, GC_get_warn_proc): New
+API functions (to get the current value of the corresponding R/W
+public variables).
+* include/gc.h: Likewise.
+* include/gc.h (GC_set_warn_proc, GC_set_free_space_divisor):
+Update the comment.
+* misc.c (GC_ignore_warn_proc): New API call-back function.
+* include/gc.h (GC_ignore_warn_proc): Likewise.
+* misc.c (GC_set_find_leak, GC_get_find_leak, GC_set_non_gc_bytes,
+GC_get_non_gc_bytes): New API setter and getter functions (for the
+public GC_find_leak and GC_non_gc_bytes variables, respectively).
+* include/gc.h: Likewise.
+* include/gc.h (GC_memalign): Add proto to GC API.
+* mallocx.c (GC_memalign): Use GC_API, GC_CALL for the definition.
+* tests/test.c (run_one_test): Test GC_memalign() on Win32 too,
+remove GC_memalign() proto.
+* misc.c (GC_write): Use multi-byte (A) variants of Win32
+GetModuleFileName() and CreateFile().
+* tests/test.c (main): Replace K&R-style function definition with the
+ANSI C one.
+
+* include/private/gcconfig.h (PLATFORM_ANDROID): New macro
+recognized (for Linux on ARM32 without glibc).
+* include/private/gcconfig.h (STRTOULL): Define for all targets
+(define as "strtoul" for most targets except for LLP64/Win64).
+* misc.c (GC_init_inner): Use STRTOULL instead of atoi/atol()
+(cast the result to word type) to decode values of "GC_TRACE",
+"GC_INITIAL_HEAP_SIZE", "GC_MAXIMUM_HEAP_SIZE" environment
+variables.
+
+* include/gc_allocator.h: Add gc_allocator_ignore_off_page.
+* tests/test_cpp.cc: Add call to gc_allocator_ignore_off_page.
+
+* win32_threads.c (GC_release_mark_lock): Correct misspelling of
+AO_load in assertion.
+
+* win32_threads.c (MAX_THREADS): Define as 1 if GC_win32_dll_threads
+is defined as FALSE (otherwise the size of dll_thread_table is near
+200 KiB for 32-bit).
+* win32_threads.c (GC_use_DllMain): Optimize for THREAD_LOCAL_ALLOC.
+* win32_threads.c (GC_Thread_Rep): Add backing_store_end and
+backing_store_ptr fields for IA64 support.
+* win32_threads.c (GC_register_my_thread_inner): Set
+backing_store_end field to reg_base value for IA64 (same as in
+pthread_support.c).
+* win32_threads.c (SET_PTHREAD_MAP_CACHE): Put parentheses in the
+"right" places, remove ';'.
+* win32_threads.c (GC_fault_handler_lock): Declare only
+if MPROTECT_VDB (and not WinCE).
+* win32_threads.c (GC_suspend): Acquire and release
+GC_fault_handler_lock only if MPROTECT_VDB (and not WinCE).
+* win32_threads.c (GC_suspend): Define as STATIC.
+* win32_threads.c (GC_push_stack_for): Fix WARN() format specifier
+(should be word-compliant, "%p" is used w/o "0x"), don't cast sp.
+* win32_threads.c (GC_push_all_stacks): Convert a group of printf()
+calls into a single one (for output atomicity).
+* win32_threads.c (GC_get_next_stack): Unprotect thread descriptor
+before altering its last_stack_min ("thread" variable is added).
+* win32_threads.c (GC_get_next_stack): Remove unnecessary checks for
+"s" is non-NULL.
+* win32_threads.c (GC_get_next_stack): Don't call GC_may_be_in_stack
+if WinCE.
+* win32_threads.c (GC_get_next_stack): Pass current_min value to
+GC_get_stack_min as-is (without -1).
+* win32_threads.c (GC_wait_marker): Remove FIXME and use "release"
+version of AO_fetch_and_sub1().
+* win32_threads.c (GC_win32_start_inner, GC_win32_start): convert int
+to pointer (and vice versa) thru word type to suppress warnings.
+* win32_threads.c (GC_mark_mutex_waitcnt): Fix comment, always
+access atomically.
+* misc.c: Change GC_THREADS tests back to THREADS.
+
+* allchblk.c (GC_print_hblkfreelist, GC_dump_regions): Convert
+a group of printf() calls into a single one (for output atomicity).
+* include/gc.h (GC_set_all_interior_pointers, GC_set_full_freq,
+GC_set_time_limit): New prototypes.
+* misc.c (GC_set_all_interior_pointers, GC_set_full_freq,
+GC_set_time_limit): New public setter/getter functions.
+* include/gc.h: Fix (and remove outdated) comments for thread-local
+allocation.
+* include/gc.h: Fix typos in comments.
+* misc.c (GC_init_inner, GC_printf): Likewise.
+* include/gc.h (GC_unregister_disappearing_link): Refine comment.
+* include/gc.h (GC_stack_base): Recognize _M_IA64 macro.
+* misc.c (GC_stack_last_cleared, GC_min_sp, GC_high_water,
+GC_bytes_allocd_at_reset, DEGRADE_RATE): Define only if THREADS.
+* misc.c (GC_stack_last_cleared, GC_min_sp, GC_high_water,
+GC_bytes_allocd_at_reset): Define as STATIC.
+* misc.c (GC_get_heap_size, GC_get_free_bytes,
+GC_get_bytes_since_gc, GC_get_total_bytes): Acquire the GC lock to
+avoid data races.
+* misc.c (GC_write_cs): Define only if THREADS (Win32/WinCE only).
+* misc.c (GC_init_inner): Initialize GC_write_cs only if THREADS.
+* misc.c (GC_init_inner): Use GC_INITIAL_HEAP_SIZE (if available) to
+set the default initial value of initial_heap_sz.
+* misc.c (GC_deinit): Destroy GC_write_cs only if THREADS.
+* misc.c (GC_init_inner): Fix WARN() format specifier (should be
+word-compliant, "%p" is used w/o "0x").
+* misc.c (GC_init_inner): Don't recognize "GC_PAUSE_TIME_TARGET"
+environment variable if SMALL_CONFIG.
+* misc.c (GC_init_inner): Recognize "GC_FULL_FREQUENCY" environment
+variable to set initial GC_full_freq value (if not SMALL_CONFIG).
+* doc/README.environment (GC_FULL_FREQUENCY): Add information.
+* doc/README.environment (GC_MARKERS): Refine information.
+* misc.c (GC_init_inner): Change GC_ASSERT to GC_STATIC_ASSERT where
+possible.
+* misc.c (IF_NEED_TO_LOCK): New macro (instead of GC_need_to_lock).
+* misc.c (GC_write): Use IF_NEED_TO_LOCK for handling GC_write_cs.
+* misc.c (GC_abort): Don't define if SMALL_CONFIG.
+* misc.c (GC_abort): Directly use WRITE() instead of GC_err_printf()
+(to prevent possible infinite recursion).
+
+* finalize.c (finalization_mark_proc): Replace K&R-style declaration
+with ANSI C one.
+* finalize.c (GC_grow_table, GC_register_finalizer_inner,
+GC_enqueue_all_finalizers): Remove outdated comments about disabling
+signals.
+* finalize.c (GC_general_register_disappearing_link): Fix assertion
+to catch NULL "obj" value.
+* finalize.c (GC_unregister_disappearing_link): Check "link"
+alignment before gaining the lock.
+* finalize.c (GC_finalize): Refine comment.
+* finalize.c (GC_finalize): Fix WARN() format specifier (should be
+word-compliant, "%p" is used w/o "0x").
+* finalize.c (GC_invoke_finalizers): Initialize "bytes_freed_before"
+variable (to 0) to suppress compiler warning.
+* include/gc_gcj.h (MARK_DESCR_OFFSET): Move to private/gc_pmark.h.
+* include/gc_gcj.h: add "extern C" header and tail.
+* include/private/gc_pmark.h: Remove GC_do_parallel_mark(),
+GC_help_wanted, GC_helper_count, GC_active_count declarations (move
+the comments to the place where these symbols are defined in mark.c).
+* mark.c: Add STATIC GC_do_parallel_mark() declaration (for use by
+GC_mark_some_inner, if PARALLEL_MARK only).
+* mark.c (GC_mark_some_inner, GC_help_wanted, GC_helper_count,
+GC_active_count, GC_do_parallel_mark): Define as STATIC.
+* pthread_support.c (GC_mark_thread): Likewise.
+* typd_mlc.c (GC_explicit_typing_initialized, GC_explicit_kind,
+GC_array_kind, GC_ext_descriptors, GC_ed_size, GC_avail_descr,
+GC_typed_mark_proc_index, GC_array_mark_proc_index, GC_eobjfreelist,
+GC_arobjfreelist): Likewise.
+* include/private/gc_pmark.h (PUSH_CONTENTS_HDR): Change GC_ASSERT
+for HBLKSIZE to GC_STATIC_ASSERT.
+* mark.c (GC_noop): Define for Borland C the same as for Watcom.
+* mark.c (GC_noop, GC_mark_and_push): Add ARGSUSED tag.
+* pthread_support.c (GC_do_blocking_inner): Likewise.
+* mark.c (GC_mark_from): Initialize "limit" (to 0) in the default
+switch branch to suppress compiler warning.
+* mark.c (GC_return_mark_stack): Append new-line to printf message.
+* mark.c: Remove unused GC_true_func(), GC_PUSH_ALL().
+* pthread_support.c (GC_mark_thread): Add dummy "return 0" to
+suppress compiler warning.
+* pthread_support.c (start_mark_threads): Move the code limiting
+"GC_markers" value (and printing a warning) to GC_thr_init().
+* pthread_support.c (GC_thr_init): Silently limit "GC_markers" value
+if based on the number of CPUs.
+* pthread_support.c (GC_thr_init): Treat incorrect "GC_markers"
+values as one.
+* pthread_support.c (GC_register_my_thread_inner): Add a check for
+"stack_end" is non-NULL (the same as in win32_threads.c).
+* pthread_support.c (pthread_create): Call GC_oom_fn before giving up
+with ENOMEM.
+* thread_local_alloc.c (return_single_freelist): Convert "for" loop
+to "while" one to suppress "possible extraneous ';'" warning.
+
+* darwin_stop_world.c (GC_push_all_stacks): Recognize ARM32.
+* include/private/gc_priv.h (GC_THREAD_STATE_T): Define for ARM32
+(Darwin only).
+* include/private/gcconfig.h: Add machine-specific part for DARWIN.
+* include/private/gcconfig.h (ARM32): Define config parameters for
+DARWIN (iPhone).
+
+* alloc.c (GC_FULL_FREQ, GC_DONT_EXPAND, GC_FREE_SPACE_DIVISOR,
+GC_TIME_LIMIT): New macros (used to control the default initial
+values of GC_full_freq variable, GC_dont_expand,
+GC_free_space_divisor, GC_time_limit respectively).
+* include/private/gc_priv.h (TIME_LIMIT): Remove macro (replaced
+with GC_TIME_LIMIT in alloc.c).
+* alloc.c (GC_need_full_gc, GC_stopped_mark, GC_finish_collection):
+Define as STATIC.
+* mark_rts.c (GC_push_current_stack, GC_push_gc_structures): Likewise.
+* include/private/gc_priv.h (GC_stopped_mark, GC_finish_collection):
+Move the prototypes to alloc.c, make STATIC.
+* include/private/gc_priv.h (GC_push_current_stack,
+GC_push_gc_structures, GC_push_regs_and_stack): Remove prototypes
+(move the comments to the places where these functions are defined).
+* mach_dep.c (GC_push_regs_and_stack): Move to mark_rts.c and define
+as STATIC.
+* alloc.c (GC_timeout_stop_func, GC_stopped_mark,
+GC_print_heap_sects): Convert a group of printf() calls into
+a single one (for output atomicity).
+* mark_rts.c (GC_print_static_roots): Likewise.
+* alloc.c (GC_stopped_mark): Output blank line (when logging) for
+convenience to delimit collections.
+* alloc.c (GC_clear_a_few_frames): Rename NWORDS to CLEAR_NWORDS;
+make "frames" local variable volatile (to prevent optimization).
+* alloc.c (GC_try_to_collect_inner, GC_stopped_mark,
+GC_finish_collection, GC_allocobj): Remove outdated comments about
+disabling signals.
+* include/private/gc_priv.h (GC_register_displacement_inner,
+GC_gcollect_inner): Likewise.
+* alloc.c (GC_try_to_collect_inner, GC_stopped_mark,
+GC_finish_collection): Initialize "start_time" local variable (to 0)
+to suppress compiler warning.
+* mark_rts.c (GC_add_roots_inner): Likewise.
+* alloc.c (GC_RATE, MAX_PRIOR_ATTEMPTS): Guard with "ifndef".
+* include/private/gc_priv.h (clock, GC_stop_world, GC_start_world,
+GC_acquire_mark_lock, GC_release_mark_lock, GC_notify_all_builder,
+GC_wait_for_reclaim, GC_notify_all_marker, GC_wait_marker): Replace
+K&R-style function prototypes with ANSI C one.
+* include/private/gc_priv.h (ABORT): Define as DebugBreak() for
+Win32/WinCE if SMALL_CONFIG (the same as in GC_abort()).
+* include/private/gc_priv.h (ROUNDED_UP_WORDS, abs): Remove unused
+macros.
+* include/private/gc_priv.h (GC_noop): Declare for Borland C the
+same as for Watcom.
+* mark_rts.c (GC_push_conditional_with_exclusions): Add ARGSUSED tag.
+
+* dbg_mlc.c (GC_store_debug_info, GC_store_debug_info_inner): Remove
+outdated comment about disabling signals.
+* mallocx.c (GC_malloc_uncollectable,
+GC_malloc_atomic_uncollectable): Likewise.
+* os_dep.c: Likewise.
+* dbg_mlc.c (GC_debug_change_stubborn, GC_debug_end_stubborn_change):
+Add ARGSUSED tag.
+* pthread_stop_world.c (GC_suspend_handler,
+GC_suspend_handler_inner): Likewise.
+* dbg_mlc.c (GC_debug_free, GC_debug_realloc): Fix printf message.
+* dbg_mlc.c (GC_debug_realloc): Set "result" to NULL in the default
+switch branch to suppress compiler warning.
+* dyn_load.c (GC_init_dyld): Use ABORT() instead of GC_abort().
+* include/private/darwin_semaphore.h (sem_init): Likewise.
+* include/javaxfc.h: Replace "GC_H" with "_GC_H".
+* include/private/dbg_mlc.h (GC_has_other_debug_info,
+GC_store_debug_info): Replace K&R-style function prototypes with ANSI
+C one.
+* include/private/gcconfig.h (GC_FreeBSDGetDataStart, real_malloc,
+GC_win32_get_mem, GC_wince_get_mem, GC_unix_get_mem): Likewise.
+* include/private/pthread_support.h (GC_stop_init): Likewise.
+* include/private/gcconfig.h: Refine comment about setting
+GC_stackbottom.
+* include/private/gcconfig.h (FIXUP_POINTER): Put parentheses in the
+"right" places.
+* include/private/pthread_support.h (GC_Thread_Rep): Refine comment
+for "stack_end" field.
+* mallocx.c (GC_malloc_uncollectable,
+GC_malloc_atomic_uncollectable): Remove cast to undefined "hbklk".
+* os_dep.c (GC_USE_MEM_TOP_DOWN): New macro (for setting
+GC_mem_top_down to MEM_TOP_DOWN for debug purposes).
+* os_dep.c (GC_gww_read_dirty, catch_exception_raise): Fix WARN()
+format specifier (should be word-compliant, "%p" is used w/o "0x").
+* pthread_stop_world.c (GC_suspend_handler_inner): Likewise.
+* os_dep.c (GC_dirty_init): Append new-line to printf messages.
+* os_dep.c (GC_mprotect_thread): Fix GC_err_printf message.
+* os_dep.c (GC_save_callers): Change GC_ASSERT to GC_STATIC_ASSERT.
+* pthread_stop_world.c (GC_retry_signals, GC_suspend_ack_sem): Define
+as STATIC.
+* pthread_stop_world.c (GC_push_all_stacks): Add assertion for that
+"thread_blocked" is not set for the current thread.
+* real_malloc.c: Add "extern GC_quiet" to suppress compiler warning.
+* reclaim.c (GC_reclaim_all): Initialize "start_time" (to 0) to
+suppress compiler warning.
+
+* tests/test.c (check_heap_stats): Avoid unbalanced brackets in ifdef.
+
+* win32_threads.c: restructure parallel marking mutex initialization.
+* win32_threads.c, alloc.c, darwin_stop_world.c, mallocx.c, mark.c,
+pthread_stop_world.c, pthread_support.c: Add runtime conditions
+on GC_parallel were appropriate.
+* pthread_support.c: Condition marker_bsp on ia64.
+(GC_segment_is_thread_stack): Fix loop upper bound.
+* reclaim.c: Limit some assertions to PARALLEL_MARK.
+* pthread_support.c: Don't acquire mark lock for thread-local
+allocation.
+* include/private/gc_priv.h: Don't define parallel mark sync
+support just for THREAD_LOCAL_ALLOC.
+
+* include/private/gcconfig.h: refine MINGW32 test.
+* mark.c: Add win64/gcc tests.
+
+* test.c (fork_a_thread, reverse_test, alloc8bytes, tree_test,
+typed_test, run_one_test, check_heap_stats, main, test): Replace
+all K&R-style function definitions with ANSI C ones.
+* trace_test.c (main): Likewise.
+* test.c (GC_COND_INIT): Define as GC_INIT() also in case of
+THREAD_LOCAL_ALLOC.
+* test.c (reverse_test): Call fork_a_thread() only if GC_PTHREADS
+or GC_WIN32_THREADS; remove fork_a_thread() macros definition.
+* test.c (reverse_test): Use "volatile" when clearing "b" and "c"
+local variables (to suppress "assigned value is never used"
+compiler warning).
+* test.c (tree_test): Use public GC_noop1() instead of private
+GC_noop().
+* test.c (typed_test): Likewise.
+* test.c (check_heap_stats): Define and assign value to
+"late_finalize_count" local variable only if its value is used
+(if FINALIZE_ON_DEMAND defined).
+* test.c (main): Remove DJGPP-specific initialization of
+GC_stackbottom (not needed anymore, handled in gcconfig.h).
+* trace_test.c: Guard #define GC_DEBUG with #ifndef.
+* trace_test.c: Include "gc_backptr.h".
+* trace_test.c (main): Call GC_INIT().
+* trace_test.c (main): Add "return 0" statement.
+
+* dyn_load.c (GC_register_dynlib_callback): Use new index j
+instead of i in the inner loop.
+
+* tests/test.c: Increment n_tests with fetch_and_add when possible,
+avoiding need to export lock.
+
+* include/gc_pthread_redirects.h:
+- dlfcn.h is included for dlopen() proto before undefining
+"dlopen" (so, it's possible now to include dlfcn.h after
+gc.h from user code);
+- GC_dlopen() proto is added (except for Darwin as
+it's missing there);
+- "dlopen" is explicitly undefined (before its redefinition).
+* include/gc.h:
+- "process.h" is included besides "windows.h"
+(for _beginthreadex/_endthreadex); win32 only.
+- GC_NO_THREAD_DECLS is moved to the right place
+(before closing "extern C").
+* pthread_support.c: Fix out of memory handling for Thread_Reps.
+* win32_threads.c: Don't include process.h on winCE,
+improve out of memory handling for thread structures, don't
+define GC_beginthreadex and GC_endthreadex for winCE.
+
+* tests/test.c: Change gcj vtable decriptor type from size_t to
+GC_word.
+
+* gcj_mlc.c: Add comment.
+* tests/test.c: Change NTEST to NTHREADS. Fork 5 threads by default.
+Run reverse_test a second time in each thread.Add comments.
+Don't rely on AO_fetch_and_add.
+
+* dyn_load.c (GC_register_dynlib_callback,
+GC_register_dynamic_libraries_dl_iterate_phdr): Add support
+for GNU_PT_RELRO relocations.
+
+* Makefile, Makefile.direct: GC_SOLARIS_PTHREADS was replaced
+by GC_SOLARIS_THREADS.
+* include/gc.h: Improve finalizer documentation.
+* mips_sgi_mach_dep.s: Replace _MIPS_SIM_ABI32 with _ABIO32.
+* pthread_stop_world.c, Makefile.dj: Fix typos.
+
+* win32_threads.c (GC_new_thread): Make first_thread
+visible to the whole file.
+(UNPROTECT): New macro.
+(GC_push_stack_for, GC_suspend, GC_start_world): unprotect
+thread structures before writing.
+(GC_suspend): Acquire GC_fault_handler_lock before suspending
+thread.
+* os_dep.c: export GC_fault_handler_lock.
+(GC_remove_protection): Check if already unprotected.
+
+* doc/README.win32: Add OpenWatcom warning.
+* include/private/gcconfig.h: Really check it in.
+
+* os_dep.c (GC_get_stack_base, windows): Replace with Dave Korn's
+code from gcc version.
+* os_dep.c: make gc compilable (optionally) for Cygwin with
+GetWriteWatch-based virtual dirty bit implementation ("os_dep.c" file).
+* os_dep.c: Make non-win32 GC_write_fault_handler STATIC.
+* mark.c (GC_noop): fix declaration definition mismatch for DMC.
+* include/private/gcconfig.h: Enable MPROTECT_VDB and GWW_VDB for
+Watcom (Win32 only). It works.
+
+* mach_dep.c: Don't use __builtin_unwind_init for register
+state on PowerPC/Darwin.
+
+* doc/gcdescr.html: Improve description of object freelist
+structure.
+* include/private/gc_priv.h: Fix comment for _size_map.
+
+* os_dep.c (GC_linux_stack_base): Relax sanity test.
+
+* include/private/gc_pmark.h (PUSH_CONTENTS_HDR for
+MARK_BIT_PER_OBJ): Add missing backslash before eoln.
+
+* misc.c (GC_set_warn_proc): Implicitly intialize GC on
+non-Cygwin win32.
+
+* configure.ac: Enable thread-local allocation for sparc-linux.
+
+* alloc.c (GC_try_to_collect): Remove duplicate initialization
+check.
+* malloc.c (GC_generic_malloc): Remove lw to eliminate single-
+threaded warnings.
+* mallocx.c (GC_generic_malloc_ignore_off_page): Likewise.
+
+* allchblk.c, backgraph.c, dbg_mlc.c, dyn_load.c,
+finalize.c, include/private/gc_pmark.h, malloc.c, mark.c,
+os_dep.c, pthread_stop_world.c, pthread_support.c, reclaim.c,
+thread_local_alloc.c.
+* misc.c: Refine comment.
+
+* os_dep.c: Define GC_GWW_BUF_LEN more intelligently. Add FIXME
+comment.
+
+* win32_threads.c (GC_push_stack_for): Yet another attempt
+at the stack_min finding logic. Try to clean up the existing code
+while minimizing VirtualQuery calls.
+(GC_win32_start_inner): Register thread before GC_printf.
+Produce more output with DEBUG_THREADS.
+*include/gc.h: Update obsolete comments.
+
+* tests/test.c:
+(gcj_class_struct2): Use cast instead of l suffix.
+Cast GetLastError to int in various places.
+Avoid unused result warning from incr/decr macros.
+Add cast for fake_gcj_mark_proc.
+Cast GC_gc_no to unsigned in printf.
+
+* include/gc.h: Fix two typos in comments.
+
+* finalize.c: Fix typo in comment.
+
+* blacklst.c (GC_print_source_pointer): Don't call GC_print_heap_obj
+with lock.
+
+* reclaim.c: (GC_reclaim_block): Scan even nearly full blocks
+if we are checking for leaks.
+
+* win32_threads.c: Remove mark lock spinning.
+* win32_threads.c, pthread_support.c: Update GC_unlocked_count,
+GC_spin_count, and GC_block_count using atomic operations.
+* tests/test.c: Declare n_tests as AO_t only if we have threads.
+
+* win32_threads.c: Support PARALLEL_MARK. Make printf arg
+types agree with format specifiers.
+Add STATIC for GC_threads.
+* include/private/gcconfig.h: Add FIXME comment.
+* tests/test.c (run_ine_test): Replace LOCK/UNLOCK use with
+AO_fetch_and_add1_full. Declare n_tests as AO_t.
+(WinMain): Don't call GC_use_DllMain.
+with PARALLEL_MARK or THREAD_LOCAL_ALLOC.
+
+* alloc.c (GC_try_to_collect_inner): Don't print redundant
+GC_bytes_allocd and GC_gc_no.
+(GC_stopped_mark): Print average world stop time.
+* include/private/gc_priv.h (MS_TIME_DIFF): Add cast.
+
+* misc.c, doc/README.environment: Add support for
+GC_FREE_SPACE_DIVISOR and GC-disable-incremental.
+* include/gc.h: Make GC_set_free_space_divisor correspond to
+(somewhat unfortunate) reality.
+
+(Mostly improves LLP64 support.)
+* backgraph.c, checksums.c, dbg_mlc.c, finalize.c, mark.c,
+misc.c, reclaim.c: Changed some int and long type to word or size_t
+(and vice versa where appropriate)
+* gcj_mlc.c, include/private/dbg_mlc.h, include/private/gcconfig.h,
+include/private/thread_local_alloc.h, mark.c,
+misc.c, thread_local_alloc.c, win32_threads.c: Added intermediate
+casts to word type when casting from int to pointer (or pointer
+to int, or data pointer to code pointer) - just to remove the
+corresponding compiler warning.
+* ptr_chck.c (GC_is_visible): cast int const to word type to
+prevent left shift overflow.
+* os_dep.c: change the type of GC_mem_top_down global variable
+(containing a flag) to DWORD.
+* include/gc_config_macros.h: define GC_SOLARIS_THREADS if GC_THREADS
+is defined on SunOS x86_64.
+* misc.c (GC_init_size_map): Ifdef out GC_ASSERT as a workaround
+for VC++ 2008 amd64 (v15.00.21022.08 for x64) compiler bug
+(the compiler gets hung if invoked with -Ox -D
+ALL_INTERIOR_POINTERS -D GC_ASSERTIONS)
+* backgraph.c: cast GC_gc_no value to unsigned short when
+assigned/compared to height_gc_no field of back_edges.
+* os_dep.c (GC_remove_protection): Add ARGSUSED.
+* win32_threads.c (GC_thread_exit_proc): Remove unused local
+variable.
+* mark.c (GC_check_dirty): Move declaration out of func body.
+
+* doc/gcinterface.html: Improve REDIRECT_MALLOC documentation.
+* include/gc.h (GC_register_my_thread): Improve comment.
+
+* Makefile.direct: Add comment for -DCHECKSUMS.
+
+* thread_local_alloc.c, include/private/thread_local_alloc.h:
+Fix typos in comments.
+* finalize.c: Declare mark_procs and GC_register_finalizer_inner
+STATIC.
+* malloc.c (GC_free): Move size calculation below assertion.
+
+* win32_threads.c (GC_get_stack_min, GC_may_be_in_stack):
+Add one entry VirtualQuery cache, I_HOLD_LOCK assertions.
+(GC_push_stack_for, GC_get_next_stack) : Hopefully fix WINCE support.
+
+* finalize.c (GC_general_register_disappearing_link): Add
+assertion.
+* malloc.c (GC_generic_malloc): Round lb to granules, not words.
+* mallocx.c (GC_generic_malloc_ignore_off_page): Round lb to
+granules, not words.
+
+* mach_dep.c (NO_GETCONTEXT): Define for sparc linux.
+* configure.ac: Define mach_dep for sparc-linux.
+
+* mark_rts.c (GC_approx_sp): Use volatile to avoid common
+warning.
+
+* dyn_load.c (GC_cond_add_roots): Fix GC_get_next_stack argument
+order.
+
+* alloc.c, dbg_mlc.c, dyn_load.c, finalize.c, gcj_mlc.c,
+include/gc.h, include/gc_config_macros.h, include/gc_cpp.h,
+include/gc_gcj.h, include/gc_mark.h, include/gc_typed.h,
+include/javaxfc.h, include/private/gc_locks.h,
+include/private/gc_priv.h, malloc.c, mallocx.c, mark.c, mark_rts.c,
+misc.c, obj_map.c, os_dep.c, pthread_support.c, ptr_chck.c,
+stubborn.c, tests/test.c, thread_local_alloc.c, typd_mlc.c
+win32_threads.c: Add GC_CALL and GC_CALLBACK macro invocations.
+* test.c: Remove some old K&R code.
+
+* win32_threads.c (GC_may_be_in_stack): New. (GC_Thread_Rep):
+Add last_stack_min. (GC_push_stack_for): Use last_stack_min.
+(GC_get_next_stack): Add limit argument, use_last_stack_min.
+(GC_suspend): make stack_base assignment conditional.
+* dyn_load.c (win32 GC_cod_add_roots): Pass limit to
+GC_get_next_stack.
+* configure_atomic_ops.sh: Remove.
+* build_atomic_ops.sh, build_atomic_ops.sh.cygwin, doc/README.win32,
+Makefile.direct: Partially support build directories whose path
+name contains blanks.
+* Makefile.am: Support new files (build_atomic_ops.sh,
+build_atomic_ops.sh.cygwin)
+
+* include/private/gc_locks.h, include/private/gc_pmark.h,
+include/private/gc_priv.h, include/private/gcconfig.h,
+mach_dep.c, mark_rts.c, misc.c, os_dep.c, pthread_stop_world.c,
+pthread_support.c, thread_local_alloc.c, typd_mlc.c, win32_threads.c:
+Fix comments.
+
+* pthread_support.c: Comment out LOCK_STATS.
+* include/gc.h: Fix comments.
+
+* misc.c (GC_init_inner): Enable GC_LOG_FILE on Cygwin.
+* include/private/gcconfig.h: Consider USE_MMAP for Cygwin.
+* os_dep.c (GC_get_main_stack_base): Use alternate definition
+with USE_MMAP.
+* include/private/gc_priv.h: Sometimes define SETJMP on Cygwin.
+
+* doc/README: Make it clearer when Makefile.direct is assumed.
+* cord/cord.am: install include/cord.h.
+
+* win32_threads.c (GC_pthread_join, GC_pthread_start_inner):
+Remove unused variables.
+* darwin_stop_world.c: Always declare GC_thr_init().
+* dbg_mlc.c (GC_debug_free_inner): Don't touch oh_sz if
+SHORT_DBG_HDRS is defined.
+* include/private/gc_pmark.h (OR_WORD_EXIT_IF_SET, parallel
+mark, USE_MARK_BITS version): Refer to correct parameter name.
+
+* finalize.c (GC_general_register_disappearing_link): Remove
+redundant code.
+* gcj_mlc.c (GC_init_gcj_malloc): Add cast to signed.
+* os_dep.c: (GC_write_fault_handler): Remove remaining
+references to deleted variable "code". Remove redundant
+FREEBSD definitions.
+* include/private/gcconfig.h (GWW_VDB): Define for X86_64 when
+defined for X86. (STATIC): Define as "static" with NO_DEBUGGING.
+
+* include/private/gc_priv.h: Update MAX_HEAP_SECTS.
+
+* dbg_mlc.c (GC_print_smashed_obj): Increase robustness with
+smashed string, (GC_debug_free_inner): Mark as free.
+* mallocx.c (GC_malloc_many): Always clear new block if
+GC_debugging_started.
+* reclaim.c: Move GC_debugging_started from
+GC_reclaim_small_nonempty_block() to GC_reclaim_generic(),
+which is also called directly.
+* doc/README: Fix spelling error. Update license summary.
+* include/gc.h (GC_PRE_INCR3, GC_POST_INCR3): add (void **) casts.
+* tests/test.c: Don't define GC_DEBUG if already defined.
+
+* doc/simple_example.html: update --enable-full-debug reference,
+Make HTML formatting standards compliant.
+* doc/debugging.html, doc/leak.html: Fix HTML formatting bugs.
+* doc/gcinterface.html: specify encoding.
+
+* doc/simple_example.html: Update thread-local allocation
+description.
+
+* configure.ac: Check for gc-debug earlier; replace remaining
+full-debug tests.
+* include/gc.h, ptr_chck.c (GC_pre_incr, GC_post_incr):
+Use signed offset type. Use ptr_t internally.
+* doc/gcinterface.html: Update LOCAL_MALLOC description.
+* doc/README.autoconf, doc/leak.html, doc/README.DGUX386:
+Fix full-debug reference.
+* include/gc.h: Rewrite GC_..._INCR and friends.
+* tests/test.c: Minimally test GC_..._INCR and friends.
+
+* mark.c: (GC_push_next_marked, GC_push_next_marked_dirty,
+GC_push_next_marked_uncollectable): Never invoke GC_push_marked
+on free hblk.
+* headers.c: Test COUNT_HDR_CACHE_HITS not USE_HDR_CACHE.
+(GC_header_cache_miss): Always blacklist pointers for free
+hblks. Add assertion and comment.
+* pthread_support.c (GC_register_my_thread): Fix #if indentation.
+* include/private/gc_hdrs.h: USE_HDR_CACHE is no longer tested.
+Delete it.
+* include/private/gc_pmark.h: (PUSH_OBJ): Add assertion.
+
+* alloc.c, include/gc_mark.h, Makefile.direct: Improve comments.
+
+* configure.ac: Set win32_threads on MinGW.
+
+Ivan's description of the patch follows. Note that a few pieces like
+the GC_malloc(0) patch, were not applied since an alternate had been
+previously applied. A few differed stylistically from the rest of
+the code (mostly casts to void * instead of target type),
+or were classified as too minor to bother. Note that
+all of Ivan's static declarations which did not correct outright
+naming bugs (as a few did), where replaced by STATIC, which is
+ignored by default.
+
+- minor bug fixing (for FreeBSD, for THREAD_LOCAL_ALLOC and for
+GC_malloc(0));
+- addition of missing getter/setter functions for public variables
+(may be useful if compiled as Win32 DLL);
+- addition of missing GC_API for some exported functions;
+- addition of missing "static" declarator for internal functions
+and variables (where possible);
+- replacement of all remaining K&R-style definitions with ANSI
+C ones (__STDC__ macro is not used anymore);
+- addition of some Win32 macro definitions (that may be missing in
+the standard headers supplied with a compiler) for GWW_VDB mode;
+- elimination of most compiler warnings (except for
+"uninitialized data" warning);
+- several typos correction;
+- missing parenthesis addition in macros in some header files of
+"libatomic_ops" module.
+
+My highlights based on reading the patch:
+
+* allchblk.c: Remove GC_freehblk_ptr decl.
+Make free_list_index_of() static.
+* include/gc.h: Use __int64 on win64, define GC_oom_func,
+GC_finalizer_notifier_proc, GC_finalizer_notifier_proc,
+add getter and setters: GC_get_gc_no, GC_get_parallel,
+GC_set_oom_fn, GC_set_finalize_on_demand,
+GC_set_java_finalization, GC_set_dont_expand,
+GC_set_no_dls, GC_set_max_retries, GC_set_dont_precollect,
+GC_set_finalizer_notifier. Always define GC_win32_free_heap.
+gc_config_macros.h: Define _REENTRANT after processing
+GC_THREADS.
+* include/gc_cpp.h: Improve GC_PLACEMENT_DELETE test,
+handling of operator new[] for old Windows compilers.
+* include/gc_inline.h (GC_MALLOC_FAST_GRANS): Add parentheses
+around arguments.
+* dbg_mlc.c, malloc.c, misc.c: Add many GC_API specs.
+* mark.c (GC_mark_and_push_stack): Fix source argument for
+blacklist printing.
+* misc.c: Fix log file naming based on environment variable
+for Windows. Make GC_set_warn_proc and GC_set_free_space_divisor
+just return current value with 0 argument. Add DONT_USE_USER32_DLL.
+Add various getters and setters as in gc.h.
+* os_dep.c: Remove no longer used GC_disable/enable_signals
+implementations. (GC_get_stack_base): Add pthread_attr_destroy
+call. No longer set GC_old_bus_handler in DARWIN workaround.
+* pthread_support.c: GC_register_my_thread must also
+call GC_init_thread_local.
+
+* Makefile.direct, mach_dep.c: Add support for NO_GETCONTEXT.
+* mach_dep.c: Include signal.h.
+* gc_priv.h: Factor out INLINE declaration.
+
+* include/private/gcconfig.h: Update MIPS/LINUX config.
+* doc/gcdescr.html: Fix typo.
+* mach_dep.c (GC_with_callee_saves_pushed): Don't rely on getcontext
+for MIPS/LINUX.
+
+* configure.ac: SPARC fixes.
+* thread_local_alloc.c(GC_mark_thread_local_fls_for): Include
+size 0, except for gcj.
+* doc/gc.man: Expand C++ cautions.
+* include/gc_inline.h: Fix comments.
+
+
+== [7.1] 2008-05-03 ==
+
+* doc/gcinterface.html: Improve C++ interface documentation.
+
+* allchblk.c (GC_allochblk): Check for overflow during size
+rounding.
+* tests/huge_test.c: New.
+* Makefile.direct, tests/tests.am: Add huge_test.c
+
+* pthread_support.c: Fix typo in comment.
+* os_dep.c (GC_win32_get_mem): Add heap section only if
+allocation succeeded.
+
+* malloc.c: (free replacement) Fix caller address space check.
+
+* finalize.c (GC_grow_table): Dereference table in null-check.
+
+* 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.
+
+* tests/test.c (run_one_test): Don't mention pthread_self().
+* misc.c: Declare GC_thr_init().
+
+* allchblk.c (add_to_fl): disable assertions with USE_MUNMAP,
+and refine assertions to handle huge unmergable blocks.
+(GC_allochblk_nth): Add comment.
+
+* include/private/gcconfig.h: Add missing FREEBSD macro
+consistency test.
+
+* 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.
+
+* windows-untested/gc.def: Remove CreateThread line.
+* windows-untested/README: New file.
+* win32_threads.c (GC_use_DllMain): Force collector initialization.
+* 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.
+
+* doc/README.win32: Fix typo.
+* configure.ac: Fix printing of enable-shared result.
+
+* 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.
+
+* include/private/gc_priv.h, mark_rts.c, typd_mlc.c:
+Add GC_push_typed_structures() to push GC_ext_descriptors.
+
+* tests/test.c: Call GC_INIT for DARWIN; test system type using
+gcconfig.h-defined macros.
+
+* 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.
+
+* mark.c (GC_push_next_marked): correct comment.
+* Makefile.direct: document NO_PROC_STAT.
+* include/private/gcconfig.h: Accomodate NO_PROC_STAT.
+
+
+== [7.1alpha2] 2008-01-10 ==
+
+* Makefile.am: Mention atomic_ops.c and atomic_ops_sysdeps.S
+again. Refer to build directory as ".".
+
+* configure.ac: Ignore --enable-parallel-mark on Darwin for now.
+* darwin_stop_world.c: Add FIXME comment for parallel marker.
+
+* include/private/gc_priv.h: Update MAX_ROOT_SETS
+and LOG_PHT_ENTRIES to handle larger heaps.
+
+* include/gc.h (GC_INIT,GC_init): Update comments.
+
+* 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.
+
+* alloc.c (GC_add_to_heap): Call GC_install_header(p) AFTER
+adjusting p.
+
+* Makefile.am: Add NT_X64_THREADS_MAKEFILE.
+
+* 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.
+
+* 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.
+
+* configure.ac: Put libatomic_ops links in build directory.
+* Makefile.am: Don't mention atomic_ops.c and atomic_ops_sysdeps.S
+as nodist sources.
+
+* include/gc.h, doc/README.macros: Add GC_NO_THREAD_REDIRECTS,
+GC_NO_THREAD_DECLS, don't test explicitly for GC_SOLARIS_THREADS.
+
+* 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.
+
+* include/gc_inline.h, include/gc_tiny_fl.h: cleanups to make usable
+in other contexts.
+
+* include/gc.h: Don't define GC_HAVE_BUILTIN_BACKTRACE for uclibc.
+
+* gc_cpp.cc: Don't include gc_cpp.h from local directory.
+
+* allchblk.c, configure.ac (add --enable-munmap)
+
+* 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).
+
+* 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.
+
+* malloc.c: Update GC_large_allocd_bytes on explicit deallocation.
+* allchblk.c: Sanity check GC_max_large_allocd_bytes.
+
+* Makefile.direct: Invoke $(MAKE) instead of make.
+
+* doc/scale.html: Reflect gc7 thread local allocation behavior.
+
+* include/extra/gc.h, include/extra/gc_cpp.h: New.
+* include/include.am: Install gc.h and gc_cpp.h in $(prefix)/include
+again.
+
+* pthread_support.c (GC_thr_init): Use sysconf(_SC_NPROCESSORS_ONLN)
+for HURD.
+
+* include/private/gcconfig.h: Add Linux/mips-64 support.
+
+* 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.
+
+* 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.
+
+* 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.
+
+* Makefile.direct: Remove comment fragment.
+* tests/tests.am: Add smashtest.
+* configure.ac: Define GC_USE_DLOPEN_WRAP with redirect-malloc.
+* 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.
+
+* 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.
+
+* include/gc.h: Define uintptr_t explicitly for VC++6.
+* msvc_dbg.c (GetModuleBase): Revert to strcat if strcat_s doesn't
+exist.
+
+
+== [7.0] 2007-07-02 ==
+
+* include/gc_config_macros.h: Also check for IA64 when setting
+GC_HPUX_THREADS.
+* mallocx.c: Change my_bytes_allocd to signed_word.
+* include/gc_pthread_redirects.h: Remove obsolete Solaris threads
+(as opposed to pthreads) support.
+
+* mach_dep.c (GC_with_callee_saves_pushed): Don't use getcontext()
+on ARM/Linux. Check getcontext() return value.
+
+* backgraph.c (per_object_func): Make argument types consistent.
+(GC_traverse_back_graph): Mark GC_deepest_obj.
+
+* finalize.c (GC_finalize): Change dl_size and fo_size to size_t.
+* os_dep.c (GC_win32_get_mem): Add GC_mem_top_down option.
+
+* doc/README.win32, doc/README, README.QUICK: Fix some of the worst
+anachronisms.
+* dyn_load.c: Partially support cygwin, but don't enable it yet.
+
+* Makefile.am: Use -no-undefined for libgc.
+* Makefile.direct: Document USE_PROC_FOR_LIBRARIES.
+* dyn_load.c (GC_register_map_entries): Rename prot_buf to prot
+consistently.
+* misc.c: Fix some WARN calls. Move GC_is_initialized setting and
+GC_thr_init() call.
+* os_dep.c: Consistently use WARN where appropriate.
+* thread_local_alloc.c: Revert change to GC_WIN32_THREADS test. Instead
+remove inappropriate pthread.h include.
+* doc/README.linux: Remove some anachronisms.
+
+* alloc.c: Also use GC_check_tls on non-Linux systems.
+* mallocx.c (GC_reclaim_generic): Remove bogus declaration.
+* include/private/gc_priv.h (GC_reclaim_generic): Declare correctly
+with prototype.
+
+* alloc.c (GC_adj_bytes_allocd): Avoid (long) casts, fix comment.
+(GC_print_heap_sects): Use size_t instead of unsigned long.
+* thread_local_alloc.c (GC_lookup_thread): Define in the correct
+context.
+* win32_threads.c, include/gc_config_macros.h: The last of Romano
+Paolo Tenca's patch. Move stdint.h include to gc_config_macros.h.
+* include/gc_inline.h: Avoid gc_priv.h dependencies.
+* tests/test.c (check_heap_stats): Replace unsigned long with size_t.
+
+* NT_X64_STATIC_THREADS_MAKEFILE: Replace obsolete -debugtype:cv.
+* mark_rts.c (GC_push_roots): Fix kind type.
+
+* doc/README.win64: New file.
+* doc/doc.am, Makefile.direct: Add README.win64.
+
+* Makefile.am, Makefile.direct: Add NT_X64_STATIC_THREADS_MAKEFILE.
+* NT_X64_STATIC_THREADS_MAKEFILE: Fix warning flags.
+* allochblk.c, alloc.c, blacklst.c, dbg_mlc.c, dyn_load.c,
+finalize.c, headers.c, mach_dep.c, malloc.c, mark.c, misc.c,
+obj_map.c, os_dep.c, ptr_chck.c, reclaim.c, typd_mlc.c,
+win32_threads.c, cord/de_win.c, include/gc_mark.h,
+include/private/gc_hdrs.h, include/private/gc_pmark.h,
+include/private/gc_priv.h, tests/test_cpp.cc:
+Replace old style function declarations. Clean up integral types.
+Remove register declarations. The change in malloc.c and the
+"int descr" declaration in mark.c are the most likely to have
+been real bugs outside of win64.
+* msvc_dbg.c: Disable on win64.
+* win32_threads.c: Add AMD64 support.
+* include/gc.h: no backtrace on AMD64 for now.
+
+* msvc_dbg.c(GetModuleBase): Replace strcat with strcat_s.
+
+* include/gc.h: (GC_word, GC_signed_word): Fix win64 definitions.
+Don't include windows.h in an extern "C" context.
+* include/private/gcconfig.h: Fix win64/X86_64 configuration.
+* tests/test.c: Eliminate more old style function definitions.
+Cleanup pointer and integer casts for win64.
+* tests/test_cpp.cc: Don't include gc_priv.h.
+* NT_STATIC_THREADS_MAKEFILE: Restrict suffixes for VC++ 2005.
+* NT_X64_STATIC_THREADS_MAKEFILE: New.
+
+* win32_threads.c: Separate out DEBUG_WIN32_PTHREADS_STACK. Ignore
+FINISHED threads for suspension. (GC_pthread_join): Add
+pthread_self() cast. (GC_pthread_start_inner): Execute cleanup
+handler when popping it.
+* include/private/gc_locks.h: Inline THREAD_EQUAL for
+GC_WIN32_PTHREADS. Define USE_PTHREAD_LOCKS only if we have
+pthreads.
+
+* gc_dlopen.c, thread_local_alloc.c, threadlibs.c, win32_threads.c,
+tests/test.c: Accomodate GC_WIN32_PTHREADS.
+* include/gc.h: Don't include windows.h for GC_WIN32_PTHREADS.
+* include/gc_config_macros.h: Define both PTHREADS and
+GC_WIN32_THREADS.
+* include/private/gc_locks.h: Nonstandard definitions of
+NUMERIC_THREAD_ID for GC_WIN32_PTHREADS.
+* doc/README.win32, Makefile.direct: Include documentation
+for GC_WIN32_PTHREADS.
+* Makefile.direct: Remove some anachronisms in the documentation.
+
+* Makefile.am: Move includes to bottom. Add better library
+dependencies. Increment library version. Remove "SUBDIRS += .".
+* cord/cord.am, tests/tests.am: Add better library dependencies.
+Remove now unnecessary dependencies.
+* include/gc.h (GC_beginthreadex, GC_endthreadex, GC_ExitThread):
+Move to define on all Windows platforms. (_beginthread): define
+to generate error if used.
+
+* include/private/gc_locks.h: Format to 80 columns.
+
+* malloc.c(GC_free): Ignore bad frees on MSWIN32 with REDIRECT_MALLOC.
+* NT_MAKEFILE: msvc_dbg.h is in include/private. Don't use cvars
+rc.
+* misc.c (WIN32 GC_write): Define GC_need_to_lock in single-threaded
+case.
+* win32_threads.c: Test for __MINGW32__ in addition to _MINGW_VER.
+(GC_CreateThread, GC_beginthreadex): Deallocate args even if we fail.
+* include/gc.h: Add GC_reachable_here(). (GC_WinMain): Add GC_API.
+(GC_beginthreadex, GC_endthreadex, GC_ExitThread): Declare.
+* tests/test.c: Add GC_reachable_here() call.
+
+* alloc.c (GC_try_to_collect): Call GC_init if necessary.
+* tests/thread_leak_test.c: Don't unconditionally define
+GC_LINUX_THREADS.
+
+* Makefile.am: Remove extra_ldflags_libgc definition.
+
+* include/private/gc_priv.h: Define AO_REQUIRE_CAS.
+
+* finalize.c (GC_unreachable_finalize_mark_proc): Don't return void
+value.
+
+
+== [7.0alpha9] 2007-05-15 ==
+
+* Some gc6.9 changes.
+* Change FindTopOfStack decl in darwin_stop_world.c.
+* Move some static tests from misc.c to gcconfig.h. Use #error.
+* Add GC_print_free_list() function.
+* Add GC_GNU_THREADS support on HURD.
+* __GNUC__ was misspelled as __GNUC in thread_local_alloc.h.
+* Integrated various MacOSX patches and tried to reconcile them.
+* Added some casts to powerpc.h in libatomic_ops to silence warnings.
+
+* Makefile.am: Include NT_STSTIC_THREADS_MAKEFILE in dist.
+* include/private/gc_locks.h: GC_compare_and_exchange, GC_atomic_add:
+remove. NUMERIC_THREAD_ID, THREAD_EQUAL: New. GC_lock_holder: now
+unsigned long. I_DONT_HOLD_LOCK, I_HOLD_LOCK: Update.
+* pthread_stop_world.c, pthread_support.c, win32_threads.c: Use
+NUMERIC_THREAD_ID, THREAD_EQUAL.
+* include/private/gcconfig.h: GENERIC_COMPARE_AND_SWAP: Remove.
+* include/private/thread_local_alloc.h: Don't USE_COMPILER_TLS on
+ARM.
+
+* dbg_mlc.c, include/gc.h, finalize.c: Merge Alexandre Oliva's
+GC_debug_register_finalizer_unreachable() patch from gcc tree.
+* thread_local_alloc.c (GC_malloc, GC_malloc_atomic): Add assertions
+to check GC has been initialized.
+
+* include/gc_cpp.h: Documentation updates.
+* include/gc_config_macros.h: Don't check for __ppc__ to set
+DARWIN_THREADS.
+* Makefile.am: Include configure_atomic_ops.sh in dist.
+
+* Makefile.am: Don't distribute copied atomic_ops files. Include
+libatomic_ops with "make dist".
+* configure.ac: Enable THREAD_LOCAL_ALLOC for Cygwin with threads.
+* win32_threads.c: Report error for Cygwin + GC_DLL.
+
+* Makefile.direct: Update THREAD_LOCAL_ALLOC documentation.
+* cord/de_win.c: Rename and move AboutBox. Call GC_INIT. Remove
+MakeProcInstance anachronism.
+* doc/README.macros: Officially remove elif prohibition.
+Remove documentation for defunct SRC_M3 support.
+* include/gc.h: Remove more SRC_M3 references.
+* include/private/gcconfig.h: Remove still more SRC_M3 references.
+GC_SOLARIS_THREADS no longer needs to be checked separately.
+
+* thread_local_alloc.c, include/private/thread_local_alloc.h:
+Spell __declspec correctly.
+* NT_STATIC_THREADS_MAKEFILE: Enable thread-local allocation.
+
+* doc/README.win32: Adjust GC_win32_dll_threads rules again.
+
+* mark.c (GC_mark_some wrapper): Restructure for readability, handle
+GC_started_thread_while_stopped.
+* misc.c (Win32 GC_write): Lock GC_write_cs only if needed.
+* win32_threads.c: (client_has_run): remove,
+GC_started_thread_while_stopped, GC_attached_thread: add.
+(GC_push_all_stacks): Add verbose output.
+(DllMain): Avoid initializing collector or the like.
+Never update both thread tables.
+* doc/README.win32: Adjust GC_win32_dll_threads rules.
+
+* pthread_stop_world.c (GC_push_all_stacks): Print thread count with
+GC_PRINT_VERBOSE_STATS.
+
+* configure.ac: Comment out redundant
+AC_DEFINE(NO_EXECUTE_PERMISSION).
+* sparc_mach_dep.S: Remove single quote in comment.
+* include/private/gcconfig.h: Fix DATAEND for NONSTOP.
+* win32_threads.c: Include stdint.h for Mingw. Add GC_API for DllMain.
+(GC_use_DllMain): Fix assertion.
+
+* configure.ac: Introduce extra_ldflags_libgc. Use it for Darwin.
+* Makefile.am (libgc_la_LDFLAGS): Use extra_ldflags_libgc.
+* include/private/gcconfig.h: Enable MPROTECT_VDB for all Darwin
+targets. Remove comments.
+Prepare ppc64 support for Darwin.
+
+* darwin_stop_world.c (GC_push_all_stacks): Fix compiler warnings.
+Make i unsigned.
+(GC_stop_world): Likewise. Remove unused GC_thread p.
+(GC_start_world): Likewise.
+
+* os_dep.c: Define GC_darwin_register_mach_handler_thread extern.
+Remove double SIG_HNDLR_PTR definition.
+(GC_forward_exception): Fix compiler warnings, make i unsigned.
+Initialize thread_state to NULL.
+(catch_exception_raise): Fix compiler warnings, make i unsigned.
+
+* include/private/gc_priv.h (NEED_FIND_LIMIT, FREEBSD variant):
+also define for X86_64.
+* configure.ac: Move generic gnu (Hurd) case to below kfreebsd case.
+* README.changes: Point to ChangeLog.
+
+* darwin_stop_world.c: Move THREAD_FLD defines to ...
+* include/private/gc_priv.h: ... here.
+Fix THREAD_STATE definitions for ppc64.
+* os_dep.c (catch_exception_raise): Use THREAD_FLD for exc_state member
+access.
+
+* configure.ac (i586-darwin): Replaced HAS_I386_THREAD_STATE_* with
+HAS_X86_THREAD_STATE32_*.
+(x86_64-*-darwin*): Extended the above check for x86_64-*-darwin* with
+HAS_X86_THREAD_STATE64_*.
+Added value 1 in the above AC_DEFINE's. Important for the upcoming
+Leopard.
+* include/private/gcconfig.h: Modified X86_64 define for Darwin.
+Removed __x86_64__ check in POWERPC section. Added base definitions
+for the X86_64 Darwin port.
+* include/private/gc_priv.h: Added GC_MACH_HEADER and GC_MACH_SECTION
+to distinguish between 32 and 64-bit applications. Added definitions
+for X86_64 Darwin.
+* darwin_stop_world.c: Added HAS_X86_THREAD_STATE64___RAX. And
+replaced HAS_I386_THREAD_STATE___EAX with HAS_X86_THREAD_STATE32___EAX.
+(GC_push_all_stacks): Added code for X86_64 Darwin. Even for the
+!DARWIN_DONT_PARSE_STACK. Maybe obsolete.
+* dyn_load.c (GC_dyld_name_for_hdr): Use GC_MACH_HEADER.
+(GC_dyld_image_add): Use GC_MACH_HEADER and GC_MACH_SECTION.
+Distinguish between getsectbynamefromheader_64 and
+getsectbynamefromheader.
+* os_dep.c (catch_exception_raise): Introduce exception definition for
+X86_64 Darwin. Replaced old i386_EXCEPTION_STATE_* definition with
+x86_EXCEPTION_STATE32_*. Add X86_64 for exc_state.faultvaddr.
+
+
+== [7.0alpha7] 2006-09-19 ==
+
+* More 6.7 changes.
+* Declare GC_dump() in gc.h.
+* Add --enable-large-config, which just defines the LARGE_CONFIG macro.
+* Make GlobalAlloc address alignment a bit more intuitive.
+* Use #elif in the definitions of GET_MEM.
+* Overhaul porting.html. Remove corresponding text from README.
+* Fix typo in DARWIN section of gcconfig.h.
+* Fix Darwin thread memory leak.
+* Update x86 AO_test_and_set implementation to use "=q".
+* Add $(EXEEXT) to many tests in tests/tests.am. (Corresponds to a
+6.7 fix, which no longer applied.)
+* Fix Darwin/PPC port.
+* Fix Cygwin/threads port.
+* Fix gcj malloc support.
+* For GNU-style make, don't build libatomic_ops unless threads are requested.
+This should allow single-threaded builds on platforms which do not
+currently support libatomic_ops.
+* Clean up and hopefully fix the CFLAGS calculation for GNU build.
+(Substantially improves things on HP/UX.)
+* Integrated Andrei Polushin's Visual C++ patches. These provide for
+stack traces, better C++ debug support, and better log file handling.
+Note that these change the location of the log file to a the path of the
+executable with a .log extension. To get the old behavior back, define
+OLD_WIN32_LOG_FILE. For the time being, I'm checking his project
+files and the like into a windows-untested subdirectory. They
+are almost certainly already out of date, but better than what we had
+before.
+* Fixed some win32 threads bugs, and added support for _beginthreadex.
+* Fix zero size thread local allocation so that explicit deallocation
+works correctly.
+* Removed serious bug in GC_malloc_uncollectable(large size).
+* Do not try to do thread-local gcj allocation in incremental mode. There
+are races in setting up the descriptor.
+* Add GC_INIT() to middle.c, fix some more GC_printfn calls.
+* Some assertions erroneously used I_HOLD_LOCK() negatively, even though
+it can now spuriously return TRUE.
+* Rename SUNOS5 macro and OS name to SOLARIS and SUNOS5DL to SOLARISDL.
+* On Linux and some Un*x variants, allocate memory by first trying sbrk,
+and then switching to mmap if that fails.
+* Fixed /proc/x/maps reading to deal with asynchronous deletions.
+* Fix REDIRECT_MALLOC with threads on Linux. It now usually seems to work
+with ugly hacks that include having calloc behave differently when it is
+called from ld.so or the pthreads library. A reasonable amount of
+infrastructure was added to support some of this.
+* Import various updated build scripts.
+* Add GC_register_has_static_roots_callback.
+* Fix serious bugs in GC_malloc_atomic_uncollectable().
+* Return GC_SUCCESS form GC_get_stack_base().
+* Fix several atomic_ops problems on IA64 with HP Compiler.
+* Update to atomic_ops-1.2.
+* Fix hb_n_marks description and reclaim.c assertion.
+* Various additional win32 threads fixes.
+* Enable GC_ASSERTIONS for Debug build with NT_THREADS_MAKEFILE.
+
+
+== [7.0alpha5] ==
+
+* More 6.6, 6.7 changes.
+* Some Solaris fixes, including some more general changes in how
+the assembly pieces of mach_dep.c are handled.
+* Removed a lot of SOLARIS_THREADS-specific code that was only
+needed with the old implementation. This included many (mostly no-op)
+versions of GC_is_fresh.
+* Don't use atomic_ops in gc_locks.h unless we need threads.
+* Fixed USE_MARK_BITS, which is once again the default without PARALLEL_MARK.
+* Removed Solaris GC_INIT hack. It's a workaround for a long dead bug,
+and it seemed to be wrong anyway.
+* Changed win32_threads.c to require preprocessor-based interception
+of thread routines by default. A client call to GC_use_DllMain is
+now required to get the old behavior in which DllMain is used to implicitly
+register threads. This was done for uniformity with other platforms, and
+because the DllMain solution seemed to require very tricky code which,
+at least in the past, imposed hard bounds on the number of threads.
+* Many small changes to make thread support work again on Cygwin.
+* Moved definition of allocator lock etc. to pthread_support.c and
+win32_threads.c for those two cases.
+* Got rid of the FASTLOCK() machinery. It doesn't seem useful on modern
+platforms.
+* Cleaned up the uncollectable allocation routines, speeding up the
+slower paths. The code did enough unnecessary work off the critical path
+that the underlying logic was getting hard to extract.
+* No longer turn off THREAD_LOCAL_ALLOC with DBG_HDRS_ALL. Indications
+are it just works, and I think the reasons for it not working disappeared
+a while ago.
+* Fixed bugs in hb_n_marks calculation and assertion.
+* Don't use __builtin_expect for pre-3.0 gcc.
+* Define GWW_VDB only for recent Microsoft tool chains.
+* Add overview.html to doc directory.
+* Fix NT_STATIC_THREADS_MAKEFILE, various compiler warnings.
+* Made thread local allocation sort of work with Cygwin. The code should
+be there to deal with other Windows variants, But non-Cygwin Windows
+threads need more bug fixes.
+
+
+== [7.0alpha4] ==
+
+* Various 6.5, 6.6 changes.
+* Removed GC_brief_async_signal_safe_sleep and used atomic_ops instead.
+* Integrated build patches from David Angelocola and Petter Urkedal.
+* Fix dynamic-linker-based pthread call redirection.
+* Renamed RS6000 to POWERPC/AIX.
+* Allow recovery from SIGSEGV in marker on Linux. This works around
+a race in thread stack marking if /proc is used to find roots. We do
+that by default with malloc redirection and threads. This involved
+moving some GC_find_limit and SETJMP related declarations to gc_priv.h.
+* Added doc/porting.html file.
+* Added ADD_HEAP_GUARD_PAGES for sbrk/*nix platforms to debug extreme
+memory overwrite errors.
+* Added trivial NO_INCREMENTAL flag to facilitate debugging.
+* Added GC_getattr_np-based GC_get_stack_base (untested).
+* Separated thread local allocation into a separate file and added the
+beginning of win32 support for that.
+
+
+== [7.0alpha3] ==
+
+* Added support for dlopen-based interception of pthread functions.
+This is only half done. The gc.h redefinitions currently interfere.
+* Integrated major automake overhaul from Petter Urkedal.
+
+
+== [7.0alpha2] ==
+
+* GC_bytes_allocd was incremented by a possibly uninitialized variable
+in GC_generic_malloc_inner. (Bug introduced in gc7.0alpha1.)
+* Win32 fixes.
+* Integrated Ben Hutchings' GetWriteWatch-based virtual dirty bit
+implementation for win32.
+* Removed pc_gc.tar and floppy targets in Makefile.direct. Removed
+pc_excludes file.
+* No longer include GC_bytes_wasted when evaluating allocation progress.
+Since we are now counting live memory, it no longer makes sense.
+* Applied Davide Angelocola's configure patch. There are now separate
+Makefile.am's in the cord and tests subdirectory, more tests, etc.
+* Renamed configure.in to configure.ac.
+* Merged a very small number of Nathanael Nerode's configure.ac
+cleanups from the gcc tree. Unfortunately, that file is a bit
+different from ours.
+* Changed EINTR handling in sem_wait slightly.
+* Restructure the root marking code. Remove all traces of
+USE_GENERIC_PUSH_REGS, and effectively make it the default.
+Make it easier to pass a context pointer to the mark routine, in
+case we ever want to do precise stack marking.
+* Replace GC_start_blocking() and GC_end_blocking() with GC_do_blocking().
+This remains undocumented, and only implemented for pthreads. But it
+removes an otherwise unavoidable race with stores of callee-save
+registers.
+* Fix GC_n_mark_bits for the default MARK_BIT_PER_GRANULE case. This
+resulted in bogus complaints in heap dumps.
+* Upgrade to libatomic_ops-1.0, and update build structure to match.
+* Remove SRC_M3 support. Clean up lock initialization code in misc.c.
+* Removed gc_local_alloc.h. If THREAD_LOCAL_ALLOC is defined, the
+thread local allocation routines are now called automatically.
+* Renamed gc_inl.h back to gc_inline.h. Changed the interface appreciably
+since locking has turned into a dominant issue, and in-line allocation
+only makes sense if it's no worse than thread-local allocation.
+Gc_inline.h is now also used to implement thread-local allocation.
+* Finished replacing stubborn allocation with manual write barrier.
+Untested.
+* Use thread-local allocation code by default.
+* Added GC_register_my_thread and friends for Posix and win32.
+* Patch for GWW_VDB from Ben Hutchings.
+* Removed explicit THREAD_LOCAL_ALLOC tests, since that now always
+redefines GC_malloc.
+* Removed now unused AIX memory allocation code.
+* Various minor fixes for bugs introduced in 7.0alpha1.
+
+
+== [7.0alpha1] ==
+
+* Remove GC_PROTO, VOLATILE, GC_PTR, and GC_CONST. Assume ANSI C compiler
+and use ANSI constructs unconditionally.
+* Introduce #elif and #error in some of the appropriate places.
+* Remove GC_printf cruft. Use stdargs.
+* Remove separate Solaris threads support. Use the more generic Posix
+implementation.
+* Use atomic_ops for atomic operations and memory barriers.
+* Clean up MPROTECT_VDB implementation. Use SA_SIGINFO wherever
+possible.
+* Remove broken SIGNALS stuff.
+* Use size_t instead of word, where appropriate.
+* Add .S.o rule to Makefile.am.
+* Officially discontinue SunOS4, several old flavors of M68K (SunOS4,
+A/UX, HP), IBM PC/RTs and RISCOS/Irix4. (I doubt the old code worked.
+If anyone cares, these should be easy to resurrect.)
+* Add EXPECT() in some critical places.
+* Redefined hb_sz and hb_body to deal with bytes rather than words.
+This affected a great deal of code. I would like to consistently use
+byte offsets and sizes where there's not a convincing reason to do
+otherwise.
+* Redefined several other variables (GC_mem_found, GC_words_allocd)
+etc. to use units of bytes. Most of these were also renamed to
+reflect that fact.
+* Killed as many "register" declarations as possible.
+* Partially replaced stubborn allocation with manual write barrier.
+It's currently broken.
+* Restructured mark code, to allow mark bits to be kept either on
+a per allocation granule or per object basis. The emphasis is
+now on the -DUSE_MARK_BYTES option, since individual bits perform
+quite badly on hyper-threaded P4s, and are probably suboptimal on
+other architectures. -DUSE_MARK_BITS is currently broken, and may
+be resurrected only for the single-threaded case. This significantly
+reduced the cache footprint required by auxiliary GC data structures.
+It also reduces space overhead for small heaps. It probably slows
+things down slightly if interior pointers are very common.
+* As part of the above, we now maintain an approximate count of set
+mark bits in each heap block.
+* As part of the above, the semantics of hb_map changed drastically.
+For MARK_BIT_PER_OBJ, it doesn't exist. For MARK_BIT_PER_GRANULE,
+it is purely a way to replace a mod instruction with a table lookup.
+(Somewhat to my surprise, this still wins on modern hardware.)
+* Removed PRINTSTATS, GATHERSTATS, and SILENT macros. Everything is
+now controlled by GC_print_stats variable and GC_PRINT_STATS
+and new GC_PRINT_VERBOSE_STATS environment variables.
+* Add GC_log_printf and use it consistently for logging output.
+* Unconditionally count the objects we reclaim in the sweep phase.
+For thread local allocation, we need that anyway, and we expect
+that's increasingly the only case that matters. And it simplifies
+the code. In general expect minor performance hacks that benefit
+only the single-threaded case to disappear.
+* Remove GC_quiet from gc.h and elsewhere.
+* Changed the heap expansion heuristic, and the definition of
+GC_free_space_divisor, to refer to live data size, instead of total
+heap size. I believe this is much more robust. It wasn't previously
+possible, because we didn't have access to live data size.
+* Thread local allocation added the extra byte in twice: Once in
+thread_local_alloc, and once in malloc_many.
+* Removed GC_malloc_words_small and GC_gcj_fast_malloc. A new
+mechanism based on the thread local allocation data structures
+is expected to be added instead. This should allow inlined code
+that is both fast and doesn't rely on collector internals.
+* Changed both free lists and reclaim lists to be indexed by granules
+instead of words, norming halving their size.
+* MERGE_SIZE is now the only option, and the macro was removed.
+(Without it, we need a memory reference to GC_all_interior_pointers
+anyway. Thus it costs us nothing.)
+* Change GC_size_map to map to granules instead of words. Make sure
+that every possible size up to TINY_FREELISTS is present.
+* Split of macros need for fast inline allocation into gc_tiny_fl.h
+in anticipation of a new inline allocator that doesn't rely on GC
+internals.
+* Changed thread local allocation to use GRANULE_BYTES and TINY_FREELISTS
+in anticipation of a merge with the inline allocation code.
+* Removed ALIGN_DOUBLE. This is mostly handled by GRANULE_BYTES.
+* Make locking on most platforms conditional on GC_need_to_lock.
+
+
+== [6.9] ==
+
+* Fix typo in PREFETCH implementation for X86_64.
+* Fix M68K LINUX port.
+* __GNUC__ was misspelled as __GNUC in new_gc_alloc.h.
+* Integrated Allan Hsu's patch for OS X VM deallocation problems.
+* Applied FreeBSD/X86_64 patch.
+
+
+== [6.8] ==
+
+* Added some support for Dragonfly BSD.
+* Improvements to the HP/UX section of configure.in/configure.ac.
+* GC_unix_get_mem could neglect to release the malloc lock on Irix, under
+extremely unlikely circumstances.
+* Added support for kFreeBSD + glibc
+* Fix more MacOS threads memory leaks
+* Added initial Solaris/X86-64 support
+
+
+== [6.7] ==
+
+* Add "int" to Solaris "end" and "etext" declaration in gc.h. Declared
+the symbols with underscores and as arrays, since that's what's actually
+used. Perhaps this could all just be removed.
+* Fixed ARM GC_test_and_set code.
+* Added casts for assignments to hb_last_reclaimed, which truncate the
+value. Added a cast to GC_adj_words_allocd. Use GetModuleHandleA
+when retrieving a handle to kernel32.dll under win32.
+* Added Tandem S-Series support.
+* Remove spurious gc:: qualifier for operator delete[] in gc_cpp.h.
+* Changed a test for LINUX in config_macros.h to one for __linux__.
+* Add prototypes for GC_finalizer_notifier and GC_thr_init.
+* Use ld instead of nonexistent ldz instruction in Darwin FindTopOfStack.
+* Add support for Darwin/X86.
+* Merge in some recent gcc fixes. Add ppc64 asm code.
+* Scan MEM_PRIVATE sections under Windows ME and predecessors.
+* Interior pointers with some largish offsets into large objects could
+be ignored, if GC_all_interior_pointers was set. (Oddly this worked
+correctly for stack references if it was not set. Otherwise it failed
+for both stack and heap references.)
+* Integrated Tatsuya Bizenn's NETBSD threads support, with some
+untested changes.
+* Added GC_strdup and friends to make leak detection work correctly
+for strdup clients. Fixed the existing strdup
+with malloc redirection to handle a null malloc return correctly.
+
+
+== [6.6] ==
+
+* Fix CPU count detection for Irix and FreeBSD.
+* Integrate Dan Bonachea's patch for the IBM XLC compiler on Darwin.
+* Integrated Andreas Tobler's FreeBSD/PowerPC patch.
+* Don't access the GC thread structure from the restart handler. It's
+unsafe, since the handler may run too late.
+* Applied Christian Thalinger's patch to change comment syntax in
+alpha_mach_dep.S.
+* Added test for GC_no_dls in GC_dyld_image_add for DARWIN.
+* Use LINUX_STACKBOTTOM for Linux/SH and LINUX/ARM.
+* Rewrote GC_parse_map_entry. This assumed a fixed column layout of
+/proc/self/maps on Linux. This ceased to be true about 2 years ago.
+The old code is probably quite problematic with -DREDIRECT_MALLOC. It
+is also used by default for IA64, though I haven't seen actual failures
+there.
+* More consistently define HBLKSIZE to 4096 on 64 bit architectures with
+4K pages.
+* With win32 threads, GC_stop_world needs to acquire GC_write_cs.
+* Move up struct callinfo declaration to make gcc 4.0.2. happy.
+
+
+== [6.5] ==
+
+* Integrated Paolo Molaro's patch to deal with EINTR in sem_wait.
+* Make GC_approx_sp() write to dummy location to ensure that stack
+is grown here, when sp looks reasonable, rather than later, when
+it might look like a bad memory reference. (Problem was never
+observed that I know of. But on rereading the code it seemed
+dubious.)
+* Separate out GC_with_callee_saves_pushed and sometimes call
+it from GC_suspend_handler in pthread_stop_world.c. Callee-save
+register values sometimes failed to get traced under HP/UX on
+PA-RISC. Linux/IA64 had the same problem, though non-stacked
+callee-save registers seem to be so rarely used there that nobody
+ever noticed.
+* Integrated an ancient Darwin powerpc_darwin_machine_dep.s patch
+from Andreas Tobler, which I had lost.
+* Fix compare_and_exchange implementation for gcc/IA64 to deal with
+pickier compiler versions.
+* Fixed Itanium 32-bit ABI support (HP/UX). In particular, the
+compare_and_exchange implementation didn't consider that possibility.
+* Undefine GC_pthread_detach in win32_threads.c.
+* Fixed inclusion of frame.h for NETBSD in os_dep.c.
+* Applied Dan Bonachea's patch to use mmap on AIX.
+* Several fixes to resurrect the Irix port on recent OS versions.
+* Change ALPHA to use LINUX_STACKBOTTOM.
+* Change SPARC64/LINUX to also use LINUX_STACKBOTTOM. Deal with potential
+bad values of __libc_stack_end on that platform.
+* Relax gctest to allow larger heap if ALIGN_DOUBLE isn't set.
+(Unnecessary in 7.0)
+* Force a define of __STDC__=0 for the IBM compiler on AIX, so that
+we get prototypes. (Unnecessary in 7.0)
+* GC_INIT definition for AIX and CYGWIN referred to DATASTART and DATAEND
+which are only defined in private include files.
+* Integrated some small gcconfig.h patches from Dan Bonachea. Also
+relaxed assertion about FreeBSD stack size in pthread_support.c.
+* Integrated Andrew Begel's darwin_stop_world.c patch for 64-bit
+support. This may need additional work.
+* Avoided potentially infinite recursion in GC_save_callers if
+the system backtrace calls malloc. The workaround currently requires
+__thread support if this code is used with threads.
+* Avoided another similar infinite recursion by conditionally
+invoking GC_save_callers in alloc.c.
+* Removed all traces of aix_irix_threads.c. AIX and Irix now use
+pthread_support.c and pthread_stop_world.c. The old code appeared
+to be unreliable for AIX, and was not regularly maintained.
+* On Irix, ignore segments with MA_FETCHOP or MA_NOTCACHED attributed;
+they're not always safe to read.
+* Fixed a previously vacuous assertion (diagnosed by the SGI compiler)
+in GC_remove_from_fl.
+* Fix stack_size assertion in GC_pthread_create.
+* Fix assertion in GC_steal_mark_stack.
+
+
+== [6.4] ==
+
+* Merge gcconfig.h changes from gcc tree.
+* Unconditionally include gc_priv.h in solaris_pthreads.c, win32_threads.h,
+aix_irix_threads.c, and solaris_threads.c to get thread definitions.
+* Start marker threads in GC_thr_init, so that they get started even
+if no other threads are ever started. (Oddly enough, the parallel
+collector worked correctly, though not well, with no helper threads.)
+* Go ahead and split large blocks in GC_allochblk_nth if GC_dont_gc
+is set.
+* GC_PRINT_BACK_HEIGHT would deadlock with thread support.
+* Let in_progress_space in backgraph.s grow dynamically.
+* Fix README.solaris2. The GC_thr_init() hack doesn't work anymore.
+* Convert GC_finalizer_mem_freed to bytes in allchblk.c.
+* Add missing declaration for GC_generic_malloc_words_small_inner.
+Without it, s390x breaks.
+* Applied several MacOSX patches to support older tool chains.
+* Bug fix for NetBSD/amd64. Add NetBSD/sh3 support.
+* Fixed an uninitialized variable in cordprnt.c.
+* Eliminated some, but not all, gcc -Wall warnings.
+* Changed some old style casts to reinterpret_cast in new_gc_alloc.h.
+* GC_extend_size_map shouldn't adjust for GC_all_interior_pointers if
+GC_DONT_ADD_BYTE_AT_END is set.
+* Changed some (long) casts to (word) in preparation for win64.
+* Changed "int stack_size" declaration in pthread_support.c to use
+size_t. (Only mattered with GC_ASSERTIONS enabled.)
+* Added CRIS (etrax) support.
+* Removed GC_IGNORE_FB frame buffer recognition, and replaced
+it with a check that the mapping type is MEM_IMAGE.
+In theory, this should work much better, but it is a high
+risk change for win32.
+* GC_allochblk_nth incremented GC_words_wasted by bytes rather than
+words.
+* Consider GC_words_wasted in GC_adj_words_allocd only if it is within
+reason. (A hack to avoid some extremely unlikely scenarios in which
+we manage to allocate only "wasted" space. 7.0 has a better fix.)
+* Changed PowerPC GC_clear implementation to use lwsync instead of
+eieio, since the documentation recommends against eieio, and
+it seems to be incorrect if the preceding memory op is a load.
+* Fixed print_block_list to print the correct kind number for
+STUBBORN.
+* Have configure.in generate an error if it is asked to support
+pthreads, but doesn't know how to.
+* Added Kazuhiro Inaoka's patch for Renesas M32R support.
+* Have the GNU build mechanism link with -ldl. Rename THREADLIBS
+to THREADDLLIBS to reflect this.
+* Added Hannes Mehnert's patch for FreeBSD/SPARC support.
+* Merged some FreeBSD specific patches to threadlibs.c and dyn_load.c.
+* Define MPROTECT_VDB on MACOSX only if threads are being used, since the
+dirty page tracking mechanism uses threads. (This avoids an undefined
+reference to _GC_darwin_register_mach_handler_thread.)
+* By popular demand, use __libc symbols only if we are built with
+USE_LIBC_PRIVATES, which is off by default, and not otherwise documented.
+* Ignore GC_enable_incremental() requests when KEEP_BACK_PTRS is set.
+The GC itself will dirty lots of pages in this cases, probably making
+it counterproductive on all platforms. And the DARWIN port crashes.
+
+
+== [6.3] ==
+
+* Compile test_cpp.cc with CXXCOMPILE instead of COMPILE.
+* Very large allocations could cause a collector hang. Correct
+calculation of GC_collect_at_heapsize.
+* GC_print_hblkfreelist printed some bogus results if USE_MUNMAP
+was defined.
+* Include gc_config_macros.h in threadlibs.c.
+* Correct MacOSX thread stop code.
+* SMALL_OBJ definition was off by one. This could cause crashes
+at startup.
+* Integrate Paolo Molara's patch to deal with a race in the Darwin
+thread stopping code.
+* Changed X86_64 implementation to use SA_SIGINFO in the MPROTECT_VDB
+implementation. The old approach appears to have been broken by
+recent kernels.
+* Added GC_ATTR_UNUSED to eliminate a warning in gc_allocator.h.
+* Fix GC_task_self declaration in os_dep.c.
+* Increase INITIAL_BUF_SZ in os_dep.c for Solaris /proc reads.
+
+
+== [6.3alpha6] ==
+
+* Define USE_GENERIC_PUSH_REGS for NetBSD/M68K.
+* Fixed the X86_64 PREFETCH macros to correctly handle ia32e (which uses
+different prefetch instructions from AMD64).
+* GC_config_macros.h did not correctly define GC_WIN32_THREADS from
+GC_THREADS.
+* Added simple_example.html.
+* Merged Andrew Gray's patch to correctly restore signal handlers on
+FreeBSD.
+* Merged a patch from Andreas Jaeger to deal with prefetch-related warnings
+on x86-64. Added some other casts so that the PREFETCH macros
+always get a ptr_t argument. Removed some casts in the PREFETCH
+implementations.
+* Added a header guard for gc_allocator.h
+and changed GC_debug_free to clobber contents of deallocated object.
+* The signal masking code in pthread_stop_world.c contained some errors.
+In particular SIGSEGV was masked in the handler, in spite of the fact that
+it wrote to the heap. This could lead to an uncaught SIGSEGV, which
+apparently became much more likely in Linux 2.6. Also fixed some
+typos, and reduced code duplication in the same area.
+* Remove ltconfig, clean up configure messages for DGUX.
+* Integrated NetBSD/OpenBSD patches from Marc Recht and Matthias Drochner.
+
+
+== [6.3alpha5] ==
+
+* Fix & vs && typo in GC_generic_malloc and
+GC_generic_malloc_ignore_off_page. (Propagated from the gcc tree.)
+* Removed SA_NODEFER hack from NetBSD and Solaris write-protect handler.
+(According to Christian Limpach, the NetBSD problem is fixed.
+Presumably so is the Solaris 2.3 problem.)
+* Removed placement delete from gc_cpp.h for the SGI compiler.
+* Changed semantics of the GC_IGNORE_FB environment variable.
+We still need help in identifying win32
+graphics memory mappings. The current "solution" is a hack.
+* Removed "MAKEOVERRIDES =" from Makefile.am and thus Makefile.in.
+It probably made more sense in the gcc context.
+* Explicitly ensure that NEED_FIND_LIMIT is defined for {Open,Net}BSD/ELF.
+* Replaced USE_HPUX_TLS macro by USE_COMPILER_TLS, since gcc often
+supports the same extension on various platforms.
+* Added some basic (completely untested) defines for win64, in support
+of future work.
+* Declared GC_jmp_buf in os_dep.s as JMP_BUF instead of jmp_buf, fixing
+a memory overwrite bug on Solaris and perhaps other platforms.
+* Added 0 != __libc_stack_end test to GC_linux_stack_base.
+Otherwise pre-linking could cause the collector to fail.
+* Changed default thread local storage implementation to USE_PTHREAD_SPECIFIC
+for HP/UX with gcc. The compiler-based implementation appears to work
+only with the vendor compiler.
+* Export GC_debug_header_size and GC_USR_PTR_FROM_BASE from gc_mark.h,
+making client mark code cleaner and less dependent on GC version.
+* Export several new procedures and GC_generic_malloc from gc_mark.h
+to support user-defined kinds. Use the new procedures to replace existing
+code in gcj_mlc.c and typd_mlc.c.
+* Added support for GC_BACKTRACES.
+* Fixed a remaining problem in CORD_str with signed characters.
+* Removed supposedly redundant, but very buggy, definitions of finalizer
+macros from javaxfc.h. Fortunately this file probably has no users.
+The correct declarations were already in gc.h.
+* Also need to set GC_in_thread_creation while waiting for GC during
+thread termination, since it is also possible to collect from an
+unregistered thread in that case.
+* Define NO_GETENV for Windows CE, since getenv doesn't appear to exist.
+Plus some other minor WinCE fixes.
+* Added GC_register_describe_type_fn.
+* Arrange for debugging finalizer registration to ignore non-heap
+registrations, since the regular version of the routine also behaves
+that way.
+* GC_gcj_malloc and friends need to check for finalizers waiting to be run.
+One of the more obscure allocation routines with missing a LOCK() call.
+* Fixed cvtres invocations in NT_MAKEFILE and NT_STATIC_THREADS_MAKEFILE
+to work with VS.NET.
+* Cleaned up GC_INIT calls in test. Updated gc.man to encourage GC_INIT
+use in portable code.
+* Taught the GC to use libunwind if --enable-full-debug is specified on
+IA64 and libunwind is present.
+* The USE_MUNMAP code could get confused about the age of a block and
+prematurely unmap it. GC_unmap_old had a bug related to wrapping of
+GC_gc_no. GC_freehblk and GC_merge_unmapped didn't maintain
+hb_last_reclaimed reasonably when blocks were merged. The code was
+fixed to reflect original intent, but that may not always be an
+improvement.
+
+
+== [6.3alpha4] ==
+
+* USE_MMAP was broken by confusion in the code dealing with USE_MMAP_ANON.
+* Darwin support was broken in alpha3 as a result of my mis-integration of
+Andrew Begel's patches. Fixed with another patch from Andrew Begel.
+* A new sanity check in pthread_stop_world.c:GC_push_all_stacks() was
+overly aggressive. We may collect from an unregistered thread during
+thread creation. Fixed by explicitly checking for that case. (Added
+GC_in_thread_creation.)
+
+
+== [6.3alpha3] ==
+
+* Removed -DSMALL_CONFIG from BCC_MAKEFILE.
+* Changed macros to test for an ARM processor (Patch from Richard Earnshaw.)
+* Mostly applied a DJGPP patch from Doug Kaufman. Especially Makefile.dj
+had suffered from serious bit rot.
+* Rewrote GC_apply_to_maps, eliminating an off-by-one subscript error,
+and a call to alloca (for lcc compatibility).
+* Changed USE_MUNMAP behavior on POSIX platforms to immediately remap
+the memory with PROT_NONE instead of unmapping it. The latter risks
+an intervening mmap grabbing the address space out from underneath us.
+Updated this code to reflect a cleaner patch from Ulrich Drepper.
+* Replaced _T with _Tp in new_gc_alloc.h to avoid a MACOS X conflict.
+(Patch from Andrew Begel.)
+* Dynamically choose whether or not lock should spin on win32.
+This may be a significant performance improvement for win32.
+* Fix Makefile.direct to actually include NT_STATIC_THREADS_MAKEFILE
+in the distribution.
+* Maybe_install_looping_handler() was accidentally exported, violating
+our name space convention.
+* Made os_dep.c use sigsetjmp and SA_NODEFER for NetBSD.
+* Integrated Andrew Begel's Darwin threads patch, adjusted according to
+some of Fergus Hendersons's comments. (Patch didn't apply cleanly,
+errors are possible.)
+* Added another test or two for the Intel 8.0 compiler to avoid
+confusing it with gcc. The single-threaded collector should now build
+with icc, at least on ia64.
+
+
+== [6.3alpha2] ==
+
+* Re-enabled I_HOLD_LOCK assertion in aix_irix_threads.h.
+* Put back the WINABI qualifier for GC_CreateThread.
+* Sometimes explicitly define __private_extern__ before DARWIN dyld.h
+include.
+* Included signal.h from pthread_support.c. Removed GC_looping_handler,
+which was dead code.
+* GC_find_start was misdeclared by gc_pmark.h if PRINT_BLACK_LIST was
+defined.
+Changed GC_find_start to never just return 0. According to its
+comment it doesn't, and it's unclear that's correct.
+* GC_alloc_large had several largely compensating bugs in the
+computation of GC_words_wasted. (It was confused about bytes vs.
+words in two places.)
+* Integrated Slava Sysoltev's patch to support more recent versions of
+the Intel compiler on IA64/Linux.
+* Changed win32 spinlock initialization to conditionally set a spin count.
+(Emmanual Stumpf pointed out that enabling this makes a large performance
+difference on win32 multiprocessors.) Also cleaned up the win32 spinlock
+initialization code a bit.
+* Fixed thread support for HP/UX/IA64. The register backing store base for
+the main thread was sometimes not set correctly.
+* Added -DEMPTY_GETENV_RESULTS flag to work around Wine problem.
+* Declare GC_stack_alloc and GC_stack_free in solaris_threads.h to
+avoid 64-bit size mismatches.
+* Fixed GC_generic_push_regs to avoid a potential and very unfortunate
+tail call optimization. This could lead to prematurely reclaimed
+objects on configurations that used the generic routine and the new
+build infrastructure (which potentially optimizes mach_dep.c).
+This was a serious bug, but it's unclear whether it has resulted in
+any real failures.
+* Fixed CORD_str to deal with signed characters.
+* Merged a couple of NOSYS/ECOS tests into os_dep.c from gcj.
+* Partially merged a win32 patch from Ben Hutchings, and substantially
+revised other parts of win32_threads.c. It had several problems.
+Under MinGW with a statically linked library, the main thread was
+not registered. Cygwin detached threads leaked thread descriptors.
+There were several race conditions. For now, unfortunately the
+static threads limit remains, though we increased it, and made table
+traversal cost depend on the actual thread count.
+There is also still some code duplication with pthread_support.c.
+(Thread descriptors did become much smaller, since Ben Hutchings
+removed the thread context from them.)
+* Integrated a Solaris configure.in patch from Rainer Orth.
+* Added GC_IGNORE_FB and associated warning to very partially address
+the issue of the collector treating a mapped frame buffer as part
+of the root set.
+
+
+== [6.3alpha1] ==
+
+* Integrated some NetBSD patches forwarded to me by Marc Recht. These
+were already in the NetBSD package.
+* GC_pthread_create waited for the semaphore even if pthread_create failed.
+Applied the analogous fix for aix_irix_threads.c.
+* Added Rainer Orth's Tru64 fixes.
+* The check for exceeding the thread table size in win32 threadDetach
+was incorrect.
+* Applied Andrew Begel's patch to correct some reentrancy issues
+with dynamic loading on Darwin.
+* GC_CreateThread() was neglecting to duplicate the thread handle in
+the table.
+* Pass +ESdbgasm only on PA-RISC machines with vendor compiler.
+* Applied more AIX threads patches from Scott Ananian.
+
+
+== [6.2] ==
+
+* Integrated a second round of Irix/AIX patches from Dan Bonachea.
+Renamed mips_sgi_mach_dep.S back to mips_sgi_mach_dep.s, since it requires
+the Irix assembler to do the C preprocessing; gcc -E doesn't work.
+* Fixed Makefile.direct for DARWIN.
+* There was a race between GC_pthread_detach and thread exit that could
+result in a thread structure being deallocated by GC_pthread_detach
+even though it was still needed by the thread exit code.
+* Fixed version parsing for non-alpha versions in acinclude.m4 and
+version checking in version.h.
+
+
+== [6.2alpha6] ==
+
+* There was an extra underscore in the name of GC_save_registers_in_stack
+for NetBSD/SPARC.
+* Integrated Brian Alliet's patch for Darwin. This restructured the
+linuxthreads/pthreads support to separate generic pthreads support
+from more the system-dependent thread-stopping code. I believe this
+should make it easier to eliminate the code duplication between
+pthreads platforms in the future. The patch included some other
+code cleanups.
+* Integrated Dan Bonachea's patch to support AIX threads. This required
+substantial manual integration, mostly due to conflicts with other
+recent threads changes. It may take another iteration to
+get it to work.
+* Removed HPUX/PA-RISC support from aix_irix_threads.c. It wasn't used
+anyway and it cluttered up the code. And anything we can do to migrate
+towards generic pthreads support is a good thing.
+* Added a more explicit test for tracing of function arguments to test.c.
+* Added Akira Tagoh's PowerPC64 patch.
+* Fixed some bit rot in the Cygwin port.
+gc.h now includes just windows.h, not winbase.h.
+* Declared GC_save_regs_in_stack() in gc_priv.h. Remove other declarations.
+* Changed --enable-cplusplus to use automake consistently. The old way
+confused libtool. "Make install" didn't work correctly for the old version.
+Previously --enable-cplusplus was broken on cygwin.
+* Changed the C version of GC_push_regs to fail at compile time if it is
+generated with an empty body. This seems to have been the cause of one
+or two subtle failures on unusual platforms. Those failures should
+now occur at build time and be easily fixable.
+
+
+== [6.2alpha5] ==
+
+* GC_invoke_finalizers could, under rare conditions, set
+GC_finalizer_mem_freed to an essentially random value. This could
+possibly cause unbounded heap growth for long-running applications
+under some conditions. (The bug was introduced in 6.1alpha5, and
+is not in gcc3.3.)
+* Attempted to sanitize the various DLL macros. GC_USE_DLL disappeared.
+GC_DLL is used instead. All internal tests are now on GC_DLL.
+README.macros is now more precise about the intended meaning.
+* Include DllMain in the multithreaded win32 version only if the
+collector is actually built as a dll.
+* Hide the cygwin threadAttach/Detach functions. They were violating our
+namespace rules.
+* Fixed an assertion in GC_check_heap_proc. Added GC_STATIC_ASSERT.
+* Removed some obsolete definitions for Linux/PowerPC in gcconfig.h.
+* CORD_cat was not rebalancing unbalanced trees in some cases, violating
+a CORD invariant. Also tweaked the re-balancing rule for
+CORD_cat_char_star.
+* Added hand-coded structured exception handling support to mark.c.
+This should enable support of dynamic libraries under win32 with
+gcc-compiled code.
+Turned on dynamic library scanning for win32/gcc.
+* Removed some remnants of read wrapping.
+GC_USE_LD_WRAP ws probably broken in recent versions.
+* The build could fail on some platforms since gcconfig.h could include
+declarations mentioning ptr_t, which was not defined, e.g. when if_mach
+was built. Also
+cleaned up tests for GC_PRIVATE_H in gcconfig.h a bit.
+* The GC_LOOP_ON_ABORT environment variable interfered with incremental
+collection, since the write fault handler was erroneously overridden.
+Handlers are now set up in the correct order.
+* It used to be possible to call GC_mark_thread_local_free_lists() while
+the world was not stopped during an incremental GC. This was not safe.
+Fortunately, it was also unnecessary. Added GC_world_stopped flag
+to avoid it. (This caused occasional crashes in GC_set_fl_marks
+with thread local allocation and incremental GC. This probably happened
+primarily on old, slow multiprocessors.)
+* Allowed overriding of MAX_THREADS in win32_threads.c from the build
+command line.
+* Taught the IA64/linux code to determine the register backing store base from
+/proc/self/maps after checking the __libc symbol, but before guessing.
+(__libc symbols are on the endangered list, and the guess is likely to not
+always be right for 2.6 kernels.) Restructured the code to read and parse
+/proc/self/maps so it only exists in one place (all platforms).
+* The -DUSE_PROC_FOR_LIBRARIES code was broken on Linux. It claimed that it
+also registered the main data segment, but didn't actually do so. (I don't
+think anyone actually uses this configuration, but ...)
+* Made another attempt to get --enablecplusplus to do the right thing.
+Since there are unavoidable problems with C programs linking against a
+dynamic library that includes C++ code, I separated out the c++ code into
+libgccpp.
+
+
+== [6.2alpha4] ==
+
+* Use LINUX_STACKBOTTOM for >= glibc2.2 on Linux/MIPS. (See Debian bug
+# 177204)
+* Integrated Jeff Sturm and Jesse Rosenstock's MACOSX threads patches.
+* Integrated Grzegorz Jakacki's substantial GNU build patch. "Make dist"
+should now work for the GNU build process. Documentation files
+are installed under share/gc.
+* Tweaked gc_cpp.h to again support the Borland compiler.
+* Updated BCC_MAKEFILE.
+* Added GC_ASSERT check for minimum thread stack size.
+* Added --enable-gc-assertions.
+* Added some web documentation to the distribution. Updated it in the
+process.
+* Separate gc_conf_macros.h from gc.h.
+* Added generic GC_THREADS client-defined macro to set the appropriate
+GC_XXX_THREADS internal macro. (gc_config_macros.h.)
+* Add debugging versions of _ignore_off_page allocation primitves.
+* Moved declarations of GC_make_closure and GC_debug_invoke_finalizer
+from gc.h to gc_priv.h.
+* Reset GC_fail_count even if only a small allocation succeeds.
+* Integrated Brian Alliet's patch for dynamic library support on Darwin.
+* gc_cpp.h's gc_cleanup destructor called GC_REGISTER_FINALIZER_IGNORE_SELF
+when it should have called the lower case version, since it was
+explicitly computing a base pointer.
+
+
+== [6.2alpha3] ==
+
+* Don't include execinfo.h in os_dep.c when it's not needed, and may not
+exist.
+
+
+== [6.2alpha2] ==
+
+* Fixed the completely broken FreeBSD code in 6.2alpha1.
+* Changed IRIX reference in dbg_mlc.c to IRIX5.
+* Attempted to work around the problems with .S filenames and the SGI
+compiler. (Untested.)
+* Worked around an HP/UX make issue with the GNU-style build process.
+* Fixed the --enable-cplusplus build machinery to allow builds without
+a C++ compiler. (That was always the intent ...)
+* Changed the debugging allocation macros to explicitly pass the return
+address for Linux and XXXBSD on hardware for which we can't get stack
+traces. Use __builtin_return_address(0) to generate it when possible.
+Some of the configuration work was cleaned up (good) and moved to gc.h
+(bad, but necessary). This should make leak detection more useful
+on a number of platforms.
+* Fixed compilation problems in dbg_mlc.c with GC_ADD_CALLER.
+* Bumped revision number for dynamic library.
+
+
+== [6.2alpha1] ==
+
+* Guard the test for GC_DUMP_REGULARLY in misc.c with
+"#ifndef NO_DEBUGGING". Otherwise it fails to build with NO_DEBUGGING
+defined.
+* Message about retrying suspend signals was incorrectly generated even when
+flag was not set.
+* Cleaned up MACOSX/NEXT root registration code. There was apparently a
+separate ifdef case in GC_register_data_segments() for no reason.
+* Removed MPROTECT_VDB for MACOSX port, based on one negative report.
+* Arrange for gc.h and friends to be correctly installed with GNU-style
+"make install".
+* Enable the GNU-style build facility include C++ support in the library
+with --enable-cplusplus.
+* Mark from GC_thread_key in linux_threads.c, in case that's allocated
+from the garbage collected heap, as it is with our own thread-specific
+storage implementation.
+* Mark all free list header blocks if they are heap allocated. This avoids
+some unnecessary tracing. And it remains correct if we clear the
+root set.
+* Improved S390/Linux support. Add S390/Linux 64-bit support.
+* Corrected the spelling of GC_{M,C}ALLOC_EXPLICTLY_TYPED to
+GC_{M,C}ALLOC_EXPLICITLY_TYPED in gc_typed.h. This is technically
+an interface change. Based on the fact that nobody reported this,
+I suspect/hope there were no clients.
+* Cleaned up gc_typed.h so that (1) it adds an extern "C" declaration
+when appropriate, (2) doesn't generate references to undefined internal
+macros, and (3) allows easier manual construction of descriptors.
+* Close the file descriptor used by GC_print_address_map().
+* Set the "close-on-exec" bit for various file descriptors maintained
+for the collector's internal use.
+* Added a hack to find memory segments owned by the system allocator
+under win32. Based on my tests, this tends to eventually find all
+segments, though it may take a while. There appear to be cleaner,
+but slower solutions under NT/XP. But they rely on an API that's
+unsupported under 9X.
+* Changed Linux PowerPC stack finding to LINUX_STACKBOTTOM.
+* Added GC_set_free_space_divisor to avoid some Windows dll issues.
+* Added FIXUP_POINTER, POINTER_SHIFT, POINTER_MASK to allow preprocessing
+of candidate pointers for tagging, etc.
+* Always lock around GC_notify_full_gc(). Simplified code for
+invoking GC_notify_full_gc().
+* Changed the way DATASTART is defined on FreeBSD to be robust against
+an unmapped page after etext.
+* Made GC_enable() and GC_disable() official. Deprecated direct update
+of GC_dont_gc. Changed GC_gcollect to be a noop when garbage collection
+is disabled.
+* Call GC_register_dynamic_libraries before stopping the world on Linux,
+in order to avoid a potential deadlock due to the dl_iterate_phdr lock.
+* Introduced a more general mechanism for platform-dependent code to
+decide whether the main data segment should be handled separately
+from dynamic libraries, or registered by GC_register_dynamic_libraries.
+The latter is more reliable and easier on Linux with dl_iterate_phdr.
+
+
+== [6.1] ==
+
+* Added GC_MAXIMUM_HEAP_SIZE environment variable.
+* Fix configure.in for MIPS/LINUX.
+* Double page hash table size for -DLARGE_CONFIG.
+* Integrated Bo Thorsen's X86-64 support.
+* STACKBOTTOM definition for LINUX/MIPS was partially changed back.
+* Replaced all occurrences of LINUX_DATA_START in gcconfig.h with
+SEARCH_FOR_DATA_START. It doesn't hurt to falll back to a search.
+And __data_start doesn't seem to get defined correctly of the GC
+library is loaded with LD_PRELOAD, e.g. for leak detection.
+* If the GC_find_leak environment variable is set, do a
+atexit(GC_gcollect) to give us at least one chance to detect leaks.
+This may report some very benign leaks, but ...
+* Addeded REDIRECT_FREE. It's necessary if we want leak detection with
+LD_PRELOAD.
+* Defer printing of leaked objects, as for smashed objects.
+* Fixed process and descriptor leak in GC_print_callers. Try for
+line number even if we got function name.)
+* Ported parallel GC support and thread local allocation to Alpha.
+Not yet well-tested.
+* Added GC_DUMP_REGULARLY and added finalization statistics to GC_dump().
+* Fixed Makefile.am to mention alpha_mach_dep.S instead of the defunct
+alpha_mach_dep.s.
+* Incorporated a change to new_gc_alloc.h,
+which should make it work with gcc3.1.
+* Use alpha_mach_dep.S only on Linux. (It's not clear that this is
+optimal, but it otherwise didn't build on Tru64.)
+* Added ifdef to guard free() in os_dep.c. Otherwise we get a
+compilation error on Irix.
+* Added an experimental version of GC_memalign to mallocx.c. This can't
+always work, since we don't handle alignment requests in the hblk-level
+allocator, and we can't handle arbitrary pointer displacements unless
+GC_all_interior_pointers is enabled. But it should work for alignment
+requests up to HBLKSIZE. This is not yet documented in the standard
+places.
+* Finally debugged the OSF1/Tru64 thread support. This needs more testing,
+since I needed to add a somewhat unconvincing workaround for signal
+delivery issues that I don't yet completely understand. But it does
+pass my tests, even in parallel GC mode. Incremental GC support is
+disabled if thread support is enabled, due to the signal issues.
+* Eliminated name-space-incorrect definition of _cdecl from gc_cpp.h.
+* Added GC_debug_malloc_replacement and GC_debug_realloc_replacement
+declarations to gc.h. On IA64, this is required for REDIRECT_MALLOC
+to work correctly with these.
+* Fixed Linux USE_PROC_FOR_LIBRARIES to work with a 64-bit /proc format.
+
+
+== [6.1alpha5] ==
+
+* Added GC_finalizer_mem_freed, and changed some of the code that
+decided on heap expansion to look at it. Memory explicitly
+deallocated by finalizers essentially needs to be counted as reclaimed
+by the GC. Otherwise there are cases in which the heap can grow
+infinitely.
+* Integrated Adam Megacz patches to not scan dynamic libraries if
+we are compiling with gcc on win32. Otherwise we need structured
+exception handling to deal with asynchronously unmapped root
+segments, and gcc doesn't directly support that.
+* Integrated Anthony Green's patch to support Wine.
+* GC_OPERATOR_NEW_ARRAY was misspelled OPERATOR_NEW_ARRAY in several
+places, including gc_cpp.cc.
+* Integrated Loren James Rittle's Alpha FreeBSD patches. These also
+changed the declarations of symbols like _end on many platforms to
+that they wouldn't mistakenly be declared as short data symbols.
+* Integrated changes from the Debian distribution.
+Fix C++ comments in POWERPC port. Add ARM32
+incremental GC support. Get rid of USE_GENERIC_PUSH_REGS for alpha/Linux,
+this time for real. Use va_copy to get rid of cord printf problems
+(finally).
+* Close file descriptor used to count cpus.
+* Don't just drop gcj free lists in GC_start_reclaim, since that can
+eventually cause the marker to see a bogus mark descriptor in the
+dropped objects. The usual symptom was a very intermittent segmentation
+fault in the marker. This mattered only if one of the GC_gcj_malloc
+variants was used.
+* Fixed Linux and Solaris/64 SPARC configuration.
+* Fixed a typo in strdup definition.
+* Changed Makefile.direct to invoke $(CC) to assemble alpha_mach_dep.S.
+This is needed on Linux. I'm not sure whether it's better or worse
+on Tru64.
+* Changed gc_cpp.h once more to declare operator new and friends only in
+a Microsoft environment. This may need further fine tuning.
+* Don't ever override strdup if it's already macro defined.
+* Changed gc_cpp.h yet again to also overload placement new. Due to the
+C++ overloading rules, the other overloaded new operations otherwise hide
+placement new, which causes many STL uses to break.
+* Integrated cygwin pthreads support from Dan Bonachea.
+* Turn on DYNAMIC_LOADING for NetBSD.
+* Changed printing code to print more complete GC times.
+* Applied Mark Mitchell's Irix patch to correct some bitrot.
+* Clarified which object-printing routines in dbg_mlc.c should hold
+the allocation lock. Restructured the code to allow reasonable object
+printing with -DREDIRECT_MALLOC.
+* Fix the Linux mmap code to always start with 0x1000 as the initial hint.
+Minor patches for 64-bit AIX, particularly to STACKBOTTOM.
+* Renamed "SUSPENDED" flag for Solaris threads support to avoid a conflict
+with a system header.
+* Cause win32_threads.c to handle an out of range stack pointer correctly,
+though currently with a warning.
+
+
+== [6.1alpha4] ==
+
+* Fixed typo in sparc_mach_dep.S, preventing the 64-bit version from
+building. Increased 64-bit heap size limit in test.c slightly, since
+a functional SPARC collector seems to slightly exceed the old limits.
+* Use NPRGREG in solaris_threads.c, thus printing all registers if things
+go wrong.
+* Added GC_MARKERS environment variable to allow use of a single marker
+thread on an MP without confusing the lock implementation.
+* Collect much less aggressively in incremental mode with GC_TIME_UNLIMITED.
+This is really a purely generational mode, and we can afford to
+postpone the collection until the heap is (nearly) full.
+* Remove read() wrapper for MPROTECT_VDB. It was causing more harm than
+good. It is often no longer needed if system calls avoid writing to
+pointerfull heap objects.
+* Fix MACOSX test in gcconfig.h.
+* Change GC_test_and_set so that it consistently has one argument.
+Add spaces to ::: in powerpc assembly code in gc_locks.h.
+* Fixed a formatting error in dbg_mlc.c. Added prototype to GC_abort()
+declaration.
+* Removed "source" argument to GC_find_start(). Eliminate GC_FIND_START().
+* Added win32 recognition code in configure.in. Changed some of the
+dllimport/export defines in gc.h.
+* GC_malloc_many didn't set hb_last_reclaimed when it called
+GC_reclaim_generic. (I'm not sure this matters much, but ...)
+* Allocating uncollectable objects with debug information sometimes
+allocated objects that were one byte too small, since uncollectable
+objects don't have the extra byte added at the end.
+* Added a bit more assertion checking to make sure that gcj objects
+on free lists never have a nonzero second word.
+* Replaced BCC_MAKEFILE with an up-to-date one.
+* Upgraded libtool, cinfigure.in and some related files to hopefully
+support NetBSD/SPARC. Unfortunately,
+libtool 1.4.2 seemed to be buggy due to missing quotes in several
+"test" invocations. Fixed those in the ltmain.sh script.
+* Some win32-specific patches, including the introduction of
+GC_CreateThread.
+* Merged in gcj changes from Anthony Green to support embedded systems.
+* Tried to consistently rename preprocessed assembly files with a capital
+.S extension.
+* Use alpha_mach_dep.S on ALPHA again. It doesn't really matter, but this
+makes our distribution consistent with the gcc one, avoiding future merge
+problems.
+* Move GET_MEM definition into gcconfig.h. Include gcconfig.h slightly
+later in gc_priv.h to avoid forward references to ptr_t.
+* Add some testing of local allocation to test.c.
+* Change definition of INVALID_QTID in specific.h. The -1 value was used
+inconsistently, and too likely to collide with a valid stack address.
+Some general clean-up of specific.[ch]. Added assertions.
+* On Pthread systems it was not safe to call GC_malloc() between fork()
+and exec(). According to the applicable standards, it doesn't appear
+to be safe to call malloc() or many other libc functions either, thus
+it's not clear this is fixable. Added experimental support for
+-DHANDLE_FORK in linux_threads.c which tries to support it. It may
+succeed if libc does the right thing. I'm not sure whether it does.
+* Documented thread local allocation primitives to require an
+explicit GC_init call. GC_init_parallel is no longer declared to
+be a constructor function, since that isn't portable and often
+seems to lead to initialization order problems.
+* Changed gc_cpp.cc and gc_cpp.h in one more attempt to make them
+compatible with Visual C++ 6.
+* Some more patches for Linux on HP PA-RISC.
+* Added include/gc_allocator.h. It implements (hopefully) standard
+conforming (as opposed to SGI-style) allocators that allocate
+collectable (gc_allocator) or GC-traceable, but not collectable
+(traceable_allocator) objects. This borrows heavily from libstc++,
+which borrows heavily from the SGI implementation, this part of
+which was written by Matt Austern. Changed test_cpp.cc to very
+minimally test this.
+* On Linux/X86, retry mmap with a different start argument. That should
+allow the collector to use more (closer to 3GB) of the address space.
+* Force 64 bit alignment with GCJ support.
+* Refined the choice of sa_handler vs. sa_sigaction in GC_dirty_init
+to accommodate some glibc5 systems.
+* Compensated for the fact that current versions of glibc set
+__libc_stack_end incorrectly on Linux/IA64 while initialization code
+is running. This could cause the collector to miss 16 bytes of
+the memory stack if GC_malloc or friends where called before main().
+* Mostly integrated Takis Psarogiannakopoulos' port to DG/UX Inix 86.
+This will probably take another iteration to work, since his
+patch conflicted with the libtool upgrade.
+* Added README.arm.cross containing some information about cross-
+compiling to an ARM processor from Margaret Fleck.
+
+
+== [6.1alpha3] ==
+
+* Minor cleanup on the gcconfig.h section for SPARC.
+* Minor fix to support Intel compiler for I386/Linux.
+* Added SPARC V9 (64-bit) support.
+* Restructured the way in which we determine whether or not to keep
+call stacks for debug allocation. By default SAVE_CALL_COUNT is
+now zero on all platforms. Added SAVE_CALL_NARGS parameters.
+If possible, use execinfo.h to capture call stack. (This should
+add support for a number of new platforms, though often at
+considerable runtime expense.)
+* Try to print symbolic information for call stacks. On Linux, we
+do this with a combination of execinfo.h and running addr2line in
+a separate process. This is both much more expensive and much more
+useful. Amazingly, it seems to be fast enough for most purposes.
+* Redefined strdup if -DREDIRECT_MALLOC is given.
+* Changed incremental collector and MPROTECT_VDB implementation so that,
+under favorable conditions, pointer-free objects are not protected.
+Added GC_incremental_protection_needs() to determine ahead of time whether
+pointer-free objects may be protected. Replaced GC_write_hint() with
+GC_remove_protection().
+* Added test for GC_ENABLE_INCREMENTAL environment variable.
+* Made GC_time_limit runtime configurable. Added GC_PAUSE_TIME_TARGET
+environment variable.
+* Eliminated GC_page_sz, a duplicate of GC_page_size.
+* Caused the Solaris and Irix thread creation primitives to call
+GC_init_inner().
+
+
+== [6.1alpha2] ==
+
+* No longer wrap read by default in multi-threaded applications. It was
+pointed out on the libgcj list that this holds the allocation lock for
+way too long if the read blocks. For now, reads into the heap are
+broken with incremental collection. It's possible to turn this back on
+if you make sure that read calls don't block (e.g. by calling select
+first).
+* Fix ifdef in Solaris_threads.h to refer to GC_SOLARIS_THREADS.
+* Added check for environment variable GC_IGNORE_GCJ_INFO.
+* Added printing of stop-the-world GC times if GC_PRINT_STATS environment
+variable is set.
+* The calloc definition in leak_detector.h was missing parentheses, and
+realloc was missing a second argument to GC_REALLOC.
+* Added GC_PRINT_BACK_HEIGHT environment variable and associated
+code, mostly in the new file backgraph.c. See doc/README.environment.
+* Added -DUSE_GLOBAL_ALLOC to work around a Windows NT issue.
+* Integrated port to NEC EWS4800 (MIPS-based workstation, with somewhat
+different address-space layout). This may help for other machines with
+holes in the data segment.
+* Changed the order in which GC_push_roots and friends push things onto
+the mark stack. GC_push_all calls need to come first, since we can't
+necessarily recover if those overflow the mark stack.
+* Some minor cleanups to mostly support the Intel compiler on Linux/IA64.
+
+
+== [6.1alpha1] ==
+
+* Non-debug, atomic allocations could result in bogus smashed object
+reports with debugging on.
+* Fixed GC_get_register_stack_base (Itanium only) to work around a glibc
+2.2.4 bug.
+* Initial port to HP/UX on Itanium. Thread support and both 32 and 64
+bit ABIs appear to work. Parallel mark support doesn't yet, due to
+some inline assembly code issues. Thread local allocation does appear
+to work.
+* ifdef'ed out glibc2.1/Itanium workaround. I suspect nobody is using
+that combination anymore.
+* Added a patch to make new_gc_alloc.h usable with gcc3.0.
+* Debugged 64-bit support on HP/UX PA-RISC.
+* Turned on dynamic loading support for FreeBSD/ELF.
+* Unregistering of finalizers with debugging allocation was broken.
+* Old finalizers were not returned correctly from GC_debug_register_finalizer.
+* Disabled MPROTECT_VDB for Linux/M68K based on a report that it doesn't work.
+* Cleaned up some statistics gathering code in reclaim.c.
+* Added some support for OpenBSD/ELF/Linux.
+* Added Jakub Jelinek's patch to use dl_iterate_phdr for dynamic library
+traversal to dyn_load.c. Changed it to weakly reference dl_iterate_phdr,
+so that the old code is stilll used with old versions of glibc.
+* Cleaned up feature test macros for various threads packages and
+integrated (partially functional) FreeBSD threads code from Loren Rittle.
+It's likely that the cleanup broke something, since it touched lots of
+code. It's also likelly that it fixed some unreported bugs in the
+less common thread implementations, since some of the original code
+didn't stand up to close scrutiny. Support for the next pthreads
+implementation should be easier to add.
+
+
+== [6.0] ==
+
+* Two more bug fixes for KEEP_BACK_PTRS and DBG_HDRS_ALL.
+* Fixed a stack clearing problem that resulted in SIGILL with a
+misaligned stack pointer for multi-threaded SPARC builds.
+* Integrated another HURD patch.
+
+
+== [6.0alpha9] ==
+
+* added README.macros.
+* Made gc.mak a symbolic link to work around winzip's tendency to ignore
+hard links.
+* Simplified the setting of NEED_FIND_LIMIT in os_dep.c, possibly breaking
+it on untested platforms.
+* Integrated initial GNU HURD port.
+* A few more fixes for Digital Mars compiler (Walter Bright).
+* Fixed gcc version recognition. Renamed OPERATOR_NEW_ARRAY to
+GC_OPERATOR_NEW_ARRAY. Changed GC_OPERATOR_NEW_ARRAY to be the default.
+It can be overridden with -DGC_NO_OPERATOR_NEW_ARRAY.
+* Changed the byte size to free-list mapping in thread local allocation
+so that size 0 allocations are handled correctly.
+* Fixed Linux/MIPS stackbottom for new toolchain.
+* Changed finalization registration to invoke GC_oom_fn when it runs out
+of memory.
+* Removed lvalue cast in finalize.c. This caused some debug configurations
+not to build with some non-gcc compilers.
+
+
+== [6.0alpha8] ==
+
+* Changed GC_debug_malloc_replacement and GC_debug_realloc_replacement
+so that they compile under Irix.
+* Updated powerpc_macosx_mach_dep.s so that it works if the collector
+is in a dynamic library.
+* Transformed README.debugging into debugging.html, updating and
+expanding it in the process. Added gcdescr.html and tree.html
+from the web site to the GC distribution.
+* Fixed several problems related to PRINT_BLACK_LIST. This involved
+restructuring some of the marker macros.
+* Fixed some problems with the sizing of objects with debug information.
+Finalization was broken KEEP_BACK_PTRS or PRINT_BLACK_LIST. Reduced the
+object size with SHORT_DEBUG_HDRS by another word.
+* The "Needed to allocate blacklisted ..." warning had inadvertently
+been turned off by default, due to a buggy test in allchblk.c. Turned
+it back on.
+* Removed the marker macros to deal with 2 pointers in interleaved fashion.
+They were messy and the performance improvement seemed minimal. We'll
+leave such scheduling issues to the compiler.
+* Changed Linux/PowerPC test to also check for __powerpc__ in response
+to a discussion on the gcc mailing list.
+* Removed the "static" from the jmp_buf
+declaration in GC_generic_push_regs. This was causing problems in
+systems that register all of their own roots. It looks far more correct
+to me without the "static" anyway.
+* Fixed several problems with thread local allocation of pointer-free or
+typed objects. The collector was reclaiming thread-local free lists, since
+it wasn't following the link fields.
+* There was apparently a long-standing race condition related to
+multi-threaded incremental collection. A collection could be started and
+a thread stopped between the memory unprotect system call and the setting of
+the corresponding dirt bit. I believe this did not affect Solaris or PCR,
+which use a different dirty-bit implementation. Fixed this by installing
+signal handlers with sigaction instead of signal, and disabling the thread
+suspend signal while in the write-protect handler. (It is unclear
+whether this scenario ever actually occurred. I found it while tracking
+down the following:)
+* Incremental collection did not cooperate correctly with the PARALLEL_MARK
+implementation of GC_malloc_many or the local_malloc primitives. It still
+doesn't work well, but it shouldn't lose memory anymore.
+* Integrated some changes from the gcc source tree that I had previously
+missed.
+* Added Makefile.direct as a copy of the default Makefile, which would
+normally be overwritten if configure is run.
+* Changed the gc.tar target in Makefile.direct to embed the version number
+in the gc directory name. This will affect future tar file distributions.
+* Changed the Irix dynamic library finding code to no longer try to
+eliminate writable text segments under Irix6.x, since that is probably no
+longer necessary, and can apparently be unsafe on occasion.
+* GC_cleanup with GC_DEBUG enabled passed a real object base address to
+GC_debug_register_finalizer_ignore_self, which expected a pointer past the
+debug header. Call GC_register_finalizer_ignore_self instead, even with
+debugging enabled.
+* The collector didn't build with call chain saving enabled but NARGS=0.
+* Fixed up the GNU-style build files enough so that they work in some
+obvious cases.
+* Added initial port to Digital Mars compiler for win32.
+
+
+== [6.0alpha7] ==
+
+* Added GC_finalizer_notifier. Fixed GC_finalize_on_demand. (The variable
+actually wasn't being tested at the right points. The build-time flag
+was.)
+* Added Tom Tromey's S390 Linux patch.
+* Added code to push GC_finalize_now in GC_push_finalizer_structures.
+* Added GC_push_gc_structures() to push all GC internal roots.
+* Integrated some FreeBSD changes from Matthew Flatt.
+* It looks like USRSTACK is not always correctly defined under Solaris.
+Hacked gcconfig.h to attempt to work around the problem. The result
+is not well tested.
+* Added Ji-Yong Chung's win32 threads and C++ fixes.
+* Arranged for hpux_test_and_clear.s to no longer be needed or built.
+It was causing build problems with gas, and it's not clear this is
+better than the pthreads alternative on this platform.
+* Some MINGW32 fixes from Hubert Garavel.
+* Added Initial Hitachi SH4 port from Kaz Kojima.
+* Ported thread-local allocation and parallel mark code to HP/UX on PA_RISC.
+* Made include/gc_mark.h more public and separated out the really private
+pieces. This is probably still not quite sufficient for clients that
+want to supply their own kind of type information. But it's a start.
+This involved lots of identifier renaming to make it namespace clean.
+* Added GC_dont_precollect for clients that need complete control over
+the root set.
+* GC_is_visible didn't do the right thing with gcj objects. (Not that
+many people are likely to care, but ...)
+* Don't redefine read with GC_USE_LD_WRAP.
+* Initial port to LINUX/HP_PA. Incremental collection and threads are not
+yet supported. (Incremental collection should work if you have the
+right kernel. Threads may work with a sufficiently patched pthread
+library.)
+* Changed gcconfig.h to recognize __i386__ as an alternative to i386 in
+many places.
+* Made win32_threads.c more tolerant of detaching a thread that it didn't
+know about.
+* Added Makefile.am and configure.in from gcc to the distribution, with
+minimal changes. For the moment, those are just placeholders. In the
+future, we're planning to switch to a GNU-style build environment for
+Un*x-like systems, though the old Makefile will remain as a backup.
+* Turned off STUBBORN_ALLOC by default, and added it back as a Makefile
+option.
+* Redistributed some functions between malloc.c and mallocx.c, so that
+simple statically linked apps no longer pull in mallocx.o.
+* Changed large object allocation to clear the first and last few words
+of each block before releasing the lock. Otherwise the marker could see
+objects with nonsensical type descriptors.
+* Fixed a couple of subtle problems that could result in not recognizing
+interior pointers from the stack. (I believe these were introduced
+in 6.0alpha6.)
+* GC_debug_free_inner called GC_free, which tried to reacquire the
+allocator lock, and hence deadlocked. (DBG_HDRS_ALL probably never worked
+with threads.)
+* Fixed several problems with back traces. Accidental references to a free
+list could cause the free list pointer to be overwritten by a back pointer.
+There seemed to be some problems with the encoding of root and finalizer
+references.
+
+
+== [6.0alpha6] ==
+
+* Changed the definition of DATASTART on ALPHA and IA64, where data_start
+and __data_start are not defined by earlier versions of glibc. This might
+need to be fixed on other platforms as well.
+* Changed the way the stack base and backing store base are found on IA64.
+This should now remain reliable on future kernels. But since it relies
+on /proc, it will no longer work in the simulated NUE environment.
+* Made the call to random() in dbg_mlc.c with -DKEEP_BACK_PTRS dependent
+on the OS. On non-Unix systems, rand() should be used instead. Handled
+small RAND_MAX.
+* Fixed the cord make rules to create the cord subdirectory, if necessary.
+* Changed fo_object_size calculation in finalize.c. Turned finalization
+of non-heap object into a no-op. Removed anachronism from GC_size()
+implementation.
+* Changed GC_push_dirty call in solaris_threads.c to GC_push_selected.
+It was missed in a previous renaming.
+* Arranged to not not mask SIGABRT in linux_threads.c.
+* Added GC_no_dls hook for applications that want to register their own
+roots.
+* Integrated Kjetil Matheussen's Amiga changes.
+* Added FREEBSD_STACKBOTTOM. Changed the X86/FreeBSD port to use it.
+* Added pthread_detach interception for platforms supported by linux_threads.c
+and irix_threads.c.
+* Changed the USE_MMAP code to check for the case in which we got the
+high end of the address space, i.e. mem_ptr + mem_sz == 0. It appears
+that this can happen under Solaris 7. It seems to be allowed by what
+I would claim is an oversight in the mmap specification.
+* Cleanup of linux_threads.c. Some code was originally cloned from
+irix_threads.c and now unnecessary. Some comments were obviously wrong.
+* (Mostly) fixed a longstanding problem with setting of dirty bits from
+a signal handler. In the presence of threads, dirty bits could get lost,
+since the etting of a bit in the bit vector was not atomic with respect
+to other updates. The fix is 100% correct only for platforms for which
+GC_test_and_set is defined. The goal is to make that all platforms with
+thread support. Matters only if incremental GC and threads are both
+enabled.
+* made GC_all_interior_pointers (a.k.a. ALL_INTERIOR_POINTERS) an
+initialization time, instead of build-time option. This is a
+nontrivial, high risk change. It should slow down the code measurably
+only if MERGE_SIZES is not defined, which is a very nonstandard
+configuration.
+* Added doc/README.environment, and implemented what it describes. This
+allows a number of additional configuration options to be set through
+the environment. It documents a few previously undocumented options.
+* Integrated Eric Benson's leak testing improvements.
+* Removed the option to throw away the beginning of each page (DISCARD_WORDS).
+This became less and less useful as processors enforce stricter alignment.
+And it hadn't been tested in ages, and was thus probably broken anyway.
+
+
+== [6.0alpha5] ==
+
+* Changed the definition of GC_pause in linux_threads.c to use a volatile
+asm. Some versions of gcc apparently optimize away writes to local volatile
+variables. This caused poor locking behavior starting at about
+4 processors.
+* Added GC_start_blocking(), GC_end_blocking() calls and wrapper for sleep
+to linux_threads.c.
+The first two calls could be used to generally avoid sending GC signals to
+blocked threads, avoiding both premature wakeups and unnecessary overhead.
+* Fixed a serious bug in thread-local allocation. At thread termination,
+GC_free could get called on small integers. Changed the code for thread
+termination to more efficiently return left-over free-lists.
+* Integrated Kjetil Matheussen's BeOS support.
+* Rearranged the directory structure to create the doc and tests
+subdirectories.
+* Sort of integrated Eric Benson's patch for OSF1. This provided basic
+OSF1 thread support by suitably extending hpux_irix_threads.c. Based
+on earlier email conversations with David Butenhof, I suspect that it
+will be more reliable in the long run to base this on linux_threads.c
+instead. Thus I attempted to patch up linux_threads.c based on Eric's code.
+The result is almost certainly broken, but hopefully close enough that
+someone with access to a machine can pick it up.
+* Integrated lots of minor changes from the NetBSD distribution. (These
+were supplied by David Brownlee. I'm not sure about the original
+authors.)
+* Hacked a bit more on the HP/UX thread-support in linux_threads.c. It
+now appears to work in the absence of incremental collection. Renamed
+hpux_irix_threads.c back to irix_threads.c, and removed the attempt to
+support HPUX there.
+* Changed gc.h to define _REENTRANT in cases in which it should already
+have been defined. It is still safer to also define it on the command
+line.
+
+
+== [6.0alpha4] ==
+
+* Moved up the detection of mostly full blocks to the initiation of the
+sweep phase. This eliminates some lock contention in the PARALLEL_MARK case,
+as multiple threads try to look at mostly full blocks concurrently.
+* Restored the code in GC_malloc_many that grabs a prefix of the global
+free list. This avoids the case in which every GC_malloc_many call
+tries and fails to allocate a new heap block, and the returns a single
+object from the global free list.
+* Some minor fixes in new_hblk.c. (Attempted to build free lists in order
+of increasing addresses instead of decreasing addresses for cache performance
+reasons. But this seems to be only a very minor gain with -DEAGER_SWEEP,
+and a loss in other cases. So the change was backed out.)
+* Fixed some of the documentation.
+* Fixed the Linux USE_PROC_FOR_LIBRARIES code to deal with apps that perform
+large numbers of mmaps. Also fixed that code to
+deal with short reads.
+* Added GC_get_total_bytes().
+* Fixed leak detection mode to avoid spurious messages under linuxthreads.
+(This should also now be easy for the other supported threads packages.
+But the code is tricky enough that I'm hesitant to do it without being able
+to test. Everything allocated in the GC thread support itself should be
+explicitly deallocated.)
+* Made it possible (with luck) to redirect malloc to GC_local_malloc.
+
+
+== [6.0alpha3] ==
+
+* Fixed the /proc/self/maps code to not seek, since that apparently is not
+reliable across all interesting kernels.
+* Fixed some compilation problems in the absence of PARALLEL_MARK
+(introduced in alpha2).
+* Fixed an algorithmic problem with PARALLEL_MARK. If work needs to
+be given back to the main mark "stack", the BOTTOM entries of the local
+stack should be given away, not the top ones. This has substantial
+performance impact, especially for > 2 processors, from what I can tell.
+* Extracted gc_lock.h from gc_priv.h. This should eventually make it a
+bit easier to avoid including gc_priv.h in clients.
+* Moved all include files to include/ and removed duplicate links to the
+same file. The old scheme was a bad idea because it was too easy to get the
+copies out of sync, and many systems don't support hard links.
+Unfortunately, it's likely that I broke some of the non-Unix Makefiles in
+the process, although I tried to update them appropriately.
+* Removed the partial support for a copied nursery. It's not clear that
+this would be a tremendous win, since we don't consistently lose to
+generational copying collectors. And it would significantly complicate
+many things. May be reintroduced if/when it really turns out to win.
+* Removed references to IRIX_JDK_THREADS, since I believe there never
+were and never will be any clients.
+* Added some code to linux_threads.c to possibly support HPUX threads
+using the Linux code. Unfortunately, it doesn't work yet, and is
+currently disabled.
+* Added support under Linux/X86 for saving the call chain, both in (debug)
+objects for client debugging, and in GC_arrays._last_stack for GC
+debugging. This was previously supported only under Solaris. It is
+not enabled by default under X86, since it requires that code be compiled
+to explicitly gave frame pointers on the call stack. (With gcc this
+currently happens by default, but is often turned off explicitly.)
+To turn it on, define SAVE_CALL_CHAIN.
+
+
+== [6.0alpha2] ==
+
+* Added USE_MARK_BYTES to reduce the need for compare-and-swap on platforms
+for which that's expensive.
+* Fixed a locking bug ib GC_gcj_malloc and some locking assertion problems.
+* Added a missing volatile to OR_WORD and renamed the parameter to
+GC_compare_and_swap so it's not a C++ reserved word.
+* Changed Linux dynamic library registration code to look at /proc/self/maps
+instead of the rld data structures when REDIRECT_MALLOC is defined.
+Otherwise some of the rld data data structures may be prematurely garbage
+collected.
+* Fixed USE_LD_WRAP a bit more, so it should now work without threads.
+* Renamed XXX_THREADS macros to GC_XXX_THREADS for namespace correctness.
+Temporarily added some backward compatibility definitions. Renamed
+USE_LD_WRAP to GC_USE_LD_WRAP.
+* Many MACOSX POWERPC changes, some additions to the gctest output, and
+a few minor generic bug fixes.
+
+
+== [6.0alpha1] ==
+
+* Added HP/PA prefetch support.
+* Added -DDBG_HDRS_ALL and -DSHORT_DBG_HDRS to reduce the cost and improve
+the reliability of generating pointer backtrace information, e.g. in
+the Bigloo environment.
+* Added parallel marking support (-DPARALLEL_MARK). This currently
+works only under IA32 and IA64 Linux, but it shouldn't be hard to adapt
+to other platforms. This is intended to be a lighter-weight (less
+new code, probably not as scalable) solution than the work by Toshio Endo
+et al, at the University of Tokyo. A number of their ideas were
+reused, though the code wasn't, and the underlying data structure
+is significantly different. In particular, we keep the global mark
+stack as a single shared data structure, but most of the work is done
+on smaller thread-local mark stacks.
+* Changed GC_malloc_many to be cheaper, and to require less mutual exclusion
+with -DPARALLEL_MARK.
+* Added full support for thread local allocation under Linux
+(-DTHREAD_LOCAL_ALLOC). This is a thin veneer on GC_malloc_many, and
+should be easily portable to other platforms, especially those that
+support pthreads.
+* CLEAR_DOUBLE was not always getting invoked when it should have been.
+* GC_gcj_malloc and friends used different out of memory handling than
+everything else, probably because I forgot about one when I implemented
+the other. They now both call GC_oom_fn(), not GC_oom_action().
+* Integrated Jakub Jelinek's fixes for Linux/SPARC.
+* Moved GC_objfreelist, GC_aobjfreelist, and GC_words_allocd out of
+GC_arrays, and separately registered the first two as excluded roots.
+This makes code compiled with gc_inl.h less dependent on the
+collector version. (It would be nice to remove the inclusion of
+gc_priv.h by gc_inl.h completely, but we're not there yet. The
+locking definitions in gc_priv.h are still referenced.)
+This change was later conditioned on SEPARATE_GLOBALS, which
+is not defined by default, since it involves a performance hit.
+* Register GC_obj_kinds separately as an excluded root region. The
+attempt to register it with GC_arrays was usually failing. (This wasn't
+serious, but seemed to generate some confusion.)
+* Moved backptr.h to gc_backptr.h.
+
+
+== [5.4] ==
+
+* Fixed a typo that prevented compilation with -DUSE_3DNOW_PREFETCH.
+* Fixed GC_is_thread_stack in solaris_threads.c. It forgot to return a value
+in the common case.
+* Fixed another silly syntax problem in GC_double_descr.
+* Fixed a GC_gcj_malloc bug: It tended to release the allocator lock twice.
+
+
+== [5.3] ==
+
+* Fixed _end declaration for OSF1.
+* There were lots of spurious leak reports in leak detection mode, caused
+by the fact that some pages were not being swept, and hence unmarked
+objects weren't making it onto free lists. (This bug dated back to 5.0.)
+* Fixed a typo in the liblinuxgc.so Makefile rule.
+* Added the GetExitCodeThread to Win32 GC_stop_world to (mostly) work
+around a Windows 95 GetOpenFileName problem.
+
+
+== [5.2] ==
+
+* dyn_load.c declared GC_scratch_last_end_ptr as an extern even if it
+was defined as a macro. This prevented the collector from building on
+Irix.
+* We quietly assumed that indirect mark descriptors were never 0.
+Our own typed allocation interface violated that. This could result
+in segmentation faults in the marker with typed allocation.
+* Fixed a _DUSE_MUNMAP bug in the heap block allocation code.
+* Taught the collector about VC++ handling array operator new.
+* The two copies of gc_hdrs.h had diverged. Made one a link to the other
+again.
+
+
+== [5.1] ==
+
+* Fixed a gc.h header bug which showed up under Irix.
+* Fixed a typo in GC_double_descr in typd_mlc.c.
+This probably could result in objects described by array descriptors not
+getting traced correctly.
+* The block nearly full tests in reclaim.c were not correct for 64 bit
+environments. This could result in unnecessary heap growth under unlikely
+conditions.
+
+
+== [5.0] ==
+
+* Fixed threadlibs.c for linux threads. -DUSE_LD_WRAP was broken and
+-ldl was omitted. Fixed Linux stack finding code to handle
+-DUSE_LD_WRAP correctly.
+* Added MSWIN32 exception handler around marker, so that the collector
+can recover from root segments that are unmapped during the collection.
+This caused occasional failures under Windows 98, and may also be
+an issue under Windows NT/2000.
+
+
+== [5.0alpha7] ==
+
+* -DREDIRECT_MALLOC was broken in alpha6. Fixed.
+* Cleaned up gc_ccp.h slightly, thus also causing the HP C++ compiler to
+accept it.
+* Removed accidental reference to dbg_mlc.c, which caused dbg_mlc.o to be
+linked into every executable.
+* Added PREFETCH to bitmap marker. Changed it to use the header cache.
+* GC_push_marked sometimes pushed one object too many, resulting in a
+segmentation fault in GC_mark_from_mark_stack. This was probably an old
+bug. It finally showed up in gctest on win32.
+* Gc_priv.h erroneously #defined GC_incremental to be TRUE instead of FALSE
+when SMALL_CONFIG was defined. This was no doubt a major performance bug for
+the default win32 configuration.
+* Removed -DSMALL_CONFIG from NT_MAKEFILE. It seemed like an anachronism now
+that the average PC has 64MB or so.
+* Integrated Bryce McKinley's patches for linux threads and dynamic loading
+from the libgcj tree. Turned on dynamic loading support for Linux/PPC.
+* Changed the stack finding code to use environ on HP/UX. This should
+probably be done on other platforms, too. Since I can't test those, that'll
+wait until after 5.0.
+
+
+== [5.0alpha6] ==
+
+* GC_malloc_explicitly_typed and friends sometimes failed to
+initialize first word.
+* Added allocation routines and support in the marker for mark descriptors
+in a type structure referenced by the first word of an object. This was
+introduced to support gcj, but hopefully in a way that makes it
+generically useful.
+* Added GC_requested_heapsize, and inhibited collections in non-incremental
+mode if the actual used heap size is less than what was explicitly
+requested.
+* The Solaris pthreads version of GC_pthread_create didn't handle a NULL
+attribute pointer. Solaris thread support used the wrong default thread
+stack size.
+* Changed PUSH_CONTENTS macro to no longer modify first parameter.
+This usually doesn't matter, but it was certainly an accident waiting
+to happen ...
+* Added GC_register_finalizer_no_order and friends to gc.h. They're
+needed by Java implementations.
+* Integrated a fix for a win32 deadlock resulting from clock() calling
+malloc.
+* Integrated Hiroshi Kawashima's port to Linux/MIPS. This was designed
+for a handheld platform, and may or may not be sufficient for other
+machines.
+* Fixed a va_arg problem with the %c specifier in cordprnt.c. It appears
+that this was always broken, but recent versions of gcc are the first to
+report the (statically detectable) bug.
+* Added an attempt at a more general solution to dlopen races/deadlocks.
+GC_dlopen now temporarily disables collection. Still not ideal, but ...
+* Added -DUSE_I686_PREFETCH, -DUSE_3DNOW_PREFETCH, and support for IA64
+prefetch instructions. May improve performance measurably, but I'm not
+sure the code will run correctly on processors that don't support the
+instruction. Won't build except with very recent gcc.
+* Added caching for header lookups in the marker. This seems to result
+in a barely measurable performance gain. Added support for interleaved
+lookups of two pointers, but unconfigured that since the performance
+gain is currently near zero, and it adds to code size.
+* Changed Linux DATA_START definition to check both data_start and
+__data_start, since nothing else seems to be portable.
+* Added -DUSE_LD_WRAP to optionally take advantage of the GNU ld function
+wrapping mechanism. Probably currently useful only on Linux.
+* Moved some variables for the scratch allocator into GC_arrays.
+* Fixed a win32 threads bug that caused the collector to not look for
+interior pointers from one of the thread stacks without
+ALL_INTERIOR_POINTERS.
+* Added Mingw32 support.
+* Changed the alpha port to use the generic register scanning code instead
+of alpha_mach_dep.s. Alpha_mach_dep.s doesn't look for pointers in fp
+registers, but gcc sometimes spills pointers there. Changed the IA64 code to
+do something similar for similar reasons.
+
+
+== [5.0alpha4] ==
+
+* Added protection fault handling patch for Linux/M68K from Fergus
+Henderson and Roman Hodek.
+* Removed the tests for SGI_SOURCE in new_gc_alloc.h. This was causing that
+interface to fail on nonSGI platforms.
+* Changed the Linux stack finding code to use /proc, after changing it
+to use HEURISTIC1.
+* Added HP/UX incremental GC support and HP/UX 11 thread support.
+Thread support is currently still flakey.
+* Added basic Linux/IA64 support.
+* Integrated Anthony Green's PicoJava support.
+* Integrated Scott Ananian's StrongARM/NetBSD support.
+* Fixed some fairly serious performance bugs in the incremental
+collector. These have probably been there essentially forever.
+(Mark bits were sometimes set before scanning dirty pages.
+The reclaim phase unnecessarily dirtied full small object pages.)
+* Changed the reclaim phase to ignore nearly full pages to avoid
+touching them.
+* Limited GC_black_list_spacing to roughly the heap growth increment.
+* Changed full collection triggering heuristic to decrease full GC
+frequency by default, but to explicitly trigger full GCs during
+heap growth. This doesn't always improve things, but on average it's
+probably a win.
+* GC_debug_free(0, ...) failed.
+
+
+== [5.0alpha3] ==
+
+* Added some highly incomplete code to support a copied young generation.
+Comments on nursery.h are appreciated.
+* Changed -DFIND_LEAK, -DJAVA_FINALIZATION, and -DFINALIZE_ON_DEMAND,
+so the same effect could be obtained with a runtime switch. This is
+a step towards standardizing on a single dynamic GC library.
+* Significantly changed the way leak detection is handled, as a consequence
+of the above.
+
+
+== [5.0alpha2] ==
+
+* Fixed bugs introduced in alpha1 (OpenBSD & large block initialization).
+* Added -DKEEP_BACK_PTRS and backptr.h interface. (The implementation
+idea came from Al Demers.)
+
+
+== [5.0alpha1] ==
+
+* Reworked large block allocator. Now uses multiple doubly linked free
+lists to approximate best fit.
+* Changed heap expansion heuristic. Entirely free blocks are no longer
+counted towards the heap size. This seems to have a major impact on
+heap size stability; the old version could expand the heap way too
+much in the presence of large block fragmentation.
+* added -DGC_ASSERTIONS and some simple assertions inside the collector.
+This is mainlyt for collector debugging.
+* added -DUSE_MUNMAP to allow the heap to shrink. Supported on only
+a few UNIX-like platforms for now.
+* added GC_dump_regions() for debugging of fragmentation issues.
+* Changed PowerPC pointer alignment under Linux to 4.
+* Changed the Linux/Alpha port to walk the data segment backwards until
+it encounters a SIGSEGV. The old way to find the start of the data
+segment broke with a recent release.
+* cordxtra.c needed to call GC_REGISTER_FINALIZER instead of
+GC_register_finalizer, so that it would continue to work with GC_DEBUG.
+* allochblk sometimes cleared the wrong block for debugging purposes
+when it dropped blacklisted blocks. This could result in spurious
+error reports with GC_DEBUG.
+* added MACOS X Server support.
+* Changed the Solaris threads code to ignore stack limits > 8 MB with
+a warning. Empirically, it is not safe to access arbitrary pages
+in such large stacks. And the dirty bit implementation does not
+guarantee that none of them will be accessed.
+* Integrated Martin Tauchmann's Amiga changes.
+* Integrated James Dominy's OpenBSD/SPARC port.
+
+
+== [4.14] ==
+
+* changed STACKBOTTOM for DJGPP.
+
+
+== [4.14alpha2] ==
+
+* -DSMALL_CONFIG did not work reliably with large (> 4K) pages.
+Recycling the mark stack during expansion could result in a size
+zero heap segment, which confused things. (This was probably also an
+issue with the normal config and huge pages.)
+* Did more work to make sure that callee-save registers were scanned
+completely, even with the setjmp-based code. Added USE_GENERIC_PUSH_REGS
+macro to facilitate testing on machines I have access to.
+* Added code to explicitly push register contents for win32 threads.
+This seems to be necessary.
+
+
+== [4.14alpha1] ==
+
+* Fixed GC_print_source_ptr to not use a prototype.
+* generalized CYGWIN test.
+* gc::new did the wrong thing with PointerFreeGC placement.
+* In the ALL_INTERIOR_POINTERS (default) case, some callee-save register
+values could fail to be scanned if the register was saved and
+reused in a GC frame. This showed up in verbose mode with gctest
+compiled with an unreleased SGI compiler. I vaguely recall an old
+bug report that may have been related. The bug was probably quite old.
+(The problem was that the stack scanning could be deferred until
+after the relevant frame was overwritten, and the new save location
+might be outside the scanned area. Fixed by more eager stack scanning.)
+* PRINT_BLACK_LIST had some problems. A few source addresses were garbage.
+* Replaced Makefile.dj and added -I flags to cord make targets.
+* GC_try_to_collect was broken with the non-incremental collector.
+* gc_cleanup destructors could pass the wrong address to
+GC_register_finalizer_ignore_self in the presence of multiple
+inheritance.
+* Changed PowerPC Linux stack finding code.
+
+
+== [4.13] ==
+
+* Fixed a crucial bug in the Watcom port. There was a redundant declaration
+of GC_push_one in gc_priv.h.
+* Added FINALIZE_ON_DEMAND.
+* Fixed some pre-ANSI cc problems in test.c.
+* Removed getpagesize() use for Solaris. It seems to be missing in one
+or two versions.
+* Fixed bool handling for SPARCCompiler version 4.2.
+* Fixed some files in include that had gotten unlinked from the main
+copy.
+* Some RS/6000 fixes (missing casts).
+* Fixed several problems in GC_debug_realloc, affecting mostly the
+FIND_LEAK case.
+* GC_exclude_static_roots contained a buggy unsigned comparison to
+terminate a loop.
+* CORD_str failed if the substring occurred at the last possible position.
+(Only affects cord users.)
+* Fixed Linux code to deal with RedHat 5.0 and integrated Peter Bigot's
+os_dep.c code for dealing with various Linux versions.
+* Added workaround for Irix pthreads sigaction bug and possible signal
+misdirection problems.
+Since alpha1:
+* Changed RS6000 STACKBOTTOM.
+* Integrated Patrick Beard's Mac changes.
+* Alpha1 didn't compile on Irix m.n, m < 6.
+* Replaced Makefile.dj with a new one from Gary Leavens.
+* Added Andrew Stitcher's changes to support SCO OpenServer.
+* Added PRINT_BLACK_LIST, to allow debugging of high densities of false
+pointers.
+* Added code to debug allocator to keep track of return address
+in GC_malloc caller, thus giving a bit more context.
+* Changed default behavior of large block allocator to more
+aggressively avoid fragmentation. This is likely to slow down the
+collector when it succeeds at reducing space cost.
+* Integrated Fergus Henderson's CYGWIN32 changes. They are untested,
+but needed for newer versions.
+* USE_MMAP had some serious bugs. This caused the collector to fail
+consistently on Solaris with -DSMALL_CONFIG.
+* Added Linux threads support.
+* Fixed more Linux threads problems.
+* Changed default GC_free_space_divisor to 3 with new large block allocation.
+* More CYGWIN32 fixes.
+* Integrated Tyson-Dowd's Linux-M68K port.
+* Minor HP PA and DEC UNIX fixes from Fergus Henderson.
+* Integrated Christoffe Raffali's Linux-SPARC changes.
+* Allowed for one more GC fixup iteration after a full GC in incremental
+mode. Some quick measurements suggested that this significantly
+reduces pause times even with smaller GC_RATE values.
+* Moved some more GC data structures into GC_arrays. This decreases
+pause times and GC overhead, but makes debugging slightly less convenient.
+* Fixed namespace pollution problem ("excl_table").
+* Made GC_incremental a constant for -DSMALL_CONFIG, hopefully shrinking
+that slightly.
+* Added some win32 threads fixes.
+* Integrated Ivan Demakov and David Stes' Watcom fixes.
+* Various other minor fixes contributed by many people.
+* Renamed config.h to gcconfig.h, since config.h tends to be used for
+many other things.
+* Integrated Matthew Flatt's support for 68K MacOS "far globals".
+* Fixed up some of the dynamic library Makefile targets for consistency
+across platforms.
+* Fixed a USE_MMAP typo that caused out-of-memory handling to fail
+on Solaris.
+* Added code to test.c to test thread creation a bit more.
+* Integrated GC_win32_free_heap.
+* Fixed Solaris 2.7 stack base finding problem. (This may actually
+have been done in an earlier alpha release.)
+Since alpha3:
+* Fixed MSWIN32 recognition test, which interfered with cygwin.
+* Removed unnecessary gc_watcom.asm from distribution. Removed
+some obsolete README.win32 text.
+* Added Alpha Linux incremental GC support.
+Changed Linux signal handler context argument to be a pointer.
+* Took care of some new warnings generated by the 7.3 SGI compiler.
+* Integrated Phillip Musumeci's FreeBSD/ELF fixes.
+* -DIRIX_THREADS was broken with the -o32 ABI (typo in gc_priv.h>
+
+
+== [4.12] ==
+
+* Fixed ElfW definition in dyn_load.c.
+This prevented the dynamic library support from compiling on some
+older ELF Linux systems.
+* Fixed UTS4 port (which I apparently mangled during the integration)
+* "Make C++" failed on Suns with SC4.0, due to a problem with "bool".
+Fixed in gc_priv.h.
+* Added more pieces for GNU win32.
+The current state of things should suffice for at least some
+applications.
+* Changed the out of memory retry count handling. (This matters only
+if GC_max_retries > 0, which is no longer the default.)
+* If a /proc read failed repeatedly, GC_written_pages was not updated
+correctly.
+* Under unlikely circumstances, the allocator could infinite loop in
+an out of memory situation.
+* Fixed a syntactic error in the DJGPP code. Also fixed a test program
+problem with DJGPP.
+* Atomic uncollectable objects were not treated correctly by the
+incremental collector. This resulted in weird log statistics and
+occasional performance problems.
+* Fixed some problems resulting from compilers that don't define
+__STDC__. In this case void * and char * were used inconsistently
+in some cases. (Void * should not have been used at all. If
+you have an ANSI superset compiler that does not define __STDC__,
+please compile with -D__STDC__=0.)
+* Fixed a compilation problem on Irix with -n32 and -DIRIX_THREADS.
+Also fixed some other IRIX_THREADS problems which may or may not have
+had observable symptoms.
+* Fixed an HP PA compilation problem in dyn_load.c.
+* SEGV fault handlers sometimes did not get reset correctly.
+* Added a fix for SOLARIS_THREADS on Intel.
+This probably needs more work to become functional.
+* Fixed struct sigcontext_struct in os_dep.c for compilation under
+Linux 2.1.X.
+* Changed the DJGPP STACKBOTTOM and DATASTART values to those ones suggested.
+These may still not be right, but it is
+it is likely to work more often than what was there before. They may
+even be exactly right.
+* Added a #include <string.h> to test_cpp.cc. This appears to help
+with HP/UX and gcc.
+* Version 4.11 failed to run in incremental mode on recent 64-bit Irix
+kernels. This was a problem related to page unaligned heap segments.
+Changed the code to page align heap sections on all platforms.
+(I had mistakenly identified this as a kernel problem earlier.
+It was not.)
+* Version 4.11 did not make allocated storage executable, except on
+one or two platforms, due to a bug in a #if test.
+* Added sparc_sunos4_mach_dep.s to support Sun's compilers under SunOS4.
+* Added GC_exclude_static_roots.
+* Fixed the object size mapping algorithm. This shouldn't matter,
+but the old code was ugly.
+* Heap checking code could die if one of the allocated objects was
+larger than its base address. (Unsigned underflow problem.)
+* Added RS6000 (AIX) dynamic library support and fixed STACK_BOTTOM.
+* Added Fergus Henderson's patches for improved robustness with large
+heaps and lots of blacklisting.
+* Added Peter Chubb's changes to support Solaris Pthreads, to support
+MMAP allocation in Solaris, to allow Solaris to find dynamic libraries
+through /proc, to add malloc_typed_ignore_off_page, and a few other
+minor features and bug fixes.
+* The Solaris 2 port should not use sbrk. I received confirmation from
+Sun that the use of sbrk and malloc in the same program is not
+supported. The collector now defines USE_MMAP by default on Solaris.
+* Replaced the djgpp makefile with Gary Leavens' version.
+* Fixed MSWIN32 detection test.
+* Added Fergus Henderson's patches to allow putting the collector into
+a DLL under GNU win32.
+* Added Ivan V. Demakov's port to Watcom C on X86.
+* Added Ian Piumarta's Linux/PowerPC port.
+* Added PointerFreeGC to the placement
+options in gc_cpp.h. This is of course unsafe, and may be controversial.
+On the other hand, it seems to be needed often enough that it's worth
+adding as a standard facility.
+
+
+== [4.11] ==
+
+* Rationalized (hopefully) GC_try_to_collect in an incremental collection
+environment. It appeared to not handle a call while a collection was in
+progress, and was otherwise too conservative.
+* Merged GC_reclaim_or_delete_all into GC_reclaim_all to get rid of some
+code.
+* Added Patrick Beard's Mac fixes, with substantial completely untested
+modifications.
+* Fixed the MPROTECT_VDB code to deal with large pages and imprecise
+fault addresses (as on an UltraSPARC running Solaris 2.5). Note that this
+was not a problem in the default configuration, which uses PROC_VDB.
+* The DEC Alpha assembly code needed to restore $gp between calls.
+* The write command for "de" was completely broken for large files.
+I used the easiest portable fix, which involved changing the semantics
+so that f.new is written instead of overwriting f. That's safer anyway.
+* Added README.solaris2 with a discussion of the possible problems of
+mixing the collector's sbrk allocation with malloc/realloc.
+* Changed the data segment starting address for SGI machines. The
+old code failed under IRIX6.
+* Required double word alignment for MIPS.
+* Various minor fixes to remove warnings.
+* Attempted to fix some Solaris threads problems.
+In particular, the collector could try to fork a thread with the
+world stopped as part of GC_thr_init. It also failed to deal with
+the case in which the original thread terminated before the whole
+process did.
+* Added -DNO_EXECUTE_PERMISSION. This has a major performance impact
+on the incremental collector under Irix, and perhaps under other
+operating systems.
+* Added some code to support allocating the heap with mmap. This may
+be preferable under some circumstances.
+* Integrated dynamic library support for HP.
+* Integrated James Clark's win32 threads support, and made a number
+of changes to it. This is still not 100% solid.
+* Integrated Alistair Crooks' support for UTS4 running on an Amdahl
+370-class machine.
+* Fixed a serious bug in explicitly typed allocation. Objects requiring
+large descriptors where handled in a way that usually resulted in
+a segmentation fault in the marker.
+* Added partial support for GNU win32 development.
+* Added optional support for Java-style finalization semantics.
+This is recommended only for Java implementations.
+* GC_malloc_uncollectable faulted instead of returning 0 when out of
+memory.
+* Calls to GC_base before the collector was initialized failed on a
+DEC Alpha.
+* Added base pointer checking to GC_REGISTER_FINALIZER in debugging mode.
+* GC_debug_realloc failed for uncollectable objects.
+* Explicitly typed allocation could crash if it ran out of memory.
+* Added minimal support for a DEC Alpha running Linux.
+* Fixed a problem with allocation of objects whose size overflowed
+ptrdiff_t. (This now fails unconditionally, as it should.)
+* Added the beginning of Irix pthread support.
+* Integrated Xiaokun Zhu's fixes for djgpp 2.01.
+* Added SGI-style STL allocator support (gc_alloc.h).
+* Fixed a serious bug in README.solaris2.
+Multi-threaded programs must include
+gc.h with SOLARIS_THREADS defined.
+* Changed GC_free so it actually deallocates uncollectable objects.
+* Added Linux ELF support for dynamic libraries.
+* Changed the Borland cc configuration so that the assembler is not
+required.
+* Fixed a bug in the C++ test that caused it to fail in 64-bit
+environments.
+
+
+== [4.10] ==
+
+* Fixed a typo around a call to GC_collect_or_expand in alloc.c. It broke
+handling of out of memory.
+
+
+== [4.9] ==
+
+* More README.debugging fixes.
+* Objects ready for finalization, but not finalized in the same GC
+cycle, could be prematurely collected. This occasionally happened
+in test_cpp.
+* Too little memory was obtained from the system for very large
+objects. That could cause a heap explosion if these objects were
+not contiguous (e.g. under PCR), and too much of them was blacklisted.
+* Due to an improper initialization, the collector was too hesitant to
+allocate blacklisted objects immediately after system startup.
+* Moved GC_arrays from the data into the bss segment by not explicitly
+initializing it to zero. This significantly
+reduces the size of executables, and probably avoids some disk accesses
+on program startup. It's conceivable that it might break a port that I
+didn't test.
+* Fixed EMX_MAKEFILE to reflect the gc_c++.h to gc_cpp.h renaming which
+occurred a while ago.
+
+
+== [4.8] ==
+
+* Changed a "comment" in a MacOS specific part of mach_dep.c that caused
+gcc to fail on other platforms.
+
+
+== [4.7] ==
+
+* Fixed some compilation problems with -DCHECKSUMS.
+* Updated some Mac specific files.
+* Fixed a serious bug for machines with non-word-aligned pointers.
+
+
+== [4.6] ==
+
+* Added Linux ELF support.
+* GC_base crashed if it was called before any other GC_ routines.
+This could happen if a gc_cleanup object was allocated outside the heap
+before any heap allocation.
+* The heap expansion heuristic was not stable if all objects had finalization
+enabled. Fixed finalize.c to count memory in finalization queue and
+avoid explicit deallocation. Changed alloc.c to also consider this count.
+(This is still not recommended. It's expensive if nothing else.)
+* GC_malloc_uncollectable(0) was broken.
+* The collector didn't compile under Linux 1.3.X.
+The current workaround is ugly, but expected to be temporary.
+* Fixed a formatting problem for SPARC stack traces.
+* Fixed some '=='s in os_dep.c that should have been assignments.
+Fortunately these were in code that should never be executed anyway.
+* Fixed the heap block allocator to only drop blacklisted blocks in small
+chunks. Made BL_LIMIT self adjusting. (Both of these were in response
+to heap growth observed by Paul Graham.)
+* Fixed the Metrowerks/68K Mac code to also mark from a6.
+* Significantly updated README.debugging.
+* Fixed some problems with longjmps out of signal handlers, especially under
+Solaris. Added a workaround for the fact that siglongjmp doesn't appear to
+do the right thing with -lthread under Solaris.
+* Added MSDOS/djgpp port.
+* Added "make reserved_namespace" and "make user_namespace". The
+first renames ALL "GC_xxx" identifiers as "_GC_xxx". The second is the
+inverse transformation. Note that doing this is guaranteed to break all
+clients written for the other names.
+* descriptor field for kind NORMAL in GC_obj_kinds with ADD_BYTE_AT_END
+defined should be -ALIGNMENT not WORDS_TO_BYTES(-1). This is
+a serious bug on machines with pointer alignment of less than a word.
+* GC_ignore_self_finalize_mark_proc didn't handle pointers to very near the
+end of the object correctly. Caused failures of the C++ test on a DEC Alpha
+with g++.
+* gc_inl.h still had problems. Partially fixed. Added warnings at the
+beginning to hopefully specify the remaining dangers.
+* Added DATAEND definition to config.h.
+* Fixed some of the .h file organization. Fixed "make floppy".
+
+
+== [4.5] ==
+
+* Fixed many minor and one major README bugs.
+* Fixed ALPHA/OSF/1 dynamic library support.
+* Added incremental GC support (MPROTECT_VDB) for Linux (with some
+help from Bruno Haible).
+* Altered SPARC recognition tests in gc.h and config.h.
+* Added basic incremental GC support for win32, as implemented by
+Windows NT and Windows 95. GC_enable_incremental is a no-op
+under win32s, which doesn't implement enough of the VM interface.
+* Added -DLARGE_CONFIG.
+* Fixed GC_..._ignore_off_page to also function without
+-DALL_INTERIOR_POINTERS.
+* (Hopefully) fixed RS/6000 port. (Only the test was broken.)
+* Fixed a performance bug in the non-incremental collector running
+on machines supporting incremental collection with MPROTECT_VDB
+(e.g. SunOS 4, DEC AXP). This turned into a correctness bug under
+win32s with win32 incremental collection. (Not all memory protection
+was disabled.)
+* Fixed some ppcr related bit rot.
+* Caused dynamic libraries to be unregistered before re-registering.
+The old way turned out to be a performance bug on some machines.
+* GC_root_size was not properly maintained under MSWIN32.
+* Added -DNO_DEBUGGING and GC_dump.
+* Fixed a couple of bugs arising with SOLARIS_THREADS +
+REDIRECT_MALLOC.
+* Added NetBSD/M68K port.
+* Fixed a serious realloc bug. For certain object sizes, the collector
+wouldn't scan the expanded part of the object.
+
+
+== [4.4] ==
+
+* ASM_CLEAR_CODE was erroneously defined for HP
+PA machines, resulting in a compile error.
+* Fixed OS/2 Makefile to create a library.
+* Gc_cleanup objects didn't work if they were created on
+the stack. Fixed.
+* One copy of Gc_cpp.h in the distribution was out of
+synch, and failed to document some known compiler
+problems with explicit destructor invocation. Partially
+fixed. There are probably other compilers on which
+gc_cleanup is miscompiled.
+* Fixed Makefile to pass C compiler flags to C++ compiler.
+* Added Mac fixes.
+* Fixed os_dep.c to work around what appears to be
+a new and different VirtualQuery bug under newer
+versions of win32S.
+* GC_non_gc_bytes was not correctly maintained by
+GC_free. Fixed.
+* Added GC_set_max_heap_size.
+* Changed allocation code to ignore blacklisting if it is preventing
+use of a very large block of memory. This has the advantage
+that naive code allocating very large objects is much more
+likely to work. The downside is you might no
+longer find out that such code should really use
+GC_malloc_ignore_off_page.
+* Changed GC_printf under win32 to close and reopen the file
+between calls. FAT file systems otherwise make the log file
+useless for debugging.
+* Added GC_try_to_collect and GC_get_bytes_since_gc. These
+allow starting an abortable collection during idle times.
+This facility does not require special OS support.
+* Added some support for the Borland development environment.
+* Removed a misfeature from checksums.c that caused unexpected
+heap growth.
+* Changed finalize.c to call WARN if it encounters a finalization cycle.
+WARN is defined in gc_priv.h to write a message, usually to stdout.
+In many environments, this may be inappropriate.
+* Renamed NO_PARAMS in gc.h to GC_NO_PARAMS, thus adhering to my own
+naming convention.
+* Added GC_set_warn_proc to intercept warnings.
+* Fixed Amiga port.
+* Fixed a bug in mark.c that could result in an access to unmapped
+memory from GC_mark_from_mark_stack on machines with unaligned
+pointers.
+* Fixed a win32 specific performance bug that could result in scanning of
+objects allocated with the system malloc.
+* Added REDIRECT_MALLOC.
+
+
+== [4.3] ==
+
+* Fixed SPARC alignment problem with GC_DEBUG.
+* Fixed Solaris threads /proc workaround. The real
+problem was an interaction with mprotect.
+* Incorporated fix from Patrick Beard for gc_c++.h (now gc_cpp.h).
+* Slightly improved allocator space utilization by
+fixing the GC_size_map mechanism.
+* Integrated some Sony News and MIPS RISCos 4.51
+patches.
+* Fixed HP_PA alignment problem.
+* Added GC_same_obj and friends. Changed GC_base
+to return 0 for pointers past the end of large objects.
+Improved GC_base performance with ALL_INTERIOR_POINTERS
+on machines with a slow integer mod operation.
+Added GC_PTR_ADD, GC_PTR_STORE, etc. to prepare
+for preprocessor.
+* changed the default on most UNIX machines to be that
+signals are not disabled during critical GC operations.
+This is still ANSI-conforming, though somewhat dangerous
+in the presence of signal handlers. But the performance
+cost of the alternative is sometimes problematic.
+Can be changed back with a minor Makefile edit.
+* renamed IS_STRING in gc.h, to CORD_IS_STRING, thus
+following my own naming convention. Added the function
+CORD_to_const_char_star.
+* Fixed a gross bug in GC_finalize. Symptom: occasional
+address faults in that function.
+* Added port to ICL DRS6000 running DRS/NX. Restructured
+things a bit to factor out common code, and remove obsolete
+code. Collector should now run under SUNOS5 with either
+mprotect or /proc dirty bits.
+* More bug fixes and workarounds for Solaris 2.X. (These were
+mostly related to putting the collector in a dynamic library,
+which didn't really work before. Also SOLARIS_THREADS
+didn't interact well with dl_open.)
+* Fixed a serious performance bug on the DEC Alpha. The text
+segment was getting registered as part of the root set.
+(Amazingly, the result was still fast enough that the bug
+was not conspicuous.) The fix works on OSF/1, version 1.3.
+Hopefully it also works on other versions of OSF/1 ...
+* Fixed a bug in GC_clear_roots.
+* Fixed a bug in GC_generic_malloc_words_small that broke
+gc_inl.h.
+* Fixed some problems with cord/de under Linux.
+* Fixed some cord problems, notably with CORD_riter4.
+* Added DG/UX port.
+* Added finalization registration routines with weaker ordering
+constraints. (This is necessary for C++ finalization with
+multiple inheritance, since the compiler often adds self-cycles.)
+* Filled the holes in the SCO port.
+* John Ellis' additions to the C++ support: From John:
+* I completely rewrote the documentation in the interface gc_c++.h
+(later renamed gc_cpp.h). I've tried to make it both clearer and more
+precise.
+* The definition of accessibility now ignores pointers from an
+finalizable object (an object with a clean-up function) to itself.
+This allows objects with virtual base classes to be finalizable by the
+collector. Compilers typically implement virtual base classes using
+pointers from an object to itself, which under the old definition of
+accessibility prevented objects with virtual base classes from ever
+being collected or finalized.
+* gc_cleanup now includes gc as a virtual base. This was enabled by
+the change in the definition of accessibility.
+* I added support for operator new[]. Since most compilers
+don't yet support operator new[], it is conditionalized on
+-DOPERATOR_NEW_ARRAY. The code is untested, but its trivial and looks
+correct.
+* The test program test_gc_c++ (later renamed test_cpp.cc)
+tries to test for the C++-specific functionality not tested by the
+other programs.
+* Added unistd.h include to misc.c. (Needed for ppcr.)
+* Added PowerMac port.
+* Fixed "srcdir"-related Makefile problems. Changed things so
+that all externally visible include files always appear in the
+include subdirectory of the source. Made gc.h directly
+includable from C++ code.
+* Changed Intel code to also mark from ebp
+* Renamed C++ related files so they could live in a FAT
+file system.
+* Changed Windows NT Makefile to include C++ support in
+gc.lib. Added C++ test as Makefile target.
+
+
+== [4.2] ==
+
+* Multiple bug fixes/workarounds in the Solaris threads version.
+(It occasionally failed to locate some register contents for
+marking. It also turns out that thr_suspend and friends are
+unreliable in Solaris 2.3. Dirty bit reads appear
+to be unreliable under some weird
+circumstances. My stack marking code
+contained a serious performance bug. The new code is
+extremely defensive, and has not failed in several CPU
+hours of testing. But no guarantees ...)
+* Added MacOS support.
+* Fixed several syntactic bugs in gc_c++.h and friends. (These
+didn't bother g++, but did bother most other compilers.)
+Fixed gc_c++.h finalization interface.
+* 64 bit alignment for allocated objects was not guaranteed in a
+few cases in which it should have been.
+* Added GC_malloc_atomic_ignore_off_page.
+* Added GC_collect_a_little.
+* Added some prototypes to gc.h.
+* Some other minor bug fixes (notably in Makefile).
+* Fixed OS/2 / EMX port.
+* Fixed AmigaDOS port.
+* Fixed the DATASTART definition under Solaris. There
+was a 1 in 16K chance of the collector missing the first
+64K of static data (and thus crashing).
+* Fixed some blatant anachronisms in the README file.
+* Fixed PCR-Makefile for upcoming PPCR release.
+
+
+== [4.1] ==
+
+* Changed finalization implementation to guarantee that
+finalization procedures are called outside of the allocation
+lock, making direct use of the interface a little less dangerous.
+MAY BREAK EXISTING CLIENTS that assume finalizers
+are protected by a lock. Since there seem to be few multi-threaded
+clients that use finalization, this is hopefully not much of
+a problem.
+* Fixed a gross bug in CORD_prev.
+* Fixed a bug in blacklst.c that could result in unbounded
+heap growth during startup on machines that do not clear
+memory obtained from the OS (e.g. win32S).
+* Ported de editor to win32/win32S. (This is now the only
+version with a mouse-sensitive UI.)
+* Added GC_malloc_ignore_off_page to allocate large arrays
+in the presence of ALL_INTERIOR_POINTERS.
+* Changed GC_call_with_alloc_lock to not disable signals in
+the single-threaded case.
+* Reduced retry count in GC_collect_or_expand for garbage
+collecting when out of memory.
+* Made uncollectable allocations bypass black-listing, as they
+should.
+* Fixed a bug in typed_test in test.c that could cause (legitimate)
+GC crashes.
+* Fixed some potential synchronization problems in finalize.c
+* Fixed a real locking problem in typd_mlc.c.
+* Worked around an AIX 3.2 compiler feature that results in
+out of bounds memory references.
+* Partially worked around an IRIX5.2 beta problem (which may
+or may not persist to the final release).
+* Fixed a bug in the heap integrity checking code that could
+result in explicitly deallocated objects being identified as
+smashed. Fixed a bug in the dbg_mlc stack saving code
+that caused old argument pointers to be considered live.
+* Fixed a bug in CORD_ncmp (and hence CORD_str).
+* Repaired the OS2 port, which had suffered from bit rot
+in 4.0. Worked around what appears to be CSet/2 V1.0
+optimizer bug.
+* Fixed a Makefile bug for target "c++".
+
+
+== [4.0] ==
+
+* Added support for Solaris threads (which was possible
+only by reimplementing some fraction of Solaris threads,
+since Sun doesn't currently make the thread debugging
+interface available).
+* Added non-threads win32 and win32S support.
+* (Grudgingly, with suitable muttering of obscenities) renamed
+files so that the collector distribution could live on a FAT
+file system. Files that are guaranteed to be useless on
+a PC still have long names. Gc_inline.h and gc_private.h
+still exist, but now just include gc_inl.h and gc_priv.h.
+* Fixed a really obscure bug in finalization that could cause
+undetected mark stack overflows. (I would be surprised if
+any real code ever tickled this one.)
+* Changed finalization code to dynamically resize the hash
+tables it maintains. (This probably does not matter for well-
+-written code. It no doubt does for C++ code that overuses
+destructors.)
+* Added typed allocation primitives. Rewrote the marker to
+accommodate them with more reasonable efficiency. This
+change should also speed up marking for GC_malloc allocated
+objects a little. See gc_typed.h for new primitives.
+* Improved debugging facilities slightly. Allocation time
+stack traces are now kept by default on SPARC/SUNOS4.
+* Added better support for small heap applications.
+* Significantly extended cord package. Fixed a bug in the
+implementation of lazily read files. Printf and friends now
+have cord variants. Cord traversals are a bit faster.
+* Made ALL_INTERIOR_POINTERS recognition the default.
+* Fixed de so that it can run in constant space, independent
+of file size. Added simple string searching to cords and de.
+* Added the Hull-Ellis C++ interface.
+* Added dynamic library support for OSF/1.
+* Changed argument to GC_expand_hp to be expressed
+in units of bytes instead of heap blocks. (Necessary
+since the heap block size now varies depending on
+configuration. The old version was never very clean.)
+* Added GC_get_heap_size(). The previous "equivalent"
+was broken.
+* Restructured the Makefile a bit.
+
+
+== [3.7] ==
+
+* Added a workaround for an HP/UX compiler bug.
+* Fixed another stack clearing performance bug. Reworked
+that code once more.
+
+
+== [3.6] ==
+
+* fixed a bug in the mark stack growth code that was introduced
+in 3.4.
+* fixed Makefile to work around DEC AXP compiler tail recursion
+bug.
+
+
+== [3.5] ==
+
+* Minor collections now mark from roots only once, if that
+doesn't cause an excessive pause.
+* The stack clearing heuristic was refined to prevent anomalies
+with very heavily recursive programs and sparse stacks.
+* Fixed a bug that prevented mark stack growth in some cases.
+GC_objects_are_marked should be set to TRUE after a call
+to GC_push_roots and as part of GC_push_marked, since
+both can now set mark bits. I think this is only a performance
+bug, but I wouldn't bet on it. It's certainly very hard to argue
+that the old version was correct.
+* Fixed an incremental collection bug that prevented it from
+working at all when HBLKSIZE != getpagesize()
+* Changed dynamic_loading.c to include gc_priv.h before testing
+DYNAMIC_LOADING. SunOS dynamic library scanning
+must have been broken in 3.4.
+* Object size rounding now adapts to program behavior.
+* Added a workaround (provided by Manuel Serrano and
+colleagues) to a long-standing SunOS 4.X (and 3.X) ld bug
+that I had incorrectly assumed to have been squished.
+The collector was broken if the text segment size was within
+32 bytes of a multiple of 8K bytes, and if the beginning of
+the data segment contained interesting roots. The workaround
+assumes a demand-loadable executable. The original may have
+have "worked" in some other cases.
+* Added dynamic library support under IRIX5.
+* Added support for EMX under OS/2.
+
+
+== [3.4] ==
+
+* Fixed a performance bug in GC_realloc.
+* Updated the amiga port.
+* Added NetBSD and 386BSD ports.
+* Added cord library.
+* Added trivial performance enhancement for
+ALL_INTERIOR_POINTERS. (Don't scan last word.)
+
+
+== [3.3] ==
+
+* PCR-specific bugs.
+* Missing locking in GC_free, redundant FASTUNLOCK
+in GC_malloc_stubborn, and 2 bugs in
+GC_unregister_disappearing_link.
+* Common symbols allocated by the SunOS4.X dynamic loader
+were not included in the root set.
+* Bug in GC_finalize
+* Merged Amiga port from Jesper Peterson (untested)
+* Merged NeXT port from Thomas Funke (significantly
+modified and untested)
+
+
+== [3.2] ==
+
+Fixed a serious and not entirely repeatable bug in
+the incremental collector. It appeared only when dirty bit info
+on the roots was available, which is normally only under Solaris.
+It also added GC_general_register_disappearing_link, and some
+testing code. Interface.c disappeared.
+
+
+== [3.1] ==
+
+* A workaround for a SunOS 4.X SPARC C compiler
+misfeature that caused problems when the collector was turned into
+a dynamic library.
+* A fix for a bug in GC_base that could result in a memory fault.
+* A fix for a performance bug (and several other misfeatures) pointed
+out by Dave Detlefs and Al Dosser.
+* Use of dirty bit information for static data under Solaris 2.X.
+* DEC Alpha/OSF1 support.
+* Incremental collection on more platforms.
+* A more refined heap expansion policy. Less space usage by default.
+* Various minor enhancements to reduce space usage, and to reduce
+the amount of memory scanned by the collector.
+* Uncollectable allocation without per object overhead.
+* More conscientious handling of out-of-memory conditions.
+* Fixed a bug in debugging stubborn allocation.
+* Fixed a bug that resulted in occasional erroneous reporting of smashed
+objects with debugging allocation.
+* Fixed bogus leak reports of size 4096 blocks with FIND_LEAK.
+
+
+== [3.0] ==
+
+Added generational/incremental collection and stubborn objects.
+
+
+== [2.5] ==
+
+* Removed an explicit call to exit(1)
+* Fixed calls to GC_printf and GC_err_printf, so the correct number of
+arguments are always supplied. The OS/2 C compiler gets confused if
+the number of actuals and the number of formals differ. (ANSI C
+doesn't require this to work. The ANSI sanctioned way of doing things
+causes too many compatibility problems.)
+
+
+== [2.4] ==
+
+Added GC_free_space_divisor as a tuning knob, added
+support for OS/2 and linux, and fixed the following bugs:
+* On machines with unaligned pointers (e.g. Sun 3), every 128th word could
+fail to be considered for marking.
+* Dynamic_load.c erroneously added 4 bytes to the length of the data and
+bss sections of the dynamic library. This could result in a bad memory
+reference if the actual length was a multiple of a page. (Observed on
+Sun 3. Can probably also happen on a Sun 4.)
+(Dynamic library handling is still broken on Sun 3s
+under 4.1.1U1, but apparently not 4.1.1. If you have such a machine,
+use -Bstatic.)
+
+
+== [2.3] ==
+
+* Added ALL_INTERIOR_POINTERS.
+* Missing declaration of etext in the A/UX version.
+* Some PCR root-finding problems.
+* Blacklisting was not 100% effective, because the plausible future
+heap bounds were being miscalculated.
+* GC_realloc didn't handle out-of-memory correctly.
+* GC_base could return a nonzero value for addresses inside free blocks.
+* test.c wasn't really thread safe, and could erroneously report failure
+in a multi-threaded environment. (The locking primitives need to be
+replaced for other threads packages.)
+* GC_CONS was thoroughly broken.
+* On a SPARC with dynamic linking, signals stayed disabled while the
+client code was running.
+
+
+== [2.2] ==
+
+* GC_realloc could fail to extend the size of the object for certain large
+object sizes.
+* A blatant subscript range error in GC_printf, which unfortunately
+wasn't exercised on machines with sufficient stack alignment constraints.
+* GC_register_displacement did the wrong thing if it was called after
+any allocation had taken place.
+* The leak finding code would eventually break after 2048 byte
+byte objects leaked.
+* interface.c didn't compile.
+* The heap size remained much too small for large stacks.
+* The stack clearing code behaved badly for large stacks, and perhaps
+on HP/PA machines.
+
+
+== [2.1] ==
+
+* The first stable version since 1.9.
+* Added support for PPCR.
+
+
+== [2.0] ==
+
+* Introduced a consistent naming convention for collector
+routines and added support for registering dynamic library data segments
+in the standard mark_roots.c. Most of the data structures were revamped.
+The treatment of interior pointers was completely changed. Finalization
+was added. Support for locking was added. Object kinds were added.
+We added a black listing facility to avoid allocating at addresses known
+to occur as integers somewhere in the address space. Much of this
+was accomplished by adapting ideas and code from the PCR collector.
+The test program was changed and expanded.
+
+
+== [1.9] ==
+
+* fixed a major bug in gc_realloc.
+
+
+== [1.8] ==
+
+* added ULTRIX support in gc_private.h.
+
+
+== [1.5] ==
+
+* ensure 8 byte alignment for objects allocated on a sparc based machine.
+
+
+== [1.4] ==
+
+* Does not use compile time determined values
+for the stack base. This no longer works on Sun 3s, since Sun 3/80s use
+a different stack base. We now use a straightforward heuristic on all
+machines on which it is known to work (incl. Sun 3s) and compile-time
+determined values for the rest. There should really be library calls
+to determine such values.
+
+
+== [1.3] ==
+
+* Fixed spurious
+assembly language assignments to TMP_SP. Only the assignment in the PC/RT
+code is necessary. On other machines, with certain compiler options,
+the assignments can lead to an unsaved register being overwritten.
+Known to cause problems under SunOS 3.5 WITHOUT the -O option. (With
+-O the compiler recognizes it as dead code. It probably shouldn't,
+but t2hat's another story.)
diff --git a/boehm-gc/EMX_MAKEFILE b/boehm-gc/EMX_MAKEFILE
index d7674b3a3e9..b52c744f8e1 100644
--- a/boehm-gc/EMX_MAKEFILE
+++ b/boehm-gc/EMX_MAKEFILE
@@ -18,28 +18,9 @@ CC= gcc
CXX=g++
# Needed only for "make c++", which adds the c++ interface
-CFLAGS= -O -DALL_INTERIOR_POINTERS -DSILENT
+CFLAGS= -O -DALL_INTERIOR_POINTERS
# Setjmp_test may yield overly optimistic results when compiled
# without optimization.
-# -DSILENT disables statistics printing, and improves performance.
-# -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
-# altered stubborn objects, at substantial performance cost.
-# -DFIND_LEAK causes the collector to assume that all inaccessible
-# objects should have been explicitly deallocated, and reports exceptions
-# -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
-# (Clients should also define SOLARIS_THREADS and then include
-# gc.h before performing thr_ or GC_ operations.)
-# -DALL_INTERIOR_POINTERS allows all pointers to the interior
-# of objects to be recognized. (See gc_private.h for consequences.)
-# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
-# usually causing it to use less space in such situations.
-# Incremental collection no longer works in this case.
-# -DDONT_ADD_BYTE_AT_END is meaningful only with
-# -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
-# causes all objects to be padded so that pointers just past the end of
-# an object can be recognized. This can be expensive. (The padding
-# is normally more than one byte due to alignment constraints.)
-# -DDONT_ADD_BYTE_AT_END disables the padding.
AR= ar
RANLIB= ar s
@@ -49,9 +30,9 @@ RANLIB= ar s
srcdir = .
VPATH = $(srcdir)
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o mallocx.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dyn_load.o dbg_mlc.o fnlz_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o mallocx.o
-CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
+CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
CORD_INCLUDE_FILES= $(srcdir)/gc.h $(srcdir)/cord/cord.h $(srcdir)/cord/ec.h \
$(srcdir)/cord/cord_pos.h
@@ -64,7 +45,7 @@ CURSES= -lcurses -ltermlib
# the SHELL environment variable.
SHELL= bash
-SPECIALCFLAGS =
+SPECIALCFLAGS =
# Alternative flags to the C compiler for mach_dep.c.
# Mach_dep.c often doesn't like optimization, and it's
# not time-critical anyway.
@@ -74,7 +55,7 @@ all: gc.a gctest.exe
$(OBJS) test.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
$(srcdir)/gcconfig.h $(srcdir)/gc_typed.h
# The dependency on Makefile is needed. Changing
-# options such as -DSILENT affects the size of GC_arrays,
+# options affects the size of GC_arrays,
# invalidating all .o files that rely on gc_priv.h
mark.o typd_mlc.o finalize.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
@@ -92,11 +73,11 @@ cords: $(CORD_OBJS) cord/cordtest.exe
gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/gc_cpp.h
$(CXX) -c -O $(srcdir)/gc_cpp.cc
-
+
c++: gc_cpp.o $(srcdir)/gc_cpp.h
$(AR) ru gc.a gc_cpp.o
$(RANLIB) gc.a
- cp $(srcdir)/gc_cpp.h include/gc_cpp.h
+ cp $(srcdir)/gc_cpp.h include/gc_cpp.h
mach_dep.o: $(srcdir)/mach_dep.c
$(CC) -o mach_dep.o -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
@@ -113,13 +94,13 @@ cord/cordxtra.o: $(srcdir)/cord/cordxtra.c $(CORD_INCLUDE_FILES)
cord/cordprnt.o: $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
$(CC) $(CFLAGS) -c $(srcdir)/cord/cordprnt.c -o cord/cordprnt.o
-cord/cordtest.exe: $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
- $(CC) $(CFLAGS) -o cord/cordtest.exe $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
+cord/cordtest.exe: $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a
+ $(CC) $(CFLAGS) -o cord/cordtest.exe $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a
-cord/de.exe: $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a
- $(CC) $(CFLAGS) -o cord/de.exe $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a $(CURSES)
+cord/de.exe: $(srcdir)/cord/tests/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a
+ $(CC) $(CFLAGS) -o cord/de.exe $(srcdir)/cord/tests/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a $(CURSES)
-clean:
+clean:
rm -f gc.a tests/test.o gctest.exe output-local output-diff $(OBJS) \
setjmp_test mon.out gmon.out a.out core \
$(CORD_OBJS) cord/cordtest.exe cord/de.exe
@@ -131,8 +112,8 @@ gctest.exe: tests/test.o gc.a
# If an optimized setjmp_test generates a segmentation fault,
# odds are your compiler is broken. Gctest may still work.
# Try compiling setjmp_t.c unoptimized.
-setjmp_test.exe: $(srcdir)/setjmp_t.c $(srcdir)/gc.h
- $(CC) $(CFLAGS) -o setjmp_test.exe $(srcdir)/setjmp_t.c
+setjmp_test.exe: $(srcdir)/tools/setjmp_t.c $(srcdir)/gc.h
+ $(CC) $(CFLAGS) -o setjmp_test.exe $(srcdir)/tools/setjmp_t.c
test: setjmp_test.exe gctest.exe
./setjmp_test
diff --git a/boehm-gc/MacProjects.sit.hqx b/boehm-gc/MacProjects.sit.hqx
deleted file mode 100644
index 99dff88b4cf..00000000000
--- a/boehm-gc/MacProjects.sit.hqx
+++ /dev/null
@@ -1,886 +0,0 @@
-(This file must be converted with BinHex 4.0)
-
-:$deKBe"bEfTPBh4c,R0TG!"6594%8dP8)3#3"&)e!!!"4UiT8dP8)3!(!!"50A*
-
--BA8#ZJ#3!aB"#3d0#'GM,MBi5bkjBf038%-ZZ3#3%)Zi!*!8"@`!N!6rN!4069"
-
-568e$3`%!UbqAD+X`19S!!!Ba!!!,*J!!!F%!!!-PfTmj1`#3"PET)d31)LTH6H4
-
-#*AqG5b5HI*)QjY$IIb00%ReTJSi6rG$jG(bZ,"Rc,9Umf[IRj)6FZ-j`GfGR)#!
-
-m-#qLqB#cj'G%46qffB3q8AppLXKc+P&*il4FMJMq3N32r[U,(PlSNdrQm-J(4!p
-
-jK)NHmKJSHY!,&chS$4)pk%8mL3I)B0'$AU6S3'q)k%%[5[5J&ffa#68)0ZM&#T!
-
-!*fHC-2dFZ3i83[Vr[4Xh'+DNQrm'J)rrpqe%ST`,FeVi6b,*qHH")4eQc28NFMN
-
-ZT*m,L"Y%-`pdAk6RLHDaeVV0a,,@P(4UUK66rUM'8bf91llS("lTh81)MBQ+4*q
-
-rfHENEhD)Ke#3!09'M%bL[P1+G88fa$3e)5Gpf0kARpBf*6eIH*0`ZBHR%ii"PbN
-
-+D&*)688M)Sm$Bm[cCdDjh2YIjmAc`(TVpi*Vka((A*&Yl@'LTSH1M*AMP#,2[A$
-
-(FHA@S"dL4dER#3b!EfBYem(C9P5iGH"a-bb-AL(F"bb-AL,F6)%a9pJUL,(hf%B
-
-TeQb["X5ib4DQXV!-fa6&mZf&3,(C&UDd-((SpeMBEIB`8Zc,BcZR3A5'X+jYj$'
-
-6)6HVV+R[!`#3!`X!(E@*MFQ%R4d"))`m[3JM[c)bBS54Tj'M(AP+MK&f%VD5SdG
-
-SANFB@3Rqc$Am83(+)`"G(D%A'9!bBQ6!b)b4Sq3SH8D1NDGNX$)bBi54!51--$*
-
-Kj0L!M"KKK"dC--,)-h+-6#KKC-$)-F)NamL!!Z06#X!!b&%bBUHp8RcN'%%6!b,
-
-i!!kV"`"DLHFaK*!!"Ym4K,,2i2X4c[,`c5!GIPf!ZcNi'8'VfJFpSfdpq+CY$8j
-
--V'f-DZr2[36#1(ael5hmfT@1cSU66D5pqDSA89pdTP-`Z[jj6T&!PmZBFZjal"&
-
-5iG6#blE$+&kLh#QZ118&(0T1J(hZ,9)5MJ9ic*qPI!ac'RJ96QMZjSbkMq()Ui6
-
-B+f,,#'N1icbM4N"aaBr1`3Z9U'8RY'XAiVXFKp#&k2D5Be%VCdh4%,+2QS'b"Q2
-
-%0PNT4rE#%kTUFqYDM56bVjfe!p8MqmL)1VmjVkJY`U[*$&*L3AMSpB@LCQ*U&l%
-
-T+3890rL,V9klFN*4@f0UTf8Z&&afN!"4GC6G8p3fN9$4+4[-@DAeK%lej"@eAAL
-
-eU@&4[Tm28%mqqUkS(F+VDa#lB&'rlRAllRP&l460Qc,)MHR$jMh@$8Y4Xc'e`cd
-
-ZE2AUUiH+fK96feb$epq&'RAQeLG&lCDjmP+"Kr8k9#qp'eI8RPf[6R$dS+$UcqI
-
-ELYSV[*ETFL&j[@lr803qd9I2A#bi4Vei3*d[+@Urk*!!&abe0HTVm%44"i4A6JN
-
-c(2I!kjRl6a9e813DK"A6p(LjRZZGaGH+1L5SiBT[(6ekd2*ILMSXU(l)#m3QMDB
-
-V+QTG!r*NG#RQai#DNh4,l0&!Ie`dYi98Y1%1A$5hKP4,`d9cHdKP'LkD@q4hYC*
-
-%dfdLeCCNN@i9UIBNLh5l5(8N68qhM&4R`d9cfdKP'bkD@dHU+qe&XRfNZSqc10j
-
-#8Me*&ZNfNZT0hSYd+dP&ri-FGM6G6P,p5D,rPNT0`dQLk5+6'NLb5"HDe'$L)Pe
-
-X8N2bj-Z'$r$6-$NZjLGC)1lB-"jQSff@[ak%LJ[rI#%p2ddAGREN(@"V+,S6CI!
-
-I!!!0$3KRBbj38%-ZZ@0M8&"$,VN!N"#$BJ#3%4B!!!d'!*!%rj!%68e38Ne33d-
-
-"!+X[PfqV-$P*!!!'-3!!&UB!!!(&!!!&C80(jji!N!BMM#0%$L)UANhN3L9rV@9
-
-B`f#c2p$XpAVVCc-[`k20Y5bJ+CTHPScj`Z'!lmr*#EPaRH(ZcR!J!!rqMKG"q)#
-
-cj'G%46qffB3q8Aqp4R6FA83PM6`KUjaYD&IlZ@jDrY"pk[b&AZrdH*kFbb9PM*S
-
-`4Kh$c8Lf0bVe+Y`Q$amM6mc%*C1(jF&1bFSdGIlLpc*04b#X&D8[&6R%+-#6HhJ
-
-kX"#A+Bp6%6RGkB&kM%'jh$ZLmam[1Irq,r82rGM"5H4bh1ZB+b"Z%&-pD)5CL9(
-
-AP(4UUK6$!(lkH+UPFXFARF-MIHHMXf!5Nd%SZYRQj'pfL)G3N!$94X#(q25G8U`
-
-VXL'QU3Njk8[phV2@0Q92J#d6rA2N1["[!%c(M4X-8p,0IcYJf2lRBmD2c)*RQEF
-
-68m'9jqq*MjHTji&GqDp$kh501r9fqVPJe4iQDRS)L!)ELqiX08i#@40jpP1+F@p
-
-iC&))L)Qq4Bk-cK-i*h`cDlN1cMBUbZA3+beKhX*-&UD`X%ME%F91fHB3BaCC''Y
-
-KNba-C@(,"-40Yl"l,#c8`YCDf%#"XGD%F4m3'*i'k"iah[Ddam+k"Xd3eV@02'B
-
-bj'D90I9p!!!-q)[jAU2HhQ[NiCQC&f(Ne`JR!hlN1''4Sjc`)hcL5IK+f(@8(q&
-
-(1&Nj2XreTBI[M!0dGB4'MK01#CFF2c,JK"*1MNZ1(q&(11@5ii5EKimF*ja``Np
-
-#bA(#bBL6BpQ6jq5imT-m2mQ!dq2N'H&2RT2M%Nii'6$J,PF!#N#jGS3IS9Uba%G
-
-'A-)*8[#%!j-9'#r3@EpUPQ9+NL6$ldj*kVS6INIK@`*q'q$hGRJCPb,`pUJm(fQ
-
-3!#mGrdQqe$Nm22hkJ2cerNp"i3$m4Z62S5YA40V([V`MbHF@)QPT2IN@3@$ceHm
-
-I&dT3GqF9K,'&&8[6LKMTbQ6@-*%bJE#4RM,b'FA*'VC5`0BBdTa"@aNXM#)mU'"
-
-N@d@XSIKMMiMh#RbbLSjLT49GG9"F84)Q8QfN&![N1hK"A'V5F,,dJIF@+`iNJEb
-
-H-(5Nar84j!"*Q54MH+j&08dYQc,(ipT9I+aFqIQc-XP313&803UUPPD4*+UAIlj
-
-$U+jMAP1QUSfEYV2Qp4HKfZ#TYQTCT)hEaCbp+ZXH0"m5USfHDV1HbL4cCT@41rr
-
-5+d+eL4&+'hR90)iLRp$LYcm)e5McQN@UMR#&$kKqr%eHU-DBejbUCC-k+P4N5r%
-
-Iha+Uc5aj)kVfm*'ej*8Dali5ULfHDLah-l$Zfer1#G9@6l8TTf*r,RKTZ2#Q8'h
-
-MA2&i%MYq(0aCicHKfPlfDYLeJ3*FFEG3l@"HmfJbqFrdHU&IU+jRHE95BmQFkJF
-
-29)qp)93hX!aCGLfYP0!jSEU4HF9)-e8M9rADGfC4U(BbVVC66+8XR2Hj2RAmGk'
-
-kLDNk8`@p0[6F"hrG,e3h`kmm(BhDMQjBm@`ejDH1pG)YbUXYM'Y'5aD`-H(VPZ)
-
-,*i6A,Nqe)D1Y'5@UV@HM3VAE)a3$3MT+9jAGa)HI#%*E@9ie+jmf-PA9dY#66`Z
-
-[fkMA!l&$eZ3)bP996crcal6`ZRdT$9NG0S#+V([`rRZ&eae,A%dMGB2V4H%9YPL
-
-LfZ3B194,NC[ik!QKZSYlaE"deVc1$3[9(XVeFJIG0T,9**@'AVXJZ2Db$%'!,$a
-
-e+d2+8SES`Z&RD1(C`m,VlM*Aj)cP#M@ZlJI#Djp(U28`fl)VL9dKY+IXeFM!HRJ
-
-MVc0#YCpj6@!,M0VrHYh,CMQN!FBjl1ZVEPhjaCK)``"6,6JiU@@ekMjdmEEPI@M
-
-3DpXKj3pi+f`LFFpIUPrF058)N4X)f4ZQ*P5c1[&!pGhC4i@Ue2BCE"bRL&haLRk
-
-Thb#ZUK&ZK-Kc9k4Z-[QKhdaf&1KhN!#*#IdZ-XfJhdPQ)I6l#![SYjD'HXp$hdA
-
-f$1LhNlN-r4DbV8$I8iS[RSEqj#URqY@$9b3dJG1XG))%khUHJMX,Vh896Z%"I%B
-
-PFK1MejpP2[@,$LpbTe[Q%h#[hhai0BBHF+r-MrTeL9G6k!!IKHa1rmf2qMf,9c6
-
-d)%I[5Hq$1hVVq60(`H@-9fb&cfkb$BBDc1-Ck@@#jrVH%0cXH$@cIK[C#F&2Q9X
-
-[qpl(HTpEQ9F`KqVA3&iYS3Pl6#ARpIXMVpCP6[+ma`PkbJPkbJPkbJPkbJPkbJP
-
-kbJPkbJPkbJPk1MHKTlbJTlbJpqGlF2RNe4CD`1XDTfUZEYjDHE@[F0T$,KbK"Vc
-
-mA!9AAPiGS3Qjm[HQi+l-LraVj'p1i3&mcNKce1@eZ4pFX(PY@1(66rD18)Im"eF
-
-YAJ1K#AYcK92peXpVBfM#AZAIKi*r&r$U$"h)dkhp2[JI!kp0S3GjhdZZV))A!43
-
-jH4kk(TLQKF4pTXhHI!ITRb%hcX3KfeN#**1EI54a"'@Z8(9Dm%D@b"Y#qhm!N!-
-
-0!!PRBfaTBLda,VPM8&"$,VN!N"#ah3#3%!9X!!!I``#3"2q3"&"56dT,38K-!3#
-
-TY1))Uc!eD!!!@F-!N!B563#3"2$I!*!)22J1`2KbNQaPEr+hGEX``Jk!Vpa0&eT
-
-RDl*eSGZ&%EEAc@iGG+hAYBDRapHZd6ETQH'lV2AbpMVJ4lN,ck0G4lMb)fcKAQi
-
-*AeLhm1)VRfPGM,"Zi8pBG1%a3VYZi@m,@rM#2'iAfhjHacE,K"[bJGYB,ZcNP&#
-
-"$cqJ[fRG`SmXR'aMC-H6r-)AXTaNHE+Fj"HkN!"0"R[G!H4jITB&`!(!dKX"PZ#
-
-Z+PX+S(dCS&YGZI3,cN3L+P4H)V5R@D3p,54$JD"3'!j')mhRcl%mUJ)9e2PVUaF
-
-j[6lNX)ll!4,jajb6UrZK!hSTX[caD`$ZIHl,pdeVm&EaLeKG-YjQB6AKT)84pF,
-
-kB$+55%ID`b-4QF0T19ckfSl,d['15$X-4cTr0"2!dIR5%1j[S4JQa0,J4lT!pkc
-
-"EjcQ2ZmmNDF36,1DH)X!8($N3ihbR+mcX1GC!E!0fi)+ra)rCUL`#HU&V9)ke`6
-
-IhTB!b&RK%B!&4fA8Ecr8+8IBcr)4Z8L+$bmVaA0$-Lr)$3+SMf0Xkh!%1L(hiM$
-
-H56i!P'Q(V3ZXrmCRE,f[6f'0N!"Z$E6%fl(AqCL20Ka-#kRdjh`qA&CRACe[!5i
-
-+PSiKjh)6PJM4H$#5%&U%HF#GqF0F$MM6fH)T68dFSQ!hQ*["e3hGME'TS#e`Fmq
-
-Sl`'0qRTZMfEcM@b8M`(hV,a,kqB4N8iZ[4Sh5b!9ddQpT9YP#5UK!NX`BDbr,"E
-
-!TME)X#08Bm,*$)fP2Ci@G1bTGUbETe@@q%4QL60h[2d5)BQGX-U5,*6)q)99'NX
-
-bP3a1pJZTH#BC&"!P%4'5XP`!Fm82LidDE@#h&eejC#m'cSQd"k1C&S(CD`*"Va"
-
-S%C+TmmkE6aJ*6S3kTd8)4GS&PNjQ"#DY1419T&!JQT+cV-0*5@'9$$5+K-58Y"%
-
-N8Ea'&)q3!*!!UeBZ'qd'!&14D",LQVJ'$qTI1DUU3$%0cAD!e9HMkl`KaGAASBj
-
-TJ#pMhSb5Rq0c+LJ3l3LJkD2dcrJM2Q%3Kh&mZL-JR(&m+L$L-)j29b,%B4br8)j
-
-X!Y$j4ZUh`)[eI!A!R(d!4AHG`LH[d[f@re6*b2mAI`)H5F0aI+2XYq2iC)+N`6M
-
-qC$b5"Z2ij,N%KHI*24K!$k@Plm*Hm'Rd8-bci0h@*rK6m%JDM[-[aZ1Nhq+IKNH
-
-UJA&mE-V&'KM(2a129!2Mq2,5(2qIrSHmNfTSR2rTH+3D'XHRfL81irM8FE,Ep4r
-
-eTUeM[5Ra8bilkJJ6f!)lF0e(0'p*Cke+2Nq9ccEjh#UIZq6c&[RmM(3ZV*!!cL0
-
-k&5l"Jp4$Ilc)-m$9BDMqeV0m$l6LhM(EAX9A,10lG,aR)2GNb6Sm29&b0@CfmMd
-
-&Mr!pHLh'hX&p"qiPVV#h)jIcaN(YAHVY!-im,lH&lp&Fc$pX!KD$+,qKqbMQh",
-
-@BjDAX[M-KFF0&bH!le%r'GC@E`LVXP9mKXdeG)3QcED[U18Vq4jY2c-fD8XFl$a
-
-Jb0pEdXPRCYXVR!e1c(f%qF`GKAUQcPT3T6E-YjCF2GYHhq#[aqa0'*p@XJl4r*8
-
-qM(Fa(e1(MAb2DUZDVTq-SD2mJ+kFAj*ldAQmX-KFQf"C5i,E1fA&P2jHj`!8*c4
-
-Cbq,eU+LUqmriLrQ-H$8"RJ(GXC,YKXYCKk(M!EcN!3MV-HG3b@DB@MEAd"P5,9[
-
-2CjDYplkH1ckr$1D5aNf'jH[,p0ehXaPCKe@(eI0#11SC',UQT)X9K3qD(G8hK#c
-
-C@GQUfADhU*AQPE#2X"A&i-9KaAUdDe$"bpQU)@mfJNfL,U61YQ4RBFiKFac+[hC
-
-Y@49Fi(Ye4UjKII9Fl[b`UM[(Ca+6ZhF[@mq`0Seer)R3*#Y$$IcK`pPc%EI6FKZ
-
-I`IV"'%bLZK'Mdl!5jqQ+3J!feU'k*f(FZf(EGY@@N!!CGAmMqd9@CrDD68d'jf(
-
-3TlQV6AYhAEJlGh4$epjV3bSqBiDXKA!BPjeTVUYp1pI,DPfESAK1"2eSD[B-elh
-
-H#"KCEIFl0K-Um0E-CFr[,$HC6Hhc`fDr-eb-HmN5*`iSE-8)!#TL+mfKpUV"jrc
-
-$X6fMXIlRYZ5'5$I94YXX-&C(`""L$Dkf)VmVe*%)GZr'mh(#3i3EqlYKNKblRf*
-
-'9fi`h"aV43`ejERI0DPfA"MDB``XX)HHa#bYS3h1c!hCcPlQ0+mDh0Yr`mEU8Hk
-
-YrAmUXCIMj8SFBkA%6iNVCjRI%C(IMj&E3@l3G[C&a#hGId-rBQbXrT)c0e6q'2p
-
-eC)89`[fJmPd62,qrh"5fBCA-$%rb1d1R5hbj`ddQ1G,60%Q1l'T#EqB1)110@)h
-
-%i!95M+ekEiM0HfqSHM1k9UQY&%V$jTQPB&VZFVm*4FmG"[Acbff$#qbZ,a3IKUr
-
-B"VZ2A1J-[B%elK$paa&k8Z63JaakNVNdL$c1fP%+A`QGIJ'bm6iH0ZklkX(0S"E
-
-8jP*3Mb,[3pbE@&fLD'2RS@ZY1`pG"kj1X1j#2R9*X*QX*TAMbYcVef*YX2)T6FA
-
-Q@D$Hf'AE5@VBGSP+2*elSqN#9T4Gc"`I)"SMr!P3K8hPL)Se--@E+!*#j8qBAdA
-
-F)f`H'*JMT!TSH@V*`'V2IZI1K@DpeEljYRXA2YJ9eU,IcfjLaVQJjXS%LTUELM'
-
-UNU1Q*M@HTVX(FV[-AA`QqadqFr3i9[JU81PlSB$r%d$A3iqhZfXV+KG!GjBeeU(
-
-[-cfI+9deX0(XqqDqeeCrEqGcqm6iUPf$i$#AQd`B@p0rSjJ6NR2d'hX'fX5-"MQ
-
-MU,pRS%(-F-NCDZeUk[$*BA*h$2XG9RaZHj-D6bq3!1YJC6AD61@QEFZ@lXi09,[
-
-#3r`40LMRE"V0'C!!FecYKJh1Q(D[`hN%90BLbX@@Y!c8C8j3QmY!ApD)[GhVGTJ
-
-**CcApF6MTA!ZjkemqUrh9AKG,PI[cVeVI+q#h6`$QIm$kKcXmZ"@c&ph+[pbaRf
-
-+-2[6I1-)JqV1YQR9UpZ-&Cd9Uc'6i5P6JCdV6"8c-TKV%$1eQ*@af2(L22GJCe"
-
-VaTDFcfaEffcXh1Pef-$Pm$Vic)0VQmqbL$(+mRVQJpGcr8kVcZZakIJ-9F5"VJ2
-
-A)XVacTfpDfd&ZhSY"9l2XleH6rpD3Epa6E1D10FlQJjH!G34SPGS&qM3*fC3Pe2
-
-L`2L%lVY,CV!*T39qcpXH[fHHVQRU'%UAhk2&Qk`VKaD[,i2ZHk`cX2[6K&iQRrQ
-
-lbPXmS@QX)1Y!&RH`da"Y"8BfPYDc4GPC#3lV4AhlG+E(2&HTGaMM!VD)&65CaPL
-
-Dr4lQB&J09`k9kE(,mhf[0f[T[[2#[mfpH2-6*6k4bk,U5Z`kcd%Ia$UcfEZ2Z!G
-
-1&'%PEF2B1aKl$'0hBH`R',X1BjX`pP1-h6AD-aHa8TJD0Z"T@[KdIJ$5L*0!R+1
-
-)NmCi#mDEj(J5i`fS4KaV[49[Y[ASjjGJCfSIkdaR)f+)e-#cLpMMH4iTJQFE+B$
-
-RFiN4RXfXNFpBZGXAc[3QM,G2Yh*CMh@3!(q8lFE6#ID-P'YZ"AefKT9M99N2Re%
-
-Z5UJ[cKd0UjR$Y@%N5eQr[bVdDANH1X3[2[#XjcJ0%Se1!jKa'U#f[M%BE`p&`TC
-
-@-mfEF*1J""c`J'Sc4b0!`0Q1cH9X!e(3aCl!)H`k4qIhpfYS1)*',+EMMLJR'JM
-
-*XAVRp4,L3*6EFHJLENI+bThcfZ@BBX$BV8U1Sr-@+@iljX&F'M+D6*J-'5#(%1k
-
-[1&EhlT'("@L3!%(&RA-a6V0,2#9X9%3D8*&8fT'k`V(k5V),NCZX$kh*MY@GDYV
-
-4Y-8%c[bAlh!l-U6&69c*e@N4Mj-C)C2d+XbiMLZjUSJ3--Aq8HQ-$[R0RcMaPa8
-
-e&lLqlpUj[TGS[iMVqri'VZr9AUl[KhZi[J-YA0r"GUl[d&eFhq'YA0rr0h*pEml
-
-RqYlHa2Ap"212)[Ba!pGh2-6e$Gc+p3dqbr80[FMe`hbZAjA&I4IA2aN0'##DQ-I
-
-F0B%8$M1bX*!!6V&dUi!$KD&N2-DNDAZFBic&F2BrKF2r6-!j%"D+4)8c'q,aD,f
-
-3!-3j51B9SJP@RdlLA(j+(8X++A@L25E3BD9ki@,HV9l@i1F0$6KDbP$RC(bL'2*
-
-%ikP8)(QCZL15MXe30%"dDAVbI)DMURqBCV&i5b4dfDrbrk!LN!!@@#SGL#9B+*j
-
-N3JH#Y3HLV#@5r"fhhq@IS5Jp9LM&BLQF6+PSMTk2cbS%9c)KQ@5a90K#Sf4N5PN
-
-S5M[3da4hiQK)k+XiA(ND$YpSYSe-m)LIZ,6N5rL%!p$M"e)Z2G@JJJ8FXU,((EM
-
-pQ)@$C4*&(*ZN6`SqKSGP)q02Q+F@[iqA@RaFJFBHbCM4qfMF%h!%89`D('LN6e`
-
-k'KDkIh4i5)XM8r4*4)JcM9hKZ+)%Kcj2Rl4%aj+pAcSALTmN,qQmF&6[3Z`$k*0
-
-%H%M18RJEF-b22R&0qM&+6,@P[&-a!BIik*1U!BGKe64B611lY)`iBNHI9"S+Ab9
-
-l)JjKd5HT3V25,H+!P%`9Z`rkT%9kNCS1THY!pHQ6Q&%@$8)T99L%Sfhd5H*hI$J
-
-64C28Y,C`Djl#m$6b!XGfTmrR*X8$d@L`Y6QkdK+%4i(E8[b59GP&,"cqQPC3ih4
-
-MlA''N6k&X1iVfl4IfC%6%hNG3kaD8[4Nmd+LGcpXR+[Xb-XNFZZYEkLS`Q4G+Yd
-
-5L413!'S-T`$1NR'U9P55`+R)+U%aM8!K9-"b-+[Xk$GR5FTkh)hN*rJB5@-L'EP
-
-%j(6IK+GdbSlH-e9"XT!!TkM$335*3-%BFqd`miD+#P4)M`VKJ,5STAS-5DFJ,A9
-
-lRF6mdQ"V)#Q+K-c,[YUNl&M9XNEZ@PkXmY(k8'eCj+P3G[5T%69*)e+cY5@CqV"
-
-#$%SP0969B)9`fR3N*L#-jAfF#50kqURL8%pU-)M3+FmipZBILqkTH!E9YJip)aj
-
-%`mKhi"GMeDhkeqSZq1IU*VIi[,SeRcM3"dM$M['C$j!!BhcZ!m11mCN2&2k,$aK
-
-qi32[Hr5%Rh[d,hX-I&T(k6&F2UIBBc4(!m'9d93k(d+2NBr*-djj`D*SpBJAZ,f
-
-9j!86F'3iZ$+9LDAqShqJf[jh,cLPbr2V[SPKZ8BUA*j'UT'@jR"M,2UIAFerUC*
-
-hbU&Hqqk24KaUB492qKV`$C4!&+Z"V#$rQ"GJ24rmKPrCa6X4KAZ0c$d@5+lmTal
-
-hVejS(qNI[*91V#iSP&p#b,2@2paR1A6E52mJe6FBBMJ1dGJL*2+9p3qIhj!![Bp
-
-M('C8fB"h)XK)5,I&%TpfThIZ`BHa&(9Vm2+9kL#QA,kQIZdYiIaLYrARRVV2f2q
-
-YNG[k'UGr%8DeBN-EK0EmEAlarTd(p5,rIHIa&j&hIpETLXk#R@jbC@-b,9jkj$[
-
-SG20dc3jaep#MG,*Rm*9,kClGd#jFfLM2Qq@TmibVrRcNcU2@95h1CX5Efl"&%5r
-
-8mURGV@U5ZdHGS,k4EYRemG4[EPCrFjZ4PqYQYFV$Li`LB4cI%5Ak4CIabTc4cV5
-
-Z`5pfTSPdXM(B'Xb,d*RQlCVl-6rbfNK(iUpddhemB9))4J14@"k%hM42efh'efl
-
-%*i192U1qBE',qSa81Y2F(%qfjbIV-mbRlM2Dk!QiiGN-X@CeBXhQjHJG2R%#l)P
-
-%*m$r!"'46R)DGS+2k[XNTp(qiGGq@r81$FI)IYZ`[)lZM!cTba)YbQKh2VHq(T'
-
-iYATPahXMf583L9i#-b!5'SA3JP$LMk5FV"eL5P&e,)!2AM(fqq[&rAqqJEX3ZJ0
-
-4GUAcq1#I[$MlrpXrj3jb$ZiY+2BkkdRM@qKR3r"mcb,mia%m2lM89dZ[Vqh!-,f
-
-QqNbpVjjZ29qJCq04M`2d!b+N'UT5MqGLqX832%q[Aej$mA2Gr%)2D,J,T!VQVUK
-
-`%6jhAB9V+HAI4,rjJHFl+Pb,m4eQEZZ5@KrPp5aF@N9GqC2+ql1S&YkPdTmG6Gr
-
-!qEV`09U+&4c&223NLQNk-DpALZNdR1mDqVXNM'QAB`crlBKL%mp(M*G"*FCZ`&J
-
-DZ&cZG*Ki-f,J@mmLMhX`*R29E-FB[Qe,XDNr4DlPFZc[1GrDKlkqQYkKeBBaYUl
-
-YEqK(@E3aM+N[HKM14ThU%2X*Hb(-`McNHXhpB"3j2BDaPJB6I!Ne%&qEaD`r`V`
-
-YU-G"k"3ar)MaKKaEKl'$NQC6hd1-Lq4B$Q0G-XB+e-BRajCJ,+'*V3bd4NrqAp,
-
-B[bJT[kddmXG*R(e#AIa5)9RRT[cr!`!!$3!*Cf0XD@)Y-LkjBe"33bkj!*!3qL)
-
-!N"!0"J!!,h3!N!6rN!438Np+5d&)6!%!UE6L#+X`0A!!!#*k!*!'$d%!N!43[J#
-
-3#1j"$F$iCXbcEQ9ffFS2dS@*jbZl63NYVcACZY$0##1XPDZ$V[@ke[$dmVQ6K5h
-
-FYGEmE+(Rmc@246PGf0D9hF)@VNAi`VhS`KGM(GQA+lmmdfiI)f`c`Tq`63P23V[
-
-Y`VEH`KHqX)9f(@(E*!Zrf-)@IZi)AhKXi3[E,M3j*432"&!HrHaD@&$M#f(,qq3
-
-@XL1hN!$"3Rk6AcKCb%+1%di@J&@""TeG+a&(42abSQ*m9@@VL(4[%29TUPEGj%S
-
-NfN09'd1a&"q0T8,*F(-`0#85E)pZZ-eZrEB+Z[80G6A,A6ir2'5jYd$i*mlPdrI
-
--@8-1XA6I6r6dUG[h&cAjUSAPI(dbhQEPDb0*+mqX6fN-*U1*9$3@'8GN$c0%(%0
-
-GelfTH&Fd4Q0)jLrR%MNc2aM&pcf8d``Y,Ak!B(cHb*GQH1E2Phb'JLQq0Yi5)P*
-
-IZ&DMccNrDX`mDiN1BLbSE&MC!)B+3p!!(FM4Z3"pmf##5,64Fd39&fA9Eck6N4(
-
-q-Kr+TK`qGQ`-&dGPAb51%'Q'J"dB3bK$iZYMHPIm%$'QJ`j8f2l6cq5j@TmTYD&
-
-8Dh0,2)CCjkGqG*&J+Y5CqU@IDmIQUUrh9q!`X*4GG$59b(1#DBYLrXT3Hc`B6B4
-
-D3NZ)Zr'(SNLFq4ETPX+0#01J@-c9Mci&E"ETe"lZK'B2D682F5pVpcl#6cM0`cF
-
-VIh2RdI%LA6N'$6l@jXi1I@kfp+LX3395@i-*Bq1p(FdBDS-m*N)0#&FB@QXXRJV
-
-TqHr&d$F[UDca!YiDjchaf-C3%T1`bTUFNM26%1V@@T1GbH#dKP"R2*d-KU#5L)D
-
-5FVQ)&NXr0"XEY)Prh,6j`NN!Fk+aB(Zk*F3lDTZ$[P"c5bMC1Arq8UD4i#5T15f
-
-KF$3@iP2*G)M2RB8&#LRFh0iTXfaMT'5S@aDD8))aK6DZ*"9[2BV(P+51c4hG,L+
-
-c53S*k44Xa8Acmd49U9R$Xk-p6,4P'e,Rh4bZH3"e6"(G$Pjab5Ikh&MNk*3JKBH
-
-am`[rd,p4KJ)IdrpGAkQ!SYrdArSB+K6p(4q-kaYR%DeiK@MHTTrT+airpFpf(!c
-
-C6D6hMrH[fSGq[SpSi@NLdj2ApC8!q05rrM0pH5A%p,FGr*AqP!RpYPrTjl,kIr)
-
-Mrc0p)kiXJcl9Cb(1%'6hP`BRQ0MP'EU4U`lF@CCrSLp0(%#3!"HAp98B52*lSGq
-
-&ZrfkrM3CD5@kEp'%2R+m!*ldPFM#f(9p0R-`C#rdT5&)cLr`#Kk#rMULrlIXZ[j
-
-d'6P$Y0N+!(Y!54rDdc&h'$"brDYqB3l4$[hhr$0$4PE$2eXNb2ieb2fErJLM)1T
-
-RZCa*(rQIH68r2Xk[*I+#iKreEj!!r52r-kc1XRmYjSpI3ai@B(RaKIqI,BSqG$#
-
-E'MkH69X[ckB'iJEe$Qi`RhhAFB-&cq&lKKZFKRc"-D9m50)#'Z6Fp%2+jFLffS0
-
-N5Tj%4@C5"GI&cC(ZFcD,h$e838lFZmM*m-eX'F$dP%A,,mqff[SF8$&N-KPiM91
-
-9NF2XSa0J@f1fH(J8"hGPCVYkTSRLJ,V55r6R486P'%J,"U5PdFrVi(p*UM20Z#1
-
-AjGIGE[0r"EdLeqdcjp[mNSplX,Y)hCYJ5aj0I@@G*jb-Gm65lHf-'iiR1d+aG!I
-
-M4Q-YACfKpTEfZ,40CpQLY-XkZ5B+lNFp6BS(cVppFXHLm)JE3biI%jRZ4TD29iR
-
-SY!R1P$QEBbjeBD*lqi'1GccMbIje'bEC1H@a56dI1a@*I@9pEqBF-qYcdaaAM`b
-
-5FjP9B(QLVT*e4Aa$'kXN*T*FX[j[jrbLXcJ8Me@X&Eh%AL-JTT!!Gd4B3#S&rjI
-
-6(0UBDSje*M'BT4+G-9BhC9*@-5jcH$[1@!XpJKl'$ZGDCHXmRb03ICB4reapCC!
-
-!(Mqj("6&rGSNfp+B@FQGKfZV'cfXb6ZLR8&V%2h"l5[mJ8hjJPR%eT0&kPUA"r-
-
-MPcHq*D-)FI[,GTp4[[$$5jiqJ&BGP+G#UkjaI6!H#dFM9NbNa28pDebXI1(,,(N
-
-ED'bUV!CChjPULFDCN!"U8NG00mXke@ZV@1Ge4VY$ke-3#PpeT"PAmJT`"+9)V,N
-
-pTl6IHLkVI,'RZ6PAIkpR2HXM[+GCRdK'0dVZpqGr6kpmXC'CT5KCd3'NL33K%LA
-
-eT(2pQ21Q5[3dR+GDX116UUkC9$)S5UXm2KGcINq`Y6NTP421bhiMS(ba5j&Vj+N
-
-6f#aTQ1JNeElPhNVPLj`GVbDV%DYQDdZbmeS[j5Xpee4GLelLG+PS4`JbeUXka[&
-
-k0V$H4$f6H2FMHFHjNP0bI"Sd(Fh4'2DERk5`R-%10TmaEFjrI`$I68b$mrG)kq6
-
-aHBBP*&LlQC0%8Xl9HQQfr9b!L@&XcMHPT*eJ*QI3,1Ibj`$iNqZ&q@YbPJ1Ha&!
-
-Tc3P+,rc(E-IjIaGE%9QEH@4l"'92bccba&FiN!#)&l6[jHikPAbI*GrYmVe9[[I
-
-)phhbr86Z2U8bGeIk!)'b%TGV)mAiNDCMGeGHc9GI%IUT&GqZ"BjUSA+ed+mA[-2
-
-LXC)(FAZaC"ZB'D&IrCc3Ep!"HarI&r!YF8GmAD,SLj2'YmVA4CaPLEK2k0IH*6a
-
-V*Vk$fS9GI4I"H5aL!-[(@%*ka9$HA3N5qMA()VUDA4&9YPT)mi[cZX*6&cM@eJP
-
-93VpZN!!h"R3P6RiqmI$[+mN)k3@15PH6#pcRH,qPD`T@&9NVUY3'[UeNf`)(%Um
-
-4l0h!LdSHK&T$P4pi$qrR04'Md+mkS'(0E3aI&)EejF*+mAAAd"56T5l"Ckd*lZ6
-
-dYG-("ec$9*M3CUehlN4&9Aer+0`PT+AR#H3GeRp3FMK[%pq9er8Y223JLKM!HEY
-
-N,mdU@jbA#DY@la65UhIkhK'(PTE4BPEM30kDR@@'[UIiiUc6TNIh["CTp`k2hPr
-
-5`jXLjbc1QSI$eZbmE28#KdHUPIB[)RkQV95-AKqV@,pZ+bUiLHmHp@@M''(eB8f
-
-f*6X2R,FYF5Vrc4ePeE6)rfDaf,5cCM&h@d69*`VTa,5qikYhmZK0Ble`+6c9aU-
-
-'$C(cf9ZKQl&q68LMIi$490Bh%PU%6PbL0f'aB1Hl9(X5aT1l$Kj@l3YE82GhXer
-
-JkbdqLcQ3!1Fk6iB8YmemmZL+iq,&A6dRGi493YT#@5[6iERXA%YphBr&!El1[CF
-
-+&dD44l1b0lLIpNA*b0Ie[@mhS`,[c9hpkT&bXm8F@aUa0,JLKIL@V(3KLJm!)8*
-
-&l+8LDUmD1G8`KVdmJ3fHfLH1XVUTHZhcb&J6TE``hq4Z-c@i`ef*B0pah)HB(K3
-
-H'HbMU6,f$BBChH*)C%0(+c3dM1IjL9Re`SV`bmEQ#NIi'&Lk[$Dk84behl,DCHN
-
-H16RiF'r0K2I@`Gr,ZCIaFJ8(9XVm+EKbPreGN!$mr6@mUF84qbhVQ,I8i-1$d1L
-
-YqD*,(#erAVJEVY!Kh&Y92c(6UfI+c4%lZQ4ZC'U$+c`cjjFl(c$,5(pJUS`F$5#
-
-EZE0`h)YZC!jHBaAMZcmFjCGm1&U$M9+Ne&j+T4(,h&)bVh&lrSC-Tmk6jY8epT%
-
-+KrZQ`[0dKhfNlm)+9rKGp,K6bKpRq*MNS4mHqT0LLL3I0lp35RH%Cbk#'pph)mE
-
-6[h0S,fP#'NXTD5D86d2hbhap`Y5EHAZ(lFME$j!!1d1fSr"6Rb5lf@C@BB2jcJl
-
-d"Pmq29"SQ8HDhKll%9B0qe'T%Lq*l`B@mDEXREcc)d9M9,K%USLj(+VSJHQqK)Q
-
-BUR$*mLCd,r",+)phKPA01S'YCFRQb(lRkmXX"TYMlpHHARDS*k*$hLm)m'`$`C@
-
-&''S*&!*9bDJjS-&YYQGB2'VT%G,Cl`MTLd2Sm'j5'3C),I`f)I@3!2%1,)HU+UJ
-
-[bkq[4qlc"L&GfMhFDr(rrZQrf[,p)kG15hMhd4&b@XV0CQ"E"aq41''CBqMY(fk
-
-6'%db`c6B2p`N-G`b3k2E`LC4PM$L%f0jKiiA$`FdZ,h'8JHGYGjZ,MFIA,hUZ$K
-
-Fiik-#KIi%CQcHi)c,(2FXEaGVJlG5DIV!UPX*XE&5&T'QM)AD5aPC#KEMpRZ(3F
-
-@d#@FcrhLGd[T9XjApG)IRkldZGhZJ5-RYrVI*)HP'-lr3A8KTMck#[J2AZG[`VV
-
-Jha3@r)a[((G3NfNVUYR5CUc-9'i"NmFYABR*P@C*M$5iH4*6"eEDLVfl+"l+"(8
-
-@M14#qZ$f$FE-%Cr66QkRcbQN$fhIF,09`KM,jee+2Zp$4fakRpHZ&p+X)mlfR0d
-
-"PD(-NB(YG[A4!D[DjheP`1FGh"ibp'lGS''H'jf"FrF4Q`L4&ES+2A+LQ%dj*8l
-
-JqAe2P46cqDAU"Zq2[3hH*IV!V%Q9RJD[$Y[IcD0hlLbM[MffBNarf[!E,'IqV1S
-
-aElL)9fHGF2%%2`0UDi(dPMEbbl2c%Kck4I2iE0i!RV[80kDaL&r1U`2Q5CH@"Lr
-
-[j0%0QdI,$*Mbr0mIb&Vl[VlL6mAA(hfaa#pj@9j6KDPc$R)3I@Chp&h`$&mbSC-
-
-1!RXIf22!RJ6fYm!H!,BEf0m"Hh*LCMEaT63VNSGE8@5Q-%`Tk#5JFa%k+H!Y`!-
-
-bRJ6HK'V%dHZYf,SBN!$R'c'C1LBRd`93$,0Ui1jQlR&I`LU#Zje9!2GEQ52F,Ia
-
-k)@hM(PmfejF`2MlEaQ@pYK(Kfraah#la*h*F5bXCXX8fMUr1HS@dXLKKFl&i-D,
-
-KRHjGikbVar'Y9la$l2RB6pmR,LdS'+0CVLaC,H`"dT@r%Z!F2cScr3P3LVMhU0$
-
-RDQ6lXmIBIJ6h2FZaT-(pd#Tr(GX$[`!BEfIS4+1rNEepHBe0*1LCXfaR!QFkYKh
-
-"[C!!E89`RpfiTTEKYhU%C9l5FSYb1eVZ[NShdqFHU(5[B[`[Xmd%lNp8ZZr%``V
-
-Z`-Sk2q2e,eY9c6DeamCH2MPq""hf),AJ0Z`'mAk4BHU,`2"fN@(D$$6B3eKJHLe
-
-ijh+BEJhfCmrNX"X@BR0iMP35pJI3b"!RLM2TKUm#`jj4mR%B@%X1Qrhh`&k8X3q
-
-"I82'4(M5h,f&[F[64H#l[1e2f"XKA3FdhPMh,0f#,XX(PR*-SARJ23cXC6*+rTj
-
-($GBeQHQ,U+Ad,JkXA`G[(hJpP*%d'S#PC1a"B'rNDPDX"RC'a[6!hT)eeX&I3XE
-
-f-%rDMYpUEQfrmLafmJQYmYTfr+%XjmL[Mpm65YCl'2rr!!d!#'GMG'9cG#kjZ@0
-
-38%-ZZ3#3%%0D!*!3(m-!!%+&!*!%rj!%8&*25NY"5%`"!+QdiJLV-$9B!!"5l3#
-
-3"K+K!*!%$I3!N!Me"!i!pCQCc1abX2*Ef-,&mj8EA@KjV4fRQfkf--,fZP@[Eld
-
-Z$dq2VmN'A5Bp-hbAY9lHAJFXfQdl+AG,Z2)ME*&GEJRrA-libQIDl@-,fic`*fc
-
-6K5HKhAEKE`YIq-)mEQiRK(pXXmb@iapGq-+kKCfFELT3q1c,IZ&ZXPf1@pl#b%)
-
-ffjdZC,)F@FK#&m,)B+r,!D4[CPq-FBbaqZ@-eH&@A,@%-I9,M(@V+THFE3i'I@,
-
-PFV%p`R[E)f,)lA5*'SmV)SBMaKm`"H(DkkSAQQdeb1%*lP8%I"Kcj(3rX&H6m0M
-
-IZTkaqjrj`UCT$PZ9X*!!V`m&fSamV5GNj#ReR!CAb"Z-H0XpDBqF`ePa(%eGaiT
-
-)S-2EcP+HcTr1B+bXmm9Kh'q$6Mf`X[$"KF4R$RhYV2*CXk3m49H%V`fdL)`T"cl
-
-J+-2j13Fpcq@-E8&E8'&IE%H%!Ne3,pZF#1HDf2Hf""Q,&l1('*Yr8%EphJ1GXSF
-
-r%JrNr)3rGBV*(aq@mf,a)FC8Kq$ER2+`6KCr)B9h0"r'+0,%0Xm[rQdqSqFB2cQ
-
-eBU69f4*S4krcbhc8LClZG$iIR'*cIAh0I"abUXM3iXkAEq$(ilQ,49r!j3f+,H)
-
-maNhp56c112ejNK@"P6JkPXIB&fjK8aKcR!drZX6iG+jqq&li[TdQiqM4U(!CR@&
-
-rGU+(,&FBA8QAdZJ+kKT@q*eSAPdm1Mm9!Sj'C"RE!a%aQhqm(IAaK-)B'-FE!ha
-
-jS(fj'%,(Uc#'FK,*f-@9@FC3113DEaI$J@M)*3)Pk"9$i'!+Qm`pccf[0,(*#J2
-
-h%ZcNS8*JE#k(6ij38,[0q$[cVaRB"FIjhRDA,pSLmUCDTmXQ1P[%8(M@V%X))mK
-
-*81HhL'j[ZmK(3P'46jb,ab@$h%jI@)iU6J@&a*8bd!J5%NZ'TC%NDKY",5%K9lA
-
-%%1kQ%f8Z9IE(4kQ5X*9Mq!UPK%dirih2+53-k[E(m!QELQ!-Rl#ccq$6B)6Z-I`
-
-FQ(52iC0Hd6f'2a&QlKPm`YDG`5GX%V)aI-*'%r+rq)3prJ`qB9260)C2f"21i"-
-
-feI!B2QRI@@I`#A[5'Ic*-1NH`dIV+GeMrFY8Q(52j8mG(mdXar#TGUKe(X1R`pq
-
-T1G'EYSlfTT4IFZ446jL-RfpLA2G!eYX*@kf3!1dTXPdLfkfbh5AE'fAlbB5G8j'
-
-`4rJkCZFXKT(SUhpj-0jKc0+KVIl1dd)2DmAG-GY8*93X&AUb"HYJr,'#0E!H,EJ
-
-1NCe#Mr)KS8HMKZmGh)rJ,V"iE"haZ#h!9,BPYJl''HE&0`Sp@9F+$qSClfFqB9h
-
-h3F6FlY%JbNC43[653pSVJdcS86hQ89H[mbKL98+8Rk[YF1I00PeH*e3+2HTqAYH
-
-N,LMMCc%HqGX+1SASE&1&f@&'l%0mMD%M4m1VBND`e)EiiS,VCTXD(2B'40m'rl5
-
-#08#c9pE!hmAAm#U26ZK4E&E48%VR2LJ-CTF+Lq-[Q!rPj"[UJRc-'14f6EKm3Rq
-
-[HC!!63aQaBb,eS*44IHY`T9#9"TN-1YJpRX&fl4AmahDMZpMp-1B4i1Br38Ef*5
-
-LZGT1Yf,T@L'kG+hYpILK5iVBA1+i5A[CfL*0plhmp&KCF6DUCir(CadF[VkJLmr
-
-hl$189GrN0XCQaUTQQmSPVV*HpY33GT)apN++X4le+M"i0Epbf"EcSZR0GUYL,E'
-
-CL0P[#,$5,pp39-AQe,`b2HjB@cfAZmLMk)i,dH$ilTe,er+S69fpF0LG9mb$!l[
-
-R31a#i(BDla#LU"ri@"l9MH5GKNUFPjh[CUb%le$F&p6Y@VGPQf+Mf`$HhiaG`0F
-
-EE!CpNpCmJ'NLh(AkA6XZh4NrZ+jVe`eZK4!eX*L4F(JZ0X03ArHcH#pICpR!*Pl
-
-XK4j0L8ffh'rc-KeIere1L4i-[$eMkE2E5r8'IIXP(S2Gl*Q)Zf#a'@X,Qq&K$)b
-
-8&-E"[@,S'A[+pp5)VrqCMI&KiNfa[Q3Qde9lQGE01baYqAD,Zb2SkYi*qa$K!H(
-
-QrQk@*rZq5ckG*6lNDIDh!N0&FHA[kK@2A1Tq5ZHFEh)rKLLeYSe0M3qAR,I8E&J
-
-jY+[rT[A9)lQhp[p4)R[CAjVd`eG)q5Ap59[1Ed$+lfq3!*Xb2P4bhK@8@k6rTRj
-
-JV+rq[$NqA2U`m"9NK3VKAUem9mqHIDj8lbP"PFc`j0R0lNQ*I,N$6AVCdp18*hY
-
-f0%'EZEh)H$fUN6,B3ica+pmIjZHp2ebp!DT9@&,)#Mf''B9-IjQPr#f@rm`"TRV
-
-fXT+Kq5E,f4-2X#q@$(82A'Tf[iND,j2dTmcpQ*4$$h,S#F8M6-VMR%F+f4IGNqB
-
-J'pZ22,VGhpLkJDP%PD'3!+P'N!"h!rF@[MkB[ljcr`h&frIIb#bGV(J(mUN2X4*
-
-pX9j4GNhmp4Y3'hcTK+D*KTP-YEkVC$Za8E*$BZ+*q*Y0FrMmf#+ql$LLcLXFCJU
-
-2[K5SU)%*YQ!q)e6KX1%9i!l`mjL@,h-VR'U"@M4@E)Vpm1i&"NfaDF-GpbrBfZ9
-
-43qpR0r'kZ8c&&BRN0640K&FKHr90+PMRPJr'GaLkK'MXKd,di#&8q%UQd23bTI"
-
-9"Y@$aT[+kbSUjl2Z'0pB$phR08+dF1AJHN20YhDrGZhcfjrC,IPAlKKLCBC5[4k
-
-q9Idh5c&Z18Dc[QH`6BT`b"(jr6f$$LR#)NHSe0H#a(a5Q2KG+Ee$aFHh0DPJl5(
-
-93@8ePZK,p9Z@,YNC(kbfH)D&!Aj)MVPY*'C3MV'dDpHCrHTGCHB"TLM1TeLdU%9
-
--9@4Q+N-4da3eSVGlhF4QX!,1CRRd4iAX3Xj@qF4Il+k`@5b@hZfl9Y@m`Nb'kFM
-
-m(e%[4TI(rJ6aDdl'AmecRb,-rM4HPmkJZV0Y@[@eEEU+cSTV%FR$LPDJFf96T)J
-
-SBV95T"T4851Qcr(ieNkAfS!@ABKZ@GfXkpaZ+bYKPM*EQ4$GZVVj(+2NSbLEp4*
-
-QXhjcHh'fc9U5,85T)[CflEd"+)FkYrHZ,P(Zk$8UEGDRHfh@rY@LC[fUCKAPh&$
-
-@Y1rVM$T#D)9kIMCdBMTe139Pm1GfheX`RFmY90UY2l2DVI1bQkD-SR6CVHVV',Y
-
-QH0(D)YCpAr&dG(pClTG)CrkkmRDVHaU[M*8KLl[iXi"f16cV#a[iKE'C33leSVV
-
-cA&k$1%ZK,B8aKer)+j[dSeNDl&DqM%FeA$0FT%'A9r0mEmcBIIHPIa9riGZ2&Y4
-
-)Z5bXVN6AH6jd%(9@BZSH+"mmR)p+fJ,I1r!p$0mpm2dGI$I#GaYmI`rI25-pFcj
-
-Ib+CiY,#QH5B*Jb`#R#"`$J)R!Rm,r%fb2`5r!f`%81ZYQ*CVS1I,dCQD4M[6f8"
-
-d%aZ`,C3pl(R%#1`5BJ$fKC34E!2I+%5,Z6XAc,!&GAHH@mc&V-9$`JriRE!1mdm
-
-QBJfY6"1EAXca96'V%%d15UJ[MKrdU2JbblTde+I(r2fRV)GU*0F[GKFZ'6FZ&@C
-
-!@&e$S`1V*BfZ3,[Ekc'f'QM#1TGaI6mfFAd[dRd&lTYa2mhe[DcQqPkGarAYVFD
-
-pRq[EGj!!kh[Gb2@pdFVerHebVZqYjlLqJ6bZladIehI`(Ul[(a4Fhf(J[@rMqRk
-
-qJHZ,jh2ph!,FAqIkPGrNqY@YA,rQDG`$A2piD5R$)dE#I+49a0+%1a6`miQp3Qa
-
-bq2hBFJaMcC%A-H[Lh9kI1084#2JDa"!f3ALEk![b$C%30K$$+Rp)$+Z#lAk4M'@
-
-U"BZ%FY95Keh3%Y-m5!m&aNNZUbm3$MY$+e3GhSKrHRQY-ib9%UaRb2XM&r&Bb[Q
-
-$#1m2Y(MG+riPr[FUR"'4$dHFrL$[$S4iX30Jl8iIhq)0r5khhm926M)p@LJ6T9)
-
-i'P,4l,[)jI1kP[&L+-6l`aiMMHaaP!k@(kR(!$5jIF64)2HV9c"fkm2Bb8M[NA,
-
-5*ahe$KKB9T9'TSPBKI4**`H4UR2Kk*+M&9J[`FHC*Q&NUD#pVUA83F[45Jadk'0
-
-F3Yf1$dpTM65,Hfl&AGM3!#1U'a&eQabGKF82I&eA%c-D$%HjjT%"U4TMFAb*[&A
-
-h)@)HETXFRBf&$h`V0NVHj1U3!,`K#cY(qL511H*j`3MI14L%iN0H')LU%pY@kEb
-
-e@+I!ap@!&jDr$K6[395bNR+a,%&ISM6!LST@Uj*V5MUX3Y#A)"$4+kM@NKY`il$
-
-S30pF$R`T#q@S*(BHeKMSieHp#Flf)`,0AQTaDcb@&2)PHQQ)5fb5Xdb1cXF+!Vj
-
-N8DB2,Ic5f4Kjid'T!M!XRlE0,$48%8&NcjVeLhiPLG[pfVbedR#BF'qX0CFl+(-
-
-SP#2N$)DCki1*FLTMEYAMF%qMfLlECUkT+5IZR$kIUlACYmcS)YhC12(&iZ3YB9'
-
-@5Q5*+ZHdkID)X$BCAmp+hXKTKT6AHm#U3r4C*hSQB(BrU*ZE[*&EJ[hH"NF&f1H
-
-b`j%@Ei"`&+-i5TRYhSDUbbZ*lE"hTGJB!9#%@0JA5pj3Yh-5l&V,'fQFRq0a03C
-
-$hZ956TYb(mp1hP#k+8NN)bQBbZ-#L*FT4c0ATc*h9&5!)3dB`XSCTF08SdMC5D3
-
-Pj6BcCAk9Up8CNNK#jN9IDNVH8!QCSr)k39+0G(N`aFD&eSVN$99-XdNF%CZY,D(
-
-`"a@L69D5SkS@&F+T)ekr#"MM-CcF0*pfUMM`5Hd-*A450pjlk`mPT8VU"Y9h0R3
-
-Mi#,4b)#J'D-9V[Mh#PIqZX**-8jAH0BrUp"aT*4UR0)#8Sh6@T!!8Se6@T!!maX
-
-Yd(kN"FGd1[HIG2TA[3DH,8Mf'TBDXp4V02ZFVQ8q2,U3!#'KemM%T"XRp@#KVcU
-
-Y"q@f5Y+$A#aMZCD&Srj`4S3qiL3hckljPY445pa8@+b09#FYcCj'[bpc@BGcr'Q
-
-!%69iq@)m[C*8URU(RG4!'ib%'PfYVS`*8j,-6"h[aReIXbG[D8k5c,e@cYh[$#h
-
-lT)pilFFr65[(JLU"+N',p`QF2Y40KM[Pq2-plHN1e&CT4R@a((P61@0C"rU4'Q`
-
-blVmMh8FNDTaTr9MRD@`4JjR-qSM6-pGM1,T84T8160L3!*%BDI-(2jh'hIh8YR5
-
-r8BZ42Y@"2cR5GhfQ,m$+0,B(FZ(*qFCchdR[JG5Dl3[K98[0EFBhc6Jf!k'Hj$p
-
-R)(rUIIG)ebZT#lVHd,,'8%3DJQ5UfdlEP"@LKiU5A8P9!ff@U2hH-(@biF`FQ[(
-
-KV+6++NJeiI9JS(a#A@K@FPTGe,p@Pj4QR&)AdSc6kT,5M&2U3T15dqU5QT4mULl
-
-T5FPrl#eaeipXJ`L95k4YN!"fmDV'M(FlXp`hrMJpBDZc9%XlCB(Q0M6#dJJhdpT
-
-%2bZdFd30'KTT[d-6#2rA22prCQFCZHEjar[pNj2C69PYp)K@DM)V+8'fT!3C%RU
-
-0$!Sc%%F&0K8NII&jQb@NScQPp1@%DKc0DD4,rDbV-ccd@PV(lCAPY$H4%a*G2UI
-
-ARl'MdM)(c3+5MpDF8)f1Rr4*kNc)faB*9I4DMcVDlZfJPej1UXfAEck8RMde1"C
-
-Ci0@')p(QjN#S(A*Mr%a[J*8"E)T3G!%pL5YhHBl+"RVj4bhpa)5,Y@G#d)*M[FH
-
-rp@3IGap(N9*kF+TlbrUSQrlA5IIaD[aidXeYj&CVNMH83&CM+!&9RaC+%&Q"[`%
-
-!PM5C'9(,)ph(*fUTr9!YMqT9DV2iP&iGfErj4+r'r8D[mMkHFibb02iMPNjf1PA
-
-[d("$VLh(CI8d(p1LX&VN*cJbP(8k[pfF2kE#ZPqTX(51-%LC%ZXU[a22)[*i8[E
-
-rZJ[cIcUGL4G#pHMBk,e2kCF0VX,2PP#E5Iik[#T1$qmHrqXJc[6'Fa2`XLUETTM
-
-$*YV-$D3cYp12%m#qEb(qhJ$feL8eGE5PqJMF0!YqXU&'QZAY39+9b(8[r8`"-MX
-
-Ah$6![T!!ITF!pTb'bfV*EbNA&PMaKL[H#UA+i@kTX"!qGeH&C3R&EkCI&X"$k6d
-
-9PN9@f#m[VUY"R%+aB%N90%@4PhahPUZj([c3IkY-$A%eUr''+[Q8"m(LQS3[kcE
-
-1G+!PiF[1j8b6mBiYqG4I![EZK'rFji"Ab"55leDmdYV+9*,[$[MHa&2kj,XIH(K
-
-90KkIa-Ep'I$!Tj5(&h&2b4cN`,G2pSf$$kqZ5Vi*m(hh+pHLCV(B#pqMEAp*2`L
-
-K$S-ce482X[1!F4&mDd`jE#EL`-(e-DD6q,X(FCd12IXm1+#IdU#-2SFi1q)HB*d
-
-54KI`ANVie'C`8jVJFZTNa%85A%ip'ebqP1"bkZr$jj-acJ0'8-Di!,i@'@-Q-2E
-
-*q68KTiMXZ`ja[9RqCFj@hp%rG"RpQjINMlqNrpQ&-qA@"ki53rAP&2rr!!!0$3p
-
-YGbpRBh4PFh3Z0MK,,VN!N""453#3%#pd!!"+8`#3"2q3"%e08&*0680$!3#V,jH
-
-ZUc!jB!!!"M%!!"R%!!!"V3!!"E(*MaZS!*!'[VXM4!iL+Pj0j%)PIdhl9fbRBC!
-
-!DR1(JAFp3hUJ2KNcZ@(k&LeHlIYc*cMM1X2GRCf"!*`N(81C&iAQNTm4&Ifii1"
-
-EpGII4h6#PiP+'R-jb[e$&IeM12rA3hh-XBk+D2XK9#@U!P9e!@eRU22XRT!!%ar
-
-%6jaP3[FjFKhiIjQ@hidE$&25cAm$`-IrIXai*1U*jZd88q%pXX1%F$M`RNJbAQS
-
-ih%%N0J*@A""6p[pE#%1,cL9X%K8j[Z%i38$F)*'R%8!QpTQQT&06TCMf4amme9+
-
-jii[1iC(HE43E%aa#QlrCjZ4[GSL(8*!!e8D-E"#r6LR@&GN3aF6F'028K*cdTGk
-
-aT$fkUhhK6F,P(Tj11!CFTLJ+QQSXDINp,M$RL-+Cm9q6j"VK+Hr'rhrjXB16b1@
-
-iec&AC&Z,)bAP)A[QZNkT`brFF9bj0@L(b*(4H3)$i*YCbh9`YK90aj%$0a!Gm&!
-
-,de[B3!XlC'%$"-Eme,D0'(Z229-8DlB`9Q$FC!Y6@9L'KA%@PQm[")V0YM#PKBP
-
-$[mI#m!L#i#MfjAH50i4eE512Q3bj@@90I4m!N!--!'XcXfpJlh2Ij$4lRaZHF-P
-
-a`Tr-D)4&@%FjIAiV9hi5rZ3i@3NqRhV5`hI'm8m[3MNjENHi%AjN`!NMR"`rbB$
-
-bTrc)FA,m$%r*F51Fm*03FTa`FTa`-Q#%%hlN'4R`Pa`RA(+FF+mMamRa)mq2m$2
-
-#bB!#GjN8B'@Y6-+0iUpN*rl)-F)*2m)*8[#%!j-9H"9SN!!()1QkKK#+`Hm@K$S
-
-HJ&m,rN[#E`hmIJLEJ,q0bk)PQTCS@&q4J@q@4d"9U,FU)md-(0Yrf-'kLSC3Ech
-
-QTZ6PDfM!,6kXTJh48"8c3%-B$Af2ZR8CG9Ip2$-35k-p#&9[4Zd)$4`EE%%G46!
-
-,R0"9-23T99CN34j4,-#2%@HJ4P(6T'aDQa#N[iMDX5G2a3J5j8hqU`G8AI)J-HU
-
-[2pc+8DXTel3Q5K1DDDe`rC'MeMLS#5QV5"2QC-jFKV@(Y,XiDUf$'TI6Q941+fY
-
-NIrEXmabeMLSdTZC&6Ae8m48krm8h(,@HFXdUSU`BRMk!q[lRHBlD3,RQ4#QENT@
-
-#"cXRI2X+4ie6jif)dMfM+mkEUadrc9%E(G5'h+TKlGFqRHHS#3He,LFDrPe`h($
-
-QCBlDa(3e*P+'jG["RP9riDM0,PI9V"`8d09SikJYP'YH1C5kHVfHlZ'SDkKIpI4
-
-i+LIkaJ28)bpbe,88e9!N694cCG6ZNqFjkMUUN!"T6DE6ZT(h&AViKGmikRVU"NX
-
-TAdR(H9q1FY4@bY@D,XL9SfF2rY6286HiPp,*+'9G,aJIFG50p#Uce14Gj3Y'd81
-
-Ek"h5cFV&)blrQ+1f8B8b8UTJU&0#eN-9cVh+8GXGe*U-j!-kU)P6p4b9*UB'dj*
-
-PCDb-E#IIrF$K4qBkCkfIRK)eFi@ZrFEXr4ae-h@$T1I(e%`C&K,!AUi3T&L#1U`
-
-I'P&bCG3h(rRp#Fje+d8&50fBrKHeFp&j@4Q5M3GV$pea1eGSfk+(0$9pa80R1GF
-
-ZCkfce*a5FDbGI1mKMRSpifUSq482fFRj!BlD6Id+#UPkaDr(MfcMU0YGVSSeRLY
-
-8Z0V[F05H43q4)19lk0aM"lL(GMKViS"LkT1'T(MH+rPeTkZ3!*U"!([&H8FjkLl
-
-+0@RS306mKfX[64ZJ+`31D"5@fGUaCaUiVRd8Y@!C+5NVP42Ef6h&a0E[S,D5e*Z
-
-k$e*4k[,4R"1qUq@S0cKV-k$Hk86c@fiEqT2V*rYSlLHcfePEppip1YM9Hl2Del9
-
-2!&`"@TQ,U#F1&[Z''jdelZ4b1(ZHmdimH"0(45eR)(&!*q9f)f6q6PCX0VTUBad
-
-IAd$pf!@`[ik1Br'KUlR)+fakrN"cHF(H36)2h%jb&H(+NrX0&jMF9VMIj$*$&L)
-
-T"p)0cLf`Yq1%"AXR6JQ`Yq'FKMf0GB,GdbRXPYLiZ+lq4#IBL8k`%jeJ*cV"6R5
-
-#RHJ%1p%*GU)6l%3Rf)P1h%qc#+[@Y15RS-eL8qhT&"fJcd&k4dVkK,dC'pb'AVi
-
-MRZjKXmB'HccD3(IrcJ8G(KYmfk)&p1R"5Hkrqa'fKQc`$Bdfm0&Ek'dF5*Cm&25
-
-6E"T+qQc(16M5i"iI4FpKHCCb3p#-XSR6I3[1YF$(e@dVrAm(hAhGA,f#1a4fVQ`
-
-D)a0bM1IcX19PNiJXd-QrQrjp$rTP0Nh4$ljDEE6C0*GdfSPEQNJ$[AaI"9dkQjE
-
-)"&rjZ5PSlpQXL6c)65I42'&jkHi((6HE659pGY(F%GhJrk#CBp-AQC!!QcfG`RF
-
-BE0C'2GbTm18(Qh@4"hI+cbI"'a-fkb-2I05,Qq*VI86`ZS90Dq6"IEUNPpZrZ6d
-
-IkmP@hp@`f9$5UmK,"LjZ2dGjKIdd'pTRSrf,Re6[[[HdcbYXX0R3aK[KcVI)#mr
-
-A-dm"R8jJFcLjAc2T0r!1Xr%Ph(NRKdhm"Y1PM9qd9#9(PFc#![X)[SNKr!e@jAm
-
-!N!-0$3pYGbpRBh4PFh3Z8&"$,VN!N"!4c!#3%%+&!*!)rj!%68e38Ne33d-"!+X
-
-[PkkV-$P&!!!'-3!!'Z!!!!'T!!!&bE5F%03!N!B"fL0%$L)UANhN3L9r6IYAE+G
-
-KN!"UFiH"Gce$HU!q'61jBIV#iB$[cjhJM1X-GhH'!`%ib6Q'-Lm+c58r)bVkFF(
-
-"YqU[[irS4$#9MENFjIkKL[iaR2rVS6lQ@%G&Y2d3UK*9JDUkJ,Bce(Pf6fJm&6R
-
-b2Z8HRJiXa'A+ir""h#2TreqK*11PKX-G4'@dI[MrP@fl(cXiL9b1Haec4BbeKmP
-
-aeJj"iNA$iL1d#Y1J+HR89#QQrG%86l98l[LLFhLNlhad)NaL2JK&0pZFr-d1m4!
-
-+XYS)fcSm[diTeKAC%-A8h"M6e)5Fp+AHXD3p1ZNm1FY%rabj$[`E!$0bi`E$P26
-
-rG@!p"$aQr-JXH*CjLX,-Um9UPGj1-5VH)fY@`*(4VHaDSf,&r6CPrlq&--R1K6X
-
-*#r!9a`Q#"HZ@0$hdcLR&Z$Fm-LN%a%6I)NG'j`NF&EkCY9`(CaX9iFL4(fpK!IC
-
-B8#c-*P,XP1dG-@D4KE%@0XR#9"C'PcdhhF,ZXE"3#eYVB3-&a[CDHNU"FB-@YXI
-
-#PPJD!bcX5f0T(aH0)DaV'hR-C-M0+Q[Uq``!Da0l'f3fmMSr"jhCCQZ%N3NRNdf
-
-14LJRP"rPR[a@3Sqr%8D1NjAJmk5Hp2#G-Ic6Le"1MJm)Pachb(2###I(6c*J%8k
-
-j%8k1RiHRj,J46[K*+$P11$P11"P3`JNrmS`-q)!-Z'6!D6eKj2L4C`f-F$+J`(8
-
-Q"D$m9QE4e,T1r"&qK,q%%k6J#3FQ+c!qS%%HJ+LU#N)S",rE%'S`i2Fjq"D$ha,
-
-iI4qf+2P[K53BJQi)Q['&0I#IjBQL)Y4CP"42pjcUHm,'ZSf'8'HBF--Ck@qdLS0
-
-b3K-d'HXH'L*+S#ZS9C93Dp(hThY##E32SH*'Y!@KRP2p0@MV!TJ"6QM*DZUi,'%
-
-T+JeJ!r"$PM03TD!SBLUKM%E&Qd60d0-c)3Z*mVDqK3&9&I13!!6eTfr[iUM&P'Y
-
-#%F4446G@Z(l(88YXe)LB`Z+S2TE@Pf(0!mTp(,A84Uf3!",*H&STD'4qmZcc(,@
-
--+M3XC`4&IJbl#Phql%Z1'UCF8eL3!,#@e`G3hrdd`e(,+GHd)+EL%XlQBDHLAlh
-
--85ZSm`B%mB'K&HG0PBjFj+L90QTjHXf`jUXI6h28L)eDPKBdpblBE[Mm*BjDaA6
-
-94Z1DiGV"R*4rj+M9$PGCAcdSS+ZfQD2@8+iCI$4qqhSpdmj4DkPIeF4)2#fiaJ2
-
-8Bbpbe(889F1L)XMT!QVVKFXFYBiUT"YMLB5UC9b&(RhKCikkRVV"`)8VDEQKZf-
-
-V4kfRA)f*V,4kp-cqUedFGB0c+Hf-8Y$eQ[B"4pe)Vc*,6IQVI%eEm0!QHSG8IIA
-
-L@5lrN!#MEUCQhhrr8(p,Ec3@kie#4,V"pIbK)a`9-T!!GBlk-`E@KJ84,f%LG'i
-
-f[T!!!'KLUKNie$XiPM(N0&lQH[KU'dGYS"j+L['X*Sp(8hPGSl0R1'UMM9U5&&e
-
-!'c8b%qDSN!"L,3rTKL6Ki3+b'A[l2CZI0G[Y06`a,LMk#PhcpFQ(1'S6pDZSCSE
-
-PC!&fUR[r&Uj3-eASS(Td!+F,U1H1r2)8jpT#83&5e5EZS1kBGej+JZb9Kc82h(-
-
-h9kKehN1+R,MPS8ZFDjZpPPPABF@aCZbG`abeRA(9j-b+KmcBG!p(lD"q"B9NGG@
-
-[CimeFp5G$PGXM+5cUec0YcMUVRN2@9(2pG$Xii2F3jhf'KR%ZMUQL6M[[CaIGcX
-
-+b8Q)f,HFGj+MGP'Z-8d&S[SrA2I32!5k3L5#cQ1CV4NkAXjer4pehS"JT*BMJmh
-
-eq+jHMVUAFXdD@Pa-LB8NHQRI3K)PI3p-0D6jHqhb!-,0lkJIrAq#kpTYIkZh1S$
-
-iJj!!%H0,"hSUqR8TjiTU6d$LH!3qd"l'QVp5(*Z0MQj%N5IR8$IK#2YVk#b4%AU
-
-KAhRjVG*[D*cA0T*HB1mJp`hf9R+*B@mR9a,f0R*MBGp1mJVX655"`0j)XK,X1mL
-
-pKlf"*+irG2*l,$B1E[#"6T2S$,#X@[56ejba+FlV&"bJcm2dMZ6dm6Xk0U4jAES
-
-MHGhp&Sp0DH#"lZkGmrT#0Q@"!rVX)TRXhr[K0j4X`S%(2RS$[3RXDKCpj(@KE-T
-
-cqZ`NL6E3i"kI4160319LE["D@$B9G'mQ#4Ai1,Ued1qGG(GeFr6blT!!hqqbU3a
-
--b$&jRrZ0-TY)B)&1lYedll[ACE1T#Rl`e9TlcUBkTp0ZdVF%-H4Z[lGR8a1Bi#X
-
-h0hN["GM8"KlNTJYSfQ*jrHjlI6UE66PpZQMZ#'l`[pH@XGNEQ*!!Qr-kq@mqf+`
-
-,HVK6rLX60R@""hI+c5IHHaBfk`-2I,5(G,jrpK(H5aSfpB%(pqQkANlrj[4mV#G
-
-EHm2$CN01V`9H%R"aqMR+bhpj`iDqe%&p8bAIR!qTj%[4$kpFY(MK'lcmYcPXk&Z
-
-H1lcmlTi0lIT[mPVbJIFUL!elGjRM4BM8c8"+#$@"@kr%qK5GrJGH8d5JeDSp%6Z
-
-S`aY94TZmpLQ+$H(Nh"cl%r`RK-KrL#Vr!3#3!aq$!!!"!*!$!43!N!-8!*!$-Tr
-
-lRLe!rr#`!,K[$#eZd!6rm2rdd"lm`FAKdkSV8FY+$deKBe"bEfTPBh4c,R0TG!)
-
-!N!06594%8dP8)3#3"P0*9%46593K!*!BUc!jI3!!8M8!!!&'"1"2l'mDG@6JrHc
-
-K@5U#NI*HN@GK!Z"2kQ`FG&2UN!"S!!,L@5[48(adA`CdC!EJ6qj[8hJS!!EJEHl
-
-LEe5!)D$!FJC1ANl!*IrX51FI-#D`jL63G!*&0K!+1Li!&Ri!)VX-S"lbUKQJ(Z`
-
-3!+SDI!$!#3ZT8,aIE!!!Q$!'8!6"aG!!N!-3!#X!"3%B!J#3"`-!N!-"!*!$!43
-
-!N!-8!*!$-J$j(l!@#J#3!a`!-J!!8f9dC`#3!`S!!2rr!*!&q@G%'@B:
-
diff --git a/boehm-gc/Mac_files/MacOS_Test_config.h b/boehm-gc/Mac_files/MacOS_Test_config.h
deleted file mode 100644
index 4e5d2527788..00000000000
--- a/boehm-gc/Mac_files/MacOS_Test_config.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- MacOS_Test_config.h
-
- Configuration flags for Macintosh development systems.
-
- Test version.
-
- <Revision History>
-
- 11/16/95 pcb Updated compilation flags to reflect latest 4.6 Makefile.
-
- by Patrick C. Beard.
- */
-/* Boehm, November 17, 1995 12:05 pm PST */
-
-#ifdef __MWERKS__
-
-// for CodeWarrior Pro with Metrowerks Standard Library (MSL).
-// #define MSL_USE_PRECOMPILED_HEADERS 0
-#include <ansi_prefix.mac.h>
-#ifndef __STDC__
-#define __STDC__ 0
-#endif
-
-#endif
-
-// these are defined again in gc_priv.h.
-#undef TRUE
-#undef FALSE
-
-#define ALL_INTERIOR_POINTERS // follows interior pointers.
-//#define SILENT // want collection messages.
-//#define DONT_ADD_BYTE_AT_END // no padding.
-//#define SMALL_CONFIG // whether to a smaller heap.
-#define NO_SIGNALS // signals aren't real on the Macintosh.
-#define USE_TEMPORARY_MEMORY // use Macintosh temporary memory.
-
-// CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT
-//
-//LIBGC_CFLAGS= -O -DNO_SIGNALS -DSILENT \
-// -DREDIRECT_MALLOC=GC_malloc_uncollectable \
-// -DDONT_ADD_BYTE_AT_END -DALL_INTERIOR_POINTERS
-// Flags for building libgc.a -- the last two are required.
-//
-// Setjmp_test may yield overly optimistic results when compiled
-// without optimization.
-// -DSILENT disables statistics printing, and improves performance.
-// -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
-// altered stubborn objects, at substantial performance cost.
-// Use only for incremental collector debugging.
-// -DFIND_LEAK causes the collector to assume that all inaccessible
-// objects should have been explicitly deallocated, and reports exceptions.
-// Finalization and the test program are not usable in this mode.
-// -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
-// (Clients should also define SOLARIS_THREADS and then include
-// gc.h before performing thr_ or GC_ operations.)
-// This is broken on nonSPARC machines.
-// -DALL_INTERIOR_POINTERS allows all pointers to the interior
-// of objects to be recognized. (See gc_priv.h for consequences.)
-// -DSMALL_CONFIG tries to tune the collector for small heap sizes,
-// usually causing it to use less space in such situations.
-// Incremental collection no longer works in this case.
-// -DLARGE_CONFIG tunes the collector for unusually large heaps.
-// Necessary for heaps larger than about 500 MB on most machines.
-// Recommended for heaps larger than about 64 MB.
-// -DDONT_ADD_BYTE_AT_END is meaningful only with
-// -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
-// causes all objects to be padded so that pointers just past the end of
-// an object can be recognized. This can be expensive. (The padding
-// is normally more than one byte due to alignment constraints.)
-// -DDONT_ADD_BYTE_AT_END disables the padding.
-// -DNO_SIGNALS does not disable signals during critical parts of
-// the GC process. This is no less correct than many malloc
-// implementations, and it sometimes has a significant performance
-// impact. However, it is dangerous for many not-quite-ANSI C
-// programs that call things like printf in asynchronous signal handlers.
-// -DGC_OPERATOR_NEW_ARRAY declares that the C++ compiler supports the
-// new syntax "operator new[]" for allocating and deleting arrays.
-// See gc_cpp.h for details. No effect on the C part of the collector.
-// This is defined implicitly in a few environments.
-// -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be defined
-// as aliases for X, GC_realloc, and GC_free, respectively.
-// Calloc is redefined in terms of the new malloc. X should
-// be either GC_malloc or GC_malloc_uncollectable.
-// The former is occasionally useful for working around leaks in code
-// you don't want to (or can't) look at. It may not work for
-// existing code, but it often does. Neither works on all platforms,
-// since some ports use malloc or calloc to obtain system memory.
-// (Probably works for UNIX, and win32.)
-// -DNO_DEBUG removes GC_dump and the debugging routines it calls.
-// Reduces code size slightly at the expense of debuggability.
diff --git a/boehm-gc/Mac_files/MacOS_config.h b/boehm-gc/Mac_files/MacOS_config.h
deleted file mode 100644
index 407bdf154a2..00000000000
--- a/boehm-gc/Mac_files/MacOS_config.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- MacOS_config.h
-
- Configuration flags for Macintosh development systems.
-
- <Revision History>
-
- 11/16/95 pcb Updated compilation flags to reflect latest 4.6 Makefile.
-
- by Patrick C. Beard.
- */
-/* Boehm, November 17, 1995 12:10 pm PST */
-
-#ifdef __MWERKS__
-
-// for CodeWarrior Pro with Metrowerks Standard Library (MSL).
-// #define MSL_USE_PRECOMPILED_HEADERS 0
-#include <ansi_prefix.mac.h>
-#ifndef __STDC__
-#define __STDC__ 0
-#endif
-
-#endif /* __MWERKS__ */
-
-// these are defined again in gc_priv.h.
-#undef TRUE
-#undef FALSE
-
-#define ALL_INTERIOR_POINTERS // follows interior pointers.
-#define SILENT // no collection messages.
-//#define DONT_ADD_BYTE_AT_END // no padding.
-//#define SMALL_CONFIG // whether to use a smaller heap.
-#define NO_SIGNALS // signals aren't real on the Macintosh.
-#define USE_TEMPORARY_MEMORY // use Macintosh temporary memory.
-
-// CFLAGS= -O -DNO_SIGNALS -DSILENT -DALL_INTERIOR_POINTERS
-//
-//LIBGC_CFLAGS= -O -DNO_SIGNALS -DSILENT \
-// -DREDIRECT_MALLOC=GC_malloc_uncollectable \
-// -DDONT_ADD_BYTE_AT_END -DALL_INTERIOR_POINTERS
-// Flags for building libgc.a -- the last two are required.
-//
-// Setjmp_test may yield overly optimistic results when compiled
-// without optimization.
-// -DSILENT disables statistics printing, and improves performance.
-// -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
-// altered stubborn objects, at substantial performance cost.
-// Use only for incremental collector debugging.
-// -DFIND_LEAK causes the collector to assume that all inaccessible
-// objects should have been explicitly deallocated, and reports exceptions.
-// Finalization and the test program are not usable in this mode.
-// -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
-// (Clients should also define SOLARIS_THREADS and then include
-// gc.h before performing thr_ or GC_ operations.)
-// This is broken on nonSPARC machines.
-// -DALL_INTERIOR_POINTERS allows all pointers to the interior
-// of objects to be recognized. (See gc_priv.h for consequences.)
-// -DSMALL_CONFIG tries to tune the collector for small heap sizes,
-// usually causing it to use less space in such situations.
-// Incremental collection no longer works in this case.
-// -DLARGE_CONFIG tunes the collector for unusually large heaps.
-// Necessary for heaps larger than about 500 MB on most machines.
-// Recommended for heaps larger than about 64 MB.
-// -DDONT_ADD_BYTE_AT_END is meaningful only with
-// -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
-// causes all objects to be padded so that pointers just past the end of
-// an object can be recognized. This can be expensive. (The padding
-// is normally more than one byte due to alignment constraints.)
-// -DDONT_ADD_BYTE_AT_END disables the padding.
-// -DNO_SIGNALS does not disable signals during critical parts of
-// the GC process. This is no less correct than many malloc
-// implementations, and it sometimes has a significant performance
-// impact. However, it is dangerous for many not-quite-ANSI C
-// programs that call things like printf in asynchronous signal handlers.
-// -DGC_OPERATOR_NEW_ARRAY declares that the C++ compiler supports the
-// new syntax "operator new[]" for allocating and deleting arrays.
-// See gc_cpp.h for details. No effect on the C part of the collector.
-// This is defined implicitly in a few environments.
-// -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be defined
-// as aliases for X, GC_realloc, and GC_free, respectively.
-// Calloc is redefined in terms of the new malloc. X should
-// be either GC_malloc or GC_malloc_uncollectable.
-// The former is occasionally useful for working around leaks in code
-// you don't want to (or can't) look at. It may not work for
-// existing code, but it often does. Neither works on all platforms,
-// since some ports use malloc or calloc to obtain system memory.
-// (Probably works for UNIX, and win32.)
-// -DNO_DEBUG removes GC_dump and the debugging routines it calls.
-// Reduces code size slightly at the expense of debuggability.
diff --git a/boehm-gc/Makefile b/boehm-gc/Makefile
deleted file mode 100644
index 20fa40a9a08..00000000000
--- a/boehm-gc/Makefile
+++ /dev/null
@@ -1,680 +0,0 @@
-# This is the original manually generated Makefile. It may still be used
-# to build the collector.
-#
-# Primary targets:
-# gc.a - builds basic library
-# c++ - adds C++ interface to library
-# cords - adds cords (heavyweight strings) to library
-# test - prints porting information, then builds basic version of gc.a,
-# and runs some tests of collector and cords. Does not add cords or
-# c++ interface to gc.a
-# cord/de - builds dumb editor based on cords.
-ABI_FLAG=
-# ABI_FLAG should be the cc flag that specifies the ABI. On most
-# platforms this will be the empty string. Possible values:
-# +DD64 for 64-bit executable on HP/UX.
-# -n32, -n64, -o32 for SGI/MIPS ABIs.
-
-AS_ABI_FLAG=$(ABI_FLAG)
-# ABI flag for assembler. On HP/UX this is +A64 for 64 bit
-# executables.
-
-CC=cc $(ABI_FLAG)
-CXX=g++ $(ABI_FLAG)
-AS=as $(AS_ABI_FLAG)
-# The above doesn't work with gas, which doesn't run cpp.
-# Define AS as `gcc -c -x assembler-with-cpp' instead.
-
-# Redefining srcdir allows object code for the nonPCR version of the collector
-# to be generated in different directories.
-srcdir= .
-VPATH= $(srcdir)
-
-CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_PERMISSION -DSILENT -DALL_INTERIOR_POINTERS
-
-# To build the parallel collector on Linux, add to the above:
-# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
-# To build the parallel collector in a static library on HP/UX,
-# add to the above:
-# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L
-# To build the thread-safe collector on Tru64, add to the above:
-# -pthread -DGC_OSF1_THREADS
-
-# HOSTCC and HOSTCFLAGS are used to build executables that will be run as
-# part of the build process, i.e. on the build machine. These will usually
-# be the same as CC and CFLAGS, except in a cross-compilation environment.
-# Note that HOSTCFLAGS should include any -D flags that affect thread support.
-HOSTCC=$(CC)
-HOSTCFLAGS=$(CFLAGS)
-
-# For dynamic library builds, it may be necessary to add flags to generate
-# PIC code, e.g. -fPIC on Linux.
-
-# Setjmp_test may yield overly optimistic results when compiled
-# without optimization.
-
-# These define arguments influence the collector configuration:
-# -DSILENT disables statistics printing, and improves performance.
-# -DFIND_LEAK causes GC_find_leak to be initially set.
-# This causes the collector to assume that all inaccessible
-# objects should have been explicitly deallocated, and reports exceptions.
-# Finalization and the test program are not usable in this mode.
-# -DGC_SOLARIS_THREADS enables support for Solaris (thr_) threads.
-# (Clients should also define GC_SOLARIS_THREADS and then include
-# gc.h before performing thr_ or dl* or GC_ operations.)
-# Must also define -D_REENTRANT.
-# -DGC_SOLARIS_PTHREADS enables support for Solaris pthreads.
-# (Internally this define GC_SOLARIS_THREADS as well.)
-# -DGC_IRIX_THREADS enables support for Irix pthreads. See README.irix.
-# -DGC_HPUX_THREADS enables support for HP/UX 11 pthreads.
-# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
-# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
-# see README.linux. -D_REENTRANT may also be required.
-# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
-# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
-# Appeared to run into some underlying thread problems.
-# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested.
-# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
-# See README.DGUX386.
-# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
-# for this Makefile only under Cygwin.
-# -DGC_THREADS should set the appropriate one of the above macros.
-# It assumes pthreads for Solaris.
-# -DALL_INTERIOR_POINTERS allows all pointers to the interior
-# of objects to be recognized. (See gc_priv.h for consequences.)
-# Alternatively, GC_all_interior_pointers can be set at process
-# initialization time.
-# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
-# usually causing it to use less space in such situations.
-# Incremental collection no longer works in this case.
-# -DLARGE_CONFIG tunes the collector for unusually large heaps.
-# Necessary for heaps larger than about 500 MB on most machines.
-# Recommended for heaps larger than about 64 MB.
-# -DDONT_ADD_BYTE_AT_END is meaningful only with -DALL_INTERIOR_POINTERS or
-# GC_all_interior_pointers = 1. Normally -DALL_INTERIOR_POINTERS
-# causes all objects to be padded so that pointers just past the end of
-# an object can be recognized. This can be expensive. (The padding
-# is normally more than one byte due to alignment constraints.)
-# -DDONT_ADD_BYTE_AT_END disables the padding.
-# -DNO_SIGNALS does not disable signals during critical parts of
-# the GC process. This is no less correct than many malloc
-# implementations, and it sometimes has a significant performance
-# impact. However, it is dangerous for many not-quite-ANSI C
-# programs that call things like printf in asynchronous signal handlers.
-# This is on by default. Turning it off has not been extensively tested with
-# compilers that reorder stores. It should have been.
-# -DNO_EXECUTE_PERMISSION may cause some or all of the heap to not
-# have execute permission, i.e. it may be impossible to execute
-# code from the heap. Currently this only affects the incremental
-# collector on UNIX machines. It may greatly improve its performance,
-# since this may avoid some expensive cache synchronization.
-# -DGC_NO_OPERATOR_NEW_ARRAY declares that the C++ compiler does not support
-# the new syntax "operator new[]" for allocating and deleting arrays.
-# See gc_cpp.h for details. No effect on the C part of the collector.
-# This is defined implicitly in a few environments. Must also be defined
-# by clients that use gc_cpp.h.
-# -DREDIRECT_MALLOC=X causes malloc to be defined as alias for X.
-# Unless the following macros are defined, realloc is also redirected
-# to GC_realloc, and free is redirected to GC_free.
-# Calloc and strdup are redefined in terms of the new malloc. X should
-# be either GC_malloc or GC_malloc_uncollectable, or
-# GC_debug_malloc_replacement. (The latter invokes GC_debug_malloc
-# with dummy source location information, but still results in
-# properly remembered call stacks on Linux/X86 and Solaris/SPARC.
-# It requires that the following two macros also be used.)
-# The former is occasionally useful for working around leaks in code
-# you don't want to (or can't) look at. It may not work for
-# existing code, but it often does. Neither works on all platforms,
-# since some ports use malloc or calloc to obtain system memory.
-# (Probably works for UNIX, and win32.) If you build with DBG_HDRS_ALL,
-# you should only use GC_debug_malloc_replacement as a malloc
-# replacement.
-# -DREDIRECT_REALLOC=X causes GC_realloc to be redirected to X.
-# The canonical use is -DREDIRECT_REALLOC=GC_debug_realloc_replacement,
-# together with -DREDIRECT_MALLOC=GC_debug_malloc_replacement to
-# generate leak reports with call stacks for both malloc and realloc.
-# This also requires the following:
-# -DREDIRECT_FREE=X causes free to be redirected to X. The
-# canonical use is -DREDIRECT_FREE=GC_debug_free.
-# -DIGNORE_FREE turns calls to free into a noop. Only useful with
-# -DREDIRECT_MALLOC.
-# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
-# Reduces code size slightly at the expense of debuggability.
-# -DJAVA_FINALIZATION makes it somewhat safer to finalize objects out of
-# order by specifying a nonstandard finalization mark procedure (see
-# finalize.c). Objects reachable from finalizable objects will be marked
-# in a sepearte postpass, and hence their memory won't be reclaimed.
-# Not recommended unless you are implementing a language that specifies
-# these semantics. Since 5.0, determines only only the initial value
-# of GC_java_finalization variable.
-# -DFINALIZE_ON_DEMAND causes finalizers to be run only in response
-# to explicit GC_invoke_finalizers() calls.
-# In 5.0 this became runtime adjustable, and this only determines the
-# initial value of GC_finalize_on_demand.
-# -DATOMIC_UNCOLLECTABLE includes code for GC_malloc_atomic_uncollectable.
-# This is useful if either the vendor malloc implementation is poor,
-# or if REDIRECT_MALLOC is used.
-# -DHBLKSIZE=ddd, where ddd is a power of 2 between 512 and 16384, explicitly
-# sets the heap block size. Each heap block is devoted to a single size and
-# kind of object. For the incremental collector it makes sense to match
-# the most likely page size. Otherwise large values result in more
-# fragmentation, but generally better performance for large heaps.
-# -DUSE_MMAP use MMAP instead of sbrk to get new memory.
-# Works for Solaris and Irix.
-# -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.
-# -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
-# the garbage collector detects a value that looks almost, but not quite,
-# like a pointer, print both the address containing the value, and the
-# value of the near-bogus-pointer. Can be used to identifiy regions of
-# memory that are likely to contribute misidentified pointers.
-# -DKEEP_BACK_PTRS Add code to save back pointers in debugging headers
-# for objects allocated with the debugging allocator. If all objects
-# through GC_MALLOC with GC_DEBUG defined, this allows the client
-# to determine how particular or randomly chosen objects are reachable
-# for debugging/profiling purposes. The gc_backptr.h interface is
-# implemented only if this is defined.
-# -DGC_ASSERTIONS Enable some internal GC assertion checking. Currently
-# this facility is only used in a few places. It is intended primarily
-# for debugging of the garbage collector itself, but could also
-# -DDBG_HDRS_ALL Make sure that all objects have debug headers. Increases
-# the reliability (from 99.9999% to 100% mod. bugs) of some of the debugging
-# code (especially KEEP_BACK_PTRS). Makes -DSHORT_DBG_HDRS possible.
-# Assumes that all client allocation is done through debugging
-# allocators.
-# -DSHORT_DBG_HDRS Assume that all objects have debug headers. Shorten
-# the headers to minimize object size, at the expense of checking for
-# writes past the end of an object. This is intended for environments
-# in which most client code is written in a "safe" language, such as
-# Scheme or Java. Assumes that all client allocation is done using
-# 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
-# on which we can quickly generate call stacks, currently Linux/(X86 & SPARC)
-# and Solaris/SPARC and platforms that provide execinfo.h.
-# Default is zero. On X86, client
-# code should NOT be compiled with -fomit-frame-pointer.
-# -DSAVE_CALL_NARGS=<n> Set the number of functions arguments to be
-# saved with each call frame. Default is zero. Ignored if we
-# don't know how to retrieve arguments on the platform.
-# -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
-# altered stubborn objects, at substantial performance cost.
-# Use only for debugging of the incremental collector.
-# -DGC_GCJ_SUPPORT includes support for gcj (and possibly other systems
-# that include a pointer to a type descriptor in each allocated object).
-# Building this way requires an ANSI C compiler.
-# -DUSE_I686_PREFETCH causes the collector to issue Pentium III style
-# prefetch instructions. No effect except on X86 Linux platforms.
-# Assumes a very recent gcc-compatible compiler and assembler.
-# (Gas prefetcht0 support was added around May 1999.)
-# Empirically the code appears to still run correctly on Pentium II
-# processors, though with no performance benefit. May not run on other
-# X86 processors? In some cases this improves performance by
-# 15% or so.
-# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
-# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
-# Minimally tested. Didn't appear to be an obvious win on a K6-2/500.
-# -DUSE_PPC_PREFETCH causes the collector to issue PowerPC style
-# prefetch instructions. No effect except on PowerPC OS X platforms.
-# Performance impact untested.
-# -DGC_USE_LD_WRAP in combination with the old flags listed in README.linux
-# causes the collector some system and pthread calls in a more transparent
-# fashion than the usual macro-based approach. Requires GNU ld, and
-# currently probably works only with Linux.
-# -DTHREAD_LOCAL_ALLOC defines GC_local_malloc(), GC_local_malloc_atomic()
-# and GC_local_gcj_malloc(). Needed for gc_gcj.h interface. These allocate
-# in a way that usually does not involve acquisition of a global lock.
-# Currently requires -DGC_LINUX_THREADS, but should be easy to port to
-# other pthreads environments. Recommended for multiprocessors.
-# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
-# "__thread" thread-local variables. This is the default in HP/UX. It
-# may help performance on recent Linux installations. (It failed for
-# me on RedHat 8, but appears to work on RedHat 9.)
-# -DPARALLEL_MARK allows the marker to run in multiple threads. Recommended
-# for multiprocessors. Currently requires Linux on X86 or IA64, though
-# support for other Posix platforms should be fairly easy to add,
-# if the thread implementation is otherwise supported.
-# -DNO_GETENV prevents the collector from looking at environment variables.
-# These may otherwise alter its configuration, or turn off GC altogether.
-# I don't know of a reason to disable this, except possibly if the
-# resulting process runs as a privileged user?
-# -DUSE_GLOBAL_ALLOC. Win32 only. Use GlobalAlloc instead of
-# VirtualAlloc to allocate the heap. May be needed to work around
-# a Windows NT/2000 issue. Incompatible with USE_MUNMAP.
-# See README.win32 for details.
-# -DMAKE_BACK_GRAPH. Enable GC_PRINT_BACK_HEIGHT environment variable.
-# See README.environment for details. Experimental. Limited platform
-# support. Implies DBG_HDRS_ALL. All allocation should be done using
-# the debug interface.
-# -DSTUBBORN_ALLOC allows allocation of "hard to change" objects, and thus
-# makes incremental collection easier. Was enabled by default until 6.0.
-# Rarely used, to my knowledge.
-# -DHANDLE_FORK attempts to make GC_malloc() work in a child process fork()ed
-# from a multithreaded parent. Currently only supported by pthread_support.c.
-# (Similar code should work on Solaris or Irix, but it hasn't been tried.)
-# -DTEST_WITH_SYSTEM_MALLOC causes gctest to allocate (and leak) large chunks
-# of memory with the standard system malloc. This will cause the root
-# set and collected heap to grow significantly if malloced memory is
-# somehow getting traced by the collector. This has no impact on the
-# generated library; it only affects the test.
-# -DPOINTER_MASK=0x... causes candidate pointers to be ANDed with the
-# given mask before being considered. If either this or the following
-# macro is defined, it will be assumed that all pointers stored in
-# the heap need to be processed this way. Stack and register pointers
-# will be considered both with and without processing.
-# These macros are normally needed only to support systems that use
-# high-order pointer tags. EXPERIMENTAL.
-# -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers
-# by the indicated amount before trying to interpret them. Applied
-# after POINTER_MASK. EXPERIMENTAL. See also the preceding macro.
-#
-
-CXXFLAGS= $(CFLAGS)
-AR= ar
-RANLIB= ranlib
-
-
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o aix_irix_threads.o pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_threads.o
-
-CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c aix_irix_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
-
-CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC
-
-CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
-
-SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.S \
- sparc_mach_dep.S include/gc.h include/gc_typed.h \
- include/private/gc_hdrs.h include/private/gc_priv.h \
- include/private/gcconfig.h include/private/gc_pmark.h \
- include/gc_inl.h include/gc_inline.h include/gc_mark.h \
- threadlibs.c if_mach.c if_not_there.c gc_cpp.cc include/gc_cpp.h \
- gcname.c include/weakpointer.h include/private/gc_locks.h \
- gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h \
- include/new_gc_alloc.h include/gc_allocator.h \
- include/javaxfc.h sparc_sunos4_mach_dep.s sparc_netbsd_mach_dep.s \
- include/private/solaris_threads.h include/gc_backptr.h \
- hpux_test_and_clear.s include/gc_gcj.h \
- include/gc_local_alloc.h include/private/dbg_mlc.h \
- include/private/specific.h powerpc_darwin_mach_dep.s \
- include/leak_detector.h include/gc_amiga_redirects.h \
- include/gc_pthread_redirects.h ia64_save_regs_in_stack.s \
- include/gc_config_macros.h include/private/pthread_support.h \
- include/private/pthread_stop_world.h include/private/darwin_semaphore.h \
- include/private/darwin_stop_world.h $(CORD_SRCS)
-
-DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
- doc/README.amiga doc/README.cords doc/debugging.html \
- doc/README.dj doc/README.hp doc/README.linux doc/README.rs6000 \
- doc/README.sgi doc/README.solaris2 doc/README.uts \
- doc/README.win32 doc/barrett_diagram doc/README \
- doc/README.contributors doc/README.changes doc/gc.man \
- doc/README.environment doc/tree.html doc/gcdescr.html \
- doc/README.autoconf doc/README.macros doc/README.ews4800 \
- doc/README.DGUX386 doc/README.arm.cross doc/leak.html \
- doc/scale.html doc/gcinterface.html doc/README.darwin \
- doc/simple_example.html
-
-TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \
- tests/leak_test.c tests/thread_leak_test.c tests/middle.c
-
-GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \
- libtool.m4 install-sh configure.host Makefile.in \
- aclocal.m4 config.sub config.guess \
- include/Makefile.am include/Makefile.in \
- doc/Makefile.am doc/Makefile.in \
- ltmain.sh mkinstalldirs depcomp missing
-
-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
-# Makefile and Makefile.direct are copies of each other.
-
-OTHER_FILES= Makefile setjmp_t.c callprocs pc_excludes \
- MacProjects.sit.hqx MacOS.c \
- Mac_files/datastart.c Mac_files/dataend.c \
- Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
- add_gc_prefix.c gc_cpp.cpp \
- version.h AmigaOS.c \
- $(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
-
-CORD_INCLUDE_FILES= $(srcdir)/include/gc.h $(srcdir)/include/cord.h \
- $(srcdir)/include/ec.h $(srcdir)/include/private/cord_pos.h
-
-UTILS= if_mach if_not_there threadlibs
-
-# Libraries needed for curses applications. Only needed for de.
-CURSES= -lcurses -ltermlib
-
-# The following is irrelevant on most systems. But a few
-# versions of make otherwise fork the shell specified in
-# the SHELL environment variable.
-SHELL= /bin/sh
-
-SPECIALCFLAGS = -I$(srcdir)/include
-# Alternative flags to the C compiler for mach_dep.c.
-# Mach_dep.c often doesn't like optimization, and it's
-# not time-critical anyway.
-# Set SPECIALCFLAGS to -q nodirect_code on Encore.
-
-all: gc.a gctest
-
-LEAKFLAGS=$(CFLAGS) -DFIND_LEAK
-
-BSD-pkg-all: bsd-libgc.a bsd-libleak.a
-
-bsd-libgc.a:
- $(MAKE) CFLAGS="$(CFLAGS)" clean c++-t
- mv gc.a bsd-libgc.a
-
-bsd-libleak.a:
- $(MAKE) -f Makefile.direct CFLAGS="$(LEAKFLAGS)" clean c++-nt
- mv gc.a bsd-libleak.a
-
-BSD-pkg-install: BSD-pkg-all
- ${CP} bsd-libgc.a libgc.a
- ${INSTALL_DATA} libgc.a ${PREFIX}/lib
- ${INSTALL_DATA} gc.h gc_cpp.h ${PREFIX}/include
- ${INSTALL_MAN} doc/gc.man ${PREFIX}/man/man3/gc.3
-
-pcr: PCR-Makefile include/private/gc_private.h include/private/gc_hdrs.h \
-include/private/gc_locks.h include/gc.h include/private/gcconfig.h \
-mach_dep.o $(SRCS)
- $(MAKE) -f PCR-Makefile depend
- $(MAKE) -f PCR-Makefile
-
-$(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
- $(srcdir)/include/private/gc_priv.h \
- $(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.h \
- $(srcdir)/include/gc.h $(srcdir)/include/gc_pthread_redirects.h \
- $(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
- $(srcdir)/include/gc_config_macros.h Makefile
-# The dependency on Makefile is needed. Changing
-# options such as -DSILENT affects the size of GC_arrays,
-# invalidating all .o files that rely on gc_priv.h
-
-mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
-
-specific.o pthread_support.o: $(srcdir)/include/private/specific.h
-
-solaris_threads.o solaris_pthreads.o: $(srcdir)/include/private/solaris_threads.h
-
-dbg_mlc.o gcj_mlc.o: $(srcdir)/include/private/dbg_mlc.h
-
-tests/test.o: tests $(srcdir)/tests/test.c
- $(CC) $(CFLAGS) -c $(srcdir)/tests/test.c
- mv test.o tests/test.o
-
-tests:
- mkdir tests
-
-base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
- echo > base_lib
- rm -f dont_ar_1
- ./if_mach SPARC SUNOS5 touch dont_ar_1
- ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(OBJS) dyn_load.o
- ./if_mach M68K AMIGA touch dont_ar_1
- ./if_mach M68K AMIGA $(AR) -vrus gc.a $(OBJS) dyn_load.o
- ./if_not_there dont_ar_1 $(AR) ru gc.a $(OBJS) dyn_load.o
- ./if_not_there dont_ar_1 $(RANLIB) gc.a || cat /dev/null
-# ignore ranlib failure; that usually means it doesn't exist, and isn't needed
-
-cords: $(CORD_OBJS) cord/cordtest $(UTILS)
- rm -f dont_ar_3
- ./if_mach SPARC SUNOS5 touch dont_ar_3
- ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(CORD_OBJS)
- ./if_mach M68K AMIGA touch dont_ar_3
- ./if_mach M68K AMIGA $(AR) -vrus gc.a $(CORD_OBJS)
- ./if_not_there dont_ar_3 $(AR) ru gc.a $(CORD_OBJS)
- ./if_not_there dont_ar_3 $(RANLIB) gc.a || cat /dev/null
-
-gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/include/gc_cpp.h $(srcdir)/include/gc.h Makefile
- $(CXX) -c $(CXXFLAGS) $(srcdir)/gc_cpp.cc
-
-test_cpp: $(srcdir)/tests/test_cpp.cc $(srcdir)/include/gc_cpp.h gc_cpp.o $(srcdir)/include/gc.h \
-base_lib $(UTILS)
- rm -f test_cpp
- ./if_mach HP_PA HPUX $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a -ldld `./threadlibs`
- ./if_not_there test_cpp $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a `./threadlibs`
-
-c++-t: c++
- ./test_cpp 1
-
-c++-nt: c++
- @echo "Use ./test_cpp 1 to test the leak library"
-
-c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp
- rm -f dont_ar_4
- ./if_mach SPARC SUNOS5 touch dont_ar_4
- ./if_mach SPARC SUNOS5 $(AR) rus gc.a gc_cpp.o
- ./if_mach M68K AMIGA touch dont_ar_4
- ./if_mach M68K AMIGA $(AR) -vrus gc.a gc_cpp.o
- ./if_not_there dont_ar_4 $(AR) ru gc.a gc_cpp.o
- ./if_not_there dont_ar_4 $(RANLIB) gc.a || cat /dev/null
- ./test_cpp 1
- echo > c++
-
-dyn_load_sunos53.o: dyn_load.c
- $(CC) $(CFLAGS) -DSUNOS53_SHARED_LIB -c $(srcdir)/dyn_load.c -o $@
-
-# SunOS5 shared library version of the collector
-sunos5gc.so: $(OBJS) dyn_load_sunos53.o
- $(CC) -G -o sunos5gc.so $(OBJS) dyn_load_sunos53.o -ldl
- ln sunos5gc.so libgc.so
-
-# Alpha/OSF shared library version of the collector
-libalphagc.so: $(OBJS)
- ld -shared -o libalphagc.so $(OBJS) dyn_load.o -lc
- ln libalphagc.so libgc.so
-
-# IRIX shared library version of the collector
-libirixgc.so: $(OBJS) dyn_load.o
- ld -shared $(ABI_FLAG) -o libirixgc.so $(OBJS) dyn_load.o -lc
- ln libirixgc.so libgc.so
-
-# Linux shared library version of the collector
-liblinuxgc.so: $(OBJS) dyn_load.o
- gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o
- ln liblinuxgc.so libgc.so
-
-# Alternative Linux rule. This is preferable, but is likely to break the
-# Makefile for some non-linux platforms.
-# LIBOBJS= $(patsubst %.o, %.lo, $(OBJS))
-#
-#.SUFFIXES: .lo $(SUFFIXES)
-#
-#.c.lo:
-# $(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -c $< -o $@
-#
-# liblinuxgc.so: $(LIBOBJS) dyn_load.lo
-# gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
-# touch liblinuxgc.so
-
-mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s \
- $(srcdir)/mips_ultrix_mach_dep.s \
- $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s \
- $(srcdir)/sparc_mach_dep.S $(srcdir)/sparc_sunos4_mach_dep.s \
- $(srcdir)/ia64_save_regs_in_stack.s \
- $(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
- rm -f mach_dep.o
- ./if_mach MIPS IRIX5 $(CC) -c -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
- ./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
- ./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
- ./if_mach POWERPC DARWIN $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
- ./if_mach ALPHA LINUX $(CC) -c -o mach_dep.o $(srcdir)/alpha_mach_dep.S
- ./if_mach SPARC SUNOS5 $(CC) -c -o mach_dep.o $(srcdir)/sparc_mach_dep.S
- ./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
- ./if_mach SPARC OPENBSD $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
- ./if_mach SPARC NETBSD $(AS) -o mach_dep.o $(srcdir)/sparc_netbsd_mach_dep.s
- ./if_mach IA64 "" as $(AS_ABI_FLAG) -o ia64_save_regs_in_stack.o $(srcdir)/ia64_save_regs_in_stack.s
- ./if_mach IA64 "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
- ./if_mach IA64 "" ld -r -o mach_dep.o mach_dep1.o ia64_save_regs_in_stack.o
- ./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
-
-mark_rts.o: $(srcdir)/mark_rts.c $(UTILS)
- rm -f mark_rts.o
- -./if_mach ALPHA OSF1 $(CC) -c $(CFLAGS) -Wo,-notail $(srcdir)/mark_rts.c
- ./if_not_there mark_rts.o $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
-# Work-around for DEC optimizer tail recursion elimination bug.
-# The ALPHA-specific line should be removed if gcc is used.
-
-alloc.o: version.h
-
-cord:
- mkdir cord
-
-cord/cordbscs.o: cord $(srcdir)/cord/cordbscs.c $(CORD_INCLUDE_FILES)
- $(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordbscs.c
- mv cordbscs.o cord/cordbscs.o
-# not all compilers understand -o filename
-
-cord/cordxtra.o: cord $(srcdir)/cord/cordxtra.c $(CORD_INCLUDE_FILES)
- $(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordxtra.c
- mv cordxtra.o cord/cordxtra.o
-
-cord/cordprnt.o: cord $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
- $(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordprnt.c
- mv cordprnt.o cord/cordprnt.o
-
-cord/cordtest: $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a $(UTILS)
- rm -f cord/cordtest
- ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -lucb
- ./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -ldld `./threadlibs`
- ./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
- ./if_not_there cord/cordtest $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
-
-cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
- rm -f cord/de
- ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
- ./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs`
- ./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
- ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
- ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
- ./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
- ./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_not_there cord/de $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) `./threadlibs`
-
-if_mach: $(srcdir)/if_mach.c $(srcdir)/include/private/gcconfig.h
- $(HOSTCC) $(HOSTCFLAGS) -o if_mach $(srcdir)/if_mach.c
-
-threadlibs: $(srcdir)/threadlibs.c $(srcdir)/include/private/gcconfig.h Makefile
- $(HOSTCC) $(HOSTCFLAGS) -o threadlibs $(srcdir)/threadlibs.c
-
-if_not_there: $(srcdir)/if_not_there.c
- $(HOSTCC) $(HOSTCFLAGS) -o if_not_there $(srcdir)/if_not_there.c
-
-clean:
- rm -f gc.a *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
- setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
- threadlibs $(CORD_OBJS) cord/cordtest cord/de
- -rm -f *~
-
-gctest: tests/test.o gc.a $(UTILS)
- rm -f gctest
- ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o gctest tests/test.o gc.a -lucb
- ./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o gctest tests/test.o gc.a -ldld `./threadlibs`
- ./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o gctest tests/test.o gc.a `./threadlibs`
- ./if_not_there gctest $(CC) $(CFLAGS) -o gctest tests/test.o gc.a `./threadlibs`
-
-# If an optimized setjmp_test generates a segmentation fault,
-# odds are your compiler is broken. Gctest may still work.
-# Try compiling setjmp_t.c unoptimized.
-setjmp_test: $(srcdir)/setjmp_t.c $(srcdir)/include/gc.h $(UTILS)
- $(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c
-
-test: KandRtest cord/cordtest
- cord/cordtest
-
-# Those tests that work even with a K&R C compiler:
-KandRtest: setjmp_test gctest
- ./setjmp_test
- ./gctest
-
-add_gc_prefix: $(srcdir)/add_gc_prefix.c $(srcdir)/version.h
- $(CC) -o add_gc_prefix $(srcdir)/add_gc_prefix.c
-
-gcname: $(srcdir)/gcname.c $(srcdir)/version.h
- $(CC) -o gcname $(srcdir)/gcname.c
-
-gc.tar: $(SRCS) $(DOC_FILES) $(OTHER_FILES) add_gc_prefix gcname
- cp Makefile Makefile.old
- cp Makefile.direct Makefile
- rm -f `./gcname`
- ln -s . `./gcname`
- ./add_gc_prefix $(SRCS) $(DOC_FILES) $(OTHER_FILES) > /tmp/gc.tar-files
- tar cvfh gc.tar `cat /tmp/gc.tar-files`
- cp gc.tar `./gcname`.tar
- gzip `./gcname`.tar
- rm `./gcname`
-
-pc_gc.tar: $(SRCS) $(OTHER_FILES)
- tar cvfX pc_gc.tar pc_excludes $(SRCS) $(OTHER_FILES)
-
-floppy: pc_gc.tar
- -mmd a:/cord
- -mmd a:/cord/private
- -mmd a:/include
- -mmd a:/include/private
- mkdir /tmp/pc_gc
- cat pc_gc.tar | (cd /tmp/pc_gc; tar xvf -)
- -mcopy -tmn /tmp/pc_gc/* a:
- -mcopy -tmn /tmp/pc_gc/cord/* a:/cord
- -mcopy -mn /tmp/pc_gc/cord/de_win.ICO a:/cord
- -mcopy -tmn /tmp/pc_gc/cord/private/* a:/cord/private
- -mcopy -tmn /tmp/pc_gc/include/* a:/include
- -mcopy -tmn /tmp/pc_gc/include/private/* a:/include/private
- rm -r /tmp/pc_gc
-
-gc.tar.Z: gc.tar
- compress gc.tar
-
-gc.tar.gz: gc.tar
- gzip gc.tar
-
-lint: $(CSRCS) tests/test.c
- lint -DLINT $(CSRCS) tests/test.c | egrep -v "possible pointer alignment problem|abort|exit|sbrk|mprotect|syscall|change in ANSI|improper alignment"
-
-# BTL: added to test shared library version of collector.
-# Currently works only under SunOS5. Requires GC_INIT call from statically
-# loaded client code.
-ABSDIR = `pwd`
-gctest_dyn_link: tests/test.o libgc.so
- $(CC) -L$(ABSDIR) -R$(ABSDIR) -o gctest_dyn_link tests/test.o -lgc -ldl -lthread
-
-gctest_irix_dyn_link: tests/test.o libirixgc.so
- $(CC) -L$(ABSDIR) -o gctest_irix_dyn_link tests/test.o -lirixgc
-
-# The following appear to be dead, especially since libgc_globals.h
-# is apparently lost.
-test_dll.o: tests/test.c libgc_globals.h
- $(CC) $(CFLAGS) -DGC_USE_DLL -c tests/test.c -o test_dll.o
-
-test_dll: test_dll.o libgc_dll.a libgc.dll
- $(CC) test_dll.o -L$(ABSDIR) -lgc_dll -o test_dll
-
-SYM_PREFIX-libgc=GC
-
-# Uncomment the following line to build a GNU win32 DLL
-# include Makefile.DLLs
-
-reserved_namespace: $(SRCS)
- for file in $(SRCS) tests/test.c tests/test_cpp.cc; do \
- sed s/GC_/_GC_/g < $$file > tmp; \
- cp tmp $$file; \
- done
-
-user_namespace: $(SRCS)
- for file in $(SRCS) tests/test.c tests/test_cpp.cc; do \
- sed s/_GC_/GC_/g < $$file > tmp; \
- cp tmp $$file; \
- done
diff --git a/boehm-gc/Makefile.DLLs b/boehm-gc/Makefile.DLLs
deleted file mode 100644
index 011f49d3bcf..00000000000
--- a/boehm-gc/Makefile.DLLs
+++ /dev/null
@@ -1,107 +0,0 @@
-#-----------------------------------------------------------------------------#
-
-# Makefile.DLLs, version 0.4.
-
-# Contributed by Fergus Henderson.
-
-# This Makefile contains rules for creating DLLs on Windows using gnu-win32.
-
-#-----------------------------------------------------------------------------#
-
-# This rule creates a `.def' file, which lists the symbols that are exported
-# from the DLL. We use `nm' to get a list of all the exported text (`T')
-# symbols and data symbols -- including uninitialized data (`B'),
-# initialized data (`D'), read-only data (`R'), and common blocks (`C').
-%.def: %.a
- echo EXPORTS > $@
- nm $< | grep '^........ [BCDRT] _' | sed 's/[^_]*_//' >> $@
-
-# We need to use macros to access global data:
-# the user of the DLL must refer to `foo' as `(*__imp_foo)'.
-# This rule creates a `_globals.h' file, which contains macros
-# for doing this.
-
-SYM_PREFIX = $(firstword $(SYM_PREFIX-$*) $*)
-DLL_MACRO = $(SYM_PREFIX)_USE_DLL
-IMP_MACRO = $(SYM_PREFIX)_IMP
-GLOBAL_MACRO = $(SYM_PREFIX)_GLOBAL
-
-%_globals.h: %.a
- echo "/* automatically generated by Makefile.DLLs */" > $@
- echo "#if defined(__GNUC__) && defined(_WIN32) \\" >> $@
- echo " && defined($(DLL_MACRO))" >> $@
- echo "# define $(IMP_MACRO)(name) __imp_##name" >> $@
- echo "# define $(GLOBAL_MACRO)(name) (*$(IMP_MACRO)(name))" >> $@
- echo "#else" >> $@
- echo "# define $(GLOBAL_MACRO)(name) name" >> $@
- echo "#endif" >> $@
- echo "" >> $@
- for sym in `nm $< | grep '^........ [BCDR] _' | sed 's/[^_]*_//'`; do \
- echo "#define $$sym $(GLOBAL_MACRO)($$sym)" >> $@; \
- done
-
-# This rule creates the export object file (`foo.exp') which contains the
-# jump table array; this export object file becomes part of the DLL.
-# This rule also creates the import library (`foo_dll.a') which contains small
-# stubs for all the functions exported by the DLL which jump to them via the
-# jump table. Executables that will use the DLL must be linked against this
-# stub library.
-%.exp %_dll.a : %.def
- dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*) \
- --def $< \
- --dllname $*.dll \
- --output-exp $*.exp \
- --output-lib $*_dll.a
-
-# The `sed' commands below are to convert DOS-style `C:\foo\bar'
-# pathnames into Unix-style `//c/foo/bar' pathnames.
-CYGWIN32_LIBS = $(shell echo \
- -L`dirname \`gcc -print-file-name=libgcc.a | \
- sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
- -L`dirname \`gcc -print-file-name=libcygwin.a | \
- sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
- -L`dirname \`gcc -print-file-name=libkernel32.a | \
- sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
- -lgcc -lcygwin -lkernel32 -lgcc)
-
-RELOCATABLE=yes
-
-ifeq "$(strip $(RELOCATABLE))" "yes"
-
-# to create relocatable DLLs, we need to do two passes
-%.dll: %.exp %.a dll_fixup.o dll_init.o
- $(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $*.base \
- -e _dll_entry@12 dll_init.o \
- dll_fixup.o $*.exp $*.a \
- $(LDLIBS) $(LDLIBS-$*) \
- $(CYGWIN32_LIBS)
- $(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll --base-file $*.base -o $@ \
- -e _dll_entry@12 dll_init.o \
- dll_fixup.o $*.exp $*.a \
- $(LDLIBS) $(LDLIBS-$*) \
- $(CYGWIN32_LIBS)
- rm -f $*.base
-else
-
-%.dll: %.exp %.a dll_fixup.o dll_init.o
- $(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $@ \
- -e _dll_entry@12 dll_init.o \
- dll_fixup.o $*.exp $*.a \
- $(LDLIBS) $(LDLIBS-$*) \
- $(CYGWIN32_LIBS)
-
-endif
-
-# This black magic piece of assembler needs to be linked in in order to
-# properly terminate the list of imported DLLs.
-dll_fixup.s:
- echo '.section .idata$$3' > dll_fixup.s
- echo '.long 0,0,0,0, 0,0,0,0' >> dll_fixup.s
-
-# This bit is necessary to provide an initialization function for the DLL.
-dll_init.c:
- echo '__attribute__((stdcall))' > dll_init.c
- echo 'int dll_entry(int handle, int reason, void *ptr)' >> dll_init.c
- echo '{return 1; }' >> dll_init.c
-
-dont_throw_away: dll_fixup.o dll_init.o
diff --git a/boehm-gc/Makefile.am b/boehm-gc/Makefile.am
index 2aba243231f..2aacca29612 100644
--- a/boehm-gc/Makefile.am
+++ b/boehm-gc/Makefile.am
@@ -1,182 +1,204 @@
# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
-#
+#
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-#
+#
# Permission is hereby granted to use or copy this program
# for any purpose, provided the above notices are retained on all copies.
# Permission to modify the code and to distribute modified code is granted,
# provided the above notices are retained, and a notice that the code was
# modified is included with the above copyright notice.
-#
-# Original author: Tom Tromey
-# Severely truncated by Hans-J. Boehm
-# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
## Process this file with automake to produce Makefile.in.
## FIXME: `make distcheck' in this directory will not currently work.
## This is most likely to the explicit flags passed to submakes.
-AUTOMAKE_OPTIONS = foreign
-
-SUBDIRS = doc include
-
-EXTRA_DIST =
- ## more items will be succesively added below
-
-if CPLUSPLUS
-extra = libgccpp.la
+# We currently use the source files directly from libatomic_ops, if we
+# use the internal version. This is done since libatomic_ops doesn't
+# use libtool, since it has no real use for it. But that seems to make
+# it hard to use either the resulting object files or libraries.
+# Thus there seems too be no real reason to recursively build in the
+# libatomic_ops directory.
+# if USE_INTERNAL_LIBATOMICS_OPS
+# SUBDIRS = @maybe_libatomic_ops@
+# else
+# SUBDIRS =
+# endif
+SUBDIRS =
+
+ACLOCAL_AMFLAGS = -I m4
+AM_CPPFLAGS = \
+ -I$(top_builddir)/include -I$(top_srcdir)/include \
+ $(ATOMIC_OPS_CFLAGS)
+
+# Initialize variables so that we can declare files locally.
+EXTRA_DIST =
+lib_LTLIBRARIES =
+include_HEADERS =
+pkginclude_HEADERS =
+dist_noinst_HEADERS =
+check_PROGRAMS =
+check_LTLIBRARIES =
+TESTS =
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = bdw-gc.pc
+
+# C Library
+# ---------
+
+lib_LTLIBRARIES += libgc.la
+if SINGLE_GC_OBJ
+libgc_la_SOURCES = extra/gc.c
+else
+EXTRA_DIST += extra/gc.c
+libgc_la_SOURCES = \
+ allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
+ dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c \
+ mach_dep.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
+ obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
+ specific.c stubborn.c thread_local_alloc.c typd_mlc.c
+
+# C Library: Architecture Dependent
+# ---------------------------------
+
+if WIN32_THREADS
+libgc_la_SOURCES += win32_threads.c
else
-extra =
+if PTHREADS
+libgc_la_SOURCES += pthread_start.c pthread_support.c
+if DARWIN_THREADS
+libgc_la_SOURCES += darwin_stop_world.c
+else
+libgc_la_SOURCES += pthread_stop_world.c
+endif
+endif
endif
-lib_LTLIBRARIES = libgc.la $(extra)
-include_HEADERS = include/gc.h include/gc_local_alloc.h \
-include/gc_pthread_redirects.h include/gc_config_macros.h \
-include/leak_detector.h include/gc_typed.h @addincludes@
+if MAKE_BACK_GRAPH
+libgc_la_SOURCES += backgraph.c
+endif
-EXTRA_HEADERS = include/gc_cpp.h include/gc_allocator.h
+if ENABLE_DISCLAIM
+libgc_la_SOURCES += fnlz_mlc.c
+endif
-if POWERPC_DARWIN
-asm_libgc_sources = powerpc_darwin_mach_dep.s
-else
-asm_libgc_sources =
endif
-libgc_la_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
-dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \
-malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
-obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
-solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
-backgraph.c win32_threads.c \
-pthread_support.c pthread_stop_world.c darwin_stop_world.c \
-$(asm_libgc_sources)
+if USE_INTERNAL_LIBATOMIC_OPS
+nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops.c
+endif
+
+if NEED_ATOMIC_OPS_ASM
+nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops_sysdeps.S
+endif
-# Include THREADLIBS here to ensure that the correct versions of
+# Include THREADDLLIBS here to ensure that the correct versions of
# linuxthread semaphore functions get linked:
-libgc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS)
+libgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS) $(ATOMIC_OPS_LIBS)
libgc_la_DEPENDENCIES = @addobjs@
-libgc_la_LDFLAGS = -version-info 1:2:0
+libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info 1:3:0 -no-undefined
-EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
- mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
- rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
- sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
+EXTRA_libgc_la_SOURCES = src/ia64_save_regs_in_stack.s src/sparc_mach_dep.S \
+ src/sparc_netbsd_mach_dep.s src/sparc_sunos4_mach_dep.s
-libgccpp_la_SOURCES = gc_cpp.cc
-libgccpp_la_LIBADD = $(THREADLIBS) $(UNWINDLIBS)
-libgccpp_la_LDFLAGS = -version-info 1:2:0
-EXTRA_DIST += alpha_mach_dep.S mips_sgi_mach_dep.s sparc_mach_dep.S
-
-AM_CXXFLAGS = @GC_CFLAGS@
-AM_CFLAGS = @GC_CFLAGS@
+# C++ Interface
+# -------------
if CPLUSPLUS
-extra_checks = test_cpp
-else
-extra_checks =
+lib_LTLIBRARIES += libgccpp.la
+pkginclude_HEADERS += include/gc_cpp.h
+include_HEADERS += include/extra/gc_cpp.h
+libgccpp_la_SOURCES = gc_cpp.cc
+libgccpp_la_LIBADD = ./libgc.la
+libgccpp_la_LDFLAGS = -version-info 1:3:0 -no-undefined
endif
-check_PROGRAMS = gctest $(extra_checks)
+# FIXME: If Visual C++ users use Makefile.am, this should go into
+# pkginclude_HEADERS with proper AM_CONDITIONALization. Otherwise
+# delete this comment.
+EXTRA_DIST += gc_cpp.cpp
-test.o: $(srcdir)/tests/test.c
- $(COMPILE) -c $(srcdir)/tests/test.c
-# Using $< in the above seems to fail with the HP/UX on Itanium make.
-test_cpp.o: $(srcdir)/tests/test_cpp.cc
- $(CXXCOMPILE) -c $(srcdir)/tests/test_cpp.cc
-## FIXME: this is probably the reason why some files from BUILT_SOURCES
-## are included in the distribution
-# gctest_OBJECTS = test.o
-gctest_SOURCES = tests/test.c
-gctest_LDADD = ./libgc.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
-test_cpp_SOURCES = tests/test_cpp.cc
-test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
+# Misc
+# ----
-TESTS = gctest $(extra_checks)
+AM_CXXFLAGS = @GC_CFLAGS@
+AM_CFLAGS = @GC_CFLAGS@
## FIXME: relies on internal code generated by automake.
-all_objs = @addobjs@ $(libgc_la_OBJECTS)
-$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
-include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
-include/gc_pthread_redirects.h include/gc_config_macros.h \
-include/gc_mark.h @addincludes@
+## FIXME: ./configure --enable-dependency-tracking should be used
+#all_objs = @addobjs@ $(libgc_la_OBJECTS)
+#$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
+#include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
+#include/gc_pthread_redirects.h include/gc_config_macros.h \
+#include/private/thread_local_alloc.h include/private_support.h \
+#include/private/pthread_stop_world.h \
+#include/gc_mark.h @addincludes@
## FIXME: we shouldn't have to do this, but automake forces us to.
-.s.lo:
## We use -Wp,-P to strip #line directives. Irix `as' chokes on
## these.
- $(LTCOMPILE) -Wp,-P -x assembler-with-cpp -c $<
+if COMPILER_XLC
+ ## XLC neither requires nor tolerates the unnecessary assembler goop
+ ASM_CPP_OPTIONS =
+else
+ ## We use -Wp,-P to strip #line directives. Irix `as' chokes on
+ ## these.
+ ASM_CPP_OPTIONS = -Wp,-P -x assembler-with-cpp
+endif
+.s.lo:
+ $(LTCOMPILE) $(ASM_CPP_OPTIONS) -c $<
-## We have our own definition of LTCOMPILE because we want to use our
-## CFLAGS, not those passed in from the top level make.
-LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) \
- $(AM_CPPFLAGS) $(CPPFLAGS) \
- $(AM_CFLAGS) $(MY_CFLAGS) $(GC_CFLAGS)
-LINK = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(MY_CFLAGS) $(LDFLAGS) -o $@
+.S.lo:
+ $(LTCOMPILE) $(ASM_CPP_OPTIONS) -c $<
## We need to add DEFS to assembler flags
## :FIXME: what if assembler does not accept -D... ?
-## (use Autoconf to prepare ASDEFS ???)
+## (use Autoconf to prepare ASDEFS?)
CCASFLAGS += $(DEFS)
-dist_noinst_SCRIPTS = callprocs configure.host
- ## callprocs --- used by Makefile.{dj,direct}
- ## configure.host --- used by Makefile.{am,dj,direct}
-
# headers which are not installed
-# (see include/Makefile.am for more)
+# (see include/include.am for more)
#
-dist_noinst_HEADERS = version.h
# documentation which is not installed
#
-EXTRA_DIST += README.QUICK
+EXTRA_DIST += README.QUICK TODO
# other makefiles
# :GOTCHA: deliberately we do not include 'Makefile'
-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
+EXTRA_DIST += BCC_MAKEFILE NT_MAKEFILE \
+ OS2_MAKEFILE PCR-Makefile digimars.mak EMX_MAKEFILE \
+ Makefile.direct Makefile.dj SMakefile.amiga \
+ WCC_MAKEFILE autogen.sh build_atomic_ops.sh build_atomic_ops.sh.cygwin \
+ NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE \
+ NT_X64_THREADS_MAKEFILE CMakeLists.txt tests/CMakeLists.txt
# files used by makefiles other than Makefile.am
#
-EXTRA_DIST += add_gc_prefix.c gcname.c if_mach.c if_not_there.c \
- hpux_test_and_clear.s pc_excludes gc.mak MacOS.c \
- MacProjects.sit.hqx mach_dep.c setjmp_t.c \
- threadlibs.c AmigaOS.c \
- Mac_files/datastart.c Mac_files/dataend.c \
- Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h
-
-# part of C++ interface
-#
-EXTRA_DIST += gc_cpp.cc gc_cpp.cpp
-
-# tests not used by Makefile.am (:FIXME: why?)
-#
-EXTRA_DIST += tests/test_cpp.cc tests/trace_test.c \
- tests/leak_test.c tests/thread_leak_test.c
-
-# cord package
-#
-EXTRA_DIST += cord/cordbscs.c cord/cordtest.c cord/de.c cord/de_win.c \
- cord/de_win.ICO cord/cordprnt.c cord/cordxtra.c cord/de_cmds.h \
- cord/de_win.h cord/de_win.RC
+EXTRA_DIST += tools/add_gc_prefix.c tools/gcname.c tools/if_mach.c \
+ tools/if_not_there.c tools/setjmp_t.c tools/threadlibs.c \
+ gc.mak extra/MacOS.c extra/AmigaOS.c \
+ extra/symbian/global_end.cpp extra/symbian/global_start.cpp \
+ extra/symbian/init_global_static_roots.cpp extra/symbian.cpp \
+ build/s60v3/bld.inf build/s60v3/libgc.mmp \
+ extra/Mac_files/datastart.c extra/Mac_files/dataend.c \
+ extra/Mac_files/MacOS_config.h \
+ include/private/msvc_dbg.h extra/msvc_dbg.c tools/callprocs.sh
-# this is an auxiliary shell file used by Makefile and Makefile.direct
#
-CONFIG_STATUS_DEPENDENCIES = $(srcdir)/configure.host
-
-# :FIXME: why do we distribute this one???
-#
-EXTRA_DIST += libtool.m4
-
-#
-# :GOTCHA: GNU make rule for making .s out of .S is flawed,
+# :GOTCHA: GNU make rule for making .s out of .S is flawed,
# it will not remove dest if building fails
.S.s:
if $(CPP) $< >$@ ; then :; else rm -f $@; fi
+
+include include/include.am
+include cord/cord.am
+include tests/tests.am
+include doc/doc.am
+# Putting these at the top causes cord to be built first, and not find libgc.a
+# on HP/UX. There may be a better fix.
diff --git a/boehm-gc/Makefile.direct b/boehm-gc/Makefile.direct
index 20fa40a9a08..c1f92ecf991 100644
--- a/boehm-gc/Makefile.direct
+++ b/boehm-gc/Makefile.direct
@@ -6,10 +6,11 @@
# c++ - adds C++ interface to library
# cords - adds cords (heavyweight strings) to library
# test - prints porting information, then builds basic version of gc.a,
-# and runs some tests of collector and cords. Does not add cords or
-# c++ interface to gc.a
+# and runs some tests of collector and cords. Does not add cords or
+# c++ interface to gc.a
# cord/de - builds dumb editor based on cords.
-ABI_FLAG=
+
+ABI_FLAG=
# ABI_FLAG should be the cc flag that specifies the ABI. On most
# platforms this will be the empty string. Possible values:
# +DD64 for 64-bit executable on HP/UX.
@@ -30,13 +31,21 @@ AS=as $(AS_ABI_FLAG)
srcdir= .
VPATH= $(srcdir)
-CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_PERMISSION -DSILENT -DALL_INTERIOR_POINTERS
+# Atomic_ops installation directory. If this doesn't exist, we create
+# it from the included libatomic_ops distribution.
+AO_SRC_DIR=$(srcdir)/libatomic_ops
+AO_INSTALL_DIR=$(srcdir)/libatomic_ops-install
+
+CFLAGS= -O -I$(srcdir)/include -I$(AO_INSTALL_DIR)/include -DATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS
# To build the parallel collector on Linux, add to the above:
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
+# To build the thread-capable preload library that intercepts
+# malloc, add -DGC_USE_DLOPEN_WRAP -DREDIRECT_MALLOC=GC_malloc -fpic
# To build the parallel collector in a static library on HP/UX,
# add to the above:
-# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L
+# -DGC_HPUX_THREADS -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L -mt
+# FIXME: PARALLEL_MARK currently broken on HP/UX.
# To build the thread-safe collector on Tru64, add to the above:
# -pthread -DGC_OSF1_THREADS
@@ -53,302 +62,96 @@ HOSTCFLAGS=$(CFLAGS)
# Setjmp_test may yield overly optimistic results when compiled
# without optimization.
-# These define arguments influence the collector configuration:
-# -DSILENT disables statistics printing, and improves performance.
-# -DFIND_LEAK causes GC_find_leak to be initially set.
-# This causes the collector to assume that all inaccessible
-# objects should have been explicitly deallocated, and reports exceptions.
-# Finalization and the test program are not usable in this mode.
-# -DGC_SOLARIS_THREADS enables support for Solaris (thr_) threads.
-# (Clients should also define GC_SOLARIS_THREADS and then include
-# gc.h before performing thr_ or dl* or GC_ operations.)
-# Must also define -D_REENTRANT.
-# -DGC_SOLARIS_PTHREADS enables support for Solaris pthreads.
-# (Internally this define GC_SOLARIS_THREADS as well.)
-# -DGC_IRIX_THREADS enables support for Irix pthreads. See README.irix.
-# -DGC_HPUX_THREADS enables support for HP/UX 11 pthreads.
-# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
-# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
-# see README.linux. -D_REENTRANT may also be required.
-# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
-# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
-# Appeared to run into some underlying thread problems.
-# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested.
-# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
-# See README.DGUX386.
-# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
-# for this Makefile only under Cygwin.
-# -DGC_THREADS should set the appropriate one of the above macros.
-# It assumes pthreads for Solaris.
-# -DALL_INTERIOR_POINTERS allows all pointers to the interior
-# of objects to be recognized. (See gc_priv.h for consequences.)
-# Alternatively, GC_all_interior_pointers can be set at process
-# initialization time.
-# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
-# usually causing it to use less space in such situations.
-# Incremental collection no longer works in this case.
-# -DLARGE_CONFIG tunes the collector for unusually large heaps.
-# Necessary for heaps larger than about 500 MB on most machines.
-# Recommended for heaps larger than about 64 MB.
-# -DDONT_ADD_BYTE_AT_END is meaningful only with -DALL_INTERIOR_POINTERS or
-# GC_all_interior_pointers = 1. Normally -DALL_INTERIOR_POINTERS
-# causes all objects to be padded so that pointers just past the end of
-# an object can be recognized. This can be expensive. (The padding
-# is normally more than one byte due to alignment constraints.)
-# -DDONT_ADD_BYTE_AT_END disables the padding.
-# -DNO_SIGNALS does not disable signals during critical parts of
-# the GC process. This is no less correct than many malloc
-# implementations, and it sometimes has a significant performance
-# impact. However, it is dangerous for many not-quite-ANSI C
-# programs that call things like printf in asynchronous signal handlers.
-# This is on by default. Turning it off has not been extensively tested with
-# compilers that reorder stores. It should have been.
-# -DNO_EXECUTE_PERMISSION may cause some or all of the heap to not
-# have execute permission, i.e. it may be impossible to execute
-# code from the heap. Currently this only affects the incremental
-# collector on UNIX machines. It may greatly improve its performance,
-# since this may avoid some expensive cache synchronization.
-# -DGC_NO_OPERATOR_NEW_ARRAY declares that the C++ compiler does not support
-# the new syntax "operator new[]" for allocating and deleting arrays.
-# See gc_cpp.h for details. No effect on the C part of the collector.
-# This is defined implicitly in a few environments. Must also be defined
-# by clients that use gc_cpp.h.
-# -DREDIRECT_MALLOC=X causes malloc to be defined as alias for X.
-# Unless the following macros are defined, realloc is also redirected
-# to GC_realloc, and free is redirected to GC_free.
-# Calloc and strdup are redefined in terms of the new malloc. X should
-# be either GC_malloc or GC_malloc_uncollectable, or
-# GC_debug_malloc_replacement. (The latter invokes GC_debug_malloc
-# with dummy source location information, but still results in
-# properly remembered call stacks on Linux/X86 and Solaris/SPARC.
-# It requires that the following two macros also be used.)
-# The former is occasionally useful for working around leaks in code
-# you don't want to (or can't) look at. It may not work for
-# existing code, but it often does. Neither works on all platforms,
-# since some ports use malloc or calloc to obtain system memory.
-# (Probably works for UNIX, and win32.) If you build with DBG_HDRS_ALL,
-# you should only use GC_debug_malloc_replacement as a malloc
-# replacement.
-# -DREDIRECT_REALLOC=X causes GC_realloc to be redirected to X.
-# The canonical use is -DREDIRECT_REALLOC=GC_debug_realloc_replacement,
-# together with -DREDIRECT_MALLOC=GC_debug_malloc_replacement to
-# generate leak reports with call stacks for both malloc and realloc.
-# This also requires the following:
-# -DREDIRECT_FREE=X causes free to be redirected to X. The
-# canonical use is -DREDIRECT_FREE=GC_debug_free.
-# -DIGNORE_FREE turns calls to free into a noop. Only useful with
-# -DREDIRECT_MALLOC.
-# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
-# Reduces code size slightly at the expense of debuggability.
-# -DJAVA_FINALIZATION makes it somewhat safer to finalize objects out of
-# order by specifying a nonstandard finalization mark procedure (see
-# finalize.c). Objects reachable from finalizable objects will be marked
-# in a sepearte postpass, and hence their memory won't be reclaimed.
-# Not recommended unless you are implementing a language that specifies
-# these semantics. Since 5.0, determines only only the initial value
-# of GC_java_finalization variable.
-# -DFINALIZE_ON_DEMAND causes finalizers to be run only in response
-# to explicit GC_invoke_finalizers() calls.
-# In 5.0 this became runtime adjustable, and this only determines the
-# initial value of GC_finalize_on_demand.
-# -DATOMIC_UNCOLLECTABLE includes code for GC_malloc_atomic_uncollectable.
-# This is useful if either the vendor malloc implementation is poor,
-# or if REDIRECT_MALLOC is used.
-# -DHBLKSIZE=ddd, where ddd is a power of 2 between 512 and 16384, explicitly
-# sets the heap block size. Each heap block is devoted to a single size and
-# kind of object. For the incremental collector it makes sense to match
-# the most likely page size. Otherwise large values result in more
-# fragmentation, but generally better performance for large heaps.
-# -DUSE_MMAP use MMAP instead of sbrk to get new memory.
-# Works for Solaris and Irix.
-# -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.
-# -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
-# the garbage collector detects a value that looks almost, but not quite,
-# like a pointer, print both the address containing the value, and the
-# value of the near-bogus-pointer. Can be used to identifiy regions of
-# memory that are likely to contribute misidentified pointers.
-# -DKEEP_BACK_PTRS Add code to save back pointers in debugging headers
-# for objects allocated with the debugging allocator. If all objects
-# through GC_MALLOC with GC_DEBUG defined, this allows the client
-# to determine how particular or randomly chosen objects are reachable
-# for debugging/profiling purposes. The gc_backptr.h interface is
-# implemented only if this is defined.
-# -DGC_ASSERTIONS Enable some internal GC assertion checking. Currently
-# this facility is only used in a few places. It is intended primarily
-# for debugging of the garbage collector itself, but could also
-# -DDBG_HDRS_ALL Make sure that all objects have debug headers. Increases
-# the reliability (from 99.9999% to 100% mod. bugs) of some of the debugging
-# code (especially KEEP_BACK_PTRS). Makes -DSHORT_DBG_HDRS possible.
-# Assumes that all client allocation is done through debugging
-# allocators.
-# -DSHORT_DBG_HDRS Assume that all objects have debug headers. Shorten
-# the headers to minimize object size, at the expense of checking for
-# writes past the end of an object. This is intended for environments
-# in which most client code is written in a "safe" language, such as
-# Scheme or Java. Assumes that all client allocation is done using
-# 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
-# on which we can quickly generate call stacks, currently Linux/(X86 & SPARC)
-# and Solaris/SPARC and platforms that provide execinfo.h.
-# Default is zero. On X86, client
-# code should NOT be compiled with -fomit-frame-pointer.
-# -DSAVE_CALL_NARGS=<n> Set the number of functions arguments to be
-# saved with each call frame. Default is zero. Ignored if we
-# don't know how to retrieve arguments on the platform.
-# -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
-# altered stubborn objects, at substantial performance cost.
-# Use only for debugging of the incremental collector.
-# -DGC_GCJ_SUPPORT includes support for gcj (and possibly other systems
-# that include a pointer to a type descriptor in each allocated object).
-# Building this way requires an ANSI C compiler.
-# -DUSE_I686_PREFETCH causes the collector to issue Pentium III style
-# prefetch instructions. No effect except on X86 Linux platforms.
-# Assumes a very recent gcc-compatible compiler and assembler.
-# (Gas prefetcht0 support was added around May 1999.)
-# Empirically the code appears to still run correctly on Pentium II
-# processors, though with no performance benefit. May not run on other
-# X86 processors? In some cases this improves performance by
-# 15% or so.
-# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
-# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
-# Minimally tested. Didn't appear to be an obvious win on a K6-2/500.
-# -DUSE_PPC_PREFETCH causes the collector to issue PowerPC style
-# prefetch instructions. No effect except on PowerPC OS X platforms.
-# Performance impact untested.
-# -DGC_USE_LD_WRAP in combination with the old flags listed in README.linux
-# causes the collector some system and pthread calls in a more transparent
-# fashion than the usual macro-based approach. Requires GNU ld, and
-# currently probably works only with Linux.
-# -DTHREAD_LOCAL_ALLOC defines GC_local_malloc(), GC_local_malloc_atomic()
-# and GC_local_gcj_malloc(). Needed for gc_gcj.h interface. These allocate
-# in a way that usually does not involve acquisition of a global lock.
-# Currently requires -DGC_LINUX_THREADS, but should be easy to port to
-# other pthreads environments. Recommended for multiprocessors.
-# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
-# "__thread" thread-local variables. This is the default in HP/UX. It
-# may help performance on recent Linux installations. (It failed for
-# me on RedHat 8, but appears to work on RedHat 9.)
-# -DPARALLEL_MARK allows the marker to run in multiple threads. Recommended
-# for multiprocessors. Currently requires Linux on X86 or IA64, though
-# support for other Posix platforms should be fairly easy to add,
-# if the thread implementation is otherwise supported.
-# -DNO_GETENV prevents the collector from looking at environment variables.
-# These may otherwise alter its configuration, or turn off GC altogether.
-# I don't know of a reason to disable this, except possibly if the
-# resulting process runs as a privileged user?
-# -DUSE_GLOBAL_ALLOC. Win32 only. Use GlobalAlloc instead of
-# VirtualAlloc to allocate the heap. May be needed to work around
-# a Windows NT/2000 issue. Incompatible with USE_MUNMAP.
-# See README.win32 for details.
-# -DMAKE_BACK_GRAPH. Enable GC_PRINT_BACK_HEIGHT environment variable.
-# See README.environment for details. Experimental. Limited platform
-# support. Implies DBG_HDRS_ALL. All allocation should be done using
-# the debug interface.
-# -DSTUBBORN_ALLOC allows allocation of "hard to change" objects, and thus
-# makes incremental collection easier. Was enabled by default until 6.0.
-# Rarely used, to my knowledge.
-# -DHANDLE_FORK attempts to make GC_malloc() work in a child process fork()ed
-# from a multithreaded parent. Currently only supported by pthread_support.c.
-# (Similar code should work on Solaris or Irix, but it hasn't been tried.)
-# -DTEST_WITH_SYSTEM_MALLOC causes gctest to allocate (and leak) large chunks
-# of memory with the standard system malloc. This will cause the root
-# set and collected heap to grow significantly if malloced memory is
-# somehow getting traced by the collector. This has no impact on the
-# generated library; it only affects the test.
-# -DPOINTER_MASK=0x... causes candidate pointers to be ANDed with the
-# given mask before being considered. If either this or the following
-# macro is defined, it will be assumed that all pointers stored in
-# the heap need to be processed this way. Stack and register pointers
-# will be considered both with and without processing.
-# These macros are normally needed only to support systems that use
-# high-order pointer tags. EXPERIMENTAL.
-# -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers
-# by the indicated amount before trying to interpret them. Applied
-# after POINTER_MASK. EXPERIMENTAL. See also the preceding macro.
-#
+# Look into doc/README.macros for the description of the "define arguments"
+# influencing the collector configuration.
-CXXFLAGS= $(CFLAGS)
+CXXFLAGS= $(CFLAGS)
AR= ar
RANLIB= ranlib
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o aix_irix_threads.o pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_threads.o
-
-CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c aix_irix_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
-
-CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC
-
-CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
-
-SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.S \
- sparc_mach_dep.S include/gc.h include/gc_typed.h \
- include/private/gc_hdrs.h include/private/gc_priv.h \
- include/private/gcconfig.h include/private/gc_pmark.h \
- include/gc_inl.h include/gc_inline.h include/gc_mark.h \
- threadlibs.c if_mach.c if_not_there.c gc_cpp.cc include/gc_cpp.h \
- gcname.c include/weakpointer.h include/private/gc_locks.h \
- gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h \
- include/new_gc_alloc.h include/gc_allocator.h \
- include/javaxfc.h sparc_sunos4_mach_dep.s sparc_netbsd_mach_dep.s \
- include/private/solaris_threads.h include/gc_backptr.h \
- hpux_test_and_clear.s include/gc_gcj.h \
- include/gc_local_alloc.h include/private/dbg_mlc.h \
- include/private/specific.h powerpc_darwin_mach_dep.s \
- include/leak_detector.h include/gc_amiga_redirects.h \
- include/gc_pthread_redirects.h ia64_save_regs_in_stack.s \
- include/gc_config_macros.h include/private/pthread_support.h \
- include/private/pthread_stop_world.h include/private/darwin_semaphore.h \
- include/private/darwin_stop_world.h $(CORD_SRCS)
-
-DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
- doc/README.amiga doc/README.cords doc/debugging.html \
- doc/README.dj doc/README.hp doc/README.linux doc/README.rs6000 \
- doc/README.sgi doc/README.solaris2 doc/README.uts \
- doc/README.win32 doc/barrett_diagram doc/README \
- doc/README.contributors doc/README.changes doc/gc.man \
- doc/README.environment doc/tree.html doc/gcdescr.html \
- doc/README.autoconf doc/README.macros doc/README.ews4800 \
- doc/README.DGUX386 doc/README.arm.cross doc/leak.html \
- doc/scale.html doc/gcinterface.html doc/README.darwin \
- doc/simple_example.html
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o \
+ headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o \
+ malloc.o stubborn.o checksums.o pthread_support.o pthread_stop_world.o \
+ darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o gcj_mlc.o specific.o \
+ gc_dlopen.o backgraph.o win32_threads.o pthread_start.o \
+ thread_local_alloc.o fnlz_mlc.o
+
+CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c \
+ headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c \
+ new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c \
+ checksums.c pthread_support.c pthread_stop_world.c darwin_stop_world.c \
+ typd_mlc.c ptr_chck.c mallocx.c gcj_mlc.c specific.c gc_dlopen.c \
+ backgraph.c win32_threads.c pthread_start.c thread_local_alloc.c fnlz_mlc.c
+
+CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/tests/de.c \
+ cord/tests/cordtest.c include/cord.h include/ec.h \
+ include/cord_pos.h cord/tests/de_win.c cord/tests/de_win.h \
+ cord/tests/de_cmds.h cord/tests/de_win.rc
+
+CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
+
+SRCS= $(CSRCS) \
+ include/gc.h include/gc_typed.h include/gc_tiny_fl.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 include/gc_disclaim.h \
+ tools/threadlibs.c \
+ tools/if_mach.c tools/if_not_there.c gc_cpp.cc include/gc_cpp.h \
+ tools/gcname.c include/weakpointer.h include/private/gc_locks.h \
+ include/new_gc_alloc.h include/gc_allocator.h \
+ include/javaxfc.h \
+ include/gc_backptr.h include/gc_gcj.h include/private/dbg_mlc.h \
+ include/private/specific.h include/leak_detector.h \
+ include/gc_pthread_redirects.h \
+ include/gc_config_macros.h include/private/pthread_support.h \
+ include/private/pthread_stop_world.h include/private/darwin_semaphore.h \
+ include/private/darwin_stop_world.h include/private/thread_local_alloc.h \
+ src/ia64_save_regs_in_stack.s src/sparc_mach_dep.S \
+ src/sparc_netbsd_mach_dep.s src/sparc_sunos4_mach_dep.s $(CORD_SRCS)
+
+DOC_FILES= README.QUICK TODO doc/README.Mac doc/README.OS2 \
+ doc/README.amiga doc/README.cords doc/debugging.html \
+ doc/finalization.html doc/porting.html doc/overview.html \
+ doc/README.dj doc/README.hp doc/README.linux doc/README.rs6000 \
+ doc/README.sgi doc/README.solaris2 doc/README.uts \
+ doc/README.symbian doc/README.win32 doc/barrett_diagram \
+ README AUTHORS doc/gc.man \
+ doc/README.environment doc/tree.html doc/gcdescr.html \
+ doc/README.autoconf doc/README.macros doc/README.ews4800 \
+ doc/README.DGUX386 doc/README.arm.cross doc/leak.html \
+ doc/scale.html doc/gcinterface.html doc/README.darwin \
+ doc/simple_example.html doc/README.win64
TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \
- tests/leak_test.c tests/thread_leak_test.c tests/middle.c
-
-GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \
- libtool.m4 install-sh configure.host Makefile.in \
- aclocal.m4 config.sub config.guess \
- include/Makefile.am include/Makefile.in \
- doc/Makefile.am doc/Makefile.in \
- ltmain.sh mkinstalldirs depcomp missing
-
-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
-# Makefile and Makefile.direct are copies of each other.
-
-OTHER_FILES= Makefile setjmp_t.c callprocs pc_excludes \
- MacProjects.sit.hqx MacOS.c \
- Mac_files/datastart.c Mac_files/dataend.c \
- Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
- add_gc_prefix.c gc_cpp.cpp \
- version.h AmigaOS.c \
- $(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
+ 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 install-sh Makefile.in \
+ aclocal.m4 config.sub config.guess \
+ include/include.am doc/doc.am \
+ ltmain.sh mkinstalldirs depcomp missing \
+ cord/cord.am tests/tests.am autogen.sh \
+ bdw-gc.pc.in compile
+
+OTHER_MAKEFILES= OS2_MAKEFILE NT_MAKEFILE gc.mak \
+ BCC_MAKEFILE EMX_MAKEFILE WCC_MAKEFILE Makefile.dj \
+ PCR-Makefile SMakefile.amiga \
+ digimars.mak Makefile.direct NT_STATIC_THREADS_MAKEFILE \
+ NT_X64_STATIC_THREADS_MAKEFILE NT_X64_THREADS_MAKEFILE \
+ build_atomic_ops.sh build_atomic_ops.sh.cygwin
+
+OTHER_FILES= tools/setjmp_t.c tools/callprocs.sh extra/MacOS.c \
+ extra/Mac_files/datastart.c extra/Mac_files/dataend.c \
+ extra/Mac_files/MacOS_config.h tools/add_gc_prefix.c gc_cpp.cpp \
+ extra/symbian/global_end.cpp extra/symbian/global_start.cpp \
+ extra/symbian/init_global_static_roots.cpp extra/symbian.cpp \
+ build/s60v3/bld.inf build/s60v3/libgc.mmp \
+ extra/AmigaOS.c extra/msvc_dbg.c include/private/msvc_dbg.h \
+ $(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
CORD_INCLUDE_FILES= $(srcdir)/include/gc.h $(srcdir)/include/cord.h \
- $(srcdir)/include/ec.h $(srcdir)/include/private/cord_pos.h
+ $(srcdir)/include/ec.h $(srcdir)/include/cord_pos.h
UTILS= if_mach if_not_there threadlibs
@@ -360,7 +163,7 @@ CURSES= -lcurses -ltermlib
# the SHELL environment variable.
SHELL= /bin/sh
-SPECIALCFLAGS = -I$(srcdir)/include
+SPECIALCFLAGS = -I$(srcdir)/include -I$(AO_INSTALL_DIR)/include
# Alternative flags to the C compiler for mach_dep.c.
# Mach_dep.c often doesn't like optimization, and it's
# not time-critical anyway.
@@ -368,6 +171,11 @@ SPECIALCFLAGS = -I$(srcdir)/include
all: gc.a gctest
+# if AO_INSTALL_DIR doesn't exist, we assume that it is pointing to
+# the default location, and we need to build
+$(AO_INSTALL_DIR):
+ CC=$(CC) MAKE=$(MAKE) $(srcdir)/build_atomic_ops.sh
+
LEAKFLAGS=$(CFLAGS) -DFIND_LEAK
BSD-pkg-all: bsd-libgc.a bsd-libleak.a
@@ -397,16 +205,20 @@ $(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
$(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.h \
$(srcdir)/include/gc.h $(srcdir)/include/gc_pthread_redirects.h \
$(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
- $(srcdir)/include/gc_config_macros.h Makefile
+ $(srcdir)/include/gc_config_macros.h Makefile $(AO_INSTALL_DIR)
# The dependency on Makefile is needed. Changing
-# options such as -DSILENT affects the size of GC_arrays,
+# options affects the size of GC_arrays,
# invalidating all .o files that rely on gc_priv.h
-mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
+Makefile: Makefile.direct
+ cp Makefile.direct Makefile
-specific.o pthread_support.o: $(srcdir)/include/private/specific.h
+mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h \
+ $(srcdir)/include/private/gc_pmark.h
-solaris_threads.o solaris_pthreads.o: $(srcdir)/include/private/solaris_threads.h
+specific.o pthread_support.o thread_local_alloc.o win32_threads.o: \
+ $(srcdir)/include/private/specific.h $(srcdir)/include/gc_inline.h \
+ $(srcdir)/include/private/thread_local_alloc.h
dbg_mlc.o gcj_mlc.o: $(srcdir)/include/private/dbg_mlc.h
@@ -420,8 +232,9 @@ tests:
base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
echo > base_lib
rm -f dont_ar_1
- ./if_mach SPARC SUNOS5 touch dont_ar_1
- ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(OBJS) dyn_load.o
+ cp $(AO_INSTALL_DIR)/lib/libatomic_ops.a gc.a
+ ./if_mach SPARC SOLARIS touch dont_ar_1
+ ./if_mach SPARC SOLARIS $(AR) rus gc.a $(OBJS) dyn_load.o
./if_mach M68K AMIGA touch dont_ar_1
./if_mach M68K AMIGA $(AR) -vrus gc.a $(OBJS) dyn_load.o
./if_not_there dont_ar_1 $(AR) ru gc.a $(OBJS) dyn_load.o
@@ -430,8 +243,8 @@ base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
cords: $(CORD_OBJS) cord/cordtest $(UTILS)
rm -f dont_ar_3
- ./if_mach SPARC SUNOS5 touch dont_ar_3
- ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(CORD_OBJS)
+ ./if_mach SPARC SOLARIS touch dont_ar_3
+ ./if_mach SPARC SOLARIS $(AR) rus gc.a $(CORD_OBJS)
./if_mach M68K AMIGA touch dont_ar_3
./if_mach M68K AMIGA $(AR) -vrus gc.a $(CORD_OBJS)
./if_not_there dont_ar_3 $(AR) ru gc.a $(CORD_OBJS)
@@ -441,7 +254,7 @@ gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/include/gc_cpp.h $(srcdir)/include/gc.h
$(CXX) -c $(CXXFLAGS) $(srcdir)/gc_cpp.cc
test_cpp: $(srcdir)/tests/test_cpp.cc $(srcdir)/include/gc_cpp.h gc_cpp.o $(srcdir)/include/gc.h \
-base_lib $(UTILS)
+ base_lib $(UTILS)
rm -f test_cpp
./if_mach HP_PA HPUX $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a -ldld `./threadlibs`
./if_not_there test_cpp $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a `./threadlibs`
@@ -454,8 +267,8 @@ c++-nt: c++
c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp
rm -f dont_ar_4
- ./if_mach SPARC SUNOS5 touch dont_ar_4
- ./if_mach SPARC SUNOS5 $(AR) rus gc.a gc_cpp.o
+ ./if_mach SPARC SOLARIS touch dont_ar_4
+ ./if_mach SPARC SOLARIS $(AR) rus gc.a gc_cpp.o
./if_mach M68K AMIGA touch dont_ar_4
./if_mach M68K AMIGA $(AR) -vrus gc.a gc_cpp.o
./if_not_there dont_ar_4 $(AR) ru gc.a gc_cpp.o
@@ -468,7 +281,7 @@ dyn_load_sunos53.o: dyn_load.c
# SunOS5 shared library version of the collector
sunos5gc.so: $(OBJS) dyn_load_sunos53.o
- $(CC) -G -o sunos5gc.so $(OBJS) dyn_load_sunos53.o -ldl
+ $(CC) -G -o sunos5gc.so $(OBJS) dyn_load_sunos53.o $(AO_INSTALL_DIR)/lib/libatomic_ops.a -ldl
ln sunos5gc.so libgc.so
# Alpha/OSF shared library version of the collector
@@ -486,6 +299,11 @@ liblinuxgc.so: $(OBJS) dyn_load.o
gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o
ln liblinuxgc.so libgc.so
+# Build gctest with dynamic library
+dyn_test:
+ $(CC) $(CFLAGS) -o gctest tests/test.c libgc.so `./threadlibs`
+ ./gctest
+
# Alternative Linux rule. This is preferable, but is likely to break the
# Makefile for some non-linux platforms.
# LIBOBJS= $(patsubst %.o, %.lo, $(OBJS))
@@ -499,23 +317,17 @@ liblinuxgc.so: $(OBJS) dyn_load.o
# gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
# touch liblinuxgc.so
-mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s \
- $(srcdir)/mips_ultrix_mach_dep.s \
- $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s \
- $(srcdir)/sparc_mach_dep.S $(srcdir)/sparc_sunos4_mach_dep.s \
- $(srcdir)/ia64_save_regs_in_stack.s \
- $(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
+mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/src/sparc_mach_dep.S \
+ $(srcdir)/src/sparc_sunos4_mach_dep.s \
+ $(srcdir)/src/ia64_save_regs_in_stack.s \
+ $(srcdir)/src/sparc_netbsd_mach_dep.s $(UTILS)
rm -f mach_dep.o
- ./if_mach MIPS IRIX5 $(CC) -c -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
- ./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
- ./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
- ./if_mach POWERPC DARWIN $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
- ./if_mach ALPHA LINUX $(CC) -c -o mach_dep.o $(srcdir)/alpha_mach_dep.S
- ./if_mach SPARC SUNOS5 $(CC) -c -o mach_dep.o $(srcdir)/sparc_mach_dep.S
- ./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
- ./if_mach SPARC OPENBSD $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
- ./if_mach SPARC NETBSD $(AS) -o mach_dep.o $(srcdir)/sparc_netbsd_mach_dep.s
- ./if_mach IA64 "" as $(AS_ABI_FLAG) -o ia64_save_regs_in_stack.o $(srcdir)/ia64_save_regs_in_stack.s
+ ./if_mach SPARC SOLARIS $(CC) -c -o mach_dep2.o $(srcdir)/src/sparc_mach_dep.S
+ ./if_mach SPARC OPENBSD $(AS) -o mach_dep2.o $(srcdir)/src/sparc_sunos4_mach_dep.s
+ ./if_mach SPARC NETBSD $(AS) -o mach_dep2.o $(srcdir)/src/sparc_netbsd_mach_dep.s
+ ./if_mach SPARC "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
+ ./if_mach SPARC "" ld -r -o mach_dep.o mach_dep1.o mach_dep2.o
+ ./if_mach IA64 "" as $(AS_ABI_FLAG) -o ia64_save_regs_in_stack.o $(srcdir)/src/ia64_save_regs_in_stack.s
./if_mach IA64 "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
./if_mach IA64 "" ld -r -o mach_dep.o mach_dep1.o ia64_save_regs_in_stack.o
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
@@ -527,7 +339,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
@@ -545,38 +357,38 @@ cord/cordprnt.o: cord $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
$(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordprnt.c
mv cordprnt.o cord/cordprnt.o
-cord/cordtest: $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a $(UTILS)
+cord/cordtest: $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a $(UTILS)
rm -f cord/cordtest
- ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -lucb
- ./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -ldld `./threadlibs`
- ./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
- ./if_not_there cord/cordtest $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
+ ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a -lucb
+ ./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a -ldld `./threadlibs`
+ ./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/cordtest $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
+ ./if_not_there cord/cordtest $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
-cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
+cord/de: $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
rm -f cord/de
- ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
- ./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs`
- ./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
- ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
- ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
- ./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
- ./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_not_there cord/de $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) `./threadlibs`
-
-if_mach: $(srcdir)/if_mach.c $(srcdir)/include/private/gcconfig.h
- $(HOSTCC) $(HOSTCFLAGS) -o if_mach $(srcdir)/if_mach.c
-
-threadlibs: $(srcdir)/threadlibs.c $(srcdir)/include/private/gcconfig.h Makefile
- $(HOSTCC) $(HOSTCFLAGS) -o threadlibs $(srcdir)/threadlibs.c
-
-if_not_there: $(srcdir)/if_not_there.c
- $(HOSTCC) $(HOSTCFLAGS) -o if_not_there $(srcdir)/if_not_there.c
-
-clean:
+ ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
+ ./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs`
+ ./if_mach POWERPC AIX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
+ ./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a
+ ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
+ ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
+ ./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
+ ./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
+ ./if_not_there cord/de $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) `./threadlibs`
+
+if_mach: $(srcdir)/tools/if_mach.c $(srcdir)/include/private/gcconfig.h
+ $(HOSTCC) $(HOSTCFLAGS) -o if_mach $(srcdir)/tools/if_mach.c
+
+threadlibs: $(srcdir)/tools/threadlibs.c $(srcdir)/include/private/gcconfig.h Makefile
+ $(HOSTCC) $(HOSTCFLAGS) -o threadlibs $(srcdir)/tools/threadlibs.c
+
+if_not_there: $(srcdir)/tools/if_not_there.c
+ $(HOSTCC) $(HOSTCFLAGS) -o if_not_there $(srcdir)/tools/if_not_there.c
+
+clean:
rm -f gc.a *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
- threadlibs $(CORD_OBJS) cord/cordtest cord/de
+ base_lib c++ threadlibs $(CORD_OBJS) cord/cordtest cord/de
-rm -f *~
gctest: tests/test.o gc.a $(UTILS)
@@ -589,8 +401,8 @@ gctest: tests/test.o gc.a $(UTILS)
# If an optimized setjmp_test generates a segmentation fault,
# odds are your compiler is broken. Gctest may still work.
# Try compiling setjmp_t.c unoptimized.
-setjmp_test: $(srcdir)/setjmp_t.c $(srcdir)/include/gc.h $(UTILS)
- $(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c
+setjmp_test: $(srcdir)/tools/setjmp_t.c $(srcdir)/include/gc.h $(UTILS) $(AO_INSTALL_DIR)
+ $(CC) $(CFLAGS) -o setjmp_test $(srcdir)/tools/setjmp_t.c
test: KandRtest cord/cordtest
cord/cordtest
@@ -600,41 +412,31 @@ KandRtest: setjmp_test gctest
./setjmp_test
./gctest
-add_gc_prefix: $(srcdir)/add_gc_prefix.c $(srcdir)/version.h
- $(CC) -o add_gc_prefix $(srcdir)/add_gc_prefix.c
+add_gc_prefix: $(srcdir)/tools/add_gc_prefix.c $(srcdir)/include/gc_version.h
+ $(CC) -o add_gc_prefix $(srcdir)/tools/add_gc_prefix.c
-gcname: $(srcdir)/gcname.c $(srcdir)/version.h
- $(CC) -o gcname $(srcdir)/gcname.c
+gcname: $(srcdir)/tools/gcname.c $(srcdir)/include/gc_version.h
+ $(CC) -o gcname $(srcdir)/tools/gcname.c
-gc.tar: $(SRCS) $(DOC_FILES) $(OTHER_FILES) add_gc_prefix gcname
- cp Makefile Makefile.old
+#We assume this is being done from source directory.
+dist gc.tar: $(SRCS) $(DOC_FILES) $(OTHER_FILES) add_gc_prefix gcname
cp Makefile.direct Makefile
+ cd $(AO_SRC_DIR); $(MAKE) dist
+ if test $(srcdir)/libatomic_ops = $(AO_SRC_DIR); \
+ then \
+ mv $(AO_SRC_DIR) $(AO_SRC_DIR).bak ; \
+ tar xvfz $(AO_SRC_DIR).bak/libatomic_ops.tar.gz ; \
+ else \
+ tar xvfz $(AO_SRC_DIR)/libatomic_ops.tar.gz ; \
+ fi
rm -f `./gcname`
ln -s . `./gcname`
- ./add_gc_prefix $(SRCS) $(DOC_FILES) $(OTHER_FILES) > /tmp/gc.tar-files
+ ./add_gc_prefix $(SRCS) $(DOC_FILES) $(OTHER_FILES) libatomic_ops > /tmp/gc.tar-files
tar cvfh gc.tar `cat /tmp/gc.tar-files`
cp gc.tar `./gcname`.tar
gzip `./gcname`.tar
rm `./gcname`
-pc_gc.tar: $(SRCS) $(OTHER_FILES)
- tar cvfX pc_gc.tar pc_excludes $(SRCS) $(OTHER_FILES)
-
-floppy: pc_gc.tar
- -mmd a:/cord
- -mmd a:/cord/private
- -mmd a:/include
- -mmd a:/include/private
- mkdir /tmp/pc_gc
- cat pc_gc.tar | (cd /tmp/pc_gc; tar xvf -)
- -mcopy -tmn /tmp/pc_gc/* a:
- -mcopy -tmn /tmp/pc_gc/cord/* a:/cord
- -mcopy -mn /tmp/pc_gc/cord/de_win.ICO a:/cord
- -mcopy -tmn /tmp/pc_gc/cord/private/* a:/cord/private
- -mcopy -tmn /tmp/pc_gc/include/* a:/include
- -mcopy -tmn /tmp/pc_gc/include/private/* a:/include/private
- rm -r /tmp/pc_gc
-
gc.tar.Z: gc.tar
compress gc.tar
@@ -654,19 +456,8 @@ gctest_dyn_link: tests/test.o libgc.so
gctest_irix_dyn_link: tests/test.o libirixgc.so
$(CC) -L$(ABSDIR) -o gctest_irix_dyn_link tests/test.o -lirixgc
-# The following appear to be dead, especially since libgc_globals.h
-# is apparently lost.
-test_dll.o: tests/test.c libgc_globals.h
- $(CC) $(CFLAGS) -DGC_USE_DLL -c tests/test.c -o test_dll.o
-
-test_dll: test_dll.o libgc_dll.a libgc.dll
- $(CC) test_dll.o -L$(ABSDIR) -lgc_dll -o test_dll
-
SYM_PREFIX-libgc=GC
-# Uncomment the following line to build a GNU win32 DLL
-# include Makefile.DLLs
-
reserved_namespace: $(SRCS)
for file in $(SRCS) tests/test.c tests/test_cpp.cc; do \
sed s/GC_/_GC_/g < $$file > tmp; \
diff --git a/boehm-gc/Makefile.dj b/boehm-gc/Makefile.dj
index 7757f15133d..4cc08deb3c6 100644
--- a/boehm-gc/Makefile.dj
+++ b/boehm-gc/Makefile.dj
@@ -19,8 +19,6 @@ CXX=gxx $(ABI_FLAG)
AS=gcc -c -x assembler-with-cpp $(ABI_FLAG)
# The above doesn't work with gas, which doesn't run cpp.
# Define AS as `gcc -c -x assembler-with-cpp' instead.
-# Under Irix 6, you will have to specify the ABI (-o32, -n32, or -64)
-# if you use something other than the default ABI on your machine.
# special defines for DJGPP
CXXLD=gxx $(ABI_FLAG)
@@ -29,172 +27,54 @@ EXE_SUFFIX=.exe
srcdir= .
VPATH= $(srcdir)
-CFLAGS= -gstabs+ -O2 -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION -DSILENT
-
-# Setjmp_test may yield overly optimistic results when compiled
-# without optimization.
-# -DSILENT disables statistics printing, and improves performance.
-# -DFIND_LEAK causes GC_find_leak to be initially set.
-# This causes the collector to assume that all inaccessible
-# objects should have been explicitly deallocated, and reports exceptions.
-# Finalization and the test program are not usable in this mode.
-# -DALL_INTERIOR_POINTERS allows all pointers to the interior
-# of objects to be recognized. (See gc_priv.h for consequences.)
-# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
-# usually causing it to use less space in such situations.
-# Incremental collection no longer works in this case.
-# -DLARGE_CONFIG tunes the collector for unusually large heaps.
-# Necessary for heaps larger than about 500 MB on most machines.
-# Recommended for heaps larger than about 64 MB.
-# -DDONT_ADD_BYTE_AT_END is meaningful only with
-# -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
-# causes all objects to be padded so that pointers just past the end of
-# an object can be recognized. This can be expensive. (The padding
-# is normally more than one byte due to alignment constraints.)
-# -DDONT_ADD_BYTE_AT_END disables the padding.
-# -DNO_SIGNALS does not disable signals during critical parts of
-# the GC process. This is no less correct than many malloc
-# implementations, and it sometimes has a significant performance
-# impact. However, it is dangerous for many not-quite-ANSI C
-# programs that call things like printf in asynchronous signal handlers.
-# This is on by default. Turning it off has not been extensively tested with
-# compilers that reorder stores. It should have been.
-# -DNO_EXECUTE_PERMISSION may cause some or all of the heap to not
-# have execute permission, i.e. it may be impossible to execute
-# code from the heap. Currently this only affects the incremental
-# collector on UNIX machines. It may greatly improve its performance,
-# since this may avoid some expensive cache synchronization.
-# -DGC_NO_OPERATOR_NEW_ARRAY declares that the C++ compiler does not support
-# the new syntax "operator new[]" for allocating and deleting arrays.
-# See gc_cpp.h for details. No effect on the C part of the collector.
-# This is defined implicitly in a few environments. Must also be defined
-# by clients that use gc_cpp.h.
-# -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be defined
-# as aliases for X, GC_realloc, and GC_free, respectively.
-# Calloc is redefined in terms of the new malloc. X should
-# be either GC_malloc or GC_malloc_uncollectable.
-# The former is occasionally useful for working around leaks in code
-# you don't want to (or can't) look at. It may not work for
-# existing code, but it often does. Neither works on all platforms,
-# since some ports use malloc or calloc to obtain system memory.
-# (Probably works for UNIX, and win32.)
-# -DIGNORE_FREE turns calls to free into a noop. Only useful with
-# -DREDIRECT_MALLOC.
-# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
-# Reduces code size slightly at the expense of debuggability.
-# -DJAVA_FINALIZATION makes it somewhat safer to finalize objects out of
-# order by specifying a nonstandard finalization mark procedure (see
-# finalize.c). Objects reachable from finalizable objects will be marked
-# in a sepearte postpass, and hence their memory won't be reclaimed.
-# Not recommended unless you are implementing a language that specifies
-# these semantics. Since 5.0, determines only only the initial value
-# of GC_java_finalization variable.
-# -DFINALIZE_ON_DEMAND causes finalizers to be run only in response
-# to explicit GC_invoke_finalizers() calls.
-# In 5.0 this became runtime adjustable, and this only determines the
-# initial value of GC_finalize_on_demand.
-# -DATOMIC_UNCOLLECTABLE includes code for GC_malloc_atomic_uncollectable.
-# This is useful if either the vendor malloc implementation is poor,
-# or if REDIRECT_MALLOC is used.
-# -DHBLKSIZE=ddd, where ddd is a power of 2 between 512 and 16384, explicitly
-# sets the heap block size. Each heap block is devoted to a single size and
-# kind of object. For the incremental collector it makes sense to match
-# the most likely page size. Otherwise large values result in more
-# fragmentation, but generally better performance for large heaps.
-# -DPRINT_BLACK_LIST Whenever a black list entry is added, i.e. whenever
-# the garbage collector detects a value that looks almost, but not quite,
-# like a pointer, print both the address containing the value, and the
-# value of the near-bogus-pointer. Can be used to identifiy regions of
-# memory that are likely to contribute misidentified pointers.
-# -DKEEP_BACK_PTRS Add code to save back pointers in debugging headers
-# for objects allocated with the debugging allocator. If all objects
-# through GC_MALLOC with GC_DEBUG defined, this allows the client
-# to determine how particular or randomly chosen objects are reachable
-# for debugging/profiling purposes. The gc_backptr.h interface is
-# implemented only if this is defined.
-# -DGC_ASSERTIONS Enable some internal GC assertion checking. Currently
-# this facility is only used in a few places. It is intended primarily
-# for debugging of the garbage collector itself, but could also
-# -DDBG_HDRS_ALL Make sure that all objects have debug headers. Increases
-# the reliability (from 99.9999% to 100%) of some of the debugging
-# code (especially KEEP_BACK_PTRS). Makes -DSHORT_DBG_HDRS possible.
-# Assumes that all client allocation is done through debugging
-# allocators.
-# -DSHORT_DBG_HDRS Assume that all objects have debug headers. Shorten
-# the headers to minimize object size, at the expense of checking for
-# writes past the end of an object. This is intended for environments
-# in which most client code is written in a "safe" language, such as
-# Scheme or Java. Assumes that all client allocation is done using
-# the GC_debug_ functions (or through the macros that expand to these.
-# (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.
-# -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
-# altered stubborn objects, at substantial performance cost.
-# Use only for debugging of the incremental collector.
-# -DGC_GCJ_SUPPORT includes support for gcj (and possibly other systems
-# that include a pointer to a type descriptor in each allocated object).
-# Building this way requires an ANSI C compiler.
-# -DUSE_I686_PREFETCH causes the collector to issue Pentium III style
-# prefetch instructions. No effect except on X86 Linux platforms.
-# Assumes a very recent gcc-compatible compiler and assembler.
-# (Gas prefetcht0 support was added around May 1999.)
-# Empirically the code appears to still run correctly on Pentium II
-# processors, though with no performance benefit. May not run on other
-# X86 processors? In some cases this improves performance by
-# 15% or so.
-# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
-# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
-# UNTESTED!!
-# -DGC_USE_LD_WRAP in combination with the gld flags listed in README.linux
-# causes the collector some system and pthread calls in a more transparent
-# fashion than the usual macro-based approach. Requires GNU ld, and
-# currently probably works only with Linux.
+CFLAGS= -gstabs+ -O2 -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION
+# Look into doc/README.macros for the description of the "define arguments"
+# influencing the collector configuration.
CXXFLAGS= $(CFLAGS) -DGC_OPERATOR_NEW_ARRAY
AR= ar
RANLIB= ranlib
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o fnlz_mlc.o
-CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c
+CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c fnlz_mlc.c
-CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC cord/SCOPTIONS.amiga cord/SMakefile.amiga
+CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/tests/de.c \
+ cord/tests/cordtest.c include/cord.h include/ec.h \
+ include/cord_pos.h cord/tests/de_win.c cord/tests/de_win.h \
+ cord/tests/de_cmds.h cord/tests/de_win.rc
-CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
+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 \
+SRCS= $(CSRCS) \
+ src/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_inl.h include/gc_inline.h gc.man \
- threadlibs.c if_mach.c if_not_there.c gc_cpp.cc include/gc_cpp.h \
+ include/private/gcconfig.h include/private/gc_mark.h include/gc_disclaim.h \
+ include/gc_inline.h gc.man tools/threadlibs.c \
+ tools/if_mach.c tools/if_not_there.c gc_cpp.cc include/gc_cpp.h \
include/weakpointer.h include/private/gc_locks.h \
- gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h \
- include/new_gc_alloc.h include/javaxfc.h sparc_sunos4_mach_dep.s \
+ include/new_gc_alloc.h include/javaxfc.h src/sparc_sunos4_mach_dep.s \
include/private/solaris_threads.h include/gc_backptr.h \
- hpux_test_and_clear.s include/gc_gcj.h \
- include/gc_local_alloc.h include/private/dbg_mlc.h \
- include/private/specific.h powerpc_darwin_mach_dep.s \
+ include/gc_gcj.h include/private/dbg_mlc.h \
+ include/private/specific.h \
include/leak_detector.h $(CORD_SRCS)
-OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
- README tests/test.c test_cpp.cc setjmp_t.c SMakefile.amiga \
- SCoptions.amiga README.amiga README.win32 cord/README \
- README.rs6000 README.QUICK callprocs pc_excludes \
- barrett_diagram README.OS2 README.Mac MacProjects.sit.hqx \
- MacOS.c EMX_MAKEFILE README.debugging \
- Mac_files/datastart.c Mac_files/dataend.c \
- 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 \
- WCC_MAKEFILE nursery.c include/gc_nursery.h include/gc_copy_descr.h
+OTHER_FILES= PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
+ README tests/test.c test_cpp.cc tools/setjmp_t.c SMakefile.amiga \
+ doc/README.amiga doc/README.win32 doc/README.cords \
+ doc/README.rs6000 README.QUICK TODO tools/callprocs.sh \
+ pc_excludes barrett_diagram doc/README.OS2 doc/README.Mac \
+ extra/MacOS.c EMX_MAKEFILE doc/README.debugging \
+ extra/Mac_files/datastart.c extra/Mac_files/dataend.c \
+ extra/Mac_files/MacOS_config.h \
+ tools/add_gc_prefix.c doc/README.solaris2 doc/README.sgi \
+ doc/README.hp doc/README.uts win32_threads.c gc.mak doc/README.dj \
+ Makefile.dj doc/README.alpha doc/README.linux WCC_MAKEFILE
CORD_INCLUDE_FILES= $(srcdir)/include/gc.h $(srcdir)/include/cord.h \
- $(srcdir)/include/ec.h $(srcdir)/include/private/cord_pos.h
+ $(srcdir)/include/ec.h $(srcdir)/include/cord_pos.h
UTILS= if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX)
@@ -221,7 +101,7 @@ $(OBJS) test.o dyn_load.o dyn_load_sunos53.o: \
$(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
Makefile
# The dependency on Makefile is needed. Changing
-# options such as -DSILENT affects the size of GC_arrays,
+# options affects the size of GC_arrays,
# invalidating all .o files that rely on gc_priv.h
mark.o typd_mlc.o finalize.o: $(srcdir)/include/gc_mark.h
@@ -229,16 +109,16 @@ mark.o typd_mlc.o finalize.o: $(srcdir)/include/gc_mark.h
base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
echo > base_lib
rm -f on_sparc_sunos5_1
- ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_1
- ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(OBJS) dyn_load.o
+ ./if_mach SPARC SOLARIS touch on_sparc_sunos5_1
+ ./if_mach SPARC SOLARIS $(AR) rus gc.a $(OBJS) dyn_load.o
./if_not_there on_sparc_sunos5_1 $(AR) ru gc.a $(OBJS) dyn_load.o
-./if_not_there on_sparc_sunos5_1 $(RANLIB) gc.a
# ignore ranlib failure; that usually means it doesn't exist, and isn't needed
cords: $(CORD_OBJS) cord/cordtest$(EXE_SUFFIX) $(UTILS)
rm -f on_sparc_sunos5_3
- ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_3
- ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(CORD_OBJS)
+ ./if_mach SPARC SOLARIS touch on_sparc_sunos5_3
+ ./if_mach SPARC SOLARIS $(AR) rus gc.a $(CORD_OBJS)
./if_not_there on_sparc_sunos5_3 $(AR) ru gc.a $(CORD_OBJS)
-./if_not_there on_sparc_sunos5_3 $(RANLIB) gc.a
@@ -254,8 +134,8 @@ base_lib $(UTILS)
c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp$(EXE_SUFFIX)
rm -f on_sparc_sunos5_4
- ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_4
- ./if_mach SPARC SUNOS5 $(AR) rus gc.a gc_cpp.o
+ ./if_mach SPARC SOLARIS touch on_sparc_sunos5_4
+ ./if_mach SPARC SOLARIS $(AR) rus gc.a gc_cpp.o
./if_not_there on_sparc_sunos5_4 $(AR) ru gc.a gc_cpp.o
-./if_not_there on_sparc_sunos5_4 $(RANLIB) gc.a
./test_cpp$(EXE_SUFFIX) 1
@@ -284,17 +164,8 @@ liblinuxgc.so: $(OBJS) dyn_load.o
gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o -lo
ln liblinuxgc.so libgc.so
-mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S $(srcdir)/mips_ultrix_mach_dep.s \
- $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s $(UTILS)
+mach_dep.o: $(srcdir)/mach_dep.c $(UTILS)
rm -f mach_dep.o
- ./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.S
- ./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
- ./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
- ./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
- ./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
- ./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.S
- ./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.S
- ./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
mark_rts.o: $(srcdir)/mark_rts.c if_mach if_not_there $(UTILS)
@@ -304,7 +175,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
@@ -319,41 +190,41 @@ cord/cordprnt.o: $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
$(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordprnt.c
mv cordprnt.o cord/cordprnt.o
-cord/cordtest$(EXE_SUFFIX): $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a $(UTILS) /tmp
+cord/cordtest$(EXE_SUFFIX): $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a $(UTILS) /tmp
rm -f cord/cordtest$(EXE_SUFFIX)
- ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest$(EXE_SUFFIX) $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -lucb
- ./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/cordtest$(EXE_SUFFIX) $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -ldld
- ./if_not_there cord/cordtest$(EXE_SUFFIX) $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
+ ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest$(EXE_SUFFIX) $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a -lucb
+ ./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/cordtest$(EXE_SUFFIX) $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a -ldld
+ ./if_not_there cord/cordtest$(EXE_SUFFIX) $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) gc.a
rm -f cord/cordtest cordtest
-mv cordtest$(EXE_SUFFIX) cord/
/tmp: $(UTILS)
./if_not_there /tmp mkdir /tmp
-cord/de$(EXE_SUFFIX): $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
+cord/de$(EXE_SUFFIX): $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
rm -f cord/de cord/de$(EXE_SUFFIX)
- ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
- ./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld
- ./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
- ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_not_there cord/de$(EXE_SUFFIX) $(CC) $(CFLAGS) -o cord/de$(EXE_SUFFIX) $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES)
-
-if_mach$(EXE_SUFFIX): $(srcdir)/if_mach.c $(srcdir)/include/private/gcconfig.h
+ ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
+ ./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld
+ ./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
+ ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
+ ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
+ ./if_not_there cord/de$(EXE_SUFFIX) $(CC) $(CFLAGS) -o cord/de$(EXE_SUFFIX) $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES)
+
+if_mach$(EXE_SUFFIX): $(srcdir)/tools/if_mach.c $(srcdir)/include/private/gcconfig.h
rm -f if_mach if_mach$(EXE_SUFFIX)
- $(CC) $(CFLAGS) -o if_mach $(srcdir)/if_mach.c
+ $(CC) $(CFLAGS) -o if_mach $(srcdir)/tools/if_mach.c
-threadlibs$(EXE_SUFFIX): $(srcdir)/threadlibs.c $(srcdir)include/private/gcconfig.h Makefile
+threadlibs$(EXE_SUFFIX): $(srcdir)/tools/threadlibs.c $(srcdir)include/private/gcconfig.h Makefile
rm -f threadlibs threadlibs$(EXE_SUFFIX)
- $(CC) $(CFLAGS) -o threadlibs $(srcdir)/threadlibs.c
+ $(CC) $(CFLAGS) -o threadlibs $(srcdir)/tools/threadlibs.c
-if_not_there$(EXE_SUFFIX): $(srcdir)/if_not_there.c
+if_not_there$(EXE_SUFFIX): $(srcdir)/tools/if_not_there.c
rm -f if_not_there if_not_there$(EXE_SUFFIX)
- $(CC) $(CFLAGS) -o if_not_there $(srcdir)/if_not_there.c
+ $(CC) $(CFLAGS) -o if_not_there $(srcdir)/tools/if_not_there.c
# Clean removes *.o several times,
# because as the first one doesn't seem to get them all!
-clean:
+clean:
rm -f gc.a *.o
rm -f *.o
rm -f *.o
@@ -376,10 +247,10 @@ gctest$(EXE_SUFFIX): tests/test.o gc.a if_mach$(EXE_SUFFIX) if_not_there$(EXE_SU
# If an optimized setjmp_test generates a segmentation fault,
# odds are your compiler is broken. Gctest may still work.
# Try compiling setjmp_t.c unoptimized.
-setjmp_test$(EXE_SUFFIX): $(srcdir)/setjmp_t.c $(srcdir)/include/gc.h \
+setjmp_test$(EXE_SUFFIX): $(srcdir)/tools/setjmp_t.c $(srcdir)/include/gc.h \
if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX)
rm -f setjmp_test$(EXE_SUFFIX)
- $(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c
+ $(CC) $(CFLAGS) -o setjmp_test $(srcdir)/tools/setjmp_t.c
rm -f setjmp_test
test: KandRtest cord/cordtest$(EXE_SUFFIX)
@@ -390,8 +261,8 @@ KandRtest: setjmp_test$(EXE_SUFFIX) gctest$(EXE_SUFFIX)
./setjmp_test$(EXE_SUFFIX)
./gctest$(EXE_SUFFIX)
-add_gc_prefix$(EXE_SUFFIX): add_gc_prefix.c
- $(CC) -o add_gc_prefix$(EXE_SUFFIX) $(srcdir)/add_gc_prefix.c
+add_gc_prefix$(EXE_SUFFIX): tools/add_gc_prefix.c
+ $(CC) -o add_gc_prefix$(EXE_SUFFIX) $(srcdir)/tools/add_gc_prefix.c
rm -f add_gc_prefix
gc.tar: $(SRCS) $(OTHER_FILES) add_gc_prefix
@@ -417,14 +288,4 @@ ABSDIR = `pwd`
gctest_dyn_link: test.o libgc.so
$(CC) -L$(ABSDIR) -R$(ABSDIR) -o gctest_dyn_link test.o -lgc -ldl -lthread
-test_dll.o: tests/test.c libgc_globals.h
- $(CC) $(CFLAGS) -DGC_USE_DLL -c tests/test.c -o test_dll.o
-
-test_dll: test_dll.o libgc_dll.a libgc.dll
- $(CC) test_dll.o -L$(ABSDIR) -lgc_dll -o test_dll
-
SYM_PREFIX-libgc=GC
-
-# Uncomment the following line to build a GNU win32 DLL
-# include Makefile.DLLs
-
diff --git a/boehm-gc/Makefile.in b/boehm-gc/Makefile.in
deleted file mode 100644
index fb52a370675..00000000000
--- a/boehm-gc/Makefile.in
+++ /dev/null
@@ -1,921 +0,0 @@
-# Makefile.in generated by automake 1.6.3 from Makefile.am.
-# @configure_input@
-
-# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
-# Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
-#
-# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-#
-# Permission is hereby granted to use or copy this program
-# for any purpose, provided the above notices are retained on all copies.
-# Permission to modify the code and to distribute modified code is granted,
-# provided the above notices are retained, and a notice that the code was
-# modified is included with the above copyright notice.
-#
-# Original author: Tom Tromey
-# Severely truncated by Hans-J. Boehm
-# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
-SHELL = @SHELL@
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-sbindir = @sbindir@
-libexecdir = @libexecdir@
-datadir = @datadir@
-sysconfdir = @sysconfdir@
-sharedstatedir = @sharedstatedir@
-localstatedir = @localstatedir@
-libdir = @libdir@
-infodir = @infodir@
-mandir = @mandir@
-includedir = @includedir@
-oldincludedir = /usr/include
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-top_builddir = .
-
-ACLOCAL = @ACLOCAL@
-AUTOCONF = @AUTOCONF@
-AUTOMAKE = @AUTOMAKE@
-AUTOHEADER = @AUTOHEADER@
-
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_DATA = @INSTALL_DATA@
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = @program_transform_name@
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-host_alias = @host_alias@
-host_triplet = @host@
-
-EXEEXT = @EXEEXT@
-OBJEXT = @OBJEXT@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-AMTAR = @AMTAR@
-AR = @AR@
-AS = @AS@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-
-CCASFLAGS = @CCASFLAGS@ $(DEFS)
-CFLAGS = @CFLAGS@
-CXX = @CXX@
-CXXFLAGS = @CXXFLAGS@
-CXXINCLUDES = @CXXINCLUDES@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-ECHO = @ECHO@
-EXTRA_TEST_LIBS = @EXTRA_TEST_LIBS@
-GC_CFLAGS = @GC_CFLAGS@
-GC_VERSION = @GC_VERSION@
-INCLUDES = @INCLUDES@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-LIBTOOL = @LIBTOOL@
-LN_S = @LN_S@
-MAINT = @MAINT@
-MY_CFLAGS = @MY_CFLAGS@
-OBJDUMP = @OBJDUMP@
-PACKAGE = @PACKAGE@
-RANLIB = @RANLIB@
-STRIP = @STRIP@
-THREADLIBS = @THREADLIBS@
-UNWINDLIBS = @UNWINDLIBS@
-VERSION = @VERSION@
-addincludes = @addincludes@
-addlibs = @addlibs@
-addobjs = @addobjs@
-addtests = @addtests@
-am__include = @am__include@
-am__quote = @am__quote@
-install_sh = @install_sh@
-target_all = @target_all@
-
-AUTOMAKE_OPTIONS = foreign
-
-SUBDIRS = doc include
-
-
-# documentation which is not installed
-#
-
-# other makefiles
-# :GOTCHA: deliberately we do not include 'Makefile'
-
-# files used by makefiles other than Makefile.am
-#
-
-# part of C++ interface
-#
-
-# tests not used by Makefile.am (:FIXME: why?)
-#
-
-# cord package
-#
-
-# :FIXME: why do we distribute this one???
-#
-EXTRA_DIST = alpha_mach_dep.S mips_sgi_mach_dep.s sparc_mach_dep.S README.QUICK 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\
-add_gc_prefix.c gcname.c if_mach.c if_not_there.c \
- hpux_test_and_clear.s pc_excludes gc.mak MacOS.c \
- MacProjects.sit.hqx mach_dep.c setjmp_t.c \
- threadlibs.c AmigaOS.c \
- Mac_files/datastart.c Mac_files/dataend.c \
- Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h\
-gc_cpp.cc gc_cpp.cpp tests/test_cpp.cc tests/trace_test.c \
- tests/leak_test.c tests/thread_leak_test.c\
-cord/cordbscs.c cord/cordtest.c cord/de.c cord/de_win.c \
- cord/de_win.ICO cord/cordprnt.c cord/cordxtra.c cord/de_cmds.h \
- cord/de_win.h cord/de_win.RC\
-libtool.m4
-
-@CPLUSPLUS_TRUE@extra = libgccpp.la
-@CPLUSPLUS_FALSE@extra =
-lib_LTLIBRARIES = libgc.la $(extra)
-
-include_HEADERS = include/gc.h include/gc_local_alloc.h \
-include/gc_pthread_redirects.h include/gc_config_macros.h \
-include/leak_detector.h include/gc_typed.h @addincludes@
-
-
-EXTRA_HEADERS = include/gc_cpp.h include/gc_allocator.h
-
-@POWERPC_DARWIN_TRUE@asm_libgc_sources = powerpc_darwin_mach_dep.s
-@POWERPC_DARWIN_FALSE@asm_libgc_sources =
-
-libgc_la_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
-dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \
-malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
-obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
-solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
-backgraph.c win32_threads.c \
-pthread_support.c pthread_stop_world.c darwin_stop_world.c \
-$(asm_libgc_sources)
-
-
-# Include THREADLIBS here to ensure that the correct versions of
-# linuxthread semaphore functions get linked:
-libgc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS)
-libgc_la_DEPENDENCIES = @addobjs@
-libgc_la_LDFLAGS = -version-info 1:2:0
-
-EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
- mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
- rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
- sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
-
-
-libgccpp_la_SOURCES = gc_cpp.cc
-libgccpp_la_LIBADD = $(THREADLIBS) $(UNWINDLIBS)
-libgccpp_la_LDFLAGS = -version-info 1:2:0
-
-AM_CXXFLAGS = @GC_CFLAGS@
-AM_CFLAGS = @GC_CFLAGS@
-
-@CPLUSPLUS_TRUE@extra_checks = test_cpp
-@CPLUSPLUS_FALSE@extra_checks =
-
-check_PROGRAMS = gctest $(extra_checks)
-
-# gctest_OBJECTS = test.o
-gctest_SOURCES = tests/test.c
-gctest_LDADD = ./libgc.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
-test_cpp_SOURCES = tests/test_cpp.cc
-test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
-
-TESTS = gctest $(extra_checks)
-
-all_objs = @addobjs@ $(libgc_la_OBJECTS)
-
-LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) \
- $(AM_CPPFLAGS) $(CPPFLAGS) \
- $(AM_CFLAGS) $(MY_CFLAGS) $(GC_CFLAGS)
-
-LINK = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(MY_CFLAGS) $(LDFLAGS) -o $@
-
-dist_noinst_SCRIPTS = callprocs configure.host
-
-# headers which are not installed
-# (see include/Makefile.am for more)
-#
-dist_noinst_HEADERS = version.h
-
-# this is an auxiliary shell file used by Makefile and Makefile.direct
-#
-CONFIG_STATUS_DEPENDENCIES = $(srcdir)/configure.host
-subdir = .
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_CLEAN_FILES =
-LTLIBRARIES = $(lib_LTLIBRARIES)
-
-@POWERPC_DARWIN_TRUE@am__objects_1 = powerpc_darwin_mach_dep.lo
-@POWERPC_DARWIN_FALSE@am__objects_1 =
-am_libgc_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo checksums.lo \
- dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
- headers.lo aix_irix_threads.lo malloc.lo mallocx.lo mark.lo \
- mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo \
- pcr_interface.lo ptr_chck.lo real_malloc.lo reclaim.lo \
- solaris_pthreads.lo solaris_threads.lo specific.lo stubborn.lo \
- typd_mlc.lo backgraph.lo win32_threads.lo pthread_support.lo \
- pthread_stop_world.lo darwin_stop_world.lo $(am__objects_1)
-libgc_la_OBJECTS = $(am_libgc_la_OBJECTS)
-libgccpp_la_DEPENDENCIES =
-am_libgccpp_la_OBJECTS = gc_cpp.lo
-libgccpp_la_OBJECTS = $(am_libgccpp_la_OBJECTS)
-@CPLUSPLUS_TRUE@check_PROGRAMS = gctest$(EXEEXT) test_cpp$(EXEEXT)
-@CPLUSPLUS_FALSE@check_PROGRAMS = gctest$(EXEEXT)
-am_gctest_OBJECTS = test.$(OBJEXT)
-gctest_OBJECTS = $(am_gctest_OBJECTS)
-gctest_DEPENDENCIES = ./libgc.la
-gctest_LDFLAGS =
-am_test_cpp_OBJECTS = test_cpp.$(OBJEXT)
-test_cpp_OBJECTS = $(am_test_cpp_OBJECTS)
-test_cpp_DEPENDENCIES = ./libgc.la ./libgccpp.la
-test_cpp_LDFLAGS =
-SCRIPTS = $(dist_noinst_SCRIPTS)
-
-
-DEFS = @DEFS@
-DEFAULT_INCLUDES = -I. -I$(srcdir)
-CPPFLAGS = @CPPFLAGS@
-LDFLAGS = @LDFLAGS@
-LIBS = @LIBS@
-depcomp = $(SHELL) $(top_srcdir)/depcomp
-am__depfiles_maybe = depfiles
-@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/aix_irix_threads.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/allchblk.Plo ./$(DEPDIR)/alloc.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/backgraph.Plo ./$(DEPDIR)/blacklst.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/checksums.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/darwin_stop_world.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/dbg_mlc.Plo ./$(DEPDIR)/dyn_load.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/finalize.Plo ./$(DEPDIR)/gc_cpp.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/gc_dlopen.Plo ./$(DEPDIR)/gcj_mlc.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/headers.Plo ./$(DEPDIR)/malloc.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/mallocx.Plo ./$(DEPDIR)/mark.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/mark_rts.Plo ./$(DEPDIR)/misc.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/new_hblk.Plo ./$(DEPDIR)/obj_map.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/os_dep.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/pcr_interface.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/pthread_stop_world.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/pthread_support.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/ptr_chck.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/real_malloc.Plo ./$(DEPDIR)/reclaim.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/solaris_pthreads.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/solaris_threads.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/specific.Plo ./$(DEPDIR)/stubborn.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/test.Po ./$(DEPDIR)/test_cpp.Po \
-@AMDEP_TRUE@ ./$(DEPDIR)/typd_mlc.Plo \
-@AMDEP_TRUE@ ./$(DEPDIR)/win32_threads.Plo
-CCASCOMPILE = $(CCAS) $(AM_CCASFLAGS) $(CCASFLAGS)
-LTCCASCOMPILE = $(LIBTOOL) --mode=compile $(CCAS) $(AM_CCASFLAGS) \
- $(CCASFLAGS)
-COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
- $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-CCLD = $(CC)
-CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
-LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \
- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
- $(AM_CXXFLAGS) $(CXXFLAGS)
-CXXLD = $(CXX)
-CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
- $(AM_LDFLAGS) $(LDFLAGS) -o $@
-DIST_SOURCES = $(libgc_la_SOURCES) $(EXTRA_libgc_la_SOURCES) \
- $(libgccpp_la_SOURCES) $(gctest_SOURCES) $(test_cpp_SOURCES)
-HEADERS = $(dist_noinst_HEADERS) $(include_HEADERS)
-
-
-RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \
- uninstall-info-recursive all-recursive install-data-recursive \
- install-exec-recursive installdirs-recursive install-recursive \
- uninstall-recursive check-recursive installcheck-recursive
-DIST_COMMON = $(dist_noinst_HEADERS) $(dist_noinst_SCRIPTS) \
- $(include_HEADERS) Makefile.am Makefile.in acinclude.m4 \
- aclocal.m4 config.guess config.sub configure configure.in \
- depcomp install-sh ltmain.sh missing mkinstalldirs
-DIST_SUBDIRS = $(SUBDIRS)
-SOURCES = $(libgc_la_SOURCES) $(EXTRA_libgc_la_SOURCES) $(libgccpp_la_SOURCES) $(gctest_SOURCES) $(test_cpp_SOURCES)
-
-all: all-recursive
-
-.SUFFIXES:
-.SUFFIXES: .S .c .cc .lo .o .obj .s
-
-am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
- configure.lineno
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
- cd $(top_srcdir) && \
- $(AUTOMAKE) --foreign Makefile
-Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status
- cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)
-
-$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
- $(SHELL) ./config.status --recheck
-$(srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
- cd $(srcdir) && $(AUTOCONF)
-
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in acinclude.m4
- cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
-libLTLIBRARIES_INSTALL = $(INSTALL)
-install-libLTLIBRARIES: $(lib_LTLIBRARIES)
- @$(NORMAL_INSTALL)
- $(mkinstalldirs) $(DESTDIR)$(libdir)
- @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
- if test -f $$p; then \
- f="`echo $$p | sed -e 's|^.*/||'`"; \
- echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f"; \
- $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f; \
- else :; fi; \
- done
-
-uninstall-libLTLIBRARIES:
- @$(NORMAL_UNINSTALL)
- @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
- p="`echo $$p | sed -e 's|^.*/||'`"; \
- echo " $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p"; \
- $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
- done
-
-clean-libLTLIBRARIES:
- -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
- @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
- dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
- test -z "$dir" && dir=.; \
- echo "rm -f \"$${dir}/so_locations\""; \
- rm -f "$${dir}/so_locations"; \
- done
-libgc.la: $(libgc_la_OBJECTS) $(libgc_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(libgc_la_LDFLAGS) $(libgc_la_OBJECTS) $(libgc_la_LIBADD) $(LIBS)
-libgccpp.la: $(libgccpp_la_OBJECTS) $(libgccpp_la_DEPENDENCIES)
- $(CXXLINK) -rpath $(libdir) $(libgccpp_la_LDFLAGS) $(libgccpp_la_OBJECTS) $(libgccpp_la_LIBADD) $(LIBS)
-
-clean-checkPROGRAMS:
- @list='$(check_PROGRAMS)'; for p in $$list; do \
- f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- echo " rm -f $$p $$f"; \
- rm -f $$p $$f ; \
- done
-test.$(OBJEXT): tests/test.c
-gctest$(EXEEXT): $(gctest_OBJECTS) $(gctest_DEPENDENCIES)
- @rm -f gctest$(EXEEXT)
- $(LINK) $(gctest_LDFLAGS) $(gctest_OBJECTS) $(gctest_LDADD) $(LIBS)
-test_cpp.$(OBJEXT): tests/test_cpp.cc
-test_cpp$(EXEEXT): $(test_cpp_OBJECTS) $(test_cpp_DEPENDENCIES)
- @rm -f test_cpp$(EXEEXT)
- $(CXXLINK) $(test_cpp_LDFLAGS) $(test_cpp_OBJECTS) $(test_cpp_LDADD) $(LIBS)
-
-mostlyclean-compile:
- -rm -f *.$(OBJEXT) core *.core
-
-distclean-compile:
- -rm -f *.tab.c
-
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix_irix_threads.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/allchblk.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backgraph.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blacklst.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checksums.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/darwin_stop_world.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbg_mlc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dyn_load.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/finalize.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gc_cpp.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gc_dlopen.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gcj_mlc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/headers.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mallocx.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mark.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mark_rts.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/new_hblk.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj_map.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_dep.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcr_interface.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pthread_stop_world.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pthread_support.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptr_chck.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/real_malloc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reclaim.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/solaris_pthreads.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/solaris_threads.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/specific.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stubborn.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_cpp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/typd_mlc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32_threads.Plo@am__quote@
-
-distclean-depend:
- -rm -rf ./$(DEPDIR)
-
-.S.o:
- $(CCASCOMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
-
-.S.obj:
- $(CCASCOMPILE) -c `cygpath -w $<`
-
-.S.lo:
- $(LTCCASCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
-
-.c.o:
-@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
-
-.c.obj:
-@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(COMPILE) -c `cygpath -w $<`
-
-.c.lo:
-@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(LTCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
-
-test.obj: tests/test.c
-@AMDEP_TRUE@ source='tests/test.c' object='test.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/test.Po' tmpdepfile='$(DEPDIR)/test.TPo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test.obj `cygpath -w tests/test.c`
-
-test.lo: tests/test.c
-@AMDEP_TRUE@ source='tests/test.c' object='test.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/test.Plo' tmpdepfile='$(DEPDIR)/test.TPlo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test.lo `test -f 'tests/test.c' || echo '$(srcdir)/'`tests/test.c
-CCDEPMODE = @CCDEPMODE@
-
-.cc.o:
-@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
-
-.cc.obj:
-@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(CXXCOMPILE) -c -o $@ `cygpath -w $<`
-
-.cc.lo:
-@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
-
-test_cpp.obj: tests/test_cpp.cc
-@AMDEP_TRUE@ source='tests/test_cpp.cc' object='test_cpp.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/test_cpp.Po' tmpdepfile='$(DEPDIR)/test_cpp.TPo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_cpp.obj `cygpath -w tests/test_cpp.cc`
-
-test_cpp.lo: tests/test_cpp.cc
-@AMDEP_TRUE@ source='tests/test_cpp.cc' object='test_cpp.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@ depfile='$(DEPDIR)/test_cpp.Plo' tmpdepfile='$(DEPDIR)/test_cpp.TPlo' @AMDEPBACKSLASH@
-@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o test_cpp.lo `test -f 'tests/test_cpp.cc' || echo '$(srcdir)/'`tests/test_cpp.cc
-CXXDEPMODE = @CXXDEPMODE@
-
-.s.o:
- $(CCASCOMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
-
-.s.obj:
- $(CCASCOMPILE) -c `cygpath -w $<`
-
-mostlyclean-libtool:
- -rm -f *.lo
-
-clean-libtool:
- -rm -rf .libs _libs
-
-distclean-libtool:
- -rm -f libtool
-uninstall-info-am:
-includeHEADERS_INSTALL = $(INSTALL_HEADER)
-install-includeHEADERS: $(include_HEADERS)
- @$(NORMAL_INSTALL)
- $(mkinstalldirs) $(DESTDIR)$(includedir)
- @list='$(include_HEADERS)'; for p in $$list; do \
- if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
- f="`echo $$p | sed -e 's|^.*/||'`"; \
- echo " $(includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(includedir)/$$f"; \
- $(includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(includedir)/$$f; \
- done
-
-uninstall-includeHEADERS:
- @$(NORMAL_UNINSTALL)
- @list='$(include_HEADERS)'; for p in $$list; do \
- f="`echo $$p | sed -e 's|^.*/||'`"; \
- echo " rm -f $(DESTDIR)$(includedir)/$$f"; \
- rm -f $(DESTDIR)$(includedir)/$$f; \
- done
-
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run `make' without going through this Makefile.
-# To change the values of `make' variables: instead of editing Makefiles,
-# (1) if the variable is set in `config.status', edit `config.status'
-# (which will cause the Makefiles to be regenerated when you run `make');
-# (2) otherwise, pass the desired values on the `make' command line.
-$(RECURSIVE_TARGETS):
- @set fnord $$MAKEFLAGS; amf=$$2; \
- dot_seen=no; \
- target=`echo $@ | sed s/-recursive//`; \
- list='$(SUBDIRS)'; for subdir in $$list; do \
- echo "Making $$target in $$subdir"; \
- if test "$$subdir" = "."; then \
- dot_seen=yes; \
- local_target="$$target-am"; \
- else \
- local_target="$$target"; \
- fi; \
- (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
- || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
- done; \
- if test "$$dot_seen" = "no"; then \
- $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
- fi; test -z "$$fail"
-
-mostlyclean-recursive clean-recursive distclean-recursive \
-maintainer-clean-recursive:
- @set fnord $$MAKEFLAGS; amf=$$2; \
- dot_seen=no; \
- case "$@" in \
- distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
- *) list='$(SUBDIRS)' ;; \
- esac; \
- rev=''; for subdir in $$list; do \
- if test "$$subdir" = "."; then :; else \
- rev="$$subdir $$rev"; \
- fi; \
- done; \
- rev="$$rev ."; \
- target=`echo $@ | sed s/-recursive//`; \
- for subdir in $$rev; do \
- echo "Making $$target in $$subdir"; \
- if test "$$subdir" = "."; then \
- local_target="$$target-am"; \
- else \
- local_target="$$target"; \
- fi; \
- (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
- || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
- done && test -z "$$fail"
-tags-recursive:
- list='$(SUBDIRS)'; for subdir in $$list; do \
- test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
- done
-
-ETAGS = etags
-ETAGSFLAGS =
-
-tags: TAGS
-
-ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
- list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | \
- $(AWK) ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- mkid -fID $$unique
-
-TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
- $(TAGS_FILES) $(LISP)
- tags=; \
- here=`pwd`; \
- list='$(SUBDIRS)'; for subdir in $$list; do \
- if test "$$subdir" = .; then :; else \
- test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
- fi; \
- done; \
- list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
- unique=`for i in $$list; do \
- if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
- done | \
- $(AWK) ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- test -z "$(ETAGS_ARGS)$$tags$$unique" \
- || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
- $$tags $$unique
-
-GTAGS:
- here=`$(am__cd) $(top_builddir) && pwd` \
- && cd $(top_srcdir) \
- && gtags -i $(GTAGS_ARGS) $$here
-
-distclean-tags:
- -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
-
-check-TESTS: $(TESTS)
- @failed=0; all=0; xfail=0; xpass=0; \
- srcdir=$(srcdir); export srcdir; \
- list='$(TESTS)'; \
- if test -n "$$list"; then \
- for tst in $$list; do \
- if test -f ./$$tst; then dir=./; \
- elif test -f $$tst; then dir=; \
- else dir="$(srcdir)/"; fi; \
- if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
- all=`expr $$all + 1`; \
- case " $(XFAIL_TESTS) " in \
- *" $$tst "*) \
- xpass=`expr $$xpass + 1`; \
- failed=`expr $$failed + 1`; \
- echo "XPASS: $$tst"; \
- ;; \
- *) \
- echo "PASS: $$tst"; \
- ;; \
- esac; \
- elif test $$? -ne 77; then \
- all=`expr $$all + 1`; \
- case " $(XFAIL_TESTS) " in \
- *" $$tst "*) \
- xfail=`expr $$xfail + 1`; \
- echo "XFAIL: $$tst"; \
- ;; \
- *) \
- failed=`expr $$failed + 1`; \
- echo "FAIL: $$tst"; \
- ;; \
- esac; \
- fi; \
- done; \
- if test "$$failed" -eq 0; then \
- if test "$$xfail" -eq 0; then \
- banner="All $$all tests passed"; \
- else \
- banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
- fi; \
- else \
- if test "$$xpass" -eq 0; then \
- banner="$$failed of $$all tests failed"; \
- else \
- banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
- fi; \
- fi; \
- dashes=`echo "$$banner" | sed s/./=/g`; \
- echo "$$dashes"; \
- echo "$$banner"; \
- echo "$$dashes"; \
- test "$$failed" -eq 0; \
- else :; fi
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-
-top_distdir = .
-distdir = $(PACKAGE)-$(VERSION)
-
-am__remove_distdir = \
- { test ! -d $(distdir) \
- || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
- && rm -fr $(distdir); }; }
-
-GZIP_ENV = --best
-distcleancheck_listfiles = find . -type f -print
-
-distdir: $(DISTFILES)
- $(am__remove_distdir)
- mkdir $(distdir)
- $(mkinstalldirs) $(distdir)/Mac_files $(distdir)/cord $(distdir)/include $(distdir)/tests
- @list='$(DISTFILES)'; for file in $$list; do \
- if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
- dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
- if test "$$dir" != "$$file" && test "$$dir" != "."; then \
- dir="/$$dir"; \
- $(mkinstalldirs) "$(distdir)$$dir"; \
- else \
- dir=''; \
- fi; \
- if test -d $$d/$$file; then \
- if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
- cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
- fi; \
- cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
- else \
- test -f $(distdir)/$$file \
- || cp -p $$d/$$file $(distdir)/$$file \
- || exit 1; \
- fi; \
- done
- list='$(SUBDIRS)'; for subdir in $$list; do \
- if test "$$subdir" = .; then :; else \
- test -d $(distdir)/$$subdir \
- || mkdir $(distdir)/$$subdir \
- || exit 1; \
- (cd $$subdir && \
- $(MAKE) $(AM_MAKEFLAGS) \
- top_distdir="$(top_distdir)" \
- distdir=../$(distdir)/$$subdir \
- distdir) \
- || exit 1; \
- fi; \
- done
- -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
- ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
- ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
- ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
- || chmod -R a+r $(distdir)
-dist-gzip: distdir
- $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
- $(am__remove_distdir)
-
-dist dist-all: distdir
- $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
- $(am__remove_distdir)
-
-# This target untars the dist file and tries a VPATH configuration. Then
-# it guarantees that the distribution is self-contained by making another
-# tarfile.
-distcheck: dist
- $(am__remove_distdir)
- GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf -
- chmod -R a-w $(distdir); chmod a+w $(distdir)
- mkdir $(distdir)/=build
- mkdir $(distdir)/=inst
- chmod a-w $(distdir)
- dc_install_base=`$(am__cd) $(distdir)/=inst && pwd` \
- && cd $(distdir)/=build \
- && ../configure --srcdir=.. --prefix=$$dc_install_base \
- $(DISTCHECK_CONFIGURE_FLAGS) \
- && $(MAKE) $(AM_MAKEFLAGS) \
- && $(MAKE) $(AM_MAKEFLAGS) dvi \
- && $(MAKE) $(AM_MAKEFLAGS) check \
- && $(MAKE) $(AM_MAKEFLAGS) install \
- && $(MAKE) $(AM_MAKEFLAGS) installcheck \
- && $(MAKE) $(AM_MAKEFLAGS) uninstall \
- && (test `find $$dc_install_base -type f -print | wc -l` -le 1 \
- || { echo "ERROR: files left after uninstall:" ; \
- find $$dc_install_base -type f -print ; \
- exit 1; } >&2 ) \
- && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \
- && rm -f $(distdir).tar.gz \
- && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
- $(am__remove_distdir)
- @echo "$(distdir).tar.gz is ready for distribution" | \
- sed 'h;s/./=/g;p;x;p;x'
-distcleancheck: distclean
- if test '$(srcdir)' = . ; then \
- echo "ERROR: distcleancheck can only run from a VPATH build" ; \
- exit 1 ; \
- fi
- test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
- || { echo "ERROR: files left after distclean:" ; \
- $(distcleancheck_listfiles) ; \
- exit 1; } >&2
-check-am: all-am
- $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
- $(MAKE) $(AM_MAKEFLAGS) check-TESTS
-check: check-recursive
-all-am: Makefile $(LTLIBRARIES) $(SCRIPTS) $(HEADERS)
-installdirs: installdirs-recursive
-installdirs-am:
- $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir)
-
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
-
-install-am: all-am
- @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-recursive
-install-strip:
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- INSTALL_STRIP_FLAG=-s \
- `test -z '$(STRIP)' || \
- echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
- -rm -f Makefile $(CONFIG_CLEAN_FILES)
-
-maintainer-clean-generic:
- @echo "This command is intended for maintainers to use"
- @echo "it deletes files that may require special tools to rebuild."
-clean: clean-recursive
-
-clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \
- clean-libtool mostlyclean-am
-
-distclean: distclean-recursive
- -rm -f $(am__CONFIG_DISTCLEAN_FILES)
-distclean-am: clean-am distclean-compile distclean-depend \
- distclean-generic distclean-libtool distclean-tags
-
-dvi: dvi-recursive
-
-dvi-am:
-
-info: info-recursive
-
-info-am:
-
-install-data-am: install-includeHEADERS
-
-install-exec-am: install-libLTLIBRARIES
-
-install-info: install-info-recursive
-
-install-man:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-recursive
- -rm -f $(am__CONFIG_DISTCLEAN_FILES)
- -rm -rf autom4te.cache
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-recursive
-
-mostlyclean-am: mostlyclean-compile mostlyclean-generic \
- mostlyclean-libtool
-
-uninstall-am: uninstall-includeHEADERS uninstall-info-am \
- uninstall-libLTLIBRARIES
-
-uninstall-info: uninstall-info-recursive
-
-.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-TESTS check-am \
- clean clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \
- clean-libtool clean-recursive dist dist-all dist-gzip distcheck \
- distclean distclean-compile distclean-depend distclean-generic \
- distclean-libtool distclean-recursive distclean-tags \
- distcleancheck distdir dvi dvi-am dvi-recursive info info-am \
- info-recursive install install-am install-data install-data-am \
- install-data-recursive install-exec install-exec-am \
- install-exec-recursive install-includeHEADERS install-info \
- install-info-am install-info-recursive install-libLTLIBRARIES \
- install-man install-recursive install-strip installcheck \
- installcheck-am installdirs installdirs-am \
- installdirs-recursive maintainer-clean maintainer-clean-generic \
- maintainer-clean-recursive mostlyclean mostlyclean-compile \
- mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \
- tags tags-recursive uninstall uninstall-am \
- uninstall-includeHEADERS uninstall-info-am \
- uninstall-info-recursive uninstall-libLTLIBRARIES \
- uninstall-recursive
-
-
-test.o: $(srcdir)/tests/test.c
- $(COMPILE) -c $(srcdir)/tests/test.c
-# Using $< in the above seems to fail with the HP/UX on Itanium make.
-test_cpp.o: $(srcdir)/tests/test_cpp.cc
- $(CXXCOMPILE) -c $(srcdir)/tests/test_cpp.cc
-$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
-include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
-include/gc_pthread_redirects.h include/gc_config_macros.h \
-include/gc_mark.h @addincludes@
-
-.s.lo:
- $(LTCOMPILE) -Wp,-P -x assembler-with-cpp -c $<
-
-#
-# :GOTCHA: GNU make rule for making .s out of .S is flawed,
-# it will not remove dest if building fails
-.S.s:
- if $(CPP) $< >$@ ; then :; else rm -f $@; fi
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/boehm-gc/NT_MAKEFILE b/boehm-gc/NT_MAKEFILE
index d1b6a5d6f1f..3cf3be985a5 100644
--- a/boehm-gc/NT_MAKEFILE
+++ b/boehm-gc/NT_MAKEFILE
@@ -1,22 +1,26 @@
# Makefile for Windows NT. Assumes Microsoft compiler, and a single thread.
-# DLLs are included in the root set under NT, but not under win32S.
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
MY_CPU=X86
CPU=$(MY_CPU)
!include <ntwin32.mak>
-OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj
+# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but
+# not earlier versions. We can deal with either, but not inconsistency.
+.SUFFIXES:
+.SUFFIXES: .obj .cpp .c
+
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj extra\msvc_dbg.obj
all: gctest.exe cord\de.exe test_cpp.exe
.c.obj:
- $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DSILENT -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_BUILD $*.c /Fo$*.obj
+ $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj
.cpp.obj:
- $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DSILENT -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_BUILD $*.CPP /Fo$*.obj
+ $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
-$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h
+$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\gc_disclaim.h include\private\msvc_dbg.h
gc.lib: $(OBJS)
lib /MACHINE:i386 /out:gc.lib $(OBJS)
@@ -26,35 +30,32 @@ gctest.exe: tests\test.obj gc.lib
# The following works for win32 debugging. For win32s debugging use debugtype:coff
# and add mapsympe line.
# This produces a "GUI" applications that opens no windows and writes to the log file
-# "gc.log". This is done to make the result runnable under win32s.
- $(link) -debug:full -debugtype:cv $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
+# "gctest.gc.log". This is done to make the result runnable under win32s.
+ $(link) -debug -debugtype:cv $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
# mapsympe -n -o gctest.sym gctest.exe
cord\de_win.rbj: cord\de_win.res
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
-cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
+cord\tests\de.obj cord\tests\de_win.obj: include\cord.h include\cord_pos.h cord\tests\de_win.h cord\tests\de_cmds.h
-cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
- $(rc) $(rcvars) -r -fo cord\de_win.res $(cvars) cord\de_win.rc
+cord\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
+ $(rc) $(rcvars) -r -fo cord\de_win.res cord\tests\de_win.rc
# Cord/de is a real win32 gui application.
-cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib
- $(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
+cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib
+ $(link) -debug -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
gc_cpp.obj: include\gc_cpp.h include\gc.h
gc_cpp.cpp: gc_cpp.cc
- copy gc_cpp.cc gc_cpp.cpp
+# copy gc_cpp.cc gc_cpp.cpp
test_cpp.cpp: tests\test_cpp.cc
copy tests\test_cpp.cc test_cpp.cpp
# This generates the C++ test executable. The executable expects
# a single numeric argument, which is the number of iterations.
-# The output appears in the file "gc.log".
+# The output appears in the file "test_cpp.gc.log".
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
- $(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
-
-
-
+ $(link) -debug -debugtype:cv $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
diff --git a/boehm-gc/NT_STATIC_THREADS_MAKEFILE b/boehm-gc/NT_STATIC_THREADS_MAKEFILE
new file mode 100644
index 00000000000..8774eab12f8
--- /dev/null
+++ b/boehm-gc/NT_STATIC_THREADS_MAKEFILE
@@ -0,0 +1,71 @@
+# Makefile for Windows NT. Assumes Microsoft compiler.
+# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
+
+MY_CPU=X86
+CPU=$(MY_CPU)
+!include <ntwin32.mak>
+
+# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but
+# not earlier versions. We can deal with either, but not inconsistency.
+.SUFFIXES:
+.SUFFIXES: .obj .cpp .c
+
+# Atomic_ops installation directory. For win32, the source directory
+# should do, since we only need the headers.
+# We assume this was manually unpacked, since I'm not sure there is
+# a Windows standard command line tool to do this.
+AO_SRC_DIR=libatomic_ops/src
+AO_INCLUDE_DIR=$(AO_SRC_DIR)
+
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj extra\msvc_dbg.obj thread_local_alloc.obj
+
+all: gctest.exe cord\de.exe test_cpp.exe
+
+.c.obj:
+ $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -DPARALLEL_MARK -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj
+
+.cpp.obj:
+ $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
+
+$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\gc_disclaim.h include\private\msvc_dbg.h
+
+gc.lib: $(OBJS)
+ lib /MACHINE:i386 /out:gc.lib $(OBJS)
+# The original NT SDK used lib32 instead of lib
+
+gctest.exe: tests\test.obj gc.lib
+# The following works for win32 debugging. For win32s debugging use debugtype:coff
+# and add mapsympe line.
+# This produces a "GUI" applications that opens no windows and writes to the log file
+# "gctest.gc.log". This is done to make the result runnable under win32s.
+ $(link) -debug -debugtype:cv $(guiflags) -stack:262144 -out:$*.exe tests\test.obj $(guilibs) gc.lib
+# mapsympe -n -o gctest.sym gctest.exe
+
+cord\de_win.rbj: cord\de_win.res
+ cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
+
+cord\tests\de.obj cord\tests\de_win.obj: include\cord.h include\cord_pos.h cord\tests\de_win.h cord\tests\de_cmds.h
+
+cord\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
+ $(rc) $(rcvars) -r -fo cord\de_win.res cord\tests\de_win.rc
+
+# Cord/de is a real win32 gui application.
+cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib
+ $(link) -debug -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
+
+gc_cpp.obj: include\gc_cpp.h include\gc.h
+
+gc_cpp.cpp: gc_cpp.cc
+# copy gc_cpp.cc gc_cpp.cpp
+
+test_cpp.cpp: tests\test_cpp.cc
+ copy tests\test_cpp.cc test_cpp.cpp
+
+# This generates the C++ test executable. The executable expects
+# a single numeric argument, which is the number of iterations.
+# The output appears in the file "test_cpp.gc.log".
+test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
+ $(link) -debug -debugtype:cv $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
+
+AO_SCR_DIR:
+ tar xvfz $(AO_SRC_DIR).tar.gz;
diff --git a/boehm-gc/NT_THREADS_MAKEFILE b/boehm-gc/NT_THREADS_MAKEFILE
deleted file mode 100644
index 5f0b5462427..00000000000
--- a/boehm-gc/NT_THREADS_MAKEFILE
+++ /dev/null
@@ -1,2158 +0,0 @@
-# Microsoft Developer Studio Generated NMAKE File, Format Version 4.10
-# This has been hand-edited way too many times.
-# A clean, manually generated makefile would be an improvement.
-
-# TARGTYPE "Win32 (x86) Application" 0x0101
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-!IF "$(CFG)" == ""
-CFG=gctest - Win32 Release
-!MESSAGE No configuration specified. Defaulting to cord - Win32 Debug.
-!ENDIF
-
-!IF "$(CFG)" != "gc - Win32 Release" && "$(CFG)" != "gc - Win32 Debug" &&\
- "$(CFG)" != "gctest - Win32 Release" && "$(CFG)" != "gctest - Win32 Debug" &&\
- "$(CFG)" != "cord - Win32 Release" && "$(CFG)" != "cord - Win32 Debug"
-!MESSAGE Invalid configuration "$(CFG)" specified.
-!MESSAGE You can specify a configuration when running NMAKE on this makefile
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "gc.mak" CFG="cord - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "gc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "gc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "gctest - Win32 Release" (based on "Win32 (x86) Application")
-!MESSAGE "gctest - Win32 Debug" (based on "Win32 (x86) Application")
-!MESSAGE "cord - Win32 Release" (based on "Win32 (x86) Application")
-!MESSAGE "cord - Win32 Debug" (based on "Win32 (x86) Application")
-!MESSAGE
-!ERROR An invalid configuration is specified.
-!ENDIF
-
-!IF "$(OS)" == "Windows_NT"
-NULL=
-!ELSE
-NULL=nul
-!ENDIF
-################################################################################
-# Begin Project
-# PROP Target_Last_Scanned "gctest - Win32 Debug"
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Target_Dir ""
-OUTDIR=.\Release
-INTDIR=.\Release
-
-ALL : ".\Release\gc.dll" ".\Release\gc.bsc"
-
-CLEAN :
- -@erase ".\Release\allchblk.obj"
- -@erase ".\Release\allchblk.sbr"
- -@erase ".\Release\alloc.obj"
- -@erase ".\Release\alloc.sbr"
- -@erase ".\Release\blacklst.obj"
- -@erase ".\Release\blacklst.sbr"
- -@erase ".\Release\checksums.obj"
- -@erase ".\Release\checksums.sbr"
- -@erase ".\Release\dbg_mlc.obj"
- -@erase ".\Release\dbg_mlc.sbr"
- -@erase ".\Release\dyn_load.obj"
- -@erase ".\Release\dyn_load.sbr"
- -@erase ".\Release\finalize.obj"
- -@erase ".\Release\finalize.sbr"
- -@erase ".\Release\gc.bsc"
- -@erase ".\Release\gc_cpp.obj"
- -@erase ".\Release\gc_cpp.sbr"
- -@erase ".\Release\gc.dll"
- -@erase ".\Release\gc.exp"
- -@erase ".\Release\gc.lib"
- -@erase ".\Release\headers.obj"
- -@erase ".\Release\headers.sbr"
- -@erase ".\Release\mach_dep.obj"
- -@erase ".\Release\mach_dep.sbr"
- -@erase ".\Release\malloc.obj"
- -@erase ".\Release\malloc.sbr"
- -@erase ".\Release\mallocx.obj"
- -@erase ".\Release\mallocx.sbr"
- -@erase ".\Release\mark.obj"
- -@erase ".\Release\mark.sbr"
- -@erase ".\Release\mark_rts.obj"
- -@erase ".\Release\mark_rts.sbr"
- -@erase ".\Release\misc.obj"
- -@erase ".\Release\misc.sbr"
- -@erase ".\Release\new_hblk.obj"
- -@erase ".\Release\new_hblk.sbr"
- -@erase ".\Release\obj_map.obj"
- -@erase ".\Release\obj_map.sbr"
- -@erase ".\Release\os_dep.obj"
- -@erase ".\Release\os_dep.sbr"
- -@erase ".\Release\ptr_chck.obj"
- -@erase ".\Release\ptr_chck.sbr"
- -@erase ".\Release\reclaim.obj"
- -@erase ".\Release\reclaim.sbr"
- -@erase ".\Release\stubborn.obj"
- -@erase ".\Release\stubborn.sbr"
- -@erase ".\Release\typd_mlc.obj"
- -@erase ".\Release\typd_mlc.sbr"
- -@erase ".\Release\win32_threads.obj"
- -@erase ".\Release\win32_threads.sbr"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "SILENT" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
-CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "SILENT" /D "GC_BUILD" /D\
- "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D\
- "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/" /c
-CPP_OBJS=.\Release/
-CPP_SBRS=.\Release/
-
-.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-MTL=mktyplib.exe
-# ADD BASE MTL /nologo /D "NDEBUG" /win32
-# ADD MTL /nologo /D "NDEBUG" /win32
-MTL_PROJ=/nologo /D "NDEBUG" /win32
-RSC=rc.exe
-# ADD BASE RSC /l 0x809 /d "NDEBUG"
-# ADD RSC /l 0x809 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
-BSC32_SBRS= \
- ".\Release\allchblk.sbr" \
- ".\Release\alloc.sbr" \
- ".\Release\blacklst.sbr" \
- ".\Release\checksums.sbr" \
- ".\Release\dbg_mlc.sbr" \
- ".\Release\dyn_load.sbr" \
- ".\Release\finalize.sbr" \
- ".\Release\gc_cpp.sbr" \
- ".\Release\headers.sbr" \
- ".\Release\mach_dep.sbr" \
- ".\Release\malloc.sbr" \
- ".\Release\mallocx.sbr" \
- ".\Release\mark.sbr" \
- ".\Release\mark_rts.sbr" \
- ".\Release\misc.sbr" \
- ".\Release\new_hblk.sbr" \
- ".\Release\obj_map.sbr" \
- ".\Release\os_dep.sbr" \
- ".\Release\ptr_chck.sbr" \
- ".\Release\reclaim.sbr" \
- ".\Release\stubborn.sbr" \
- ".\Release\typd_mlc.sbr" \
- ".\Release\win32_threads.sbr"
-
-".\Release\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
- $(BSC32) @<<
- $(BSC32_FLAGS) $(BSC32_SBRS)
-<<
-
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
- odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
- /pdb:"$(OUTDIR)/gc.pdb" /machine:I386 /out:"$(OUTDIR)/gc.dll"\
- /implib:"$(OUTDIR)/gc.lib"
-LINK32_OBJS= \
- ".\Release\allchblk.obj" \
- ".\Release\alloc.obj" \
- ".\Release\blacklst.obj" \
- ".\Release\checksums.obj" \
- ".\Release\dbg_mlc.obj" \
- ".\Release\dyn_load.obj" \
- ".\Release\finalize.obj" \
- ".\Release\gc_cpp.obj" \
- ".\Release\headers.obj" \
- ".\Release\mach_dep.obj" \
- ".\Release\malloc.obj" \
- ".\Release\mallocx.obj" \
- ".\Release\mark.obj" \
- ".\Release\mark_rts.obj" \
- ".\Release\misc.obj" \
- ".\Release\new_hblk.obj" \
- ".\Release\obj_map.obj" \
- ".\Release\os_dep.obj" \
- ".\Release\ptr_chck.obj" \
- ".\Release\reclaim.obj" \
- ".\Release\stubborn.obj" \
- ".\Release\typd_mlc.obj" \
- ".\Release\win32_threads.obj"
-
-".\Release\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Target_Dir ""
-OUTDIR=.\Debug
-INTDIR=.\Debug
-
-ALL : ".\Debug\gc.dll" ".\Debug\gc.bsc"
-
-CLEAN :
- -@erase ".\Debug\allchblk.obj"
- -@erase ".\Debug\allchblk.sbr"
- -@erase ".\Debug\alloc.obj"
- -@erase ".\Debug\alloc.sbr"
- -@erase ".\Debug\blacklst.obj"
- -@erase ".\Debug\blacklst.sbr"
- -@erase ".\Debug\checksums.obj"
- -@erase ".\Debug\checksums.sbr"
- -@erase ".\Debug\dbg_mlc.obj"
- -@erase ".\Debug\dbg_mlc.sbr"
- -@erase ".\Debug\dyn_load.obj"
- -@erase ".\Debug\dyn_load.sbr"
- -@erase ".\Debug\finalize.obj"
- -@erase ".\Debug\finalize.sbr"
- -@erase ".\Debug\gc_cpp.obj"
- -@erase ".\Debug\gc_cpp.sbr"
- -@erase ".\Debug\gc.bsc"
- -@erase ".\Debug\gc.dll"
- -@erase ".\Debug\gc.exp"
- -@erase ".\Debug\gc.lib"
- -@erase ".\Debug\gc.map"
- -@erase ".\Debug\gc.pdb"
- -@erase ".\Debug\headers.obj"
- -@erase ".\Debug\headers.sbr"
- -@erase ".\Debug\mach_dep.obj"
- -@erase ".\Debug\mach_dep.sbr"
- -@erase ".\Debug\malloc.obj"
- -@erase ".\Debug\malloc.sbr"
- -@erase ".\Debug\mallocx.obj"
- -@erase ".\Debug\mallocx.sbr"
- -@erase ".\Debug\mark.obj"
- -@erase ".\Debug\mark.sbr"
- -@erase ".\Debug\mark_rts.obj"
- -@erase ".\Debug\mark_rts.sbr"
- -@erase ".\Debug\misc.obj"
- -@erase ".\Debug\misc.sbr"
- -@erase ".\Debug\new_hblk.obj"
- -@erase ".\Debug\new_hblk.sbr"
- -@erase ".\Debug\obj_map.obj"
- -@erase ".\Debug\obj_map.sbr"
- -@erase ".\Debug\os_dep.obj"
- -@erase ".\Debug\os_dep.sbr"
- -@erase ".\Debug\ptr_chck.obj"
- -@erase ".\Debug\ptr_chck.sbr"
- -@erase ".\Debug\reclaim.obj"
- -@erase ".\Debug\reclaim.sbr"
- -@erase ".\Debug\stubborn.obj"
- -@erase ".\Debug\stubborn.sbr"
- -@erase ".\Debug\typd_mlc.obj"
- -@erase ".\Debug\typd_mlc.sbr"
- -@erase ".\Debug\vc40.idb"
- -@erase ".\Debug\vc40.pdb"
- -@erase ".\Debug\win32_threads.obj"
- -@erase ".\Debug\win32_threads.sbr"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "SILENT" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
-CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "SILENT" /D "GC_BUILD"\
- /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D\
- "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/"\
- /Fd"$(INTDIR)/" /c
-CPP_OBJS=.\Debug/
-CPP_SBRS=.\Debug/
-
-.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-MTL=mktyplib.exe
-# ADD BASE MTL /nologo /D "_DEBUG" /win32
-# ADD MTL /nologo /D "_DEBUG" /win32
-MTL_PROJ=/nologo /D "_DEBUG" /win32
-RSC=rc.exe
-# ADD BASE RSC /l 0x809 /d "_DEBUG"
-# ADD RSC /l 0x809 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
-BSC32_SBRS= \
- ".\Debug\allchblk.sbr" \
- ".\Debug\alloc.sbr" \
- ".\Debug\blacklst.sbr" \
- ".\Debug\checksums.sbr" \
- ".\Debug\dbg_mlc.sbr" \
- ".\Debug\dyn_load.sbr" \
- ".\Debug\finalize.sbr" \
- ".\Debug\gc_cpp.sbr" \
- ".\Debug\headers.sbr" \
- ".\Debug\mach_dep.sbr" \
- ".\Debug\malloc.sbr" \
- ".\Debug\mallocx.sbr" \
- ".\Debug\mark.sbr" \
- ".\Debug\mark_rts.sbr" \
- ".\Debug\misc.sbr" \
- ".\Debug\new_hblk.sbr" \
- ".\Debug\obj_map.sbr" \
- ".\Debug\os_dep.sbr" \
- ".\Debug\ptr_chck.sbr" \
- ".\Debug\reclaim.sbr" \
- ".\Debug\stubborn.sbr" \
- ".\Debug\typd_mlc.sbr" \
- ".\Debug\win32_threads.sbr"
-
-".\Debug\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
- $(BSC32) @<<
- $(BSC32_FLAGS) $(BSC32_SBRS)
-<<
-
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
- odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
- /pdb:"$(OUTDIR)/gc.pdb" /map:"$(INTDIR)/gc.map" /debug /machine:I386\
- /out:"$(OUTDIR)/gc.dll" /implib:"$(OUTDIR)/gc.lib"
-LINK32_OBJS= \
- ".\Debug\allchblk.obj" \
- ".\Debug\alloc.obj" \
- ".\Debug\blacklst.obj" \
- ".\Debug\checksums.obj" \
- ".\Debug\dbg_mlc.obj" \
- ".\Debug\dyn_load.obj" \
- ".\Debug\finalize.obj" \
- ".\Debug\gc_cpp.obj" \
- ".\Debug\headers.obj" \
- ".\Debug\mach_dep.obj" \
- ".\Debug\malloc.obj" \
- ".\Debug\mallocx.obj" \
- ".\Debug\mark.obj" \
- ".\Debug\mark_rts.obj" \
- ".\Debug\misc.obj" \
- ".\Debug\new_hblk.obj" \
- ".\Debug\obj_map.obj" \
- ".\Debug\os_dep.obj" \
- ".\Debug\ptr_chck.obj" \
- ".\Debug\reclaim.obj" \
- ".\Debug\stubborn.obj" \
- ".\Debug\typd_mlc.obj" \
- ".\Debug\win32_threads.obj"
-
-".\Debug\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-!ELSEIF "$(CFG)" == "gctest - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "gctest\Release"
-# PROP BASE Intermediate_Dir "gctest\Release"
-# PROP BASE Target_Dir "gctest"
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "gctest\Release"
-# PROP Intermediate_Dir "gctest\Release"
-# PROP Target_Dir "gctest"
-OUTDIR=.\gctest\Release
-INTDIR=.\gctest\Release
-
-ALL : "gc - Win32 Release" ".\Release\gctest.exe"
-
-CLEAN :
- -@erase ".\gctest\Release\test.obj"
- -@erase ".\Release\gctest.exe"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-test.c : tests\test.c
- copy tests\test.c test.c
-
-CPP=cl.exe
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /YX /c
-CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
- "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS"\
- /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /c
-CPP_OBJS=.\gctest\Release/
-CPP_SBRS=.\.
-
-.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-MTL=mktyplib.exe
-# ADD BASE MTL /nologo /D "NDEBUG" /win32
-# ADD MTL /nologo /D "NDEBUG" /win32
-MTL_PROJ=/nologo /D "NDEBUG" /win32
-RSC=rc.exe
-# ADD BASE RSC /l 0x809 /d "NDEBUG"
-# ADD RSC /l 0x809 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/gctest.exe"
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
- odbccp32.lib /nologo /subsystem:windows /incremental:no\
- /pdb:"$(OUTDIR)/gctest.pdb" /machine:I386 /out:"Release/gctest.exe"
-LINK32_OBJS= \
- ".\gctest\Release\test.obj" \
- ".\Release\gc.lib"
-
-".\Release\gctest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "gctest\Debug"
-# PROP BASE Intermediate_Dir "gctest\Debug"
-# PROP BASE Target_Dir "gctest"
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "gctest\Debug"
-# PROP Intermediate_Dir "gctest\Debug"
-# PROP Target_Dir "gctest"
-OUTDIR=.\gctest\Debug
-INTDIR=.\gctest\Debug
-
-ALL : "gc - Win32 Debug" ".\Debug\gctest.exe" ".\gctest\Debug\gctest.bsc"
-
-CLEAN :
- -@erase ".\Debug\gctest.exe"
- -@erase ".\gctest\Debug\gctest.bsc"
- -@erase ".\gctest\Debug\gctest.map"
- -@erase ".\gctest\Debug\gctest.pdb"
- -@erase ".\gctest\Debug\test.obj"
- -@erase ".\gctest\Debug\test.sbr"
- -@erase ".\gctest\Debug\vc40.idb"
- -@erase ".\gctest\Debug\vc40.pdb"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
-CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
- /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR"$(INTDIR)/"\
- /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
-CPP_OBJS=.\gctest\Debug/
-CPP_SBRS=.\gctest\Debug/
-
-.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-MTL=mktyplib.exe
-# ADD BASE MTL /nologo /D "_DEBUG" /win32
-# ADD MTL /nologo /D "_DEBUG" /win32
-MTL_PROJ=/nologo /D "_DEBUG" /win32
-RSC=rc.exe
-# ADD BASE RSC /l 0x809 /d "_DEBUG"
-# ADD RSC /l 0x809 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
-BSC32_SBRS= \
- ".\gctest\Debug\test.sbr"
-
-".\gctest\Debug\gctest.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
- $(BSC32) @<<
- $(BSC32_FLAGS) $(BSC32_SBRS)
-<<
-
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /map /debug /machine:I386 /out:"Debug/gctest.exe"
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
- odbccp32.lib /nologo /subsystem:windows /incremental:no\
- /pdb:"$(OUTDIR)/gctest.pdb" /map:"$(INTDIR)/gctest.map" /debug /machine:I386\
- /out:"Debug/gctest.exe"
-LINK32_OBJS= \
- ".\Debug\gc.lib" \
- ".\gctest\Debug\test.obj"
-
-".\Debug\gctest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-!ELSEIF "$(CFG)" == "cord - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "cord\Release"
-# PROP BASE Intermediate_Dir "cord\Release"
-# PROP BASE Target_Dir "cord"
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "cord\Release"
-# PROP Intermediate_Dir "cord\Release"
-# PROP Target_Dir "cord"
-OUTDIR=.\cord\Release
-INTDIR=.\cord\Release
-
-ALL : "gc - Win32 Release" ".\Release\de.exe"
-
-CLEAN :
- -@erase ".\cord\Release\cordbscs.obj"
- -@erase ".\cord\Release\cordxtra.obj"
- -@erase ".\cord\Release\de.obj"
- -@erase ".\cord\Release\de_win.obj"
- -@erase ".\cord\Release\de_win.res"
- -@erase ".\Release\de.exe"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
-CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "." /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
- "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c
-CPP_OBJS=.\cord\Release/
-CPP_SBRS=.\.
-
-.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-MTL=mktyplib.exe
-# ADD BASE MTL /nologo /D "NDEBUG" /win32
-# ADD MTL /nologo /D "NDEBUG" /win32
-MTL_PROJ=/nologo /D "NDEBUG" /win32
-RSC=rc.exe
-# ADD BASE RSC /l 0x809 /d "NDEBUG"
-# ADD RSC /l 0x809 /d "NDEBUG"
-RSC_PROJ=/l 0x809 /fo"$(INTDIR)/de_win.res" /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/de.exe"
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
- odbccp32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)/de.pdb"\
- /machine:I386 /out:"Release/de.exe"
-LINK32_OBJS= \
- ".\cord\Release\cordbscs.obj" \
- ".\cord\Release\cordxtra.obj" \
- ".\cord\Release\de.obj" \
- ".\cord\Release\de_win.obj" \
- ".\cord\Release\de_win.res" \
- ".\Release\gc.lib"
-
-".\Release\de.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "cord\Debug"
-# PROP BASE Intermediate_Dir "cord\Debug"
-# PROP BASE Target_Dir "cord"
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "cord\Debug"
-# PROP Intermediate_Dir "cord\Debug"
-# PROP Target_Dir "cord"
-OUTDIR=.\cord\Debug
-INTDIR=.\cord\Debug
-
-ALL : "gc - Win32 Debug" ".\Debug\de.exe"
-
-CLEAN :
- -@erase ".\cord\Debug\cordbscs.obj"
- -@erase ".\cord\Debug\cordxtra.obj"
- -@erase ".\cord\Debug\de.obj"
- -@erase ".\cord\Debug\de.pdb"
- -@erase ".\cord\Debug\de_win.obj"
- -@erase ".\cord\Debug\de_win.res"
- -@erase ".\cord\Debug\vc40.idb"
- -@erase ".\cord\Debug\vc40.pdb"
- -@erase ".\Debug\de.exe"
- -@erase ".\Debug\de.ilk"
-
-"$(OUTDIR)" :
- if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
-
-CPP=cl.exe
-# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
-CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /I include /D "_DEBUG" /D "WIN32" /D\
- "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX\
- /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
-CPP_OBJS=.\cord\Debug/
-CPP_SBRS=.\.
-
-.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
-
-.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
-
-MTL=mktyplib.exe
-# ADD BASE MTL /nologo /D "_DEBUG" /win32
-# ADD MTL /nologo /D "_DEBUG" /win32
-MTL_PROJ=/nologo /D "_DEBUG" /win32
-RSC=rc.exe
-# ADD BASE RSC /l 0x809 /d "_DEBUG"
-# ADD RSC /l 0x809 /d "_DEBUG"
-RSC_PROJ=/l 0x809 /fo"$(INTDIR)/de_win.res" /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
-BSC32_SBRS= \
-
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/de.exe"
-LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
- odbccp32.lib /nologo /subsystem:windows /incremental:yes\
- /pdb:"$(OUTDIR)/de.pdb" /debug /machine:I386 /out:"Debug/de.exe"
-LINK32_OBJS= \
- ".\cord\Debug\cordbscs.obj" \
- ".\cord\Debug\cordxtra.obj" \
- ".\cord\Debug\de.obj" \
- ".\cord\Debug\de_win.obj" \
- ".\cord\Debug\de_win.res" \
- ".\Debug\gc.lib"
-
-".\Debug\de.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LINK32_OBJS)
-<<
-
-!ENDIF
-
-################################################################################
-# Begin Target
-
-# Name "gc - Win32 Release"
-# Name "gc - Win32 Debug"
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-!ENDIF
-
-################################################################################
-# Begin Source File
-
-SOURCE=.\gc_cpp.cpp
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_RECLA=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- ".\include\gc_cpp.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_RECLA=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\gc_cpp.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-
-".\Release\gc_cpp.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_RECLA=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- ".\include\gc_cpp.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_RECLA=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\gc_cpp.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-
-".\Debug\gc_cpp.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\reclaim.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_RECLA=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_RECLA=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\reclaim.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-
-".\Release\reclaim.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_RECLA=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_RECLA=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\reclaim.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-
-".\Debug\reclaim.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-
-################################################################################
-# Begin Source File
-
-SOURCE=.\os_dep.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_OS_DE=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\STAT.H"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_OS_DE=\
- ".\il\PCR_IL.h"\
- ".\mm\PCR_MM.h"\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
- ".\vd\PCR_VD.h"\
-
-
-".\Release\os_dep.obj" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
-
-".\Release\os_dep.sbr" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_OS_DE=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\STAT.H"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_OS_DE=\
- ".\il\PCR_IL.h"\
- ".\mm\PCR_MM.h"\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
- ".\vd\PCR_VD.h"\
-
-
-".\Debug\os_dep.obj" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
-
-".\Debug\os_dep.sbr" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\misc.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_MISC_=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MISC_=\
- ".\il\PCR_IL.h"\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\misc.obj" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
-
-".\Release\misc.sbr" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_MISC_=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MISC_=\
- ".\il\PCR_IL.h"\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\misc.obj" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
-
-".\Debug\misc.sbr" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\mark_rts.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_MARK_=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MARK_=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\mark_rts.obj" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
-
-".\Release\mark_rts.sbr" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_MARK_=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MARK_=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\mark_rts.obj" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
-
-".\Debug\mark_rts.sbr" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\mach_dep.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_MACH_=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MACH_=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\mach_dep.obj" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
-
-".\Release\mach_dep.sbr" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_MACH_=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MACH_=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\mach_dep.obj" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
-
-".\Debug\mach_dep.sbr" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\headers.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_HEADE=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_HEADE=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\headers.obj" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
-
-".\Release\headers.sbr" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_HEADE=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_HEADE=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\headers.obj" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
-
-".\Debug\headers.sbr" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\alloc.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_ALLOC=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_ALLOC=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\alloc.obj" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
-
-".\Release\alloc.sbr" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_ALLOC=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_ALLOC=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\alloc.obj" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
-
-".\Debug\alloc.sbr" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\allchblk.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_ALLCH=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_ALLCH=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\allchblk.obj" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
-
-".\Release\allchblk.sbr" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_ALLCH=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_ALLCH=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\allchblk.obj" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
-
-".\Debug\allchblk.sbr" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\stubborn.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_STUBB=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_STUBB=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\stubborn.obj" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
-
-".\Release\stubborn.sbr" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_STUBB=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_STUBB=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\stubborn.obj" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
-
-".\Debug\stubborn.sbr" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\obj_map.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_OBJ_M=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_OBJ_M=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\obj_map.obj" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
-
-".\Release\obj_map.sbr" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_OBJ_M=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_OBJ_M=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\obj_map.obj" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
-
-".\Debug\obj_map.sbr" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\new_hblk.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_NEW_H=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_NEW_H=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\new_hblk.obj" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
-
-".\Release\new_hblk.sbr" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_NEW_H=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_NEW_H=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\new_hblk.obj" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
-
-".\Debug\new_hblk.sbr" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\mark.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_MARK_C=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_pmark.h"\
- ".\include\gc_mark.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MARK_C=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\mark.obj" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
-
-".\Release\mark.sbr" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_MARK_C=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_pmark.h"\
- ".\include\gc_mark.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MARK_C=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\mark.obj" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
-
-".\Debug\mark.sbr" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\malloc.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_MALLO=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MALLO=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\malloc.obj" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
-
-".\Release\malloc.sbr" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_MALLO=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MALLO=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\malloc.obj" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
-
-".\Debug\malloc.sbr" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\mallocx.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_MALLX=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MALLX=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\mallocx.obj" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
-
-".\Release\mallocx.sbr" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_MALLX=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_MALLX=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\mallocx.obj" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
-
-".\Debug\mallocx.sbr" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\finalize.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_FINAL=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_pmark.h"\
- ".\include\gc_mark.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_FINAL=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\finalize.obj" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
-
-".\Release\finalize.sbr" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_FINAL=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_pmark.h"\
- ".\include\gc_mark.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_FINAL=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\finalize.obj" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
-
-".\Debug\finalize.sbr" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\dbg_mlc.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_DBG_M=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_DBG_M=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\dbg_mlc.obj" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
-
-".\Release\dbg_mlc.sbr" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_DBG_M=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_DBG_M=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\dbg_mlc.obj" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
-
-".\Debug\dbg_mlc.sbr" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\blacklst.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_BLACK=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_BLACK=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\blacklst.obj" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
-
-".\Release\blacklst.sbr" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_BLACK=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_BLACK=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\blacklst.obj" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
-
-".\Debug\blacklst.sbr" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\typd_mlc.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_TYPD_=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_pmark.h"\
- ".\include\gc_mark.h"\
- ".\include\private\gc_priv.h"\
- ".\include\gc_typed.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_TYPD_=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\typd_mlc.obj" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
-
-".\Release\typd_mlc.sbr" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_TYPD_=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_pmark.h"\
- ".\include\gc_mark.h"\
- ".\include\private\gc_priv.h"\
- ".\include\gc_typed.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_TYPD_=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\typd_mlc.obj" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
-
-".\Debug\typd_mlc.sbr" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\ptr_chck.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_PTR_C=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_pmark.h"\
- ".\include\gc_mark.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_PTR_C=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\ptr_chck.obj" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
-
-".\Release\ptr_chck.sbr" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_PTR_C=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_pmark.h"\
- ".\include\gc_mark.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_PTR_C=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\ptr_chck.obj" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
-
-".\Debug\ptr_chck.sbr" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\dyn_load.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_DYN_L=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\STAT.H"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_DYN_L=\
- ".\il\PCR_IL.h"\
- ".\mm\PCR_MM.h"\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\dyn_load.obj" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
-
-".\Release\dyn_load.sbr" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_DYN_L=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\STAT.H"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_DYN_L=\
- ".\il\PCR_IL.h"\
- ".\mm\PCR_MM.h"\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\dyn_load.obj" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
-
-".\Debug\dyn_load.sbr" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\win32_threads.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_WIN32=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_WIN32=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\win32_threads.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
-
-".\Release\win32_threads.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_WIN32=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_WIN32=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\win32_threads.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
-
-".\Debug\win32_threads.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\checksums.c
-
-!IF "$(CFG)" == "gc - Win32 Release"
-
-DEP_CPP_CHECK=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_CHECK=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Release\checksums.obj" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
-
-".\Release\checksums.sbr" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-
-DEP_CPP_CHECK=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_CHECK=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-".\Debug\checksums.obj" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
-
-".\Debug\checksums.sbr" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-# End Target
-################################################################################
-# Begin Target
-
-# Name "gctest - Win32 Release"
-# Name "gctest - Win32 Debug"
-
-!IF "$(CFG)" == "gctest - Win32 Release"
-
-!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
-
-!ENDIF
-
-################################################################################
-# Begin Project Dependency
-
-# Project_Dep_Name "gc"
-
-!IF "$(CFG)" == "gctest - Win32 Release"
-
-"gc - Win32 Release" :
- $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Release"
-
-!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
-
-"gc - Win32 Debug" :
- $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Debug"
-
-!ENDIF
-
-# End Project Dependency
-################################################################################
-# Begin Source File
-
-SOURCE=.\tests\test.c
-DEP_CPP_TEST_=\
- ".\include\private\gcconfig.h"\
- ".\include\gc.h"\
- ".\include\private\gc_hdrs.h"\
- ".\include\private\gc_priv.h"\
- ".\include\gc_typed.h"\
- {$(INCLUDE)}"\sys\TYPES.H"\
-
-NODEP_CPP_TEST_=\
- ".\th\PCR_Th.h"\
- ".\th\PCR_ThCrSec.h"\
- ".\th\PCR_ThCtl.h"\
-
-
-!IF "$(CFG)" == "gctest - Win32 Release"
-
-
-".\gctest\Release\test.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
-
-
-!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
-
-
-".\gctest\Debug\test.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
-
-".\gctest\Debug\test.sbr" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
-
-
-!ENDIF
-
-# End Source File
-# End Target
-################################################################################
-# Begin Target
-
-# Name "cord - Win32 Release"
-# Name "cord - Win32 Debug"
-
-!IF "$(CFG)" == "cord - Win32 Release"
-
-!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-
-!ENDIF
-
-################################################################################
-# Begin Project Dependency
-
-# Project_Dep_Name "gc"
-
-!IF "$(CFG)" == "cord - Win32 Release"
-
-"gc - Win32 Release" :
- $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Release"
-
-!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-
-"gc - Win32 Debug" :
- $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Debug"
-
-!ENDIF
-
-# End Project Dependency
-################################################################################
-# Begin Source File
-
-SOURCE=.\cord\de_win.c
-DEP_CPP_DE_WI=\
- ".\include\cord.h"\
- ".\cord\de_cmds.h"\
- ".\cord\de_win.h"\
- ".\include\private\cord_pos.h"\
-
-NODEP_CPP_DE_WI=\
- ".\include\gc.h"\
-
-
-!IF "$(CFG)" == "cord - Win32 Release"
-
-
-".\cord\Release\de_win.obj" : $(SOURCE) $(DEP_CPP_DE_WI) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-
-
-".\cord\Debug\de_win.obj" : $(SOURCE) $(DEP_CPP_DE_WI) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\cord\de.c
-DEP_CPP_DE_C2e=\
- ".\include\cord.h"\
- ".\cord\de_cmds.h"\
- ".\cord\de_win.h"\
- ".\include\private\cord_pos.h"\
-
-NODEP_CPP_DE_C2e=\
- ".\include\gc.h"\
-
-
-!IF "$(CFG)" == "cord - Win32 Release"
-
-
-".\cord\Release\de.obj" : $(SOURCE) $(DEP_CPP_DE_C2e) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-
-
-".\cord\Debug\de.obj" : $(SOURCE) $(DEP_CPP_DE_C2e) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\cord\cordxtra.c
-DEP_CPP_CORDX=\
- ".\include\cord.h"\
- ".\include\ec.h"\
- ".\include\private\cord_pos.h"\
-
-NODEP_CPP_CORDX=\
- ".\include\gc.h"\
-
-
-!IF "$(CFG)" == "cord - Win32 Release"
-
-
-".\cord\Release\cordxtra.obj" : $(SOURCE) $(DEP_CPP_CORDX) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-
-
-".\cord\Debug\cordxtra.obj" : $(SOURCE) $(DEP_CPP_CORDX) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\cord\cordbscs.c
-DEP_CPP_CORDB=\
- ".\include\cord.h"\
- ".\include\private\cord_pos.h"\
-
-NODEP_CPP_CORDB=\
- ".\include\gc.h"\
-
-
-!IF "$(CFG)" == "cord - Win32 Release"
-
-
-".\cord\Release\cordbscs.obj" : $(SOURCE) $(DEP_CPP_CORDB) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-
-
-".\cord\Debug\cordbscs.obj" : $(SOURCE) $(DEP_CPP_CORDB) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ENDIF
-
-# End Source File
-################################################################################
-# Begin Source File
-
-SOURCE=.\cord\de_win.RC
-
-!IF "$(CFG)" == "cord - Win32 Release"
-
-
-".\cord\Release\de_win.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x809 /fo"$(INTDIR)/de_win.res" /i "cord" /d "NDEBUG" $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-
-
-".\cord\Debug\de_win.res" : $(SOURCE) "$(INTDIR)"
- $(RSC) /l 0x809 /fo"$(INTDIR)/de_win.res" /i "cord" /d "_DEBUG" $(SOURCE)
-
-
-!ENDIF
-
-# End Source File
-# End Target
-# End Project
-################################################################################
diff --git a/boehm-gc/NT_X64_STATIC_THREADS_MAKEFILE b/boehm-gc/NT_X64_STATIC_THREADS_MAKEFILE
new file mode 100644
index 00000000000..3ccb75d45a3
--- /dev/null
+++ b/boehm-gc/NT_X64_STATIC_THREADS_MAKEFILE
@@ -0,0 +1,70 @@
+# Makefile for Windows NT. Assumes Microsoft compiler.
+# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
+
+MY_CPU=AMD64
+CPU=$(MY_CPU)
+!include <ntwin32.mak>
+
+# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but
+# not earlier versions. We can deal with either, but not inconsistency.
+.SUFFIXES:
+.SUFFIXES: .obj .cpp .c
+
+# Atomic_ops installation directory. For win32, the source directory
+# should do, since we only need the headers.
+# We assume this was manually unpacked, since I'm not sure there is
+# a Windows standard command line tool to do this.
+AO_SRC_DIR=libatomic_ops/src
+AO_INCLUDE_DIR=$(AO_SRC_DIR)
+
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj extra\msvc_dbg.obj thread_local_alloc.obj
+
+all: gctest.exe cord\de.exe test_cpp.exe
+
+.c.obj:
+ $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj /wd4701
+# Disable "may not be initialized" warnings. They're too approximate.
+# Disable crt security warnings, since unfortunately they warn about all sorts
+# of safe uses of strncpy. It would be nice to leave the rest enabled.
+
+.cpp.obj:
+ $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_THREADS -DTHREAD_LOCAL_ALLOC -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
+
+$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\gc_disclaim.h include\private\msvc_dbg.h
+
+gc.lib: $(OBJS)
+ lib /MACHINE:X64 /out:gc.lib $(OBJS)
+
+gctest.exe: tests\test.obj gc.lib
+# This produces a "GUI" applications that opens no windows and writes to
+# the log file "gctest.gc.log".
+ $(link) $(ldebug) $(guiflags) -out:$*.exe tests\test.obj $(guilibs) gc.lib
+
+cord\de_win.rbj: cord\de_win.res
+ cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
+
+cord\tests\de.obj cord\tests\de_win.obj: include\cord.h include\cord_pos.h cord\tests\de_win.h cord\tests\de_cmds.h
+
+cord\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
+ $(rc) $(rcvars) -r -fo cord\de_win.res cord\tests\de_win.rc
+
+# Cord/de is a real win32 gui application.
+cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib
+ $(link) $(ldebug) $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
+
+gc_cpp.obj: include\gc_cpp.h include\gc.h
+
+gc_cpp.cpp: gc_cpp.cc
+# copy gc_cpp.cc gc_cpp.cpp
+
+test_cpp.cpp: tests\test_cpp.cc
+ copy tests\test_cpp.cc test_cpp.cpp
+
+# This generates the C++ test executable. The executable expects
+# a single numeric argument, which is the number of iterations.
+# The output appears in the file "test_cpp.gc.log".
+test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
+ $(link) $(ldebug) $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
+
+AO_SCR_DIR:
+ tar xvfz $(AO_SRC_DIR).tar.gz;
diff --git a/boehm-gc/NT_X64_THREADS_MAKEFILE b/boehm-gc/NT_X64_THREADS_MAKEFILE
new file mode 100644
index 00000000000..b8495d0872c
--- /dev/null
+++ b/boehm-gc/NT_X64_THREADS_MAKEFILE
@@ -0,0 +1,87 @@
+# Makefile for Windows NT. Assumes Microsoft compiler.
+# modified 2007 August by Friedrich Dominicus:
+# - copied from NT_X64_STATIC_THREADS_MAKEFILES
+# - checked agaist gc.mak (NT_THREADS_MAKEFILE)
+# - added changes to integrate the tools
+# - currently just with debug information
+# problems can be sent to
+# frido at q-software-solutions.de
+#
+# or the mailing list
+
+
+MY_CPU=AMD64
+CPU=$(MY_CPU)
+!include <ntwin32.mak>
+
+# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but # not earlier versions. We can deal with either, but not inconsistency.
+.SUFFIXES:
+.SUFFIXES: .obj .cpp .c
+
+# Atomic_ops installation directory. For win32, the source directory
+# should do, since we only need the headers.
+# We assume this was manually unpacked, since I'm not sure there is
+# a Windows standard command line tool to do this.
+AO_SRC_DIR=libatomic_ops/src
+AO_INCLUDE_DIR=$(AO_SRC_DIR)
+
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj extra\msvc_dbg.obj thread_local_alloc.obj
+
+all: gc64.dll gctest.exe cord\de.exe test_cpp.exe
+
+.c.obj:
+ $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_DLL -DGC_THREADS -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj /wd4701
+# Disable "may not be initialized" warnings. They're too approximate.
+# Disable crt security warnings, since unfortunately they warn about all sorts # of safe uses of strncpy. It would be nice to leave the rest enabled.
+
+.cpp.obj:
+ $(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_DLL -DGC_THREADS -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
+
+$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\gc_disclaim.h include\private\msvc_dbg.h
+
+
+LINK64=link.exe
+LINK64_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib \
+shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo \
+/subsystem:windows /dll /incremental:no /pdb:"gc.pdb" /machine:X64 /out:"gc64.dll" \
+/implib:"gc64_dll.lib"
+
+gc64.dll : $(OBJS)
+ $(LINK64) $(ldebug) $(LINK64_FLAGS) $(OBJS)
+
+
+gctest.exe: tests\test.obj gc64_dll.lib
+# This produces a "GUI" applications that opens no windows and writes to
+# the log file "gctest.gc.log".
+ $(link) $(ldebug) $(guiflags) -out:$*.exe tests\test.obj $(guilibs) gc64_dll.lib
+
+cord\de_win.rbj: cord\de_win.res
+ cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
+
+cord\tests\de.obj cord\tests\de_win.obj: include\cord.h include\cord_pos.h cord\tests\de_win.h cord\tests\de_cmds.h
+
+cord\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
+ $(rc) $(rcvars) -r -fo cord\de_win.res cord\tests\de_win.rc
+
+# Cord/de is a real win32 gui application.
+cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc64_dll.lib
+ $(link) $(ldebug) $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\de_win.rbj gc64_dll.lib $(guilibs)
+
+gc_cpp.obj: include\gc_cpp.h include\gc.h
+
+gc_cpp.cpp: gc_cpp.cc
+# copy gc_cpp.cc gc_cpp.cpp
+
+test_cpp.cpp: tests\test_cpp.cc
+ copy tests\test_cpp.cc test_cpp.cpp
+
+# This generates the C++ test executable. The executable expects # a single numeric argument, which is the number of iterations.
+# The output appears in the file "test_cpp.gc.log".
+test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc64_dll.lib
+ $(link) $(ldebug) $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc64_dll.lib $(guilibs)
+
+AO_SCR_DIR:
+ tar xvfz $(AO_SRC_DIR).tar.gz;
+
+clean:
+ del *.obj gc64_dll.lib gc64.dll
diff --git a/boehm-gc/OS2_MAKEFILE b/boehm-gc/OS2_MAKEFILE
index 690598d69d4..acfcd566d7e 100644
--- a/boehm-gc/OS2_MAKEFILE
+++ b/boehm-gc/OS2_MAKEFILE
@@ -5,12 +5,12 @@
# Significantly revised for GC version 4.4 by Mark Boulter (Jan 1994).
-OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj typd_mlc.obj ptr_chck.obj mallocx.obj
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj fnlz_mlc.obj malloc.obj stubborn.obj typd_mlc.obj ptr_chck.obj mallocx.obj
CORDOBJS= cord\cordbscs.obj cord\cordxtra.obj cord\cordprnt.obj
CC= icc
-CFLAGS= /O /Q /DSILENT /DSMALL_CONFIG /DALL_INTERIOR_POINTERS
+CFLAGS= /O /Q /DSMALL_CONFIG /DALL_INTERIOR_POINTERS
# Use /Ti instead of /O for debugging
# Setjmp_test may yield overly optimistic results when compiled
# without optimization.
@@ -32,14 +32,14 @@ mach_dep.obj: mach_dep.c
gctest.exe: test.obj gc.lib
$(CC) $(CFLAGS) /B"/STACK:524288" /Fegctest test.obj gc.lib
-cord\cordbscs.obj: cord\cordbscs.c include\cord.h include\private\cord_pos.h
+cord\cordbscs.obj: cord\cordbscs.c include\cord.h include\cord_pos.h
$(CC) $(CFLAGS) /C /Focord\cordbscs cord\cordbscs.c
-cord\cordxtra.obj: cord\cordxtra.c include\cord.h include\private\cord_pos.h include\ec.h
+cord\cordxtra.obj: cord\cordxtra.c include\cord.h include\cord_pos.h include\ec.h
$(CC) $(CFLAGS) /C /Focord\cordxtra cord\cordxtra.c
-cord\cordprnt.obj: cord\cordprnt.c include\cord.h include\private\cord_pos.h include\ec.h
+cord\cordprnt.obj: cord\cordprnt.c include\cord.h include\cord_pos.h include\ec.h
$(CC) $(CFLAGS) /C /Focord\cordprnt cord\cordprnt.c
-cord\cordtest.exe: cord\cordtest.c include\cord.h include\private\cord_pos.h include\ec.h $(CORDOBJS) gc.lib
- $(CC) $(CFLAGS) /B"/STACK:65536" /Fecord\cordtest cord\cordtest.c gc.lib $(CORDOBJS)
+cord\cordtest.exe: cord\tests\cordtest.c include\cord.h include\cord_pos.h include\ec.h $(CORDOBJS) gc.lib
+ $(CC) $(CFLAGS) /B"/STACK:65536" /Fecord\cordtest cord\tests\cordtest.c gc.lib $(CORDOBJS)
diff --git a/boehm-gc/PCR-Makefile b/boehm-gc/PCR-Makefile
index 1eae3672556..ff057808568 100644
--- a/boehm-gc/PCR-Makefile
+++ b/boehm-gc/PCR-Makefile
@@ -10,10 +10,9 @@ include ../config/common.mk
# compilation flags, etc.
#
-
CPPFLAGS = $(INCLUDE) $(CONFIG_CPPFLAGS) \
-DPCR_NO_RENAME -DPCR_NO_HOSTDEP_ERR
-#CFLAGS = -DPCR -DSILENT $(CONFIG_CFLAGS)
+#CFLAGS = -DPCR $(CONFIG_CFLAGS)
CFLAGS = -DPCR $(CONFIG_CFLAGS)
SPECIALCFLAGS = # For code involving asm's
@@ -27,21 +26,15 @@ LDRFLAGS = $(CONFIG_LDRFLAGS)
LDFLAGS = $(CONFIG_LDFLAGS)
#
-#
-#
-#
# BEGIN PACKAGE-SPECIFIC PART
#
-#
-#
-#
# Fix to point to local pcr installation directory.
PCRDIR= ..
-COBJ= alloc.o reclaim.o allchblk.o misc.o os_dep.o mark_rts.o headers.o mark.o obj_map.o pcr_interface.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o mallocx.o
+COBJ= alloc.o reclaim.o allchblk.o misc.o os_dep.o mark_rts.o headers.o mark.o obj_map.o pcr_interface.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o fnlz_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o mallocx.o
-CSRC= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c mallocx.c
+CSRC= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c fnlz_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c mallocx.c
SHELL= /bin/sh
@@ -50,19 +43,5 @@ default: gc.o
gc.o: $(COBJ) mach_dep.o
$(LDR) $(CONFIG_LDRFLAGS) -o gc.o $(COBJ) mach_dep.o
-
-mach_dep.o: mach_dep.c mips_mach_dep.s rs6000_mach_dep.s if_mach if_not_there
- rm -f mach_dep.o
- ./if_mach MIPS "" as -o mach_dep.o mips_mach_dep.s
- ./if_mach RS6000 "" as -o mach_dep.o rs6000_mach_dep.s
- ./if_mach ALPHA "" as -o mach_dep.o alpha_mach_dep.s
- ./if_mach SPARC SUNOS5 as -o mach_dep.o sparc_mach_dep.s
- ./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) mach_dep.c
-
-if_mach: if_mach.c gcconfig.h
- $(CC) $(CFLAGS) -o if_mach if_mach.c
-
-if_not_there: if_not_there.c
- $(CC) $(CFLAGS) -o if_not_there if_not_there.c
-
-
+mach_dep.o: mach_dep.c
+ $(CC) -c $(SPECIALCFLAGS) mach_dep.c
diff --git a/boehm-gc/doc/README b/boehm-gc/README
index ff77113ee8c..a59436ae910 100644
--- a/boehm-gc/doc/README
+++ b/boehm-gc/README
@@ -1,7 +1,7 @@
Copyright (c) 1988, 1989 Hans-J. Boehm, Alan J. Demers
Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
-Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
+Copyright (c) 1999-2011 by Hewlett-Packard Development Company.
The file linux_threads.c is also
Copyright (c) 1998 by Fergus Henderson. All rights reserved.
@@ -11,7 +11,10 @@ Copyright (c) 2001 by Red Hat Inc. All rights reserved.
Several files supporting GNU-style builds are copyrighted by the Free
Software Foundation, and carry a different license from that given
-below.
+below. The files included in the libatomic_ops distribution (included
+here) use either the license below, or a similar MIT-style license,
+or, for some files not actually used by the garbage-collector library, the
+GPL.
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -25,10 +28,15 @@ modified is included with the above copyright notice.
A few of the files needed to use the GNU-style build procedure come with
slightly different licenses, though they are all similar in spirit. A few
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
+collector. (If you are concerned about such things, I recommend you look
at the notice in config.guess or ltmain.sh.)
-This is version 6.3 of a conservative garbage collector for C and C++.
+The atomic_ops library contains some code that is covered by the GNU General
+Public License, but is not needed by, nor linked into the collector library.
+It is included here only because the atomic_ops distribution is, for
+simplicity, included in its entirety.
+
+This is version 7.3alpha3 of a conservative garbage collector for C and C++.
You might find a more recent version of this at
@@ -71,7 +79,7 @@ http://www.hpl.hp.com/personal/Hans_Boehm/papers/, among other places.)
Unlike the collector described in the second reference, this collector
operates either with the mutator stopped during the entire collection
(default) or incrementally during allocations. (The latter is supported
-on only a few machines.) On the most common platforms, it can be built
+on fewer machines.) On the most common platforms, it can be built
with or without thread support. On a few platforms, it can take advantage
of a multiprocessor to speed up garbage collection.
@@ -92,7 +100,7 @@ collector. (See doc/README.cords and H.-J. Boehm, R. Atkinson, and M. Plass,
(December 1995), pp. 1315-1330. This is very similar to the "rope" package
in Xerox Cedar, or the "rope" package in the SGI STL or the g++ distribution.)
-Further collector documantation can be found at
+Further collector documentation can be found at
http://www.hpl.hp.com/personal/Hans_Boehm/gc
@@ -110,25 +118,27 @@ introduced leaks, the amount of unreclaimed memory typically stays
bounded.
In the following, an "object" is defined to be a region of memory allocated
-by the routines described below.
+by the routines described below.
Any objects not intended to be collected must be pointed to either
from other such accessible objects, or from the registers,
stack, data, or statically allocated bss segments. Pointers from
the stack or registers may point to anywhere inside an object.
The same is true for heap pointers if the collector is compiled with
- ALL_INTERIOR_POINTERS defined, as is now the default.
+ALL_INTERIOR_POINTERS defined, or GC_all_interior_pointers is otherwise
+set, as is now the default.
Compiling without ALL_INTERIOR_POINTERS may reduce accidental retention
-of garbage objects, by requiring pointers from the heap to to the beginning
+of garbage objects, by requiring pointers from the heap to the beginning
of an object. But this no longer appears to be a significant
-issue for most programs.
+issue for most programs occupying a small fraction of the possible
+address space.
There are a number of routines which modify the pointer recognition
algorithm. GC_register_displacement allows certain interior pointers
to be recognized even if ALL_INTERIOR_POINTERS is nor defined.
GC_malloc_ignore_off_page allows some pointers into the middle of large objects
-to be disregarded, greatly reducing the probablility of accidental
+to be disregarded, greatly reducing the probability of accidental
retention of large objects. For most purposes it seems best to compile
with ALL_INTERIOR_POINTERS and to use GC_malloc_ignore_off_page if
you get collector warnings from allocations of very large objects.
@@ -165,9 +175,7 @@ need to be informed.
and during uninterruptible parts of the allocation process.
Like standard ANSI C mallocs, by default it is unsafe to invoke
malloc (and other GC routines) from a signal handler while another
-malloc call may be in progress. Removing -DNO_SIGNALS from Makefile
-attempts to remedy that. But that may not be reliable with a compiler that
-substantially reorders memory operations inside GC_malloc.
+malloc call may be in progress.
The allocator/collector can also be configured for thread-safe operation.
(Full signal safety can also be achieved, but only at the cost of two system
@@ -181,29 +189,40 @@ stored on the thread's stack for the duration of their lifetime.
INSTALLATION AND PORTABILITY
- As distributed, the macro SILENT is defined in Makefile.
-In the event of problems, this can be removed to obtain a moderate
-amount of descriptive output for each collection.
+ As distributed, the collector operates silently
+In the event of problems, this can usually be changed by defining the
+GC_PRINT_STATS or GC_PRINT_VERBOSE_STATS environment variables. This
+will result in a few lines of descriptive output for each collection.
(The given statistics exhibit a few peculiarities.
Things don't appear to add up for a variety of reasons, most notably
fragmentation losses. These are probably much more significant for the
contrived program "test.c" than for your application.)
- Note that typing "make test" will automatically build the collector
-and then run setjmp_test and gctest. Setjmp_test will give you information
-about configuring the collector, which is useful primarily if you have
-a machine that's not already supported. Gctest is a somewhat superficial
-test of collector functionality. Failure is indicated by a core dump or
-a message to the effect that the collector is broken. Gctest takes about
-35 seconds to run on a SPARCstation 2. It may use up to 8 MB of memory. (The
-multi-threaded version will use more. 64-bit versions may use more.)
-"Make test" will also, as its last step, attempt to build and test the
-"cord" string library. This will fail without an ANSI C compiler, but
-the garbage collector itself should still be usable.
-
- The Makefile will generate a library gc.a which you should link against.
+ On most Un*x-like platforms, the collector can be built either using a
+GNU autoconf-based build infrastructure (type "configure; make" in the
+simplest case), or with a classic makefile by itself (type
+"make -f Makefile.direct"). Here we focus on the latter option.
+On other platforms, typically only the latter option is available, though
+with a different supplied Makefile.)
+
+ For the Makefile.direct-based process, typing "make test" instead of "make"
+will automatically build the collector and then run setjmp_test and gctest.
+Setjmp_test will give you information about configuring the collector, which is
+useful primarily if you have a machine that's not already supported. Gctest is
+a somewhat superficial test of collector functionality. Failure is indicated
+by a core dump or a message to the effect that the collector is broken. Gctest
+takes about a second to two to run on reasonable 2007 vintage desktops. It may
+use up to about 30MB of memory. (The multi-threaded version will use more.
+64-bit versions may use more.) "Make test" will also, as its last step, attempt
+to build and test the "cord" string library.)
+
+ Makefile.direct will generate a library gc.a which you should link against.
Typing "make cords" will add the cord library to gc.a.
-Note that this requires an ANSI C compiler.
+
+ The GNU style build process understands the usual targets. "Make check"
+runs a number of tests. "Make install" installs at least libgc, and libcord.
+Try "./configure --help" to see the configuration options. It is currently
+not possible to exercise all combinations of build options this way.
It is suggested that if you need to replace a piece of the collector
(e.g. GC_mark_rts.c) you simply list your version ahead of gc.a on the
@@ -220,10 +239,6 @@ machines that use a flat 32-bit or 64-bit address space.
That includes the vast majority of Workstations and X86 (X >= 3) PCs.
(The list here was deleted because it was getting too long and constantly
out of date.)
- It does NOT run under plain 16-bit DOS or Windows 3.X. There are however
-various packages (e.g. win32s, djgpp) that allow flat 32-bit address
-applications to run under those systemsif the have at least an 80386 processor,
-and several of those are compatible with the collector.
In a few cases (Amiga, OS/2, Win32, MacOS) a separate makefile
or equivalent is supplied. Many of these have separate README.system
@@ -255,86 +270,17 @@ enforce less alignment for pointers.
or 64 bit addresses will require a major effort. A port to plain MSDOS
or win16 is hard.
- For machines not already mentioned, or for nonstandard compilers, the
-following are likely to require change:
-
-1. The parameters in gcconfig.h.
- The parameters that will usually require adjustment are
- STACKBOTTOM, ALIGNMENT and DATASTART. Setjmp_test
- prints its guesses of the first two.
- DATASTART should be an expression for computing the
- address of the beginning of the data segment. This can often be
- &etext. But some memory management units require that there be
- some unmapped space between the text and the data segment. Thus
- it may be more complicated. On UNIX systems, this is rarely
- documented. But the adb "$m" command may be helpful. (Note
- that DATASTART will usually be a function of &etext. Thus a
- single experiment is usually insufficient.)
- STACKBOTTOM is used to initialize GC_stackbottom, which
- should be a sufficient approximation to the coldest stack address.
- On some machines, it is difficult to obtain such a value that is
- valid across a variety of MMUs, OS releases, etc. A number of
- alternatives exist for using the collector in spite of this. See the
- discussion in gcconfig.h immediately preceding the various
- definitions of STACKBOTTOM.
-
-2. mach_dep.c.
- The most important routine here is one to mark from registers.
- The distributed file includes a generic hack (based on setjmp) that
- happens to work on many machines, and may work on yours. Try
- compiling and running setjmp_t.c to see whether it has a chance of
- working. (This is not correct C, so don't blame your compiler if it
- doesn't work. Based on limited experience, register window machines
- are likely to cause trouble. If your version of setjmp claims that
- all accessible variables, including registers, have the value they
- had at the time of the longjmp, it also will not work. Vanilla 4.2 BSD
- on Vaxen makes such a claim. SunOS does not.)
- If your compiler does not allow in-line assembly code, or if you prefer
- not to use such a facility, mach_dep.c may be replaced by a .s file
- (as we did for the MIPS machine and the PC/RT).
- At this point enough architectures are supported by mach_dep.c
- that you will rarely need to do more than adjust for assembler
- syntax.
-
-3. os_dep.c (and gc_priv.h).
- Several kinds of operating system dependent routines reside here.
- Many are optional. Several are invoked only through corresponding
- macros in gc_priv.h, which may also be redefined as appropriate.
- The routine GC_register_data_segments is crucial. It registers static
- data areas that must be traversed by the collector. (User calls to
- GC_add_roots may sometimes be used for similar effect.)
- Routines to obtain memory from the OS also reside here.
- Alternatively this can be done entirely by the macro GET_MEM
- defined in gc_priv.h. Routines to disable and reenable signals
- also reside here if they are need by the macros DISABLE_SIGNALS
- and ENABLE_SIGNALS defined in gc_priv.h.
- In a multithreaded environment, the macros LOCK and UNLOCK
- in gc_priv.h will need to be suitably redefined.
- The incremental collector requires page dirty information, which
- is acquired through routines defined in os_dep.c. Unless directed
- otherwise by gcconfig.h, these are implemented as stubs that simply
- treat all pages as dirty. (This of course makes the incremental
- collector much less useful.)
-
-4. dyn_load.c
- This provides a routine that allows the collector to scan data
- segments associated with dynamic libraries. Often it is not
- necessary to provide this routine unless user-written dynamic
- libraries are used.
-
- For a different version of UN*X or different machines using the
-Motorola 68000, Vax, SPARC, 80386, NS 32000, PC/RT, or MIPS architecture,
-it should frequently suffice to change definitions in gcconfig.h.
-
+ For machines not already mentioned, or for nonstandard compilers,
+some porting suggestions are provided in the "porting.html" file.
THE C INTERFACE TO THE ALLOCATOR
The following routines are intended to be directly called by the user.
Note that usually only GC_malloc is necessary. GC_clear_roots and GC_add_roots
calls may be required if the collector has to trace from nonstandard places
-(e.g. from dynamic library data areas on a machine on which the
+(e.g. from dynamic library data areas on a machine on which the
collector doesn't already understand them.) On some machines, it may
-be desirable to set GC_stacktop to a good approximation of the stack base.
+be desirable to set GC_stacktop to a good approximation of the stack base.
(This enhances code portability on HP PA machines, since there is no
good way for the collector to compute this value.) Client code may include
"gc.h", which defines all of the following, plus many others.
@@ -384,17 +330,17 @@ good way for the collector to compute this value.) Client code may include
program startup.)
6) GC_malloc_ignore_off_page(bytes)
- - identical to GC_malloc, but the client promises to keep a pointer to
- the somewhere within the first 256 bytes of the object while it is
- live. (This pointer should nortmally be declared volatile to prevent
- interference from compiler optimizations.) This is the recommended
- way to allocate anything that is likely to be larger than 100Kbytes
- or so. (GC_malloc may result in failure to reclaim such objects.)
+ - identical to GC_malloc, but the client promises to keep a pointer to
+ the somewhere within the first 256 bytes of the object while it is
+ live. (This pointer should normally be declared volatile to prevent
+ interference from compiler optimizations.) This is the recommended
+ way to allocate anything that is likely to be larger than 100Kbytes
+ or so. (GC_malloc may result in failure to reclaim such objects.)
7) GC_set_warn_proc(proc)
- - Can be used to redirect warnings from the collector. Such warnings
- should be rare, and should not be ignored during code development.
-
+ - Can be used to redirect warnings from the collector. Such warnings
+ should be rare, and should not be ignored during code development.
+
8) GC_enable_incremental()
- Enables generational and incremental collection. Useful for large
heaps on machines that provide access to page dirty information.
@@ -406,13 +352,13 @@ good way for the collector to compute this value.) Client code may include
9) Several routines to allow for registration of finalization code.
User supplied finalization code may be invoked when an object becomes
unreachable. To call (*f)(obj, x) when obj becomes inaccessible, use
- GC_register_finalizer(obj, f, x, 0, 0);
+ GC_register_finalizer(obj, f, x, 0, 0);
For more sophisticated uses, and for finalization ordering issues,
see gc.h.
The global variable GC_free_space_divisor may be adjusted up from its
-default value of 4 to use less space and more collection time, or down for
-the opposite effect. Setting it to 1 or 0 will effectively disable collections
+default value of 3 to use less space and more collection time, or down for
+the opposite effect. Setting it to 1 will almost disable collections
and cause all allocations to simply grow the heap.
The variable GC_non_gc_bytes, which is normally 0, may be changed to reflect
@@ -422,7 +368,7 @@ in excessive memory consumption.
Some additional tuning is possible through the parameters defined
near the top of gc_priv.h.
-
+
If only GC_malloc is intended to be used, it might be appropriate to define:
#define malloc(n) GC_malloc(n)
@@ -448,44 +394,28 @@ See gc_cpp.h for the definition of the interface. This interface
tries to approximate the Ellis-Detlefs C++ garbage collection
proposal without compiler changes.
-Cautions:
-1. Arrays allocated without new placement syntax are
-allocated as uncollectable objects. They are traced by the
-collector, but will not be reclaimed.
-
-2. Failure to use "make c++" in combination with (1) will
-result in arrays allocated using the default new operator.
-This is likely to result in disaster without linker warnings.
-
-3. If your compiler supports an overloaded new[] operator,
-then gc_cpp.cc and gc_cpp.h should be suitably modified.
-
-4. Many current C++ compilers have deficiencies that
-break some of the functionality. See the comments in gc_cpp.h
-for suggested workarounds.
+ Very often it will also be necessary to use gc_allocator.h and the
+allocator declared there to construct STL data structures. Otherwise
+subobjects of STL data structures will be allocated using a system
+allocator, and objects they refer to may be prematurely collected.
USE AS LEAK DETECTOR:
The collector may be used to track down leaks in C programs that are
intended to run with malloc/free (e.g. code with extreme real-time or
-portability constraints). To do so define FIND_LEAK in Makefile
+portability constraints). To do so define FIND_LEAK in Makefile.
This will cause the collector to invoke the report_leak
routine defined near the top of reclaim.c whenever an inaccessible
object is found that has not been explicitly freed. Such objects will
also be automatically reclaimed.
- Productive use of this facility normally involves redefining report_leak
-to do something more intelligent. This typically requires annotating
-objects with additional information (e.g. creation time stack trace) that
-identifies their origin. Such code is typically not very portable, and is
-not included here, except on SPARC machines.
- If all objects are allocated with GC_DEBUG_MALLOC (see next section),
-then the default version of report_leak will report the source file
-and line number at which the leaked object was allocated. This may
-sometimes be sufficient. (On SPARC/SUNOS4 machines, it will also report
-a cryptic stack trace. This can often be turned into a sympolic stack
-trace by invoking program "foo" with "callprocs foo". Callprocs is
-a short shell script that invokes adb to expand program counter values
-to symbolic addresses. It was largely supplied by Scott Schwartz.)
+ If all objects are allocated with GC_DEBUG_MALLOC (see next section), then
+the default version of report_leak will report at least the source file and
+line number at which the leaked object was allocated. This may sometimes be
+sufficient. (On a few machines, it will also report a cryptic stack trace.
+If this is not symbolic, it can sometimes be called into a symbolic stack
+trace by invoking program "foo" with "tools/callprocs.sh foo". It is a short
+shell script that invokes adb to expand program counter values to symbolic
+addresses. It was largely supplied by Scott Schwartz.)
Note that the debugging facilities described in the next section can
sometimes be slightly LESS effective in leak finding mode, since in
leak finding mode, GC_debug_free actually results in reuse of the object.
@@ -508,8 +438,7 @@ collector is invoked while the object is live. The first deallocation
of an object will clear the debugging info associated with an
object, so accidentally repeated calls to GC_debug_free will report the
deallocation of an object without debugging information. Out of
-memory errors will be reported to stderr, in addition to returning
-NIL.
+memory errors will be reported to stderr, in addition to returning NULL.
GC_debug_malloc checking during garbage collection is enabled
with the first call to GC_debug_malloc. This will result in some
@@ -521,7 +450,7 @@ the debugger.
or GC_free, and conversely. It is however acceptable to allocate only
some objects with GC_debug_malloc, and to use GC_malloc for other objects,
provided the two pools are kept distinct. In this case, there is a very
-low probablility that GC_malloc allocated objects may be misidentified as
+low probability that GC_malloc allocated objects may be misidentified as
having been overwritten. This should happen with probability at most
one in 2**32. This probability is zero if GC_debug_malloc is never called.
@@ -545,7 +474,7 @@ in the header, see the definition of the type oh in debug_malloc.c)
INCREMENTAL/GENERATIONAL COLLECTION:
-The collector normally interrupts client code for the duration of
+The collector normally interrupts client code for the duration of
a garbage collection mark phase. This may be unacceptable if interactive
response is needed for programs with large heaps. The collector
can also run in a "generational" mode, in which it usually attempts to
@@ -587,14 +516,14 @@ objects. Stubborn objects are treated less efficiently than pointerfree
A rough rule of thumb is that, in the absence of VM information, garbage
collection pauses are proportional to the amount of pointerful storage
plus the amount of modified "stubborn" storage that is reachable during
-the collection.
+the collection.
Initial allocation of stubborn objects takes longer than allocation
of other objects, since other data structures need to be maintained.
We recommend against random use of stubborn objects in client
code, since bugs caused by inappropriate writes to stubborn objects
-are likely to be very infrequently observed and hard to trace.
+are likely to be very infrequently observed and hard to trace.
However, their use may be appropriate in a few carefully written
library routines that do not make the objects themselves available
for writing by client code.
@@ -607,16 +536,16 @@ reclaimed. Exclusive-or'ing forward and backward links in a list
doesn't cut it.
Some C optimizers may lose the last undisguised pointer to a memory
object as a consequence of clever optimizations. This has almost
-never been observed in practice. Send mail to boehm@acm.org
-for suggestions on how to fix your compiler.
+never been observed in practice.
This is not a real-time collector. In the standard configuration,
percentage of time required for collection should be constant across
heap sizes. But collection pauses will increase for larger heaps.
-(On SPARCstation 2s collection times will be on the order of 300 msecs
-per MB of accessible memory that needs to be scanned. Your mileage
-may vary.) The incremental/generational collection facility helps,
-but is portable only if "stubborn" allocation is used.
- Please address bug reports to boehm@acm.org. If you are
+They will decrease with the number of processors if parallel marking
+is enabled.
+(On 2007 vintage machines, GC times may be on the order of 5 msecs
+per MB of accessible memory that needs to be scanned and processor.
+Your mileage may vary.) The incremental/generational collection facility
+may help in some cases.
+ Please address bug reports to gc@linux.hpl.hp.com. If you are
contemplating a major addition, you might also send mail to ask whether
it's already been done (or whether we tried and discarded it).
-
diff --git a/boehm-gc/README.QUICK b/boehm-gc/README.QUICK
index 8294a87d9ea..30e6724564d 100644
--- a/boehm-gc/README.QUICK
+++ b/boehm-gc/README.QUICK
@@ -18,43 +18,47 @@ that appears not to significantly restrict use of the collector, though
use of those files for a purpose other than building the collector may
require the resulting code to be covered by the GPL.
-For more details and the names of other contributors, see the
-doc/README* files and include/gc.h. This file describes typical use of
-the collector on a machine that is already supported.
+For more details and the names of other contributors, see the README,
+doc/README.*, AUTHORS and include/gc.h files. These files describe typical
+use of the collector on a machine that is already supported.
-For the version number, see doc/README or version.h.
+For the version number, see README or include/gc_version.h files.
INSTALLATION:
Under UN*X, Linux:
Alternative 1 (the old way): type "make test" in this directory.
- Link against gc.a.
+ Link against gc.a. With the most recent GC distributions
+ you may have to type "make -f Makefile.direct test" or
+ copy Makefile.direct to Makefile first.
Alternative 2 (the new way): type
- "./configure --prefix=<dir>; make; make check; make install".
- Link against <dir>/lib/libgc.a or <dir>/lib/libgc.so.
- See README.autoconf for details
+ "./configure --prefix=<dir>; make; make check; make install".
+ Link against <dir>/lib/libgc.a or <dir>/lib/libgc.so.
+ See README.autoconf for details
-Under OS/2 or Windows 95, 98, Me, NT, or 2000:
+Under Windows 95, 98, Me, NT, or 2000:
copy the appropriate makefile to MAKEFILE, read it, and type "nmake test".
(Under Windows, this assumes you have Microsoft command-line tools
-installed, and have DOS configured with enough environment space to run them.)
-Read the machine specific README in the doc directory if one exists.
-The only way to develop code with the collector for Windows 3.1 is
-to develop under Windows NT or 95+, and then to use win32S.
-
-If you need thread support, you will need to either follow the special
-platform-dependent instructions (win32), or add a suitable define
-option as described in Makefile.
-
-If you wish to use the cord (structured string) library, type
-"make cords". (This requires an ANSI C compiler. You may need
-to redefine CC in the Makefile. The CORD_printf implementation in
-cordprnt.c is known to be less than perfectly portable. The rest
-of the package should still work.)
-
-If you wish to use the collector from C++, type
-"make c++". These add further files to gc.a and to the include
-subdirectory. See cord/cord.h and include/gc_cpp.h.
+installed, and suitably configured.)
+Read the machine specific README.XXX in the doc directory if one exists.
+
+If you need thread support, you will need to follow the special
+platform-dependent instructions (win32), or define GC_THREADS
+as described in doc/README.macros, or possibly use
+--enable-threads=posix when running the configure script.
+
+If you wish to use the cord (structured string) library with the stand-alone
+Makefile.direct, type "make cords", after copying to "Makefile".
+(This requires an ANSI C compiler. You may
+need to redefine CC in the Makefile. The CORD_printf implementation in
+cordprnt.c is known to be less than perfectly portable. The rest of the
+package should still work.)
+
+If you wish to use the collector from C++, type "make c++", or use
+--enable-cplusplus with the configure script. With Makefile.direct,
+these ones add further files to gc.a and to the include subdirectory.
+With the alternate build process,this generates libgccpp.
+See cord/cord.h and include/gc_cpp.h.
TYPICAL USE:
Include "gc.h" from the include subdirectory. Link against the
@@ -67,7 +71,7 @@ Define GC_DEBUG before including gc.h for additional checking.
More documentation on the collector interface can be found at
http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcinterface.html,
-in doc/README, and in include/gc.h .
+in README and other files in the doc directory, and in include/gc.h file.
WARNINGS:
@@ -82,4 +86,3 @@ accessed with pthread_getspecific()). The collector does scan
thread stacks though, so generally the best solution is to ensure that
any pointers stored in thread-local storage are also stored on the
thread's stack for the duration of their lifetime.
-
diff --git a/boehm-gc/SMakefile.amiga b/boehm-gc/SMakefile.amiga
index e2085051bbc..ebc8eae3bd1 100644
--- a/boehm-gc/SMakefile.amiga
+++ b/boehm-gc/SMakefile.amiga
@@ -19,14 +19,13 @@ MATHLIB=LIB:scm881.lib
#----------------COMPILER OPTIONS---------------------
-IGNORE= IGNORE=85 IGNORE=154 IGNORE=161 IGNORE=100
+IGNORE= IGNORE=85 IGNORE=154 IGNORE=161 IGNORE=100
OPTIMIZE=optimize optimizetime optglobal optimizerdepth=100 optimizerpeephole optloop OPTSCHED optimizerinlocal optimizerrecurdepth=100
# optimizerinline optimizercomplexity=100
OPT= $(OPTIMIZE) CPU=$(CPU) math=$(MATH) NOSTACKCHECK VERBOSE \
MAPHUNK NOVERSION NOICONS nodebug \
-DEFINE SILENT \
parm=reg \
DEFINE __USE_SYSBASE
@@ -45,7 +44,7 @@ DEFINE GC_AMIGA_GC
SCOPT= $(SOPT) define GC_AMIGA_MAKINGLIB
-CSCOPT= $(OPT) DEFINE AMIGA IGNORE=100 IGNORE=161
+CSCOPT= $(OPT) DEFINE AMIGA IGNORE=100 IGNORE=161
#------------------LINKING----------------------------
@@ -73,7 +72,7 @@ cord/cordtest: cord/cordtest.o cord/cord$(CPU).lib gc$(CPU).lib
#------------------LIBBING----------------------------
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o mallocx.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o mallocx.o fnlz_mlc.o
gc$(CPU).lib: $(OBJS)
$(LIBER) gc$(CPU).lib r $(OBJS)
@@ -100,7 +99,7 @@ allchblk.o : allchblk.c $(INC)
misc.o : misc.c $(INC)
$(CC) misc.c $(SCOPT)
-os_dep.o : os_dep.c $(INC) AmigaOS.c
+os_dep.o : os_dep.c $(INC) extra/AmigaOS.c
$(CC) os_dep.c $(SCOPT)
mark_rts.o : mark_rts.c $(INC)
@@ -133,6 +132,9 @@ dyn_load.o : dyn_load.c $(INC)
dbg_mlc.o : dbg_mlc.c $(INC)
$(CC) dbg_mlc.c $(SCOPT)
+fnlz_mlc.o : fnlz_mlc.c $(INC)
+ $(CC) fnlz_mlc.c $(SCOPT)
+
malloc.o : malloc.c $(INC)
$(CC) malloc.c $(SCOPT)
@@ -157,8 +159,8 @@ ptr_chck.o: ptr_chck.c $(INC)
test.o : test.c $(INC)
$(CC) test.c $(SOPT)
-setjmp_t: setjmp_t.c gc.h
- $(CC) setjmp_t.c $(SOPT)
+setjmp_t: tools/setjmp_t.c gc.h
+ $(CC) tools/setjmp_t.c $(SOPT)
# cords:
@@ -172,7 +174,5 @@ cord/cordprnt.o: cord/cordprnt.c
cord/cordxtra.o: cord/cordxtra.c
sc cord/cordxtra.c $(CSCOPT)
-cord/cordtest.o: cord/cordtest.c
- sc cord/cordtest.c $(CSCOPT)
-
-
+cord/cordtest.o: cord/tests/cordtest.c
+ sc cord/tests/cordtest.c $(CSCOPT)
diff --git a/boehm-gc/TODO b/boehm-gc/TODO
new file mode 100644
index 00000000000..d8a8b76de2d
--- /dev/null
+++ b/boehm-gc/TODO
@@ -0,0 +1,75 @@
+== TODO tasks ==
+
+tests/CMakeLists.txt: Add more executables (see tests.am).
+
+Use C++0x ATM (atomic memory operations) if available (either from the
+compiler runtime, provided it is reliable, or from the future libatomic_ops).
+
+Add a test for libatomic_ops minimal version required (at compile time).
+
+windows-untested: Remove if CMake can generate MS Visual Studio 6.0, 7.0, 8.0
+project files.
+
+BCC_MAKEFILE: Remove if CMake can generate Makefile for this compiler.
+(Same for WCC_MAKEFILE, OS2_MAKEFILE, NT_MAKEFILE, NT_STATIC_THREADS_MAKEFILE,
+NT_X64_STATIC_THREADS_MAKEFILE, NT_X64_THREADS_MAKEFILE, digimars.mak,
+gc.mak.)
+
+Makefile.dj: Remove if it is possible to use Makefile.direct (or
+auto-generated Makefile) instead. (Same for EMX_MAKEFILE.)
+
+build_atomic_ops.sh[.cygwin]: Remove if really not needed.
+
+BCC_MAKEFILE, EMX_MAKEFILE, OS2_MAKEFILE, PCR-Makefile, WCC_MAKEFILE,
+SMakefile.amiga, Makefile.dj, digimars.mak: move to "build" folder.
+
+Do type-punning via union (instead of pointer type cast) to enable safe
+'-fstrict-aliasing' compiler optimization option.
+
+Support CAN_HANDLE_FORK if USE_WINALLOC for Cygwin.
+
+Enable GC_set_handle_fork(1) for Darwin with GC_dirty_maintained on (both
+single and multi-threaded modes).
+
+Add more fields to GC_prof_stats_s (potential candidates are:
+requested_heapsize, max_large_allocd_bytes, large_allocd_bytes, bytes_dropped,
+bytes_finalized, bytes_freed, finalizer_bytes_freed, composite_in_use,
+atomic_in_use, GC_n_heap_sects, GC_n_memory, GC_black_list_spacing,
+GC_root_size, GC_max_root_size, n_root_sets, GC_total_stacksize,
+GC_collect_at_heapsize, GC_fail_count, GC_mark_stack_size, last_fo_entries,
+last_bytes_finalized, last_finalizer_notification_no, GC_dl_entries,
+GC_old_dl_entries, GC_used_heap_size_after_full, GC_total_stack_black_listed,
+signed_log_dl_table_size, GC_n_rescuing_pages, signed_log_fo_table_size,
+GC_excl_table_entries, GC_stack_last_cleared, GC_bytes_allocd_at_reset,
+GC_n_heap_bases, registered_threads_cnt, GC_max_thread_index, GC_block_count,
+GC_unlocked_count, GC_hdr_cache_hits, GC_hdr_cache_misses, GC_spin_count).
+
+
+== FIXME tasks ==
+
+Solaris + GCC: make check fails with the message:
+libc.so.1: gctest: fatal: libgcc_s.so.1: open failed: No such file or directory
+
+Solaris/x86[_64]: gctest fails if PROC_VDB.
+
+Darwin/x86_64: deadlock might occur between:
+dlclose() -> GC_dyld_image_remove() -> GC_lock() and
+GC_inner_start_routine()+LOCK -> dyld_stub_binder_().
+
+HP-UX 11.00 with the vendor cc fails:
+Perhaps GC_push_regs was configured incorrectly? FAIL: gctest.
+
+FreeBSD 9.0/x86_64 (gcc-4.2.1-20070831): gctest segfaults sometimes in
+GC_typed_mark_proc if configured with --enable-threads=pthreads.
+
+OpenBSD 5.1/i386: leaktest fails rarely (unless logging redirected to file):
+cannot write to stderr from GC_gcollect invoked from 'atexit' hook.
+
+NetBSD 5.1/x86: threadkey_test hangs sometimes.
+
+Cygwin: subthread_create: exception STATUS_ACCESS_VIOLATION.
+
+Cygwin: gctest: assertion failure at UNLOCK in GC_fork_parent_proc.
+
+Sun C++ 5.11: test_cpp.cc:237: Error: Too few arguments in call to
+"operator delete(void*, GCPlacement, extern "C" void(*)(void*,void*), void*)".
diff --git a/boehm-gc/WCC_MAKEFILE b/boehm-gc/WCC_MAKEFILE
index 32b01df1754..d1cca27afeb 100644
--- a/boehm-gc/WCC_MAKEFILE
+++ b/boehm-gc/WCC_MAKEFILE
@@ -25,7 +25,7 @@ CPU=5
OPTIM=-oneatx -s
#OPTIM=-ohneatx -s
-DEFS=-DALL_INTERIOR_POINTERS -DSILENT -DNO_SIGNALS #-DSMALL_CONFIG #-DGC_DEBUG
+DEFS=-DALL_INTERIOR_POINTERS #-DSMALL_CONFIG #-DGC_DEBUG
#####
@@ -76,7 +76,7 @@ OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj &
mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj &
obj_map.obj blacklst.obj finalize.obj new_hblk.obj &
dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj &
- typd_mlc.obj ptr_chck.obj mallocx.obj
+ typd_mlc.obj ptr_chck.obj mallocx.obj fnlz_mlc.obj
all: gc.lib gctest.exe test_cpp.exe
@@ -98,13 +98,13 @@ gc.dll: $(OBJS) .AUTODEPEND
@for %i in ($(OBJS)) do @%append $*.lnk file '%i'
!ifeq CALLING s
@%append $*.lnk export GC_is_marked
- @%append $*.lnk export GC_incr_words_allocd
- @%append $*.lnk export GC_incr_mem_freed
+ @%append $*.lnk export GC_incr_bytes_allocd
+ @%append $*.lnk export GC_incr_bytes_freed
@%append $*.lnk export GC_generic_malloc_words_small
!else
@%append $*.lnk export GC_is_marked_
- @%append $*.lnk export GC_incr_words_allocd_
- @%append $*.lnk export GC_incr_mem_freed_
+ @%append $*.lnk export GC_incr_bytes_allocd_
+ @%append $*.lnk export GC_incr_bytes_freed_
@%append $*.lnk export GC_generic_malloc_words_small_
!endif
*wlink @$*.lnk
@@ -156,12 +156,12 @@ test_cpp.exe: test_cpp.obj gc.lib
@%append $*.lnk library gc.lib
!ifdef MAKE_AS_DLL
!ifeq CALLING s
- @%append $*.lnk import GC_incr_words_allocd gc
- @%append $*.lnk import GC_incr_mem_freed gc
+ @%append $*.lnk import GC_incr_bytes_allocd gc
+ @%append $*.lnk import GC_incr_bytes_freed gc
@%append $*.lnk import GC_generic_malloc_words_small gc
!else
- @%append $*.lnk import GC_incr_words_allocd_ gc
- @%append $*.lnk import GC_incr_mem_freed_ gc
+ @%append $*.lnk import GC_incr_bytes_allocd_ gc
+ @%append $*.lnk import GC_incr_bytes_freed_ gc
@%append $*.lnk import GC_generic_malloc_words_small_ gc
!endif
!endif
diff --git a/boehm-gc/aclocal.m4 b/boehm-gc/aclocal.m4
deleted file mode 100644
index ca95db121f0..00000000000
--- a/boehm-gc/aclocal.m4
+++ /dev/null
@@ -1,4369 +0,0 @@
-# aclocal.m4 generated automatically by aclocal 1.6.3 -*- Autoconf -*-
-
-# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
-# Free Software Foundation, Inc.
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-#
-#
-# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-#
-# Permission is hereby granted to use or copy this program
-# for any purpose, provided the above notices are retained on all copies.
-# Permission to modify the code and to distribute modified code is granted,
-# provided the above notices are retained, and a notice that the code was
-# modified is included with the above copyright notice.
-#
-# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
-
-# GC_SET_VERSION
-# sets and AC_DEFINEs GC_VERSION_MAJOR, GC_VERSION_MINOR and GC_ALPHA_VERSION
-# based on the contents of PACKAGE_VERSION; PACKAGE_VERSION must conform to
-# [0-9]+[.][0-9]+(alpha[0.9]+)?
-# in lex syntax; if there is no alpha number, GC_ALPHA_VERSION is empty
-#
-AC_DEFUN(GC_SET_VERSION, [
- AC_MSG_CHECKING(GC version numbers)
- GC_VERSION_MAJOR=`echo $PACKAGE_VERSION | sed 's/^\([[0-9]][[0-9]]*\)[[.]].*$/\1/g'`
- GC_VERSION_MINOR=`echo $PACKAGE_VERSION | sed 's/^[[^.]]*[[.]]\([[0-9]][[0-9]]*\).*$/\1/g'`
- GC_ALPHA_VERSION=`echo $PACKAGE_VERSION | sed 's/^[[^.]]*[[.]][[0-9]]*//'`
-
- case "$GC_ALPHA_VERSION" in
- alpha*)
- GC_ALPHA_VERSION=`echo $GC_ALPHA_VERSION \
- | sed 's/alpha\([[0-9]][[0-9]]*\)/\1/'` ;;
- *) GC_ALPHA_MAJOR='' ;;
- esac
-
- if test :$GC_VERSION_MAJOR: = :: \
- -o :$GC_VERSION_MINOR: = :: ;
- then
- AC_MSG_RESULT(invalid)
- AC_MSG_ERROR([nonconforming PACKAGE_VERSION='$PACKAGE_VERSION'])
- fi
-
- AC_DEFINE_UNQUOTED(GC_VERSION_MAJOR, $GC_VERSION_MAJOR)
- AC_DEFINE_UNQUOTED(GC_VERSION_MINOR, $GC_VERSION_MINOR)
- if test :$GC_ALPHA_VERSION: != :: ; then
- AC_DEFINE_UNQUOTED(GC_ALPHA_VERSION, $GC_ALPHA_VERSION)
- fi
- AC_MSG_RESULT(major=$GC_VERSION_MAJOR minor=$GC_VERSION_MINOR \
-${GC_ALPHA_VERSION:+alpha=}$GC_ALPHA_VERSION)
-])
-
-sinclude(libtool.m4)
-
-# Do all the work for Automake. -*- Autoconf -*-
-
-# This macro actually does too much some checks are only needed if
-# your package does certain things. But this isn't really a big deal.
-
-# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
-# Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# serial 8
-
-# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
-# written in clear, in which case automake, when reading aclocal.m4,
-# will think it sees a *use*, and therefore will trigger all it's
-# C support machinery. Also note that it means that autoscan, seeing
-# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
-
-
-AC_PREREQ([2.52])
-
-# Autoconf 2.50 wants to disallow AM_ names. We explicitly allow
-# the ones we care about.
-m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
-
-# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
-# AM_INIT_AUTOMAKE([OPTIONS])
-# -----------------------------------------------
-# The call with PACKAGE and VERSION arguments is the old style
-# call (pre autoconf-2.50), which is being phased out. PACKAGE
-# and VERSION should now be passed to AC_INIT and removed from
-# the call to AM_INIT_AUTOMAKE.
-# We support both call styles for the transition. After
-# the next Automake release, Autoconf can make the AC_INIT
-# arguments mandatory, and then we can depend on a new Autoconf
-# release and drop the old call support.
-AC_DEFUN([AM_INIT_AUTOMAKE],
-[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
- AC_REQUIRE([AC_PROG_INSTALL])dnl
-# test to see if srcdir already configured
-if test "`cd $srcdir && pwd`" != "`pwd`" &&
- test -f $srcdir/config.status; then
- AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
-fi
-
-# Define the identity of the package.
-dnl Distinguish between old-style and new-style calls.
-m4_ifval([$2],
-[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
- AC_SUBST([PACKAGE], [$1])dnl
- AC_SUBST([VERSION], [$2])],
-[_AM_SET_OPTIONS([$1])dnl
- AC_SUBST([PACKAGE], [AC_PACKAGE_TARNAME])dnl
- AC_SUBST([VERSION], [AC_PACKAGE_VERSION])])dnl
-
-_AM_IF_OPTION([no-define],,
-[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
- AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
-
-# Some tools Automake needs.
-AC_REQUIRE([AM_SANITY_CHECK])dnl
-AC_REQUIRE([AC_ARG_PROGRAM])dnl
-AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
-AM_MISSING_PROG(AUTOCONF, autoconf)
-AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
-AM_MISSING_PROG(AUTOHEADER, autoheader)
-AM_MISSING_PROG(MAKEINFO, makeinfo)
-AM_MISSING_PROG(AMTAR, tar)
-AM_PROG_INSTALL_SH
-AM_PROG_INSTALL_STRIP
-# We need awk for the "check" target. The system "awk" is bad on
-# some platforms.
-AC_REQUIRE([AC_PROG_AWK])dnl
-AC_REQUIRE([AC_PROG_MAKE_SET])dnl
-
-_AM_IF_OPTION([no-dependencies],,
-[AC_PROVIDE_IFELSE([AC_PROG_][CC],
- [_AM_DEPENDENCIES(CC)],
- [define([AC_PROG_][CC],
- defn([AC_PROG_][CC])[_AM_DEPENDENCIES(CC)])])dnl
-AC_PROVIDE_IFELSE([AC_PROG_][CXX],
- [_AM_DEPENDENCIES(CXX)],
- [define([AC_PROG_][CXX],
- defn([AC_PROG_][CXX])[_AM_DEPENDENCIES(CXX)])])dnl
-])
-])
-
-# Copyright 2002 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-
-# AM_AUTOMAKE_VERSION(VERSION)
-# ----------------------------
-# Automake X.Y traces this macro to ensure aclocal.m4 has been
-# generated from the m4 files accompanying Automake X.Y.
-AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.6"])
-
-# AM_SET_CURRENT_AUTOMAKE_VERSION
-# -------------------------------
-# Call AM_AUTOMAKE_VERSION so it can be traced.
-# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
-AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
- [AM_AUTOMAKE_VERSION([1.6.3])])
-
-# Helper functions for option handling. -*- Autoconf -*-
-
-# Copyright 2001, 2002 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# serial 2
-
-# _AM_MANGLE_OPTION(NAME)
-# -----------------------
-AC_DEFUN([_AM_MANGLE_OPTION],
-[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
-
-# _AM_SET_OPTION(NAME)
-# ------------------------------
-# Set option NAME. Presently that only means defining a flag for this option.
-AC_DEFUN([_AM_SET_OPTION],
-[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
-
-# _AM_SET_OPTIONS(OPTIONS)
-# ----------------------------------
-# OPTIONS is a space-separated list of Automake options.
-AC_DEFUN([_AM_SET_OPTIONS],
-[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
-
-# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
-# -------------------------------------------
-# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
-AC_DEFUN([_AM_IF_OPTION],
-[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
-
-#
-# Check to make sure that the build environment is sane.
-#
-
-# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# serial 3
-
-# AM_SANITY_CHECK
-# ---------------
-AC_DEFUN([AM_SANITY_CHECK],
-[AC_MSG_CHECKING([whether build environment is sane])
-# Just in case
-sleep 1
-echo timestamp > conftest.file
-# Do `set' in a subshell so we don't clobber the current shell's
-# arguments. Must try -L first in case configure is actually a
-# symlink; some systems play weird games with the mod time of symlinks
-# (eg FreeBSD returns the mod time of the symlink's containing
-# directory).
-if (
- set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
- if test "$[*]" = "X"; then
- # -L didn't work.
- set X `ls -t $srcdir/configure conftest.file`
- fi
- rm -f conftest.file
- if test "$[*]" != "X $srcdir/configure conftest.file" \
- && test "$[*]" != "X conftest.file $srcdir/configure"; then
-
- # If neither matched, then we have a broken ls. This can happen
- # if, for instance, CONFIG_SHELL is bash and it inherits a
- # broken ls alias from the environment. This has actually
- # happened. Such a system could not be considered "sane".
- AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
-alias in your environment])
- fi
-
- test "$[2]" = conftest.file
- )
-then
- # Ok.
- :
-else
- AC_MSG_ERROR([newly created file is older than distributed files!
-Check your system clock])
-fi
-AC_MSG_RESULT(yes)])
-
-# -*- Autoconf -*-
-
-
-# Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# serial 3
-
-# AM_MISSING_PROG(NAME, PROGRAM)
-# ------------------------------
-AC_DEFUN([AM_MISSING_PROG],
-[AC_REQUIRE([AM_MISSING_HAS_RUN])
-$1=${$1-"${am_missing_run}$2"}
-AC_SUBST($1)])
-
-
-# AM_MISSING_HAS_RUN
-# ------------------
-# Define MISSING if not defined so far and test if it supports --run.
-# If it does, set am_missing_run to use it, otherwise, to nothing.
-AC_DEFUN([AM_MISSING_HAS_RUN],
-[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
-# Use eval to expand $SHELL
-if eval "$MISSING --run true"; then
- am_missing_run="$MISSING --run "
-else
- am_missing_run=
- AC_MSG_WARN([`missing' script is too old or missing])
-fi
-])
-
-# AM_AUX_DIR_EXPAND
-
-# Copyright 2001 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
-# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
-# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
-#
-# Of course, Automake must honor this variable whenever it calls a
-# tool from the auxiliary directory. The problem is that $srcdir (and
-# therefore $ac_aux_dir as well) can be either absolute or relative,
-# depending on how configure is run. This is pretty annoying, since
-# it makes $ac_aux_dir quite unusable in subdirectories: in the top
-# source directory, any form will work fine, but in subdirectories a
-# relative path needs to be adjusted first.
-#
-# $ac_aux_dir/missing
-# fails when called from a subdirectory if $ac_aux_dir is relative
-# $top_srcdir/$ac_aux_dir/missing
-# fails if $ac_aux_dir is absolute,
-# fails when called from a subdirectory in a VPATH build with
-# a relative $ac_aux_dir
-#
-# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
-# are both prefixed by $srcdir. In an in-source build this is usually
-# harmless because $srcdir is `.', but things will broke when you
-# start a VPATH build or use an absolute $srcdir.
-#
-# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
-# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
-# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
-# and then we would define $MISSING as
-# MISSING="\${SHELL} $am_aux_dir/missing"
-# This will work as long as MISSING is not called from configure, because
-# unfortunately $(top_srcdir) has no meaning in configure.
-# However there are other variables, like CC, which are often used in
-# configure, and could therefore not use this "fixed" $ac_aux_dir.
-#
-# Another solution, used here, is to always expand $ac_aux_dir to an
-# absolute PATH. The drawback is that using absolute paths prevent a
-# configured tree to be moved without reconfiguration.
-
-# Rely on autoconf to set up CDPATH properly.
-AC_PREREQ([2.50])
-
-AC_DEFUN([AM_AUX_DIR_EXPAND], [
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
-])
-
-# AM_PROG_INSTALL_SH
-# ------------------
-# Define $install_sh.
-
-# Copyright 2001 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-AC_DEFUN([AM_PROG_INSTALL_SH],
-[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-install_sh=${install_sh-"$am_aux_dir/install-sh"}
-AC_SUBST(install_sh)])
-
-# AM_PROG_INSTALL_STRIP
-
-# Copyright 2001 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# One issue with vendor `install' (even GNU) is that you can't
-# specify the program used to strip binaries. This is especially
-# annoying in cross-compiling environments, where the build's strip
-# is unlikely to handle the host's binaries.
-# Fortunately install-sh will honor a STRIPPROG variable, so we
-# always use install-sh in `make install-strip', and initialize
-# STRIPPROG with the value of the STRIP variable (set by the user).
-AC_DEFUN([AM_PROG_INSTALL_STRIP],
-[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
-# Installed binaries are usually stripped using `strip' when the user
-# run `make install-strip'. However `strip' might not be the right
-# tool to use in cross-compilation environments, therefore Automake
-# will honor the `STRIP' environment variable to overrule this program.
-dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
-if test "$cross_compiling" != no; then
- AC_CHECK_TOOL([STRIP], [strip], :)
-fi
-INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
-AC_SUBST([INSTALL_STRIP_PROGRAM])])
-
-# serial 4 -*- Autoconf -*-
-
-# Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-
-# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
-# written in clear, in which case automake, when reading aclocal.m4,
-# will think it sees a *use*, and therefore will trigger all it's
-# C support machinery. Also note that it means that autoscan, seeing
-# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
-
-
-
-# _AM_DEPENDENCIES(NAME)
-# ----------------------
-# See how the compiler implements dependency checking.
-# NAME is "CC", "CXX", "GCJ", or "OBJC".
-# We try a few techniques and use that to set a single cache variable.
-#
-# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
-# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
-# dependency, and given that the user is not expected to run this macro,
-# just rely on AC_PROG_CC.
-AC_DEFUN([_AM_DEPENDENCIES],
-[AC_REQUIRE([AM_SET_DEPDIR])dnl
-AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
-AC_REQUIRE([AM_MAKE_INCLUDE])dnl
-AC_REQUIRE([AM_DEP_TRACK])dnl
-
-ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
- [$1], CXX, [depcc="$CXX" am_compiler_list=],
- [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
- [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
- [depcc="$$1" am_compiler_list=])
-
-AC_CACHE_CHECK([dependency style of $depcc],
- [am_cv_$1_dependencies_compiler_type],
-[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
- # We make a subdir and do the tests there. Otherwise we can end up
- # making bogus files that we don't know about and never remove. For
- # instance it was reported that on HP-UX the gcc test will end up
- # making a dummy file named `D' -- because `-MD' means `put the output
- # in D'.
- mkdir conftest.dir
- # Copy depcomp to subdir because otherwise we won't find it if we're
- # using a relative directory.
- cp "$am_depcomp" conftest.dir
- cd conftest.dir
-
- am_cv_$1_dependencies_compiler_type=none
- if test "$am_compiler_list" = ""; then
- am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
- fi
- for depmode in $am_compiler_list; do
- # We need to recreate these files for each test, as the compiler may
- # overwrite some of them when testing with obscure command lines.
- # This happens at least with the AIX C compiler.
- echo '#include "conftest.h"' > conftest.c
- echo 'int i;' > conftest.h
- echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf
-
- case $depmode in
- nosideeffect)
- # after this tag, mechanisms are not by side-effect, so they'll
- # only be used when explicitly requested
- if test "x$enable_dependency_tracking" = xyes; then
- continue
- else
- break
- fi
- ;;
- none) break ;;
- esac
- # We check with `-c' and `-o' for the sake of the "dashmstdout"
- # mode. It turns out that the SunPro C++ compiler does not properly
- # handle `-M -o', and we need to detect this.
- if depmode=$depmode \
- source=conftest.c object=conftest.o \
- depfile=conftest.Po tmpdepfile=conftest.TPo \
- $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 &&
- grep conftest.h conftest.Po > /dev/null 2>&1 &&
- ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
- am_cv_$1_dependencies_compiler_type=$depmode
- break
- fi
- done
-
- cd ..
- rm -rf conftest.dir
-else
- am_cv_$1_dependencies_compiler_type=none
-fi
-])
-AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
-])
-
-
-# AM_SET_DEPDIR
-# -------------
-# Choose a directory name for dependency files.
-# This macro is AC_REQUIREd in _AM_DEPENDENCIES
-AC_DEFUN([AM_SET_DEPDIR],
-[rm -f .deps 2>/dev/null
-mkdir .deps 2>/dev/null
-if test -d .deps; then
- DEPDIR=.deps
-else
- # MS-DOS does not allow filenames that begin with a dot.
- DEPDIR=_deps
-fi
-rmdir .deps 2>/dev/null
-AC_SUBST([DEPDIR])
-])
-
-
-# AM_DEP_TRACK
-# ------------
-AC_DEFUN([AM_DEP_TRACK],
-[AC_ARG_ENABLE(dependency-tracking,
-[ --disable-dependency-tracking Speeds up one-time builds
- --enable-dependency-tracking Do not reject slow dependency extractors])
-if test "x$enable_dependency_tracking" != xno; then
- am_depcomp="$ac_aux_dir/depcomp"
- AMDEPBACKSLASH='\'
-fi
-AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
-AC_SUBST([AMDEPBACKSLASH])
-])
-
-# Generate code to set up dependency tracking. -*- Autoconf -*-
-
-# Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-#serial 2
-
-# _AM_OUTPUT_DEPENDENCY_COMMANDS
-# ------------------------------
-AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
-[for mf in $CONFIG_FILES; do
- # Strip MF so we end up with the name of the file.
- mf=`echo "$mf" | sed -e 's/:.*$//'`
- # Check whether this is an Automake generated Makefile or not.
- # We used to match only the files named `Makefile.in', but
- # some people rename them; so instead we look at the file content.
- # Grep'ing the first line is not enough: some people post-process
- # each Makefile.in and add a new line on top of each file to say so.
- # So let's grep whole file.
- if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
- dirpart=`AS_DIRNAME("$mf")`
- else
- continue
- fi
- grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue
- # Extract the definition of DEP_FILES from the Makefile without
- # running `make'.
- DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"`
- test -z "$DEPDIR" && continue
- # When using ansi2knr, U may be empty or an underscore; expand it
- U=`sed -n -e '/^U = / s///p' < "$mf"`
- test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR"
- # We invoke sed twice because it is the simplest approach to
- # changing $(DEPDIR) to its actual value in the expansion.
- for file in `sed -n -e '
- /^DEP_FILES = .*\\\\$/ {
- s/^DEP_FILES = //
- :loop
- s/\\\\$//
- p
- n
- /\\\\$/ b loop
- p
- }
- /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \
- sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
- # Make sure the directory exists.
- test -f "$dirpart/$file" && continue
- fdir=`AS_DIRNAME(["$file"])`
- AS_MKDIR_P([$dirpart/$fdir])
- # echo "creating $dirpart/$file"
- echo '# dummy' > "$dirpart/$file"
- done
-done
-])# _AM_OUTPUT_DEPENDENCY_COMMANDS
-
-
-# AM_OUTPUT_DEPENDENCY_COMMANDS
-# -----------------------------
-# This macro should only be invoked once -- use via AC_REQUIRE.
-#
-# This code is only required when automatic dependency tracking
-# is enabled. FIXME. This creates each `.P' file that we will
-# need in order to bootstrap the dependency handling code.
-AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
-[AC_CONFIG_COMMANDS([depfiles],
- [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
- [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
-])
-
-# Copyright 2001 Free Software Foundation, Inc. -*- Autoconf -*-
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# serial 2
-
-# AM_MAKE_INCLUDE()
-# -----------------
-# Check to see how make treats includes.
-AC_DEFUN([AM_MAKE_INCLUDE],
-[am_make=${MAKE-make}
-cat > confinc << 'END'
-doit:
- @echo done
-END
-# If we don't find an include directive, just comment out the code.
-AC_MSG_CHECKING([for style of include used by $am_make])
-am__include="#"
-am__quote=
-_am_result=none
-# First try GNU make style include.
-echo "include confinc" > confmf
-# We grep out `Entering directory' and `Leaving directory'
-# messages which can occur if `w' ends up in MAKEFLAGS.
-# In particular we don't look at `^make:' because GNU make might
-# be invoked under some other name (usually "gmake"), in which
-# case it prints its new name instead of `make'.
-if test "`$am_make -s -f confmf 2> /dev/null | fgrep -v 'ing directory'`" = "done"; then
- am__include=include
- am__quote=
- _am_result=GNU
-fi
-# Now try BSD make style include.
-if test "$am__include" = "#"; then
- echo '.include "confinc"' > confmf
- if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
- am__include=.include
- am__quote="\""
- _am_result=BSD
- fi
-fi
-AC_SUBST(am__include)
-AC_SUBST(am__quote)
-AC_MSG_RESULT($_am_result)
-rm -f confinc confmf
-])
-
-# AM_CONDITIONAL -*- Autoconf -*-
-
-# Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# serial 5
-
-AC_PREREQ(2.52)
-
-# AM_CONDITIONAL(NAME, SHELL-CONDITION)
-# -------------------------------------
-# Define a conditional.
-AC_DEFUN([AM_CONDITIONAL],
-[ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
- [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
-AC_SUBST([$1_TRUE])
-AC_SUBST([$1_FALSE])
-if $2; then
- $1_TRUE=
- $1_FALSE='#'
-else
- $1_TRUE='#'
- $1_FALSE=
-fi
-AC_CONFIG_COMMANDS_PRE(
-[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
- AC_MSG_ERROR([conditional \"$1\" was never defined.
-Usually this means the macro was only invoked conditionally.])
-fi])])
-
-# Figure out how to run the assembler. -*- Autoconf -*-
-
-# serial 2
-
-# Copyright 2001 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# AM_PROG_AS
-# ----------
-AC_DEFUN([AM_PROG_AS],
-[# By default we simply use the C compiler to build assembly code.
-AC_REQUIRE([AC_PROG_CC])
-: ${CCAS='$(CC)'}
-# Set ASFLAGS if not already set.
-: ${CCASFLAGS='$(CFLAGS)'}
-AC_SUBST(CCAS)
-AC_SUBST(CCASFLAGS)])
-
-# Add --enable-maintainer-mode option to configure.
-# From Jim Meyering
-
-# Copyright 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-# serial 1
-
-AC_DEFUN([AM_MAINTAINER_MODE],
-[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
- dnl maintainer-mode is disabled by default
- AC_ARG_ENABLE(maintainer-mode,
-[ --enable-maintainer-mode enable make rules and dependencies not useful
- (and sometimes confusing) to the casual installer],
- USE_MAINTAINER_MODE=$enableval,
- USE_MAINTAINER_MODE=no)
- AC_MSG_RESULT([$USE_MAINTAINER_MODE])
- AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
- MAINT=$MAINTAINER_MODE_TRUE
- AC_SUBST(MAINT)dnl
-]
-)
-
-# libtool.m4 - Configure libtool for the host system. -*-Shell-script-*-
-
-# serial 46 AC_PROG_LIBTOOL
-
-AC_DEFUN([AC_PROG_LIBTOOL],
-[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-AC_SUBST(LIBTOOL)dnl
-
-# Prevent multiple expansion
-define([AC_PROG_LIBTOOL], [])
-])
-
-AC_DEFUN([AC_LIBTOOL_SETUP],
-[AC_PREREQ(2.13)dnl
-AC_REQUIRE([AC_ENABLE_SHARED])dnl
-AC_REQUIRE([AC_ENABLE_STATIC])dnl
-AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_PROG_LD])dnl
-AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
-AC_REQUIRE([AC_PROG_NM])dnl
-AC_REQUIRE([AC_PROG_LN_S])dnl
-AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
-AC_REQUIRE([AC_OBJEXT])dnl
-AC_REQUIRE([AC_EXEEXT])dnl
-dnl
-
-_LT_AC_PROG_ECHO_BACKSLASH
-# Only perform the check for file, if the check method requires it
-case $deplibs_check_method in
-file_magic*)
- if test "$file_magic_cmd" = '$MAGIC_CMD'; then
- AC_PATH_MAGIC
- fi
- ;;
-esac
-
-AC_CHECK_TOOL(RANLIB, ranlib, :)
-AC_CHECK_TOOL(STRIP, strip, :)
-
-ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
-ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
-enable_win32_dll=yes, enable_win32_dll=no)
-
-AC_ARG_ENABLE(libtool-lock,
- [ --disable-libtool-lock avoid locking (might break parallel builds)])
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-*-*-irix6*)
- # Find out which ABI we are using.
- echo '[#]line __oline__ "configure"' > conftest.$ac_ext
- if AC_TRY_EVAL(ac_compile); then
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -32"
- ;;
- *N32*)
- LD="${LD-ld} -n32"
- ;;
- *64-bit*)
- LD="${LD-ld} -64"
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-
-*-*-sco3.2v5*)
- # On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -belf"
- AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
- [AC_LANG_SAVE
- AC_LANG_C
- AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
- AC_LANG_RESTORE])
- if test x"$lt_cv_cc_needs_belf" != x"yes"; then
- # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
- CFLAGS="$SAVE_CFLAGS"
- fi
- ;;
-
-ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
-[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
- AC_CHECK_TOOL(DLLTOOL, dlltool, false)
- AC_CHECK_TOOL(AS, as, false)
- AC_CHECK_TOOL(OBJDUMP, objdump, false)
-
- # recent cygwin and mingw systems supply a stub DllMain which the user
- # can override, but on older systems we have to supply one
- AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain,
- [AC_TRY_LINK([],
- [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*);
- DllMain (0, 0, 0);],
- [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])])
-
- case $host/$CC in
- *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*)
- # old mingw systems require "-dll" to link a DLL, while more recent ones
- # require "-mdll"
- SAVE_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -mdll"
- AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch,
- [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])])
- CFLAGS="$SAVE_CFLAGS" ;;
- *-*-cygwin* | *-*-pw32*)
- # cygwin systems need to pass --dll to the linker, and not link
- # crt.o which will require a WinMain@16 definition.
- lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;;
- esac
- ;;
- ])
-esac
-
-_LT_AC_LTCONFIG_HACK
-
-])
-
-# AC_LIBTOOL_HEADER_ASSERT
-# ------------------------
-AC_DEFUN([AC_LIBTOOL_HEADER_ASSERT],
-[AC_CACHE_CHECK([whether $CC supports assert without backlinking],
- [lt_cv_func_assert_works],
- [case $host in
- *-*-solaris*)
- if test "$GCC" = yes && test "$with_gnu_ld" != yes; then
- case `$CC --version 2>/dev/null` in
- [[12]].*) lt_cv_func_assert_works=no ;;
- *) lt_cv_func_assert_works=yes ;;
- esac
- fi
- ;;
- esac])
-
-if test "x$lt_cv_func_assert_works" = xyes; then
- AC_CHECK_HEADERS(assert.h)
-fi
-])# AC_LIBTOOL_HEADER_ASSERT
-
-# _LT_AC_CHECK_DLFCN
-# --------------------
-AC_DEFUN([_LT_AC_CHECK_DLFCN],
-[AC_CHECK_HEADERS(dlfcn.h)
-])# _LT_AC_CHECK_DLFCN
-
-# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
-# ---------------------------------
-AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
-[AC_REQUIRE([AC_CANONICAL_HOST])
-AC_REQUIRE([AC_PROG_NM])
-AC_REQUIRE([AC_OBJEXT])
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-AC_MSG_CHECKING([command to parse $NM output])
-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [dnl
-
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix. What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[[BCDEGRST]]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
-
-# Transform the above into a raw symbol and a C symbol.
-symxfrm='\1 \2\3 \3'
-
-# Transform an extracted symbol line into a proper C declaration
-lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'"
-
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
-
-# Define system-specific variables.
-case $host_os in
-aix*)
- symcode='[[BCDT]]'
- ;;
-cygwin* | mingw* | pw32*)
- symcode='[[ABCDGISTW]]'
- ;;
-hpux*) # Its linker distinguishes data from code symbols
- lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
- lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
- ;;
-irix*)
- symcode='[[BCDEGRST]]'
- ;;
-solaris* | sysv5*)
- symcode='[[BDT]]'
- ;;
-sysv4)
- symcode='[[DFNSTU]]'
- ;;
-esac
-
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $host_os in
-mingw*)
- opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
- ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
- symcode='[[ABCDGISTW]]'
-fi
-
-# Try without a prefix undercore, then with it.
-for ac_symprfx in "" "_"; do
-
- # Write the raw and C identifiers.
-lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
-
- # Check to see that the pipe works correctly.
- pipe_works=no
- rm -f conftest*
- cat > conftest.$ac_ext <<EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-EOF
-
- if AC_TRY_EVAL(ac_compile); then
- # Now try to grab the symbols.
- nlist=conftest.nm
- if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
- # Try sorting and uniquifying the output.
- if sort "$nlist" | uniq > "$nlist"T; then
- mv -f "$nlist"T "$nlist"
- else
- rm -f "$nlist"T
- fi
-
- # Make sure that we snagged all the symbols we need.
- if egrep ' nm_test_var$' "$nlist" >/dev/null; then
- if egrep ' nm_test_func$' "$nlist" >/dev/null; then
- cat <<EOF > conftest.$ac_ext
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-EOF
- # Now generate the symbol file.
- eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext'
-
- cat <<EOF >> conftest.$ac_ext
-#if defined (__STDC__) && __STDC__
-# define lt_ptr void *
-#else
-# define lt_ptr char *
-# define const
-#endif
-
-/* The mapping between symbol names and symbols. */
-const struct {
- const char *name;
- lt_ptr address;
-}
-lt_preloaded_symbols[[]] =
-{
-EOF
- sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr) \&\2},/" < "$nlist" >> conftest.$ac_ext
- cat <<\EOF >> conftest.$ac_ext
- {0, (lt_ptr) 0}
-};
-
-#ifdef __cplusplus
-}
-#endif
-EOF
- # Now try linking the two files.
- mv conftest.$ac_objext conftstm.$ac_objext
- save_LIBS="$LIBS"
- save_CFLAGS="$CFLAGS"
- LIBS="conftstm.$ac_objext"
- CFLAGS="$CFLAGS$no_builtin_flag"
- if AC_TRY_EVAL(ac_link) && test -s conftest; then
- pipe_works=yes
- fi
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
- else
- echo "cannot find nm_test_func in $nlist" >&AC_FD_CC
- fi
- else
- echo "cannot find nm_test_var in $nlist" >&AC_FD_CC
- fi
- else
- echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC
- fi
- else
- echo "$progname: failed program was:" >&AC_FD_CC
- cat conftest.$ac_ext >&5
- fi
- rm -f conftest* conftst*
-
- # Do not use the global_symbol_pipe unless it works.
- if test "$pipe_works" = yes; then
- break
- else
- lt_cv_sys_global_symbol_pipe=
- fi
-done
-])
-global_symbol_pipe="$lt_cv_sys_global_symbol_pipe"
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
- global_symbol_to_cdecl=
- global_symbol_to_c_name_address=
-else
- global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl"
- global_symbol_to_c_name_address="$lt_cv_global_symbol_to_c_name_address"
-fi
-if test -z "$global_symbol_pipe$global_symbol_to_cdec$global_symbol_to_c_name_address";
-then
- AC_MSG_RESULT(failed)
-else
- AC_MSG_RESULT(ok)
-fi
-]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
-
-# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR
-# ---------------------------------
-AC_DEFUN([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR],
-[# Find the correct PATH separator. Usually this is `:', but
-# DJGPP uses `;' like DOS.
-if test "X${PATH_SEPARATOR+set}" != Xset; then
- UNAME=${UNAME-`uname 2>/dev/null`}
- case X$UNAME in
- *-DOS) lt_cv_sys_path_separator=';' ;;
- *) lt_cv_sys_path_separator=':' ;;
- esac
- PATH_SEPARATOR=$lt_cv_sys_path_separator
-fi
-])# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR
-
-# _LT_AC_PROG_ECHO_BACKSLASH
-# --------------------------
-# Add some code to the start of the generated configure script which
-# will find an echo command which doesn't interpret backslashes.
-AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
-[ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
- [AC_DIVERT_PUSH(NOTICE)])
-_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR
-
-# Check that we are running under the correct shell.
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-case X$ECHO in
-X*--fallback-echo)
- # Remove one level of quotation (which was required for Make).
- ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
- ;;
-esac
-
-echo=${ECHO-echo}
-if test "X[$]1" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
-elif test "X[$]1" = X--fallback-echo; then
- # Avoid inline document here, it may be left over
- :
-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
- # Yippee, $echo works!
- :
-else
- # Restart under the correct shell.
- exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
-fi
-
-if test "X[$]1" = X--fallback-echo; then
- # used as fallback echo
- shift
- cat <<EOF
-$*
-EOF
- exit 0
-fi
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
-
-if test -z "$ECHO"; then
-if test "X${echo_test_string+set}" != Xset; then
-# find a string as large as possible, as long as the shell can cope with it
- for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
- # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
- if (echo_test_string="`eval $cmd`") 2>/dev/null &&
- echo_test_string="`eval $cmd`" &&
- (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
- then
- break
- fi
- done
-fi
-
-if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- :
-else
- # The Solaris, AIX, and Digital Unix default echo programs unquote
- # backslashes. This makes it impossible to quote backslashes using
- # echo "$something" | sed 's/\\/\\\\/g'
- #
- # So, first we look for a working echo in the user's PATH.
-
- IFS="${IFS= }"; save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for dir in $PATH /usr/ucb; do
- if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
- test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- echo="$dir/echo"
- break
- fi
- done
- IFS="$save_ifs"
-
- if test "X$echo" = Xecho; then
- # We didn't find a better echo, so look for alternatives.
- if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- # This shell has a builtin print -r that does the trick.
- echo='print -r'
- elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
- test "X$CONFIG_SHELL" != X/bin/ksh; then
- # If we have ksh, try running configure again with it.
- ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
- export ORIGINAL_CONFIG_SHELL
- CONFIG_SHELL=/bin/ksh
- export CONFIG_SHELL
- exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
- else
- # Try using printf.
- echo='printf %s\n'
- if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- # Cool, printf works
- :
- elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
- test "X$echo_testing_string" = 'X\t' &&
- echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
- export CONFIG_SHELL
- SHELL="$CONFIG_SHELL"
- export SHELL
- echo="$CONFIG_SHELL [$]0 --fallback-echo"
- elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
- test "X$echo_testing_string" = 'X\t' &&
- echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- echo="$CONFIG_SHELL [$]0 --fallback-echo"
- else
- # maybe with a smaller string...
- prev=:
-
- for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
- if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
- then
- break
- fi
- prev="$cmd"
- done
-
- if test "$prev" != 'sed 50q "[$]0"'; then
- echo_test_string=`eval $prev`
- export echo_test_string
- exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
- else
- # Oops. We lost completely, so just stick with echo.
- echo=echo
- fi
- fi
- fi
- fi
-fi
-fi
-
-# Copy echo and quote the copy suitably for passing to libtool from
-# the Makefile, instead of quoting the original, which is used later.
-ECHO=$echo
-if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
- ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
-fi
-
-AC_SUBST(ECHO)
-AC_DIVERT_POP
-])# _LT_AC_PROG_ECHO_BACKSLASH
-
-# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
-# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
-# ------------------------------------------------------------------
-AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
-[if test "$cross_compiling" = yes; then :
- [$4]
-else
- AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<EOF
-[#line __oline__ "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" void exit (int);
-#endif
-
-void fnord() { int i=42;}
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- /* dlclose (self); */
- }
-
- exit (status);
-}]
-EOF
- if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) $1 ;;
- x$lt_dlneed_uscore) $2 ;;
- x$lt_unknown|x*) $3 ;;
- esac
- else :
- # compilation failed
- $3
- fi
-fi
-rm -fr conftest*
-])# _LT_AC_TRY_DLOPEN_SELF
-
-# AC_LIBTOOL_DLOPEN_SELF
-# -------------------
-AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
-[if test "x$enable_dlopen" != xyes; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
- lt_cv_dlopen=no
- lt_cv_dlopen_libs=
-
- case $host_os in
- beos*)
- lt_cv_dlopen="load_add_on"
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
- ;;
-
- cygwin* | mingw* | pw32*)
- lt_cv_dlopen="LoadLibrary"
- lt_cv_dlopen_libs=
- ;;
-
- *)
- AC_CHECK_FUNC([shl_load],
- [lt_cv_dlopen="shl_load"],
- [AC_CHECK_LIB([dld], [shl_load],
- [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
- [AC_CHECK_FUNC([dlopen],
- [lt_cv_dlopen="dlopen"],
- [AC_CHECK_LIB([dl], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
- [AC_CHECK_LIB([svld], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
- [AC_CHECK_LIB([dld], [dld_link],
- [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
- ])
- ])
- ])
- ])
- ])
- ;;
- esac
-
- if test "x$lt_cv_dlopen" != xno; then
- enable_dlopen=yes
- else
- enable_dlopen=no
- fi
-
- case $lt_cv_dlopen in
- dlopen)
- save_CPPFLAGS="$CPPFLAGS"
- AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
- test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
- save_LDFLAGS="$LDFLAGS"
- eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
- save_LIBS="$LIBS"
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- AC_CACHE_CHECK([whether a program can dlopen itself],
- lt_cv_dlopen_self, [dnl
- _LT_AC_TRY_DLOPEN_SELF(
- lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
- lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
- ])
-
- if test "x$lt_cv_dlopen_self" = xyes; then
- LDFLAGS="$LDFLAGS $link_static_flag"
- AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
- lt_cv_dlopen_self_static, [dnl
- _LT_AC_TRY_DLOPEN_SELF(
- lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
- lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
- ])
- fi
-
- CPPFLAGS="$save_CPPFLAGS"
- LDFLAGS="$save_LDFLAGS"
- LIBS="$save_LIBS"
- ;;
- esac
-
- case $lt_cv_dlopen_self in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case $lt_cv_dlopen_self_static in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-])# AC_LIBTOOL_DLOPEN_SELF
-
-AC_DEFUN([_LT_AC_LTCONFIG_HACK],
-[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])dnl
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e s/^X//'
-sed_quote_subst='s/\([[\\"\\`$\\\\]]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([[\\"\\`\\\\]]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Constants:
-rm="rm -f"
-
-# Global variables:
-default_ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a `.a' archive for static linking (except M$VC,
-# which needs '.lib').
-libext=a
-ltmain="$ac_aux_dir/ltmain.sh"
-ofile="$default_ofile"
-with_gnu_ld="$lt_cv_prog_gnu_ld"
-need_locks="$enable_libtool_lock"
-
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
-
-# Set sane defaults for various variables
-test -z "$AR" && AR=ar
-test -z "$AR_FLAGS" && AR_FLAGS=cru
-test -z "$AS" && AS=as
-test -z "$CC" && CC=cc
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-test -z "$LD" && LD=ld
-test -z "$LN_S" && LN_S="ln -s"
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-test -z "$NM" && NM=nm
-test -z "$OBJDUMP" && OBJDUMP=objdump
-test -z "$RANLIB" && RANLIB=:
-test -z "$STRIP" && STRIP=:
-test -z "$ac_objext" && ac_objext=o
-
-if test x"$host" != x"$build"; then
- ac_tool_prefix=${host_alias}-
-else
- ac_tool_prefix=
-fi
-
-# Transform linux* to *-*-linux-gnu*, to support old configure scripts.
-case $host_os in
-linux-gnu*) ;;
-linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
-esac
-
-case $host_os in
-aix3*)
- # AIX sometimes has problems with the GCC collect2 program. For some
- # reason, if we set the COLLECT_NAMES environment variable, the problems
- # vanish in a puff of smoke.
- if test "X${COLLECT_NAMES+set}" != Xset; then
- COLLECT_NAMES=
- export COLLECT_NAMES
- fi
- ;;
-esac
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
- case $host_os in
- openbsd*)
- old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
- ;;
- *)
- old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
- ;;
- esac
- old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
-fi
-
-# Allow CC to be a program name with arguments.
-set dummy $CC
-compiler="[$]2"
-
-AC_MSG_CHECKING([for objdir])
-rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
- objdir=.libs
-else
- # MS-DOS does not allow filenames that begin with a dot.
- objdir=_libs
-fi
-rmdir .libs 2>/dev/null
-AC_MSG_RESULT($objdir)
-
-
-AC_ARG_WITH(pic,
-[ --with-pic try to use only PIC/non-PIC objects [default=use both]],
-pic_mode="$withval", pic_mode=default)
-test -z "$pic_mode" && pic_mode=default
-
-# We assume here that the value for lt_cv_prog_cc_pic will not be cached
-# in isolation, and that seeing it set (from the cache) indicates that
-# the associated values are set (in the cache) correctly too.
-AC_MSG_CHECKING([for $compiler option to produce PIC])
-AC_CACHE_VAL(lt_cv_prog_cc_pic,
-[ lt_cv_prog_cc_pic=
- lt_cv_prog_cc_shlib=
- lt_cv_prog_cc_wl=
- lt_cv_prog_cc_static=
- lt_cv_prog_cc_no_builtin=
- lt_cv_prog_cc_can_build_shared=$can_build_shared
-
- if test "$GCC" = yes; then
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static='-static'
-
- case $host_os in
- aix*)
- # Below there is a dirty hack to force normal static linking with -ldl
- # The problem is because libdl dynamically linked with both libc and
- # libC (AIX C++ library), which obviously doesn't included in libraries
- # list by gcc. This cause undefined symbols with -static flags.
- # This hack allows C programs to be linked with "-static -ldl", but
- # not sure about C++ programs.
- lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC"
- ;;
- amigaos*)
- # FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
- lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4'
- ;;
- beos* | irix5* | irix6* | osf3* | osf4* | osf5*)
- # PIC is the default for these OSes.
- ;;
- darwin* | rhapsody*)
- # PIC is the default on this platform
- # Common symbols not allowed in MH_DYLIB files
- lt_cv_prog_cc_pic='-fno-common'
- ;;
- cygwin* | mingw* | pw32* | os2*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- lt_cv_prog_cc_pic='-DDLL_EXPORT'
- ;;
- sysv4*MP*)
- if test -d /usr/nec; then
- lt_cv_prog_cc_pic=-Kconform_pic
- fi
- ;;
- *)
- lt_cv_prog_cc_pic='-fPIC'
- ;;
- esac
- else
- # PORTME Check for PIC flags for the system compiler.
- case $host_os in
- aix3* | aix4* | aix5*)
- lt_cv_prog_cc_wl='-Wl,'
- # All AIX code is PIC.
- if test "$host_cpu" = ia64; then
- # AIX 5 now supports IA64 processor
- lt_cv_prog_cc_static='-Bstatic'
- else
- lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp'
- fi
- ;;
-
- hpux9* | hpux10* | hpux11*)
- # Is there a better lt_cv_prog_cc_static that works with the bundled CC?
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive"
- lt_cv_prog_cc_pic='+Z'
- ;;
-
- irix5* | irix6*)
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static='-non_shared'
- # PIC (with -KPIC) is the default.
- ;;
-
- cygwin* | mingw* | pw32* | os2*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- lt_cv_prog_cc_pic='-DDLL_EXPORT'
- ;;
-
- newsos6)
- lt_cv_prog_cc_pic='-KPIC'
- lt_cv_prog_cc_static='-Bstatic'
- ;;
-
- osf3* | osf4* | osf5*)
- # All OSF/1 code is PIC.
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static='-non_shared'
- ;;
-
- sco3.2v5*)
- lt_cv_prog_cc_pic='-Kpic'
- lt_cv_prog_cc_static='-dn'
- lt_cv_prog_cc_shlib='-belf'
- ;;
-
- solaris*)
- lt_cv_prog_cc_pic='-KPIC'
- lt_cv_prog_cc_static='-Bstatic'
- lt_cv_prog_cc_wl='-Wl,'
- ;;
-
- sunos4*)
- lt_cv_prog_cc_pic='-PIC'
- lt_cv_prog_cc_static='-Bstatic'
- lt_cv_prog_cc_wl='-Qoption ld '
- ;;
-
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- lt_cv_prog_cc_pic='-KPIC'
- lt_cv_prog_cc_static='-Bstatic'
- if test "x$host_vendor" = xsni; then
- lt_cv_prog_cc_wl='-LD'
- else
- lt_cv_prog_cc_wl='-Wl,'
- fi
- ;;
-
- uts4*)
- lt_cv_prog_cc_pic='-pic'
- lt_cv_prog_cc_static='-Bstatic'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec ;then
- lt_cv_prog_cc_pic='-Kconform_pic'
- lt_cv_prog_cc_static='-Bstatic'
- fi
- ;;
-
- *)
- lt_cv_prog_cc_can_build_shared=no
- ;;
- esac
- fi
-])
-if test -z "$lt_cv_prog_cc_pic"; then
- AC_MSG_RESULT([none])
-else
- AC_MSG_RESULT([$lt_cv_prog_cc_pic])
-
- # Check to make sure the pic_flag actually works.
- AC_MSG_CHECKING([if $compiler PIC flag $lt_cv_prog_cc_pic works])
- AC_CACHE_VAL(lt_cv_prog_cc_pic_works, [dnl
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC"
- AC_TRY_COMPILE([], [], [dnl
- case $host_os in
- hpux9* | hpux10* | hpux11*)
- # On HP-UX, both CC and GCC only warn that PIC is supported... then
- # they create non-PIC objects. So, if there were any warnings, we
- # assume that PIC is not supported.
- if test -s conftest.err; then
- lt_cv_prog_cc_pic_works=no
- else
- lt_cv_prog_cc_pic_works=yes
- fi
- ;;
- *)
- lt_cv_prog_cc_pic_works=yes
- ;;
- esac
- ], [dnl
- lt_cv_prog_cc_pic_works=no
- ])
- CFLAGS="$save_CFLAGS"
- ])
-
- if test "X$lt_cv_prog_cc_pic_works" = Xno; then
- lt_cv_prog_cc_pic=
- lt_cv_prog_cc_can_build_shared=no
- else
- lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic"
- fi
-
- AC_MSG_RESULT([$lt_cv_prog_cc_pic_works])
-fi
-
-# Check for any special shared library compilation flags.
-if test -n "$lt_cv_prog_cc_shlib"; then
- AC_MSG_WARN([\`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries])
- if echo "$old_CC $old_CFLAGS " | egrep -e "[[ ]]$lt_cv_prog_cc_shlib[[ ]]" >/dev/null; then :
- else
- AC_MSG_WARN([add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure])
- lt_cv_prog_cc_can_build_shared=no
- fi
-fi
-
-AC_MSG_CHECKING([if $compiler static flag $lt_cv_prog_cc_static works])
-AC_CACHE_VAL([lt_cv_prog_cc_static_works], [dnl
- lt_cv_prog_cc_static_works=no
- save_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static"
- AC_TRY_LINK([], [], [lt_cv_prog_cc_static_works=yes])
- LDFLAGS="$save_LDFLAGS"
-])
-
-# Belt *and* braces to stop my trousers falling down:
-test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static=
-AC_MSG_RESULT([$lt_cv_prog_cc_static_works])
-
-pic_flag="$lt_cv_prog_cc_pic"
-special_shlib_compile_flags="$lt_cv_prog_cc_shlib"
-wl="$lt_cv_prog_cc_wl"
-link_static_flag="$lt_cv_prog_cc_static"
-no_builtin_flag="$lt_cv_prog_cc_no_builtin"
-can_build_shared="$lt_cv_prog_cc_can_build_shared"
-
-
-# Check to see if options -o and -c are simultaneously supported by compiler
-AC_MSG_CHECKING([if $compiler supports -c -o file.$ac_objext])
-AC_CACHE_VAL([lt_cv_compiler_c_o], [
-$rm -r conftest 2>/dev/null
-mkdir conftest
-cd conftest
-echo "int some_variable = 0;" > conftest.$ac_ext
-mkdir out
-# According to Tom Tromey, Ian Lance Taylor reported there are C compilers
-# that will create temporary files in the current directory regardless of
-# the output directory. Thus, making CWD read-only will cause this test
-# to fail, enabling locking or at least warning the user not to do parallel
-# builds.
-chmod -w .
-save_CFLAGS="$CFLAGS"
-CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
-compiler_c_o=no
-if { (eval echo configure:__oline__: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s out/conftest.err; then
- lt_cv_compiler_c_o=no
- else
- lt_cv_compiler_c_o=yes
- fi
-else
- # Append any errors to the config.log.
- cat out/conftest.err 1>&AC_FD_CC
- lt_cv_compiler_c_o=no
-fi
-CFLAGS="$save_CFLAGS"
-chmod u+w .
-$rm conftest* out/*
-rmdir out
-cd ..
-rmdir conftest
-$rm -r conftest 2>/dev/null
-])
-compiler_c_o=$lt_cv_compiler_c_o
-AC_MSG_RESULT([$compiler_c_o])
-
-if test x"$compiler_c_o" = x"yes"; then
- # Check to see if we can write to a .lo
- AC_MSG_CHECKING([if $compiler supports -c -o file.lo])
- AC_CACHE_VAL([lt_cv_compiler_o_lo], [
- lt_cv_compiler_o_lo=no
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -c -o conftest.lo"
- save_objext="$ac_objext"
- ac_objext=lo
- AC_TRY_COMPILE([], [int some_variable = 0;], [dnl
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- lt_cv_compiler_o_lo=no
- else
- lt_cv_compiler_o_lo=yes
- fi
- ])
- ac_objext="$save_objext"
- CFLAGS="$save_CFLAGS"
- ])
- compiler_o_lo=$lt_cv_compiler_o_lo
- AC_MSG_RESULT([$compiler_o_lo])
-else
- compiler_o_lo=no
-fi
-
-# Check to see if we can do hard links to lock some files if needed
-hard_links="nottested"
-if test "$compiler_c_o" = no && test "$need_locks" != no; then
- # do not overwrite the value of need_locks provided by the user
- AC_MSG_CHECKING([if we can lock with hard links])
- hard_links=yes
- $rm conftest*
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- touch conftest.a
- ln conftest.a conftest.b 2>&5 || hard_links=no
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- AC_MSG_RESULT([$hard_links])
- if test "$hard_links" = no; then
- AC_MSG_WARN([\`$CC' does not support \`-c -o', so \`make -j' may be unsafe])
- need_locks=warn
- fi
-else
- need_locks=no
-fi
-
-if test "$GCC" = yes; then
- # Check to see if options -fno-rtti -fno-exceptions are supported by compiler
- AC_MSG_CHECKING([if $compiler supports -fno-rtti -fno-exceptions])
- echo "int some_variable = 0;" > conftest.$ac_ext
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext"
- compiler_rtti_exceptions=no
- AC_TRY_COMPILE([], [int some_variable = 0;], [dnl
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- compiler_rtti_exceptions=no
- else
- compiler_rtti_exceptions=yes
- fi
- ])
- CFLAGS="$save_CFLAGS"
- AC_MSG_RESULT([$compiler_rtti_exceptions])
-
- if test "$compiler_rtti_exceptions" = "yes"; then
- no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions'
- else
- no_builtin_flag=' -fno-builtin'
- fi
-fi
-
-# See if the linker supports building shared libraries.
-AC_MSG_CHECKING([whether the linker ($LD) supports shared libraries])
-
-allow_undefined_flag=
-no_undefined_flag=
-need_lib_prefix=unknown
-need_version=unknown
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-archive_cmds=
-archive_expsym_cmds=
-old_archive_from_new_cmds=
-old_archive_from_expsyms_cmds=
-export_dynamic_flag_spec=
-whole_archive_flag_spec=
-thread_safe_flag_spec=
-hardcode_into_libs=no
-hardcode_libdir_flag_spec=
-hardcode_libdir_separator=
-hardcode_direct=no
-hardcode_minus_L=no
-hardcode_shlibpath_var=unsupported
-runpath_var=
-link_all_deplibs=unknown
-always_export_symbols=no
-export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols'
-# include_expsyms should be a list of space-separated symbols to be *always*
-# included in the symbol list
-include_expsyms=
-# exclude_expsyms can be an egrep regular expression of symbols to exclude
-# it will be wrapped by ` (' and `)$', so one must not match beginning or
-# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
-# as well as any symbol that contains `d'.
-exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
-# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
-# platforms (ab)use it in PIC code, but their linkers get confused if
-# the symbol is explicitly referenced. Since portable code cannot
-# rely on this symbol name, it's probably fine to never include it in
-# preloaded symbol tables.
-extract_expsyms_cmds=
-
-case $host_os in
-cygwin* | mingw* | pw32*)
- # FIXME: the MSVC++ port hasn't been tested in a loooong time
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- if test "$GCC" != yes; then
- with_gnu_ld=no
- fi
- ;;
-openbsd*)
- with_gnu_ld=no
- ;;
-esac
-
-ld_shlibs=yes
-if test "$with_gnu_ld" = yes; then
- # If archive_cmds runs LD, not CC, wlarc should be empty
- wlarc='${wl}'
-
- # See if GNU ld supports shared libraries.
- case $host_os in
- aix3* | aix4* | aix5*)
- # On AIX, the GNU linker is very broken
- # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available.
- ld_shlibs=no
- cat <<EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.9.1, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support. If you
-*** really care for shared libraries, you may want to modify your PATH
-*** so that a non-GNU linker is found, and then restart.
-
-EOF
- ;;
-
- amigaos*)
- archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
-
- # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
- # that the semantics of dynamic libraries on AmigaOS, at least up
- # to version 4, is to share data among multiple programs linked
- # with the same dynamic library. Since this doesn't match the
- # behavior of shared libraries on other platforms, we can use
- # them.
- ld_shlibs=no
- ;;
-
- beos*)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- allow_undefined_flag=unsupported
- # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
- # support --undefined. This deserves some investigation. FIXME
- archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- cygwin* | mingw* | pw32*)
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec='-L$libdir'
- allow_undefined_flag=unsupported
- always_export_symbols=yes
-
- extract_expsyms_cmds='test -f $output_objdir/impgen.c || \
- sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~
- test -f $output_objdir/impgen.exe || (cd $output_objdir && \
- if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \
- else $CC -o impgen impgen.c ; fi)~
- $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def'
-
- old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib'
-
- # cygwin and mingw dlls have different entry points and sets of symbols
- # to exclude.
- # FIXME: what about values for MSVC?
- dll_entry=__cygwin_dll_entry@12
- dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~
- case $host_os in
- mingw*)
- # mingw values
- dll_entry=_DllMainCRTStartup@12
- dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~
- ;;
- esac
-
- # mingw and cygwin differ, and it's simplest to just exclude the union
- # of the two symbol sets.
- dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12
-
- # recent cygwin and mingw systems supply a stub DllMain which the user
- # can override, but on older systems we have to supply one (in ltdll.c)
- if test "x$lt_cv_need_dllmain" = "xyes"; then
- ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext "
- ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $''0 > $output_objdir/$soname-ltdll.c~
- test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~'
- else
- ltdll_obj=
- ltdll_cmds=
- fi
-
- # Extract the symbol export list from an `--export-all' def file,
- # then regenerate the def file from the symbol export list, so that
- # the compiled dll only exports the symbol export list.
- # Be careful not to strip the DATA tag left be newer dlltools.
- export_symbols_cmds="$ltdll_cmds"'
- $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~
- sed -e "1,/EXPORTS/d" -e "s/ @ [[0-9]]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols'
-
- # If the export-symbols file already is a .def file (1st line
- # is EXPORTS), use it as is.
- # If DATA tags from a recent dlltool are present, honour them!
- archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then
- cp $export_symbols $output_objdir/$soname-def;
- else
- echo EXPORTS > $output_objdir/$soname-def;
- _lt_hint=1;
- cat $export_symbols | while read symbol; do
- set dummy \$symbol;
- case \[$]# in
- 2) echo " \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;;
- *) echo " \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;;
- esac;
- _lt_hint=`expr 1 + \$_lt_hint`;
- done;
- fi~
- '"$ltdll_cmds"'
- $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
- $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~
- $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
- $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~
- $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags'
- ;;
-
- netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
- wlarc=
- else
- archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- fi
- ;;
-
- solaris* | sysv5*)
- if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then
- ld_shlibs=no
- cat <<EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-EOF
- elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- sunos4*)
- archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- wlarc=
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- *)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
- esac
-
- if test "$ld_shlibs" = yes; then
- runpath_var=LD_RUN_PATH
- hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
- export_dynamic_flag_spec='${wl}--export-dynamic'
- case $host_os in
- cygwin* | mingw* | pw32*)
- # dlltool doesn't understand --whole-archive et. al.
- whole_archive_flag_spec=
- ;;
- *)
- # ancient GNU ld didn't support --whole-archive et. al.
- if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then
- whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
- else
- whole_archive_flag_spec=
- fi
- ;;
- esac
- fi
-else
- # PORTME fill in a description of your system's linker (not GNU ld)
- case $host_os in
- aix3*)
- allow_undefined_flag=unsupported
- always_export_symbols=yes
- archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
- # Note: this linker hardcodes the directories in LIBPATH if there
- # are no directories specified by -L.
- hardcode_minus_L=yes
- if test "$GCC" = yes && test -z "$link_static_flag"; then
- # Neither direct hardcoding nor static linking is supported with a
- # broken collect2.
- hardcode_direct=unsupported
- fi
- ;;
-
- aix4* | aix5*)
- if test "$host_cpu" = ia64; then
- # On IA64, the linker does run time linking by default, so we don't
- # have to do anything special.
- aix_use_runtimelinking=no
- exp_sym_flag='-Bexport'
- no_entry_flag=""
- else
- aix_use_runtimelinking=no
-
- # Test if we are trying to use run time linking or normal
- # AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
- case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
- for ld_flag in $LDFLAGS; do
- if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
- aix_use_runtimelinking=yes
- break
- fi
- done
- esac
-
- exp_sym_flag='-bexport'
- no_entry_flag='-bnoentry'
- fi
-
- # When large executables or shared objects are built, AIX ld can
- # have problems creating the table of contents. If linking a library
- # or program results in "error TOC overflow" add -mminimal-toc to
- # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
- # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
- hardcode_direct=yes
- archive_cmds=''
- hardcode_libdir_separator=':'
- if test "$GCC" = yes; then
- case $host_os in aix4.[[012]]|aix4.[[012]].*)
- collect2name=`${CC} -print-prog-name=collect2`
- if test -f "$collect2name" && \
- strings "$collect2name" | grep resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- hardcode_direct=yes
- else
- # We have old collect2
- hardcode_direct=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- hardcode_minus_L=yes
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_libdir_separator=
- fi
- esac
-
- shared_flag='-shared'
- else
- # not using gcc
- if test "$host_cpu" = ia64; then
- shared_flag='${wl}-G'
- else
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag='${wl}-G'
- else
- shared_flag='${wl}-bM:SRE'
- fi
- fi
- fi
-
- # It seems that -bexpall can do strange things, so it is better to
- # generate a list of symbols to export.
- always_export_symbols=yes
- if test "$aix_use_runtimelinking" = yes; then
- # Warning - without using the other runtime loading flags (-brtl),
- # -berok will link without error, but may produce a broken library.
- allow_undefined_flag='-berok'
- hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
- archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
- else
- if test "$host_cpu" = ia64; then
- hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
- allow_undefined_flag="-z nodefs"
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
- else
- hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib'
- # Warning - without using the other run time loading flags,
- # -berok will link without error, but may produce a broken library.
- allow_undefined_flag='${wl}-berok'
- # This is a bit strange, but is similar to how AIX traditionally builds
- # it's shared libraries.
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname'
- fi
- fi
- ;;
-
- amigaos*)
- archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- # see comment about different semantics on the GNU ld section
- ld_shlibs=no
- ;;
-
- cygwin* | mingw* | pw32*)
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec=' '
- allow_undefined_flag=unsupported
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # FIXME: Setting linknames here is a bad hack.
- archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames='
- # The linker will automatically build a .lib file if we build a DLL.
- old_archive_from_new_cmds='true'
- # FIXME: Should let the user specify the lib program.
- old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs'
- fix_srcfile_path='`cygpath -w "$srcfile"`'
- ;;
-
- darwin* | rhapsody*)
- case "$host_os" in
- rhapsody* | darwin1.[[012]])
- allow_undefined_flag='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- allow_undefined_flag='-flat_namespace -undefined suppress'
- ;;
- esac
- # FIXME: Relying on posixy $() will cause problems for
- # cross-compilation, but unfortunately the echo tests do not
- # yet detect zsh echo's removal of \ escapes.
- archive_cmds='$nonopt $(test "x$module" = xyes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring'
- # We need to add '_' to the symbols in $export_symbols first
- #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- whole_archive_flag_spec='-all_load $convenience'
- ;;
-
- freebsd1*)
- ld_shlibs=no
- ;;
-
- # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
- # support. Future versions do this automatically, but an explicit c++rt0.o
- # does not break anything, and helps significantly (at the cost of a little
- # extra space).
- freebsd2.2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- # Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd*)
- archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- hpux9* | hpux10* | hpux11*)
- case $host_os in
- hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;;
- *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;;
- esac
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator=:
- hardcode_direct=yes
- hardcode_minus_L=yes # Not in the search PATH, but as the default
- # location of the library.
- export_dynamic_flag_spec='${wl}-E'
- ;;
-
- irix5* | irix6*)
- if test "$GCC" = yes; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- else
- archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
- fi
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- link_all_deplibs=yes
- ;;
-
- netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
- else
- archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
- fi
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- newsos6)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- hardcode_shlibpath_var=no
- ;;
-
- openbsd*)
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- export_dynamic_flag_spec='${wl}-E'
- else
- case "$host_os" in
- openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-R$libdir'
- ;;
- *)
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- ;;
- esac
- fi
- ;;
-
- os2*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- allow_undefined_flag=unsupported
- archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
- old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
- ;;
-
- osf3*)
- if test "$GCC" = yes; then
- allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- else
- allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
- fi
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- ;;
-
- osf4* | osf5*) # as osf3* with the addition of -msym flag
- if test "$GCC" = yes; then
- allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- else
- allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
- archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
- $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
-
- #Both c and cxx compiler support -rpath directly
- hardcode_libdir_flag_spec='-rpath $libdir'
- fi
- hardcode_libdir_separator=:
- ;;
-
- sco3.2v5*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- export_dynamic_flag_spec='${wl}-Bexport'
- ;;
-
- solaris*)
- # gcc --version < 3.0 without binutils cannot create self contained
- # shared libraries reliably, requiring libgcc.a to resolve some of
- # the object symbols generated in some cases. Libraries that use
- # assert need libgcc.a to resolve __eprintf, for example. Linking
- # a copy of libgcc.a into every shared library to guarantee resolving
- # such symbols causes other problems: According to Tim Van Holder
- # <tim.van.holder@pandora.be>, C++ libraries end up with a separate
- # (to the application) exception stack for one thing.
- no_undefined_flag=' -z defs'
- if test "$GCC" = yes; then
- case `$CC --version 2>/dev/null` in
- [[12]].*)
- cat <<EOF 1>&2
-
-*** Warning: Releases of GCC earlier than version 3.0 cannot reliably
-*** create self contained shared libraries on Solaris systems, without
-*** introducing a dependency on libgcc.a. Therefore, libtool is disabling
-*** -no-undefined support, which will at least allow you to build shared
-*** libraries. However, you may find that when you link such libraries
-*** into an application without using GCC, you have to manually add
-*** \`gcc --print-libgcc-file-name\` to the link command. We urge you to
-*** upgrade to a newer version of GCC. Another option is to rebuild your
-*** current GCC to use the GNU linker from GNU binutils 2.9.1 or newer.
-
-EOF
- no_undefined_flag=
- ;;
- esac
- fi
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_shlibpath_var=no
- case $host_os in
- solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
- *) # Supported since Solaris 2.6 (maybe 2.5.1?)
- whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
- esac
- link_all_deplibs=yes
- ;;
-
- sunos4*)
- if test "x$host_vendor" = xsequent; then
- # Use $CC to link under sequent, because it throws in some extra .o
- # files that make .init and .fini sections work.
- archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
- fi
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- sysv4)
- if test "x$host_vendor" = xsno; then
- archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes # is this really true???
- else
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=no #Motorola manual says yes, but my tests say they lie
- fi
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
- ;;
-
- sysv4.3*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- export_dynamic_flag_spec='-Bexport'
- ;;
-
- sysv5*)
- no_undefined_flag=' -z text'
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- hardcode_libdir_flag_spec=
- hardcode_shlibpath_var=no
- runpath_var='LD_RUN_PATH'
- ;;
-
- uts4*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- dgux*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ld_shlibs=yes
- fi
- ;;
-
- sysv4.2uw2*)
- archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_minus_L=no
- hardcode_shlibpath_var=no
- hardcode_runpath_var=yes
- runpath_var=LD_RUN_PATH
- ;;
-
- sysv5uw7* | unixware7*)
- no_undefined_flag='${wl}-z ${wl}text'
- if test "$GCC" = yes; then
- archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
- fi
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
- ;;
-
- *)
- ld_shlibs=no
- ;;
- esac
-fi
-AC_MSG_RESULT([$ld_shlibs])
-test "$ld_shlibs" = no && can_build_shared=no
-
-# Check hardcoding attributes.
-AC_MSG_CHECKING([how to hardcode library paths into programs])
-hardcode_action=
-if test -n "$hardcode_libdir_flag_spec" || \
- test -n "$runpath_var"; then
-
- # We can hardcode non-existant directories.
- if test "$hardcode_direct" != no &&
- # If the only mechanism to avoid hardcoding is shlibpath_var, we
- # have to relink, otherwise we might link with an installed library
- # when we should be linking with a yet-to-be-installed one
- ## test "$hardcode_shlibpath_var" != no &&
- test "$hardcode_minus_L" != no; then
- # Linking always hardcodes the temporary library directory.
- hardcode_action=relink
- else
- # We can link without hardcoding, and we can hardcode nonexisting dirs.
- hardcode_action=immediate
- fi
-else
- # We cannot hardcode anything, or else we can only hardcode existing
- # directories.
- hardcode_action=unsupported
-fi
-AC_MSG_RESULT([$hardcode_action])
-
-striplib=
-old_striplib=
-AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-# PORTME Fill in your ld.so characteristics
-AC_MSG_CHECKING([dynamic linker characteristics])
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-
-case $host_os in
-aix3*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix $libname.a'
- shlibpath_var=LIBPATH
-
- # AIX has no versioning support, so we append a major version to the name.
- soname_spec='${libname}${release}.so$major'
- ;;
-
-aix4* | aix5*)
- version_type=linux
- if test "$host_cpu" = ia64; then
- # AIX 5 supports IA64
- library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- else
- # With GCC up to 2.95.x, collect2 would create an import file
- # for dependence libraries. The import file would start with
- # the line `#! .'. This would cause the generated library to
- # depend on `.', always an invalid library. This was fixed in
- # development snapshots of GCC prior to 3.0.
- case $host_os in
- aix4 | aix4.[[01]] | aix4.[[01]].*)
- if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
- echo ' yes '
- echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
- :
- else
- can_build_shared=no
- fi
- ;;
- esac
- # AIX (on Power*) has no versioning support, so currently we can
- # not hardcode correct soname into executable. Probably we can
- # add versioning support to collect2, so additional links can
- # be useful in future.
- if test "$aix_use_runtimelinking" = yes; then
- # If using run time linking (on AIX 4.2 or later) use lib<name>.so
- # instead of lib<name>.a to let people know that these are not
- # typical AIX shared libraries.
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- else
- # We preserve .a as extension for shared libraries through AIX4.2
- # and later when we are not doing run time linking.
- library_names_spec='${libname}${release}.a $libname.a'
- soname_spec='${libname}${release}.so$major'
- fi
- shlibpath_var=LIBPATH
- fi
- ;;
-
-amigaos*)
- library_names_spec='$libname.ixlibrary $libname.a'
- # Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done'
- ;;
-
-beos*)
- library_names_spec='${libname}.so'
- dynamic_linker="$host_os ld.so"
- shlibpath_var=LIBRARY_PATH
- ;;
-
-bsdi4*)
- version_type=linux
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
- sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
- export_dynamic_flag_spec=-rdynamic
- # the default ld.so.conf also contains /usr/contrib/lib and
- # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
- # libtool to hard-code these into programs
- ;;
-
-cygwin* | mingw* | pw32*)
- version_type=windows
- need_version=no
- need_lib_prefix=no
- case $GCC,$host_os in
- yes,cygwin*)
- library_names_spec='$libname.dll.a'
- soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll'
- postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog .libs/$dlname \$dldir/$dlname'
- postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $rm \$dlpath'
- ;;
- yes,mingw*)
- library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll'
- sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"`
- ;;
- yes,pw32*)
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll'
- ;;
- *)
- library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll $libname.lib'
- ;;
- esac
- dynamic_linker='Win32 ld.exe'
- # FIXME: first we should search . and the directory the executable is in
- shlibpath_var=PATH
- ;;
-
-darwin* | rhapsody*)
- dynamic_linker="$host_os dyld"
- version_type=darwin
- need_lib_prefix=no
- need_version=no
- # FIXME: Relying on posixy $() will cause problems for
- # cross-compilation, but unfortunately the echo tests do not
- # yet detect zsh echo's removal of \ escapes.
- library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)'
- soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)'
- shlibpath_overrides_runpath=yes
- shlibpath_var=DYLD_LIBRARY_PATH
- ;;
-
-freebsd1*)
- dynamic_linker=no
- ;;
-
-freebsd*)
- objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
- version_type=freebsd-$objformat
- case $version_type in
- freebsd-elf*)
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
- need_version=no
- need_lib_prefix=no
- ;;
- freebsd-*)
- library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix'
- need_version=yes
- ;;
- esac
- shlibpath_var=LD_LIBRARY_PATH
- case $host_os in
- freebsd2*)
- shlibpath_overrides_runpath=yes
- ;;
- *)
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
- esac
- ;;
-
-gnu*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- hardcode_into_libs=yes
- ;;
-
-hpux9* | hpux10* | hpux11*)
- # Give a soname corresponding to the major version so that dld.sl refuses to
- # link against other versions.
- dynamic_linker="$host_os dld.sl"
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- shlibpath_var=SHLIB_PATH
- shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl'
- soname_spec='${libname}${release}.sl$major'
- # HP-UX runs *really* slowly unless shared libraries are mode 555.
- postinstall_cmds='chmod 555 $lib'
- ;;
-
-irix5* | irix6*)
- version_type=irix
- need_lib_prefix=no
- need_version=no
- soname_spec='${libname}${release}.so$major'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so'
- case $host_os in
- irix5*)
- libsuff= shlibsuff=
- ;;
- *)
- case $LD in # libtool.m4 will add one of these switches to LD
- *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;;
- *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;;
- *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;;
- *) libsuff= shlibsuff= libmagic=never-match;;
- esac
- ;;
- esac
- shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
- sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
- ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*)
- dynamic_linker=no
- ;;
-
-# This must be Linux ELF.
-linux-gnu*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- # This implies no fast_install, which is unacceptable.
- # Some rework will be needed to allow for fast_install
- # before this can be enabled.
- hardcode_into_libs=yes
-
- # We used to test for /lib/ld.so.1 and disable shared libraries on
- # powerpc, because MkLinux only supported shared libraries with the
- # GNU dynamic linker. Since this was broken with cross compilers,
- # most powerpc-linux boxes support dynamic linking these days and
- # people can always --disable-shared, the test was removed, and we
- # assume the GNU/Linux dynamic linker is in use.
- dynamic_linker='GNU/Linux ld.so'
- ;;
-
-netbsd*)
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- dynamic_linker='NetBSD (a.out) ld.so'
- else
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so'
- soname_spec='${libname}${release}.so$major'
- dynamic_linker='NetBSD ld.elf_so'
- fi
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
-
-newsos6)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- ;;
-
-openbsd*)
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- case "$host_os" in
- openbsd2.[[89]] | openbsd2.[[89]].*)
- shlibpath_overrides_runpath=no
- ;;
- *)
- shlibpath_overrides_runpath=yes
- ;;
- esac
- else
- shlibpath_overrides_runpath=yes
- fi
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-os2*)
- libname_spec='$name'
- need_lib_prefix=no
- library_names_spec='$libname.dll $libname.a'
- dynamic_linker='OS/2 ld.exe'
- shlibpath_var=LIBPATH
- ;;
-
-osf3* | osf4* | osf5*)
- version_type=osf
- need_version=no
- soname_spec='${libname}${release}.so'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
- ;;
-
-sco3.2v5*)
- version_type=osf
- soname_spec='${libname}${release}.so$major'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-solaris*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- # ldd complains unless libraries are executable
- postinstall_cmds='chmod +x $lib'
- ;;
-
-sunos4*)
- version_type=sunos
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- if test "$with_gnu_ld" = yes; then
- need_lib_prefix=no
- fi
- need_version=yes
- ;;
-
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- case $host_vendor in
- sni)
- shlibpath_overrides_runpath=no
- ;;
- motorola)
- need_lib_prefix=no
- need_version=no
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
- ;;
- esac
- ;;
-
-uts4*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-dgux*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-sysv4*MP*)
- if test -d /usr/nec ;then
- version_type=linux
- library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so'
- soname_spec='$libname.so.$major'
- shlibpath_var=LD_LIBRARY_PATH
- fi
- ;;
-
-*)
- dynamic_linker=no
- ;;
-esac
-AC_MSG_RESULT([$dynamic_linker])
-test "$dynamic_linker" = no && can_build_shared=no
-
-# Report the final consequences.
-AC_MSG_CHECKING([if libtool supports shared libraries])
-AC_MSG_RESULT([$can_build_shared])
-
-AC_MSG_CHECKING([whether to build shared libraries])
-test "$can_build_shared" = "no" && enable_shared=no
-
-# On AIX, shared libraries and static libraries use the same namespace, and
-# are all built from PIC.
-case "$host_os" in
-aix3*)
- test "$enable_shared" = yes && enable_static=no
- if test -n "$RANLIB"; then
- archive_cmds="$archive_cmds~\$RANLIB \$lib"
- postinstall_cmds='$RANLIB $lib'
- fi
- ;;
-
-aix4*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
- fi
- ;;
-esac
-AC_MSG_RESULT([$enable_shared])
-
-AC_MSG_CHECKING([whether to build static libraries])
-# Make sure either enable_shared or enable_static is yes.
-test "$enable_shared" = yes || enable_static=yes
-AC_MSG_RESULT([$enable_static])
-
-if test "$hardcode_action" = relink; then
- # Fast installation is not supported
- enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
- test "$enable_shared" = no; then
- # Fast installation is not necessary
- enable_fast_install=needless
-fi
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-AC_LIBTOOL_DLOPEN_SELF
-
-if test "$enable_shared" = yes && test "$GCC" = yes; then
- case $archive_cmds in
- *'~'*)
- # FIXME: we may have to deal with multi-command sequences.
- ;;
- '$CC '*)
- # Test whether the compiler implicitly links with -lc since on some
- # systems, -lgcc has to come before -lc. If gcc already passes -lc
- # to ld, don't add -lc before -lgcc.
- AC_MSG_CHECKING([whether -lc should be explicitly linked in])
- AC_CACHE_VAL([lt_cv_archive_cmds_need_lc],
- [$rm conftest*
- echo 'static int dummy;' > conftest.$ac_ext
-
- if AC_TRY_EVAL(ac_compile); then
- soname=conftest
- lib=conftest
- libobjs=conftest.$ac_objext
- deplibs=
- wl=$lt_cv_prog_cc_wl
- compiler_flags=-v
- linker_flags=-v
- verstring=
- output_objdir=.
- libname=conftest
- save_allow_undefined_flag=$allow_undefined_flag
- allow_undefined_flag=
- if AC_TRY_EVAL(archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
- then
- lt_cv_archive_cmds_need_lc=no
- else
- lt_cv_archive_cmds_need_lc=yes
- fi
- allow_undefined_flag=$save_allow_undefined_flag
- else
- cat conftest.err 1>&5
- fi])
- AC_MSG_RESULT([$lt_cv_archive_cmds_need_lc])
- ;;
- esac
-fi
-need_lc=${lt_cv_archive_cmds_need_lc-yes}
-
-# The second clause should only fire when bootstrapping the
-# libtool distribution, otherwise you forgot to ship ltmain.sh
-# with your package, and you will get complaints that there are
-# no rules to generate ltmain.sh.
-if test -f "$ltmain"; then
- :
-else
- # If there is no Makefile yet, we rely on a make rule to execute
- # `config.status --recheck' to rerun these tests and create the
- # libtool script then.
- test -f Makefile && make "$ltmain"
-fi
-
-if test -f "$ltmain"; then
- trap "$rm \"${ofile}T\"; exit 1" 1 2 15
- $rm -f "${ofile}T"
-
- echo creating $ofile
-
- # Now quote all the things that may contain metacharacters while being
- # careful not to overquote the AC_SUBSTed values. We take copies of the
- # variables and quote the copies for generation of the libtool script.
- for var in echo old_CC old_CFLAGS \
- AR AR_FLAGS CC LD LN_S NM SHELL \
- reload_flag reload_cmds wl \
- pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \
- thread_safe_flag_spec whole_archive_flag_spec libname_spec \
- library_names_spec soname_spec \
- RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \
- old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \
- postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \
- old_striplib striplib file_magic_cmd export_symbols_cmds \
- deplibs_check_method allow_undefined_flag no_undefined_flag \
- finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \
- global_symbol_to_c_name_address \
- hardcode_libdir_flag_spec hardcode_libdir_separator \
- sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
- compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do
-
- case $var in
- reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \
- old_postinstall_cmds | old_postuninstall_cmds | \
- export_symbols_cmds | archive_cmds | archive_expsym_cmds | \
- extract_expsyms_cmds | old_archive_from_expsyms_cmds | \
- postinstall_cmds | postuninstall_cmds | \
- finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
- # Double-quote double-evaled strings.
- eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
- ;;
- *)
- eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
- ;;
- esac
- done
-
- cat <<__EOF__ > "${ofile}T"
-#! $SHELL
-
-# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-#
-# Copyright (C) 1996-2000 Free Software Foundation, Inc.
-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="sed -e s/^X//"
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
-
-# ### BEGIN LIBTOOL CONFIG
-
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-
-# Shell to use when invoking shell scripts.
-SHELL=$lt_SHELL
-
-# Whether or not to build shared libraries.
-build_libtool_libs=$enable_shared
-
-# Whether or not to build static libraries.
-build_old_libs=$enable_static
-
-# Whether or not to add -lc for building shared libraries.
-build_libtool_need_lc=$need_lc
-
-# Whether or not to optimize for fast installation.
-fast_install=$enable_fast_install
-
-# The host system.
-host_alias=$host_alias
-host=$host
-
-# An echo program that does not interpret backslashes.
-echo=$lt_echo
-
-# The archiver.
-AR=$lt_AR
-AR_FLAGS=$lt_AR_FLAGS
-
-# The default C compiler.
-CC=$lt_CC
-
-# Is the compiler the GNU C compiler?
-with_gcc=$GCC
-
-# The linker used to build libraries.
-LD=$lt_LD
-
-# Whether we need hard or soft links.
-LN_S=$lt_LN_S
-
-# A BSD-compatible nm program.
-NM=$lt_NM
-
-# A symbol stripping program
-STRIP=$STRIP
-
-# Used to examine libraries when file_magic_cmd begins "file"
-MAGIC_CMD=$MAGIC_CMD
-
-# Used on cygwin: DLL creation program.
-DLLTOOL="$DLLTOOL"
-
-# Used on cygwin: object dumper.
-OBJDUMP="$OBJDUMP"
-
-# Used on cygwin: assembler.
-AS="$AS"
-
-# The name of the directory that contains temporary libtool files.
-objdir=$objdir
-
-# How to create reloadable object files.
-reload_flag=$lt_reload_flag
-reload_cmds=$lt_reload_cmds
-
-# How to pass a linker flag through the compiler.
-wl=$lt_wl
-
-# Object file suffix (normally "o").
-objext="$ac_objext"
-
-# Old archive suffix (normally "a").
-libext="$libext"
-
-# Executable file suffix (normally "").
-exeext="$exeext"
-
-# Additional compiler flags for building library objects.
-pic_flag=$lt_pic_flag
-pic_mode=$pic_mode
-
-# Does compiler simultaneously support -c and -o options?
-compiler_c_o=$lt_compiler_c_o
-
-# Can we write directly to a .lo ?
-compiler_o_lo=$lt_compiler_o_lo
-
-# Must we lock files when doing compilation ?
-need_locks=$lt_need_locks
-
-# Do we need the lib prefix for modules?
-need_lib_prefix=$need_lib_prefix
-
-# Do we need a version for libraries?
-need_version=$need_version
-
-# Whether dlopen is supported.
-dlopen_support=$enable_dlopen
-
-# Whether dlopen of programs is supported.
-dlopen_self=$enable_dlopen_self
-
-# Whether dlopen of statically linked programs is supported.
-dlopen_self_static=$enable_dlopen_self_static
-
-# Compiler flag to prevent dynamic linking.
-link_static_flag=$lt_link_static_flag
-
-# Compiler flag to turn off builtin functions.
-no_builtin_flag=$lt_no_builtin_flag
-
-# Compiler flag to allow reflexive dlopens.
-export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
-
-# Compiler flag to generate shared objects directly from archives.
-whole_archive_flag_spec=$lt_whole_archive_flag_spec
-
-# Compiler flag to generate thread-safe objects.
-thread_safe_flag_spec=$lt_thread_safe_flag_spec
-
-# Library versioning type.
-version_type=$version_type
-
-# Format of library name prefix.
-libname_spec=$lt_libname_spec
-
-# List of archive names. First name is the real one, the rest are links.
-# The last name is the one that the linker finds with -lNAME.
-library_names_spec=$lt_library_names_spec
-
-# The coded name of the library, if different from the real name.
-soname_spec=$lt_soname_spec
-
-# Commands used to build and install an old-style archive.
-RANLIB=$lt_RANLIB
-old_archive_cmds=$lt_old_archive_cmds
-old_postinstall_cmds=$lt_old_postinstall_cmds
-old_postuninstall_cmds=$lt_old_postuninstall_cmds
-
-# Create an old-style archive from a shared archive.
-old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
-
-# Create a temporary old-style archive to link instead of a shared archive.
-old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
-
-# Commands used to build and install a shared archive.
-archive_cmds=$lt_archive_cmds
-archive_expsym_cmds=$lt_archive_expsym_cmds
-postinstall_cmds=$lt_postinstall_cmds
-postuninstall_cmds=$lt_postuninstall_cmds
-
-# Commands to strip libraries.
-old_striplib=$lt_old_striplib
-striplib=$lt_striplib
-
-# Method to check whether dependent libraries are shared objects.
-deplibs_check_method=$lt_deplibs_check_method
-
-# Command to use when deplibs_check_method == file_magic.
-file_magic_cmd=$lt_file_magic_cmd
-
-# Flag that allows shared libraries with undefined symbols to be built.
-allow_undefined_flag=$lt_allow_undefined_flag
-
-# Flag that forces no undefined symbols.
-no_undefined_flag=$lt_no_undefined_flag
-
-# Commands used to finish a libtool library installation in a directory.
-finish_cmds=$lt_finish_cmds
-
-# Same as above, but a single script fragment to be evaled but not shown.
-finish_eval=$lt_finish_eval
-
-# Take the output of nm and produce a listing of raw symbols and C names.
-global_symbol_pipe=$lt_global_symbol_pipe
-
-# Transform the output of nm in a proper C declaration
-global_symbol_to_cdecl=$lt_global_symbol_to_cdecl
-
-# Transform the output of nm in a C name address pair
-global_symbol_to_c_name_address=$lt_global_symbol_to_c_name_address
-
-# This is the shared library runtime path variable.
-runpath_var=$runpath_var
-
-# This is the shared library path variable.
-shlibpath_var=$shlibpath_var
-
-# Is shlibpath searched before the hard-coded library search path?
-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
-
-# How to hardcode a shared library path into an executable.
-hardcode_action=$hardcode_action
-
-# Whether we should hardcode library paths into libraries.
-hardcode_into_libs=$hardcode_into_libs
-
-# Flag to hardcode \$libdir into a binary during linking.
-# This must work even if \$libdir does not exist.
-hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
-
-# Whether we need a single -rpath flag with a separated argument.
-hardcode_libdir_separator=$lt_hardcode_libdir_separator
-
-# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
-# resulting binary.
-hardcode_direct=$hardcode_direct
-
-# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
-# resulting binary.
-hardcode_minus_L=$hardcode_minus_L
-
-# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
-# the resulting binary.
-hardcode_shlibpath_var=$hardcode_shlibpath_var
-
-# Variables whose values should be saved in libtool wrapper scripts and
-# restored at relink time.
-variables_saved_for_relink="$variables_saved_for_relink"
-
-# Whether libtool must link a program against all its dependency libraries.
-link_all_deplibs=$link_all_deplibs
-
-# Compile-time system search path for libraries
-sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
-
-# Run-time system search path for libraries
-sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
-
-# Fix the shell variable \$srcfile for the compiler.
-fix_srcfile_path="$fix_srcfile_path"
-
-# Set to yes if exported symbols are required.
-always_export_symbols=$always_export_symbols
-
-# The commands to list exported symbols.
-export_symbols_cmds=$lt_export_symbols_cmds
-
-# The commands to extract the exported symbol list from a shared archive.
-extract_expsyms_cmds=$lt_extract_expsyms_cmds
-
-# Symbols that should not be listed in the preloaded symbols.
-exclude_expsyms=$lt_exclude_expsyms
-
-# Symbols that must always be exported.
-include_expsyms=$lt_include_expsyms
-
-# ### END LIBTOOL CONFIG
-
-__EOF__
-
- case $host_os in
- aix3*)
- cat <<\EOF >> "${ofile}T"
-
-# AIX sometimes has problems with the GCC collect2 program. For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
- COLLECT_NAMES=
- export COLLECT_NAMES
-fi
-EOF
- ;;
- esac
-
- case $host_os in
- cygwin* | mingw* | pw32* | os2*)
- cat <<'EOF' >> "${ofile}T"
- # This is a source program that is used to create dlls on Windows
- # Don't remove nor modify the starting and closing comments
-# /* ltdll.c starts here */
-# #define WIN32_LEAN_AND_MEAN
-# #include <windows.h>
-# #undef WIN32_LEAN_AND_MEAN
-# #include <stdio.h>
-#
-# #ifndef __CYGWIN__
-# # ifdef __CYGWIN32__
-# # define __CYGWIN__ __CYGWIN32__
-# # endif
-# #endif
-#
-# #ifdef __cplusplus
-# extern "C" {
-# #endif
-# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
-# #ifdef __cplusplus
-# }
-# #endif
-#
-# #ifdef __CYGWIN__
-# #include <cygwin/cygwin_dll.h>
-# DECLARE_CYGWIN_DLL( DllMain );
-# #endif
-# HINSTANCE __hDllInstance_base;
-#
-# BOOL APIENTRY
-# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
-# {
-# __hDllInstance_base = hInst;
-# return TRUE;
-# }
-# /* ltdll.c ends here */
- # This is a source program that is used to create import libraries
- # on Windows for dlls which lack them. Don't remove nor modify the
- # starting and closing comments
-# /* impgen.c starts here */
-# /* Copyright (C) 1999-2000 Free Software Foundation, Inc.
-#
-# This file is part of GNU libtool.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-# */
-#
-# #include <stdio.h> /* for printf() */
-# #include <unistd.h> /* for open(), lseek(), read() */
-# #include <fcntl.h> /* for O_RDONLY, O_BINARY */
-# #include <string.h> /* for strdup() */
-#
-# /* O_BINARY isn't required (or even defined sometimes) under Unix */
-# #ifndef O_BINARY
-# #define O_BINARY 0
-# #endif
-#
-# static unsigned int
-# pe_get16 (fd, offset)
-# int fd;
-# int offset;
-# {
-# unsigned char b[2];
-# lseek (fd, offset, SEEK_SET);
-# read (fd, b, 2);
-# return b[0] + (b[1]<<8);
-# }
-#
-# static unsigned int
-# pe_get32 (fd, offset)
-# int fd;
-# int offset;
-# {
-# unsigned char b[4];
-# lseek (fd, offset, SEEK_SET);
-# read (fd, b, 4);
-# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# static unsigned int
-# pe_as32 (ptr)
-# void *ptr;
-# {
-# unsigned char *b = ptr;
-# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# int
-# main (argc, argv)
-# int argc;
-# char *argv[];
-# {
-# int dll;
-# unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
-# unsigned long export_rva, export_size, nsections, secptr, expptr;
-# unsigned long name_rvas, nexp;
-# unsigned char *expdata, *erva;
-# char *filename, *dll_name;
-#
-# filename = argv[1];
-#
-# dll = open(filename, O_RDONLY|O_BINARY);
-# if (dll < 1)
-# return 1;
-#
-# dll_name = filename;
-#
-# for (i=0; filename[i]; i++)
-# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':')
-# dll_name = filename + i +1;
-#
-# pe_header_offset = pe_get32 (dll, 0x3c);
-# opthdr_ofs = pe_header_offset + 4 + 20;
-# num_entries = pe_get32 (dll, opthdr_ofs + 92);
-#
-# if (num_entries < 1) /* no exports */
-# return 1;
-#
-# export_rva = pe_get32 (dll, opthdr_ofs + 96);
-# export_size = pe_get32 (dll, opthdr_ofs + 100);
-# nsections = pe_get16 (dll, pe_header_offset + 4 +2);
-# secptr = (pe_header_offset + 4 + 20 +
-# pe_get16 (dll, pe_header_offset + 4 + 16));
-#
-# expptr = 0;
-# for (i = 0; i < nsections; i++)
-# {
-# char sname[8];
-# unsigned long secptr1 = secptr + 40 * i;
-# unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
-# unsigned long vsize = pe_get32 (dll, secptr1 + 16);
-# unsigned long fptr = pe_get32 (dll, secptr1 + 20);
-# lseek(dll, secptr1, SEEK_SET);
-# read(dll, sname, 8);
-# if (vaddr <= export_rva && vaddr+vsize > export_rva)
-# {
-# expptr = fptr + (export_rva - vaddr);
-# if (export_rva + export_size > vaddr + vsize)
-# export_size = vsize - (export_rva - vaddr);
-# break;
-# }
-# }
-#
-# expdata = (unsigned char*)malloc(export_size);
-# lseek (dll, expptr, SEEK_SET);
-# read (dll, expdata, export_size);
-# erva = expdata - export_rva;
-#
-# nexp = pe_as32 (expdata+24);
-# name_rvas = pe_as32 (expdata+32);
-#
-# printf ("EXPORTS\n");
-# for (i = 0; i<nexp; i++)
-# {
-# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4);
-# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i);
-# }
-#
-# return 0;
-# }
-# /* impgen.c ends here */
-
-EOF
- ;;
- esac
-
- # We use sed instead of cat because bash on DJGPP gets confused if
- # if finds mixed CR/LF and LF-only lines. Since sed operates in
- # text mode, it properly converts lines to CR/LF. This bash problem
- # is reportedly fixed, but why not run on old versions too?
- sed '$q' "$ltmain" >> "${ofile}T" || (rm -f "${ofile}T"; exit 1)
-
- mv -f "${ofile}T" "$ofile" || \
- (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T")
- chmod +x "$ofile"
-fi
-
-])# _LT_AC_LTCONFIG_HACK
-
-# AC_LIBTOOL_DLOPEN - enable checks for dlopen support
-AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])])
-
-# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's
-AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])])
-
-# AC_ENABLE_SHARED - implement the --enable-shared flag
-# Usage: AC_ENABLE_SHARED[(DEFAULT)]
-# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
-# `yes'.
-AC_DEFUN([AC_ENABLE_SHARED],
-[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(shared,
-changequote(<<, >>)dnl
-<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case $enableval in
-yes) enable_shared=yes ;;
-no) enable_shared=no ;;
-*)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac],
-enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl
-])
-
-# AC_DISABLE_SHARED - set the default shared flag to --disable-shared
-AC_DEFUN([AC_DISABLE_SHARED],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_SHARED(no)])
-
-# AC_ENABLE_STATIC - implement the --enable-static flag
-# Usage: AC_ENABLE_STATIC[(DEFAULT)]
-# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
-# `yes'.
-AC_DEFUN([AC_ENABLE_STATIC],
-[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(static,
-changequote(<<, >>)dnl
-<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case $enableval in
-yes) enable_static=yes ;;
-no) enable_static=no ;;
-*)
- enable_static=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_static=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac],
-enable_static=AC_ENABLE_STATIC_DEFAULT)dnl
-])
-
-# AC_DISABLE_STATIC - set the default static flag to --disable-static
-AC_DEFUN([AC_DISABLE_STATIC],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_STATIC(no)])
-
-
-# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag
-# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)]
-# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
-# `yes'.
-AC_DEFUN([AC_ENABLE_FAST_INSTALL],
-[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(fast-install,
-changequote(<<, >>)dnl
-<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case $enableval in
-yes) enable_fast_install=yes ;;
-no) enable_fast_install=no ;;
-*)
- enable_fast_install=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_fast_install=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac],
-enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl
-])
-
-# AC_DISABLE_FAST_INSTALL - set the default to --disable-fast-install
-AC_DEFUN([AC_DISABLE_FAST_INSTALL],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_FAST_INSTALL(no)])
-
-# AC_LIBTOOL_PICMODE - implement the --with-pic flag
-# Usage: AC_LIBTOOL_PICMODE[(MODE)]
-# Where MODE is either `yes' or `no'. If omitted, it defaults to
-# `both'.
-AC_DEFUN([AC_LIBTOOL_PICMODE],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-pic_mode=ifelse($#,1,$1,default)])
-
-
-# AC_PATH_TOOL_PREFIX - find a file program which can recognise shared library
-AC_DEFUN([AC_PATH_TOOL_PREFIX],
-[AC_MSG_CHECKING([for $1])
-AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
-[case $MAGIC_CMD in
- /*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
- ;;
- ?:/*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path.
- ;;
- *)
- ac_save_MAGIC_CMD="$MAGIC_CMD"
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
-dnl $ac_dummy forces splitting on constant user-supplied paths.
-dnl POSIX.2 word splitting is done only on the output of word expansions,
-dnl not every word. This closes a longstanding sh security hole.
- ac_dummy="ifelse([$2], , $PATH, [$2])"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$1; then
- lt_cv_path_MAGIC_CMD="$ac_dir/$1"
- if test -n "$file_magic_test_file"; then
- case $deplibs_check_method in
- "file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- egrep "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS="$ac_save_ifs"
- MAGIC_CMD="$ac_save_MAGIC_CMD"
- ;;
-esac])
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-if test -n "$MAGIC_CMD"; then
- AC_MSG_RESULT($MAGIC_CMD)
-else
- AC_MSG_RESULT(no)
-fi
-])
-
-
-# AC_PATH_MAGIC - find a file program which can recognise a shared library
-AC_DEFUN([AC_PATH_MAGIC],
-[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl
-AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin:$PATH)
-if test -z "$lt_cv_path_MAGIC_CMD"; then
- if test -n "$ac_tool_prefix"; then
- AC_PATH_TOOL_PREFIX(file, /usr/bin:$PATH)
- else
- MAGIC_CMD=:
- fi
-fi
-])
-
-
-# AC_PROG_LD - find the path to the GNU or non-GNU linker
-AC_DEFUN([AC_PROG_LD],
-[AC_ARG_WITH(gnu-ld,
-[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
-test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl
-ac_prog=ld
-if test "$GCC" = yes; then
- # Check if gcc -print-prog-name=ld gives a path.
- AC_MSG_CHECKING([for ld used by GCC])
- case $host in
- *-*-mingw*)
- # gcc leaves a trailing carriage return which upsets mingw
- ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
- *)
- ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
- esac
- case $ac_prog in
- # Accept absolute paths.
- [[\\/]]* | [[A-Za-z]]:[[\\/]]*)
- re_direlt='/[[^/]][[^/]]*/\.\./'
- # Canonicalize the path of ld
- ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
- while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
- ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
- done
- test -z "$LD" && LD="$ac_prog"
- ;;
- "")
- # If it fails, then pretend we aren't using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
-elif test "$with_gnu_ld" = yes; then
- AC_MSG_CHECKING([for GNU ld])
-else
- AC_MSG_CHECKING([for non-GNU ld])
-fi
-AC_CACHE_VAL(lt_cv_path_LD,
-[if test -z "$LD"; then
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH; do
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- lt_cv_path_LD="$ac_dir/$ac_prog"
- # Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some GNU ld's only accept -v.
- # Break only if it was the GNU/non-GNU ld that we prefer.
- if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
- test "$with_gnu_ld" != no && break
- else
- test "$with_gnu_ld" != yes && break
- fi
- fi
- done
- IFS="$ac_save_ifs"
-else
- lt_cv_path_LD="$LD" # Let the user override the test with a path.
-fi])
-LD="$lt_cv_path_LD"
-if test -n "$LD"; then
- AC_MSG_RESULT($LD)
-else
- AC_MSG_RESULT(no)
-fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
-AC_PROG_LD_GNU
-])
-
-# AC_PROG_LD_GNU -
-AC_DEFUN([AC_PROG_LD_GNU],
-[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
-[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
-if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
- lt_cv_prog_gnu_ld=yes
-else
- lt_cv_prog_gnu_ld=no
-fi])
-with_gnu_ld=$lt_cv_prog_gnu_ld
-])
-
-# AC_PROG_LD_RELOAD_FLAG - find reload flag for linker
-# -- PORTME Some linkers may need a different reload flag.
-AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
-[AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag,
-[lt_cv_ld_reload_flag='-r'])
-reload_flag=$lt_cv_ld_reload_flag
-test -n "$reload_flag" && reload_flag=" $reload_flag"
-])
-
-# AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies
-# -- PORTME fill in with the dynamic library characteristics
-AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
-[AC_CACHE_CHECK([how to recognise dependant libraries],
-lt_cv_deplibs_check_method,
-[lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given egrep regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
-
-case $host_os in
-aix4* | aix5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-beos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-bsdi4*)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- lt_cv_file_magic_test_file=/shlib/libc.so
- ;;
-
-cygwin* | mingw* | pw32*)
- lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- ;;
-
-darwin* | rhapsody*)
- lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- case "$host_os" in
- rhapsody* | darwin1.[[012]])
- lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1`
- ;;
- *) # Darwin 1.3 on
- lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib'
- ;;
- esac
- ;;
-
-freebsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
- case $host_cpu in
- i*86 )
- # Not sure whether the presence of OpenBSD here was a mistake.
- # Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- ;;
- esac
- else
- lt_cv_deplibs_check_method=pass_all
- fi
- ;;
-
-gnu*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-hpux10.20*|hpux11*)
- lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libc.sl
- ;;
-
-irix5* | irix6*)
- case $host_os in
- irix5*)
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1"
- ;;
- *)
- case $LD in
- *-32|*"-32 ") libmagic=32-bit;;
- *-n32|*"-n32 ") libmagic=N32;;
- *-64|*"-64 ") libmagic=64-bit;;
- *) libmagic=never-match;;
- esac
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1"
- ;;
- esac
- lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*`
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-# This must be Linux ELF.
-linux-gnu*)
- case $host_cpu in
- alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* | s390* )
- lt_cv_deplibs_check_method=pass_all ;;
- *)
- # glibc up to 2.1.1 does not perform some relocations on ARM
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;;
- esac
- lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
- ;;
-
-netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
- lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so\.[[0-9]]+\.[[0-9]]+$'
- else
- lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so$'
- fi
- ;;
-
-newos6*)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libnls.so
- ;;
-
-openbsd*)
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object'
- else
- lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
- fi
- ;;
-
-osf3* | osf4* | osf5*)
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method='file_magic COFF format alpha shared library'
- lt_cv_file_magic_test_file=/shlib/libc.so
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sco3.2v5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-solaris*)
- lt_cv_deplibs_check_method=pass_all
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
-
-sysv5uw[[78]]* | sysv4*uw2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- case $host_vendor in
- motorola)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
- ;;
- ncr)
- lt_cv_deplibs_check_method=pass_all
- ;;
- sequent)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
- ;;
- sni)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
- esac
- ;;
-esac
-])
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-])
-
-
-# AC_PROG_NM - find the path to a BSD-compatible name lister
-AC_DEFUN([AC_PROG_NM],
-[AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl
-AC_MSG_CHECKING([for BSD-compatible nm])
-AC_CACHE_VAL(lt_cv_path_NM,
-[if test -n "$NM"; then
- # Let the user override the test.
- lt_cv_path_NM="$NM"
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
- test -z "$ac_dir" && ac_dir=.
- tmp_nm=$ac_dir/${ac_tool_prefix}nm
- if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- # Tru64's nm complains that /dev/null is an invalid object file
- if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then
- lt_cv_path_NM="$tmp_nm -B"
- break
- elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
- lt_cv_path_NM="$tmp_nm -p"
- break
- else
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
- fi
- fi
- done
- IFS="$ac_save_ifs"
- test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
-fi])
-NM="$lt_cv_path_NM"
-AC_MSG_RESULT([$NM])
-])
-
-# AC_CHECK_LIBM - check for math library
-AC_DEFUN([AC_CHECK_LIBM],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-LIBM=
-case $host in
-*-*-beos* | *-*-cygwin* | *-*-pw32*)
- # These system don't have libm
- ;;
-*-ncr-sysv4.3*)
- AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
- AC_CHECK_LIB(m, main, LIBM="$LIBM -lm")
- ;;
-*)
- AC_CHECK_LIB(m, main, LIBM="-lm")
- ;;
-esac
-])
-
-# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for
-# the libltdl convenience library and INCLTDL to the include flags for
-# the libltdl header and adds --enable-ltdl-convenience to the
-# configure arguments. Note that LIBLTDL and INCLTDL are not
-# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not
-# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed
-# with '${top_builddir}/' and INCLTDL will be prefixed with
-# '${top_srcdir}/' (note the single quotes!). If your package is not
-# flat and you're not using automake, define top_builddir and
-# top_srcdir appropriately in the Makefiles.
-AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
- case $enable_ltdl_convenience in
- no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
- "") enable_ltdl_convenience=yes
- ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
- esac
- LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
- INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
-])
-
-# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for
-# the libltdl installable library and INCLTDL to the include flags for
-# the libltdl header and adds --enable-ltdl-install to the configure
-# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is
-# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed
-# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will
-# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed
-# with '${top_srcdir}/' (note the single quotes!). If your package is
-# not flat and you're not using automake, define top_builddir and
-# top_srcdir appropriately in the Makefiles.
-# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
-AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
- AC_CHECK_LIB(ltdl, main,
- [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
- [if test x"$enable_ltdl_install" = xno; then
- AC_MSG_WARN([libltdl not installed, but installation disabled])
- else
- enable_ltdl_install=yes
- fi
- ])
- if test x"$enable_ltdl_install" = x"yes"; then
- ac_configure_args="$ac_configure_args --enable-ltdl-install"
- LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
- INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
- else
- ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
- LIBLTDL="-lltdl"
- INCLTDL=
- fi
-])
-
-# old names
-AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL])
-AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
-AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
-AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
-AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
-AC_DEFUN([AM_PROG_LD], [AC_PROG_LD])
-AC_DEFUN([AM_PROG_NM], [AC_PROG_NM])
-
-# This is just to silence aclocal about the macro not being used
-ifelse([AC_DISABLE_FAST_INSTALL])
-
diff --git a/boehm-gc/add_gc_prefix.c b/boehm-gc/add_gc_prefix.c
deleted file mode 100644
index 59515c7866e..00000000000
--- a/boehm-gc/add_gc_prefix.c
+++ /dev/null
@@ -1,20 +0,0 @@
-# include <stdio.h>
-# include "version.h"
-
-int main(argc, argv, envp)
-int argc;
-char ** argv;
-char ** envp;
-{
- int i;
-
- for (i = 1; i < argc; i++) {
- if (GC_ALPHA_VERSION == GC_NOT_ALPHA) {
- printf("gc%d.%d/%s ", GC_VERSION_MAJOR, GC_VERSION_MINOR, argv[i]);
- } else {
- printf("gc%d.%dalpha%d/%s ", GC_VERSION_MAJOR,
- GC_VERSION_MINOR, GC_ALPHA_VERSION, argv[i]);
- }
- }
- return(0);
-}
diff --git a/boehm-gc/allchblk.c b/boehm-gc/allchblk.c
index 793c468b928..5ddafdb3f7f 100644
--- a/boehm-gc/allchblk.c
+++ b/boehm-gc/allchblk.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1998-1999 by Silicon Graphics. All rights reserved.
@@ -14,11 +14,15 @@
* modified is included with the above copyright notice.
*/
-/* #define DEBUG */
-#include <stdio.h>
#include "private/gc_priv.h"
-GC_bool GC_use_entire_heap = 0;
+#include <stdio.h>
+
+#ifdef GC_USE_ENTIRE_HEAP
+ int GC_use_entire_heap = TRUE;
+#else
+ int GC_use_entire_heap = FALSE;
+#endif
/*
* Free heap blocks are kept on one of several free lists,
@@ -26,143 +30,144 @@ GC_bool GC_use_entire_heap = 0;
* Adjacent free blocks are coalesced.
*/
-
+
# define MAX_BLACK_LIST_ALLOC (2*HBLKSIZE)
- /* largest block we will allocate starting on a black */
- /* listed block. Must be >= HBLKSIZE. */
+ /* largest block we will allocate starting on a black */
+ /* listed block. Must be >= HBLKSIZE. */
# define UNIQUE_THRESHOLD 32
- /* Sizes up to this many HBLKs each have their own free list */
+ /* Sizes up to this many HBLKs each have their own free list */
# define HUGE_THRESHOLD 256
- /* Sizes of at least this many heap blocks are mapped to a */
- /* single free list. */
+ /* Sizes of at least this many heap blocks are mapped to a */
+ /* single free list. */
# define FL_COMPRESSION 8
- /* In between sizes map this many distinct sizes to a single */
- /* bin. */
-
-# define N_HBLK_FLS (HUGE_THRESHOLD - UNIQUE_THRESHOLD)/FL_COMPRESSION \
- + UNIQUE_THRESHOLD
-
-struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
-
-#ifndef USE_MUNMAP
-
+ /* In between sizes map this many distinct sizes to a single */
+ /* bin. */
+
+# define N_HBLK_FLS ((HUGE_THRESHOLD - UNIQUE_THRESHOLD) / FL_COMPRESSION \
+ + UNIQUE_THRESHOLD)
+
+#ifndef GC_GCJ_SUPPORT
+ STATIC
+#endif
+ struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
+ /* List of completely empty heap blocks */
+ /* Linked through hb_next field of */
+ /* header structure associated with */
+ /* block. Remains externally visible */
+ /* as used by GNU GCJ currently. */
+
+#ifndef GC_GCJ_SUPPORT
+ STATIC
+#endif
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? */
-# ifdef __GNUC__
- __inline__
-# endif
- static GC_bool GC_enough_large_bytes_left(bytes,n)
- word bytes;
- int n;
- {
- int i;
- for (i = N_HBLK_FLS; i >= n; --i) {
- bytes += GC_free_bytes[i];
- if (bytes > GC_max_large_allocd_bytes) return TRUE;
- }
- return FALSE;
- }
+ /* Number of free bytes on each list. Remains visible to GCJ. */
-# define INCR_FREE_BYTES(n, b) GC_free_bytes[n] += (b);
-
-# define FREE_ASSERT(e) GC_ASSERT(e)
-
-#else /* USE_MUNMAP */
-
-# define INCR_FREE_BYTES(n, b)
-# define FREE_ASSERT(e)
+/* Return the largest n such that the number of free bytes on lists */
+/* n .. N_HBLK_FLS is greater or equal to GC_max_large_allocd_bytes */
+/* minus GC_large_allocd_bytes. If there is no such n, return 0. */
+GC_INLINE int GC_enough_large_bytes_left(void)
+{
+ int n;
+ word bytes = GC_large_allocd_bytes;
-#endif /* USE_MUNMAP */
+ 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 0;
+}
/* Map a number of blocks to the appropriate large block free list index. */
-int GC_hblk_fl_from_blocks(blocks_needed)
-word blocks_needed;
+STATIC int GC_hblk_fl_from_blocks(word blocks_needed)
{
- if (blocks_needed <= UNIQUE_THRESHOLD) return blocks_needed;
+ if (blocks_needed <= UNIQUE_THRESHOLD) return (int)blocks_needed;
if (blocks_needed >= HUGE_THRESHOLD) return N_HBLK_FLS;
- return (blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
- + UNIQUE_THRESHOLD;
-
+ return (int)(blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
+ + UNIQUE_THRESHOLD;
+
}
-# define PHDR(hhdr) HDR(hhdr -> hb_prev)
-# define NHDR(hhdr) HDR(hhdr -> hb_next)
+# define PHDR(hhdr) HDR((hhdr) -> hb_prev)
+# define NHDR(hhdr) HDR((hhdr) -> hb_next)
# ifdef USE_MUNMAP
# define IS_MAPPED(hhdr) (((hhdr) -> hb_flags & WAS_UNMAPPED) == 0)
-# else /* !USE_MMAP */
-# define IS_MAPPED(hhdr) 1
-# endif /* USE_MUNMAP */
+# else
+# define IS_MAPPED(hhdr) TRUE
+# endif /* !USE_MUNMAP */
+
+#if !defined(NO_DEBUGGING) || defined(GC_ASSERTIONS)
+ /* Should return the same value as GC_large_free_bytes. */
+ GC_INNER word GC_compute_large_free_bytes(void)
+ {
+ struct hblk * h;
+ hdr * hhdr;
+ word total_free = 0;
+ unsigned i;
+
+ for (i = 0; i <= N_HBLK_FLS; ++i) {
+ for (h = GC_hblkfreelist[i]; h != 0; h = hhdr->hb_next) {
+ hhdr = HDR(h);
+ total_free += hhdr->hb_sz;
+ }
+ }
+ return total_free;
+ }
+#endif /* !NO_DEBUGGING || GC_ASSERTIONS */
# if !defined(NO_DEBUGGING)
-void GC_print_hblkfreelist()
+void GC_print_hblkfreelist(void)
{
struct hblk * h;
- word total_free = 0;
hdr * hhdr;
- word sz;
- int i;
-
+ unsigned i;
+ word total;
+
for (i = 0; i <= N_HBLK_FLS; ++i) {
h = GC_hblkfreelist[i];
-# ifdef USE_MUNMAP
- if (0 != h) GC_printf1("Free list %ld:\n",
- (unsigned long)i);
-# else
- if (0 != h) GC_printf2("Free list %ld (Total size %ld):\n",
- (unsigned long)i,
- (unsigned long)GC_free_bytes[i]);
-# endif
+ if (0 != h) GC_printf("Free list %u (total size %lu):\n",
+ i, (unsigned long)GC_free_bytes[i]);
while (h != 0) {
hhdr = HDR(h);
- sz = hhdr -> hb_sz;
- GC_printf2("\t0x%lx size %lu ", (unsigned long)h, (unsigned long)sz);
- total_free += sz;
- if (GC_is_black_listed(h, HBLKSIZE) != 0) {
- GC_printf0("start black listed\n");
- } else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0) {
- GC_printf0("partially black listed\n");
- } else {
- GC_printf0("not black listed\n");
- }
+ GC_printf("\t%p size %lu %s black listed\n",
+ (void *)h, (unsigned long) hhdr -> hb_sz,
+ GC_is_black_listed(h, HBLKSIZE) != 0 ? "start" :
+ GC_is_black_listed(h, hhdr -> hb_sz) != 0 ? "partially" :
+ "not");
h = hhdr -> hb_next;
}
}
-# ifndef USE_MUNMAP
- if (total_free != GC_large_free_bytes) {
- GC_printf1("GC_large_free_bytes = %lu (INCONSISTENT!!)\n",
- (unsigned long) GC_large_free_bytes);
- }
-# endif
- GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free);
+ GC_printf("GC_large_free_bytes: %lu\n",
+ (unsigned long)GC_large_free_bytes);
+
+ if ((total = GC_compute_large_free_bytes()) != GC_large_free_bytes)
+ GC_err_printf("GC_large_free_bytes INCONSISTENT!! Should be: %lu\n",
+ (unsigned long)total);
}
/* Return the free list index on which the block described by the header */
-/* appears, or -1 if it appears nowhere. */
-int free_list_index_of(wanted)
-hdr * wanted;
+/* appears, or -1 if it appears nowhere. */
+static int free_list_index_of(hdr *wanted)
{
struct hblk * h;
hdr * hhdr;
int i;
-
+
for (i = 0; i <= N_HBLK_FLS; ++i) {
h = GC_hblkfreelist[i];
while (h != 0) {
hhdr = HDR(h);
- if (hhdr == wanted) return i;
+ if (hhdr == wanted) return i;
h = hhdr -> hb_next;
}
}
return -1;
}
-void GC_dump_regions()
+void GC_dump_regions(void)
{
unsigned i;
ptr_t start, end;
@@ -170,276 +175,302 @@ void GC_dump_regions()
size_t bytes;
hdr *hhdr;
for (i = 0; i < GC_n_heap_sects; ++i) {
- start = GC_heap_sects[i].hs_start;
- bytes = GC_heap_sects[i].hs_bytes;
- end = start + bytes;
- /* Merge in contiguous sections. */
- while (i+1 < GC_n_heap_sects && GC_heap_sects[i+1].hs_start == end) {
- ++i;
- end = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
- }
- GC_printf2("***Section from 0x%lx to 0x%lx\n", start, end);
- for (p = start; p < end;) {
- hhdr = HDR(p);
- GC_printf1("\t0x%lx ", (unsigned long)p);
- if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
- GC_printf1("Missing header!!(%ld)\n", hhdr);
- p += HBLKSIZE;
- continue;
- }
- if (HBLK_IS_FREE(hhdr)) {
+ start = GC_heap_sects[i].hs_start;
+ bytes = GC_heap_sects[i].hs_bytes;
+ end = start + bytes;
+ /* Merge in contiguous sections. */
+ while (i+1 < GC_n_heap_sects && GC_heap_sects[i+1].hs_start == end) {
+ ++i;
+ end = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
+ }
+ GC_printf("***Section from %p to %p\n", start, end);
+ for (p = start; (word)p < (word)end; ) {
+ hhdr = HDR(p);
+ if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+ GC_printf("\t%p Missing header!!(%p)\n", p, (void *)hhdr);
+ p += HBLKSIZE;
+ continue;
+ }
+ if (HBLK_IS_FREE(hhdr)) {
int correct_index = GC_hblk_fl_from_blocks(
- divHBLKSZ(hhdr -> hb_sz));
- int actual_index;
-
- GC_printf1("\tfree block of size 0x%lx bytes",
- (unsigned long)(hhdr -> hb_sz));
- if (IS_MAPPED(hhdr)) {
- GC_printf0("\n");
- } else {
- GC_printf0("(unmapped)\n");
- }
- actual_index = free_list_index_of(hhdr);
- if (-1 == actual_index) {
- GC_printf1("\t\tBlock not on free list %ld!!\n",
- correct_index);
- } else if (correct_index != actual_index) {
- GC_printf2("\t\tBlock on list %ld, should be on %ld!!\n",
- actual_index, correct_index);
- }
- p += hhdr -> hb_sz;
- } else {
- GC_printf1("\tused for blocks of size 0x%lx bytes\n",
- (unsigned long)WORDS_TO_BYTES(hhdr -> hb_sz));
- p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
- }
- }
+ divHBLKSZ(hhdr -> hb_sz));
+ int actual_index;
+
+ GC_printf("\t%p\tfree block of size 0x%lx bytes%s\n", p,
+ (unsigned long)(hhdr -> hb_sz),
+ IS_MAPPED(hhdr) ? "" : " (unmapped)");
+ actual_index = free_list_index_of(hhdr);
+ if (-1 == actual_index) {
+ GC_printf("\t\tBlock not on free list %d!!\n",
+ correct_index);
+ } else if (correct_index != actual_index) {
+ GC_printf("\t\tBlock on list %d, should be on %d!!\n",
+ actual_index, correct_index);
+ }
+ p += hhdr -> hb_sz;
+ } else {
+ GC_printf("\t%p\tused for blocks of size 0x%lx bytes\n", p,
+ (unsigned long)(hhdr -> hb_sz));
+ p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
+ }
+ }
}
}
# endif /* NO_DEBUGGING */
-/* Initialize hdr for a block containing the indicated size and */
-/* kind of objects. */
-/* Return FALSE on failure. */
-static GC_bool setup_header(hhdr, sz, kind, flags)
-register hdr * hhdr;
-word sz; /* object size in words */
-int kind;
-unsigned char flags;
+/* Initialize hdr for a block containing the indicated size and */
+/* kind of objects. */
+/* Return FALSE on failure. */
+static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
+ int kind, unsigned flags)
{
- register word descr;
-
- /* Add description of valid object pointers */
- if (!GC_add_map_entry(sz)) return(FALSE);
- hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
-
+ word descr;
+# ifndef MARK_BIT_PER_OBJ
+ size_t granules;
+# endif
+
+# ifdef ENABLE_DISCLAIM
+ if (GC_obj_kinds[kind].ok_disclaim_proc)
+ flags |= HAS_DISCLAIM;
+ if (GC_obj_kinds[kind].ok_mark_unconditionally)
+ flags |= MARK_UNCONDITIONALLY;
+# endif
+
/* Set size, kind and mark proc fields */
- hhdr -> hb_sz = sz;
- hhdr -> hb_obj_kind = kind;
- hhdr -> hb_flags = flags;
+ hhdr -> hb_sz = byte_sz;
+ hhdr -> hb_obj_kind = (unsigned char)kind;
+ hhdr -> hb_flags = (unsigned char)flags;
+ hhdr -> hb_block = block;
descr = GC_obj_kinds[kind].ok_descriptor;
- if (GC_obj_kinds[kind].ok_relocate_descr) descr += WORDS_TO_BYTES(sz);
+ if (GC_obj_kinds[kind].ok_relocate_descr) descr += byte_sz;
hhdr -> hb_descr = descr;
-
+
+# ifdef MARK_BIT_PER_OBJ
+ /* Set hb_inv_sz as portably as possible. */
+ /* We set it to the smallest value such that sz * inv_sz > 2**32 */
+ /* This may be more precision than necessary. */
+ if (byte_sz > MAXOBJBYTES) {
+ hhdr -> hb_inv_sz = LARGE_INV_SZ;
+ } else {
+ word inv_sz;
+
+# if CPP_WORDSZ == 64
+ inv_sz = ((word)1 << 32)/byte_sz;
+ if (((inv_sz*byte_sz) >> 32) == 0) ++inv_sz;
+# else /* 32 bit words */
+ GC_ASSERT(byte_sz >= 4);
+ inv_sz = ((unsigned)1 << 31)/byte_sz;
+ inv_sz *= 2;
+ while (inv_sz*byte_sz > byte_sz) ++inv_sz;
+# endif
+ hhdr -> hb_inv_sz = inv_sz;
+ }
+# else /* MARK_BIT_PER_GRANULE */
+ hhdr -> hb_large_block = (unsigned char)(byte_sz > MAXOBJBYTES);
+ granules = BYTES_TO_GRANULES(byte_sz);
+ if (EXPECT(!GC_add_map_entry(granules), FALSE)) {
+ /* Make it look like a valid block. */
+ hhdr -> hb_sz = HBLKSIZE;
+ hhdr -> hb_descr = 0;
+ hhdr -> hb_large_block = TRUE;
+ hhdr -> hb_map = 0;
+ return FALSE;
+ } else {
+ size_t index = (hhdr -> hb_large_block? 0 : granules);
+ hhdr -> hb_map = GC_obj_map[index];
+ }
+# endif /* MARK_BIT_PER_GRANULE */
+
/* Clear mark bits */
- GC_clear_hdr_marks(hhdr);
-
+ GC_clear_hdr_marks(hhdr);
+
hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
return(TRUE);
}
-#define FL_UNKNOWN -1
-/*
- * Remove hhdr from the appropriate free list.
- * We assume it is on the nth free list, or on the size
- * appropriate free list if n is FL_UNKNOWN.
- */
-void GC_remove_from_fl(hhdr, n)
-hdr * hhdr;
-int n;
+/* Remove hhdr from the free list (it is assumed to specified by index). */
+STATIC void GC_remove_from_fl_at(hdr *hhdr, int index)
{
- int index;
-
GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
-# ifndef USE_MUNMAP
- /* We always need index to mainatin free counts. */
- if (FL_UNKNOWN == n) {
- index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
- } else {
- index = n;
- }
-# endif
if (hhdr -> hb_prev == 0) {
-# ifdef USE_MUNMAP
- if (FL_UNKNOWN == n) {
- index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
- } else {
- index = n;
- }
-# endif
- GC_ASSERT(HDR(GC_hblkfreelist[index]) == hhdr);
- GC_hblkfreelist[index] = hhdr -> hb_next;
+ GC_ASSERT(HDR(GC_hblkfreelist[index]) == hhdr);
+ GC_hblkfreelist[index] = hhdr -> hb_next;
} else {
- hdr *phdr;
- GET_HDR(hhdr -> hb_prev, phdr);
- phdr -> hb_next = hhdr -> hb_next;
+ hdr *phdr;
+ GET_HDR(hhdr -> hb_prev, phdr);
+ phdr -> hb_next = hhdr -> hb_next;
}
- INCR_FREE_BYTES(index, - (signed_word)(hhdr -> hb_sz));
- FREE_ASSERT(GC_free_bytes[index] >= 0);
+ /* We always need index to maintain free counts. */
+ GC_ASSERT(GC_free_bytes[index] >= hhdr -> hb_sz);
+ GC_free_bytes[index] -= hhdr -> hb_sz;
if (0 != hhdr -> hb_next) {
- hdr * nhdr;
- GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
- GET_HDR(hhdr -> hb_next, nhdr);
- nhdr -> hb_prev = hhdr -> hb_prev;
+ hdr * nhdr;
+ GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
+ GET_HDR(hhdr -> hb_next, nhdr);
+ nhdr -> hb_prev = hhdr -> hb_prev;
}
}
-/*
- * Return a pointer to the free block ending just before h, if any.
- */
-struct hblk * GC_free_block_ending_at(h)
-struct hblk *h;
+/* Remove hhdr from the appropriate free list (we assume it is on the */
+/* size-appropriate free list). */
+GC_INLINE void GC_remove_from_fl(hdr *hhdr)
+{
+ GC_remove_from_fl_at(hhdr, GC_hblk_fl_from_blocks(divHBLKSZ(hhdr->hb_sz)));
+}
+
+/* Return a pointer to the free block ending just before h, if any. */
+STATIC struct hblk * GC_free_block_ending_at(struct hblk *h)
{
struct hblk * p = h - 1;
hdr * phdr;
GET_HDR(p, phdr);
while (0 != phdr && IS_FORWARDING_ADDR_OR_NIL(phdr)) {
- p = FORWARDED_ADDR(p,phdr);
- phdr = HDR(p);
+ p = FORWARDED_ADDR(p,phdr);
+ phdr = HDR(p);
}
if (0 != phdr) {
if(HBLK_IS_FREE(phdr)) {
- return p;
- } else {
- return 0;
- }
+ return p;
+ } else {
+ return 0;
+ }
}
p = GC_prev_block(h - 1);
if (0 != p) {
phdr = HDR(p);
if (HBLK_IS_FREE(phdr) && (ptr_t)p + phdr -> hb_sz == (ptr_t)h) {
- return p;
+ return p;
}
}
return 0;
}
-/*
- * Add hhdr to the appropriate free list.
- * We maintain individual free lists sorted by address.
- */
-void GC_add_to_fl(h, hhdr)
-struct hblk *h;
-hdr * hhdr;
+/* Add hhdr to the appropriate free list. */
+/* We maintain individual free lists sorted by address. */
+STATIC 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;
- INCR_FREE_BYTES(index, hhdr -> hb_sz);
- FREE_ASSERT(GC_free_bytes[index] <= GC_large_free_bytes)
+ GC_free_bytes[index] += hhdr -> hb_sz;
+ GC_ASSERT(GC_free_bytes[index] <= GC_large_free_bytes);
hhdr -> hb_next = second;
hhdr -> hb_prev = 0;
if (0 != second) {
GET_HDR(second, second_hdr);
second_hdr -> hb_prev = h;
}
- GC_invalidate_map(hhdr);
+ hhdr -> hb_flags |= FREE_BLK;
}
#ifdef USE_MUNMAP
+# ifndef MUNMAP_THRESHOLD
+# define MUNMAP_THRESHOLD 6
+# endif
+
+GC_INNER int GC_unmap_threshold = MUNMAP_THRESHOLD;
+
/* Unmap blocks that haven't been recently touched. This is the only way */
-/* way blocks are ever unmapped. */
-void GC_unmap_old(void)
+/* way blocks are ever unmapped. */
+GC_INNER void GC_unmap_old(void)
{
struct hblk * h;
hdr * hhdr;
- word sz;
- unsigned short last_rec, threshold;
int i;
-# define UNMAP_THRESHOLD 6
-
+
+ if (GC_unmap_threshold == 0)
+ return; /* unmapping disabled */
+
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);
- last_rec = hhdr -> hb_last_reclaimed;
- if ((last_rec > GC_gc_no || last_rec < threshold)
- && threshold < GC_gc_no /* not recently wrapped */) {
- sz = hhdr -> hb_sz;
- GC_unmap((ptr_t)h, sz);
- hhdr -> hb_flags |= WAS_UNMAPPED;
- }
+ if (!IS_MAPPED(hhdr)) continue;
+
+ if ((unsigned short)GC_gc_no - hhdr -> hb_last_reclaimed >
+ (unsigned short)GC_unmap_threshold) {
+ GC_unmap((ptr_t)h, hhdr -> hb_sz);
+ hhdr -> hb_flags |= WAS_UNMAPPED;
+ }
}
- }
+ }
}
-/* Merge all unmapped blocks that are adjacent to other free */
-/* blocks. This may involve remapping, since all blocks are either */
-/* fully mapped or fully unmapped. */
-void GC_merge_unmapped(void)
+/* Merge all unmapped blocks that are adjacent to other free */
+/* blocks. This may involve remapping, since all blocks are either */
+/* fully mapped or fully unmapped. */
+GC_INNER void GC_merge_unmapped(void)
{
struct hblk * h, *next;
hdr * hhdr, *nexthdr;
word size, nextsize;
int i;
-
+
for (i = 0; i <= N_HBLK_FLS; ++i) {
h = GC_hblkfreelist[i];
while (h != 0) {
- GET_HDR(h, hhdr);
- size = hhdr->hb_sz;
- 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 (IS_MAPPED(hhdr)) {
- GC_ASSERT(!IS_MAPPED(nexthdr));
- /* make both consistent, so that we can merge */
- if (size > nextsize) {
- GC_remap((ptr_t)next, nextsize);
- } else {
- GC_unmap((ptr_t)h, size);
- hhdr -> hb_flags |= WAS_UNMAPPED;
- }
- } else if (IS_MAPPED(nexthdr)) {
- GC_ASSERT(!IS_MAPPED(hhdr));
- if (size > nextsize) {
- GC_unmap((ptr_t)next, nextsize);
- } else {
- GC_remap((ptr_t)h, size);
- hhdr -> hb_flags &= ~WAS_UNMAPPED;
- hhdr -> hb_last_reclaimed = nexthdr -> hb_last_reclaimed;
- }
- } else {
- /* Unmap any gap in the middle */
- GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nexthdr -> hb_sz);
- }
- /* If they are both unmapped, we merge, but leave unmapped. */
- GC_remove_from_fl(hhdr, i);
- GC_remove_from_fl(nexthdr, FL_UNKNOWN);
- hhdr -> hb_sz += nexthdr -> hb_sz;
- GC_remove_header(next);
- GC_add_to_fl(h, hhdr);
- /* Start over at beginning of list */
- h = GC_hblkfreelist[i];
- } else /* not mergable with successor */ {
- h = hhdr -> hb_next;
- }
+ GET_HDR(h, hhdr);
+ size = hhdr->hb_sz;
+ next = (struct hblk *)((word)h + size);
+ GET_HDR(next, nexthdr);
+ /* Coalesce with successor, if possible */
+ if (0 != nexthdr && HBLK_IS_FREE(nexthdr)
+ && (signed_word) (size + (nextsize = nexthdr->hb_sz)) > 0
+ /* no pot. overflow */) {
+ /* Note that we usually try to avoid adjacent free blocks */
+ /* that are either both mapped or both unmapped. But that */
+ /* isn't guaranteed to hold since we remap blocks when we */
+ /* split them, and don't merge at that point. It may also */
+ /* not hold if the merged block would be too big. */
+ if (IS_MAPPED(hhdr) && !IS_MAPPED(nexthdr)) {
+ /* make both consistent, so that we can merge */
+ if (size > nextsize) {
+ GC_remap((ptr_t)next, nextsize);
+ } else {
+ GC_unmap((ptr_t)h, size);
+ GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize);
+ hhdr -> hb_flags |= WAS_UNMAPPED;
+ }
+ } else if (IS_MAPPED(nexthdr) && !IS_MAPPED(hhdr)) {
+ if (size > nextsize) {
+ GC_unmap((ptr_t)next, nextsize);
+ GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize);
+ } else {
+ GC_remap((ptr_t)h, size);
+ hhdr -> hb_flags &= ~WAS_UNMAPPED;
+ hhdr -> hb_last_reclaimed = nexthdr -> hb_last_reclaimed;
+ }
+ } else if (!IS_MAPPED(hhdr) && !IS_MAPPED(nexthdr)) {
+ /* Unmap any gap in the middle */
+ GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize);
+ }
+ /* If they are both unmapped, we merge, but leave unmapped. */
+ GC_remove_from_fl_at(hhdr, i);
+ GC_remove_from_fl(nexthdr);
+ hhdr -> hb_sz += nexthdr -> hb_sz;
+ GC_remove_header(next);
+ GC_add_to_fl(h, hhdr);
+ /* Start over at beginning of list */
+ h = GC_hblkfreelist[i];
+ } else /* not mergable with successor */ {
+ h = hhdr -> hb_next;
+ }
} /* while (h != 0) ... */
} /* for ... */
}
@@ -455,31 +486,28 @@ void GC_merge_unmapped(void)
* The header for the returned block must be set up by the caller.
* If the return value is not 0, then hhdr is the header for it.
*/
-struct hblk * GC_get_first_part(h, hhdr, bytes, index)
-struct hblk *h;
-hdr * hhdr;
-word bytes;
-int index;
+STATIC struct hblk * GC_get_first_part(struct hblk *h, hdr *hhdr,
+ size_t bytes, int index)
{
word total_size = hhdr -> hb_sz;
struct hblk * rest;
hdr * rest_hdr;
GC_ASSERT((total_size & (HBLKSIZE-1)) == 0);
- GC_remove_from_fl(hhdr, index);
+ GC_remove_from_fl_at(hhdr, index);
if (total_size == bytes) return h;
rest = (struct hblk *)((word)h + bytes);
rest_hdr = GC_install_header(rest);
if (0 == rest_hdr) {
- /* This may be very bad news ... */
- WARN("Header allocation failed: Dropping block.\n", 0);
- return(0);
+ /* FIXME: This is likely to be very bad news ... */
+ WARN("Header allocation failed: Dropping block.\n", 0);
+ return(0);
}
rest_hdr -> hb_sz = total_size - bytes;
rest_hdr -> hb_flags = 0;
# ifdef GC_ASSERTIONS
/* Mark h not free, to avoid assertion about adjacent free blocks. */
- hhdr -> hb_map = 0;
+ hhdr -> hb_flags &= ~FREE_BLK;
# endif
GC_add_to_fl(rest, rest_hdr);
return h;
@@ -494,15 +522,13 @@ int index;
*
* Nhdr is not completely filled in, since it is about to allocated.
* It may in fact end up on the wrong free list for its size.
+ * That's not a disaster, since n is about to be allocated
+ * by our caller.
* (Hence adding it to a free list is silly. But this path is hopefully
* rare enough that it doesn't matter. The code is cleaner this way.)
*/
-void GC_split_block(h, hhdr, n, nhdr, index)
-struct hblk *h;
-hdr * hhdr;
-struct hblk *n;
-hdr * nhdr;
-int index; /* Index of free list */
+STATIC void GC_split_block(struct hblk *h, hdr *hhdr, struct hblk *n,
+ hdr *nhdr, int index /* Index of free list */)
{
word total_size = hhdr -> hb_sz;
word h_size = (word)n - (word)h;
@@ -515,259 +541,281 @@ int index; /* Index of free list */
nhdr -> hb_sz = total_size - h_size;
nhdr -> hb_flags = 0;
if (0 != prev) {
- HDR(prev) -> hb_next = n;
+ HDR(prev) -> hb_next = n;
} else {
GC_hblkfreelist[index] = n;
}
if (0 != next) {
- HDR(next) -> hb_prev = n;
+ HDR(next) -> hb_prev = n;
}
- INCR_FREE_BYTES(index, -(signed_word)h_size);
- FREE_ASSERT(GC_free_bytes[index] > 0);
-# ifdef GC_ASSERTIONS
- nhdr -> hb_map = 0; /* Don't fail test for consecutive */
- /* free blocks in GC_add_to_fl. */
-# endif
+ GC_ASSERT(GC_free_bytes[index] > h_size);
+ GC_free_bytes[index] -= h_size;
# ifdef USE_MUNMAP
- hhdr -> hb_last_reclaimed = GC_gc_no;
+ hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
# endif
hhdr -> hb_sz = h_size;
GC_add_to_fl(h, hhdr);
- GC_invalidate_map(nhdr);
+ nhdr -> hb_flags |= FREE_BLK;
}
-
-struct hblk * GC_allochblk_nth();
+
+STATIC struct hblk *
+GC_allochblk_nth(size_t sz /* bytes */, int kind, unsigned flags, int n,
+ int may_split);
+#define AVOID_SPLIT_REMAPPED 2
/*
* Allocate (and return pointer to) a heap block
- * for objects of size sz words, searching the nth free list.
+ * for objects of size sz bytes, searching the nth free list.
*
* NOTE: We set obj_map field in header correctly.
* Caller is responsible for building an object freelist in block.
*
- * Unlike older versions of the collectors, the client is responsible
- * for clearing the block, if necessary.
+ * The client is responsible for clearing the block, if necessary.
*/
-struct hblk *
-GC_allochblk(sz, kind, flags)
-word sz;
-int kind;
-unsigned flags; /* IGNORE_OFF_PAGE or 0 */
+GC_INNER struct hblk *
+GC_allochblk(size_t sz, int kind, unsigned flags/* IGNORE_OFF_PAGE or 0 */)
{
- word blocks = OBJ_SZ_TO_BLOCKS(sz);
- int start_list = GC_hblk_fl_from_blocks(blocks);
- int i;
- for (i = start_list; i <= N_HBLK_FLS; ++i) {
- struct hblk * result = GC_allochblk_nth(sz, kind, flags, i);
- if (0 != result) {
- return result;
- }
+ word blocks;
+ int start_list;
+ struct hblk *result;
+ int may_split;
+ 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;
}
- return 0;
+ start_list = GC_hblk_fl_from_blocks(blocks);
+ /* Try for an exact match first. */
+ result = GC_allochblk_nth(sz, kind, flags, start_list, FALSE);
+ if (0 != result) return result;
+
+ may_split = TRUE;
+ if (GC_use_entire_heap || GC_dont_gc
+ || USED_HEAP_SIZE < GC_requested_heapsize
+ || GC_incremental || !GC_should_collect()) {
+ /* Should use more of the heap, even if it requires splitting. */
+ split_limit = N_HBLK_FLS;
+ } 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();
+# ifdef USE_MUNMAP
+ if (split_limit > 0)
+ may_split = AVOID_SPLIT_REMAPPED;
+# endif
+ }
+ if (start_list < UNIQUE_THRESHOLD) {
+ /* No reason to try start_list again, since all blocks are exact */
+ /* matches. */
+ ++start_list;
+ }
+ for (; start_list <= split_limit; ++start_list) {
+ result = GC_allochblk_nth(sz, kind, flags, start_list, may_split);
+ if (0 != result)
+ break;
+ }
+ return result;
}
-/*
- * The same, but with search restricted to nth free list.
- */
-struct hblk *
-GC_allochblk_nth(sz, kind, flags, n)
-word sz;
-int kind;
-unsigned char flags; /* IGNORE_OFF_PAGE or 0 */
-int n;
+
+STATIC long GC_large_alloc_warn_suppressed = 0;
+ /* Number of warnings suppressed so far. */
+
+/* The same, but with search restricted to nth free list. Flags is */
+/* IGNORE_OFF_PAGE or zero. sz is in bytes. The may_split flag */
+/* indicates whether it is OK to split larger blocks (if set to */
+/* AVOID_SPLIT_REMAPPED then memory remapping followed by splitting */
+/* should be generally avoided). */
+STATIC struct hblk *
+GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split)
{
- register struct hblk *hbp;
- register hdr * hhdr; /* Header corr. to hbp */
- register struct hblk *thishbp;
- register hdr * thishdr; /* Header corr. to hbp */
+ struct hblk *hbp;
+ hdr * hhdr; /* Header corr. to hbp */
+ /* Initialized after loop if hbp !=0 */
+ /* Gcc uninitialized use warning is bogus. */
+ struct hblk *thishbp;
+ hdr * thishdr; /* Header corr. to hbp */
signed_word size_needed; /* number of bytes in requested objects */
- signed_word size_avail; /* bytes available in this block */
+ signed_word size_avail; /* bytes available in this block */
size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz);
/* search for a big enough block in free list */
- hbp = GC_hblkfreelist[n];
- for(; 0 != hbp; hbp = hhdr -> hb_next) {
- GET_HDR(hbp, hhdr);
- size_avail = hhdr->hb_sz;
- if (size_avail < size_needed) continue;
- if (!GC_use_entire_heap
- && size_avail != size_needed
- && 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_mem_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. */
- {
- signed_word next_size;
-
- thishbp = hhdr -> hb_next;
- if (thishbp != 0) {
- 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;
- }
- }
- }
- if ( !IS_UNCOLLECTABLE(kind) &&
- (kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC)) {
- struct hblk * lasthbp = hbp;
- ptr_t search_end = (ptr_t)hbp + size_avail - size_needed;
- signed_word orig_avail = size_avail;
- signed_word eff_size_needed = ((flags & IGNORE_OFF_PAGE)?
- HBLKSIZE
- : size_needed);
-
-
- while ((ptr_t)lasthbp <= search_end
- && (thishbp = GC_is_black_listed(lasthbp,
- (word)eff_size_needed))
- != 0) {
- lasthbp = thishbp;
- }
- size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
- thishbp = lasthbp;
- if (size_avail >= size_needed) {
- if (thishbp != hbp &&
- 0 != (thishdr = GC_install_header(thishbp))) {
- /* Make sure it's mapped before we mangle it. */
-# ifdef USE_MUNMAP
- if (!IS_MAPPED(hhdr)) {
- GC_remap((ptr_t)hbp, hhdr -> hb_sz);
- hhdr -> hb_flags &= ~WAS_UNMAPPED;
- }
-# endif
- /* Split the block at thishbp */
- GC_split_block(hbp, hhdr, thishbp, thishdr, n);
- /* Advance to thishbp */
- hbp = thishbp;
- hhdr = thishdr;
- /* We must now allocate thishbp, since it may */
- /* be on the wrong free list. */
- }
- } else if (size_needed > (signed_word)BL_LIMIT
- && orig_avail - size_needed
- > (signed_word)BL_LIMIT) {
- /* Punt, since anything else risks unreasonable heap growth. */
- if (++GC_large_alloc_warn_suppressed
- >= GC_large_alloc_warn_interval) {
- WARN("Repeated allocation of very large block "
- "(appr. size %ld):\n"
- "\tMay lead to memory leak and poor performance.\n",
- size_needed);
- GC_large_alloc_warn_suppressed = 0;
- }
- size_avail = orig_avail;
- } else if (size_avail == 0 && size_needed == HBLKSIZE
- && IS_MAPPED(hhdr)) {
- if (!GC_find_leak) {
- static unsigned count = 0;
-
- /* The block is completely blacklisted. We need */
- /* to drop some such blocks, since otherwise we spend */
- /* all our time traversing them if pointerfree */
- /* blocks are unpopular. */
- /* A dropped block will be reconsidered at next GC. */
- if ((++count & 3) == 0) {
- /* Allocate and drop the block in small chunks, to */
- /* maximize the chance that we will recover some */
- /* later. */
- word total_size = hhdr -> hb_sz;
- struct hblk * limit = hbp + divHBLKSZ(total_size);
- struct hblk * h;
- struct hblk * prev = hhdr -> hb_prev;
-
- GC_words_wasted += total_size;
- GC_large_free_bytes -= total_size;
- GC_remove_from_fl(hhdr, n);
- for (h = hbp; h < limit; h++) {
- if (h == hbp || 0 != (hhdr = GC_install_header(h))) {
- (void) setup_header(
- hhdr,
- BYTES_TO_WORDS(HBLKSIZE),
- PTRFREE, 0); /* Cant fail */
- if (GC_debugging_started) {
- BZERO(h, HBLKSIZE);
- }
- }
- }
- /* Restore hbp to point at free block */
- hbp = prev;
- if (0 == hbp) {
- return GC_allochblk_nth(sz, kind, flags, n);
- }
- hhdr = HDR(hbp);
- }
- }
- }
- }
- if( size_avail >= size_needed ) {
-# ifdef USE_MUNMAP
- if (!IS_MAPPED(hhdr)) {
- GC_remap((ptr_t)hbp, hhdr -> hb_sz);
- hhdr -> hb_flags &= ~WAS_UNMAPPED;
- }
-# endif
- /* hbp may be on the wrong freelist; the parameter n */
- /* is important. */
- hbp = GC_get_first_part(hbp, hhdr, size_needed, n);
- break;
- }
- }
+ hbp = GC_hblkfreelist[n];
+ for(; 0 != hbp; hbp = hhdr -> hb_next) {
+ GET_HDR(hbp, hhdr);
+ size_avail = hhdr->hb_sz;
+ if (size_avail < size_needed) continue;
+ 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);
+ 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;
+ }
+ }
+ }
+ if (!IS_UNCOLLECTABLE(kind) && (kind != PTRFREE
+ || size_needed > (signed_word)MAX_BLACK_LIST_ALLOC)) {
+ struct hblk * lasthbp = hbp;
+ ptr_t search_end = (ptr_t)hbp + size_avail - size_needed;
+ signed_word orig_avail = size_avail;
+ signed_word eff_size_needed = (flags & IGNORE_OFF_PAGE) != 0 ?
+ (signed_word)HBLKSIZE
+ : size_needed;
+
+ while ((word)lasthbp <= (word)search_end
+ && (thishbp = GC_is_black_listed(lasthbp,
+ (word)eff_size_needed)) != 0) {
+ lasthbp = thishbp;
+ }
+ size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
+ thishbp = lasthbp;
+ if (size_avail >= size_needed) {
+ if (thishbp != hbp) {
+# ifdef USE_MUNMAP
+ /* Avoid remapping followed by splitting. */
+ if (may_split == AVOID_SPLIT_REMAPPED && !IS_MAPPED(hhdr))
+ continue;
+# endif
+ thishdr = GC_install_header(thishbp);
+ if (0 != thishdr) {
+ /* Make sure it's mapped before we mangle it. */
+# ifdef USE_MUNMAP
+ if (!IS_MAPPED(hhdr)) {
+ GC_remap((ptr_t)hbp, hhdr -> hb_sz);
+ hhdr -> hb_flags &= ~WAS_UNMAPPED;
+ }
+# endif
+ /* Split the block at thishbp */
+ GC_split_block(hbp, hhdr, thishbp, thishdr, n);
+ /* Advance to thishbp */
+ hbp = thishbp;
+ hhdr = thishdr;
+ /* We must now allocate thishbp, since it may */
+ /* be on the wrong free list. */
+ }
+ }
+ } else if (size_needed > (signed_word)BL_LIMIT
+ && orig_avail - size_needed
+ > (signed_word)BL_LIMIT) {
+ /* Punt, since anything else risks unreasonable heap growth. */
+ if (++GC_large_alloc_warn_suppressed
+ >= GC_large_alloc_warn_interval) {
+ WARN("Repeated allocation of very large block "
+ "(appr. size %" WARN_PRIdPTR "):\n"
+ "\tMay lead to memory leak and poor performance.\n",
+ size_needed);
+ GC_large_alloc_warn_suppressed = 0;
+ }
+ size_avail = orig_avail;
+ } else if (size_avail == 0 && size_needed == HBLKSIZE
+ && IS_MAPPED(hhdr)) {
+ if (!GC_find_leak) {
+ static unsigned count = 0;
+
+ /* The block is completely blacklisted. We need */
+ /* to drop some such blocks, since otherwise we spend */
+ /* all our time traversing them if pointerfree */
+ /* blocks are unpopular. */
+ /* A dropped block will be reconsidered at next GC. */
+ if ((++count & 3) == 0) {
+ /* Allocate and drop the block in small chunks, to */
+ /* maximize the chance that we will recover some */
+ /* later. */
+ word total_size = hhdr -> hb_sz;
+ struct hblk * limit = hbp + divHBLKSZ(total_size);
+ struct hblk * h;
+ struct hblk * prev = hhdr -> hb_prev;
+
+ GC_large_free_bytes -= total_size;
+ GC_bytes_dropped += total_size;
+ GC_remove_from_fl_at(hhdr, n);
+ for (h = hbp; (word)h < (word)limit; h++) {
+ if (h != hbp) {
+ hhdr = GC_install_header(h);
+ }
+ if (NULL != hhdr) {
+ (void)setup_header(hhdr, h, HBLKSIZE, PTRFREE, 0);
+ /* Can't fail. */
+ if (GC_debugging_started) {
+ BZERO(h, HBLKSIZE);
+ }
+ }
+ }
+ /* Restore hbp to point at free block */
+ hbp = prev;
+ if (0 == hbp) {
+ return GC_allochblk_nth(sz, kind, flags, n, may_split);
+ }
+ hhdr = HDR(hbp);
+ }
+ }
+ }
+ }
+ if( size_avail >= size_needed ) {
+# ifdef USE_MUNMAP
+ 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 */
+ /* is important. */
+ hbp = GC_get_first_part(hbp, hhdr, size_needed, n);
+ break;
+ }
+ }
if (0 == hbp) return 0;
-
+
/* Add it to map of valid blocks */
- if (!GC_install_counts(hbp, (word)size_needed)) return(0);
- /* This leaks memory under very rare conditions. */
-
+ if (!GC_install_counts(hbp, (word)size_needed)) return(0);
+ /* This leaks memory under very rare conditions. */
+
/* Set up header */
- if (!setup_header(hhdr, sz, kind, flags)) {
+ if (!setup_header(hhdr, hbp, sz, kind, flags)) {
GC_remove_counts(hbp, (word)size_needed);
return(0); /* ditto */
}
-
- /* Notify virtual dirty bit implementation that we are about to write. */
- /* Ensure that pointerfree objects are not protected if it's avoidable. */
- GC_remove_protection(hbp, divHBLKSZ(size_needed),
- (hhdr -> hb_descr == 0) /* pointer-free */);
-
- /* We just successfully allocated a block. Restart count of */
- /* consecutive failures. */
- {
- extern unsigned GC_fail_count;
-
- GC_fail_count = 0;
- }
+# ifndef GC_DISABLE_INCREMENTAL
+ /* Notify virtual dirty bit implementation that we are about to */
+ /* write. Ensure that pointerfree objects are not protected if */
+ /* it's avoidable. This also ensures that newly allocated */
+ /* blocks are treated as dirty. Necessary since we don't */
+ /* protect free blocks. */
+ GC_ASSERT((size_needed & (HBLKSIZE-1)) == 0);
+ GC_remove_protection(hbp, divHBLKSZ(size_needed),
+ (hhdr -> hb_descr == 0) /* pointer-free */);
+# endif
+ /* We just successfully allocated a block. Restart count of */
+ /* consecutive failures. */
+ GC_fail_count = 0;
GC_large_free_bytes -= size_needed;
-
GC_ASSERT(IS_MAPPED(hhdr));
return( hbp );
}
-
-struct hblk * GC_freehblk_ptr = 0; /* Search position hint for GC_freehblk */
/*
* Free a heap block.
@@ -776,61 +824,64 @@ struct hblk * GC_freehblk_ptr = 0; /* Search position hint for GC_freehblk */
*
* All mark words are assumed to be cleared.
*/
-void
-GC_freehblk(hbp)
-struct hblk *hbp;
+GC_INNER void GC_freehblk(struct hblk *hbp)
{
-struct hblk *next, *prev;
-hdr *hhdr, *prevhdr, *nexthdr;
-signed_word size;
-
+ struct hblk *next, *prev;
+ hdr *hhdr, *prevhdr, *nexthdr;
+ word size;
GET_HDR(hbp, hhdr);
- size = hhdr->hb_sz;
- size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size);
- GC_remove_counts(hbp, (word)size);
+ size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr->hb_sz);
+ if ((signed_word)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 don't catch it here, strange things happen */
+ /* later. */
+ GC_remove_counts(hbp, size);
hhdr->hb_sz = size;
# ifdef USE_MUNMAP
- hhdr -> hb_last_reclaimed = GC_gc_no;
+ hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
# endif
-
+
/* Check for duplicate deallocation in the easy case */
if (HBLK_IS_FREE(hhdr)) {
- GC_printf1("Duplicate large block deallocation of 0x%lx\n",
- (unsigned long) hbp);
- ABORT("Duplicate large block deallocation");
+ GC_COND_LOG_PRINTF("Duplicate large block deallocation of %p\n",
+ (void *)hbp);
+ ABORT("Duplicate large block deallocation");
}
GC_ASSERT(IS_MAPPED(hhdr));
- GC_invalidate_map(hhdr);
- next = (struct hblk *)((word)hbp + size);
+ hhdr -> hb_flags |= FREE_BLK;
+ next = (struct hblk *)((ptr_t)hbp + 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)) {
- GC_remove_from_fl(nexthdr, FL_UNKNOWN);
- hhdr -> hb_sz += nexthdr -> hb_sz;
- GC_remove_header(next);
+ 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);
+ hhdr -> hb_sz += nexthdr -> hb_sz;
+ GC_remove_header(next);
}
/* Coalesce with predecessor, if possible. */
if (0 != prev) {
- prevhdr = HDR(prev);
- if (IS_MAPPED(prevhdr)) {
- GC_remove_from_fl(prevhdr, FL_UNKNOWN);
- prevhdr -> hb_sz += hhdr -> hb_sz;
-# ifdef USE_MUNMAP
- prevhdr -> hb_last_reclaimed = GC_gc_no;
-# endif
- GC_remove_header(hbp);
- hbp = prev;
- hhdr = prevhdr;
- }
+ prevhdr = HDR(prev);
+ if (IS_MAPPED(prevhdr)
+ && (signed_word)(hhdr -> hb_sz + prevhdr -> hb_sz) > 0) {
+ GC_remove_from_fl(prevhdr);
+ prevhdr -> hb_sz += hhdr -> hb_sz;
+# ifdef USE_MUNMAP
+ prevhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
+# endif
+ GC_remove_header(hbp);
+ hbp = prev;
+ hhdr = prevhdr;
+ }
}
- /* FIXME: It is not clear we really always want to do these merges */
- /* with -DUSE_MUNMAP, since it updates ages and hence prevents */
- /* unmapping. */
+ /* FIXME: It is not clear we really always want to do these merges */
+ /* with USE_MUNMAP, since it updates ages and hence prevents */
+ /* unmapping. */
GC_large_free_bytes += size;
- GC_add_to_fl(hbp, hhdr);
+ GC_add_to_fl(hbp, hhdr);
}
-
diff --git a/boehm-gc/alloc.c b/boehm-gc/alloc.c
index 1ac6ff8111f..925c53bbefc 100644
--- a/boehm-gc/alloc.c
+++ b/boehm-gc/alloc.c
@@ -2,7 +2,7 @@
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
* Copyright (c) 1998 by Silicon Graphics. All rights reserved.
- * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -15,18 +15,19 @@
*
*/
+#include "private/gc_priv.h"
-# include "private/gc_priv.h"
-
-# include <stdio.h>
-# if !defined(MACOS) && !defined(MSWINCE)
-# include <signal.h>
+#include <stdio.h>
+#if !defined(MACOS) && !defined(MSWINCE)
+# include <signal.h>
+# if !defined(__CC_ARM)
# include <sys/types.h>
# endif
+#endif
/*
* Separate free lists are maintained for different sized objects
- * up to MAXOBJSZ.
+ * up to MAXOBJBYTES.
* The call GC_allocobj(i,k) ensures that the freelist for
* kind k objects of size i points to a non-empty
* free list. It returns a pointer to the first entry on the free list.
@@ -45,11 +46,11 @@
*/
/*
- * The allocator uses GC_allochblk to allocate large chunks of objects.
+ * The allocator uses GC_allochblk to allocate large chunks of objects.
* These chunks all start on addresses which are multiples of
* HBLKSZ. Each allocated chunk has an associated header,
* which can be located quickly based on the address of the chunk.
- * (See headers.c for details.)
+ * (See headers.c for details.)
* This makes it possible to check quickly whether an
* arbitrary address corresponds to an object administered by the
* allocator.
@@ -59,306 +60,394 @@ word GC_non_gc_bytes = 0; /* Number of bytes not intended to be collected */
word GC_gc_no = 0;
-#ifndef SMALL_CONFIG
- int GC_incremental = 0; /* By default, stop the world. */
+#ifndef GC_DISABLE_INCREMENTAL
+ GC_INNER int GC_incremental = 0; /* By default, stop the world. */
#endif
-int GC_parallel = FALSE; /* By default, parallel GC is off. */
+#ifdef THREADS
+ int GC_parallel = FALSE; /* By default, parallel GC is off. */
+#endif
-int GC_full_freq = 19; /* Every 20th collection is a full */
- /* collection, whether we need it */
- /* or not. */
+#ifndef GC_FULL_FREQ
+# define GC_FULL_FREQ 19 /* Every 20th collection is a full */
+ /* collection, whether we need it */
+ /* or not. */
+#endif
-GC_bool GC_need_full_gc = FALSE;
- /* Need full GC do to heap growth. */
+int GC_full_freq = GC_FULL_FREQ;
-#ifdef THREADS
- GC_bool GC_world_stopped = FALSE;
-# define IF_THREADS(x) x
-#else
-# define IF_THREADS(x)
+STATIC GC_bool GC_need_full_gc = FALSE;
+ /* Need full GC do to heap growth. */
+
+#ifdef THREAD_LOCAL_ALLOC
+ GC_INNER GC_bool GC_world_stopped = FALSE;
#endif
-word GC_used_heap_size_after_full = 0;
+STATIC word GC_used_heap_size_after_full = 0;
-char * GC_copyright[] =
+/* GC_copyright symbol is externally visible. */
+char * const GC_copyright[] =
{"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ",
"Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. ",
"Copyright (c) 1996-1998 by Silicon Graphics. All rights reserved. ",
-"Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved. ",
+"Copyright (c) 1999-2009 by Hewlett-Packard Company. All rights reserved. ",
"THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
" EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.",
"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
+ const unsigned GC_version = ((GC_VERSION_MAJOR << 16) |
+ (GC_VERSION_MINOR << 8) | GC_TMP_ALPHA_VERSION);
+#endif
+
+GC_API unsigned GC_CALL GC_get_version(void)
+{
+ return (GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) |
+ GC_TMP_ALPHA_VERSION;
+}
/* some more variables */
-extern signed_word GC_mem_found; /* Number of reclaimed longwords */
- /* after garbage collection */
+#ifdef GC_DONT_EXPAND
+ int GC_dont_expand = TRUE;
+#else
+ int GC_dont_expand = FALSE;
+#endif
+
+#ifndef GC_FREE_SPACE_DIVISOR
+# define GC_FREE_SPACE_DIVISOR 3 /* must be > 0 */
+#endif
-GC_bool GC_dont_expand = 0;
+word GC_free_space_divisor = GC_FREE_SPACE_DIVISOR;
-word GC_free_space_divisor = 3;
+GC_INNER int GC_CALLBACK GC_never_stop_func(void)
+{
+ return(0);
+}
+
+#ifndef GC_TIME_LIMIT
+# define GC_TIME_LIMIT 50 /* We try to keep pause times from exceeding */
+ /* this by much. In milliseconds. */
+#endif
-extern GC_bool GC_collection_in_progress();
- /* Collection is in progress, or was abandoned. */
+unsigned long GC_time_limit = GC_TIME_LIMIT;
-extern GC_bool GC_print_back_height;
+#ifndef NO_CLOCK
+ STATIC CLOCK_TYPE GC_start_time = 0;
+ /* Time at which we stopped world. */
+ /* used only in GC_timeout_stop_func. */
+#endif
-int GC_never_stop_func GC_PROTO((void)) { return(0); }
+STATIC int GC_n_attempts = 0; /* Number of attempts at finishing */
+ /* collection within GC_time_limit. */
-unsigned long GC_time_limit = TIME_LIMIT;
+STATIC GC_stop_func GC_default_stop_func = GC_never_stop_func;
+ /* accessed holding the lock. */
-CLOCK_TYPE GC_start_time; /* Time at which we stopped world. */
- /* used only in GC_timeout_stop_func. */
+GC_API void GC_CALL GC_set_stop_func(GC_stop_func stop_func)
+{
+ DCL_LOCK_STATE;
+ GC_ASSERT(stop_func != 0);
+ LOCK();
+ GC_default_stop_func = stop_func;
+ UNLOCK();
+}
-int GC_n_attempts = 0; /* Number of attempts at finishing */
- /* collection within GC_time_limit. */
+GC_API GC_stop_func GC_CALL GC_get_stop_func(void)
+{
+ GC_stop_func stop_func;
+ DCL_LOCK_STATE;
+ LOCK();
+ stop_func = GC_default_stop_func;
+ UNLOCK();
+ return stop_func;
+}
-#if defined(SMALL_CONFIG) || defined(NO_CLOCK)
-# define GC_timeout_stop_func GC_never_stop_func
+#if defined(GC_DISABLE_INCREMENTAL) || defined(NO_CLOCK)
+# define GC_timeout_stop_func GC_default_stop_func
#else
- int GC_timeout_stop_func GC_PROTO((void))
+ STATIC int GC_CALLBACK GC_timeout_stop_func (void)
{
CLOCK_TYPE current_time;
static unsigned count = 0;
unsigned long time_diff;
-
+
+ if ((*GC_default_stop_func)())
+ return(1);
+
if ((count++ & 3) != 0) return(0);
GET_TIME(current_time);
time_diff = MS_TIME_DIFF(current_time,GC_start_time);
if (time_diff >= GC_time_limit) {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0("Abandoning stopped marking after ");
- GC_printf1("%lu msecs", (unsigned long)time_diff);
- GC_printf1("(attempt %ld)\n", (unsigned long) GC_n_attempts);
- }
-# endif
- return(1);
+ GC_COND_LOG_PRINTF(
+ "Abandoning stopped marking after %lu msecs (attempt %d)\n",
+ time_diff, GC_n_attempts);
+ return(1);
}
return(0);
}
-#endif /* !SMALL_CONFIG */
+#endif /* !GC_DISABLE_INCREMENTAL */
-/* Return the minimum number of words that must be allocated between */
-/* collections to amortize the collection cost. */
-static word min_words_allocd()
+#ifdef THREADS
+ GC_INNER word GC_total_stacksize = 0; /* updated on every push_all_stacks */
+#endif
+
+/* Return the minimum number of bytes that must be allocated between */
+/* collections to amortize the collection cost. Should be non-zero. */
+static word min_bytes_allocd(void)
{
-# ifdef THREADS
- /* We punt, for now. */
- register signed_word stack_size = 10000;
+ word result;
+# ifdef STACK_GROWS_UP
+ word stack_size = GC_approx_sp() - GC_stackbottom;
+ /* GC_stackbottom is used only for a single-threaded case. */
# else
- int dummy;
- register signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom;
+ word stack_size = GC_stackbottom - GC_approx_sp();
+# endif
+
+ word total_root_size; /* includes double stack size, */
+ /* since the stack is expensive */
+ /* to scan. */
+ word scan_size; /* Estimate of memory to be scanned */
+ /* during normal GC. */
+
+# ifdef THREADS
+ if (GC_need_to_lock) {
+ /* We are multi-threaded... */
+ stack_size = GC_total_stacksize;
+ /* For now, we just use the value computed during the latest GC. */
+# ifdef DEBUG_THREADS
+ GC_log_printf("Total stacks size: %lu\n",
+ (unsigned long)stack_size);
+# endif
+ }
# endif
- word total_root_size; /* includes double stack size, */
- /* since the stack is expensive */
- /* to scan. */
- word scan_size; /* Estimate of memory to be scanned */
- /* during normal GC. */
-
- if (stack_size < 0) stack_size = -stack_size;
+
total_root_size = 2 * stack_size + GC_root_size;
- scan_size = BYTES_TO_WORDS(GC_heapsize - GC_large_free_bytes
- + (GC_large_free_bytes >> 2)
- /* use a bit more of large empty heap */
- + total_root_size);
- if (TRUE_INCREMENTAL) {
- return scan_size / (2 * GC_free_space_divisor);
- } else {
- return scan_size / GC_free_space_divisor;
+ scan_size = 2 * GC_composite_in_use + GC_atomic_in_use / 4
+ + total_root_size;
+ result = scan_size / GC_free_space_divisor;
+ if (GC_incremental) {
+ result /= 2;
}
+ return result > 0 ? result : 1;
}
-/* Return the number of words allocated, adjusted for explicit storage */
-/* management, etc.. This number is used in deciding when to trigger */
-/* collections. */
-word GC_adj_words_allocd()
+STATIC word GC_non_gc_bytes_at_gc = 0;
+ /* Number of explicitly managed bytes of storage */
+ /* at last collection. */
+
+/* Return the number of bytes allocated, adjusted for explicit storage */
+/* management, etc.. This number is used in deciding when to trigger */
+/* collections. */
+STATIC word GC_adj_bytes_allocd(void)
{
- register signed_word result;
- register signed_word expl_managed =
- BYTES_TO_WORDS((long)GC_non_gc_bytes
- - (long)GC_non_gc_bytes_at_gc);
-
- /* Don't count what was explicitly freed, or newly allocated for */
- /* explicit management. Note that deallocating an explicitly */
- /* managed object should not alter result, assuming the client */
- /* is playing by the rules. */
- result = (signed_word)GC_words_allocd
- - (signed_word)GC_mem_freed
- + (signed_word)GC_finalizer_mem_freed - expl_managed;
- if (result > (signed_word)GC_words_allocd) {
- result = GC_words_allocd;
- /* probably client bug or unfortunate scheduling */
+ signed_word result;
+ signed_word expl_managed = (signed_word)GC_non_gc_bytes
+ - (signed_word)GC_non_gc_bytes_at_gc;
+
+ /* Don't count what was explicitly freed, or newly allocated for */
+ /* explicit management. Note that deallocating an explicitly */
+ /* managed object should not alter result, assuming the client */
+ /* is playing by the rules. */
+ result = (signed_word)GC_bytes_allocd
+ + (signed_word)GC_bytes_dropped
+ - (signed_word)GC_bytes_freed
+ + (signed_word)GC_finalizer_bytes_freed
+ - expl_managed;
+ if (result > (signed_word)GC_bytes_allocd) {
+ result = GC_bytes_allocd;
+ /* probably client bug or unfortunate scheduling */
}
- result += GC_words_finalized;
- /* We count objects enqueued for finalization as though they */
- /* had been reallocated this round. Finalization is user */
- /* visible progress. And if we don't count this, we have */
- /* stability problems for programs that finalize all objects. */
- result += GC_words_wasted;
- /* This doesn't reflect useful work. But if there is lots of */
- /* new fragmentation, the same is probably true of the heap, */
- /* and the collection will be correspondingly cheaper. */
- if (result < (signed_word)(GC_words_allocd >> 3)) {
- /* Always count at least 1/8 of the allocations. We don't want */
- /* to collect too infrequently, since that would inhibit */
- /* coalescing of free storage blocks. */
- /* This also makes us partially robust against client bugs. */
- return(GC_words_allocd >> 3);
+ result += GC_bytes_finalized;
+ /* We count objects enqueued for finalization as though they */
+ /* had been reallocated this round. Finalization is user */
+ /* visible progress. And if we don't count this, we have */
+ /* stability problems for programs that finalize all objects. */
+ if (result < (signed_word)(GC_bytes_allocd >> 3)) {
+ /* Always count at least 1/8 of the allocations. We don't want */
+ /* to collect too infrequently, since that would inhibit */
+ /* coalescing of free storage blocks. */
+ /* This also makes us partially robust against client bugs. */
+ return(GC_bytes_allocd >> 3);
} else {
return(result);
}
}
-/* Clear up a few frames worth of garbage left at the top of the stack. */
-/* This is used to prevent us from accidentally treating garbade left */
-/* on the stack by other parts of the collector as roots. This */
-/* differs from the code in misc.c, which actually tries to keep the */
-/* stack clear of long-lived, client-generated garbage. */
-void GC_clear_a_few_frames()
+/* Clear up a few frames worth of garbage left at the top of the stack. */
+/* This is used to prevent us from accidentally treating garbage left */
+/* on the stack by other parts of the collector as roots. This */
+/* differs from the code in misc.c, which actually tries to keep the */
+/* stack clear of long-lived, client-generated garbage. */
+STATIC void GC_clear_a_few_frames(void)
{
-# define NWORDS 64
- word frames[NWORDS];
- register int i;
-
- for (i = 0; i < NWORDS; i++) frames[i] = 0;
+# ifndef CLEAR_NWORDS
+# define CLEAR_NWORDS 64
+# endif
+ volatile word frames[CLEAR_NWORDS];
+ BZERO((word *)frames, CLEAR_NWORDS * sizeof(word));
}
-/* Heap size at which we need a collection to avoid expanding past */
-/* limits used by blacklisting. */
-static word GC_collect_at_heapsize = (word)(-1);
+/* Heap size at which we need a collection to avoid expanding past */
+/* limits used by blacklisting. */
+STATIC word GC_collect_at_heapsize = (word)(-1);
/* Have we allocated enough to amortize a collection? */
-GC_bool GC_should_collect()
+GC_INNER GC_bool GC_should_collect(void)
{
- return(GC_adj_words_allocd() >= min_words_allocd()
- || GC_heapsize >= GC_collect_at_heapsize);
+ 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);
}
+/* STATIC */ GC_start_callback_proc GC_start_call_back = 0;
+ /* Called at start of full collections. */
+ /* Not called if 0. Called with the allocation */
+ /* lock held. Not used by GC itself. */
+
+GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc fn)
+{
+ DCL_LOCK_STATE;
+ LOCK();
+ GC_start_call_back = fn;
+ UNLOCK();
+}
+
+GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void)
+{
+ GC_start_callback_proc fn;
+ DCL_LOCK_STATE;
+ LOCK();
+ fn = GC_start_call_back;
+ UNLOCK();
+ return fn;
+}
-void GC_notify_full_gc()
+GC_INLINE void GC_notify_full_gc(void)
{
- if (GC_start_call_back != (void (*) GC_PROTO((void)))0) {
- (*GC_start_call_back)();
+ if (GC_start_call_back != 0) {
+ (*GC_start_call_back)();
}
}
-GC_bool GC_is_full_gc = FALSE;
+STATIC GC_bool GC_is_full_gc = FALSE;
-/*
+STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func);
+STATIC void GC_finish_collection(void);
+
+/*
* Initiate a garbage collection if appropriate.
* Choose judiciously
* between partial, full, and stop-world collections.
- * Assumes lock held, signals disabled.
*/
-void GC_maybe_gc()
+STATIC void GC_maybe_gc(void)
{
static int n_partial_gcs = 0;
+ GC_ASSERT(I_HOLD_LOCK());
+ ASSERT_CANCEL_DISABLED();
if (GC_should_collect()) {
if (!GC_incremental) {
- GC_gcollect_inner();
+ /* FIXME: If possible, GC_default_stop_func should be used here */
+ GC_try_to_collect_inner(GC_never_stop_func);
n_partial_gcs = 0;
return;
} else {
-# ifdef PARALLEL_MARK
- GC_wait_for_reclaim();
-# endif
- if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf2(
- "***>Full mark for collection %lu after %ld allocd bytes\n",
- (unsigned long) GC_gc_no+1,
- (long)WORDS_TO_BYTES(GC_words_allocd));
- }
-# endif
- GC_promote_black_lists();
- (void)GC_reclaim_all((GC_stop_func)0, TRUE);
- GC_clear_marks();
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_wait_for_reclaim();
+# endif
+ if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) {
+ GC_COND_LOG_PRINTF(
+ "***>Full mark for collection %lu after %lu allocd bytes\n",
+ (unsigned long)GC_gc_no + 1, (unsigned long)GC_bytes_allocd);
+ GC_promote_black_lists();
+ (void)GC_reclaim_all((GC_stop_func)0, TRUE);
+ GC_notify_full_gc();
+ GC_clear_marks();
n_partial_gcs = 0;
- GC_notify_full_gc();
- GC_is_full_gc = TRUE;
+ GC_is_full_gc = TRUE;
} else {
n_partial_gcs++;
}
- }
- /* We try to mark with the world stopped. */
- /* If we run out of time, this turns into */
- /* incremental marking. */
-# ifndef NO_CLOCK
+ }
+ /* We try to mark with the world stopped. */
+ /* If we run out of time, this turns into */
+ /* incremental marking. */
+# ifndef NO_CLOCK
if (GC_time_limit != GC_TIME_UNLIMITED) { GET_TIME(GC_start_time); }
-# endif
- if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED?
- GC_never_stop_func : GC_timeout_stop_func)) {
+# endif
+ /* FIXME: If possible, GC_default_stop_func should be */
+ /* used instead of GC_never_stop_func here. */
+ if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED?
+ GC_never_stop_func : GC_timeout_stop_func)) {
# ifdef SAVE_CALL_CHAIN
GC_save_callers(GC_last_stack);
# endif
GC_finish_collection();
} else {
- if (!GC_is_full_gc) {
- /* Count this as the first attempt */
- GC_n_attempts++;
- }
- }
+ if (!GC_is_full_gc) {
+ /* Count this as the first attempt */
+ GC_n_attempts++;
+ }
+ }
}
}
/*
- * Stop the world garbage collection. Assumes lock held, signals disabled.
- * If stop_func is not GC_never_stop_func, then abort if stop_func returns TRUE.
+ * Stop the world garbage collection. Assumes lock held. If stop_func is
+ * not GC_never_stop_func then abort if stop_func returns TRUE.
* Return TRUE if we successfully completed the collection.
*/
-GC_bool GC_try_to_collect_inner(stop_func)
-GC_stop_func stop_func;
+GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
{
-# ifdef CONDPRINT
- CLOCK_TYPE start_time, current_time;
+# ifndef SMALL_CONFIG
+ CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
+ CLOCK_TYPE current_time;
# endif
- if (GC_dont_gc) return FALSE;
+ ASSERT_CANCEL_DISABLED();
+ if (GC_dont_gc || (*stop_func)()) return FALSE;
if (GC_incremental && GC_collection_in_progress()) {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0(
- "GC_try_to_collect_inner: finishing collection in progress\n");
- }
-# endif /* CONDPRINT */
- /* Just finish collection already in progress. */
- while(GC_collection_in_progress()) {
- if (stop_func()) return(FALSE);
- GC_collect_a_little_inner(1);
- }
+ GC_COND_LOG_PRINTF(
+ "GC_try_to_collect_inner: finishing collection in progress\n");
+ /* Just finish collection already in progress. */
+ while(GC_collection_in_progress()) {
+ if ((*stop_func)()) return(FALSE);
+ GC_collect_a_little_inner(1);
+ }
}
- if (stop_func == GC_never_stop_func) GC_notify_full_gc();
-# ifdef CONDPRINT
+ GC_notify_full_gc();
+# ifndef SMALL_CONFIG
if (GC_print_stats) {
- if (GC_print_stats) GET_TIME(start_time);
- GC_printf2(
- "Initiating full world-stop collection %lu after %ld allocd bytes\n",
- (unsigned long) GC_gc_no+1,
- (long)WORDS_TO_BYTES(GC_words_allocd));
+ GET_TIME(start_time);
+ GC_stats_log_printf("Initiating full world-stop collection!\n");
}
# endif
GC_promote_black_lists();
- /* Make sure all blocks have been reclaimed, so sweep routines */
- /* don't see cleared mark bits. */
- /* If we're guaranteed to finish, then this is unnecessary. */
- /* In the find_leak case, we have to finish to guarantee that */
- /* previously unmarked objects are not reported as leaks. */
+ /* Make sure all blocks have been reclaimed, so sweep routines */
+ /* don't see cleared mark bits. */
+ /* If we're guaranteed to finish, then this is unnecessary. */
+ /* In the find_leak case, we have to finish to guarantee that */
+ /* previously unmarked objects are not reported as leaks. */
# ifdef PARALLEL_MARK
- GC_wait_for_reclaim();
+ if (GC_parallel)
+ GC_wait_for_reclaim();
# endif
- if ((GC_find_leak || stop_func != GC_never_stop_func)
- && !GC_reclaim_all(stop_func, FALSE)) {
- /* Aborted. So far everything is still consistent. */
- return(FALSE);
- }
- GC_invalidate_mark_state(); /* Flush mark stack. */
+ if ((GC_find_leak || stop_func != GC_never_stop_func)
+ && !GC_reclaim_all(stop_func, FALSE)) {
+ /* Aborted. So far everything is still consistent. */
+ return(FALSE);
+ }
+ GC_invalidate_mark_state(); /* Flush mark stack. */
GC_clear_marks();
# ifdef SAVE_CALL_CHAIN
GC_save_callers(GC_last_stack);
@@ -366,132 +455,162 @@ GC_stop_func stop_func;
GC_is_full_gc = TRUE;
if (!GC_stopped_mark(stop_func)) {
if (!GC_incremental) {
- /* We're partially done and have no way to complete or use */
- /* current work. Reestablish invariants as cheaply as */
- /* possible. */
- GC_invalidate_mark_state();
- GC_unpromote_black_lists();
- } /* else we claim the world is already still consistent. We'll */
- /* finish incrementally. */
+ /* We're partially done and have no way to complete or use */
+ /* current work. Reestablish invariants as cheaply as */
+ /* possible. */
+ GC_invalidate_mark_state();
+ GC_unpromote_black_lists();
+ } /* else we claim the world is already still consistent. We'll */
+ /* finish incrementally. */
return(FALSE);
}
GC_finish_collection();
-# if defined(CONDPRINT)
+# ifndef SMALL_CONFIG
if (GC_print_stats) {
GET_TIME(current_time);
- GC_printf1("Complete collection took %lu msecs\n",
- MS_TIME_DIFF(current_time,start_time));
+ GC_stats_log_printf("Complete collection took %lu msecs\n",
+ MS_TIME_DIFF(current_time,start_time));
}
# endif
return(TRUE);
}
-
-
/*
* Perform n units of garbage collection work. A unit is intended to touch
* roughly GC_RATE pages. Every once in a while, we do more than that.
- * This needa to be a fairly large number with our current incremental
+ * This needs to be a fairly large number with our current incremental
* GC strategy, since otherwise we allocate too much during GC, and the
* cleanup gets expensive.
*/
-# define GC_RATE 10
+#ifndef GC_RATE
+# define GC_RATE 10
+#endif
+#ifndef MAX_PRIOR_ATTEMPTS
# define MAX_PRIOR_ATTEMPTS 1
- /* Maximum number of prior attempts at world stop marking */
- /* A value of 1 means that we finish the second time, no matter */
- /* how long it takes. Doesn't count the initial root scan */
- /* for a full GC. */
+#endif
+ /* Maximum number of prior attempts at world stop marking */
+ /* A value of 1 means that we finish the second time, no matter */
+ /* how long it takes. Doesn't count the initial root scan */
+ /* for a full GC. */
-int GC_deficit = 0; /* The number of extra calls to GC_mark_some */
- /* that we have made. */
+STATIC int GC_deficit = 0;/* The number of extra calls to GC_mark_some */
+ /* that we have made. */
-void GC_collect_a_little_inner(n)
-int n;
+GC_INNER void GC_collect_a_little_inner(int n)
{
- register int i;
-
+ int i;
+ IF_CANCEL(int cancel_state;)
+
if (GC_dont_gc) return;
+ DISABLE_CANCEL(cancel_state);
if (GC_incremental && GC_collection_in_progress()) {
- for (i = GC_deficit; i < GC_RATE*n; i++) {
- if (GC_mark_some((ptr_t)0)) {
- /* Need to finish a collection */
-# ifdef SAVE_CALL_CHAIN
- GC_save_callers(GC_last_stack);
-# endif
-# ifdef PARALLEL_MARK
- GC_wait_for_reclaim();
-# endif
- if (GC_n_attempts < MAX_PRIOR_ATTEMPTS
- && GC_time_limit != GC_TIME_UNLIMITED) {
- GET_TIME(GC_start_time);
- if (!GC_stopped_mark(GC_timeout_stop_func)) {
- GC_n_attempts++;
- break;
- }
- } else {
- (void)GC_stopped_mark(GC_never_stop_func);
- }
- GC_finish_collection();
- break;
- }
- }
- if (GC_deficit > 0) GC_deficit -= GC_RATE*n;
- if (GC_deficit < 0) GC_deficit = 0;
+ for (i = GC_deficit; i < GC_RATE*n; i++) {
+ if (GC_mark_some((ptr_t)0)) {
+ /* Need to finish a collection */
+# ifdef SAVE_CALL_CHAIN
+ GC_save_callers(GC_last_stack);
+# endif
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_wait_for_reclaim();
+# endif
+ if (GC_n_attempts < MAX_PRIOR_ATTEMPTS
+ && GC_time_limit != GC_TIME_UNLIMITED) {
+# ifndef NO_CLOCK
+ GET_TIME(GC_start_time);
+# endif
+ if (!GC_stopped_mark(GC_timeout_stop_func)) {
+ GC_n_attempts++;
+ break;
+ }
+ } else {
+ /* FIXME: If possible, GC_default_stop_func should be */
+ /* used here. */
+ (void)GC_stopped_mark(GC_never_stop_func);
+ }
+ GC_finish_collection();
+ break;
+ }
+ }
+ if (GC_deficit > 0) GC_deficit -= GC_RATE*n;
+ if (GC_deficit < 0) GC_deficit = 0;
} else {
GC_maybe_gc();
}
+ RESTORE_CANCEL(cancel_state);
}
-int GC_collect_a_little GC_PROTO(())
+GC_INNER void (*GC_check_heap)(void) = 0;
+GC_INNER void (*GC_print_all_smashed)(void) = 0;
+
+GC_API int GC_CALL GC_collect_a_little(void)
{
int result;
DCL_LOCK_STATE;
- DISABLE_SIGNALS();
LOCK();
GC_collect_a_little_inner(1);
result = (int)GC_collection_in_progress();
UNLOCK();
- ENABLE_SIGNALS();
if (!result && GC_debugging_started) GC_print_all_smashed();
return(result);
}
+#ifndef SMALL_CONFIG
+ /* Variables for world-stop average delay time statistic computation. */
+ /* "divisor" is incremented every world-stop and halved when reached */
+ /* its maximum (or upon "total_time" oveflow). */
+ static unsigned world_stopped_total_time = 0;
+ static unsigned world_stopped_total_divisor = 0;
+# ifndef MAX_TOTAL_TIME_DIVISOR
+ /* We shall not use big values here (so "outdated" delay time */
+ /* values would have less impact on "average" delay time value than */
+ /* newer ones). */
+# define MAX_TOTAL_TIME_DIVISOR 1000
+# endif
+#endif
+
+#ifdef USE_MUNMAP
+# define IF_USE_MUNMAP(x) x
+# define COMMA_IF_USE_MUNMAP(x) /* comma */, x
+#else
+# define IF_USE_MUNMAP(x) /* empty */
+# define COMMA_IF_USE_MUNMAP(x) /* empty */
+#endif
+
/*
- * Assumes lock is held, signals are disabled.
- * We stop the world.
+ * Assumes lock is held. We stop the world and mark from all roots.
* If stop_func() ever returns TRUE, we may fail and return FALSE.
* Increment GC_gc_no if we succeed.
*/
-GC_bool GC_stopped_mark(stop_func)
-GC_stop_func stop_func;
+STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
{
- register int i;
- int dummy;
-# if defined(PRINTTIMES) || defined(CONDPRINT)
- CLOCK_TYPE start_time, current_time;
-# endif
-
-# ifdef PRINTTIMES
- GET_TIME(start_time);
+ unsigned i;
+# ifndef SMALL_CONFIG
+ CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
+ CLOCK_TYPE current_time;
# endif
-# if defined(CONDPRINT) && !defined(PRINTTIMES)
- if (GC_print_stats) GET_TIME(start_time);
+
+# if !defined(REDIRECT_MALLOC) && defined(USE_WINALLOC)
+ GC_add_current_malloc_heap();
# endif
# if defined(REGISTER_LIBRARIES_EARLY)
GC_cond_register_dynamic_libraries();
# endif
+
+# ifndef SMALL_CONFIG
+ if (GC_print_stats)
+ GET_TIME(start_time);
+# endif
+
STOP_WORLD();
- IF_THREADS(GC_world_stopped = TRUE);
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("--> Marking for collection %lu ",
- (unsigned long) GC_gc_no + 1);
- GC_printf2("after %lu allocd bytes + %lu wasted bytes\n",
- (unsigned long) WORDS_TO_BYTES(GC_words_allocd),
- (unsigned long) WORDS_TO_BYTES(GC_words_wasted));
- }
+# ifdef THREAD_LOCAL_ALLOC
+ GC_world_stopped = TRUE;
# endif
+ /* Output blank line for convenience here */
+ GC_COND_LOG_PRINTF(
+ "\n--> Marking for collection %lu after %lu allocated bytes\n",
+ (unsigned long)GC_gc_no + 1, (unsigned long) GC_bytes_allocd);
# ifdef MAKE_BACK_GRAPH
if (GC_print_back_height) {
GC_build_back_graph();
@@ -501,378 +620,513 @@ GC_stop_func stop_func;
/* Mark from all roots. */
/* Minimize junk left in my registers and on the stack */
GC_clear_a_few_frames();
- GC_noop(0,0,0,0,0,0);
- GC_initiate_gc();
- for(i = 0;;i++) {
- if ((*stop_func)()) {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0("Abandoned stopped marking after ");
- GC_printf1("%lu iterations\n",
- (unsigned long)i);
- }
-# endif
- GC_deficit = i; /* Give the mutator a chance. */
- IF_THREADS(GC_world_stopped = FALSE);
- START_WORLD();
- return(FALSE);
- }
- if (GC_mark_some((ptr_t)(&dummy))) break;
- }
-
+ GC_noop6(0,0,0,0,0,0);
+
+ GC_initiate_gc();
+ for (i = 0;;i++) {
+ if ((*stop_func)()) {
+ GC_COND_LOG_PRINTF("Abandoned stopped marking after"
+ " %u iterations\n", i);
+ GC_deficit = i; /* Give the mutator a chance. */
+# ifdef THREAD_LOCAL_ALLOC
+ GC_world_stopped = FALSE;
+# endif
+ START_WORLD();
+ return(FALSE);
+ }
+ if (GC_mark_some(GC_approx_sp())) break;
+ }
+
GC_gc_no++;
-# ifdef PRINTSTATS
- GC_printf2("Collection %lu reclaimed %ld bytes",
- (unsigned long) GC_gc_no - 1,
- (long)WORDS_TO_BYTES(GC_mem_found));
-# else
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Collection %lu finished", (unsigned long) GC_gc_no - 1);
- }
-# endif
-# endif /* !PRINTSTATS */
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1(" ---> heapsize = %lu bytes\n",
- (unsigned long) GC_heapsize);
- /* Printf arguments may be pushed in funny places. Clear the */
- /* space. */
- GC_printf0("");
- }
-# endif /* CONDPRINT */
+ GC_COND_LOG_PRINTF("GC %lu reclaimed %ld bytes --> heapsize: %lu"
+ " bytes" IF_USE_MUNMAP(" (%lu unmapped)") "\n",
+ (unsigned long)GC_gc_no, (long)GC_bytes_found,
+ (unsigned long)GC_heapsize /*, */
+ COMMA_IF_USE_MUNMAP((unsigned long)GC_unmapped_bytes));
/* Check all debugged objects for consistency */
- if (GC_debugging_started) {
- (*GC_check_heap)();
- }
-
- IF_THREADS(GC_world_stopped = FALSE);
+ if (GC_debugging_started) {
+ (*GC_check_heap)();
+ }
+
+# ifdef THREAD_LOCAL_ALLOC
+ GC_world_stopped = FALSE;
+# endif
START_WORLD();
-# ifdef PRINTTIMES
- GET_TIME(current_time);
- GC_printf1("World-stopped marking took %lu msecs\n",
- MS_TIME_DIFF(current_time,start_time));
-# else
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GET_TIME(current_time);
- GC_printf1("World-stopped marking took %lu msecs\n",
- MS_TIME_DIFF(current_time,start_time));
- }
-# endif
+# ifndef SMALL_CONFIG
+ if (GC_print_stats) {
+ unsigned long time_diff;
+ unsigned total_time, divisor;
+ GET_TIME(current_time);
+ time_diff = MS_TIME_DIFF(current_time,start_time);
+
+ /* Compute new world-stop delay total time */
+ total_time = world_stopped_total_time;
+ divisor = world_stopped_total_divisor;
+ if ((int)total_time < 0 || divisor >= MAX_TOTAL_TIME_DIVISOR) {
+ /* Halve values if overflow occurs */
+ total_time >>= 1;
+ divisor >>= 1;
+ }
+ total_time += time_diff < (((unsigned)-1) >> 1) ?
+ (unsigned)time_diff : ((unsigned)-1) >> 1;
+ /* Update old world_stopped_total_time and its divisor */
+ world_stopped_total_time = total_time;
+ world_stopped_total_divisor = ++divisor;
+
+ GC_ASSERT(divisor != 0);
+ GC_stats_log_printf(
+ "World-stopped marking took %lu msecs (%u in average)\n",
+ time_diff, total_time / divisor);
+ }
# endif
return(TRUE);
}
-/* Set all mark bits for the free list whose first entry is q */
-#ifdef __STDC__
- void GC_set_fl_marks(ptr_t q)
-#else
- void GC_set_fl_marks(q)
- ptr_t q;
-#endif
+/* Set all mark bits for the free list whose first entry is q */
+GC_INNER void GC_set_fl_marks(ptr_t q)
{
- ptr_t p;
- struct hblk * h, * last_h = 0;
+ struct hblk *h, *last_h;
hdr *hhdr;
- int word_no;
-
- for (p = q; p != 0; p = obj_link(p)){
- h = HBLKPTR(p);
- if (h != last_h) {
- last_h = h;
- hhdr = HDR(h);
- }
- word_no = (((word *)p) - ((word *)h));
- set_mark_bit_from_hdr(hhdr, word_no);
+ IF_PER_OBJ(size_t sz;)
+ unsigned bit_no;
+
+ if (q != NULL) {
+ h = HBLKPTR(q);
+ last_h = h;
+ hhdr = HDR(h);
+ IF_PER_OBJ(sz = hhdr->hb_sz;)
+
+ for (;;) {
+ bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, sz);
+ if (!mark_bit_from_hdr(hhdr, bit_no)) {
+ set_mark_bit_from_hdr(hhdr, bit_no);
+ ++hhdr -> hb_n_marks;
+ }
+
+ q = obj_link(q);
+ if (q == NULL)
+ break;
+
+ h = HBLKPTR(q);
+ if (h != last_h) {
+ last_h = h;
+ hhdr = HDR(h);
+ IF_PER_OBJ(sz = hhdr->hb_sz;)
+ }
+ }
}
}
-/* Clear all mark bits for the free list whose first entry is q */
-/* Decrement GC_mem_found by number of words on free list. */
-#ifdef __STDC__
- void GC_clear_fl_marks(ptr_t q)
-#else
- void GC_clear_fl_marks(q)
- ptr_t q;
-#endif
+#if defined(GC_ASSERTIONS) && defined(THREADS) && defined(THREAD_LOCAL_ALLOC)
+ /* Check that all mark bits for the free list whose first entry is */
+ /* (*pfreelist) are set. Check skipped if points to a special value. */
+ void GC_check_fl_marks(void **pfreelist)
+ {
+# ifdef AO_HAVE_load_acquire_read
+ AO_t *list = (AO_t *)AO_load_acquire_read((AO_t *)pfreelist);
+ /* Atomic operations are used because the world is running. */
+ AO_t *prev;
+ AO_t *p;
+
+ if ((word)list <= HBLKSIZE) return;
+
+ prev = (AO_t *)pfreelist;
+ for (p = list; p != NULL;) {
+ AO_t *next;
+
+ if (!GC_is_marked(p)) {
+ GC_err_printf("Unmarked object %p on list %p\n",
+ (void *)p, (void *)list);
+ ABORT("Unmarked local free list entry");
+ }
+
+ /* While traversing the free-list, it re-reads the pointer to */
+ /* the current node before accepting its next pointer and */
+ /* bails out if the latter has changed. That way, it won't */
+ /* try to follow the pointer which might be been modified */
+ /* after the object was returned to the client. It might */
+ /* perform the mark-check on the just allocated object but */
+ /* that should be harmless. */
+ next = (AO_t *)AO_load_acquire_read(p);
+ if (AO_load(prev) != (AO_t)p)
+ break;
+ prev = p;
+ p = next;
+ }
+# else
+ /* FIXME: Not implemented (just skipped). */
+ (void)pfreelist;
+# endif
+ }
+#endif /* GC_ASSERTIONS && THREAD_LOCAL_ALLOC */
+
+/* Clear all mark bits for the free list whose first entry is q */
+/* Decrement GC_bytes_found by number of bytes on free list. */
+STATIC void GC_clear_fl_marks(ptr_t q)
{
- ptr_t p;
- struct hblk * h, * last_h = 0;
+ struct hblk *h, *last_h;
hdr *hhdr;
- int word_no;
-
- for (p = q; p != 0; p = obj_link(p)){
- h = HBLKPTR(p);
- if (h != last_h) {
- last_h = h;
- hhdr = HDR(h);
- }
- word_no = (((word *)p) - ((word *)h));
- clear_mark_bit_from_hdr(hhdr, word_no);
-# ifdef GATHERSTATS
- GC_mem_found -= hhdr -> hb_sz;
-# endif
+ size_t sz;
+ unsigned bit_no;
+
+ if (q != NULL) {
+ h = HBLKPTR(q);
+ last_h = h;
+ hhdr = HDR(h);
+ sz = hhdr->hb_sz; /* Normally set only once. */
+
+ for (;;) {
+ bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, sz);
+ if (mark_bit_from_hdr(hhdr, bit_no)) {
+ size_t n_marks = hhdr -> hb_n_marks - 1;
+ clear_mark_bit_from_hdr(hhdr, bit_no);
+# ifdef PARALLEL_MARK
+ /* Appr. count, don't decrement to zero! */
+ if (0 != n_marks || !GC_parallel) {
+ hhdr -> hb_n_marks = n_marks;
+ }
+# else
+ hhdr -> hb_n_marks = n_marks;
+# endif
+ }
+ GC_bytes_found -= sz;
+
+ q = obj_link(q);
+ if (q == NULL)
+ break;
+
+ h = HBLKPTR(q);
+ if (h != last_h) {
+ last_h = h;
+ hhdr = HDR(h);
+ sz = hhdr->hb_sz;
+ }
+ }
}
}
-/* Finish up a collection. Assumes lock is held, signals are disabled, */
-/* but the world is otherwise running. */
-void GC_finish_collection()
+#if defined(GC_ASSERTIONS) && defined(THREADS) && defined(THREAD_LOCAL_ALLOC)
+ void GC_check_tls(void);
+#endif
+
+GC_on_heap_resize_proc GC_on_heap_resize = 0;
+
+/* Finish up a collection. Assumes mark bits are consistent, lock is */
+/* held, but the world is otherwise running. */
+STATIC void GC_finish_collection(void)
{
-# ifdef PRINTTIMES
- CLOCK_TYPE start_time;
- CLOCK_TYPE finalize_time;
- CLOCK_TYPE done_time;
-
- GET_TIME(start_time);
- finalize_time = start_time;
+# ifndef SMALL_CONFIG
+ CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
+ CLOCK_TYPE finalize_time = 0;
+ CLOCK_TYPE done_time;
+# endif
+
+# if defined(GC_ASSERTIONS) && defined(THREADS) \
+ && defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
+ /* Check that we marked some of our own data. */
+ /* FIXME: Add more checks. */
+ GC_check_tls();
+# endif
+
+# ifndef SMALL_CONFIG
+ if (GC_print_stats)
+ GET_TIME(start_time);
# endif
-# ifdef GATHERSTATS
- GC_mem_found = 0;
+# ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
+ if (GC_bytes_found > 0)
+ GC_reclaimed_bytes_before_gc += (word)GC_bytes_found;
# endif
+ GC_bytes_found = 0;
# if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
- if (getenv("GC_PRINT_ADDRESS_MAP") != 0) {
- GC_print_address_map();
- }
+ if (GETENV("GC_PRINT_ADDRESS_MAP") != 0) {
+ GC_print_address_map();
+ }
# endif
COND_DUMP;
if (GC_find_leak) {
- /* Mark all objects on the free list. All objects should be */
- /* marked when we're done. */
- {
- register word size; /* current object size */
- int kind;
- ptr_t q;
-
- for (kind = 0; kind < GC_n_kinds; kind++) {
- for (size = 1; size <= MAXOBJSZ; size++) {
- q = GC_obj_kinds[kind].ok_freelist[size];
- if (q != 0) GC_set_fl_marks(q);
- }
- }
- }
- GC_start_reclaim(TRUE);
- /* The above just checks; it doesn't really reclaim anything. */
+ /* Mark all objects on the free list. All objects should be */
+ /* marked when we're done. */
+ word size; /* current object size */
+ unsigned kind;
+ ptr_t q;
+
+ for (kind = 0; kind < GC_n_kinds; kind++) {
+ for (size = 1; size <= MAXOBJGRANULES; size++) {
+ q = GC_obj_kinds[kind].ok_freelist[size];
+ if (q != 0) GC_set_fl_marks(q);
+ }
+ }
+ GC_start_reclaim(TRUE);
+ /* The above just checks; it doesn't really reclaim anything. */
}
- GC_finalize();
+# ifndef GC_NO_FINALIZATION
+ GC_finalize();
+# endif
# ifdef STUBBORN_ALLOC
GC_clean_changing_list();
# endif
-# ifdef PRINTTIMES
- GET_TIME(finalize_time);
+# ifndef SMALL_CONFIG
+ if (GC_print_stats)
+ GET_TIME(finalize_time);
# endif
if (GC_print_back_height) {
# ifdef MAKE_BACK_GRAPH
- GC_traverse_back_graph();
-# else
-# ifndef SMALL_CONFIG
- GC_err_printf0("Back height not available: "
- "Rebuild collector with -DMAKE_BACK_GRAPH\n");
-# endif
+ GC_traverse_back_graph();
+# elif !defined(SMALL_CONFIG)
+ GC_err_printf("Back height not available: "
+ "Rebuild collector with -DMAKE_BACK_GRAPH\n");
# endif
}
/* Clear free list mark bits, in case they got accidentally marked */
- /* (or GC_find_leak is set and they were intentionally marked). */
- /* Also subtract memory remaining from GC_mem_found count. */
+ /* (or GC_find_leak is set and they were intentionally marked). */
+ /* Also subtract memory remaining from GC_bytes_found count. */
/* Note that composite objects on free list are cleared. */
/* Thus accidentally marking a free list is not a problem; only */
/* objects on the list itself will be marked, and that's fixed here. */
- {
- register word size; /* current object size */
- register ptr_t q; /* pointer to current object */
- int kind;
-
- for (kind = 0; kind < GC_n_kinds; kind++) {
- for (size = 1; size <= MAXOBJSZ; size++) {
- q = GC_obj_kinds[kind].ok_freelist[size];
- if (q != 0) GC_clear_fl_marks(q);
- }
- }
+ {
+ word size; /* current object size */
+ ptr_t q; /* pointer to current object */
+ unsigned kind;
+
+ for (kind = 0; kind < GC_n_kinds; kind++) {
+ for (size = 1; size <= MAXOBJGRANULES; size++) {
+ q = GC_obj_kinds[kind].ok_freelist[size];
+ if (q != 0) GC_clear_fl_marks(q);
+ }
}
+ }
+ GC_VERBOSE_LOG_PRINTF("Bytes recovered before sweep - f.l. count = %ld\n",
+ (long)GC_bytes_found);
-# ifdef PRINTSTATS
- GC_printf1("Bytes recovered before sweep - f.l. count = %ld\n",
- (long)WORDS_TO_BYTES(GC_mem_found));
-# endif
/* Reconstruct free lists to contain everything not marked */
- GC_start_reclaim(FALSE);
- if (GC_is_full_gc) {
- GC_used_heap_size_after_full = USED_HEAP_SIZE;
- GC_need_full_gc = FALSE;
- } else {
- GC_need_full_gc =
- BYTES_TO_WORDS(USED_HEAP_SIZE - GC_used_heap_size_after_full)
- > min_words_allocd();
- }
-
-# ifdef PRINTSTATS
- GC_printf2(
- "Immediately reclaimed %ld bytes in heap of size %lu bytes",
- (long)WORDS_TO_BYTES(GC_mem_found),
- (unsigned long)GC_heapsize);
-# ifdef USE_MUNMAP
- GC_printf1("(%lu unmapped)", GC_unmapped_bytes);
-# endif
- GC_printf2(
- "\n%lu (atomic) + %lu (composite) collectable bytes in use\n",
- (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
- (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
-# endif
+ GC_start_reclaim(FALSE);
+ GC_COND_LOG_PRINTF("Heap contains %lu pointer-containing"
+ " + %lu pointer-free reachable bytes\n",
+ (unsigned long)GC_composite_in_use,
+ (unsigned long)GC_atomic_in_use);
+ if (GC_is_full_gc) {
+ GC_used_heap_size_after_full = USED_HEAP_SIZE;
+ GC_need_full_gc = FALSE;
+ } else {
+ GC_need_full_gc = USED_HEAP_SIZE - GC_used_heap_size_after_full
+ > min_bytes_allocd();
+ }
+
+ GC_VERBOSE_LOG_PRINTF("Immediately reclaimed %ld bytes, heapsize:"
+ " %lu bytes" IF_USE_MUNMAP(" (%lu unmapped)") "\n",
+ (long)GC_bytes_found,
+ (unsigned long)GC_heapsize /*, */
+ COMMA_IF_USE_MUNMAP((unsigned long)
+ GC_unmapped_bytes));
- GC_n_attempts = 0;
- GC_is_full_gc = FALSE;
/* Reset or increment counters for next cycle */
- GC_words_allocd_before_gc += GC_words_allocd;
- GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
- GC_words_allocd = 0;
- GC_words_wasted = 0;
- GC_mem_freed = 0;
- GC_finalizer_mem_freed = 0;
-
-# ifdef USE_MUNMAP
- GC_unmap_old();
-# endif
-# ifdef PRINTTIMES
- GET_TIME(done_time);
- GC_printf2("Finalize + initiate sweep took %lu + %lu msecs\n",
- MS_TIME_DIFF(finalize_time,start_time),
- MS_TIME_DIFF(done_time,finalize_time));
+ GC_n_attempts = 0;
+ GC_is_full_gc = FALSE;
+ 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;
+
+ IF_USE_MUNMAP(GC_unmap_old());
+
+# ifndef SMALL_CONFIG
+ if (GC_print_stats) {
+ GET_TIME(done_time);
+
+ /* A convenient place to output finalization statistics. */
+# ifndef GC_NO_FINALIZATION
+ GC_print_finalization_stats();
+# endif
+
+ GC_stats_log_printf(
+ "Finalize plus initiate sweep took %lu + %lu msecs\n",
+ MS_TIME_DIFF(finalize_time,start_time),
+ MS_TIME_DIFF(done_time,finalize_time));
+ }
# endif
}
-/* Externally callable routine to invoke full, stop-world collection */
-# if defined(__STDC__) || defined(__cplusplus)
- int GC_try_to_collect(GC_stop_func stop_func)
-# else
- int GC_try_to_collect(stop_func)
- GC_stop_func stop_func;
-# endif
+/* If stop_func == 0 then GC_default_stop_func is used instead. */
+STATIC GC_bool GC_try_to_collect_general(GC_stop_func stop_func,
+ GC_bool force_unmap GC_ATTR_UNUSED)
{
- int result;
+ GC_bool result;
+ IF_USE_MUNMAP(int old_unmap_threshold;)
+ IF_CANCEL(int cancel_state;)
DCL_LOCK_STATE;
-
+
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
if (GC_debugging_started) GC_print_all_smashed();
GC_INVOKE_FINALIZERS();
- DISABLE_SIGNALS();
LOCK();
+ DISABLE_CANCEL(cancel_state);
+# ifdef USE_MUNMAP
+ old_unmap_threshold = GC_unmap_threshold;
+ if (force_unmap ||
+ (GC_force_unmap_on_gcollect && old_unmap_threshold > 0))
+ GC_unmap_threshold = 1; /* unmap as much as possible */
+# endif
ENTER_GC();
- if (!GC_is_initialized) GC_init_inner();
/* Minimize junk left in my registers */
- GC_noop(0,0,0,0,0,0);
- result = (int)GC_try_to_collect_inner(stop_func);
+ GC_noop6(0,0,0,0,0,0);
+ result = GC_try_to_collect_inner(stop_func != 0 ? stop_func :
+ GC_default_stop_func);
EXIT_GC();
+ IF_USE_MUNMAP(GC_unmap_threshold = old_unmap_threshold); /* restore */
+ RESTORE_CANCEL(cancel_state);
UNLOCK();
- ENABLE_SIGNALS();
- if(result) {
+ if (result) {
if (GC_debugging_started) GC_print_all_smashed();
GC_INVOKE_FINALIZERS();
}
return(result);
}
-void GC_gcollect GC_PROTO(())
+/* Externally callable routines to invoke full, stop-the-world collection. */
+GC_API int GC_CALL GC_try_to_collect(GC_stop_func stop_func)
{
- (void)GC_try_to_collect(GC_never_stop_func);
+ GC_ASSERT(stop_func != 0);
+ return (int)GC_try_to_collect_general(stop_func, FALSE);
+}
+
+GC_API void GC_CALL GC_gcollect(void)
+{
+ /* 0 is passed as stop_func to get GC_default_stop_func value */
+ /* while holding the allocation lock (to prevent data races). */
+ (void)GC_try_to_collect_general(0, FALSE);
if (GC_have_errors) GC_print_all_errors();
}
-word GC_n_heap_sects = 0; /* Number of sections currently in heap. */
+GC_API void GC_CALL GC_gcollect_and_unmap(void)
+{
+ (void)GC_try_to_collect_general(GC_never_stop_func, TRUE);
+}
+
+GC_INNER word GC_n_heap_sects = 0;
+ /* Number of sections currently in heap. */
+
+#ifdef USE_PROC_FOR_LIBRARIES
+ GC_INNER 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. */
+ GC_INNER void GC_add_to_our_memory(ptr_t p, size_t bytes)
+ {
+ if (0 == p) return;
+ if (GC_n_memory >= MAX_HEAP_SECTS)
+ ABORT("Too many GC-allocated memory sections: Increase MAX_HEAP_SECTS");
+ 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.
*/
-void GC_add_to_heap(p, bytes)
-struct hblk *p;
-word bytes;
+GC_INNER void GC_add_to_heap(struct hblk *p, size_t bytes)
{
- word words;
hdr * phdr;
-
+ word endp;
+
if (GC_n_heap_sects >= MAX_HEAP_SECTS) {
- ABORT("Too many heap sections: Increase MAXHINCR or 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 */
- /* almost certainly result in a 0 return from the allocator, */
- /* which is entirely appropriate. */
- return;
+ /* This is extremely unlikely. Can't add it. This will */
+ /* almost certainly result in a 0 return from the allocator, */
+ /* 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++;
- words = BYTES_TO_WORDS(bytes);
- phdr -> hb_sz = words;
- phdr -> hb_map = (unsigned char *)1; /* A value != GC_invalid_map */
+ phdr -> hb_sz = bytes;
phdr -> hb_flags = 0;
GC_freehblk(p);
GC_heapsize += bytes;
- if ((ptr_t)p <= (ptr_t)GC_least_plausible_heap_addr
+ if ((word)p <= (word)GC_least_plausible_heap_addr
|| GC_least_plausible_heap_addr == 0) {
- GC_least_plausible_heap_addr = (GC_PTR)((ptr_t)p - sizeof(word));
- /* Making it a little smaller than necessary prevents */
- /* us from getting a false hit from the variable */
- /* itself. There's some unintentional reflection */
- /* here. */
+ GC_least_plausible_heap_addr = (void *)((ptr_t)p - sizeof(word));
+ /* Making it a little smaller than necessary prevents */
+ /* us from getting a false hit from the variable */
+ /* itself. There's some unintentional reflection */
+ /* here. */
}
- if ((ptr_t)p + bytes >= (ptr_t)GC_greatest_plausible_heap_addr) {
- GC_greatest_plausible_heap_addr = (GC_PTR)((ptr_t)p + bytes);
+ if ((word)p + bytes >= (word)GC_greatest_plausible_heap_addr) {
+ GC_greatest_plausible_heap_addr = (void *)endp;
}
}
-# if !defined(NO_DEBUGGING)
-void GC_print_heap_sects()
-{
- register unsigned i;
-
- GC_printf1("Total heap size: %lu\n", (unsigned long) GC_heapsize);
+#if !defined(NO_DEBUGGING)
+ void GC_print_heap_sects(void)
+ {
+ unsigned i;
+
+ GC_printf("Total heap size: %lu" IF_USE_MUNMAP(" (%lu unmapped)") "\n",
+ (unsigned long)GC_heapsize /*, */
+ COMMA_IF_USE_MUNMAP((unsigned long)GC_unmapped_bytes));
+
for (i = 0; i < GC_n_heap_sects; i++) {
- unsigned long start = (unsigned long) GC_heap_sects[i].hs_start;
- unsigned long len = (unsigned long) GC_heap_sects[i].hs_bytes;
- struct hblk *h;
- unsigned nbl = 0;
-
- GC_printf3("Section %ld from 0x%lx to 0x%lx ", (unsigned long)i,
- start, (unsigned long)(start + len));
- for (h = (struct hblk *)start; h < (struct hblk *)(start + len); h++) {
- if (GC_is_black_listed(h, HBLKSIZE)) nbl++;
- }
- GC_printf2("%lu/%lu blacklisted\n", (unsigned long)nbl,
- (unsigned long)(len/HBLKSIZE));
+ ptr_t start = GC_heap_sects[i].hs_start;
+ size_t len = GC_heap_sects[i].hs_bytes;
+ struct hblk *h;
+ unsigned nbl = 0;
+
+ for (h = (struct hblk *)start; (word)h < (word)(start + len); h++) {
+ if (GC_is_black_listed(h, HBLKSIZE)) nbl++;
+ }
+ GC_printf("Section %d from %p to %p %lu/%lu blacklisted\n",
+ i, start, start + len,
+ (unsigned long)nbl, (unsigned long)(len/HBLKSIZE));
}
-}
-# endif
+ }
+#endif
-GC_PTR GC_least_plausible_heap_addr = (GC_PTR)ONES;
-GC_PTR GC_greatest_plausible_heap_addr = 0;
+void * GC_least_plausible_heap_addr = (void *)ONES;
+void * GC_greatest_plausible_heap_addr = 0;
-ptr_t GC_max(x,y)
-ptr_t x, y;
+GC_INLINE word GC_max(word x, word y)
{
return(x > y? x : y);
}
-ptr_t GC_min(x,y)
-ptr_t x, y;
+GC_INLINE word GC_min(word x, word y)
{
return(x < y? x : y);
}
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_set_max_heap_size(GC_word n)
-# else
- void GC_set_max_heap_size(n)
- GC_word n;
-# endif
+STATIC word GC_max_heapsize = 0;
+
+GC_API void GC_CALL GC_set_max_heap_size(GC_word n)
{
GC_max_heapsize = n;
}
@@ -886,200 +1140,218 @@ GC_word GC_max_retries = 0;
* Tiny values of n are rounded up.
* Returns FALSE on failure.
*/
-GC_bool GC_expand_hp_inner(n)
-word n;
+GC_INNER GC_bool GC_expand_hp_inner(word n)
{
word bytes;
struct hblk * space;
- word expansion_slop; /* Number of bytes by which we expect the */
- /* heap to expand soon. */
+ word expansion_slop; /* Number of bytes by which we expect the */
+ /* heap to expand soon. */
if (n < MINHINCR) n = MINHINCR;
bytes = n * HBLKSIZE;
/* Make sure bytes is a multiple of GC_page_size */
{
- word mask = GC_page_size - 1;
- bytes += mask;
- bytes &= ~mask;
+ word mask = GC_page_size - 1;
+ bytes += mask;
+ bytes &= ~mask;
}
-
+
if (GC_max_heapsize != 0 && GC_heapsize + bytes > GC_max_heapsize) {
/* Exceeded self-imposed limit */
return(FALSE);
}
space = GET_MEM(bytes);
- if( space == 0 ) {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Failed to expand heap by %ld bytes\n",
- (unsigned long)bytes);
- }
-# endif
- return(FALSE);
+ GC_add_to_our_memory((ptr_t)space, bytes);
+ if (space == 0) {
+ GC_COND_LOG_PRINTF("Failed to expand heap by %lu bytes\n",
+ (unsigned long)bytes);
+ return(FALSE);
}
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf2("Increasing heap size by %lu after %lu allocated bytes\n",
- (unsigned long)bytes,
- (unsigned long)WORDS_TO_BYTES(GC_words_allocd));
-# ifdef UNDEFINED
- GC_printf1("Root size = %lu\n", GC_root_size);
- GC_print_block_list(); GC_print_hblkfreelist();
- GC_printf0("\n");
-# endif
- }
-# endif
- expansion_slop = WORDS_TO_BYTES(min_words_allocd()) + 4*MAXHINCR*HBLKSIZE;
- if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
- || GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) {
+ GC_COND_LOG_PRINTF(
+ "Increasing heap size by %lu after %lu allocated bytes\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 needed for */
+ /* correctness. */
+ expansion_slop = min_bytes_allocd() + 4*MAXHINCR*HBLKSIZE;
+ if ((GC_last_heap_addr == 0 && !((word)space & SIGNB))
+ || (GC_last_heap_addr != 0
+ && (word)GC_last_heap_addr < (word)space)) {
/* Assume the heap is growing up */
- GC_greatest_plausible_heap_addr =
- (GC_PTR)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 =
- (GC_PTR)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);
/* Force GC before we are likely to allocate past expansion_slop */
GC_collect_at_heapsize =
- GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE;
-# if defined(LARGE_CONFIG)
- if (GC_collect_at_heapsize < GC_heapsize /* wrapped */)
- GC_collect_at_heapsize = (word)(-1);
-# endif
+ GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE;
+ if (GC_collect_at_heapsize < GC_heapsize /* wrapped */)
+ GC_collect_at_heapsize = (word)(-1);
+ if (GC_on_heap_resize)
+ (*GC_on_heap_resize)(GC_heapsize);
+
return(TRUE);
}
/* Really returns a bool, but it's externally visible, so that's clumsy. */
-/* Arguments is in bytes. */
-# if defined(__STDC__) || defined(__cplusplus)
- int GC_expand_hp(size_t bytes)
-# else
- int GC_expand_hp(bytes)
- size_t bytes;
-# endif
+/* Arguments is in bytes. Includes GC_init() call. */
+GC_API int GC_CALL GC_expand_hp(size_t bytes)
{
int result;
DCL_LOCK_STATE;
-
- DISABLE_SIGNALS();
+
LOCK();
- if (!GC_is_initialized) GC_init_inner();
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
result = (int)GC_expand_hp_inner(divHBLKSZ((word)bytes));
if (result) GC_requested_heapsize += bytes;
UNLOCK();
- ENABLE_SIGNALS();
return(result);
}
-unsigned GC_fail_count = 0;
- /* How many consecutive GC/expansion failures? */
- /* Reset by GC_allochblk. */
+word GC_fo_entries = 0; /* used also in extra/MacOS.c */
+
+GC_INNER unsigned GC_fail_count = 0;
+ /* How many consecutive GC/expansion failures? */
+ /* Reset by GC_allochblk. */
-GC_bool GC_collect_or_expand(needed_blocks, ignore_off_page)
-word needed_blocks;
-GC_bool ignore_off_page;
+static word last_fo_entries = 0;
+static word last_bytes_finalized = 0;
+
+/* Collect or expand heap in an attempt make the indicated number of */
+/* free blocks available. Should be called until the blocks are */
+/* available (seting retry value to TRUE unless this is the first call */
+/* in a loop) or until it fails by returning FALSE. */
+GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
+ GC_bool ignore_off_page,
+ GC_bool retry)
{
+ GC_bool gc_not_stopped = TRUE;
+ word blocks_to_get;
+ IF_CANCEL(int cancel_state;)
+
+ DISABLE_CANCEL(cancel_state);
if (!GC_incremental && !GC_dont_gc &&
- (GC_dont_expand && GC_words_allocd > 0 || GC_should_collect())) {
- GC_gcollect_inner();
- } else {
- word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
- + needed_blocks;
-
- if (blocks_to_get > MAXHINCR) {
- word slop;
-
- if (ignore_off_page) {
- slop = 4;
- } else {
- slop = 2*divHBLKSZ(BL_LIMIT);
- if (slop > needed_blocks) slop = needed_blocks;
- }
- if (needed_blocks + slop > MAXHINCR) {
- blocks_to_get = needed_blocks + slop;
- } else {
- blocks_to_get = MAXHINCR;
- }
+ ((GC_dont_expand && GC_bytes_allocd > 0)
+ || (GC_fo_entries > (last_fo_entries + 500)
+ && (last_bytes_finalized | GC_bytes_finalized) != 0)
+ || GC_should_collect())) {
+ /* Try to do a full collection using 'default' stop_func (unless */
+ /* nothing has been allocated since the latest collection or heap */
+ /* expansion is disabled). */
+ gc_not_stopped = GC_try_to_collect_inner(
+ GC_bytes_allocd > 0 && (!GC_dont_expand || !retry) ?
+ GC_default_stop_func : GC_never_stop_func);
+ if (gc_not_stopped == TRUE || !retry) {
+ /* Either the collection hasn't been aborted or this is the */
+ /* first attempt (in a loop). */
+ last_fo_entries = GC_fo_entries;
+ last_bytes_finalized = GC_bytes_finalized;
+ RESTORE_CANCEL(cancel_state);
+ return(TRUE);
}
- if (!GC_expand_hp_inner(blocks_to_get)
+ }
+
+ blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
+ + needed_blocks;
+ if (blocks_to_get > MAXHINCR) {
+ word slop;
+
+ /* Get the minimum required to make it likely that we can satisfy */
+ /* the current request in the presence of black-listing. */
+ /* This will probably be more than MAXHINCR. */
+ if (ignore_off_page) {
+ slop = 4;
+ } else {
+ slop = 2 * divHBLKSZ(BL_LIMIT);
+ if (slop > needed_blocks) slop = needed_blocks;
+ }
+ if (needed_blocks + slop > MAXHINCR) {
+ blocks_to_get = needed_blocks + slop;
+ } else {
+ blocks_to_get = MAXHINCR;
+ }
+ }
+
+ if (!GC_expand_hp_inner(blocks_to_get)
&& !GC_expand_hp_inner(needed_blocks)) {
- if (GC_fail_count++ < GC_max_retries) {
- WARN("Out of Memory! Trying to continue ...\n", 0);
- GC_gcollect_inner();
- } else {
-# if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
- WARN("Out of Memory! Returning NIL!\n", 0);
-# endif
- return(FALSE);
- }
+ if (gc_not_stopped == FALSE) {
+ /* Don't increment GC_fail_count here (and no warning). */
+ GC_gcollect_inner();
+ GC_ASSERT(GC_bytes_allocd == 0);
+ } else if (GC_fail_count++ < GC_max_retries) {
+ WARN("Out of Memory! Trying to continue ...\n", 0);
+ GC_gcollect_inner();
} else {
-# ifdef CONDPRINT
- if (GC_fail_count && GC_print_stats) {
- GC_printf0("Memory available again ...\n");
- }
-# endif
+# if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
+ WARN("Out of Memory! Heap size: %" WARN_PRIdPTR " MiB."
+ " Returning NULL!\n", (GC_heapsize - GC_unmapped_bytes) >> 20);
+# endif
+ RESTORE_CANCEL(cancel_state);
+ return(FALSE);
}
+ } else if (GC_fail_count) {
+ GC_COND_LOG_PRINTF("Memory available again...\n");
}
+ RESTORE_CANCEL(cancel_state);
return(TRUE);
}
/*
- * Make sure the object free list for sz is not empty.
+ * Make sure the object free list for size gran (in granules) is not empty.
* Return a pointer to the first object on the free list.
* The object MUST BE REMOVED FROM THE FREE LIST BY THE CALLER.
- * Assumes we hold the allocator lock and signals are disabled.
- *
+ * Assumes we hold the allocator lock.
*/
-ptr_t GC_allocobj(sz, kind)
-word sz;
-int kind;
+GC_INNER ptr_t GC_allocobj(size_t gran, int kind)
{
- ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
+ void ** flh = &(GC_obj_kinds[kind].ok_freelist[gran]);
GC_bool tried_minor = FALSE;
-
- if (sz == 0) return(0);
+ GC_bool retry = FALSE;
+
+ if (gran == 0) return(0);
while (*flh == 0) {
ENTER_GC();
/* Do our share of marking work */
if(TRUE_INCREMENTAL) GC_collect_a_little_inner(1);
/* Sweep blocks for objects of this size */
- GC_continue_reclaim(sz, kind);
+ GC_continue_reclaim(gran, kind);
EXIT_GC();
if (*flh == 0) {
- GC_new_hblk(sz, kind);
+ GC_new_hblk(gran, kind);
}
if (*flh == 0) {
ENTER_GC();
- if (GC_incremental && GC_time_limit == GC_TIME_UNLIMITED
- && ! tried_minor ) {
- GC_collect_a_little_inner(1);
- tried_minor = TRUE;
- } else {
- if (!GC_collect_or_expand((word)1,FALSE)) {
- EXIT_GC();
- return(0);
- }
- }
- EXIT_GC();
+ if (GC_incremental && GC_time_limit == GC_TIME_UNLIMITED
+ && !tried_minor) {
+ GC_collect_a_little_inner(1);
+ tried_minor = TRUE;
+ } else {
+ if (!GC_collect_or_expand(1, FALSE, retry)) {
+ EXIT_GC();
+ return(0);
+ }
+ retry = TRUE;
+ }
+ EXIT_GC();
}
}
- /* Successful allocation; reset failure count. */
+ /* Successful allocation; reset failure count. */
GC_fail_count = 0;
-
+
return(*flh);
}
diff --git a/boehm-gc/alpha_mach_dep.s b/boehm-gc/alpha_mach_dep.s
deleted file mode 100644
index 53547307a5d..00000000000
--- a/boehm-gc/alpha_mach_dep.s
+++ /dev/null
@@ -1,87 +0,0 @@
- # $Id: alpha_mach_dep.s,v 1.2 1993/01/18 22:54:51 dosser Exp $
- .arch ev6
-
- .text
- .align 4
- .globl GC_push_regs
- .ent GC_push_regs 2
-GC_push_regs:
- ldgp $gp, 0($27)
- lda $sp, -16($sp)
- stq $26, 0($sp)
- .mask 0x04000000, 0
- .frame $sp, 16, $26, 0
-
- # $0 integer result
- # $1-$8 temp regs - not preserved cross calls
- # $9-$15 call saved regs
- # $16-$21 argument regs - not preserved cross calls
- # $22-$28 temp regs - not preserved cross calls
- # $29 global pointer - not preserved cross calls
- # $30 stack pointer
-
-# define call_push(x) \
- mov x, $16; \
- jsr $26, GC_push_one; \
- ldgp $gp, 0($26)
-
- call_push($9)
- call_push($10)
- call_push($11)
- call_push($12)
- call_push($13)
- call_push($14)
- call_push($15)
-
- # $f0-$f1 floating point results
- # $f2-$f9 call saved regs
- # $f10-$f30 temp regs - not preserved cross calls
-
- # Use the most efficient transfer method for this hardware.
- # Bit 1 detects the FIX extension, which includes ftoit.
- amask 2, $0
- bne $0, $use_stack
-
-#undef call_push
-#define call_push(x) \
- ftoit x, $16; \
- jsr $26, GC_push_one; \
- ldgp $gp, 0($26)
-
- call_push($f2)
- call_push($f3)
- call_push($f4)
- call_push($f5)
- call_push($f6)
- call_push($f7)
- call_push($f8)
- call_push($f9)
-
- ldq $26, 0($sp)
- lda $sp, 16($sp)
- ret $31, ($26), 1
-
- .align 4
-$use_stack:
-
-#undef call_push
-#define call_push(x) \
- stt x, 8($sp); \
- ldq $16, 8($sp); \
- jsr $26, GC_push_one; \
- ldgp $gp, 0($26)
-
- call_push($f2)
- call_push($f3)
- call_push($f4)
- call_push($f5)
- call_push($f6)
- call_push($f7)
- call_push($f8)
- call_push($f9)
-
- ldq $26, 0($sp)
- lda $sp, 16($sp)
- ret $31, ($26), 1
-
- .end GC_push_regs
diff --git a/boehm-gc/autogen.sh b/boehm-gc/autogen.sh
new file mode 100755
index 00000000000..8a614f919d1
--- /dev/null
+++ b/boehm-gc/autogen.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+set -e
+
+# This script creates (or regenerates) configure (as well as aclocal.m4,
+# config.h.in, Makefile.in, etc.) missing in the source repository.
+#
+# If you compile from a distribution tarball, you can skip this. Otherwise,
+# make sure that you have Autoconf, Automake, Libtool, and pkg-config
+# installed on your system, and that the corresponding *.m4 files are visible
+# to the aclocal. The latter can be achieved by using packages shipped by
+# your OS, or by installing custom versions of all four packages to the same
+# prefix. Otherwise, you may need to invoke autoreconf with the appropriate
+# -I options to locate the required *.m4 files.
+
+autoreconf -i
+
+echo
+echo "Ready to run './configure'."
diff --git a/boehm-gc/backgraph.c b/boehm-gc/backgraph.c
new file mode 100644
index 00000000000..3659f8782ce
--- /dev/null
+++ b/boehm-gc/backgraph.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2001 by Hewlett-Packard Company. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+#include "private/dbg_mlc.h"
+
+/*
+ * This implements a full, though not well-tuned, representation of the
+ * backwards points-to graph. This is used to test for non-GC-robust
+ * data structures; the code is not used during normal garbage collection.
+ *
+ * One restriction is that we drop all back-edges from nodes with very
+ * high in-degree, and simply add them add them to a list of such
+ * nodes. They are then treated as permanent roots. Id this by itself
+ * doesn't introduce a space leak, then such nodes can't contribute to
+ * a growing space leak.
+ */
+
+#ifdef MAKE_BACK_GRAPH
+
+#define MAX_IN 10 /* Maximum in-degree we handle directly */
+
+/* #include <unistd.h> */
+
+#if !defined(DBG_HDRS_ALL) || (ALIGNMENT != CPP_WORDSZ/8) /* || !defined(UNIX_LIKE) */
+# error The configuration does not support MAKE_BACK_GRAPH
+#endif
+
+/* We store single back pointers directly in the object's oh_bg_ptr field. */
+/* If there is more than one ptr to an object, we store q | FLAG_MANY, */
+/* where q is a pointer to a back_edges object. */
+/* Every once in a while we use a back_edges object even for a single */
+/* pointer, since we need the other fields in the back_edges structure to */
+/* be present in some fraction of the objects. Otherwise we get serious */
+/* performance issues. */
+#define FLAG_MANY 2
+
+typedef struct back_edges_struct {
+ word n_edges; /* Number of edges, including those in continuation */
+ /* structures. */
+ unsigned short flags;
+# define RETAIN 1 /* Directly points to a reachable object; */
+ /* retain for next GC. */
+ unsigned short height_gc_no;
+ /* If height > 0, then the GC_gc_no value when it */
+ /* was computed. If it was computed this cycle, then */
+ /* it is current. If it was computed during the */
+ /* last cycle, then it represents the old height, */
+ /* which is only saved for live objects referenced by */
+ /* dead ones. This may grow due to refs from newly */
+ /* dead objects. */
+ signed_word height;
+ /* Longest path through unreachable nodes to this node */
+ /* that we found using depth first search. */
+
+# define HEIGHT_UNKNOWN ((signed_word)(-2))
+# define HEIGHT_IN_PROGRESS ((signed_word)(-1))
+ ptr_t edges[MAX_IN];
+ struct back_edges_struct *cont;
+ /* Pointer to continuation structure; we use only the */
+ /* edges field in the continuation. */
+ /* also used as free list link. */
+} back_edges;
+
+/* Allocate a new back edge structure. Should be more sophisticated */
+/* if this were production code. */
+#define MAX_BACK_EDGE_STRUCTS 100000
+static back_edges *back_edge_space = 0;
+STATIC int GC_n_back_edge_structs = 0;
+ /* Serves as pointer to never used */
+ /* back_edges space. */
+static back_edges *avail_back_edges = 0;
+ /* Pointer to free list of deallocated */
+ /* back_edges structures. */
+
+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;
+ avail_back_edges = result -> cont;
+ result -> cont = 0;
+ return result;
+ }
+ if (GC_n_back_edge_structs >= MAX_BACK_EDGE_STRUCTS - 1) {
+ ABORT("Needed too much space for back edges: adjust "
+ "MAX_BACK_EDGE_STRUCTS");
+ }
+ return back_edge_space + (GC_n_back_edge_structs++);
+}
+
+/* Deallocate p and its associated continuation structures. */
+static void deallocate_back_edges(back_edges *p)
+{
+ back_edges *last = p;
+
+ while (0 != last -> cont) last = last -> cont;
+ last -> cont = avail_back_edges;
+ avail_back_edges = p;
+}
+
+/* Table of objects that are currently on the depth-first search */
+/* stack. Only objects with in-degree one are in this table. */
+/* Other objects are identified using HEIGHT_IN_PROGRESS. */
+/* FIXME: This data structure NEEDS IMPROVEMENT. */
+#define INITIAL_IN_PROGRESS 10000
+static ptr_t * in_progress_space = 0;
+static size_t in_progress_size = 0;
+static size_t n_in_progress = 0;
+
+static void push_in_progress(ptr_t p)
+{
+ if (n_in_progress >= in_progress_size) {
+ 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;
+ /* FIXME: This just drops the old space. */
+ }
+ }
+ if (in_progress_space == 0)
+ ABORT("MAKE_BACK_GRAPH: Out of in-progress space: "
+ "Huge linear data structure?");
+ in_progress_space[n_in_progress++] = p;
+}
+
+static GC_bool is_in_progress(ptr_t p)
+{
+ size_t i;
+ for (i = 0; i < n_in_progress; ++i) {
+ if (in_progress_space[i] == p) return TRUE;
+ }
+ return FALSE;
+}
+
+GC_INLINE void pop_in_progress(ptr_t p GC_ATTR_UNUSED)
+{
+ --n_in_progress;
+ GC_ASSERT(in_progress_space[n_in_progress] == p);
+}
+
+#define GET_OH_BG_PTR(p) \
+ (ptr_t)GC_REVEAL_POINTER(((oh *)(p)) -> oh_bg_ptr)
+#define SET_OH_BG_PTR(p,q) (((oh *)(p)) -> oh_bg_ptr = GC_HIDE_POINTER(q))
+
+/* Execute s once for each predecessor q of p in the points-to graph. */
+/* s should be a bracketed statement. We declare q. */
+#define FOR_EACH_PRED(q, p, s) \
+ { \
+ ptr_t q = GET_OH_BG_PTR(p); \
+ if (!((word)q & FLAG_MANY)) { \
+ if (q && !((word)q & 1)) s \
+ /* !((word)q & 1) checks for a misinterpreted freelist link */ \
+ } else { \
+ back_edges *orig_be_ = (back_edges *)((word)q & ~FLAG_MANY); \
+ back_edges *be_ = orig_be_; \
+ int local_; \
+ word total_; \
+ word n_edges_ = be_ -> n_edges; \
+ for (total_ = 0, local_ = 0; total_ < n_edges_; ++local_, ++total_) { \
+ if (local_ == MAX_IN) { \
+ be_ = be_ -> cont; \
+ local_ = 0; \
+ } \
+ q = be_ -> edges[local_]; s \
+ } \
+ } \
+ }
+
+/* Ensure that p has a back_edges structure associated with it. */
+static void ensure_struct(ptr_t p)
+{
+ ptr_t old_back_ptr = GET_OH_BG_PTR(p);
+
+ if (!((word)old_back_ptr & FLAG_MANY)) {
+ back_edges *be = new_back_edges();
+ be -> flags = 0;
+ if (0 == old_back_ptr) {
+ be -> n_edges = 0;
+ } else {
+ be -> n_edges = 1;
+ be -> edges[0] = old_back_ptr;
+ }
+ be -> height = HEIGHT_UNKNOWN;
+ be -> height_gc_no = (unsigned short)(GC_gc_no - 1);
+ GC_ASSERT((word)be >= (word)back_edge_space);
+ SET_OH_BG_PTR(p, (word)be | FLAG_MANY);
+ }
+}
+
+/* Add the (forward) edge from p to q to the backward graph. Both p */
+/* q are pointers to the object base, i.e. pointers to an oh. */
+static void add_edge(ptr_t p, ptr_t q)
+{
+ ptr_t old_back_ptr = GET_OH_BG_PTR(q);
+ back_edges * be, *be_cont;
+ word i;
+ static unsigned random_number = 13;
+# define GOT_LUCKY_NUMBER (((++random_number) & 0x7f) == 0)
+ /* A not very random number we use to occasionally allocate a */
+ /* back_edges structure even for a single backward edge. This */
+ /* prevents us from repeatedly tracing back through very long */
+ /* chains, since we will have some place to store height and */
+ /* in_progress flags along the way. */
+
+ GC_ASSERT(p == GC_base(p) && q == GC_base(q));
+ if (!GC_HAS_DEBUG_INFO(q) || !GC_HAS_DEBUG_INFO(p)) {
+ /* This is really a misinterpreted free list link, since we saw */
+ /* a pointer to a free list. Don't overwrite it! */
+ return;
+ }
+ if (0 == old_back_ptr) {
+ SET_OH_BG_PTR(q, p);
+ if (GOT_LUCKY_NUMBER) ensure_struct(q);
+ return;
+ }
+ /* Check whether it was already in the list of predecessors. */
+ FOR_EACH_PRED(pred, q, { if (p == pred) return; });
+ ensure_struct(q);
+ old_back_ptr = GET_OH_BG_PTR(q);
+ be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY);
+ for (i = be -> n_edges, be_cont = be; i > MAX_IN; i -= MAX_IN)
+ be_cont = be_cont -> cont;
+ if (i == MAX_IN) {
+ be_cont -> cont = new_back_edges();
+ be_cont = be_cont -> cont;
+ i = 0;
+ }
+ be_cont -> edges[i] = p;
+ be -> n_edges++;
+# ifdef DEBUG_PRINT_BIG_N_EDGES
+ if (GC_print_stats == VERBOSE && be -> n_edges == 100) {
+ GC_err_printf("The following object has big in-degree:\n");
+ GC_print_heap_obj(q);
+ }
+# endif
+}
+
+typedef void (*per_object_func)(ptr_t p, size_t n_bytes, word gc_descr);
+
+static void per_object_helper(struct hblk *h, word fn)
+{
+ hdr * hhdr = HDR(h);
+ size_t sz = hhdr -> hb_sz;
+ word descr = hhdr -> hb_descr;
+ per_object_func f = (per_object_func)fn;
+ int i = 0;
+
+ do {
+ f((ptr_t)(h -> hb_body + i), sz, descr);
+ i += (int)sz;
+ } while ((word)i + sz <= BYTES_TO_WORDS(HBLKSIZE));
+}
+
+GC_INLINE void GC_apply_to_each_object(per_object_func f)
+{
+ GC_apply_to_all_blocks(per_object_helper, (word)f);
+}
+
+static void reset_back_edge(ptr_t p, size_t n_bytes GC_ATTR_UNUSED,
+ word gc_descr GC_ATTR_UNUSED)
+{
+ /* Skip any free list links, or dropped blocks */
+ if (GC_HAS_DEBUG_INFO(p)) {
+ ptr_t old_back_ptr = GET_OH_BG_PTR(p);
+ if ((word)old_back_ptr & FLAG_MANY) {
+ back_edges *be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY);
+ if (!(be -> flags & RETAIN)) {
+ deallocate_back_edges(be);
+ SET_OH_BG_PTR(p, 0);
+ } else {
+
+ GC_ASSERT(GC_is_marked(p));
+
+ /* Back edges may point to objects that will not be retained. */
+ /* Delete them for now, but remember the height. */
+ /* Some will be added back at next GC. */
+ be -> n_edges = 0;
+ if (0 != be -> cont) {
+ deallocate_back_edges(be -> cont);
+ be -> cont = 0;
+ }
+
+ GC_ASSERT(GC_is_marked(p));
+
+ /* We only retain things for one GC cycle at a time. */
+ be -> flags &= ~RETAIN;
+ }
+ } else /* Simple back pointer */ {
+ /* Clear to avoid dangling pointer. */
+ SET_OH_BG_PTR(p, 0);
+ }
+ }
+}
+
+static void add_back_edges(ptr_t p, size_t n_bytes, word gc_descr)
+{
+ word *currentp = (word *)(p + sizeof(oh));
+
+ /* For now, fix up non-length descriptors conservatively. */
+ if((gc_descr & GC_DS_TAGS) != GC_DS_LENGTH) {
+ gc_descr = n_bytes;
+ }
+ while ((word)currentp < (word)(p + gc_descr)) {
+ word current = *currentp++;
+ FIXUP_POINTER(current);
+ if (current >= (word)GC_least_plausible_heap_addr &&
+ current <= (word)GC_greatest_plausible_heap_addr) {
+ ptr_t target = GC_base((void *)current);
+ if (0 != target) {
+ add_edge(p, target);
+ }
+ }
+ }
+}
+
+/* Rebuild the representation of the backward reachability graph. */
+/* Does not examine mark bits. Can be called before GC. */
+GC_INNER void GC_build_back_graph(void)
+{
+ GC_apply_to_each_object(add_back_edges);
+}
+
+/* Return an approximation to the length of the longest simple path */
+/* through unreachable objects to p. We refer to this as the height */
+/* of p. */
+static word backwards_height(ptr_t p)
+{
+ word result;
+ ptr_t back_ptr = GET_OH_BG_PTR(p);
+ back_edges *be;
+
+ if (0 == back_ptr) return 1;
+ if (!((word)back_ptr & FLAG_MANY)) {
+ if (is_in_progress(p)) return 0; /* DFS back edge, i.e. we followed */
+ /* an edge to an object already */
+ /* on our stack: ignore */
+ push_in_progress(p);
+ result = backwards_height(back_ptr)+1;
+ pop_in_progress(p);
+ return result;
+ }
+ be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
+ if (be -> height >= 0 && be -> height_gc_no == (unsigned short)GC_gc_no)
+ return be -> height;
+ /* Ignore back edges in DFS */
+ if (be -> height == HEIGHT_IN_PROGRESS) return 0;
+ result = (be -> height > 0? be -> height : 1);
+ be -> height = HEIGHT_IN_PROGRESS;
+ FOR_EACH_PRED(q, p, {
+ word this_height;
+ if (GC_is_marked(q) && !(FLAG_MANY & (word)GET_OH_BG_PTR(p))) {
+ GC_COND_LOG_PRINTF("Found bogus pointer from %p to %p\n", q, p);
+ /* Reachable object "points to" unreachable one. */
+ /* Could be caused by our lax treatment of GC descriptors. */
+ this_height = 1;
+ } else {
+ this_height = backwards_height(q);
+ }
+ if (this_height >= result) result = this_height + 1;
+ });
+ be -> height = result;
+ be -> height_gc_no = (unsigned short)GC_gc_no;
+ return result;
+}
+
+STATIC word GC_max_height = 0;
+STATIC ptr_t GC_deepest_obj = NULL;
+
+/* Compute the maximum height of every unreachable predecessor p of a */
+/* reachable object. Arrange to save the heights of all such objects p */
+/* so that they can be used in calculating the height of objects in the */
+/* next GC. */
+/* Set GC_max_height to be the maximum height we encounter, and */
+/* GC_deepest_obj to be the corresponding object. */
+static void update_max_height(ptr_t p, size_t n_bytes GC_ATTR_UNUSED,
+ word gc_descr GC_ATTR_UNUSED)
+{
+ if (GC_is_marked(p) && GC_HAS_DEBUG_INFO(p)) {
+ word p_height = 0;
+ ptr_t p_deepest_obj = 0;
+ ptr_t back_ptr;
+ back_edges *be = 0;
+
+ /* If we remembered a height last time, use it as a minimum. */
+ /* It may have increased due to newly unreachable chains pointing */
+ /* to p, but it can't have decreased. */
+ back_ptr = GET_OH_BG_PTR(p);
+ if (0 != back_ptr && ((word)back_ptr & FLAG_MANY)) {
+ be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
+ if (be -> height != HEIGHT_UNKNOWN) p_height = be -> height;
+ }
+ FOR_EACH_PRED(q, p, {
+ if (!GC_is_marked(q) && GC_HAS_DEBUG_INFO(q)) {
+ word q_height;
+
+ q_height = backwards_height(q);
+ if (q_height > p_height) {
+ p_height = q_height;
+ p_deepest_obj = q;
+ }
+ }
+ });
+ if (p_height > 0) {
+ /* Remember the height for next time. */
+ if (be == 0) {
+ ensure_struct(p);
+ back_ptr = GET_OH_BG_PTR(p);
+ be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
+ }
+ be -> flags |= RETAIN;
+ be -> height = p_height;
+ be -> height_gc_no = (unsigned short)GC_gc_no;
+ }
+ if (p_height > GC_max_height) {
+ GC_max_height = p_height;
+ GC_deepest_obj = p_deepest_obj;
+ }
+ }
+}
+
+STATIC word GC_max_max_height = 0;
+
+GC_INNER void GC_traverse_back_graph(void)
+{
+ GC_max_height = 0;
+ GC_apply_to_each_object(update_max_height);
+ if (0 != GC_deepest_obj)
+ GC_set_mark_bit(GC_deepest_obj); /* Keep it until we can print it. */
+}
+
+void GC_print_back_graph_stats(void)
+{
+ GC_printf("Maximum backwards height of reachable objects at GC %lu is %lu\n",
+ (unsigned long) GC_gc_no, (unsigned long)GC_max_height);
+ if (GC_max_height > GC_max_max_height) {
+ GC_max_max_height = GC_max_height;
+ GC_err_printf(
+ "The following unreachable object is last in a longest chain "
+ "of unreachable objects:\n");
+ GC_print_heap_obj(GC_deepest_obj);
+ }
+ GC_COND_LOG_PRINTF("Needed max total of %d back-edge structs\n",
+ GC_n_back_edge_structs);
+ GC_apply_to_each_object(reset_back_edge);
+ GC_deepest_obj = 0;
+}
+
+#endif /* MAKE_BACK_GRAPH */
diff --git a/boehm-gc/bdw-gc.pc.in b/boehm-gc/bdw-gc.pc.in
new file mode 100644
index 00000000000..ef4c23410de
--- /dev/null
+++ b/boehm-gc/bdw-gc.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Boehm-Demers-Weiser Conservative Garbage Collector
+Description: A garbage collector for C and C++
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lgc
+Cflags: -I${includedir}
diff --git a/boehm-gc/blacklst.c b/boehm-gc/blacklst.c
index ae2f95cb3fe..77ad6758eac 100644
--- a/boehm-gc/blacklst.c
+++ b/boehm-gc/blacklst.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
*
@@ -11,8 +11,8 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, August 9, 1995 6:09 pm PDT */
-# include "private/gc_priv.h"
+
+#include "private/gc_priv.h"
/*
* We maintain several hash tables of hblks that have had false hits.
@@ -23,10 +23,10 @@
* from elsewhere, since the former can pin a large object that spans the
* block, eventhough it does not start on the dangerous block.
*/
-
+
/*
* Externally callable routines are:
-
+
* GC_add_to_black_list_normal
* GC_add_to_black_list_stack
* GC_promote_black_lists
@@ -35,100 +35,109 @@
* All require that the allocator lock is held.
*/
-/* Pointers to individual tables. We replace one table by another by */
-/* switching these pointers. */
-word * GC_old_normal_bl;
- /* Nonstack false references seen at last full */
- /* collection. */
-word * GC_incomplete_normal_bl;
- /* Nonstack false references seen since last */
- /* full collection. */
-word * GC_old_stack_bl;
-word * GC_incomplete_stack_bl;
-
-word GC_total_stack_black_listed;
-
-word GC_black_list_spacing = MINHINCR*HBLKSIZE; /* Initial rough guess */
-
-void GC_clear_bl();
-
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_default_print_heap_obj_proc(ptr_t p)
-# else
- void GC_default_print_heap_obj_proc(p)
- ptr_t p;
-# endif
+/* Pointers to individual tables. We replace one table by another by */
+/* switching these pointers. */
+STATIC word * GC_old_normal_bl = NULL;
+ /* Nonstack false references seen at last full */
+ /* collection. */
+STATIC word * GC_incomplete_normal_bl = NULL;
+ /* Nonstack false references seen since last */
+ /* full collection. */
+STATIC word * GC_old_stack_bl = NULL;
+STATIC word * GC_incomplete_stack_bl = NULL;
+
+STATIC word GC_total_stack_black_listed = 0;
+ /* Number of bytes on stack blacklist. */
+
+GC_INNER word GC_black_list_spacing = MINHINCR * HBLKSIZE;
+ /* Initial rough guess. */
+
+STATIC void GC_clear_bl(word *);
+
+GC_INNER void GC_default_print_heap_obj_proc(ptr_t p)
{
ptr_t base = GC_base(p);
+ int kind = HDR(base)->hb_obj_kind;
- GC_err_printf2("start: 0x%lx, appr. length: %ld", base, GC_size(base));
+ GC_err_printf("object at %p of appr. %lu bytes (%s)\n",
+ base, (unsigned long)GC_size(base),
+ kind == PTRFREE ? "atomic" :
+ IS_UNCOLLECTABLE(kind) ? "uncollectable" : "composite");
}
-void (*GC_print_heap_obj) GC_PROTO((ptr_t p)) =
- GC_default_print_heap_obj_proc;
+GC_INNER void (*GC_print_heap_obj)(ptr_t p) = GC_default_print_heap_obj_proc;
+
+#ifdef PRINT_BLACK_LIST
+ STATIC void GC_print_blacklisted_ptr(word p, ptr_t source,
+ const char *kind_str)
+ {
+ ptr_t base = GC_base(source);
-void GC_print_source_ptr(p)
-ptr_t p;
-{
- ptr_t base = GC_base(p);
if (0 == base) {
- if (0 == p) {
- GC_err_printf0("in register");
- } else {
- GC_err_printf0("in root set");
- }
+ GC_err_printf("Black listing (%s) %p referenced from %p in %s\n",
+ kind_str, (ptr_t)p, source,
+ NULL != source ? "root set" : "register");
} else {
- GC_err_printf0("in object at ");
- (*GC_print_heap_obj)(base);
+ /* FIXME: We can't call the debug version of GC_print_heap_obj */
+ /* (with PRINT_CALL_CHAIN) here because the lock is held and */
+ /* the world is stopped. */
+ GC_err_printf("Black listing (%s) %p referenced from %p in"
+ " object at %p of appr. %lu bytes\n",
+ kind_str, (ptr_t)p, source,
+ base, (unsigned long)GC_size(base));
+ }
+ }
+#endif /* PRINT_BLACK_LIST */
+
+GC_INNER void GC_bl_init_no_interiors(void)
+{
+ if (GC_incomplete_normal_bl == 0) {
+ GC_old_normal_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
+ GC_incomplete_normal_bl = (word *)GC_scratch_alloc(
+ sizeof(page_hash_table));
+ if (GC_old_normal_bl == 0 || GC_incomplete_normal_bl == 0) {
+ GC_err_printf("Insufficient memory for black list\n");
+ EXIT();
}
+ GC_clear_bl(GC_old_normal_bl);
+ GC_clear_bl(GC_incomplete_normal_bl);
+ }
}
-void GC_bl_init()
+GC_INNER void GC_bl_init(void)
{
if (!GC_all_interior_pointers) {
- GC_old_normal_bl = (word *)
- GC_scratch_alloc((word)(sizeof (page_hash_table)));
- GC_incomplete_normal_bl = (word *)GC_scratch_alloc
- ((word)(sizeof(page_hash_table)));
- if (GC_old_normal_bl == 0 || GC_incomplete_normal_bl == 0) {
- GC_err_printf0("Insufficient memory for black list\n");
- EXIT();
- }
- GC_clear_bl(GC_old_normal_bl);
- GC_clear_bl(GC_incomplete_normal_bl);
+ GC_bl_init_no_interiors();
}
- GC_old_stack_bl = (word *)GC_scratch_alloc((word)(sizeof(page_hash_table)));
- GC_incomplete_stack_bl = (word *)GC_scratch_alloc
- ((word)(sizeof(page_hash_table)));
+ GC_old_stack_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
+ GC_incomplete_stack_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
if (GC_old_stack_bl == 0 || GC_incomplete_stack_bl == 0) {
- GC_err_printf0("Insufficient memory for black list\n");
+ GC_err_printf("Insufficient memory for black list\n");
EXIT();
}
GC_clear_bl(GC_old_stack_bl);
GC_clear_bl(GC_incomplete_stack_bl);
}
-
-void GC_clear_bl(doomed)
-word *doomed;
+
+STATIC void GC_clear_bl(word *doomed)
{
BZERO(doomed, sizeof(page_hash_table));
}
-void GC_copy_bl(old, new)
-word *new, *old;
+STATIC void GC_copy_bl(word *old, word *new)
{
BCOPY(old, new, sizeof(page_hash_table));
}
-static word total_stack_black_listed();
+static word total_stack_black_listed(void);
-/* Signal the completion of a collection. Turn the incomplete black */
-/* lists into new black lists, etc. */
-void GC_promote_black_lists()
+/* Signal the completion of a collection. Turn the incomplete black */
+/* lists into new black lists, etc. */
+GC_INNER void GC_promote_black_lists(void)
{
word * very_old_normal_bl = GC_old_normal_bl;
word * very_old_stack_bl = GC_old_stack_bl;
-
+
GC_old_normal_bl = GC_incomplete_normal_bl;
GC_old_stack_bl = GC_incomplete_stack_bl;
if (!GC_all_interior_pointers) {
@@ -138,27 +147,26 @@ void GC_promote_black_lists()
GC_incomplete_normal_bl = very_old_normal_bl;
GC_incomplete_stack_bl = very_old_stack_bl;
GC_total_stack_black_listed = total_stack_black_listed();
-# ifdef PRINTSTATS
- GC_printf1("%ld bytes in heap blacklisted for interior pointers\n",
- (unsigned long)GC_total_stack_black_listed);
-# endif
+ GC_VERBOSE_LOG_PRINTF(
+ "%lu bytes in heap blacklisted for interior pointers\n",
+ (unsigned long)GC_total_stack_black_listed);
if (GC_total_stack_black_listed != 0) {
GC_black_list_spacing =
- HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
+ HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
}
if (GC_black_list_spacing < 3 * HBLKSIZE) {
- GC_black_list_spacing = 3 * HBLKSIZE;
+ GC_black_list_spacing = 3 * HBLKSIZE;
}
if (GC_black_list_spacing > MAXHINCR * HBLKSIZE) {
- GC_black_list_spacing = MAXHINCR * HBLKSIZE;
- /* Makes it easier to allocate really huge blocks, which otherwise */
- /* may have problems with nonuniform blacklist distributions. */
- /* This way we should always succeed immediately after growing the */
- /* heap. */
+ GC_black_list_spacing = MAXHINCR * HBLKSIZE;
+ /* Makes it easier to allocate really huge blocks, which otherwise */
+ /* may have problems with nonuniform blacklist distributions. */
+ /* This way we should always succeed immediately after growing the */
+ /* heap. */
}
}
-void GC_unpromote_black_lists()
+GC_INNER void GC_unpromote_black_lists(void)
{
if (!GC_all_interior_pointers) {
GC_copy_bl(GC_old_normal_bl, GC_incomplete_normal_bl);
@@ -166,60 +174,47 @@ void GC_unpromote_black_lists()
GC_copy_bl(GC_old_stack_bl, GC_incomplete_stack_bl);
}
-/* P is not a valid pointer reference, but it falls inside */
-/* the plausible heap bounds. */
-/* Add it to the normal incomplete black list if appropriate. */
+/* P is not a valid pointer reference, but it falls inside */
+/* the plausible heap bounds. */
+/* Add it to the normal incomplete black list if appropriate. */
#ifdef PRINT_BLACK_LIST
- void GC_add_to_black_list_normal(p, source)
- ptr_t source;
+ GC_INNER void GC_add_to_black_list_normal(word p, ptr_t source)
#else
- void GC_add_to_black_list_normal(p)
+ GC_INNER void GC_add_to_black_list_normal(word p)
#endif
-word p;
{
- if (!(GC_modws_valid_offsets[p & (sizeof(word)-1)])) return;
- {
- register int index = PHT_HASH(p);
-
- if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_normal_bl, index)) {
-# ifdef PRINT_BLACK_LIST
- if (!get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
- GC_err_printf2(
- "Black listing (normal) 0x%lx referenced from 0x%lx ",
- (unsigned long) p, (unsigned long) source);
- GC_print_source_ptr(source);
- GC_err_puts("\n");
- }
-# endif
- set_pht_entry_from_index(GC_incomplete_normal_bl, index);
- } /* else this is probably just an interior pointer to an allocated */
- /* object, and isn't worth black listing. */
- }
+ if (GC_modws_valid_offsets[p & (sizeof(word)-1)]) {
+ word index = PHT_HASH((word)p);
+
+ if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_normal_bl, index)) {
+# ifdef PRINT_BLACK_LIST
+ if (!get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
+ GC_print_blacklisted_ptr(p, source, "normal");
+ }
+# endif
+ set_pht_entry_from_index(GC_incomplete_normal_bl, index);
+ } /* else this is probably just an interior pointer to an allocated */
+ /* object, and isn't worth black listing. */
+ }
}
/* And the same for false pointers from the stack. */
#ifdef PRINT_BLACK_LIST
- void GC_add_to_black_list_stack(p, source)
- ptr_t source;
+ GC_INNER void GC_add_to_black_list_stack(word p, ptr_t source)
#else
- void GC_add_to_black_list_stack(p)
+ GC_INNER void GC_add_to_black_list_stack(word p)
#endif
-word p;
{
- register int index = PHT_HASH(p);
-
- if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_stack_bl, index)) {
-# ifdef PRINT_BLACK_LIST
- if (!get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
- GC_err_printf2(
- "Black listing (stack) 0x%lx referenced from 0x%lx ",
- (unsigned long)p, (unsigned long)source);
- GC_print_source_ptr(source);
- GC_err_puts("\n");
- }
-# endif
- set_pht_entry_from_index(GC_incomplete_stack_bl, index);
- }
+ word index = PHT_HASH((word)p);
+
+ if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_stack_bl, index)) {
+# ifdef PRINT_BLACK_LIST
+ if (!get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
+ GC_print_blacklisted_ptr(p, source, "stack");
+ }
+# endif
+ set_pht_entry_from_index(GC_incomplete_stack_bl, index);
+ }
}
/*
@@ -230,26 +225,24 @@ word p;
* If (h,len) is not black listed, return 0.
* Knows about the structure of the black list hash tables.
*/
-struct hblk * GC_is_black_listed(h, len)
-struct hblk * h;
-word len;
+struct hblk * GC_is_black_listed(struct hblk *h, word len)
{
- register int index = PHT_HASH((word)h);
- register word i;
- word nblocks = divHBLKSZ(len);
+ word index = PHT_HASH((word)h);
+ word i;
+ word nblocks;
- if (!GC_all_interior_pointers) {
- if (get_pht_entry_from_index(GC_old_normal_bl, index)
- || get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
- return(h+1);
- }
+ if (!GC_all_interior_pointers
+ && (get_pht_entry_from_index(GC_old_normal_bl, index)
+ || get_pht_entry_from_index(GC_incomplete_normal_bl, index))) {
+ return (h+1);
}
-
- for (i = 0; ; ) {
+
+ nblocks = divHBLKSZ(len);
+ for (i = 0;;) {
if (GC_old_stack_bl[divWORDSZ(index)] == 0
&& GC_incomplete_stack_bl[divWORDSZ(index)] == 0) {
/* An easy case */
- i += WORDSZ - modWORDSZ(index);
+ i += WORDSZ - modWORDSZ(index);
} else {
if (get_pht_entry_from_index(GC_old_stack_bl, index)
|| get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
@@ -263,38 +256,34 @@ word len;
return(0);
}
-
-/* Return the number of blacklisted blocks in a given range. */
-/* Used only for statistical purposes. */
-/* Looks only at the GC_incomplete_stack_bl. */
-word GC_number_stack_black_listed(start, endp1)
-struct hblk *start, *endp1;
+/* Return the number of blacklisted blocks in a given range. */
+/* Used only for statistical purposes. */
+/* Looks only at the GC_incomplete_stack_bl. */
+STATIC word GC_number_stack_black_listed(struct hblk *start,
+ struct hblk *endp1)
{
register struct hblk * h;
word result = 0;
-
- for (h = start; h < endp1; h++) {
- register int index = PHT_HASH((word)h);
-
+
+ for (h = start; (word)h < (word)endp1; h++) {
+ word index = PHT_HASH((word)h);
+
if (get_pht_entry_from_index(GC_old_stack_bl, index)) result++;
}
return(result);
}
-
/* Return the total number of (stack) black-listed bytes. */
-static word total_stack_black_listed()
+static word total_stack_black_listed(void)
{
register unsigned i;
word total = 0;
-
+
for (i = 0; i < GC_n_heap_sects; i++) {
- struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
- word len = (word) GC_heap_sects[i].hs_bytes;
- struct hblk * endp1 = start + len/HBLKSIZE;
-
- total += GC_number_stack_black_listed(start, endp1);
+ struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
+ struct hblk * endp1 = start + GC_heap_sects[i].hs_bytes/HBLKSIZE;
+
+ total += GC_number_stack_black_listed(start, endp1);
}
return(total * HBLKSIZE);
}
-
diff --git a/boehm-gc/build/s60v3/bld.inf b/boehm-gc/build/s60v3/bld.inf
new file mode 100644
index 00000000000..491fcf43435
--- /dev/null
+++ b/boehm-gc/build/s60v3/bld.inf
@@ -0,0 +1,11 @@
+/*
+ Name : bld.inf
+ Description : This file provides the information required for building the
+ whole of a libgc.
+*/
+
+PRJ_PLATFORMS
+default armv5
+
+PRJ_MMPFILES
+libgc.mmp
diff --git a/boehm-gc/build/s60v3/libgc.mmp b/boehm-gc/build/s60v3/libgc.mmp
new file mode 100644
index 00000000000..df3b5c81778
--- /dev/null
+++ b/boehm-gc/build/s60v3/libgc.mmp
@@ -0,0 +1,77 @@
+TARGET libgc.dll
+
+TARGETTYPE dll
+UID 0x1000008d 0x200107C2 // check uid
+
+EXPORTUNFROZEN
+EPOCALLOWDLLDATA
+//ALWAYS_BUILD_AS_ARM
+//nocompresstarget
+//srcdbg
+//baseaddress 00500000
+//LINKEROPTION CW -map libgc.map
+//LINKEROPTION CW -filealign 0x10000
+
+CAPABILITY PowerMgmt ReadDeviceData ReadUserData WriteDeviceData WriteUserData SwEvent LocalServices NetworkServices UserEnvironment
+
+
+MACRO ALL_INTERIOR_POINTERS
+MACRO NO_EXECUTE_PERMISSION
+MACRO USE_MMAP
+MACRO GC_DONT_REGISTER_MAIN_STATIC_DATA
+MACRO GC_DLL
+MACRO GC_BUILD
+MACRO SYMBIAN
+//MACRO ENABLE_DISCLAIM
+//MACRO GC_GCJ_SUPPORT
+
+USERINCLUDE ..\..\include
+USERINCLUDE ..\..\include\private
+
+SYSTEMINCLUDE \epoc32\include
+SYSTEMINCLUDE \epoc32\include\stdapis
+
+SOURCEPATH ..\..\
+
+SOURCE allchblk.c
+SOURCE alloc.c
+SOURCE blacklst.c
+SOURCE dbg_mlc.c
+SOURCE dyn_load.c
+SOURCE finalize.c
+SOURCE fnlz_mlc.c
+//SOURCE gc_cpp.cpp
+SOURCE gcj_mlc.c
+SOURCE headers.c
+SOURCE mach_dep.c
+SOURCE malloc.c
+SOURCE mallocx.c
+SOURCE mark.c
+SOURCE mark_rts.c
+SOURCE misc.c
+SOURCE new_hblk.c
+SOURCE obj_map.c
+SOURCE os_dep.c
+SOURCE extra/symbian.cpp
+SOURCE ptr_chck.c
+SOURCE reclaim.c
+SOURCE stubborn.c
+SOURCE typd_mlc.c
+
+/*
+#ifdef ENABLE_ABIV2_MODE
+ DEBUGGABLE_UDEBONLY
+#endif
+*/
+
+// Using main() as entry point
+STATICLIBRARY libcrt0.lib
+
+// libc and euser are always needed when using main() entry point
+LIBRARY libc.lib
+
+
+LIBRARY euser.lib
+LIBRARY efsrv.lib
+LIBRARY avkon.lib
+LIBRARY eikcore.lib
diff --git a/boehm-gc/build_atomic_ops.sh b/boehm-gc/build_atomic_ops.sh
new file mode 100755
index 00000000000..aa42decee1b
--- /dev/null
+++ b/boehm-gc/build_atomic_ops.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+P=`pwd`/libatomic_ops-install
+cd libatomic_ops
+./configure --prefix=$P
+$MAKE CC=$CC install
diff --git a/boehm-gc/build_atomic_ops.sh.cygwin b/boehm-gc/build_atomic_ops.sh.cygwin
new file mode 100755
index 00000000000..848a270d49b
--- /dev/null
+++ b/boehm-gc/build_atomic_ops.sh.cygwin
@@ -0,0 +1,14 @@
+#!/bin/sh
+# We install through the temporary directory in case pwd contains spaces,
+# which otherwise breaks the build machinery.
+# This is a gross hack and probably breaks incremental rebuilds
+mkdir libatomic_ops-install
+P=`pwd`
+Q=`mktemp -d`
+ln -s "$P" $Q/dir
+cd $Q/dir/libatomic_ops
+./configure --prefix=$Q/dir/libatomic_ops-install
+$MAKE CC=$CC install
+cd /
+rm $Q/dir
+rmdir $Q
diff --git a/boehm-gc/checksums.c b/boehm-gc/checksums.c
index 57a6ebc2160..f5ad843a11d 100644
--- a/boehm-gc/checksums.c
+++ b/boehm-gc/checksums.c
@@ -10,190 +10,215 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, March 29, 1995 12:51 pm PST */
-# ifdef CHECKSUMS
-# include "private/gc_priv.h"
+#include "private/gc_priv.h"
-/* This is debugging code intended to verify the results of dirty bit */
-/* computations. Works only in a single threaded environment. */
-/* We assume that stubborn objects are changed only when they are */
-/* enabled for writing. (Certain kinds of writing are actually */
-/* safe under other conditions.) */
-# define NSUMS 10000
+#ifdef CHECKSUMS
-# define OFFSET 0x10000
+/* This is debugging code intended to verify the results of dirty bit */
+/* computations. Works only in a single threaded environment. */
+/* We assume that stubborn objects are changed only when they are */
+/* enabled for writing. (Certain kinds of writing are actually */
+/* safe under other conditions.) */
+#define NSUMS 10000
+
+#define OFFSET 0x10000
typedef struct {
- GC_bool new_valid;
- word old_sum;
- word new_sum;
- struct hblk * block; /* Block to which this refers + OFFSET */
- /* to hide it from collector. */
+ GC_bool new_valid;
+ word old_sum;
+ word new_sum;
+ struct hblk * block; /* Block to which this refers + OFFSET */
+ /* to hide it from collector. */
} page_entry;
-page_entry GC_sums [NSUMS];
+page_entry GC_sums[NSUMS];
+
+STATIC word GC_faulted[NSUMS] = { 0 };
+ /* Record of pages on which we saw a write fault. */
+
+STATIC size_t GC_n_faulted = 0;
+
+void GC_record_fault(struct hblk * h)
+{
+ word page = (word)h;
+
+ page += GC_page_size - 1;
+ page &= ~(GC_page_size - 1);
+ if (GC_n_faulted >= NSUMS) ABORT("write fault log overflowed");
+ GC_faulted[GC_n_faulted++] = page;
+}
+
+STATIC GC_bool GC_was_faulted(struct hblk *h)
+{
+ size_t i;
+ word page = (word)h;
-word GC_checksum(h)
-struct hblk *h;
+ page += GC_page_size - 1;
+ page &= ~(GC_page_size - 1);
+ for (i = 0; i < GC_n_faulted; ++i) {
+ if (GC_faulted[i] == page) return TRUE;
+ }
+ return FALSE;
+}
+
+STATIC word GC_checksum(struct hblk *h)
{
- register word *p = (word *)h;
- register word *lim = (word *)(h+1);
- register word result = 0;
-
- while (p < lim) {
+ word *p = (word *)h;
+ word *lim = (word *)(h+1);
+ word result = 0;
+
+ while ((word)p < (word)lim) {
result += *p++;
}
return(result | 0x80000000 /* doesn't look like pointer */);
}
-# ifdef STUBBORN_ALLOC
-/* Check whether a stubborn object from the given block appears on */
-/* the appropriate free list. */
-GC_bool GC_on_free_list(h)
-struct hblk *h;
-{
- register hdr * hhdr = HDR(h);
- register int sz = hhdr -> hb_sz;
+#ifdef STUBBORN_ALLOC
+ /* Check whether a stubborn object from the given block appears on */
+ /* the appropriate free list. */
+ STATIC GC_bool GC_on_free_list(struct hblk *h)
+ {
+ hdr * hhdr = HDR(h);
+ size_t sz = BYTES_TO_WORDS(hhdr -> hb_sz);
ptr_t p;
-
- if (sz > MAXOBJSZ) return(FALSE);
+
+ if (sz > MAXOBJWORDS) return(FALSE);
for (p = GC_sobjfreelist[sz]; p != 0; p = obj_link(p)) {
if (HBLKPTR(p) == h) return(TRUE);
}
return(FALSE);
-}
-# endif
-
-int GC_n_dirty_errors;
-int GC_n_changed_errors;
-int GC_n_clean;
-int GC_n_dirty;
-
-void GC_update_check_page(h, index)
-struct hblk *h;
-int index;
+ }
+#endif
+
+int GC_n_dirty_errors = 0;
+int GC_n_faulted_dirty_errors = 0;
+int GC_n_changed_errors = 0;
+int GC_n_clean = 0;
+int GC_n_dirty = 0;
+
+STATIC void GC_update_check_page(struct hblk *h, int index)
{
page_entry *pe = GC_sums + index;
- register hdr * hhdr = HDR(h);
+ hdr * hhdr = HDR(h);
struct hblk *b;
-
+
if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed");
pe -> old_sum = pe -> new_sum;
pe -> new_sum = GC_checksum(h);
# if !defined(MSWIN32) && !defined(MSWINCE)
if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) {
- GC_printf1("GC_page_was_ever_dirty(0x%lx) is wrong\n",
- (unsigned long)h);
+ GC_err_printf("GC_page_was_ever_dirty(%p) is wrong\n", (void *)h);
}
# endif
if (GC_page_was_dirty(h)) {
- GC_n_dirty++;
+ GC_n_dirty++;
} else {
- GC_n_clean++;
+ GC_n_clean++;
}
b = h;
while (IS_FORWARDING_ADDR_OR_NIL(hhdr) && hhdr != 0) {
- b -= (word)hhdr;
- hhdr = HDR(b);
+ b -= (word)hhdr;
+ hhdr = HDR(b);
}
if (pe -> new_valid
- && hhdr != 0 && hhdr -> hb_descr != 0 /* may contain pointers */
- && pe -> old_sum != pe -> new_sum) {
- if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) {
- /* Set breakpoint here */GC_n_dirty_errors++;
- }
-# ifdef STUBBORN_ALLOC
- if ( hhdr -> hb_map != GC_invalid_map
- && hhdr -> hb_obj_kind == STUBBORN
- && !GC_page_was_changed(h)
- && !GC_on_free_list(h)) {
- /* if GC_on_free_list(h) then reclaim may have touched it */
- /* without any allocations taking place. */
- /* Set breakpoint here */GC_n_changed_errors++;
- }
-# endif
+ && hhdr != 0 && hhdr -> hb_descr != 0 /* may contain pointers */
+ && pe -> old_sum != pe -> new_sum) {
+ if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) {
+ GC_bool was_faulted = GC_was_faulted(h);
+ /* Set breakpoint here */GC_n_dirty_errors++;
+ if (was_faulted) GC_n_faulted_dirty_errors++;
+ }
+# ifdef STUBBORN_ALLOC
+ if (!HBLK_IS_FREE(hhdr)
+ && hhdr -> hb_obj_kind == STUBBORN
+ && !GC_page_was_changed(h)
+ && !GC_on_free_list(h)) {
+ /* if GC_on_free_list(h) then reclaim may have touched it */
+ /* without any allocations taking place. */
+ /* Set breakpoint here */GC_n_changed_errors++;
+ }
+# endif
}
pe -> new_valid = TRUE;
pe -> block = h + OFFSET;
}
-word GC_bytes_in_used_blocks;
+word GC_bytes_in_used_blocks = 0;
-void GC_add_block(h, dummy)
-struct hblk *h;
-word dummy;
+STATIC void GC_add_block(struct hblk *h, word dummy GC_ATTR_UNUSED)
{
- register hdr * hhdr = HDR(h);
- register bytes = WORDS_TO_BYTES(hhdr -> hb_sz);
-
+ hdr * hhdr = HDR(h);
+ size_t bytes = hhdr -> hb_sz;
+
bytes += HBLKSIZE-1;
bytes &= ~(HBLKSIZE-1);
GC_bytes_in_used_blocks += bytes;
}
-void GC_check_blocks()
+STATIC void GC_check_blocks(void)
{
word bytes_in_free_blocks = GC_large_free_bytes;
-
+
GC_bytes_in_used_blocks = 0;
GC_apply_to_all_blocks(GC_add_block, (word)0);
- GC_printf2("GC_bytes_in_used_blocks = %ld, bytes_in_free_blocks = %ld ",
- GC_bytes_in_used_blocks, bytes_in_free_blocks);
- GC_printf1("GC_heapsize = %ld\n", GC_heapsize);
+ GC_COND_LOG_PRINTF("GC_bytes_in_used_blocks = %lu,"
+ " bytes_in_free_blocks = %lu, heapsize = %lu\n",
+ (unsigned long)GC_bytes_in_used_blocks,
+ (unsigned long)bytes_in_free_blocks,
+ (unsigned long)GC_heapsize);
if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) {
- GC_printf0("LOST SOME BLOCKS!!\n");
+ GC_err_printf("LOST SOME BLOCKS!!\n");
}
}
/* Should be called immediately after GC_read_dirty and GC_read_changed. */
-void GC_check_dirty()
+void GC_check_dirty(void)
{
- register int index;
- register unsigned i;
- register struct hblk *h;
- register ptr_t start;
-
+ int index;
+ unsigned i;
+ struct hblk *h;
+ ptr_t start;
+
GC_check_blocks();
-
+
GC_n_dirty_errors = 0;
+ GC_n_faulted_dirty_errors = 0;
GC_n_changed_errors = 0;
GC_n_clean = 0;
GC_n_dirty = 0;
-
+
index = 0;
for (i = 0; i < GC_n_heap_sects; i++) {
- start = GC_heap_sects[i].hs_start;
+ start = GC_heap_sects[i].hs_start;
for (h = (struct hblk *)start;
- h < (struct hblk *)(start + GC_heap_sects[i].hs_bytes);
- h++) {
+ (word)h < (word)(start + GC_heap_sects[i].hs_bytes); h++) {
GC_update_check_page(h, index);
index++;
if (index >= NSUMS) goto out;
}
}
out:
- GC_printf2("Checked %lu clean and %lu dirty pages\n",
- (unsigned long) GC_n_clean, (unsigned long) GC_n_dirty);
+ GC_COND_LOG_PRINTF("Checked %lu clean and %lu dirty pages\n",
+ (unsigned long)GC_n_clean, (unsigned long)GC_n_dirty);
if (GC_n_dirty_errors > 0) {
- GC_printf1("Found %lu dirty bit errors\n",
- (unsigned long)GC_n_dirty_errors);
+ GC_err_printf("Found %d dirty bit errors (%d were faulted)\n",
+ GC_n_dirty_errors, GC_n_faulted_dirty_errors);
}
if (GC_n_changed_errors > 0) {
- GC_printf1("Found %lu changed bit errors\n",
- (unsigned long)GC_n_changed_errors);
- GC_printf0("These may be benign (provoked by nonpointer changes)\n");
-# ifdef THREADS
- GC_printf0(
- "Also expect 1 per thread currently allocating a stubborn obj.\n");
-# endif
+ GC_err_printf("Found %lu changed bit errors\n",
+ (unsigned long)GC_n_changed_errors);
+ GC_err_printf(
+ "These may be benign (provoked by nonpointer changes)\n");
+# ifdef THREADS
+ GC_err_printf(
+ "Also expect 1 per thread currently allocating a stubborn obj\n");
+# endif
}
+ for (i = 0; i < GC_n_faulted; ++i) {
+ GC_faulted[i] = 0; /* Don't expose block pointers to GC */
+ }
+ GC_n_faulted = 0;
}
-# else
-
-extern int GC_quiet;
- /* ANSI C doesn't allow translation units to be empty. */
- /* So we guarantee this one is nonempty. */
-
-# endif /* CHECKSUMS */
+#endif /* CHECKSUMS */
diff --git a/boehm-gc/config.guess b/boehm-gc/config.guess
deleted file mode 100755
index ed2e03b7f2b..00000000000
--- a/boehm-gc/config.guess
+++ /dev/null
@@ -1,1321 +0,0 @@
-#! /bin/sh
-# Attempt to guess a canonical system name.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002 Free Software Foundation, Inc.
-
-timestamp='2002-03-20'
-
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Originally written by Per Bothner <per@bothner.com>.
-# Please send patches to <config-patches@gnu.org>. Submit a context
-# diff and a properly formatted ChangeLog entry.
-#
-# This script attempts to guess a canonical system name similar to
-# config.sub. If it succeeds, it prints the system name on stdout, and
-# exits with 0. Otherwise, it exits with 1.
-#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION]
-
-Output the configuration name of the system \`$me' is run on.
-
-Operation modes:
- -h, --help print this help, then exit
- -t, --time-stamp print date of last modification, then exit
- -v, --version print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.guess ($timestamp)
-
-Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions. There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
- case $1 in
- --time-stamp | --time* | -t )
- echo "$timestamp" ; exit 0 ;;
- --version | -v )
- echo "$version" ; exit 0 ;;
- --help | --h* | -h )
- echo "$usage"; exit 0 ;;
- -- ) # Stop option processing
- shift; break ;;
- - ) # Use stdin as input.
- break ;;
- -* )
- echo "$me: invalid option $1$help" >&2
- exit 1 ;;
- * )
- break ;;
- esac
-done
-
-if test $# != 0; then
- echo "$me: too many arguments$help" >&2
- exit 1
-fi
-
-
-dummy=dummy-$$
-trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
-
-# CC_FOR_BUILD -- compiler used by this script.
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
-
-set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,) echo "int dummy(){}" > $dummy.c ;
- for c in cc gcc c89 c99 ; do
- ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ;
- if test $? = 0 ; then
- CC_FOR_BUILD="$c"; break ;
- fi ;
- done ;
- rm -f $dummy.c $dummy.o $dummy.rel ;
- if test x"$CC_FOR_BUILD" = x ; then
- CC_FOR_BUILD=no_compiler_found ;
- fi
- ;;
- ,,*) CC_FOR_BUILD=$CC ;;
- ,*,*) CC_FOR_BUILD=$HOST_CC ;;
-esac'
-
-# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
- PATH=$PATH:/.attbin ; export PATH
-fi
-
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-
-# Note: order is significant - the case branches are not exclusive.
-
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
- *:NetBSD:*:*)
- # NetBSD (nbsd) targets should (where applicable) match one or
- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
- # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
- # switched to ELF, *-*-netbsd* would select the old
- # object file format. This provides both forward
- # compatibility and a consistent mechanism for selecting the
- # object file format.
- #
- # Note: NetBSD doesn't particularly care about the vendor
- # portion of the name. We always set it to "unknown".
- sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
- /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
- case "${UNAME_MACHINE_ARCH}" in
- arm*) machine=arm-unknown ;;
- sh3el) machine=shl-unknown ;;
- sh3eb) machine=sh-unknown ;;
- *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
- esac
- # The Operating System including object format, if it has switched
- # to ELF recently, or will in the future.
- case "${UNAME_MACHINE_ARCH}" in
- arm*|i386|m68k|ns32k|sh3*|sparc|vax)
- eval $set_cc_for_build
- if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep __ELF__ >/dev/null
- then
- # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
- # Return netbsd for either. FIX?
- os=netbsd
- else
- os=netbsdelf
- fi
- ;;
- *)
- os=netbsd
- ;;
- esac
- # The OS release
- release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
- # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
- # contains redundant information, the shorter form:
- # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "${machine}-${os}${release}"
- exit 0 ;;
- amiga:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- arc:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- hp300:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mac68k:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- macppc:OpenBSD:*:*)
- echo powerpc-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvme68k:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvme88k:OpenBSD:*:*)
- echo m88k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvmeppc:OpenBSD:*:*)
- echo powerpc-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- pmax:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- sgi:OpenBSD:*:*)
- echo mipseb-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- sun3:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- wgrisc:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- *:OpenBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- alpha:OSF1:*:*)
- if test $UNAME_RELEASE = "V4.0"; then
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
- fi
- # A Vn.n version is a released version.
- # A Tn.n version is a released field test version.
- # A Xn.n version is an unreleased experimental baselevel.
- # 1.2 uses "1.2" for uname -r.
- cat <<EOF >$dummy.s
- .data
-\$Lformat:
- .byte 37,100,45,37,120,10,0 # "%d-%x\n"
-
- .text
- .globl main
- .align 4
- .ent main
-main:
- .frame \$30,16,\$26,0
- ldgp \$29,0(\$27)
- .prologue 1
- .long 0x47e03d80 # implver \$0
- lda \$2,-1
- .long 0x47e20c21 # amask \$2,\$1
- lda \$16,\$Lformat
- mov \$0,\$17
- not \$1,\$18
- jsr \$26,printf
- ldgp \$29,0(\$26)
- mov 0,\$16
- jsr \$26,exit
- .end main
-EOF
- eval $set_cc_for_build
- $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
- if test "$?" = 0 ; then
- case `./$dummy` in
- 0-0)
- UNAME_MACHINE="alpha"
- ;;
- 1-0)
- UNAME_MACHINE="alphaev5"
- ;;
- 1-1)
- UNAME_MACHINE="alphaev56"
- ;;
- 1-101)
- UNAME_MACHINE="alphapca56"
- ;;
- 2-303)
- UNAME_MACHINE="alphaev6"
- ;;
- 2-307)
- UNAME_MACHINE="alphaev67"
- ;;
- 2-1307)
- UNAME_MACHINE="alphaev68"
- ;;
- esac
- fi
- rm -f $dummy.s $dummy
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- exit 0 ;;
- Alpha\ *:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # Should we change UNAME_MACHINE based on the output of uname instead
- # of the specific Alpha model?
- echo alpha-pc-interix
- exit 0 ;;
- 21064:Windows_NT:50:3)
- echo alpha-dec-winnt3.5
- exit 0 ;;
- Amiga*:UNIX_System_V:4.0:*)
- echo m68k-unknown-sysv4
- exit 0;;
- *:[Aa]miga[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-amigaos
- exit 0 ;;
- *:[Mm]orph[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-morphos
- exit 0 ;;
- *:OS/390:*:*)
- echo i370-ibm-openedition
- exit 0 ;;
- arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix${UNAME_RELEASE}
- exit 0;;
- SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
- echo hppa1.1-hitachi-hiuxmpp
- exit 0;;
- Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
- # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
- echo pyramid-pyramid-sysv3
- else
- echo pyramid-pyramid-bsd
- fi
- exit 0 ;;
- NILE*:*:*:dcosx)
- echo pyramid-pyramid-svr4
- exit 0 ;;
- sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- i86pc:SunOS:5.*:*)
- echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- sun4*:SunOS:6*:*)
- # According to config.sub, this is the proper way to canonicalize
- # SunOS6. Hard to guess exactly what SunOS6 will be like, but
- # it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
- Series*|S4*)
- UNAME_RELEASE=`uname -v`
- ;;
- esac
- # Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
- exit 0 ;;
- sun3*:SunOS:*:*)
- echo m68k-sun-sunos${UNAME_RELEASE}
- exit 0 ;;
- sun*:*:4.2BSD:*)
- UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
- test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
- case "`/bin/arch`" in
- sun3)
- echo m68k-sun-sunos${UNAME_RELEASE}
- ;;
- sun4)
- echo sparc-sun-sunos${UNAME_RELEASE}
- ;;
- esac
- exit 0 ;;
- aushp:SunOS:*:*)
- echo sparc-auspex-sunos${UNAME_RELEASE}
- exit 0 ;;
- # The situation for MiNT is a little confusing. The machine name
- # can be virtually everything (everything which is not
- # "atarist" or "atariste" at least should have a processor
- # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
- # to the lowercase version "mint" (or "freemint"). Finally
- # the system name "TOS" denotes a system which is actually not
- # MiNT. But MiNT is downward compatible to TOS, so this should
- # be no problem.
- atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit 0 ;;
- atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit 0 ;;
- *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit 0 ;;
- milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint${UNAME_RELEASE}
- exit 0 ;;
- hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint${UNAME_RELEASE}
- exit 0 ;;
- *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint${UNAME_RELEASE}
- exit 0 ;;
- powerpc:machten:*:*)
- echo powerpc-apple-machten${UNAME_RELEASE}
- exit 0 ;;
- RISC*:Mach:*:*)
- echo mips-dec-mach_bsd4.3
- exit 0 ;;
- RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix${UNAME_RELEASE}
- exit 0 ;;
- VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix${UNAME_RELEASE}
- exit 0 ;;
- 2020:CLIX:*:* | 2430:CLIX:*:*)
- echo clipper-intergraph-clix${UNAME_RELEASE}
- exit 0 ;;
- mips:*:*:UMIPS | mips:*:*:RISCos)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
-#ifdef __cplusplus
-#include <stdio.h> /* for printf() prototype */
- int main (int argc, char *argv[]) {
-#else
- int main (argc, argv) int argc; char *argv[]; {
-#endif
- #if defined (host_mips) && defined (MIPSEB)
- #if defined (SYSTYPE_SYSV)
- printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_SVR4)
- printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
- printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
- #endif
- #endif
- exit (-1);
- }
-EOF
- $CC_FOR_BUILD $dummy.c -o $dummy \
- && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
- && rm -f $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- echo mips-mips-riscos${UNAME_RELEASE}
- exit 0 ;;
- Motorola:PowerMAX_OS:*:*)
- echo powerpc-motorola-powermax
- exit 0 ;;
- Night_Hawk:Power_UNIX:*:*)
- echo powerpc-harris-powerunix
- exit 0 ;;
- m88k:CX/UX:7*:*)
- echo m88k-harris-cxux7
- exit 0 ;;
- m88k:*:4*:R4*)
- echo m88k-motorola-sysv4
- exit 0 ;;
- m88k:*:3*:R3*)
- echo m88k-motorola-sysv3
- exit 0 ;;
- AViiON:dgux:*:*)
- # DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
- if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
- then
- if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
- [ ${TARGET_BINARY_INTERFACE}x = x ]
- then
- echo m88k-dg-dgux${UNAME_RELEASE}
- else
- echo m88k-dg-dguxbcs${UNAME_RELEASE}
- fi
- else
- echo i586-dg-dgux${UNAME_RELEASE}
- fi
- exit 0 ;;
- M88*:DolphinOS:*:*) # DolphinOS (SVR3)
- echo m88k-dolphin-sysv3
- exit 0 ;;
- M88*:*:R3*:*)
- # Delta 88k system running SVR3
- echo m88k-motorola-sysv3
- exit 0 ;;
- XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
- echo m88k-tektronix-sysv3
- exit 0 ;;
- Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
- echo m68k-tektronix-bsd
- exit 0 ;;
- *:IRIX*:*:*)
- echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
- exit 0 ;;
- ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
- i*86:AIX:*:*)
- echo i386-ibm-aix
- exit 0 ;;
- ia64:AIX:*:*)
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
- else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
- fi
- echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
- exit 0 ;;
- *:AIX:2:3)
- if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <sys/systemcfg.h>
-
- main()
- {
- if (!__power_pc())
- exit(1);
- puts("powerpc-ibm-aix3.2.5");
- exit(0);
- }
-EOF
- $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- echo rs6000-ibm-aix3.2.5
- elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
- echo rs6000-ibm-aix3.2.4
- else
- echo rs6000-ibm-aix3.2
- fi
- exit 0 ;;
- *:AIX:*:[45])
- IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
- if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
- IBM_ARCH=rs6000
- else
- IBM_ARCH=powerpc
- fi
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
- else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
- fi
- echo ${IBM_ARCH}-ibm-aix${IBM_REV}
- exit 0 ;;
- *:AIX:*:*)
- echo rs6000-ibm-aix
- exit 0 ;;
- ibmrt:4.4BSD:*|romp-ibm:BSD:*)
- echo romp-ibm-bsd4.4
- exit 0 ;;
- ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
- echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
- exit 0 ;; # report: romp-ibm BSD 4.3
- *:BOSX:*:*)
- echo rs6000-bull-bosx
- exit 0 ;;
- DPX/2?00:B.O.S.:*:*)
- echo m68k-bull-sysv3
- exit 0 ;;
- 9000/[34]??:4.3bsd:1.*:*)
- echo m68k-hp-bsd
- exit 0 ;;
- hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
- echo m68k-hp-bsd4.4
- exit 0 ;;
- 9000/[34678]??:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- case "${UNAME_MACHINE}" in
- 9000/31? ) HP_ARCH=m68000 ;;
- 9000/[34]?? ) HP_ARCH=m68k ;;
- 9000/[678][0-9][0-9])
- if [ -x /usr/bin/getconf ]; then
- sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "${sc_cpu_version}" in
- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
- 532) # CPU_PA_RISC2_0
- case "${sc_kernel_bits}" in
- 32) HP_ARCH="hppa2.0n" ;;
- 64) HP_ARCH="hppa2.0w" ;;
- '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
- esac ;;
- esac
- fi
- if [ "${HP_ARCH}" = "" ]; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
-
- #define _HPUX_SOURCE
- #include <stdlib.h>
- #include <unistd.h>
-
- int main ()
- {
- #if defined(_SC_KERNEL_BITS)
- long bits = sysconf(_SC_KERNEL_BITS);
- #endif
- long cpu = sysconf (_SC_CPU_VERSION);
-
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
- case CPU_PA_RISC2_0:
- #if defined(_SC_KERNEL_BITS)
- switch (bits)
- {
- case 64: puts ("hppa2.0w"); break;
- case 32: puts ("hppa2.0n"); break;
- default: puts ("hppa2.0"); break;
- } break;
- #else /* !defined(_SC_KERNEL_BITS) */
- puts ("hppa2.0"); break;
- #endif
- default: puts ("hppa1.0"); break;
- }
- exit (0);
- }
-EOF
- (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`./$dummy`
- if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
- rm -f $dummy.c $dummy
- fi ;;
- esac
- echo ${HP_ARCH}-hp-hpux${HPUX_REV}
- exit 0 ;;
- ia64:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- echo ia64-hp-hpux${HPUX_REV}
- exit 0 ;;
- 3050*:HI-UX:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <unistd.h>
- int
- main ()
- {
- long cpu = sysconf (_SC_CPU_VERSION);
- /* The order matters, because CPU_IS_HP_MC68K erroneously returns
- true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
- results, however. */
- if (CPU_IS_PA_RISC (cpu))
- {
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
- default: puts ("hppa-hitachi-hiuxwe2"); break;
- }
- }
- else if (CPU_IS_HP_MC68K (cpu))
- puts ("m68k-hitachi-hiuxwe2");
- else puts ("unknown-hitachi-hiuxwe2");
- exit (0);
- }
-EOF
- $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- echo unknown-hitachi-hiuxwe2
- exit 0 ;;
- 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
- echo hppa1.1-hp-bsd
- exit 0 ;;
- 9000/8??:4.3bsd:*:*)
- echo hppa1.0-hp-bsd
- exit 0 ;;
- *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
- echo hppa1.0-hp-mpeix
- exit 0 ;;
- hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
- echo hppa1.1-hp-osf
- exit 0 ;;
- hp8??:OSF1:*:*)
- echo hppa1.0-hp-osf
- exit 0 ;;
- i*86:OSF1:*:*)
- if [ -x /usr/sbin/sysversion ] ; then
- echo ${UNAME_MACHINE}-unknown-osf1mk
- else
- echo ${UNAME_MACHINE}-unknown-osf1
- fi
- exit 0 ;;
- parisc*:Lites*:*:*)
- echo hppa1.1-hp-lites
- exit 0 ;;
- C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
- echo c1-convex-bsd
- exit 0 ;;
- C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit 0 ;;
- C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
- echo c34-convex-bsd
- exit 0 ;;
- C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
- echo c38-convex-bsd
- exit 0 ;;
- C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
- echo c4-convex-bsd
- exit 0 ;;
- CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
- CRAY*[A-Z]90:*:*:*)
- echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
- | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
- -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
- -e 's/\.[^.]*$/.X/'
- exit 0 ;;
- CRAY*TS:*:*:*)
- echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
- CRAY*T3D:*:*:*)
- echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
- CRAY*T3E:*:*:*)
- echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
- CRAY*SV1:*:*:*)
- echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit 0 ;;
- F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit 0 ;;
- i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
- echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
- exit 0 ;;
- sparc*:BSD/OS:*:*)
- echo sparc-unknown-bsdi${UNAME_RELEASE}
- exit 0 ;;
- *:BSD/OS:*:*)
- echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
- exit 0 ;;
- *:FreeBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
- exit 0 ;;
- i*:CYGWIN*:*)
- echo ${UNAME_MACHINE}-pc-cygwin
- exit 0 ;;
- i*:MINGW*:*)
- echo ${UNAME_MACHINE}-pc-mingw32
- exit 0 ;;
- i*:PW*:*)
- echo ${UNAME_MACHINE}-pc-pw32
- exit 0 ;;
- x86:Interix*:3*)
- echo i386-pc-interix3
- exit 0 ;;
- i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
- # UNAME_MACHINE based on the output of uname instead of i386?
- echo i386-pc-interix
- exit 0 ;;
- i*:UWIN*:*)
- echo ${UNAME_MACHINE}-pc-uwin
- exit 0 ;;
- p*:CYGWIN*:*)
- echo powerpcle-unknown-cygwin
- exit 0 ;;
- prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- *:GNU:*:*)
- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
- exit 0 ;;
- i*86:Minix:*:*)
- echo ${UNAME_MACHINE}-pc-minix
- exit 0 ;;
- arm*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
- ia64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
- m68*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
- mips:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef mips
- #undef mipsel
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mipsel
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips
- #else
- CPU=
- #endif
- #endif
-EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
- rm -f $dummy.c
- test x"${CPU}" != x && echo "${CPU}-pc-linux-gnu" && exit 0
- ;;
- ppc:Linux:*:*)
- echo powerpc-unknown-linux-gnu
- exit 0 ;;
- ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-gnu
- exit 0 ;;
- alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
- EV5) UNAME_MACHINE=alphaev5 ;;
- EV56) UNAME_MACHINE=alphaev56 ;;
- PCA56) UNAME_MACHINE=alphapca56 ;;
- PCA57) UNAME_MACHINE=alphapca56 ;;
- EV6) UNAME_MACHINE=alphaev6 ;;
- EV67) UNAME_MACHINE=alphaev67 ;;
- EV68*) UNAME_MACHINE=alphaev68 ;;
- esac
- objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
- exit 0 ;;
- parisc:Linux:*:* | hppa:Linux:*:*)
- # Look for CPU level
- case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-gnu ;;
- PA8*) echo hppa2.0-unknown-linux-gnu ;;
- *) echo hppa-unknown-linux-gnu ;;
- esac
- exit 0 ;;
- parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-gnu
- exit 0 ;;
- s390:Linux:*:* | s390x:Linux:*:*)
- echo ${UNAME_MACHINE}-ibm-linux
- exit 0 ;;
- sh*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
- sparc:Linux:*:* | sparc64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit 0 ;;
- x86_64:Linux:*:*)
- echo x86_64-unknown-linux-gnu
- exit 0 ;;
- i*86:Linux:*:*)
- # The BFD linker knows what the default object file format is, so
- # first see if it will tell us. cd to the root directory to prevent
- # problems with other programs or directories called `ld' in the path.
- # Set LC_ALL=C to ensure ld outputs messages in English.
- ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
- | sed -ne '/supported targets:/!d
- s/[ ][ ]*/ /g
- s/.*supported targets: *//
- s/ .*//
- p'`
- case "$ld_supported_targets" in
- elf32-i386)
- TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
- ;;
- a.out-i386-linux)
- echo "${UNAME_MACHINE}-pc-linux-gnuaout"
- exit 0 ;;
- coff-i386)
- echo "${UNAME_MACHINE}-pc-linux-gnucoff"
- exit 0 ;;
- "")
- # Either a pre-BFD a.out linker (linux-gnuoldld) or
- # one that does not give us useful --help.
- echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
- exit 0 ;;
- esac
- # Determine whether the default compiler is a.out or elf
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <features.h>
- #ifdef __ELF__
- # ifdef __GLIBC__
- # if __GLIBC__ >= 2
- LIBC=gnu
- # else
- LIBC=gnulibc1
- # endif
- # else
- LIBC=gnulibc1
- # endif
- #else
- #ifdef __INTEL_COMPILER
- LIBC=gnu
- #else
- LIBC=gnuaout
- #endif
- #endif
-EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
- rm -f $dummy.c
- test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
- test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
- ;;
- i*86:DYNIX/ptx:4*:*)
- # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
- # earlier versions are messed up and put the nodename in both
- # sysname and nodename.
- echo i386-sequent-sysv4
- exit 0 ;;
- i*86:UNIX_SV:4.2MP:2.*)
- # Unixware is an offshoot of SVR4, but it has its own version
- # number series starting with 2...
- # I am not positive that other SVR4 systems won't match this,
- # I just have to hope. -- rms.
- # Use sysv4.2uw... so that sysv4* matches it.
- echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
- exit 0 ;;
- i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
- UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
- if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
- else
- echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
- fi
- exit 0 ;;
- i*86:*:5:[78]*)
- case `/bin/uname -X | grep "^Machine"` in
- *486*) UNAME_MACHINE=i486 ;;
- *Pentium) UNAME_MACHINE=i586 ;;
- *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
- esac
- echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
- exit 0 ;;
- i*86:*:3.2:*)
- if test -f /usr/options/cb.name; then
- UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
- echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
- elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
- (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
- (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
- && UNAME_MACHINE=i586
- (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
- && UNAME_MACHINE=i686
- (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
- && UNAME_MACHINE=i686
- echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
- else
- echo ${UNAME_MACHINE}-pc-sysv32
- fi
- exit 0 ;;
- i*86:*DOS:*:*)
- echo ${UNAME_MACHINE}-pc-msdosdjgpp
- exit 0 ;;
- pc:*:*:*)
- # Left here for compatibility:
- # uname -m prints for DJGPP always 'pc', but it prints nothing about
- # the processor, so we play safe by assuming i386.
- echo i386-pc-msdosdjgpp
- exit 0 ;;
- Intel:Mach:3*:*)
- echo i386-pc-mach3
- exit 0 ;;
- paragon:*:*:*)
- echo i860-intel-osf1
- exit 0 ;;
- i860:*:4.*:*) # i860-SVR4
- if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
- else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
- fi
- exit 0 ;;
- mini*:CTIX:SYS*5:*)
- # "miniframe"
- echo m68010-convergent-sysv
- exit 0 ;;
- M68*:*:R3V[567]*:*)
- test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
- 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0)
- OS_REL=''
- test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && echo i486-ncr-sysv4.3${OS_REL} && exit 0
- /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
- 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && echo i486-ncr-sysv4 && exit 0 ;;
- m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
- echo m68k-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
- mc68030:UNIX_System_V:4.*:*)
- echo m68k-atari-sysv4
- exit 0 ;;
- i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
- echo i386-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
- TSUNAMI:LynxOS:2.*:*)
- echo sparc-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
- rs6000:LynxOS:2.*:*)
- echo rs6000-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
- PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
- echo powerpc-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
- SM[BE]S:UNIX_SV:*:*)
- echo mips-dde-sysv${UNAME_RELEASE}
- exit 0 ;;
- RM*:ReliantUNIX-*:*:*)
- echo mips-sni-sysv4
- exit 0 ;;
- RM*:SINIX-*:*:*)
- echo mips-sni-sysv4
- exit 0 ;;
- *:SINIX-*:*:*)
- if uname -p 2>/dev/null >/dev/null ; then
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
- echo ${UNAME_MACHINE}-sni-sysv4
- else
- echo ns32k-sni-sysv
- fi
- exit 0 ;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
- # says <Richard.M.Bartel@ccMail.Census.GOV>
- echo i586-unisys-sysv4
- exit 0 ;;
- *:UNIX_System_V:4*:FTX*)
- # From Gerald Hewes <hewes@openmarket.com>.
- # How about differentiating between stratus architectures? -djm
- echo hppa1.1-stratus-sysv4
- exit 0 ;;
- *:*:*:FTX*)
- # From seanf@swdc.stratus.com.
- echo i860-stratus-sysv4
- exit 0 ;;
- *:VOS:*:*)
- # From Paul.Green@stratus.com.
- echo hppa1.1-stratus-vos
- exit 0 ;;
- mc68*:A/UX:*:*)
- echo m68k-apple-aux${UNAME_RELEASE}
- exit 0 ;;
- news*:NEWS-OS:6*:*)
- echo mips-sony-newsos6
- exit 0 ;;
- R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
- if [ -d /usr/nec ]; then
- echo mips-nec-sysv${UNAME_RELEASE}
- else
- echo mips-unknown-sysv${UNAME_RELEASE}
- fi
- exit 0 ;;
- BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
- echo powerpc-be-beos
- exit 0 ;;
- BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
- echo powerpc-apple-beos
- exit 0 ;;
- BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
- echo i586-pc-beos
- exit 0 ;;
- SX-4:SUPER-UX:*:*)
- echo sx4-nec-superux${UNAME_RELEASE}
- exit 0 ;;
- SX-5:SUPER-UX:*:*)
- echo sx5-nec-superux${UNAME_RELEASE}
- exit 0 ;;
- Power*:Rhapsody:*:*)
- echo powerpc-apple-rhapsody${UNAME_RELEASE}
- exit 0 ;;
- *:Rhapsody:*:*)
- echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
- exit 0 ;;
- *:Darwin:*:*)
- echo `uname -p`-apple-darwin${UNAME_RELEASE}
- exit 0 ;;
- *:procnto*:*:* | *:QNX:[0123456789]*:*)
- UNAME_PROCESSOR=`uname -p`
- if test "$UNAME_PROCESSOR" = "x86"; then
- UNAME_PROCESSOR=i386
- UNAME_MACHINE=pc
- fi
- echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
- exit 0 ;;
- *:QNX:*:4*)
- echo i386-pc-qnx
- exit 0 ;;
- NSR-[GKLNPTVW]:NONSTOP_KERNEL:*:*)
- echo nsr-tandem-nsk${UNAME_RELEASE}
- exit 0 ;;
- *:NonStop-UX:*:*)
- echo mips-compaq-nonstopux
- exit 0 ;;
- BS2000:POSIX*:*:*)
- echo bs2000-siemens-sysv
- exit 0 ;;
- DS/*:UNIX_System_V:*:*)
- echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
- exit 0 ;;
- *:Plan9:*:*)
- # "uname -m" is not consistent, so use $cputype instead. 386
- # is converted to i386 for consistency with other x86
- # operating systems.
- if test "$cputype" = "386"; then
- UNAME_MACHINE=i386
- else
- UNAME_MACHINE="$cputype"
- fi
- echo ${UNAME_MACHINE}-unknown-plan9
- exit 0 ;;
- i*86:OS/2:*:*)
- # If we were able to find `uname', then EMX Unix compatibility
- # is probably installed.
- echo ${UNAME_MACHINE}-pc-os2-emx
- exit 0 ;;
- *:TOPS-10:*:*)
- echo pdp10-unknown-tops10
- exit 0 ;;
- *:TENEX:*:*)
- echo pdp10-unknown-tenex
- exit 0 ;;
- KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
- echo pdp10-dec-tops20
- exit 0 ;;
- XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
- echo pdp10-xkl-tops20
- exit 0 ;;
- *:TOPS-20:*:*)
- echo pdp10-unknown-tops20
- exit 0 ;;
- *:ITS:*:*)
- echo pdp10-unknown-its
- exit 0 ;;
- i*86:XTS-300:*:STOP)
- echo ${UNAME_MACHINE}-unknown-stop
- exit 0 ;;
- i*86:atheos:*:*)
- echo ${UNAME_MACHINE}-unknown-atheos
- exit 0 ;;
-esac
-
-#echo '(No uname command or uname output not recognized.)' 1>&2
-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
-
-eval $set_cc_for_build
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
- /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
- I don't know.... */
- printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
- printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
- "4"
-#else
- ""
-#endif
- ); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
- printf ("arm-acorn-riscix"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
- printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
- int version;
- version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
- if (version < 4)
- printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
- else
- printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
- exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
- printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
- printf ("ns32k-encore-mach\n"); exit (0);
-#else
- printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
- printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
- printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
- printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
- struct utsname un;
-
- uname(&un);
-
- if (strncmp(un.version, "V2", 2) == 0) {
- printf ("i386-sequent-ptx2\n"); exit (0);
- }
- if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
- printf ("i386-sequent-ptx1\n"); exit (0);
- }
- printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-# if !defined (ultrix)
-# include <sys/param.h>
-# if defined (BSD)
-# if BSD == 43
- printf ("vax-dec-bsd4.3\n"); exit (0);
-# else
-# if BSD == 199006
- printf ("vax-dec-bsd4.3reno\n"); exit (0);
-# else
- printf ("vax-dec-bsd\n"); exit (0);
-# endif
-# endif
-# else
- printf ("vax-dec-bsd\n"); exit (0);
-# endif
-# else
- printf ("vax-dec-ultrix\n"); exit (0);
-# endif
-#endif
-
-#if defined (alliant) && defined (i860)
- printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
- exit (1);
-}
-EOF
-
-$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
-rm -f $dummy.c $dummy
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
- case `getsysinfo -f cpu_type` in
- c1*)
- echo c1-convex-bsd
- exit 0 ;;
- c2*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit 0 ;;
- c34*)
- echo c34-convex-bsd
- exit 0 ;;
- c38*)
- echo c38-convex-bsd
- exit 0 ;;
- c4*)
- echo c4-convex-bsd
- exit 0 ;;
- esac
-fi
-
-cat >&2 <<EOF
-$0: unable to guess system type
-
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
-
- ftp://ftp.gnu.org/pub/gnu/config/
-
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <config-patches@gnu.org> in order to provide the needed
-information to handle your system.
-
-config.guess timestamp = $timestamp
-
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
-
-hostinfo = `(hostinfo) 2>/dev/null`
-/bin/universe = `(/bin/universe) 2>/dev/null`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
-/bin/arch = `(/bin/arch) 2>/dev/null`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
-
-UNAME_MACHINE = ${UNAME_MACHINE}
-UNAME_RELEASE = ${UNAME_RELEASE}
-UNAME_SYSTEM = ${UNAME_SYSTEM}
-UNAME_VERSION = ${UNAME_VERSION}
-EOF
-
-exit 1
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
diff --git a/boehm-gc/config.sub b/boehm-gc/config.sub
deleted file mode 100755
index f3657978c74..00000000000
--- a/boehm-gc/config.sub
+++ /dev/null
@@ -1,1443 +0,0 @@
-#! /bin/sh
-# Configuration validation subroutine script.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002 Free Software Foundation, Inc.
-
-timestamp='2002-03-07'
-
-# This file is (in principle) common to ALL GNU software.
-# The presence of a machine in this file suggests that SOME GNU software
-# can handle that machine. It does not imply ALL GNU software can.
-#
-# This file is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Please send patches to <config-patches@gnu.org>. Submit a context
-# diff and a properly formatted ChangeLog entry.
-#
-# Configuration subroutine to validate and canonicalize a configuration type.
-# Supply the specified configuration type as an argument.
-# If it is invalid, we print an error message on stderr and exit with code 1.
-# Otherwise, we print the canonical config type on stdout and succeed.
-
-# This file is supposed to be the same for all GNU packages
-# and recognize all the CPU types, system types and aliases
-# that are meaningful with *any* GNU software.
-# Each package is responsible for reporting which valid configurations
-# it does not support. The user should be able to distinguish
-# a failure to support a valid configuration from a meaningless
-# configuration.
-
-# The goal of this file is to map all the various variations of a given
-# machine specification into a single specification in the form:
-# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or in some cases, the newer four-part form:
-# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-# It is wrong to echo any other type of specification.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
- $0 [OPTION] ALIAS
-
-Canonicalize a configuration name.
-
-Operation modes:
- -h, --help print this help, then exit
- -t, --time-stamp print date of last modification, then exit
- -v, --version print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.sub ($timestamp)
-
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions. There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
- case $1 in
- --time-stamp | --time* | -t )
- echo "$timestamp" ; exit 0 ;;
- --version | -v )
- echo "$version" ; exit 0 ;;
- --help | --h* | -h )
- echo "$usage"; exit 0 ;;
- -- ) # Stop option processing
- shift; break ;;
- - ) # Use stdin as input.
- break ;;
- -* )
- echo "$me: invalid option $1$help"
- exit 1 ;;
-
- *local*)
- # First pass through any local machine types.
- echo $1
- exit 0;;
-
- * )
- break ;;
- esac
-done
-
-case $# in
- 0) echo "$me: missing argument$help" >&2
- exit 1;;
- 1) ;;
- *) echo "$me: too many arguments$help" >&2
- exit 1;;
-esac
-
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
- nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-* | rtmk-nova*)
- os=-$maybe_os
- basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
- ;;
- *)
- basic_machine=`echo $1 | sed 's/-[^-]*$//'`
- if [ $basic_machine != $1 ]
- then os=`echo $1 | sed 's/.*-/-/'`
- else os=; fi
- ;;
-esac
-
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work. We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
- -sun*os*)
- # Prevent following clause from handling this invalid input.
- ;;
- -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
- -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
- -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
- -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
- -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
- -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis)
- os=
- basic_machine=$1
- ;;
- -sim | -cisco | -oki | -wec | -winbond)
- os=
- basic_machine=$1
- ;;
- -scout)
- ;;
- -wrs)
- os=-vxworks
- basic_machine=$1
- ;;
- -chorusos*)
- os=-chorusos
- basic_machine=$1
- ;;
- -chorusrdb)
- os=-chorusrdb
- basic_machine=$1
- ;;
- -hiux*)
- os=-hiuxwe2
- ;;
- -sco5)
- os=-sco3.2v5
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco4)
- os=-sco3.2v4
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2.[4-9]*)
- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2v[4-9]*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco*)
- os=-sco3.2v2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -udk*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -isc)
- os=-isc2.2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -clix*)
- basic_machine=clipper-intergraph
- ;;
- -isc*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -lynx*)
- os=-lynxos
- ;;
- -ptx*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
- ;;
- -windowsnt*)
- os=`echo $os | sed -e 's/windowsnt/winnt/'`
- ;;
- -psos*)
- os=-psos
- ;;
- -mint | -mint[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
-esac
-
-# Decode aliases for certain CPU-COMPANY combinations.
-case $basic_machine in
- # Recognize the basic CPU types without company name.
- # Some are omitted here because they have special meanings below.
- 1750a | 580 \
- | a29k \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
- | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
- | c4x | clipper \
- | d10v | d30v | dsp16xx \
- | fr30 \
- | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
- | i370 | i860 | i960 | ia64 \
- | m32r | m68000 | m68k | m88k | mcore \
- | mips | mips16 | mips64 | mips64el | mips64orion | mips64orionel \
- | mips64vr4100 | mips64vr4100el | mips64vr4300 \
- | mips64vr4300el | mips64vr5000 | mips64vr5000el \
- | mipsbe | mipseb | mipsel | mipsle | mipstx39 | mipstx39el \
- | mipsisa32 | mipsisa64 \
- | mn10200 | mn10300 \
- | ns16k | ns32k \
- | openrisc | or32 \
- | pdp10 | pdp11 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
- | pyramid \
- | sh | sh[34] | sh[34]eb | shbe | shle | sh64 \
- | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
- | strongarm \
- | tahoe | thumb | tic80 | tron \
- | v850 | v850e \
- | we32k \
- | x86 | xscale | xstormy16 | xtensa \
- | z8k)
- basic_machine=$basic_machine-unknown
- ;;
- m6811 | m68hc11 | m6812 | m68hc12)
- # Motorola 68HC11/12.
- basic_machine=$basic_machine-unknown
- os=-none
- ;;
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
- ;;
-
- # We use `pc' rather than `unknown'
- # because (1) that's what they normally are, and
- # (2) the word "unknown" tends to confuse beginning users.
- i*86 | x86_64)
- basic_machine=$basic_machine-pc
- ;;
- # Object if more than one company name word.
- *-*-*)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
- # Recognize the basic CPU types with company name.
- 580-* \
- | a29k-* \
- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
- | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
- | arm-* | armbe-* | armle-* | armv*-* \
- | avr-* \
- | bs2000-* \
- | c[123]* | c30-* | [cjt]90-* | c54x-* \
- | clipper-* | cydra-* \
- | d10v-* | d30v-* \
- | elxsi-* \
- | f30[01]-* | f700-* | fr30-* | fx80-* \
- | h8300-* | h8500-* \
- | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
- | i*86-* | i860-* | i960-* | ia64-* \
- | m32r-* \
- | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | mcore-* \
- | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \
- | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \
- | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipseb-* \
- | mipsle-* | mipsel-* | mipstx39-* | mipstx39el-* \
- | none-* | np1-* | ns16k-* | ns32k-* \
- | orion-* \
- | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
- | pyramid-* \
- | romp-* | rs6000-* \
- | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* | sh64-* \
- | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
- | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
- | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \
- | v850-* | v850e-* | vax-* \
- | we32k-* \
- | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
- | xtensa-* \
- | ymp-* \
- | z8k-*)
- ;;
- # Recognize the various machine names and aliases which stand
- # for a CPU type and a company and sometimes even an OS.
- 386bsd)
- basic_machine=i386-unknown
- os=-bsd
- ;;
- 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
- basic_machine=m68000-att
- ;;
- 3b*)
- basic_machine=we32k-att
- ;;
- a29khif)
- basic_machine=a29k-amd
- os=-udi
- ;;
- adobe68k)
- basic_machine=m68010-adobe
- os=-scout
- ;;
- alliant | fx80)
- basic_machine=fx80-alliant
- ;;
- altos | altos3068)
- basic_machine=m68k-altos
- ;;
- am29k)
- basic_machine=a29k-none
- os=-bsd
- ;;
- amdahl)
- basic_machine=580-amdahl
- os=-sysv
- ;;
- amiga | amiga-*)
- basic_machine=m68k-unknown
- ;;
- amigaos | amigados)
- basic_machine=m68k-unknown
- os=-amigaos
- ;;
- amigaunix | amix)
- basic_machine=m68k-unknown
- os=-sysv4
- ;;
- apollo68)
- basic_machine=m68k-apollo
- os=-sysv
- ;;
- apollo68bsd)
- basic_machine=m68k-apollo
- os=-bsd
- ;;
- aux)
- basic_machine=m68k-apple
- os=-aux
- ;;
- balance)
- basic_machine=ns32k-sequent
- os=-dynix
- ;;
- c90)
- basic_machine=c90-cray
- os=-unicos
- ;;
- convex-c1)
- basic_machine=c1-convex
- os=-bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- os=-bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- os=-bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- os=-bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- os=-bsd
- ;;
- cray | j90)
- basic_machine=j90-cray
- os=-unicos
- ;;
- crds | unos)
- basic_machine=m68k-crds
- ;;
- cris | cris-* | etrax*)
- basic_machine=cris-axis
- ;;
- da30 | da30-*)
- basic_machine=m68k-da30
- ;;
- decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
- basic_machine=mips-dec
- ;;
- decsystem10* | dec10*)
- basic_machine=pdp10-dec
- os=-tops10
- ;;
- decsystem20* | dec20*)
- basic_machine=pdp10-dec
- os=-tops20
- ;;
- delta | 3300 | motorola-3300 | motorola-delta \
- | 3300-motorola | delta-motorola)
- basic_machine=m68k-motorola
- ;;
- delta88)
- basic_machine=m88k-motorola
- os=-sysv3
- ;;
- dpx20 | dpx20-*)
- basic_machine=rs6000-bull
- os=-bosx
- ;;
- dpx2* | dpx2*-bull)
- basic_machine=m68k-bull
- os=-sysv3
- ;;
- ebmon29k)
- basic_machine=a29k-amd
- os=-ebmon
- ;;
- elxsi)
- basic_machine=elxsi-elxsi
- os=-bsd
- ;;
- encore | umax | mmax)
- basic_machine=ns32k-encore
- ;;
- es1800 | OSE68k | ose68k | ose | OSE)
- basic_machine=m68k-ericsson
- os=-ose
- ;;
- fx2800)
- basic_machine=i860-alliant
- ;;
- genix)
- basic_machine=ns32k-ns
- ;;
- gmicro)
- basic_machine=tron-gmicro
- os=-sysv
- ;;
- go32)
- basic_machine=i386-pc
- os=-go32
- ;;
- h3050r* | hiux*)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- h8300hms)
- basic_machine=h8300-hitachi
- os=-hms
- ;;
- h8300xray)
- basic_machine=h8300-hitachi
- os=-xray
- ;;
- h8500hms)
- basic_machine=h8500-hitachi
- os=-hms
- ;;
- harris)
- basic_machine=m88k-harris
- os=-sysv3
- ;;
- hp300-*)
- basic_machine=m68k-hp
- ;;
- hp300bsd)
- basic_machine=m68k-hp
- os=-bsd
- ;;
- hp300hpux)
- basic_machine=m68k-hp
- os=-hpux
- ;;
- hp3k9[0-9][0-9] | hp9[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k2[0-9][0-9] | hp9k31[0-9])
- basic_machine=m68000-hp
- ;;
- hp9k3[2-9][0-9])
- basic_machine=m68k-hp
- ;;
- hp9k6[0-9][0-9] | hp6[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k7[0-79][0-9] | hp7[0-79][0-9])
- basic_machine=hppa1.1-hp
- ;;
- hp9k78[0-9] | hp78[0-9])
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][13679] | hp8[0-9][13679])
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][0-9] | hp8[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hppa-next)
- os=-nextstep3
- ;;
- hppaosf)
- basic_machine=hppa1.1-hp
- os=-osf
- ;;
- hppro)
- basic_machine=hppa1.1-hp
- os=-proelf
- ;;
- i370-ibm* | ibm*)
- basic_machine=i370-ibm
- ;;
-# I'm not sure what "Sysv32" means. Should this be sysv3.2?
- i*86v32)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv32
- ;;
- i*86v4*)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv4
- ;;
- i*86v)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv
- ;;
- i*86sol2)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-solaris2
- ;;
- i386mach)
- basic_machine=i386-mach
- os=-mach
- ;;
- i386-vsta | vsta)
- basic_machine=i386-unknown
- os=-vsta
- ;;
- iris | iris4d)
- basic_machine=mips-sgi
- case $os in
- -irix*)
- ;;
- *)
- os=-irix4
- ;;
- esac
- ;;
- isi68 | isi)
- basic_machine=m68k-isi
- os=-sysv
- ;;
- m88k-omron*)
- basic_machine=m88k-omron
- ;;
- magnum | m3230)
- basic_machine=mips-mips
- os=-sysv
- ;;
- merlin)
- basic_machine=ns32k-utek
- os=-sysv
- ;;
- mingw32)
- basic_machine=i386-pc
- os=-mingw32
- ;;
- miniframe)
- basic_machine=m68000-convergent
- ;;
- *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
- mips3*-*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
- ;;
- mips3*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
- ;;
- mmix*)
- basic_machine=mmix-knuth
- os=-mmixware
- ;;
- monitor)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- morphos)
- basic_machine=powerpc-unknown
- os=-morphos
- ;;
- msdos)
- basic_machine=i386-pc
- os=-msdos
- ;;
- mvs)
- basic_machine=i370-ibm
- os=-mvs
- ;;
- ncr3000)
- basic_machine=i486-ncr
- os=-sysv4
- ;;
- netbsd386)
- basic_machine=i386-unknown
- os=-netbsd
- ;;
- netwinder)
- basic_machine=armv4l-rebel
- os=-linux
- ;;
- news | news700 | news800 | news900)
- basic_machine=m68k-sony
- os=-newsos
- ;;
- news1000)
- basic_machine=m68030-sony
- os=-newsos
- ;;
- news-3600 | risc-news)
- basic_machine=mips-sony
- os=-newsos
- ;;
- necv70)
- basic_machine=v70-nec
- os=-sysv
- ;;
- next | m*-next )
- basic_machine=m68k-next
- case $os in
- -nextstep* )
- ;;
- -ns2*)
- os=-nextstep2
- ;;
- *)
- os=-nextstep3
- ;;
- esac
- ;;
- nh3000)
- basic_machine=m68k-harris
- os=-cxux
- ;;
- nh[45]000)
- basic_machine=m88k-harris
- os=-cxux
- ;;
- nindy960)
- basic_machine=i960-intel
- os=-nindy
- ;;
- mon960)
- basic_machine=i960-intel
- os=-mon960
- ;;
- nonstopux)
- basic_machine=mips-compaq
- os=-nonstopux
- ;;
- np1)
- basic_machine=np1-gould
- ;;
- nsr-tandem)
- basic_machine=nsr-tandem
- ;;
- op50n-* | op60c-*)
- basic_machine=hppa1.1-oki
- os=-proelf
- ;;
- or32 | or32-*)
- basic_machine=or32-unknown
- os=-coff
- ;;
- OSE68000 | ose68000)
- basic_machine=m68000-ericsson
- os=-ose
- ;;
- os68k)
- basic_machine=m68k-none
- os=-os68k
- ;;
- pa-hitachi)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- paragon)
- basic_machine=i860-intel
- os=-osf
- ;;
- pbd)
- basic_machine=sparc-tti
- ;;
- pbb)
- basic_machine=m68k-tti
- ;;
- pc532 | pc532-*)
- basic_machine=ns32k-pc532
- ;;
- pentium | p5 | k5 | k6 | nexgen | viac3)
- basic_machine=i586-pc
- ;;
- pentiumpro | p6 | 6x86 | athlon)
- basic_machine=i686-pc
- ;;
- pentiumii | pentium2)
- basic_machine=i686-pc
- ;;
- pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
- basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumpro-* | p6-* | 6x86-* | athlon-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumii-* | pentium2-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pn)
- basic_machine=pn-gould
- ;;
- power) basic_machine=power-ibm
- ;;
- ppc) basic_machine=powerpc-unknown
- ;;
- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppcle | powerpclittle | ppc-le | powerpc-little)
- basic_machine=powerpcle-unknown
- ;;
- ppcle-* | powerpclittle-*)
- basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64) basic_machine=powerpc64-unknown
- ;;
- ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64le | powerpc64little | ppc64-le | powerpc64-little)
- basic_machine=powerpc64le-unknown
- ;;
- ppc64le-* | powerpc64little-*)
- basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ps2)
- basic_machine=i386-ibm
- ;;
- pw32)
- basic_machine=i586-unknown
- os=-pw32
- ;;
- rom68k)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- rm[46]00)
- basic_machine=mips-siemens
- ;;
- rtpc | rtpc-*)
- basic_machine=romp-ibm
- ;;
- s390 | s390-*)
- basic_machine=s390-ibm
- ;;
- s390x | s390x-*)
- basic_machine=s390x-ibm
- ;;
- sa29200)
- basic_machine=a29k-amd
- os=-udi
- ;;
- sequent)
- basic_machine=i386-sequent
- ;;
- sh)
- basic_machine=sh-hitachi
- os=-hms
- ;;
- sparclite-wrs | simso-wrs)
- basic_machine=sparclite-wrs
- os=-vxworks
- ;;
- sps7)
- basic_machine=m68k-bull
- os=-sysv2
- ;;
- spur)
- basic_machine=spur-unknown
- ;;
- st2000)
- basic_machine=m68k-tandem
- ;;
- stratus)
- basic_machine=i860-stratus
- os=-sysv4
- ;;
- sun2)
- basic_machine=m68000-sun
- ;;
- sun2os3)
- basic_machine=m68000-sun
- os=-sunos3
- ;;
- sun2os4)
- basic_machine=m68000-sun
- os=-sunos4
- ;;
- sun3os3)
- basic_machine=m68k-sun
- os=-sunos3
- ;;
- sun3os4)
- basic_machine=m68k-sun
- os=-sunos4
- ;;
- sun4os3)
- basic_machine=sparc-sun
- os=-sunos3
- ;;
- sun4os4)
- basic_machine=sparc-sun
- os=-sunos4
- ;;
- sun4sol2)
- basic_machine=sparc-sun
- os=-solaris2
- ;;
- sun3 | sun3-*)
- basic_machine=m68k-sun
- ;;
- sun4)
- basic_machine=sparc-sun
- ;;
- sun386 | sun386i | roadrunner)
- basic_machine=i386-sun
- ;;
- sv1)
- basic_machine=sv1-cray
- os=-unicos
- ;;
- symmetry)
- basic_machine=i386-sequent
- os=-dynix
- ;;
- t3d)
- basic_machine=alpha-cray
- os=-unicos
- ;;
- t3e)
- basic_machine=alphaev5-cray
- os=-unicos
- ;;
- t90)
- basic_machine=t90-cray
- os=-unicos
- ;;
- tic54x | c54x*)
- basic_machine=tic54x-unknown
- os=-coff
- ;;
- tx39)
- basic_machine=mipstx39-unknown
- ;;
- tx39el)
- basic_machine=mipstx39el-unknown
- ;;
- toad1)
- basic_machine=pdp10-xkl
- os=-tops20
- ;;
- tower | tower-32)
- basic_machine=m68k-ncr
- ;;
- udi29k)
- basic_machine=a29k-amd
- os=-udi
- ;;
- ultra3)
- basic_machine=a29k-nyu
- os=-sym1
- ;;
- v810 | necv810)
- basic_machine=v810-nec
- os=-none
- ;;
- vaxv)
- basic_machine=vax-dec
- os=-sysv
- ;;
- vms)
- basic_machine=vax-dec
- os=-vms
- ;;
- vpp*|vx|vx-*)
- basic_machine=f301-fujitsu
- ;;
- vxworks960)
- basic_machine=i960-wrs
- os=-vxworks
- ;;
- vxworks68)
- basic_machine=m68k-wrs
- os=-vxworks
- ;;
- vxworks29k)
- basic_machine=a29k-wrs
- os=-vxworks
- ;;
- w65*)
- basic_machine=w65-wdc
- os=-none
- ;;
- w89k-*)
- basic_machine=hppa1.1-winbond
- os=-proelf
- ;;
- windows32)
- basic_machine=i386-pc
- os=-windows32-msvcrt
- ;;
- xps | xps100)
- basic_machine=xps100-honeywell
- ;;
- ymp)
- basic_machine=ymp-cray
- os=-unicos
- ;;
- z8k-*-coff)
- basic_machine=z8k-unknown
- os=-sim
- ;;
- none)
- basic_machine=none-none
- os=-none
- ;;
-
-# Here we handle the default manufacturer of certain CPU types. It is in
-# some cases the only manufacturer, in others, it is the most popular.
- w89k)
- basic_machine=hppa1.1-winbond
- ;;
- op50n)
- basic_machine=hppa1.1-oki
- ;;
- op60c)
- basic_machine=hppa1.1-oki
- ;;
- romp)
- basic_machine=romp-ibm
- ;;
- rs6000)
- basic_machine=rs6000-ibm
- ;;
- vax)
- basic_machine=vax-dec
- ;;
- pdp10)
- # there are many clones, so DEC is not a safe bet
- basic_machine=pdp10-unknown
- ;;
- pdp11)
- basic_machine=pdp11-dec
- ;;
- we32k)
- basic_machine=we32k-att
- ;;
- sh3 | sh4 | sh3eb | sh4eb)
- basic_machine=sh-unknown
- ;;
- sh64)
- basic_machine=sh64-unknown
- ;;
- sparc | sparcv9 | sparcv9b)
- basic_machine=sparc-sun
- ;;
- cydra)
- basic_machine=cydra-cydrome
- ;;
- orion)
- basic_machine=orion-highlevel
- ;;
- orion105)
- basic_machine=clipper-highlevel
- ;;
- mac | mpw | mac-mpw)
- basic_machine=m68k-apple
- ;;
- pmac | pmac-mpw)
- basic_machine=powerpc-apple
- ;;
- c4x*)
- basic_machine=c4x-none
- os=-coff
- ;;
- *-unknown)
- # Make sure to match an already-canonicalized machine name.
- ;;
- *)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
-esac
-
-# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
- *-digital*)
- basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
- ;;
- *-commodore*)
- basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
- ;;
- *)
- ;;
-esac
-
-# Decode manufacturer-specific aliases for certain operating systems.
-
-if [ x"$os" != x"" ]
-then
-case $os in
- # First match some system type aliases
- # that might get confused with valid system types.
- # -solaris* is a basic system type, with this one exception.
- -solaris1 | -solaris1.*)
- os=`echo $os | sed -e 's|solaris1|sunos4|'`
- ;;
- -solaris)
- os=-solaris2
- ;;
- -svr4*)
- os=-sysv4
- ;;
- -unixware*)
- os=-sysv4.2uw
- ;;
- -gnu/linux*)
- os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
- ;;
- # First accept the basic system types.
- # The portable systems comes first.
- # Each alternative MUST END IN A *, to match a version number.
- # -sysv* is not here because it comes later, after sysvr4.
- -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
- | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* \
- | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
- | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
- | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
- | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
- | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* \
- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
- | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
- | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
- | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
- | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
- | -morphos* | -superux* | -rtmk* | -rtmk-nova*)
- # Remember, each alternative MUST END IN *, to match a version number.
- ;;
- -qnx*)
- case $basic_machine in
- x86-* | i*86-*)
- ;;
- *)
- os=-nto$os
- ;;
- esac
- ;;
- -nto*)
- os=-nto-qnx
- ;;
- -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
- | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
- | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
- ;;
- -mac*)
- os=`echo $os | sed -e 's|mac|macos|'`
- ;;
- -linux*)
- os=`echo $os | sed -e 's|linux|linux-gnu|'`
- ;;
- -sunos5*)
- os=`echo $os | sed -e 's|sunos5|solaris2|'`
- ;;
- -sunos6*)
- os=`echo $os | sed -e 's|sunos6|solaris3|'`
- ;;
- -opened*)
- os=-openedition
- ;;
- -wince*)
- os=-wince
- ;;
- -osfrose*)
- os=-osfrose
- ;;
- -osf*)
- os=-osf
- ;;
- -utek*)
- os=-bsd
- ;;
- -dynix*)
- os=-bsd
- ;;
- -acis*)
- os=-aos
- ;;
- -atheos*)
- os=-atheos
- ;;
- -386bsd)
- os=-bsd
- ;;
- -ctix* | -uts*)
- os=-sysv
- ;;
- -nova*)
- os=-rtmk-nova
- ;;
- -ns2 )
- os=-nextstep2
- ;;
- -nsk*)
- os=-nsk
- ;;
- # Preserve the version number of sinix5.
- -sinix5.*)
- os=`echo $os | sed -e 's|sinix|sysv|'`
- ;;
- -sinix*)
- os=-sysv4
- ;;
- -triton*)
- os=-sysv3
- ;;
- -oss*)
- os=-sysv3
- ;;
- -svr4)
- os=-sysv4
- ;;
- -svr3)
- os=-sysv3
- ;;
- -sysvr4)
- os=-sysv4
- ;;
- # This must come after -sysvr4.
- -sysv*)
- ;;
- -ose*)
- os=-ose
- ;;
- -es1800*)
- os=-ose
- ;;
- -xenix)
- os=-xenix
- ;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- os=-mint
- ;;
- -none)
- ;;
- *)
- # Get rid of the `-' at the beginning of $os.
- os=`echo $os | sed 's/[^-]*-//'`
- echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
- exit 1
- ;;
-esac
-else
-
-# Here we handle the default operating systems that come with various machines.
-# The value should be what the vendor currently ships out the door with their
-# machine or put another way, the most popular os provided with the machine.
-
-# Note that if you're going to try to match "-MANUFACTURER" here (say,
-# "-sun"), then you have to tell the case statement up towards the top
-# that MANUFACTURER isn't an operating system. Otherwise, code above
-# will signal an error saying that MANUFACTURER isn't an operating
-# system, and we'll never get to this point.
-
-case $basic_machine in
- *-acorn)
- os=-riscix1.2
- ;;
- arm*-rebel)
- os=-linux
- ;;
- arm*-semi)
- os=-aout
- ;;
- # This must come before the *-dec entry.
- pdp10-*)
- os=-tops20
- ;;
- pdp11-*)
- os=-none
- ;;
- *-dec | vax-*)
- os=-ultrix4.2
- ;;
- m68*-apollo)
- os=-domain
- ;;
- i386-sun)
- os=-sunos4.0.2
- ;;
- m68000-sun)
- os=-sunos3
- # This also exists in the configure program, but was not the
- # default.
- # os=-sunos4
- ;;
- m68*-cisco)
- os=-aout
- ;;
- mips*-cisco)
- os=-elf
- ;;
- mips*-*)
- os=-elf
- ;;
- or32-*)
- os=-coff
- ;;
- *-tti) # must be before sparc entry or we get the wrong os.
- os=-sysv3
- ;;
- sparc-* | *-sun)
- os=-sunos4.1.1
- ;;
- *-be)
- os=-beos
- ;;
- *-ibm)
- os=-aix
- ;;
- *-wec)
- os=-proelf
- ;;
- *-winbond)
- os=-proelf
- ;;
- *-oki)
- os=-proelf
- ;;
- *-hp)
- os=-hpux
- ;;
- *-hitachi)
- os=-hiux
- ;;
- i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
- os=-sysv
- ;;
- *-cbm)
- os=-amigaos
- ;;
- *-dg)
- os=-dgux
- ;;
- *-dolphin)
- os=-sysv3
- ;;
- m68k-ccur)
- os=-rtu
- ;;
- m88k-omron*)
- os=-luna
- ;;
- *-next )
- os=-nextstep
- ;;
- *-sequent)
- os=-ptx
- ;;
- *-crds)
- os=-unos
- ;;
- *-ns)
- os=-genix
- ;;
- i370-*)
- os=-mvs
- ;;
- *-next)
- os=-nextstep3
- ;;
- *-gould)
- os=-sysv
- ;;
- *-highlevel)
- os=-bsd
- ;;
- *-encore)
- os=-bsd
- ;;
- *-sgi)
- os=-irix
- ;;
- *-siemens)
- os=-sysv4
- ;;
- *-masscomp)
- os=-rtu
- ;;
- f30[01]-fujitsu | f700-fujitsu)
- os=-uxpv
- ;;
- *-rom68k)
- os=-coff
- ;;
- *-*bug)
- os=-coff
- ;;
- *-apple)
- os=-macos
- ;;
- *-atari*)
- os=-mint
- ;;
- *)
- os=-none
- ;;
-esac
-fi
-
-# Here we handle the case where we know the os, and the CPU type, but not the
-# manufacturer. We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
- *-unknown)
- case $os in
- -riscix*)
- vendor=acorn
- ;;
- -sunos*)
- vendor=sun
- ;;
- -aix*)
- vendor=ibm
- ;;
- -beos*)
- vendor=be
- ;;
- -hpux*)
- vendor=hp
- ;;
- -mpeix*)
- vendor=hp
- ;;
- -hiux*)
- vendor=hitachi
- ;;
- -unos*)
- vendor=crds
- ;;
- -dgux*)
- vendor=dg
- ;;
- -luna*)
- vendor=omron
- ;;
- -genix*)
- vendor=ns
- ;;
- -mvs* | -opened*)
- vendor=ibm
- ;;
- -ptx*)
- vendor=sequent
- ;;
- -vxsim* | -vxworks*)
- vendor=wrs
- ;;
- -aux*)
- vendor=apple
- ;;
- -hms*)
- vendor=hitachi
- ;;
- -mpw* | -macos*)
- vendor=apple
- ;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- vendor=atari
- ;;
- -vos*)
- vendor=stratus
- ;;
- esac
- basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
- ;;
-esac
-
-echo $basic_machine$os
-exit 0
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
diff --git a/boehm-gc/configure b/boehm-gc/configure
deleted file mode 100755
index 7c4d08b9591..00000000000
--- a/boehm-gc/configure
+++ /dev/null
@@ -1,10039 +0,0 @@
-#! /bin/sh
-# From configure.in Revision: 1.2 .
-# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.53 for gc 6.3.
-#
-# Report bugs to <Hans.Boehm@hp.com>.
-#
-# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
-# Free Software Foundation, Inc.
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-
-# Find the correct PATH separator. Usually this is `:', but
-# DJGPP uses `;' like DOS.
-if test "X${PATH_SEPARATOR+set}" != Xset; then
- UNAME=${UNAME-`uname 2>/dev/null`}
- case X$UNAME in
- *-DOS) lt_cv_sys_path_separator=';' ;;
- *) lt_cv_sys_path_separator=':' ;;
- esac
- PATH_SEPARATOR=$lt_cv_sys_path_separator
-fi
-
-
-# Check that we are running under the correct shell.
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-case X$ECHO in
-X*--fallback-echo)
- # Remove one level of quotation (which was required for Make).
- ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','`
- ;;
-esac
-
-echo=${ECHO-echo}
-if test "X$1" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
-elif test "X$1" = X--fallback-echo; then
- # Avoid inline document here, it may be left over
- :
-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
- # Yippee, $echo works!
- :
-else
- # Restart under the correct shell.
- exec $SHELL "$0" --no-reexec ${1+"$@"}
-fi
-
-if test "X$1" = X--fallback-echo; then
- # used as fallback echo
- shift
- cat <<EOF
-
-EOF
- exit 0
-fi
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
-
-if test -z "$ECHO"; then
-if test "X${echo_test_string+set}" != Xset; then
-# find a string as large as possible, as long as the shell can cope with it
- for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
- # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
- if (echo_test_string="`eval $cmd`") 2>/dev/null &&
- echo_test_string="`eval $cmd`" &&
- (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
- then
- break
- fi
- done
-fi
-
-if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- :
-else
- # The Solaris, AIX, and Digital Unix default echo programs unquote
- # backslashes. This makes it impossible to quote backslashes using
- # echo "$something" | sed 's/\\/\\\\/g'
- #
- # So, first we look for a working echo in the user's PATH.
-
- IFS="${IFS= }"; save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for dir in $PATH /usr/ucb; do
- if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
- test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- echo="$dir/echo"
- break
- fi
- done
- IFS="$save_ifs"
-
- if test "X$echo" = Xecho; then
- # We didn't find a better echo, so look for alternatives.
- if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- # This shell has a builtin print -r that does the trick.
- echo='print -r'
- elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
- test "X$CONFIG_SHELL" != X/bin/ksh; then
- # If we have ksh, try running configure again with it.
- ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
- export ORIGINAL_CONFIG_SHELL
- CONFIG_SHELL=/bin/ksh
- export CONFIG_SHELL
- exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
- else
- # Try using printf.
- echo='printf %s\n'
- if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- # Cool, printf works
- :
- elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
- test "X$echo_testing_string" = 'X\t' &&
- echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
- export CONFIG_SHELL
- SHELL="$CONFIG_SHELL"
- export SHELL
- echo="$CONFIG_SHELL $0 --fallback-echo"
- elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
- test "X$echo_testing_string" = 'X\t' &&
- echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- echo="$CONFIG_SHELL $0 --fallback-echo"
- else
- # maybe with a smaller string...
- prev=:
-
- for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
- if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
- then
- break
- fi
- prev="$cmd"
- done
-
- if test "$prev" != 'sed 50q "$0"'; then
- echo_test_string=`eval $prev`
- export echo_test_string
- exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
- else
- # Oops. We lost completely, so just stick with echo.
- echo=echo
- fi
- fi
- fi
- fi
-fi
-fi
-
-# Copy echo and quote the copy suitably for passing to libtool from
-# the Makefile, instead of quoting the original, which is used later.
-ECHO=$echo
-if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
- ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
-fi
-
-
-
-if expr a : '\(a\)' >/dev/null 2>&1; then
- as_expr=expr
-else
- as_expr=false
-fi
-
-
-## --------------------- ##
-## M4sh Initialization. ##
-## --------------------- ##
-
-# Be Bourne compatible
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
- emulate sh
- NULLCMD=:
-elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
- set -o posix
-fi
-
-# NLS nuisances.
-# Support unset when possible.
-if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
- as_unset=unset
-else
- as_unset=false
-fi
-
-(set +x; test -n "`(LANG=C; export LANG) 2>&1`") &&
- { $as_unset LANG || test "${LANG+set}" != set; } ||
- { LANG=C; export LANG; }
-(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") &&
- { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } ||
- { LC_ALL=C; export LC_ALL; }
-(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") &&
- { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } ||
- { LC_TIME=C; export LC_TIME; }
-(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") &&
- { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } ||
- { LC_CTYPE=C; export LC_CTYPE; }
-(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") &&
- { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } ||
- { LANGUAGE=C; export LANGUAGE; }
-(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") &&
- { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } ||
- { LC_COLLATE=C; export LC_COLLATE; }
-(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") &&
- { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } ||
- { LC_NUMERIC=C; export LC_NUMERIC; }
-(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") &&
- { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } ||
- { LC_MESSAGES=C; export LC_MESSAGES; }
-
-
-# Name of the executable.
-as_me=`(basename "$0") 2>/dev/null ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
- X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)$' \| \
- . : '\(.\)' 2>/dev/null ||
-echo X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
- /^X\/\(\/\/\)$/{ s//\1/; q; }
- /^X\/\(\/\).*/{ s//\1/; q; }
- s/.*/./; q'`
-
-# PATH needs CR, and LINENO needs CR and PATH.
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
- echo "#! /bin/sh" >conftest.sh
- echo "exit 0" >>conftest.sh
- chmod +x conftest.sh
- if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then
- PATH_SEPARATOR=';'
- else
- PATH_SEPARATOR=:
- fi
- rm -f conftest.sh
-fi
-
-
- as_lineno_1=$LINENO
- as_lineno_2=$LINENO
- as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
- test "x$as_lineno_1" != "x$as_lineno_2" &&
- test "x$as_lineno_3" = "x$as_lineno_2" || {
- # Find who we are. Look in the path if we contain no path at all
- # relative or not.
- case $0 in
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-done
-
- ;;
- esac
- # We did not find ourselves, most probably we were run as `sh COMMAND'
- # in which case we are not to be found in the path.
- if test "x$as_myself" = x; then
- as_myself=$0
- fi
- if test ! -f "$as_myself"; then
- { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
- { (exit 1); exit 1; }; }
- fi
- case $CONFIG_SHELL in
- '')
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for as_base in sh bash ksh sh5; do
- case $as_dir in
- /*)
- if ("$as_dir/$as_base" -c '
- as_lineno_1=$LINENO
- as_lineno_2=$LINENO
- as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
- test "x$as_lineno_1" != "x$as_lineno_2" &&
- test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
- CONFIG_SHELL=$as_dir/$as_base
- export CONFIG_SHELL
- exec "$CONFIG_SHELL" "$0" ${1+"$@"}
- fi;;
- esac
- done
-done
-;;
- esac
-
- # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
- # uniformly replaced by the line number. The first 'sed' inserts a
- # line-number line before each line; the second 'sed' does the real
- # work. The second script uses 'N' to pair each line-number line
- # with the numbered line, and appends trailing '-' during
- # substitution so that $LINENO is not a special case at line end.
- # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
- # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
- sed '=' <$as_myself |
- sed '
- N
- s,$,-,
- : loop
- s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
- t loop
- s,-$,,
- s,^['$as_cr_digits']*\n,,
- ' >$as_me.lineno &&
- chmod +x $as_me.lineno ||
- { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
- { (exit 1); exit 1; }; }
-
- # Don't try to exec as it changes $[0], causing all sort of problems
- # (the dirname of $[0] is not the place where we might find the
- # original and so on. Autoconf is especially sensible to this).
- . ./$as_me.lineno
- # Exit status is that of the last command.
- exit
-}
-
-
-case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
- *c*,-n*) ECHO_N= ECHO_C='
-' ECHO_T=' ' ;;
- *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
- *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
-esac
-
-if expr a : '\(a\)' >/dev/null 2>&1; then
- as_expr=expr
-else
- as_expr=false
-fi
-
-rm -f conf$$ conf$$.exe conf$$.file
-echo >conf$$.file
-if ln -s conf$$.file conf$$ 2>/dev/null; then
- # We could just check for DJGPP; but this test a) works b) is more generic
- # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
- if test -f conf$$.exe; then
- # Don't use ln at all; we don't have any links
- as_ln_s='cp -p'
- else
- as_ln_s='ln -s'
- fi
-elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
-else
- as_ln_s='cp -p'
-fi
-rm -f conf$$ conf$$.exe conf$$.file
-
-as_executable_p="test -f"
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
-
-
-# IFS
-# We need space, tab and new line, in precisely that order.
-as_nl='
-'
-IFS=" $as_nl"
-
-# CDPATH.
-$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; }
-
-
-# Name of the host.
-# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
-# so uname gets run too.
-ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
-
-exec 6>&1
-
-#
-# Initializations.
-#
-ac_default_prefix=/usr/local
-cross_compiling=no
-subdirs=
-MFLAGS=
-MAKEFLAGS=
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-# Maximum number of lines to put in a shell here document.
-# This variable seems obsolete. It should probably be removed, and
-# only ac_max_sed_lines should be used.
-: ${ac_max_here_lines=38}
-
-# Identity of this package.
-PACKAGE_NAME='gc'
-PACKAGE_TARNAME='gc'
-PACKAGE_VERSION='6.3'
-PACKAGE_STRING='gc 6.3'
-PACKAGE_BUGREPORT='Hans.Boehm@hp.com'
-
-ac_unique_file="gcj_mlc.c"
-# Factoring default headers for most tests.
-ac_includes_default="\
-#include <stdio.h>
-#if HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#if HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif
-#if STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# if HAVE_STDLIB_H
-# include <stdlib.h>
-# endif
-#endif
-#if HAVE_STRING_H
-# if !STDC_HEADERS && HAVE_MEMORY_H
-# include <memory.h>
-# endif
-# include <string.h>
-#endif
-#if HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#if HAVE_INTTYPES_H
-# include <inttypes.h>
-#else
-# if HAVE_STDINT_H
-# include <stdint.h>
-# endif
-#endif
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif"
-
-
-# Initialize some variables set by options.
-ac_init_help=
-ac_init_version=false
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-cache_file=/dev/null
-exec_prefix=NONE
-no_create=
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-verbose=
-x_includes=NONE
-x_libraries=NONE
-
-# Installation directory options.
-# These are left unexpanded so users can "make install exec_prefix=/foo"
-# and all the variables that are supposed to be based on exec_prefix
-# by default will actually change.
-# Use braces instead of parens because sh, perl, etc. also accept them.
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datadir='${prefix}/share'
-sysconfdir='${prefix}/etc'
-sharedstatedir='${prefix}/com'
-localstatedir='${prefix}/var'
-libdir='${exec_prefix}/lib'
-includedir='${prefix}/include'
-oldincludedir='/usr/include'
-infodir='${prefix}/info'
-mandir='${prefix}/man'
-
-ac_prev=
-for ac_option
-do
- # If the previous option needs an argument, assign it.
- if test -n "$ac_prev"; then
- eval "$ac_prev=\$ac_option"
- ac_prev=
- continue
- fi
-
- ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
-
- # Accept the important Cygnus configure options, so we can diagnose typos.
-
- case $ac_option in
-
- -bindir | --bindir | --bindi | --bind | --bin | --bi)
- ac_prev=bindir ;;
- -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
- bindir=$ac_optarg ;;
-
- -build | --build | --buil | --bui | --bu)
- ac_prev=build_alias ;;
- -build=* | --build=* | --buil=* | --bui=* | --bu=*)
- build_alias=$ac_optarg ;;
-
- -cache-file | --cache-file | --cache-fil | --cache-fi \
- | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
- ac_prev=cache_file ;;
- -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
- | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
- cache_file=$ac_optarg ;;
-
- --config-cache | -C)
- cache_file=config.cache ;;
-
- -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
- ac_prev=datadir ;;
- -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
- | --da=*)
- datadir=$ac_optarg ;;
-
- -disable-* | --disable-*)
- ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
- { echo "$as_me: error: invalid feature name: $ac_feature" >&2
- { (exit 1); exit 1; }; }
- ac_feature=`echo $ac_feature | sed 's/-/_/g'`
- eval "enable_$ac_feature=no" ;;
-
- -enable-* | --enable-*)
- ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
- { echo "$as_me: error: invalid feature name: $ac_feature" >&2
- { (exit 1); exit 1; }; }
- ac_feature=`echo $ac_feature | sed 's/-/_/g'`
- case $ac_option in
- *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
- *) ac_optarg=yes ;;
- esac
- eval "enable_$ac_feature='$ac_optarg'" ;;
-
- -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
- | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
- | --exec | --exe | --ex)
- ac_prev=exec_prefix ;;
- -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
- | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
- | --exec=* | --exe=* | --ex=*)
- exec_prefix=$ac_optarg ;;
-
- -gas | --gas | --ga | --g)
- # Obsolete; use --with-gas.
- with_gas=yes ;;
-
- -help | --help | --hel | --he | -h)
- ac_init_help=long ;;
- -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
- ac_init_help=recursive ;;
- -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
- ac_init_help=short ;;
-
- -host | --host | --hos | --ho)
- ac_prev=host_alias ;;
- -host=* | --host=* | --hos=* | --ho=*)
- host_alias=$ac_optarg ;;
-
- -includedir | --includedir | --includedi | --included | --include \
- | --includ | --inclu | --incl | --inc)
- ac_prev=includedir ;;
- -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
- | --includ=* | --inclu=* | --incl=* | --inc=*)
- includedir=$ac_optarg ;;
-
- -infodir | --infodir | --infodi | --infod | --info | --inf)
- ac_prev=infodir ;;
- -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
- infodir=$ac_optarg ;;
-
- -libdir | --libdir | --libdi | --libd)
- ac_prev=libdir ;;
- -libdir=* | --libdir=* | --libdi=* | --libd=*)
- libdir=$ac_optarg ;;
-
- -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
- | --libexe | --libex | --libe)
- ac_prev=libexecdir ;;
- -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
- | --libexe=* | --libex=* | --libe=*)
- libexecdir=$ac_optarg ;;
-
- -localstatedir | --localstatedir | --localstatedi | --localstated \
- | --localstate | --localstat | --localsta | --localst \
- | --locals | --local | --loca | --loc | --lo)
- ac_prev=localstatedir ;;
- -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
- | --localstate=* | --localstat=* | --localsta=* | --localst=* \
- | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
- localstatedir=$ac_optarg ;;
-
- -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
- ac_prev=mandir ;;
- -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
- mandir=$ac_optarg ;;
-
- -nfp | --nfp | --nf)
- # Obsolete; use --without-fp.
- with_fp=no ;;
-
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c | -n)
- no_create=yes ;;
-
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
- no_recursion=yes ;;
-
- -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
- | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
- | --oldin | --oldi | --old | --ol | --o)
- ac_prev=oldincludedir ;;
- -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
- | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
- | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
- oldincludedir=$ac_optarg ;;
-
- -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
- ac_prev=prefix ;;
- -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
- prefix=$ac_optarg ;;
-
- -program-prefix | --program-prefix | --program-prefi | --program-pref \
- | --program-pre | --program-pr | --program-p)
- ac_prev=program_prefix ;;
- -program-prefix=* | --program-prefix=* | --program-prefi=* \
- | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
- program_prefix=$ac_optarg ;;
-
- -program-suffix | --program-suffix | --program-suffi | --program-suff \
- | --program-suf | --program-su | --program-s)
- ac_prev=program_suffix ;;
- -program-suffix=* | --program-suffix=* | --program-suffi=* \
- | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
- program_suffix=$ac_optarg ;;
-
- -program-transform-name | --program-transform-name \
- | --program-transform-nam | --program-transform-na \
- | --program-transform-n | --program-transform- \
- | --program-transform | --program-transfor \
- | --program-transfo | --program-transf \
- | --program-trans | --program-tran \
- | --progr-tra | --program-tr | --program-t)
- ac_prev=program_transform_name ;;
- -program-transform-name=* | --program-transform-name=* \
- | --program-transform-nam=* | --program-transform-na=* \
- | --program-transform-n=* | --program-transform-=* \
- | --program-transform=* | --program-transfor=* \
- | --program-transfo=* | --program-transf=* \
- | --program-trans=* | --program-tran=* \
- | --progr-tra=* | --program-tr=* | --program-t=*)
- program_transform_name=$ac_optarg ;;
-
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil)
- silent=yes ;;
-
- -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
- ac_prev=sbindir ;;
- -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
- | --sbi=* | --sb=*)
- sbindir=$ac_optarg ;;
-
- -sharedstatedir | --sharedstatedir | --sharedstatedi \
- | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
- | --sharedst | --shareds | --shared | --share | --shar \
- | --sha | --sh)
- ac_prev=sharedstatedir ;;
- -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
- | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
- | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
- | --sha=* | --sh=*)
- sharedstatedir=$ac_optarg ;;
-
- -site | --site | --sit)
- ac_prev=site ;;
- -site=* | --site=* | --sit=*)
- site=$ac_optarg ;;
-
- -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
- ac_prev=srcdir ;;
- -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
- srcdir=$ac_optarg ;;
-
- -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
- | --syscon | --sysco | --sysc | --sys | --sy)
- ac_prev=sysconfdir ;;
- -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
- | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
- sysconfdir=$ac_optarg ;;
-
- -target | --target | --targe | --targ | --tar | --ta | --t)
- ac_prev=target_alias ;;
- -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
- target_alias=$ac_optarg ;;
-
- -v | -verbose | --verbose | --verbos | --verbo | --verb)
- verbose=yes ;;
-
- -version | --version | --versio | --versi | --vers | -V)
- ac_init_version=: ;;
-
- -with-* | --with-*)
- ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
- { echo "$as_me: error: invalid package name: $ac_package" >&2
- { (exit 1); exit 1; }; }
- ac_package=`echo $ac_package| sed 's/-/_/g'`
- case $ac_option in
- *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
- *) ac_optarg=yes ;;
- esac
- eval "with_$ac_package='$ac_optarg'" ;;
-
- -without-* | --without-*)
- ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
- { echo "$as_me: error: invalid package name: $ac_package" >&2
- { (exit 1); exit 1; }; }
- ac_package=`echo $ac_package | sed 's/-/_/g'`
- eval "with_$ac_package=no" ;;
-
- --x)
- # Obsolete; use --with-x.
- with_x=yes ;;
-
- -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
- | --x-incl | --x-inc | --x-in | --x-i)
- ac_prev=x_includes ;;
- -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
- | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
- x_includes=$ac_optarg ;;
-
- -x-libraries | --x-libraries | --x-librarie | --x-librari \
- | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
- ac_prev=x_libraries ;;
- -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
- | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
- x_libraries=$ac_optarg ;;
-
- -*) { echo "$as_me: error: unrecognized option: $ac_option
-Try \`$0 --help' for more information." >&2
- { (exit 1); exit 1; }; }
- ;;
-
- *=*)
- ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
- # Reject names that are not valid shell variable names.
- expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
- { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
- { (exit 1); exit 1; }; }
- ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
- eval "$ac_envvar='$ac_optarg'"
- export $ac_envvar ;;
-
- *)
- # FIXME: should be removed in autoconf 3.0.
- echo "$as_me: WARNING: you should use --build, --host, --target" >&2
- expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
- echo "$as_me: WARNING: invalid host type: $ac_option" >&2
- : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
- ;;
-
- esac
-done
-
-if test -n "$ac_prev"; then
- ac_option=--`echo $ac_prev | sed 's/_/-/g'`
- { echo "$as_me: error: missing argument to $ac_option" >&2
- { (exit 1); exit 1; }; }
-fi
-
-# Be sure to have absolute paths.
-for ac_var in exec_prefix prefix
-do
- eval ac_val=$`echo $ac_var`
- case $ac_val in
- [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
- *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
- { (exit 1); exit 1; }; };;
- esac
-done
-
-# Be sure to have absolute paths.
-for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
- localstatedir libdir includedir oldincludedir infodir mandir
-do
- eval ac_val=$`echo $ac_var`
- case $ac_val in
- [\\/$]* | ?:[\\/]* ) ;;
- *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
- { (exit 1); exit 1; }; };;
- esac
-done
-
-# There might be people who depend on the old broken behavior: `$host'
-# used to hold the argument of --host etc.
-# FIXME: To remove some day.
-build=$build_alias
-host=$host_alias
-target=$target_alias
-
-# FIXME: To remove some day.
-if test "x$host_alias" != x; then
- if test "x$build_alias" = x; then
- cross_compiling=maybe
- echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
- If a cross compiler is detected then cross compile mode will be used." >&2
- elif test "x$build_alias" != "x$host_alias"; then
- cross_compiling=yes
- fi
-fi
-
-ac_tool_prefix=
-test -n "$host_alias" && ac_tool_prefix=$host_alias-
-
-test "$silent" = yes && exec 6>/dev/null
-
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
- ac_srcdir_defaulted=yes
- # Try the directory containing this script, then its parent.
- ac_confdir=`(dirname "$0") 2>/dev/null ||
-$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$0" : 'X\(//\)[^/]' \| \
- X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)' \| \
- . : '\(.\)' 2>/dev/null ||
-echo X"$0" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
- /^X\(\/\/\)[^/].*/{ s//\1/; q; }
- /^X\(\/\/\)$/{ s//\1/; q; }
- /^X\(\/\).*/{ s//\1/; q; }
- s/.*/./; q'`
- srcdir=$ac_confdir
- if test ! -r $srcdir/$ac_unique_file; then
- srcdir=..
- fi
-else
- ac_srcdir_defaulted=no
-fi
-if test ! -r $srcdir/$ac_unique_file; then
- if test "$ac_srcdir_defaulted" = yes; then
- { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
- { (exit 1); exit 1; }; }
- else
- { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
- { (exit 1); exit 1; }; }
- fi
-fi
-srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
-ac_env_build_alias_set=${build_alias+set}
-ac_env_build_alias_value=$build_alias
-ac_cv_env_build_alias_set=${build_alias+set}
-ac_cv_env_build_alias_value=$build_alias
-ac_env_host_alias_set=${host_alias+set}
-ac_env_host_alias_value=$host_alias
-ac_cv_env_host_alias_set=${host_alias+set}
-ac_cv_env_host_alias_value=$host_alias
-ac_env_target_alias_set=${target_alias+set}
-ac_env_target_alias_value=$target_alias
-ac_cv_env_target_alias_set=${target_alias+set}
-ac_cv_env_target_alias_value=$target_alias
-ac_env_CC_set=${CC+set}
-ac_env_CC_value=$CC
-ac_cv_env_CC_set=${CC+set}
-ac_cv_env_CC_value=$CC
-ac_env_CFLAGS_set=${CFLAGS+set}
-ac_env_CFLAGS_value=$CFLAGS
-ac_cv_env_CFLAGS_set=${CFLAGS+set}
-ac_cv_env_CFLAGS_value=$CFLAGS
-ac_env_LDFLAGS_set=${LDFLAGS+set}
-ac_env_LDFLAGS_value=$LDFLAGS
-ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
-ac_cv_env_LDFLAGS_value=$LDFLAGS
-ac_env_CPPFLAGS_set=${CPPFLAGS+set}
-ac_env_CPPFLAGS_value=$CPPFLAGS
-ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
-ac_cv_env_CPPFLAGS_value=$CPPFLAGS
-ac_env_CXX_set=${CXX+set}
-ac_env_CXX_value=$CXX
-ac_cv_env_CXX_set=${CXX+set}
-ac_cv_env_CXX_value=$CXX
-ac_env_CXXFLAGS_set=${CXXFLAGS+set}
-ac_env_CXXFLAGS_value=$CXXFLAGS
-ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set}
-ac_cv_env_CXXFLAGS_value=$CXXFLAGS
-ac_env_CPP_set=${CPP+set}
-ac_env_CPP_value=$CPP
-ac_cv_env_CPP_set=${CPP+set}
-ac_cv_env_CPP_value=$CPP
-
-#
-# Report the --help message.
-#
-if test "$ac_init_help" = "long"; then
- # Omit some internal or obsolete options to make the list less imposing.
- # This message is too long to be a string in the A/UX 3.1 sh.
- cat <<_ACEOF
-\`configure' configures gc 6.3 to adapt to many kinds of systems.
-
-Usage: $0 [OPTION]... [VAR=VALUE]...
-
-To assign environment variables (e.g., CC, CFLAGS...), specify them as
-VAR=VALUE. See below for descriptions of some of the useful variables.
-
-Defaults for the options are specified in brackets.
-
-Configuration:
- -h, --help display this help and exit
- --help=short display options specific to this package
- --help=recursive display the short help of all the included packages
- -V, --version display version information and exit
- -q, --quiet, --silent do not print \`checking...' messages
- --cache-file=FILE cache test results in FILE [disabled]
- -C, --config-cache alias for \`--cache-file=config.cache'
- -n, --no-create do not create output files
- --srcdir=DIR find the sources in DIR [configure dir or \`..']
-
-_ACEOF
-
- cat <<_ACEOF
-Installation directories:
- --prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
- --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
-
-By default, \`make install' will install all the files in
-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
-an installation prefix other than \`$ac_default_prefix' using \`--prefix',
-for instance \`--prefix=\$HOME'.
-
-For better control, use the options below.
-
-Fine tuning of the installation directories:
- --bindir=DIR user executables [EPREFIX/bin]
- --sbindir=DIR system admin executables [EPREFIX/sbin]
- --libexecdir=DIR program executables [EPREFIX/libexec]
- --datadir=DIR read-only architecture-independent data [PREFIX/share]
- --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
- --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
- --localstatedir=DIR modifiable single-machine data [PREFIX/var]
- --libdir=DIR object code libraries [EPREFIX/lib]
- --includedir=DIR C header files [PREFIX/include]
- --oldincludedir=DIR C header files for non-gcc [/usr/include]
- --infodir=DIR info documentation [PREFIX/info]
- --mandir=DIR man documentation [PREFIX/man]
-_ACEOF
-
- cat <<\_ACEOF
-
-Program names:
- --program-prefix=PREFIX prepend PREFIX to installed program names
- --program-suffix=SUFFIX append SUFFIX to installed program names
- --program-transform-name=PROGRAM run sed PROGRAM on installed program names
-
-System types:
- --build=BUILD configure for building on BUILD [guessed]
- --host=HOST cross-compile to build programs to run on HOST [BUILD]
- --target=TARGET configure for building compilers for TARGET [HOST]
-_ACEOF
-fi
-
-if test -n "$ac_init_help"; then
- case $ac_init_help in
- short | recursive ) echo "Configuration of gc 6.3:";;
- esac
- cat <<\_ACEOF
-
-Optional Features:
- --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
- --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
- --disable-dependency-tracking Speeds up one-time builds
- --enable-dependency-tracking Do not reject slow dependency extractors
- --enable-maintainer-mode enable make rules and dependencies not useful
- (and sometimes confusing) to the casual installer
- --enable-threads=TYPE choose threading package
- --enable-parallel-mark parallelize marking and free list construction
- --enable-cplusplus install C++ support
- --enable-shared=PKGS build shared libraries default=yes
- --enable-static=PKGS build static libraries default=yes
- --enable-fast-install=PKGS optimize for fast installation default=yes
- --disable-libtool-lock avoid locking (might break parallel builds)
- --enable-full-debug include full support for pointer backtracing etc.
- --enable-redirect-malloc redirect malloc and friends to GC routines
- --enable-gc-assertions collector-internal assertion checking
-
-Optional Packages:
- --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
- --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --with-ecos enable runtime eCos target support
- --with-gnu-ld assume the C compiler uses GNU ld default=no
- --with-pic try to use only PIC/non-PIC objects default=use both
- --with-target-subdir=SUBDIR
- configuring with a cross compiler
- --with-cross-host=HOST configuring with a cross compiler
-
-Some influential environment variables:
- CC C compiler command
- CFLAGS C compiler flags
- LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
- nonstandard directory <lib dir>
- CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
- headers in a nonstandard directory <include dir>
- CXX C++ compiler command
- CXXFLAGS C++ compiler flags
- CPP C preprocessor
-
-Use these variables to override the choices made by `configure' or to help
-it to find libraries and programs with nonstandard names/locations.
-
-Report bugs to <Hans.Boehm@hp.com>.
-_ACEOF
-fi
-
-if test "$ac_init_help" = "recursive"; then
- # If there are subdirs, report their specific --help.
- ac_popdir=`pwd`
- for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
- test -d $ac_dir || continue
- ac_builddir=.
-
-if test "$ac_dir" != .; then
- ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
- # A "../" for each directory in $ac_dir_suffix.
- ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
-else
- ac_dir_suffix= ac_top_builddir=
-fi
-
-case $srcdir in
- .) # No --srcdir option. We are building in place.
- ac_srcdir=.
- if test -z "$ac_top_builddir"; then
- ac_top_srcdir=.
- else
- ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
- fi ;;
- [\\/]* | ?:[\\/]* ) # Absolute path.
- ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir ;;
- *) # Relative path.
- ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_builddir$srcdir ;;
-esac
-# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
-# absolute.
-ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
-ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd`
-ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
-ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
-
- cd $ac_dir
- # Check for guested configure; otherwise get Cygnus style configure.
- if test -f $ac_srcdir/configure.gnu; then
- echo
- $SHELL $ac_srcdir/configure.gnu --help=recursive
- elif test -f $ac_srcdir/configure; then
- echo
- $SHELL $ac_srcdir/configure --help=recursive
- elif test -f $ac_srcdir/configure.ac ||
- test -f $ac_srcdir/configure.in; then
- echo
- $ac_configure --help
- else
- echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
- fi
- cd $ac_popdir
- done
-fi
-
-test -n "$ac_init_help" && exit 0
-if $ac_init_version; then
- cat <<\_ACEOF
-gc configure 6.3
-generated by GNU Autoconf 2.53
-
-Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
-Free Software Foundation, Inc.
-This configure script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it.
-_ACEOF
- exit 0
-fi
-exec 5>config.log
-cat >&5 <<_ACEOF
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-
-It was created by gc $as_me 6.3, which was
-generated by GNU Autoconf 2.53. Invocation command line was
-
- $ $0 $@
-
-_ACEOF
-{
-cat <<_ASUNAME
-## --------- ##
-## Platform. ##
-## --------- ##
-
-hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
-
-/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
-/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
-/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
-
-_ASUNAME
-
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- echo "PATH: $as_dir"
-done
-
-} >&5
-
-cat >&5 <<_ACEOF
-
-
-## ----------- ##
-## Core tests. ##
-## ----------- ##
-
-_ACEOF
-
-
-# Keep a trace of the command line.
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Also quote any args containing shell meta-characters.
-ac_configure_args=
-ac_sep=
-for ac_arg
-do
- case $ac_arg in
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c | -n ) continue ;;
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
- continue ;;
- *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
- ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- case " $ac_configure_args " in
- *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
- *) ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
- ac_sep=" " ;;
- esac
- # Get rid of the leading space.
-done
-
-# When interrupted or exit'd, cleanup temporary files, and complete
-# config.log. We remove comments because anyway the quotes in there
-# would cause problems or look ugly.
-# WARNING: Be sure not to use single quotes in there, as some shells,
-# such as our DU 5.0 friend, will then `close' the trap.
-trap 'exit_status=$?
- # Save into config.log some information that might help in debugging.
- {
- echo
- cat <<\_ASBOX
-## ---------------- ##
-## Cache variables. ##
-## ---------------- ##
-_ASBOX
- echo
- # The following way of writing the cache mishandles newlines in values,
-{
- (set) 2>&1 |
- case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
- *ac_space=\ *)
- sed -n \
- "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
- ;;
- *)
- sed -n \
- "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
- ;;
- esac;
-}
- echo
- if test -s confdefs.h; then
- cat <<\_ASBOX
-## ----------- ##
-## confdefs.h. ##
-## ----------- ##
-_ASBOX
- echo
- sed "/^$/d" confdefs.h
- echo
- fi
- test "$ac_signal" != 0 &&
- echo "$as_me: caught signal $ac_signal"
- echo "$as_me: exit $exit_status"
- } >&5
- rm -f core core.* *.core &&
- rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
- exit $exit_status
- ' 0
-for ac_signal in 1 2 13 15; do
- trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
-done
-ac_signal=0
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -rf conftest* confdefs.h
-# AIX cpp loses on an empty file, so make sure it contains at least a newline.
-echo >confdefs.h
-
-# Predefined preprocessor variables.
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_NAME "$PACKAGE_NAME"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_VERSION "$PACKAGE_VERSION"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_STRING "$PACKAGE_STRING"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
-_ACEOF
-
-
-# Let the site file select an alternate cache file if it wants to.
-# Prefer explicitly selected file to automatically selected ones.
-if test -z "$CONFIG_SITE"; then
- if test "x$prefix" != xNONE; then
- CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
- else
- CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
- fi
-fi
-for ac_site_file in $CONFIG_SITE; do
- if test -r "$ac_site_file"; then
- { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
-echo "$as_me: loading site script $ac_site_file" >&6;}
- sed 's/^/| /' "$ac_site_file" >&5
- . "$ac_site_file"
- fi
-done
-
-if test -r "$cache_file"; then
- # Some versions of bash will fail to source /dev/null (special
- # files actually), so we avoid doing that.
- if test -f "$cache_file"; then
- { echo "$as_me:$LINENO: loading cache $cache_file" >&5
-echo "$as_me: loading cache $cache_file" >&6;}
- case $cache_file in
- [\\/]* | ?:[\\/]* ) . $cache_file;;
- *) . ./$cache_file;;
- esac
- fi
-else
- { echo "$as_me:$LINENO: creating cache $cache_file" >&5
-echo "$as_me: creating cache $cache_file" >&6;}
- >$cache_file
-fi
-
-# Check that the precious variables saved in the cache have kept the same
-# value.
-ac_cache_corrupted=false
-for ac_var in `(set) 2>&1 |
- sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
- eval ac_old_set=\$ac_cv_env_${ac_var}_set
- eval ac_new_set=\$ac_env_${ac_var}_set
- eval ac_old_val="\$ac_cv_env_${ac_var}_value"
- eval ac_new_val="\$ac_env_${ac_var}_value"
- case $ac_old_set,$ac_new_set in
- set,)
- { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,set)
- { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
-echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,);;
- *)
- if test "x$ac_old_val" != "x$ac_new_val"; then
- { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
-echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
- { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
-echo "$as_me: former value: $ac_old_val" >&2;}
- { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
-echo "$as_me: current value: $ac_new_val" >&2;}
- ac_cache_corrupted=:
- fi;;
- esac
- # Pass precious variables to config.status.
- if test "$ac_new_set" = set; then
- case $ac_new_val in
- *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
- ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
- *) ac_arg=$ac_var=$ac_new_val ;;
- esac
- case " $ac_configure_args " in
- *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
- *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
- esac
- fi
-done
-if $ac_cache_corrupted; then
- { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
-echo "$as_me: error: changes in the environment can compromise the build" >&2;}
- { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
-echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
- { (exit 1); exit 1; }; }
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
-
-ac_aux_dir=
-for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
- if test -f $ac_dir/install-sh; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install-sh -c"
- break
- elif test -f $ac_dir/install.sh; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install.sh -c"
- break
- elif test -f $ac_dir/shtool; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/shtool install -c"
- break
- fi
-done
-if test -z "$ac_aux_dir"; then
- { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
-echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
- { (exit 1); exit 1; }; }
-fi
-ac_config_guess="$SHELL $ac_aux_dir/config.guess"
-ac_config_sub="$SHELL $ac_aux_dir/config.sub"
-ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
-
-# Make sure we can run config.sub.
-$ac_config_sub sun4 >/dev/null 2>&1 ||
- { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
-echo "$as_me: error: cannot run $ac_config_sub" >&2;}
- { (exit 1); exit 1; }; }
-
-echo "$as_me:$LINENO: checking build system type" >&5
-echo $ECHO_N "checking build system type... $ECHO_C" >&6
-if test "${ac_cv_build+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_cv_build_alias=$build_alias
-test -z "$ac_cv_build_alias" &&
- ac_cv_build_alias=`$ac_config_guess`
-test -z "$ac_cv_build_alias" &&
- { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
-echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
- { (exit 1); exit 1; }; }
-ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
- { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
-echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
- { (exit 1); exit 1; }; }
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_build" >&5
-echo "${ECHO_T}$ac_cv_build" >&6
-build=$ac_cv_build
-build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-
-
-echo "$as_me:$LINENO: checking host system type" >&5
-echo $ECHO_N "checking host system type... $ECHO_C" >&6
-if test "${ac_cv_host+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_cv_host_alias=$host_alias
-test -z "$ac_cv_host_alias" &&
- ac_cv_host_alias=$ac_cv_build_alias
-ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
- { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
-echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
- { (exit 1); exit 1; }; }
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_host" >&5
-echo "${ECHO_T}$ac_cv_host" >&6
-host=$ac_cv_host
-host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-
-
-echo "$as_me:$LINENO: checking target system type" >&5
-echo $ECHO_N "checking target system type... $ECHO_C" >&6
-if test "${ac_cv_target+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_cv_target_alias=$target_alias
-test "x$ac_cv_target_alias" = "x" &&
- ac_cv_target_alias=$ac_cv_host_alias
-ac_cv_target=`$ac_config_sub $ac_cv_target_alias` ||
- { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5
-echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;}
- { (exit 1); exit 1; }; }
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_target" >&5
-echo "${ECHO_T}$ac_cv_target" >&6
-target=$ac_cv_target
-target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-
-
-# The aliases save the names the user supplied, while $host etc.
-# will get canonicalized.
-test -n "$target_alias" &&
- test "$program_prefix$program_suffix$program_transform_name" = \
- NONENONEs,x,x, &&
- program_prefix=${target_alias}-
-
-
-
- echo "$as_me:$LINENO: checking GC version numbers" >&5
-echo $ECHO_N "checking GC version numbers... $ECHO_C" >&6
- GC_VERSION_MAJOR=`echo $PACKAGE_VERSION | sed 's/^\([0-9][0-9]*\)[.].*$/\1/g'`
- GC_VERSION_MINOR=`echo $PACKAGE_VERSION | sed 's/^[^.]*[.]\([0-9][0-9]*\).*$/\1/g'`
- GC_ALPHA_VERSION=`echo $PACKAGE_VERSION | sed 's/^[^.]*[.][0-9]*//'`
-
- case "$GC_ALPHA_VERSION" in
- alpha*)
- GC_ALPHA_VERSION=`echo $GC_ALPHA_VERSION \
- | sed 's/alpha\([0-9][0-9]*\)/\1/'` ;;
- *) GC_ALPHA_MAJOR='' ;;
- esac
-
- if test :$GC_VERSION_MAJOR: = :: \
- -o :$GC_VERSION_MINOR: = :: ;
- then
- echo "$as_me:$LINENO: result: invalid" >&5
-echo "${ECHO_T}invalid" >&6
- { { echo "$as_me:$LINENO: error: nonconforming PACKAGE_VERSION='$PACKAGE_VERSION'" >&5
-echo "$as_me: error: nonconforming PACKAGE_VERSION='$PACKAGE_VERSION'" >&2;}
- { (exit 1); exit 1; }; }
- fi
-
- cat >>confdefs.h <<_ACEOF
-#define GC_VERSION_MAJOR $GC_VERSION_MAJOR
-_ACEOF
-
- cat >>confdefs.h <<_ACEOF
-#define GC_VERSION_MINOR $GC_VERSION_MINOR
-_ACEOF
-
- if test :$GC_ALPHA_VERSION: != :: ; then
- cat >>confdefs.h <<_ACEOF
-#define GC_ALPHA_VERSION $GC_ALPHA_VERSION
-_ACEOF
-
- fi
- echo "$as_me:$LINENO: result: major=$GC_VERSION_MAJOR minor=$GC_VERSION_MINOR \
-${GC_ALPHA_VERSION:+alpha=}$GC_ALPHA_VERSION" >&5
-echo "${ECHO_T}major=$GC_VERSION_MAJOR minor=$GC_VERSION_MINOR \
-${GC_ALPHA_VERSION:+alpha=}$GC_ALPHA_VERSION" >&6
-
-am__api_version="1.6"
-# Find a good install program. We prefer a C program (faster),
-# so one script is as good as another. But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AmigaOS /C/install, which installs bootblocks on floppy discs
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# ./install, which can be erroneously created by make from ./install.sh.
-echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
-echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
-if test -z "$INSTALL"; then
-if test "${ac_cv_path_install+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in
- ./ | .// | /cC/* | \
- /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
- /usr/ucb/* ) ;;
- *)
- # OSF1 and SCO ODT 3.0 have their own names for install.
- # Don't use installbsd from OSF since it installs stuff as root
- # by default.
- for ac_prog in ginstall scoinst install; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
- if test $ac_prog = install &&
- grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
- # AIX install. It has an incompatible calling convention.
- :
- elif test $ac_prog = install &&
- grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
- # program-specific install script used by HP pwplus--don't use.
- :
- else
- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
- break 3
- fi
- fi
- done
- done
- ;;
-esac
-done
-
-
-fi
- if test "${ac_cv_path_install+set}" = set; then
- INSTALL=$ac_cv_path_install
- else
- # As a last resort, use the slow shell script. We don't cache a
- # path for INSTALL within a source directory, because that will
- # break other packages using the cache if that directory is
- # removed, or if the path is relative.
- INSTALL=$ac_install_sh
- fi
-fi
-echo "$as_me:$LINENO: result: $INSTALL" >&5
-echo "${ECHO_T}$INSTALL" >&6
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
-
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-
-echo "$as_me:$LINENO: checking whether build environment is sane" >&5
-echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6
-# Just in case
-sleep 1
-echo timestamp > conftest.file
-# Do `set' in a subshell so we don't clobber the current shell's
-# arguments. Must try -L first in case configure is actually a
-# symlink; some systems play weird games with the mod time of symlinks
-# (eg FreeBSD returns the mod time of the symlink's containing
-# directory).
-if (
- set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
- if test "$*" = "X"; then
- # -L didn't work.
- set X `ls -t $srcdir/configure conftest.file`
- fi
- rm -f conftest.file
- if test "$*" != "X $srcdir/configure conftest.file" \
- && test "$*" != "X conftest.file $srcdir/configure"; then
-
- # If neither matched, then we have a broken ls. This can happen
- # if, for instance, CONFIG_SHELL is bash and it inherits a
- # broken ls alias from the environment. This has actually
- # happened. Such a system could not be considered "sane".
- { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken
-alias in your environment" >&5
-echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken
-alias in your environment" >&2;}
- { (exit 1); exit 1; }; }
- fi
-
- test "$2" = conftest.file
- )
-then
- # Ok.
- :
-else
- { { echo "$as_me:$LINENO: error: newly created file is older than distributed files!
-Check your system clock" >&5
-echo "$as_me: error: newly created file is older than distributed files!
-Check your system clock" >&2;}
- { (exit 1); exit 1; }; }
-fi
-echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
-test "$program_prefix" != NONE &&
- program_transform_name="s,^,$program_prefix,;$program_transform_name"
-# Use a double $ so make ignores it.
-test "$program_suffix" != NONE &&
- program_transform_name="s,\$,$program_suffix,;$program_transform_name"
-# Double any \ or $. echo might interpret backslashes.
-# By default was `s,x,x', remove it if useless.
-cat <<\_ACEOF >conftest.sed
-s/[\\$]/&&/g;s/;s,x,x,$//
-_ACEOF
-program_transform_name=`echo $program_transform_name | sed -f conftest.sed`
-rm conftest.sed
-
-
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
-
-test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
-# Use eval to expand $SHELL
-if eval "$MISSING --run true"; then
- am_missing_run="$MISSING --run "
-else
- am_missing_run=
- { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
-echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
-fi
-
-for ac_prog in gawk mawk nawk awk
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_AWK+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$AWK"; then
- ac_cv_prog_AWK="$AWK" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_AWK="$ac_prog"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-AWK=$ac_cv_prog_AWK
-if test -n "$AWK"; then
- echo "$as_me:$LINENO: result: $AWK" >&5
-echo "${ECHO_T}$AWK" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- test -n "$AWK" && break
-done
-
-echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5
-echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6
-set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'`
-if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.make <<\_ACEOF
-all:
- @echo 'ac_maketemp="${MAKE}"'
-_ACEOF
-# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
-eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
-if test -n "$ac_maketemp"; then
- eval ac_cv_prog_make_${ac_make}_set=yes
-else
- eval ac_cv_prog_make_${ac_make}_set=no
-fi
-rm -f conftest.make
-fi
-if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
- SET_MAKE=
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
- SET_MAKE="MAKE=${MAKE-make}"
-fi
-
- # test to see if srcdir already configured
-if test "`cd $srcdir && pwd`" != "`pwd`" &&
- test -f $srcdir/config.status; then
- { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
-echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
- { (exit 1); exit 1; }; }
-fi
-
-# Define the identity of the package.
- PACKAGE=gc
- VERSION=6.3
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE "$PACKAGE"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define VERSION "$VERSION"
-_ACEOF
-
-# Some tools Automake needs.
-
-ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
-
-
-AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
-
-
-AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
-
-
-AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
-
-
-MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
-
-
-AMTAR=${AMTAR-"${am_missing_run}tar"}
-
-install_sh=${install_sh-"$am_aux_dir/install-sh"}
-
-# Installed binaries are usually stripped using `strip' when the user
-# run `make install-strip'. However `strip' might not be the right
-# tool to use in cross-compilation environments, therefore Automake
-# will honor the `STRIP' environment variable to overrule this program.
-if test "$cross_compiling" != no; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
-set dummy ${ac_tool_prefix}strip; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_STRIP+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$STRIP"; then
- ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_STRIP="${ac_tool_prefix}strip"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-STRIP=$ac_cv_prog_STRIP
-if test -n "$STRIP"; then
- echo "$as_me:$LINENO: result: $STRIP" >&5
-echo "${ECHO_T}$STRIP" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_STRIP"; then
- ac_ct_STRIP=$STRIP
- # Extract the first word of "strip", so it can be a program name with args.
-set dummy strip; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_STRIP"; then
- ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_STRIP="strip"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
- test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
-fi
-fi
-ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
-if test -n "$ac_ct_STRIP"; then
- echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
-echo "${ECHO_T}$ac_ct_STRIP" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- STRIP=$ac_ct_STRIP
-else
- STRIP="$ac_cv_prog_STRIP"
-fi
-
-fi
-INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
-
-# We need awk for the "check" target. The system "awk" is bad on
-# some platforms.
-
-
-
-
-
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}gcc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="gcc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- CC=$ac_ct_CC
-else
- CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}cc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="cc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- CC=$ac_ct_CC
-else
- CC="$ac_cv_prog_CC"
-fi
-
-fi
-if test -z "$CC"; then
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
- ac_prog_rejected=yes
- continue
- fi
- ac_cv_prog_CC="cc"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-if test $ac_prog_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $ac_cv_prog_CC
- shift
- if test $# != 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same basename, so the bogon will be chosen
- # first if we set CC to just the basename; use the full file name.
- shift
- set dummy "$as_dir/$ac_word" ${1+"$@"}
- shift
- ac_cv_prog_CC="$@"
- fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- for ac_prog in cl
- do
- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- test -n "$CC" && break
- done
-fi
-if test -z "$CC"; then
- ac_ct_CC=$CC
- for ac_prog in cl
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="$ac_prog"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- test -n "$ac_ct_CC" && break
-done
-
- CC=$ac_ct_CC
-fi
-
-fi
-
-
-test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH" >&5
-echo "$as_me: error: no acceptable C compiler found in \$PATH" >&2;}
- { (exit 1); exit 1; }; }
-
-# Provide some information about the compiler.
-echo "$as_me:$LINENO:" \
- "checking for C compiler version" >&5
-ac_compiler=`set X $ac_compile; echo $2`
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
- (eval $ac_compiler --version </dev/null >&5) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
- (eval $ac_compiler -v </dev/null >&5) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
- (eval $ac_compiler -V </dev/null >&5) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
-
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.exe"
-# Try to create an executable without -o first, disregard a.out.
-# It will help us diagnose broken compilers, and finding out an intuition
-# of exeext.
-echo "$as_me:$LINENO: checking for C compiler default output" >&5
-echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
-ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
- (eval $ac_link_default) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; then
- # Find the output, starting from the most likely. This scheme is
-# not robust to junk in `.', hence go to wildcards (a.*) only as a last
-# resort.
-
-# Be careful to initialize this variable, since it used to be cached.
-# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
-ac_cv_exeext=
-for ac_file in `ls a_out.exe a.exe conftest.exe 2>/dev/null;
- ls a.out conftest 2>/dev/null;
- ls a.* conftest.* 2>/dev/null`; do
- case $ac_file in
- *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb | *.xSYM ) ;;
- a.out ) # We found the default executable, but exeext='' is most
- # certainly right.
- break;;
- *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- # FIXME: I believe we export ac_cv_exeext for Libtool --akim.
- export ac_cv_exeext
- break;;
- * ) break;;
- esac
-done
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-{ { echo "$as_me:$LINENO: error: C compiler cannot create executables" >&5
-echo "$as_me: error: C compiler cannot create executables" >&2;}
- { (exit 77); exit 77; }; }
-fi
-
-ac_exeext=$ac_cv_exeext
-echo "$as_me:$LINENO: result: $ac_file" >&5
-echo "${ECHO_T}$ac_file" >&6
-
-# Check the compiler produces executables we can run. If not, either
-# the compiler is broken, or we cross compile.
-echo "$as_me:$LINENO: checking whether the C compiler works" >&5
-echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
-# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
-# If not cross compiling, check that we can run a simple program.
-if test "$cross_compiling" != yes; then
- if { ac_try='./$ac_file'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- cross_compiling=no
- else
- if test "$cross_compiling" = maybe; then
- cross_compiling=yes
- else
- { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
-If you meant to cross compile, use \`--host'." >&5
-echo "$as_me: error: cannot run C compiled programs.
-If you meant to cross compile, use \`--host'." >&2;}
- { (exit 1); exit 1; }; }
- fi
- fi
-fi
-echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
-
-rm -f a.out a.exe conftest$ac_cv_exeext
-ac_clean_files=$ac_clean_files_save
-# Check the compiler produces executables we can run. If not, either
-# the compiler is broken, or we cross compile.
-echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
-echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
-echo "$as_me:$LINENO: result: $cross_compiling" >&5
-echo "${ECHO_T}$cross_compiling" >&6
-
-echo "$as_me:$LINENO: checking for suffix of executables" >&5
-echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; then
- # If both `conftest.exe' and `conftest' are `present' (well, observable)
-# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
-# work properly (i.e., refer to `conftest.exe'), while it won't with
-# `rm'.
-for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do
- case $ac_file in
- *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;;
- *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- export ac_cv_exeext
- break;;
- * ) break;;
- esac
-done
-else
- { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link" >&5
-echo "$as_me: error: cannot compute suffix of executables: cannot compile and link" >&2;}
- { (exit 1); exit 1; }; }
-fi
-
-rm -f conftest$ac_cv_exeext
-echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
-echo "${ECHO_T}$ac_cv_exeext" >&6
-
-rm -f conftest.$ac_ext
-EXEEXT=$ac_cv_exeext
-ac_exeext=$EXEEXT
-echo "$as_me:$LINENO: checking for suffix of object files" >&5
-echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
-if test "${ac_cv_objext+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.o conftest.obj
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; then
- for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;;
- *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
- break;;
- esac
-done
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile" >&5
-echo "$as_me: error: cannot compute suffix of object files: cannot compile" >&2;}
- { (exit 1); exit 1; }; }
-fi
-
-rm -f conftest.$ac_cv_objext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
-echo "${ECHO_T}$ac_cv_objext" >&6
-OBJEXT=$ac_cv_objext
-ac_objext=$OBJEXT
-echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
-echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
-if test "${ac_cv_c_compiler_gnu+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_compiler_gnu=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_compiler_gnu=no
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
-echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
-GCC=`test $ac_compiler_gnu = yes && echo yes`
-ac_test_CFLAGS=${CFLAGS+set}
-ac_save_CFLAGS=$CFLAGS
-CFLAGS="-g"
-echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
-echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
-if test "${ac_cv_prog_cc_g+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_prog_cc_g=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_prog_cc_g=no
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
-echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
-if test "$ac_test_CFLAGS" = set; then
- CFLAGS=$ac_save_CFLAGS
-elif test $ac_cv_prog_cc_g = yes; then
- if test "$GCC" = yes; then
- CFLAGS="-g -O2"
- else
- CFLAGS="-g"
- fi
-else
- if test "$GCC" = yes; then
- CFLAGS="-O2"
- else
- CFLAGS=
- fi
-fi
-# Some people use a C++ compiler to compile C. Since we use `exit',
-# in C++ we need to declare it. In case someone uses the same compiler
-# for both compiling C and C++ we need to have the C++ compiler decide
-# the declaration of exit, since it's the most demanding environment.
-cat >conftest.$ac_ext <<_ACEOF
-#ifndef __cplusplus
- choke me
-#endif
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- for ac_declaration in \
- ''\
- '#include <stdlib.h>' \
- 'extern "C" void std::exit (int) throw (); using std::exit;' \
- 'extern "C" void std::exit (int); using std::exit;' \
- 'extern "C" void exit (int) throw ();' \
- 'extern "C" void exit (int);' \
- 'void exit (int);'
-do
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <stdlib.h>
-$ac_declaration
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-exit (42);
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- :
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-continue
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-$ac_declaration
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-exit (42);
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- break
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-done
-rm -f conftest*
-if test -n "$ac_declaration"; then
- echo '#ifdef __cplusplus' >>confdefs.h
- echo $ac_declaration >>confdefs.h
- echo '#endif' >>confdefs.h
-fi
-
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-rm -f .deps 2>/dev/null
-mkdir .deps 2>/dev/null
-if test -d .deps; then
- DEPDIR=.deps
-else
- # MS-DOS does not allow filenames that begin with a dot.
- DEPDIR=_deps
-fi
-rmdir .deps 2>/dev/null
-
-
-ac_config_commands="$ac_config_commands depfiles"
-
-
-am_make=${MAKE-make}
-cat > confinc << 'END'
-doit:
- @echo done
-END
-# If we don't find an include directive, just comment out the code.
-echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
-echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6
-am__include="#"
-am__quote=
-_am_result=none
-# First try GNU make style include.
-echo "include confinc" > confmf
-# We grep out `Entering directory' and `Leaving directory'
-# messages which can occur if `w' ends up in MAKEFLAGS.
-# In particular we don't look at `^make:' because GNU make might
-# be invoked under some other name (usually "gmake"), in which
-# case it prints its new name instead of `make'.
-if test "`$am_make -s -f confmf 2> /dev/null | fgrep -v 'ing directory'`" = "done"; then
- am__include=include
- am__quote=
- _am_result=GNU
-fi
-# Now try BSD make style include.
-if test "$am__include" = "#"; then
- echo '.include "confinc"' > confmf
- if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
- am__include=.include
- am__quote="\""
- _am_result=BSD
- fi
-fi
-
-
-echo "$as_me:$LINENO: result: $_am_result" >&5
-echo "${ECHO_T}$_am_result" >&6
-rm -f confinc confmf
-
-# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given.
-if test "${enable_dependency_tracking+set}" = set; then
- enableval="$enable_dependency_tracking"
-
-fi;
-if test "x$enable_dependency_tracking" != xno; then
- am_depcomp="$ac_aux_dir/depcomp"
- AMDEPBACKSLASH='\'
-fi
-
-
-if test "x$enable_dependency_tracking" != xno; then
- AMDEP_TRUE=
- AMDEP_FALSE='#'
-else
- AMDEP_TRUE='#'
- AMDEP_FALSE=
-fi
-
-
-
-
-depcc="$CC" am_compiler_list=
-
-echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
-echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
-if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
- # We make a subdir and do the tests there. Otherwise we can end up
- # making bogus files that we don't know about and never remove. For
- # instance it was reported that on HP-UX the gcc test will end up
- # making a dummy file named `D' -- because `-MD' means `put the output
- # in D'.
- mkdir conftest.dir
- # Copy depcomp to subdir because otherwise we won't find it if we're
- # using a relative directory.
- cp "$am_depcomp" conftest.dir
- cd conftest.dir
-
- am_cv_CC_dependencies_compiler_type=none
- if test "$am_compiler_list" = ""; then
- am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
- fi
- for depmode in $am_compiler_list; do
- # We need to recreate these files for each test, as the compiler may
- # overwrite some of them when testing with obscure command lines.
- # This happens at least with the AIX C compiler.
- echo '#include "conftest.h"' > conftest.c
- echo 'int i;' > conftest.h
- echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf
-
- case $depmode in
- nosideeffect)
- # after this tag, mechanisms are not by side-effect, so they'll
- # only be used when explicitly requested
- if test "x$enable_dependency_tracking" = xyes; then
- continue
- else
- break
- fi
- ;;
- none) break ;;
- esac
- # We check with `-c' and `-o' for the sake of the "dashmstdout"
- # mode. It turns out that the SunPro C++ compiler does not properly
- # handle `-M -o', and we need to detect this.
- if depmode=$depmode \
- source=conftest.c object=conftest.o \
- depfile=conftest.Po tmpdepfile=conftest.TPo \
- $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 &&
- grep conftest.h conftest.Po > /dev/null 2>&1 &&
- ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
- am_cv_CC_dependencies_compiler_type=$depmode
- break
- fi
- done
-
- cd ..
- rm -rf conftest.dir
-else
- am_cv_CC_dependencies_compiler_type=none
-fi
-
-fi
-echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
-echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6
-CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
-
-
-ac_ext=cc
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-if test -n "$ac_tool_prefix"; then
- for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
- do
- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CXX+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$CXX"; then
- ac_cv_prog_CXX="$CXX" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-CXX=$ac_cv_prog_CXX
-if test -n "$CXX"; then
- echo "$as_me:$LINENO: result: $CXX" >&5
-echo "${ECHO_T}$CXX" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- test -n "$CXX" && break
- done
-fi
-if test -z "$CXX"; then
- ac_ct_CXX=$CXX
- for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_CXX"; then
- ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CXX="$ac_prog"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
-if test -n "$ac_ct_CXX"; then
- echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
-echo "${ECHO_T}$ac_ct_CXX" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- test -n "$ac_ct_CXX" && break
-done
-test -n "$ac_ct_CXX" || ac_ct_CXX="g++"
-
- CXX=$ac_ct_CXX
-fi
-
-
-# Provide some information about the compiler.
-echo "$as_me:$LINENO:" \
- "checking for C++ compiler version" >&5
-ac_compiler=`set X $ac_compile; echo $2`
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
- (eval $ac_compiler --version </dev/null >&5) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
- (eval $ac_compiler -v </dev/null >&5) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
- (eval $ac_compiler -V </dev/null >&5) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
-
-echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
-echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6
-if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_compiler_gnu=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_compiler_gnu=no
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
-echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6
-GXX=`test $ac_compiler_gnu = yes && echo yes`
-ac_test_CXXFLAGS=${CXXFLAGS+set}
-ac_save_CXXFLAGS=$CXXFLAGS
-CXXFLAGS="-g"
-echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
-echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6
-if test "${ac_cv_prog_cxx_g+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_prog_cxx_g=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_prog_cxx_g=no
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
-echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6
-if test "$ac_test_CXXFLAGS" = set; then
- CXXFLAGS=$ac_save_CXXFLAGS
-elif test $ac_cv_prog_cxx_g = yes; then
- if test "$GXX" = yes; then
- CXXFLAGS="-g -O2"
- else
- CXXFLAGS="-g"
- fi
-else
- if test "$GXX" = yes; then
- CXXFLAGS="-O2"
- else
- CXXFLAGS=
- fi
-fi
-for ac_declaration in \
- ''\
- '#include <stdlib.h>' \
- 'extern "C" void std::exit (int) throw (); using std::exit;' \
- 'extern "C" void std::exit (int); using std::exit;' \
- 'extern "C" void exit (int) throw ();' \
- 'extern "C" void exit (int);' \
- 'void exit (int);'
-do
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <stdlib.h>
-$ac_declaration
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-exit (42);
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- :
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-continue
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-$ac_declaration
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-exit (42);
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- break
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-done
-rm -f conftest*
-if test -n "$ac_declaration"; then
- echo '#ifdef __cplusplus' >>confdefs.h
- echo $ac_declaration >>confdefs.h
- echo '#endif' >>confdefs.h
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-depcc="$CXX" am_compiler_list=
-
-echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
-echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6
-if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
- # We make a subdir and do the tests there. Otherwise we can end up
- # making bogus files that we don't know about and never remove. For
- # instance it was reported that on HP-UX the gcc test will end up
- # making a dummy file named `D' -- because `-MD' means `put the output
- # in D'.
- mkdir conftest.dir
- # Copy depcomp to subdir because otherwise we won't find it if we're
- # using a relative directory.
- cp "$am_depcomp" conftest.dir
- cd conftest.dir
-
- am_cv_CXX_dependencies_compiler_type=none
- if test "$am_compiler_list" = ""; then
- am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
- fi
- for depmode in $am_compiler_list; do
- # We need to recreate these files for each test, as the compiler may
- # overwrite some of them when testing with obscure command lines.
- # This happens at least with the AIX C compiler.
- echo '#include "conftest.h"' > conftest.c
- echo 'int i;' > conftest.h
- echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf
-
- case $depmode in
- nosideeffect)
- # after this tag, mechanisms are not by side-effect, so they'll
- # only be used when explicitly requested
- if test "x$enable_dependency_tracking" = xyes; then
- continue
- else
- break
- fi
- ;;
- none) break ;;
- esac
- # We check with `-c' and `-o' for the sake of the "dashmstdout"
- # mode. It turns out that the SunPro C++ compiler does not properly
- # handle `-M -o', and we need to detect this.
- if depmode=$depmode \
- source=conftest.c object=conftest.o \
- depfile=conftest.Po tmpdepfile=conftest.TPo \
- $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 &&
- grep conftest.h conftest.Po > /dev/null 2>&1 &&
- ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
- am_cv_CXX_dependencies_compiler_type=$depmode
- break
- fi
- done
-
- cd ..
- rm -rf conftest.dir
-else
- am_cv_CXX_dependencies_compiler_type=none
-fi
-
-fi
-echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5
-echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6
-CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
-
-
-
-# By default we simply use the C compiler to build assembly code.
-
-: ${CCAS='$(CC)'}
-# Set ASFLAGS if not already set.
-: ${CCASFLAGS='$(CFLAGS)'}
-
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ar; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_AR+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$AR"; then
- ac_cv_prog_AR="$AR" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_AR="${ac_tool_prefix}ar"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-AR=$ac_cv_prog_AR
-if test -n "$AR"; then
- echo "$as_me:$LINENO: result: $AR" >&5
-echo "${ECHO_T}$AR" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_AR"; then
- ac_ct_AR=$AR
- # Extract the first word of "ar", so it can be a program name with args.
-set dummy ar; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_AR"; then
- ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_AR="ar"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-ac_ct_AR=$ac_cv_prog_ac_ct_AR
-if test -n "$ac_ct_AR"; then
- echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
-echo "${ECHO_T}$ac_ct_AR" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- AR=$ac_ct_AR
-else
- AR="$ac_cv_prog_AR"
-fi
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_RANLIB+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
- echo "$as_me:$LINENO: result: $RANLIB" >&5
-echo "${ECHO_T}$RANLIB" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
- ac_ct_RANLIB=$RANLIB
- # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_RANLIB"; then
- ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_RANLIB="ranlib"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
- test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
-fi
-fi
-ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
- echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
-echo "${ECHO_T}$ac_ct_RANLIB" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- RANLIB=$ac_ct_RANLIB
-else
- RANLIB="$ac_cv_prog_RANLIB"
-fi
- # :)
-
-# Find a good install program. We prefer a C program (faster),
-# so one script is as good as another. But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AmigaOS /C/install, which installs bootblocks on floppy discs
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# ./install, which can be erroneously created by make from ./install.sh.
-echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
-echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
-if test -z "$INSTALL"; then
-if test "${ac_cv_path_install+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in
- ./ | .// | /cC/* | \
- /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
- /usr/ucb/* ) ;;
- *)
- # OSF1 and SCO ODT 3.0 have their own names for install.
- # Don't use installbsd from OSF since it installs stuff as root
- # by default.
- for ac_prog in ginstall scoinst install; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
- if test $ac_prog = install &&
- grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
- # AIX install. It has an incompatible calling convention.
- :
- elif test $ac_prog = install &&
- grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
- # program-specific install script used by HP pwplus--don't use.
- :
- else
- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
- break 3
- fi
- fi
- done
- done
- ;;
-esac
-done
-
-
-fi
- if test "${ac_cv_path_install+set}" = set; then
- INSTALL=$ac_cv_path_install
- else
- # As a last resort, use the slow shell script. We don't cache a
- # path for INSTALL within a source directory, because that will
- # break other packages using the cache if that directory is
- # removed, or if the path is relative.
- INSTALL=$ac_install_sh
- fi
-fi
-echo "$as_me:$LINENO: result: $INSTALL" >&5
-echo "${ECHO_T}$INSTALL" >&6
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
-
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-
-
-echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5
-echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6
- # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
-if test "${enable_maintainer_mode+set}" = set; then
- enableval="$enable_maintainer_mode"
- USE_MAINTAINER_MODE=$enableval
-else
- USE_MAINTAINER_MODE=no
-fi;
- echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5
-echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6
-
-
-if test $USE_MAINTAINER_MODE = yes; then
- MAINTAINER_MODE_TRUE=
- MAINTAINER_MODE_FALSE='#'
-else
- MAINTAINER_MODE_TRUE='#'
- MAINTAINER_MODE_FALSE=
-fi
-
- MAINT=$MAINTAINER_MODE_TRUE
-
-
-
-. ${srcdir}/configure.host
-
-GC_CFLAGS=${gc_cflags}
-
-
-# Check whether --enable-threads or --disable-threads was given.
-if test "${enable_threads+set}" = set; then
- enableval="$enable_threads"
- THREADS=$enableval
-else
- echo "$as_me:$LINENO: checking for thread model used by GCC" >&5
-echo $ECHO_N "checking for thread model used by GCC... $ECHO_C" >&6
- THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
- if test -z "$THREADS"; then
- THREADS=no
- fi
- echo "$as_me:$LINENO: result: $THREADS" >&5
-echo "${ECHO_T}$THREADS" >&6
-fi;
-
-# Check whether --enable-parallel-mark or --disable-parallel-mark was given.
-if test "${enable_parallel_mark+set}" = set; then
- enableval="$enable_parallel_mark"
- case "$THREADS" in
- no | none | single)
- { { echo "$as_me:$LINENO: error: Parallel mark requires --enable-threads=x spec" >&5
-echo "$as_me: error: Parallel mark requires --enable-threads=x spec" >&2;}
- { (exit 1); exit 1; }; }
- ;;
- esac
-
-fi;
-
-# Check whether --enable-cplusplus or --disable-cplusplus was given.
-if test "${enable_cplusplus+set}" = set; then
- enableval="$enable_cplusplus"
-
-fi;
-
-INCLUDES=-I${srcdir}/include
-THREADLIBS=
-case "$THREADS" in
- no | none | single)
- THREADS=none
- ;;
- posix | pthreads)
- THREADS=posix
- THREADLIBS=-lpthread
- case "$host" in
- x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
- cat >>confdefs.h <<\_ACEOF
-#define GC_LINUX_THREADS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define _REENTRANT 1
-_ACEOF
-
- if test "${enable_parallel_mark}" = yes; then
- cat >>confdefs.h <<\_ACEOF
-#define PARALLEL_MARK 1
-_ACEOF
-
- fi
- cat >>confdefs.h <<\_ACEOF
-#define THREAD_LOCAL_ALLOC 1
-_ACEOF
-
- ;;
- *-*-linux*)
- cat >>confdefs.h <<\_ACEOF
-#define GC_LINUX_THREADS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define _REENTRANT 1
-_ACEOF
-
- ;;
- *-*-aix*)
- cat >>confdefs.h <<\_ACEOF
-#define GC_AIX_THREADS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define _REENTRANT 1
-_ACEOF
-
- ;;
- *-*-hpux*)
- { echo "$as_me:$LINENO: WARNING: \"Only HP/UX 11 threads are supported.\"" >&5
-echo "$as_me: WARNING: \"Only HP/UX 11 threads are supported.\"" >&2;}
- cat >>confdefs.h <<\_ACEOF
-#define GC_HPUX_THREADS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define _POSIX_C_SOURCE 199506L
-_ACEOF
-
- if test "${enable_parallel_mark}" = yes; then
- cat >>confdefs.h <<\_ACEOF
-#define PARALLEL_MARK 1
-_ACEOF
-
- fi
- cat >>confdefs.h <<\_ACEOF
-#define THREAD_LOCAL_ALLOC 1
-_ACEOF
-
- THREADLIBS="-lpthread -lrt"
- ;;
- *-*-freebsd*)
- { echo "$as_me:$LINENO: WARNING: \"FreeBSD does not yet fully support threads with Boehm GC.\"" >&5
-echo "$as_me: WARNING: \"FreeBSD does not yet fully support threads with Boehm GC.\"" >&2;}
- cat >>confdefs.h <<\_ACEOF
-#define GC_FREEBSD_THREADS 1
-_ACEOF
-
- INCLUDES="$INCLUDES -pthread"
- THREADLIBS=-pthread
- ;;
- *-*-solaris*)
- cat >>confdefs.h <<\_ACEOF
-#define GC_SOLARIS_THREADS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define GC_SOLARIS_PTHREADS 1
-_ACEOF
-
- ;;
- *-*-irix*)
- cat >>confdefs.h <<\_ACEOF
-#define GC_IRIX_THREADS 1
-_ACEOF
-
- ;;
- *-*-cygwin*)
- cat >>confdefs.h <<\_ACEOF
-#define GC_WIN32_THREADS 1
-_ACEOF
-
- ;;
- *-*-darwin*)
- cat >>confdefs.h <<\_ACEOF
-#define GC_DARWIN_THREADS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define THREAD_LOCAL_ALLOC 1
-_ACEOF
-
- if test "${enable_parallel_mark}" = yes; then
- cat >>confdefs.h <<\_ACEOF
-#define PARALLEL_MARK 1
-_ACEOF
-
- fi
- ;;
- *-*-osf*)
- cat >>confdefs.h <<\_ACEOF
-#define GC_OSF1_THREADS 1
-_ACEOF
-
- if test "${enable_parallel_mark}" = yes; then
- cat >>confdefs.h <<\_ACEOF
-#define PARALLEL_MARK 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define THREAD_LOCAL_ALLOC 1
-_ACEOF
-
- # May want to enable it in other cases, too.
- # Measurements havent yet been done.
- fi
- INCLUDES="$INCLUDES -pthread"
- THREADLIBS="-lpthread -lrt"
- ;;
- esac
- ;;
- win32)
- cat >>confdefs.h <<\_ACEOF
-#define GC_WIN32_THREADS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define NO_GETENV 1
-_ACEOF
-
- ;;
- dgux386)
- THREADS=dgux386
- echo "$as_me:$LINENO: result: $THREADLIBS" >&5
-echo "${ECHO_T}$THREADLIBS" >&6
- # Use pthread GCC switch
- THREADLIBS=-pthread
- if test "${enable_parallel_mark}" = yes; then
- cat >>confdefs.h <<\_ACEOF
-#define PARALLEL_MARK 1
-_ACEOF
-
- fi
- cat >>confdefs.h <<\_ACEOF
-#define THREAD_LOCAL_ALLOC 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define GC_DGUX386_THREADS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define DGUX_THREADS 1
-_ACEOF
-
- # Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
- INCLUDES="-pthread $INCLUDES"
- ;;
- aix)
- THREADS=posix
- THREADLIBS=-lpthread
- cat >>confdefs.h <<\_ACEOF
-#define GC_AIX_THREADS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define _REENTRANT 1
-_ACEOF
-
- ;;
- decosf1 | irix | mach | os2 | solaris | dce | vxworks)
- { { echo "$as_me:$LINENO: error: thread package $THREADS not yet supported" >&5
-echo "$as_me: error: thread package $THREADS not yet supported" >&2;}
- { (exit 1); exit 1; }; }
- ;;
- *)
- { { echo "$as_me:$LINENO: error: $THREADS is an unknown thread package" >&5
-echo "$as_me: error: $THREADS is an unknown thread package" >&2;}
- { (exit 1); exit 1; }; }
- ;;
-esac
-
-
-case "$host" in
- powerpc-*-darwin*)
- powerpc_darwin=true
- ;;
-esac
-
-
-if test x$powerpc_darwin = xtrue; then
- POWERPC_DARWIN_TRUE=
- POWERPC_DARWIN_FALSE='#'
-else
- POWERPC_DARWIN_TRUE='#'
- POWERPC_DARWIN_FALSE=
-fi
-
-
-# We never want libdl on darwin. It is a fake libdl that just ends up making
-# dyld calls anyway
-case "$host" in
- *-*-darwin*) ;;
- *)
-
-echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
-echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
-if test "${ac_cv_lib_dl_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-dlopen ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dl_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_lib_dl_dlopen=no
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
-echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
-if test $ac_cv_lib_dl_dlopen = yes; then
- EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl"
-fi
-
- ;;
-esac
-
-
-
-target_all=libgc.la
-
-
-TARGET_ECOS="no"
-
-# Check whether --with-ecos or --without-ecos was given.
-if test "${with_ecos+set}" = set; then
- withval="$with_ecos"
- TARGET_ECOS="$with_ecos"
-
-fi;
-
-addobjs=
-addlibs=
-addincludes=
-addtests=
-CXXINCLUDES=
-case "$TARGET_ECOS" in
- no)
- ;;
- *)
- cat >>confdefs.h <<\_ACEOF
-#define ECOS 1
-_ACEOF
-
- CXXINCLUDES="-I${TARGET_ECOS}/include"
- addobjs="$addobjs ecos.lo"
- ;;
-esac
-
-if test "${enable_cplusplus}" = yes; then
- addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
- addtests="$addtests test_cpp"
-fi
-
-
-
-if test "${enable_cplusplus}" = yes; then
- CPLUSPLUS_TRUE=
- CPLUSPLUS_FALSE='#'
-else
- CPLUSPLUS_TRUE='#'
- CPLUSPLUS_FALSE=
-fi
-
-
-
-
-
-
-
-# Configuration of shared libraries
-#
-echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
-echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
-# Check whether --enable-shared or --disable-shared was given.
-if test "${enable_shared+set}" = set; then
- enableval="$enable_shared"
- p=${PACKAGE-default}
-case $enableval in
-yes) enable_shared=yes ;;
-no) enable_shared=no ;;
-*)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac
-else
- enable_shared=yes
-fi;
-
-case "$host" in
- alpha-*-openbsd*)
- enable_shared=no
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
- ;;
- *)
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
- ;;
-esac
-
-# Configuration of machine-dependent code
-#
-echo "$as_me:$LINENO: checking which machine-dependent code should be used" >&5
-echo $ECHO_N "checking which machine-dependent code should be used... $ECHO_C" >&6
-machdep=
-case "$host" in
- alpha-*-openbsd*)
- machdep="alpha_mach_dep.lo"
- if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
- { echo "$as_me:$LINENO: WARNING: OpenBSD/Alpha without dlopen(). Shared library support is disabled" >&5
-echo "$as_me: WARNING: OpenBSD/Alpha without dlopen(). Shared library support is disabled" >&2;}
- fi
- ;;
- alpha*-*-linux*)
- machdep="alpha_mach_dep.lo"
- ;;
- i?86-*-solaris2.[89] | i?86-*-solaris2.1?)
- cat >>confdefs.h <<\_ACEOF
-#define SOLARIS25_PROC_VDB_BUG_FIXED 1
-_ACEOF
-
- ;;
- mipstx39-*-elf*)
- machdep="mips_ultrix_mach_dep.lo"
- cat >>confdefs.h <<\_ACEOF
-#define STACKBASE __stackbase
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define DATASTART_IS_ETEXT 1
-_ACEOF
-
- ;;
- mips-dec-ultrix*)
- machdep="mips_ultrix_mach-dep.lo"
- ;;
- mips-nec-sysv*|mips-unknown-sysv*)
- ;;
- mips*-*-linux*)
- ;;
- mips-*-*)
- machdep="mips_sgi_mach_dep.lo"
- cat >>confdefs.h <<\_ACEOF
-#define NO_EXECUTE_PERMISSION 1
-_ACEOF
-
- ;;
- sparc-*-netbsd*)
- machdep="sparc_netbsd_mach_dep.lo"
- ;;
- sparc-sun-solaris2.3)
- machdep="sparc_mach_dep.lo"
- cat >>confdefs.h <<\_ACEOF
-#define SUNOS53_SHARED_LIB 1
-_ACEOF
-
- ;;
- sparc-sun-solaris2.*)
- machdep="sparc_mach_dep.lo"
- ;;
- ia64-*-*)
- machdep="mach_dep.lo ia64_save_regs_in_stack.lo"
- ;;
-esac
-if test x"$machdep" = x; then
-echo "$as_me:$LINENO: result: $machdep" >&5
-echo "${ECHO_T}$machdep" >&6
- machdep="mach_dep.lo"
-fi
-addobjs="$addobjs $machdep"
-
-
-
-
-
-# Check whether --enable-static or --disable-static was given.
-if test "${enable_static+set}" = set; then
- enableval="$enable_static"
- p=${PACKAGE-default}
-case $enableval in
-yes) enable_static=yes ;;
-no) enable_static=no ;;
-*)
- enable_static=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_static=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac
-else
- enable_static=yes
-fi;
-# Check whether --enable-fast-install or --disable-fast-install was given.
-if test "${enable_fast_install+set}" = set; then
- enableval="$enable_fast_install"
- p=${PACKAGE-default}
-case $enableval in
-yes) enable_fast_install=yes ;;
-no) enable_fast_install=no ;;
-*)
- enable_fast_install=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_fast_install=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac
-else
- enable_fast_install=yes
-fi;
-# Find the correct PATH separator. Usually this is `:', but
-# DJGPP uses `;' like DOS.
-if test "X${PATH_SEPARATOR+set}" != Xset; then
- UNAME=${UNAME-`uname 2>/dev/null`}
- case X$UNAME in
- *-DOS) lt_cv_sys_path_separator=';' ;;
- *) lt_cv_sys_path_separator=':' ;;
- esac
- PATH_SEPARATOR=$lt_cv_sys_path_separator
-fi
-
-
-# Check whether --with-gnu-ld or --without-gnu-ld was given.
-if test "${with_gnu_ld+set}" = set; then
- withval="$with_gnu_ld"
- test "$withval" = no || with_gnu_ld=yes
-else
- with_gnu_ld=no
-fi;
-ac_prog=ld
-if test "$GCC" = yes; then
- # Check if gcc -print-prog-name=ld gives a path.
- echo "$as_me:$LINENO: checking for ld used by GCC" >&5
-echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6
- case $host in
- *-*-mingw*)
- # gcc leaves a trailing carriage return which upsets mingw
- ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
- *)
- ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
- esac
- case $ac_prog in
- # Accept absolute paths.
- [\\/]* | [A-Za-z]:[\\/]*)
- re_direlt='/[^/][^/]*/\.\./'
- # Canonicalize the path of ld
- ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
- while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
- ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
- done
- test -z "$LD" && LD="$ac_prog"
- ;;
- "")
- # If it fails, then pretend we aren't using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
-elif test "$with_gnu_ld" = yes; then
- echo "$as_me:$LINENO: checking for GNU ld" >&5
-echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6
-else
- echo "$as_me:$LINENO: checking for non-GNU ld" >&5
-echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6
-fi
-if test "${lt_cv_path_LD+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -z "$LD"; then
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH; do
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- lt_cv_path_LD="$ac_dir/$ac_prog"
- # Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some GNU ld's only accept -v.
- # Break only if it was the GNU/non-GNU ld that we prefer.
- if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
- test "$with_gnu_ld" != no && break
- else
- test "$with_gnu_ld" != yes && break
- fi
- fi
- done
- IFS="$ac_save_ifs"
-else
- lt_cv_path_LD="$LD" # Let the user override the test with a path.
-fi
-fi
-
-LD="$lt_cv_path_LD"
-if test -n "$LD"; then
- echo "$as_me:$LINENO: result: $LD" >&5
-echo "${ECHO_T}$LD" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
-echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
- { (exit 1); exit 1; }; }
-echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
-echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6
-if test "${lt_cv_prog_gnu_ld+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- # I'd rather use --version here, but apparently some GNU ld's only accept -v.
-if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
- lt_cv_prog_gnu_ld=yes
-else
- lt_cv_prog_gnu_ld=no
-fi
-fi
-echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
-echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6
-with_gnu_ld=$lt_cv_prog_gnu_ld
-
-
-echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5
-echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6
-if test "${lt_cv_ld_reload_flag+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- lt_cv_ld_reload_flag='-r'
-fi
-echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5
-echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6
-reload_flag=$lt_cv_ld_reload_flag
-test -n "$reload_flag" && reload_flag=" $reload_flag"
-
-echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5
-echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6
-if test "${lt_cv_path_NM+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$NM"; then
- # Let the user override the test.
- lt_cv_path_NM="$NM"
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
- test -z "$ac_dir" && ac_dir=.
- tmp_nm=$ac_dir/${ac_tool_prefix}nm
- if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- # Tru64's nm complains that /dev/null is an invalid object file
- if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then
- lt_cv_path_NM="$tmp_nm -B"
- break
- elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
- lt_cv_path_NM="$tmp_nm -p"
- break
- else
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
- fi
- fi
- done
- IFS="$ac_save_ifs"
- test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
-fi
-fi
-
-NM="$lt_cv_path_NM"
-echo "$as_me:$LINENO: result: $NM" >&5
-echo "${ECHO_T}$NM" >&6
-
-echo "$as_me:$LINENO: checking whether ln -s works" >&5
-echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
-LN_S=$as_ln_s
-if test "$LN_S" = "ln -s"; then
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
-else
- echo "$as_me:$LINENO: result: no, using $LN_S" >&5
-echo "${ECHO_T}no, using $LN_S" >&6
-fi
-
-echo "$as_me:$LINENO: checking how to recognise dependant libraries" >&5
-echo $ECHO_N "checking how to recognise dependant libraries... $ECHO_C" >&6
-if test "${lt_cv_deplibs_check_method+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given egrep regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
-
-case $host_os in
-aix4* | aix5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-beos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-bsdi4*)
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- lt_cv_file_magic_test_file=/shlib/libc.so
- ;;
-
-cygwin* | mingw* | pw32*)
- lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- ;;
-
-darwin* | rhapsody*)
- lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- case "$host_os" in
- rhapsody* | darwin1.[012])
- lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1`
- ;;
- *) # Darwin 1.3 on
- lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib'
- ;;
- esac
- ;;
-
-freebsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
- case $host_cpu in
- i*86 )
- # Not sure whether the presence of OpenBSD here was a mistake.
- # Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- ;;
- esac
- else
- lt_cv_deplibs_check_method=pass_all
- fi
- ;;
-
-gnu*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-hpux10.20*|hpux11*)
- lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libc.sl
- ;;
-
-irix5* | irix6*)
- case $host_os in
- irix5*)
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1"
- ;;
- *)
- case $LD in
- *-32|*"-32 ") libmagic=32-bit;;
- *-n32|*"-n32 ") libmagic=N32;;
- *-64|*"-64 ") libmagic=64-bit;;
- *) libmagic=never-match;;
- esac
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1"
- ;;
- esac
- lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*`
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-# This must be Linux ELF.
-linux-gnu*)
- case $host_cpu in
- alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* | s390* )
- lt_cv_deplibs_check_method=pass_all ;;
- *)
- # glibc up to 2.1.1 does not perform some relocations on ARM
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;;
- esac
- lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
- ;;
-
-netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
- lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$'
- else
- lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$'
- fi
- ;;
-
-newos6*)
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libnls.so
- ;;
-
-openbsd*)
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object'
- else
- lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
- fi
- ;;
-
-osf3* | osf4* | osf5*)
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method='file_magic COFF format alpha shared library'
- lt_cv_file_magic_test_file=/shlib/libc.so
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sco3.2v5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-solaris*)
- lt_cv_deplibs_check_method=pass_all
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
-
-sysv5uw[78]* | sysv4*uw2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- case $host_vendor in
- motorola)
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
- ;;
- ncr)
- lt_cv_deplibs_check_method=pass_all
- ;;
- sequent)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
- ;;
- sni)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
- esac
- ;;
-esac
-
-fi
-echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5
-echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-
-
-
-
-
-
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-echo "$as_me:$LINENO: checking command to parse $NM output" >&5
-echo $ECHO_N "checking command to parse $NM output... $ECHO_C" >&6
-if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix. What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[BCDEGRST]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
-
-# Transform the above into a raw symbol and a C symbol.
-symxfrm='\1 \2\3 \3'
-
-# Transform an extracted symbol line into a proper C declaration
-lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'"
-
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
-
-# Define system-specific variables.
-case $host_os in
-aix*)
- symcode='[BCDT]'
- ;;
-cygwin* | mingw* | pw32*)
- symcode='[ABCDGISTW]'
- ;;
-hpux*) # Its linker distinguishes data from code symbols
- lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
- lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
- ;;
-irix*)
- symcode='[BCDEGRST]'
- ;;
-solaris* | sysv5*)
- symcode='[BDT]'
- ;;
-sysv4)
- symcode='[DFNSTU]'
- ;;
-esac
-
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $host_os in
-mingw*)
- opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
- ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
- symcode='[ABCDGISTW]'
-fi
-
-# Try without a prefix undercore, then with it.
-for ac_symprfx in "" "_"; do
-
- # Write the raw and C identifiers.
-lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
-
- # Check to see that the pipe works correctly.
- pipe_works=no
- rm -f conftest*
- cat > conftest.$ac_ext <<EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-EOF
-
- if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; then
- # Now try to grab the symbols.
- nlist=conftest.nm
- if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5
- (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && test -s "$nlist"; then
- # Try sorting and uniquifying the output.
- if sort "$nlist" | uniq > "$nlist"T; then
- mv -f "$nlist"T "$nlist"
- else
- rm -f "$nlist"T
- fi
-
- # Make sure that we snagged all the symbols we need.
- if egrep ' nm_test_var$' "$nlist" >/dev/null; then
- if egrep ' nm_test_func$' "$nlist" >/dev/null; then
- cat <<EOF > conftest.$ac_ext
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-EOF
- # Now generate the symbol file.
- eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext'
-
- cat <<EOF >> conftest.$ac_ext
-#if defined (__STDC__) && __STDC__
-# define lt_ptr void *
-#else
-# define lt_ptr char *
-# define const
-#endif
-
-/* The mapping between symbol names and symbols. */
-const struct {
- const char *name;
- lt_ptr address;
-}
-lt_preloaded_symbols[] =
-{
-EOF
- sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr) \&\2},/" < "$nlist" >> conftest.$ac_ext
- cat <<\EOF >> conftest.$ac_ext
- {0, (lt_ptr) 0}
-};
-
-#ifdef __cplusplus
-}
-#endif
-EOF
- # Now try linking the two files.
- mv conftest.$ac_objext conftstm.$ac_objext
- save_LIBS="$LIBS"
- save_CFLAGS="$CFLAGS"
- LIBS="conftstm.$ac_objext"
- CFLAGS="$CFLAGS$no_builtin_flag"
- if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && test -s conftest; then
- pipe_works=yes
- fi
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
- else
- echo "cannot find nm_test_func in $nlist" >&5
- fi
- else
- echo "cannot find nm_test_var in $nlist" >&5
- fi
- else
- echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
- fi
- else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- fi
- rm -f conftest* conftst*
-
- # Do not use the global_symbol_pipe unless it works.
- if test "$pipe_works" = yes; then
- break
- else
- lt_cv_sys_global_symbol_pipe=
- fi
-done
-
-fi
-
-global_symbol_pipe="$lt_cv_sys_global_symbol_pipe"
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
- global_symbol_to_cdecl=
- global_symbol_to_c_name_address=
-else
- global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl"
- global_symbol_to_c_name_address="$lt_cv_global_symbol_to_c_name_address"
-fi
-if test -z "$global_symbol_pipe$global_symbol_to_cdec$global_symbol_to_c_name_address";
-then
- echo "$as_me:$LINENO: result: failed" >&5
-echo "${ECHO_T}failed" >&6
-else
- echo "$as_me:$LINENO: result: ok" >&5
-echo "${ECHO_T}ok" >&6
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
-echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
- CPP=
-fi
-if test -z "$CPP"; then
- if test "${ac_cv_prog_CPP+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- # Double quotes because CPP needs to be expanded
- for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
- do
- ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <assert.h>
- Syntax error
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
- ac_status=$?
- egrep -v '^ *\+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- else
- ac_cpp_err=
- fi
-else
- ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
- :
-else
- echo "$as_me: failed program was:" >&5
- cat conftest.$ac_ext >&5
- # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.$ac_ext
-
- # OK, works on sane cases. Now check whether non-existent headers
- # can be detected and how.
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <ac_nonexistent.h>
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
- ac_status=$?
- egrep -v '^ *\+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- else
- ac_cpp_err=
- fi
-else
- ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
- # Broken: success on invalid input.
-continue
-else
- echo "$as_me: failed program was:" >&5
- cat conftest.$ac_ext >&5
- # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
- break
-fi
-
- done
- ac_cv_prog_CPP=$CPP
-
-fi
- CPP=$ac_cv_prog_CPP
-else
- ac_cv_prog_CPP=$CPP
-fi
-echo "$as_me:$LINENO: result: $CPP" >&5
-echo "${ECHO_T}$CPP" >&6
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
- # Use a header file that comes with gcc, so configuring glibc
- # with a fresh cross-compiler works.
- # On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp. "Syntax error" is here to catch this case.
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <assert.h>
- Syntax error
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
- ac_status=$?
- egrep -v '^ *\+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- else
- ac_cpp_err=
- fi
-else
- ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
- :
-else
- echo "$as_me: failed program was:" >&5
- cat conftest.$ac_ext >&5
- # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.$ac_ext
-
- # OK, works on sane cases. Now check whether non-existent headers
- # can be detected and how.
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <ac_nonexistent.h>
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
- ac_status=$?
- egrep -v '^ *\+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- else
- ac_cpp_err=
- fi
-else
- ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
- # Broken: success on invalid input.
-continue
-else
- echo "$as_me: failed program was:" >&5
- cat conftest.$ac_ext >&5
- # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
- :
-else
- { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check" >&5
-echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;}
- { (exit 1); exit 1; }; }
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-echo "$as_me:$LINENO: checking for ANSI C header files" >&5
-echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
-if test "${ac_cv_header_stdc+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
- ac_status=$?
- egrep -v '^ *\+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- else
- ac_cpp_err=
- fi
-else
- ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
- ac_cv_header_stdc=yes
-else
- echo "$as_me: failed program was:" >&5
- cat conftest.$ac_ext >&5
- ac_cv_header_stdc=no
-fi
-rm -f conftest.err conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
- # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "memchr" >/dev/null 2>&1; then
- :
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "free" >/dev/null 2>&1; then
- :
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
- if test "$cross_compiling" = yes; then
- :
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <ctype.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \
- || ('j' <= (c) && (c) <= 'r') \
- || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
- int i;
- for (i = 0; i < 256; i++)
- if (XOR (islower (i), ISLOWER (i))
- || toupper (i) != TOUPPER (i))
- exit(2);
- exit (0);
-}
-_ACEOF
-rm -f conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- :
-else
- echo "$as_me: program exited with status $ac_status" >&5
-echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-( exit $ac_status )
-ac_cv_header_stdc=no
-fi
-rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
-fi
-fi
-echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
-echo "${ECHO_T}$ac_cv_header_stdc" >&6
-if test $ac_cv_header_stdc = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define STDC_HEADERS 1
-_ACEOF
-
-fi
-
-# On IRIX 5.3, sys/types and inttypes.h are conflicting.
-
-
-
-
-
-
-
-
-
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
- inttypes.h stdint.h unistd.h
-do
-as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
-echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-$ac_includes_default
-
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- eval "$as_ac_Header=yes"
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-eval "$as_ac_Header=no"
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
-if test `eval echo '${'$as_ac_Header'}'` = yes; then
- cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
-
-for ac_header in dlfcn.h
-do
-as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
- echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
-else
- # Is the header compilable?
-echo "$as_me:$LINENO: checking $ac_header usability" >&5
-echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_header_compiler=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_header_compiler=no
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-echo "${ECHO_T}$ac_header_compiler" >&6
-
-# Is the header present?
-echo "$as_me:$LINENO: checking $ac_header presence" >&5
-echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <$ac_header>
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
- ac_status=$?
- egrep -v '^ *\+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- else
- ac_cpp_err=
- fi
-else
- ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
- ac_header_preproc=yes
-else
- echo "$as_me: failed program was:" >&5
- cat conftest.$ac_ext >&5
- ac_header_preproc=no
-fi
-rm -f conftest.err conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-echo "${ECHO_T}$ac_header_preproc" >&6
-
-# So? What about this header?
-case $ac_header_compiler:$ac_header_preproc in
- yes:no )
- { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
- { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
- no:yes )
- { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
- { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
-echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
- { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
-esac
-echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- eval "$as_ac_Header=$ac_header_preproc"
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
-
-fi
-if test `eval echo '${'$as_ac_Header'}'` = yes; then
- cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
-
-
-
-# Only perform the check for file, if the check method requires it
-case $deplibs_check_method in
-file_magic*)
- if test "$file_magic_cmd" = '$MAGIC_CMD'; then
- echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5
-echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6
-if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- case $MAGIC_CMD in
- /*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
- ;;
- ?:/*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path.
- ;;
- *)
- ac_save_MAGIC_CMD="$MAGIC_CMD"
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="/usr/bin:$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/${ac_tool_prefix}file; then
- lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
- if test -n "$file_magic_test_file"; then
- case $deplibs_check_method in
- "file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- egrep "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS="$ac_save_ifs"
- MAGIC_CMD="$ac_save_MAGIC_CMD"
- ;;
-esac
-fi
-
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-if test -n "$MAGIC_CMD"; then
- echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
-echo "${ECHO_T}$MAGIC_CMD" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-if test -z "$lt_cv_path_MAGIC_CMD"; then
- if test -n "$ac_tool_prefix"; then
- echo "$as_me:$LINENO: checking for file" >&5
-echo $ECHO_N "checking for file... $ECHO_C" >&6
-if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- case $MAGIC_CMD in
- /*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
- ;;
- ?:/*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path.
- ;;
- *)
- ac_save_MAGIC_CMD="$MAGIC_CMD"
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="/usr/bin:$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/file; then
- lt_cv_path_MAGIC_CMD="$ac_dir/file"
- if test -n "$file_magic_test_file"; then
- case $deplibs_check_method in
- "file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- egrep "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS="$ac_save_ifs"
- MAGIC_CMD="$ac_save_MAGIC_CMD"
- ;;
-esac
-fi
-
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-if test -n "$MAGIC_CMD"; then
- echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
-echo "${ECHO_T}$MAGIC_CMD" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- else
- MAGIC_CMD=:
- fi
-fi
-
- fi
- ;;
-esac
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_RANLIB+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
- echo "$as_me:$LINENO: result: $RANLIB" >&5
-echo "${ECHO_T}$RANLIB" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
- ac_ct_RANLIB=$RANLIB
- # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_RANLIB"; then
- ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_RANLIB="ranlib"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
- test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
-fi
-fi
-ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
- echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
-echo "${ECHO_T}$ac_ct_RANLIB" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- RANLIB=$ac_ct_RANLIB
-else
- RANLIB="$ac_cv_prog_RANLIB"
-fi
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
-set dummy ${ac_tool_prefix}strip; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_STRIP+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$STRIP"; then
- ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_STRIP="${ac_tool_prefix}strip"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
-fi
-fi
-STRIP=$ac_cv_prog_STRIP
-if test -n "$STRIP"; then
- echo "$as_me:$LINENO: result: $STRIP" >&5
-echo "${ECHO_T}$STRIP" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_STRIP"; then
- ac_ct_STRIP=$STRIP
- # Extract the first word of "strip", so it can be a program name with args.
-set dummy strip; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test -n "$ac_ct_STRIP"; then
- ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_STRIP="strip"
- echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
-done
-
- test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":"
-fi
-fi
-ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
-if test -n "$ac_ct_STRIP"; then
- echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
-echo "${ECHO_T}$ac_ct_STRIP" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
- STRIP=$ac_ct_STRIP
-else
- STRIP="$ac_cv_prog_STRIP"
-fi
-
-
-enable_dlopen=no
-enable_win32_dll=no
-
-# Check whether --enable-libtool-lock or --disable-libtool-lock was given.
-if test "${enable_libtool_lock+set}" = set; then
- enableval="$enable_libtool_lock"
-
-fi;
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-*-*-irix6*)
- # Find out which ABI we are using.
- echo '#line 5406 "configure"' > conftest.$ac_ext
- if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; then
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -32"
- ;;
- *N32*)
- LD="${LD-ld} -n32"
- ;;
- *64-bit*)
- LD="${LD-ld} -64"
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-
-*-*-sco3.2v5*)
- # On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -belf"
- echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5
-echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6
-if test "${lt_cv_cc_needs_belf+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-
-
- ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- lt_cv_cc_needs_belf=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-lt_cv_cc_needs_belf=no
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
- ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-fi
-echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5
-echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6
- if test x"$lt_cv_cc_needs_belf" != x"yes"; then
- # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
- CFLAGS="$SAVE_CFLAGS"
- fi
- ;;
-
-
-esac
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e s/^X//'
-sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Constants:
-rm="rm -f"
-
-# Global variables:
-default_ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a `.a' archive for static linking (except M$VC,
-# which needs '.lib').
-libext=a
-ltmain="$ac_aux_dir/ltmain.sh"
-ofile="$default_ofile"
-with_gnu_ld="$lt_cv_prog_gnu_ld"
-need_locks="$enable_libtool_lock"
-
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
-
-# Set sane defaults for various variables
-test -z "$AR" && AR=ar
-test -z "$AR_FLAGS" && AR_FLAGS=cru
-test -z "$AS" && AS=as
-test -z "$CC" && CC=cc
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-test -z "$LD" && LD=ld
-test -z "$LN_S" && LN_S="ln -s"
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-test -z "$NM" && NM=nm
-test -z "$OBJDUMP" && OBJDUMP=objdump
-test -z "$RANLIB" && RANLIB=:
-test -z "$STRIP" && STRIP=:
-test -z "$ac_objext" && ac_objext=o
-
-if test x"$host" != x"$build"; then
- ac_tool_prefix=${host_alias}-
-else
- ac_tool_prefix=
-fi
-
-# Transform linux* to *-*-linux-gnu*, to support old configure scripts.
-case $host_os in
-linux-gnu*) ;;
-linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
-esac
-
-case $host_os in
-aix3*)
- # AIX sometimes has problems with the GCC collect2 program. For some
- # reason, if we set the COLLECT_NAMES environment variable, the problems
- # vanish in a puff of smoke.
- if test "X${COLLECT_NAMES+set}" != Xset; then
- COLLECT_NAMES=
- export COLLECT_NAMES
- fi
- ;;
-esac
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
- case $host_os in
- openbsd*)
- old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
- ;;
- *)
- old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
- ;;
- esac
- old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
-fi
-
-# Allow CC to be a program name with arguments.
-set dummy $CC
-compiler="$2"
-
-echo "$as_me:$LINENO: checking for objdir" >&5
-echo $ECHO_N "checking for objdir... $ECHO_C" >&6
-rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
- objdir=.libs
-else
- # MS-DOS does not allow filenames that begin with a dot.
- objdir=_libs
-fi
-rmdir .libs 2>/dev/null
-echo "$as_me:$LINENO: result: $objdir" >&5
-echo "${ECHO_T}$objdir" >&6
-
-
-
-# Check whether --with-pic or --without-pic was given.
-if test "${with_pic+set}" = set; then
- withval="$with_pic"
- pic_mode="$withval"
-else
- pic_mode=default
-fi;
-test -z "$pic_mode" && pic_mode=default
-
-# We assume here that the value for lt_cv_prog_cc_pic will not be cached
-# in isolation, and that seeing it set (from the cache) indicates that
-# the associated values are set (in the cache) correctly too.
-echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
-echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6
-if test "${lt_cv_prog_cc_pic+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- lt_cv_prog_cc_pic=
- lt_cv_prog_cc_shlib=
- lt_cv_prog_cc_wl=
- lt_cv_prog_cc_static=
- lt_cv_prog_cc_no_builtin=
- lt_cv_prog_cc_can_build_shared=$can_build_shared
-
- if test "$GCC" = yes; then
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static='-static'
-
- case $host_os in
- aix*)
- # Below there is a dirty hack to force normal static linking with -ldl
- # The problem is because libdl dynamically linked with both libc and
- # libC (AIX C++ library), which obviously doesn't included in libraries
- # list by gcc. This cause undefined symbols with -static flags.
- # This hack allows C programs to be linked with "-static -ldl", but
- # not sure about C++ programs.
- lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC"
- ;;
- amigaos*)
- # FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
- lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4'
- ;;
- beos* | irix5* | irix6* | osf3* | osf4* | osf5*)
- # PIC is the default for these OSes.
- ;;
- darwin* | rhapsody*)
- # PIC is the default on this platform
- # Common symbols not allowed in MH_DYLIB files
- lt_cv_prog_cc_pic='-fno-common'
- ;;
- cygwin* | mingw* | pw32* | os2*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- lt_cv_prog_cc_pic='-DDLL_EXPORT'
- ;;
- sysv4*MP*)
- if test -d /usr/nec; then
- lt_cv_prog_cc_pic=-Kconform_pic
- fi
- ;;
- *)
- lt_cv_prog_cc_pic='-fPIC'
- ;;
- esac
- else
- # PORTME Check for PIC flags for the system compiler.
- case $host_os in
- aix3* | aix4* | aix5*)
- lt_cv_prog_cc_wl='-Wl,'
- # All AIX code is PIC.
- if test "$host_cpu" = ia64; then
- # AIX 5 now supports IA64 processor
- lt_cv_prog_cc_static='-Bstatic'
- else
- lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp'
- fi
- ;;
-
- hpux9* | hpux10* | hpux11*)
- # Is there a better lt_cv_prog_cc_static that works with the bundled CC?
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive"
- lt_cv_prog_cc_pic='+Z'
- ;;
-
- irix5* | irix6*)
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static='-non_shared'
- # PIC (with -KPIC) is the default.
- ;;
-
- cygwin* | mingw* | pw32* | os2*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- lt_cv_prog_cc_pic='-DDLL_EXPORT'
- ;;
-
- newsos6)
- lt_cv_prog_cc_pic='-KPIC'
- lt_cv_prog_cc_static='-Bstatic'
- ;;
-
- osf3* | osf4* | osf5*)
- # All OSF/1 code is PIC.
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static='-non_shared'
- ;;
-
- sco3.2v5*)
- lt_cv_prog_cc_pic='-Kpic'
- lt_cv_prog_cc_static='-dn'
- lt_cv_prog_cc_shlib='-belf'
- ;;
-
- solaris*)
- lt_cv_prog_cc_pic='-KPIC'
- lt_cv_prog_cc_static='-Bstatic'
- lt_cv_prog_cc_wl='-Wl,'
- ;;
-
- sunos4*)
- lt_cv_prog_cc_pic='-PIC'
- lt_cv_prog_cc_static='-Bstatic'
- lt_cv_prog_cc_wl='-Qoption ld '
- ;;
-
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- lt_cv_prog_cc_pic='-KPIC'
- lt_cv_prog_cc_static='-Bstatic'
- if test "x$host_vendor" = xsni; then
- lt_cv_prog_cc_wl='-LD'
- else
- lt_cv_prog_cc_wl='-Wl,'
- fi
- ;;
-
- uts4*)
- lt_cv_prog_cc_pic='-pic'
- lt_cv_prog_cc_static='-Bstatic'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec ;then
- lt_cv_prog_cc_pic='-Kconform_pic'
- lt_cv_prog_cc_static='-Bstatic'
- fi
- ;;
-
- *)
- lt_cv_prog_cc_can_build_shared=no
- ;;
- esac
- fi
-
-fi
-
-if test -z "$lt_cv_prog_cc_pic"; then
- echo "$as_me:$LINENO: result: none" >&5
-echo "${ECHO_T}none" >&6
-else
- echo "$as_me:$LINENO: result: $lt_cv_prog_cc_pic" >&5
-echo "${ECHO_T}$lt_cv_prog_cc_pic" >&6
-
- # Check to make sure the pic_flag actually works.
- echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_cv_prog_cc_pic works" >&5
-echo $ECHO_N "checking if $compiler PIC flag $lt_cv_prog_cc_pic works... $ECHO_C" >&6
- if test "${lt_cv_prog_cc_pic_works+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC"
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- case $host_os in
- hpux9* | hpux10* | hpux11*)
- # On HP-UX, both CC and GCC only warn that PIC is supported... then
- # they create non-PIC objects. So, if there were any warnings, we
- # assume that PIC is not supported.
- if test -s conftest.err; then
- lt_cv_prog_cc_pic_works=no
- else
- lt_cv_prog_cc_pic_works=yes
- fi
- ;;
- *)
- lt_cv_prog_cc_pic_works=yes
- ;;
- esac
-
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
- lt_cv_prog_cc_pic_works=no
-
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
- CFLAGS="$save_CFLAGS"
-
-fi
-
-
- if test "X$lt_cv_prog_cc_pic_works" = Xno; then
- lt_cv_prog_cc_pic=
- lt_cv_prog_cc_can_build_shared=no
- else
- lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic"
- fi
-
- echo "$as_me:$LINENO: result: $lt_cv_prog_cc_pic_works" >&5
-echo "${ECHO_T}$lt_cv_prog_cc_pic_works" >&6
-fi
-
-# Check for any special shared library compilation flags.
-if test -n "$lt_cv_prog_cc_shlib"; then
- { echo "$as_me:$LINENO: WARNING: \`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries" >&5
-echo "$as_me: WARNING: \`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries" >&2;}
- if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$lt_cv_prog_cc_shlib[ ]" >/dev/null; then :
- else
- { echo "$as_me:$LINENO: WARNING: add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&5
-echo "$as_me: WARNING: add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure" >&2;}
- lt_cv_prog_cc_can_build_shared=no
- fi
-fi
-
-echo "$as_me:$LINENO: checking if $compiler static flag $lt_cv_prog_cc_static works" >&5
-echo $ECHO_N "checking if $compiler static flag $lt_cv_prog_cc_static works... $ECHO_C" >&6
-if test "${lt_cv_prog_cc_static_works+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- lt_cv_prog_cc_static_works=no
- save_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static"
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- lt_cv_prog_cc_static_works=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
- LDFLAGS="$save_LDFLAGS"
-
-fi
-
-
-# Belt *and* braces to stop my trousers falling down:
-test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static=
-echo "$as_me:$LINENO: result: $lt_cv_prog_cc_static_works" >&5
-echo "${ECHO_T}$lt_cv_prog_cc_static_works" >&6
-
-pic_flag="$lt_cv_prog_cc_pic"
-special_shlib_compile_flags="$lt_cv_prog_cc_shlib"
-wl="$lt_cv_prog_cc_wl"
-link_static_flag="$lt_cv_prog_cc_static"
-no_builtin_flag="$lt_cv_prog_cc_no_builtin"
-can_build_shared="$lt_cv_prog_cc_can_build_shared"
-
-
-# Check to see if options -o and -c are simultaneously supported by compiler
-echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
-echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6
-if test "${lt_cv_compiler_c_o+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-
-$rm -r conftest 2>/dev/null
-mkdir conftest
-cd conftest
-echo "int some_variable = 0;" > conftest.$ac_ext
-mkdir out
-# According to Tom Tromey, Ian Lance Taylor reported there are C compilers
-# that will create temporary files in the current directory regardless of
-# the output directory. Thus, making CWD read-only will cause this test
-# to fail, enabling locking or at least warning the user not to do parallel
-# builds.
-chmod -w .
-save_CFLAGS="$CFLAGS"
-CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
-compiler_c_o=no
-if { (eval echo configure:5942: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s out/conftest.err; then
- lt_cv_compiler_c_o=no
- else
- lt_cv_compiler_c_o=yes
- fi
-else
- # Append any errors to the config.log.
- cat out/conftest.err 1>&5
- lt_cv_compiler_c_o=no
-fi
-CFLAGS="$save_CFLAGS"
-chmod u+w .
-$rm conftest* out/*
-rmdir out
-cd ..
-rmdir conftest
-$rm -r conftest 2>/dev/null
-
-fi
-
-compiler_c_o=$lt_cv_compiler_c_o
-echo "$as_me:$LINENO: result: $compiler_c_o" >&5
-echo "${ECHO_T}$compiler_c_o" >&6
-
-if test x"$compiler_c_o" = x"yes"; then
- # Check to see if we can write to a .lo
- echo "$as_me:$LINENO: checking if $compiler supports -c -o file.lo" >&5
-echo $ECHO_N "checking if $compiler supports -c -o file.lo... $ECHO_C" >&6
- if test "${lt_cv_compiler_o_lo+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-
- lt_cv_compiler_o_lo=no
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -c -o conftest.lo"
- save_objext="$ac_objext"
- ac_objext=lo
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-int some_variable = 0;
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- lt_cv_compiler_o_lo=no
- else
- lt_cv_compiler_o_lo=yes
- fi
-
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
- ac_objext="$save_objext"
- CFLAGS="$save_CFLAGS"
-
-fi
-
- compiler_o_lo=$lt_cv_compiler_o_lo
- echo "$as_me:$LINENO: result: $compiler_o_lo" >&5
-echo "${ECHO_T}$compiler_o_lo" >&6
-else
- compiler_o_lo=no
-fi
-
-# Check to see if we can do hard links to lock some files if needed
-hard_links="nottested"
-if test "$compiler_c_o" = no && test "$need_locks" != no; then
- # do not overwrite the value of need_locks provided by the user
- echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
-echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6
- hard_links=yes
- $rm conftest*
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- touch conftest.a
- ln conftest.a conftest.b 2>&5 || hard_links=no
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- echo "$as_me:$LINENO: result: $hard_links" >&5
-echo "${ECHO_T}$hard_links" >&6
- if test "$hard_links" = no; then
- { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
-echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
- need_locks=warn
- fi
-else
- need_locks=no
-fi
-
-if test "$GCC" = yes; then
- # Check to see if options -fno-rtti -fno-exceptions are supported by compiler
- echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
-echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6
- echo "int some_variable = 0;" > conftest.$ac_ext
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext"
- compiler_rtti_exceptions=no
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-int some_variable = 0;
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- compiler_rtti_exceptions=no
- else
- compiler_rtti_exceptions=yes
- fi
-
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
- CFLAGS="$save_CFLAGS"
- echo "$as_me:$LINENO: result: $compiler_rtti_exceptions" >&5
-echo "${ECHO_T}$compiler_rtti_exceptions" >&6
-
- if test "$compiler_rtti_exceptions" = "yes"; then
- no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions'
- else
- no_builtin_flag=' -fno-builtin'
- fi
-fi
-
-# See if the linker supports building shared libraries.
-echo "$as_me:$LINENO: checking whether the linker ($LD) supports shared libraries" >&5
-echo $ECHO_N "checking whether the linker ($LD) supports shared libraries... $ECHO_C" >&6
-
-allow_undefined_flag=
-no_undefined_flag=
-need_lib_prefix=unknown
-need_version=unknown
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-archive_cmds=
-archive_expsym_cmds=
-old_archive_from_new_cmds=
-old_archive_from_expsyms_cmds=
-export_dynamic_flag_spec=
-whole_archive_flag_spec=
-thread_safe_flag_spec=
-hardcode_into_libs=no
-hardcode_libdir_flag_spec=
-hardcode_libdir_separator=
-hardcode_direct=no
-hardcode_minus_L=no
-hardcode_shlibpath_var=unsupported
-runpath_var=
-link_all_deplibs=unknown
-always_export_symbols=no
-export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols'
-# include_expsyms should be a list of space-separated symbols to be *always*
-# included in the symbol list
-include_expsyms=
-# exclude_expsyms can be an egrep regular expression of symbols to exclude
-# it will be wrapped by ` (' and `)$', so one must not match beginning or
-# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
-# as well as any symbol that contains `d'.
-exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
-# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
-# platforms (ab)use it in PIC code, but their linkers get confused if
-# the symbol is explicitly referenced. Since portable code cannot
-# rely on this symbol name, it's probably fine to never include it in
-# preloaded symbol tables.
-extract_expsyms_cmds=
-
-case $host_os in
-cygwin* | mingw* | pw32*)
- # FIXME: the MSVC++ port hasn't been tested in a loooong time
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- if test "$GCC" != yes; then
- with_gnu_ld=no
- fi
- ;;
-openbsd*)
- with_gnu_ld=no
- ;;
-esac
-
-ld_shlibs=yes
-if test "$with_gnu_ld" = yes; then
- # If archive_cmds runs LD, not CC, wlarc should be empty
- wlarc='${wl}'
-
- # See if GNU ld supports shared libraries.
- case $host_os in
- aix3* | aix4* | aix5*)
- # On AIX, the GNU linker is very broken
- # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available.
- ld_shlibs=no
- cat <<EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.9.1, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support. If you
-*** really care for shared libraries, you may want to modify your PATH
-*** so that a non-GNU linker is found, and then restart.
-
-EOF
- ;;
-
- amigaos*)
- archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
-
- # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
- # that the semantics of dynamic libraries on AmigaOS, at least up
- # to version 4, is to share data among multiple programs linked
- # with the same dynamic library. Since this doesn't match the
- # behavior of shared libraries on other platforms, we can use
- # them.
- ld_shlibs=no
- ;;
-
- beos*)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- allow_undefined_flag=unsupported
- # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
- # support --undefined. This deserves some investigation. FIXME
- archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- cygwin* | mingw* | pw32*)
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec='-L$libdir'
- allow_undefined_flag=unsupported
- always_export_symbols=yes
-
- extract_expsyms_cmds='test -f $output_objdir/impgen.c || \
- sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~
- test -f $output_objdir/impgen.exe || (cd $output_objdir && \
- if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \
- else $CC -o impgen impgen.c ; fi)~
- $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def'
-
- old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib'
-
- # cygwin and mingw dlls have different entry points and sets of symbols
- # to exclude.
- # FIXME: what about values for MSVC?
- dll_entry=__cygwin_dll_entry@12
- dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~
- case $host_os in
- mingw*)
- # mingw values
- dll_entry=_DllMainCRTStartup@12
- dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~
- ;;
- esac
-
- # mingw and cygwin differ, and it's simplest to just exclude the union
- # of the two symbol sets.
- dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12
-
- # recent cygwin and mingw systems supply a stub DllMain which the user
- # can override, but on older systems we have to supply one (in ltdll.c)
- if test "x$lt_cv_need_dllmain" = "xyes"; then
- ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext "
- ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $''0 > $output_objdir/$soname-ltdll.c~
- test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~'
- else
- ltdll_obj=
- ltdll_cmds=
- fi
-
- # Extract the symbol export list from an `--export-all' def file,
- # then regenerate the def file from the symbol export list, so that
- # the compiled dll only exports the symbol export list.
- # Be careful not to strip the DATA tag left be newer dlltools.
- export_symbols_cmds="$ltdll_cmds"'
- $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~
- sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols'
-
- # If the export-symbols file already is a .def file (1st line
- # is EXPORTS), use it as is.
- # If DATA tags from a recent dlltool are present, honour them!
- archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then
- cp $export_symbols $output_objdir/$soname-def;
- else
- echo EXPORTS > $output_objdir/$soname-def;
- _lt_hint=1;
- cat $export_symbols | while read symbol; do
- set dummy \$symbol;
- case \$# in
- 2) echo " \$2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;;
- *) echo " \$2 @ \$_lt_hint \$3 ; " >> $output_objdir/$soname-def;;
- esac;
- _lt_hint=`expr 1 + \$_lt_hint`;
- done;
- fi~
- '"$ltdll_cmds"'
- $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
- $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~
- $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
- $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~
- $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags'
- ;;
-
- netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
- wlarc=
- else
- archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- fi
- ;;
-
- solaris* | sysv5*)
- if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then
- ld_shlibs=no
- cat <<EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-EOF
- elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- sunos4*)
- archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- wlarc=
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- *)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
- esac
-
- if test "$ld_shlibs" = yes; then
- runpath_var=LD_RUN_PATH
- hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
- export_dynamic_flag_spec='${wl}--export-dynamic'
- case $host_os in
- cygwin* | mingw* | pw32*)
- # dlltool doesn't understand --whole-archive et. al.
- whole_archive_flag_spec=
- ;;
- *)
- # ancient GNU ld didn't support --whole-archive et. al.
- if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then
- whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
- else
- whole_archive_flag_spec=
- fi
- ;;
- esac
- fi
-else
- # PORTME fill in a description of your system's linker (not GNU ld)
- case $host_os in
- aix3*)
- allow_undefined_flag=unsupported
- always_export_symbols=yes
- archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
- # Note: this linker hardcodes the directories in LIBPATH if there
- # are no directories specified by -L.
- hardcode_minus_L=yes
- if test "$GCC" = yes && test -z "$link_static_flag"; then
- # Neither direct hardcoding nor static linking is supported with a
- # broken collect2.
- hardcode_direct=unsupported
- fi
- ;;
-
- aix4* | aix5*)
- if test "$host_cpu" = ia64; then
- # On IA64, the linker does run time linking by default, so we don't
- # have to do anything special.
- aix_use_runtimelinking=no
- exp_sym_flag='-Bexport'
- no_entry_flag=""
- else
- aix_use_runtimelinking=no
-
- # Test if we are trying to use run time linking or normal
- # AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
- case $host_os in aix4.[23]|aix4.[23].*|aix5*)
- for ld_flag in $LDFLAGS; do
- if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
- aix_use_runtimelinking=yes
- break
- fi
- done
- esac
-
- exp_sym_flag='-bexport'
- no_entry_flag='-bnoentry'
- fi
-
- # When large executables or shared objects are built, AIX ld can
- # have problems creating the table of contents. If linking a library
- # or program results in "error TOC overflow" add -mminimal-toc to
- # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
- # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
- hardcode_direct=yes
- archive_cmds=''
- hardcode_libdir_separator=':'
- if test "$GCC" = yes; then
- case $host_os in aix4.[012]|aix4.[012].*)
- collect2name=`${CC} -print-prog-name=collect2`
- if test -f "$collect2name" && \
- strings "$collect2name" | grep resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- hardcode_direct=yes
- else
- # We have old collect2
- hardcode_direct=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- hardcode_minus_L=yes
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_libdir_separator=
- fi
- esac
-
- shared_flag='-shared'
- else
- # not using gcc
- if test "$host_cpu" = ia64; then
- shared_flag='${wl}-G'
- else
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag='${wl}-G'
- else
- shared_flag='${wl}-bM:SRE'
- fi
- fi
- fi
-
- # It seems that -bexpall can do strange things, so it is better to
- # generate a list of symbols to export.
- always_export_symbols=yes
- if test "$aix_use_runtimelinking" = yes; then
- # Warning - without using the other runtime loading flags (-brtl),
- # -berok will link without error, but may produce a broken library.
- allow_undefined_flag='-berok'
- hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
- archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
- else
- if test "$host_cpu" = ia64; then
- hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
- allow_undefined_flag="-z nodefs"
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
- else
- hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib'
- # Warning - without using the other run time loading flags,
- # -berok will link without error, but may produce a broken library.
- allow_undefined_flag='${wl}-berok'
- # This is a bit strange, but is similar to how AIX traditionally builds
- # it's shared libraries.
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname'
- fi
- fi
- ;;
-
- amigaos*)
- archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- # see comment about different semantics on the GNU ld section
- ld_shlibs=no
- ;;
-
- cygwin* | mingw* | pw32*)
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec=' '
- allow_undefined_flag=unsupported
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # FIXME: Setting linknames here is a bad hack.
- archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames='
- # The linker will automatically build a .lib file if we build a DLL.
- old_archive_from_new_cmds='true'
- # FIXME: Should let the user specify the lib program.
- old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs'
- fix_srcfile_path='`cygpath -w "$srcfile"`'
- ;;
-
- darwin* | rhapsody*)
- case "$host_os" in
- rhapsody* | darwin1.[012])
- allow_undefined_flag='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- allow_undefined_flag='-flat_namespace -undefined suppress'
- ;;
- esac
- # FIXME: Relying on posixy $() will cause problems for
- # cross-compilation, but unfortunately the echo tests do not
- # yet detect zsh echo's removal of \ escapes.
- archive_cmds='$nonopt $(test "x$module" = xyes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring'
- # We need to add '_' to the symbols in $export_symbols first
- #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- whole_archive_flag_spec='-all_load $convenience'
- ;;
-
- freebsd1*)
- ld_shlibs=no
- ;;
-
- # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
- # support. Future versions do this automatically, but an explicit c++rt0.o
- # does not break anything, and helps significantly (at the cost of a little
- # extra space).
- freebsd2.2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- # Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd*)
- archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- hpux9* | hpux10* | hpux11*)
- case $host_os in
- hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;;
- *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;;
- esac
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator=:
- hardcode_direct=yes
- hardcode_minus_L=yes # Not in the search PATH, but as the default
- # location of the library.
- export_dynamic_flag_spec='${wl}-E'
- ;;
-
- irix5* | irix6*)
- if test "$GCC" = yes; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- else
- archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
- fi
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- link_all_deplibs=yes
- ;;
-
- netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
- else
- archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
- fi
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- newsos6)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- hardcode_shlibpath_var=no
- ;;
-
- openbsd*)
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- export_dynamic_flag_spec='${wl}-E'
- else
- case "$host_os" in
- openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-R$libdir'
- ;;
- *)
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- ;;
- esac
- fi
- ;;
-
- os2*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- allow_undefined_flag=unsupported
- archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
- old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
- ;;
-
- osf3*)
- if test "$GCC" = yes; then
- allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- else
- allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
- fi
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- ;;
-
- osf4* | osf5*) # as osf3* with the addition of -msym flag
- if test "$GCC" = yes; then
- allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- else
- allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
- archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
- $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
-
- #Both c and cxx compiler support -rpath directly
- hardcode_libdir_flag_spec='-rpath $libdir'
- fi
- hardcode_libdir_separator=:
- ;;
-
- sco3.2v5*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- export_dynamic_flag_spec='${wl}-Bexport'
- ;;
-
- solaris*)
- # gcc --version < 3.0 without binutils cannot create self contained
- # shared libraries reliably, requiring libgcc.a to resolve some of
- # the object symbols generated in some cases. Libraries that use
- # assert need libgcc.a to resolve __eprintf, for example. Linking
- # a copy of libgcc.a into every shared library to guarantee resolving
- # such symbols causes other problems: According to Tim Van Holder
- # <tim.van.holder@pandora.be>, C++ libraries end up with a separate
- # (to the application) exception stack for one thing.
- no_undefined_flag=' -z defs'
- if test "$GCC" = yes; then
- case `$CC --version 2>/dev/null` in
- [12].*)
- cat <<EOF 1>&2
-
-*** Warning: Releases of GCC earlier than version 3.0 cannot reliably
-*** create self contained shared libraries on Solaris systems, without
-*** introducing a dependency on libgcc.a. Therefore, libtool is disabling
-*** -no-undefined support, which will at least allow you to build shared
-*** libraries. However, you may find that when you link such libraries
-*** into an application without using GCC, you have to manually add
-*** \`gcc --print-libgcc-file-name\` to the link command. We urge you to
-*** upgrade to a newer version of GCC. Another option is to rebuild your
-*** current GCC to use the GNU linker from GNU binutils 2.9.1 or newer.
-
-EOF
- no_undefined_flag=
- ;;
- esac
- fi
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_shlibpath_var=no
- case $host_os in
- solaris2.[0-5] | solaris2.[0-5].*) ;;
- *) # Supported since Solaris 2.6 (maybe 2.5.1?)
- whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
- esac
- link_all_deplibs=yes
- ;;
-
- sunos4*)
- if test "x$host_vendor" = xsequent; then
- # Use $CC to link under sequent, because it throws in some extra .o
- # files that make .init and .fini sections work.
- archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
- fi
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- sysv4)
- if test "x$host_vendor" = xsno; then
- archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes # is this really true???
- else
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=no #Motorola manual says yes, but my tests say they lie
- fi
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
- ;;
-
- sysv4.3*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- export_dynamic_flag_spec='-Bexport'
- ;;
-
- sysv5*)
- no_undefined_flag=' -z text'
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- hardcode_libdir_flag_spec=
- hardcode_shlibpath_var=no
- runpath_var='LD_RUN_PATH'
- ;;
-
- uts4*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- dgux*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ld_shlibs=yes
- fi
- ;;
-
- sysv4.2uw2*)
- archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_minus_L=no
- hardcode_shlibpath_var=no
- hardcode_runpath_var=yes
- runpath_var=LD_RUN_PATH
- ;;
-
- sysv5uw7* | unixware7*)
- no_undefined_flag='${wl}-z ${wl}text'
- if test "$GCC" = yes; then
- archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
- fi
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
- ;;
-
- *)
- ld_shlibs=no
- ;;
- esac
-fi
-echo "$as_me:$LINENO: result: $ld_shlibs" >&5
-echo "${ECHO_T}$ld_shlibs" >&6
-test "$ld_shlibs" = no && can_build_shared=no
-
-# Check hardcoding attributes.
-echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
-echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6
-hardcode_action=
-if test -n "$hardcode_libdir_flag_spec" || \
- test -n "$runpath_var"; then
-
- # We can hardcode non-existant directories.
- if test "$hardcode_direct" != no &&
- # If the only mechanism to avoid hardcoding is shlibpath_var, we
- # have to relink, otherwise we might link with an installed library
- # when we should be linking with a yet-to-be-installed one
- ## test "$hardcode_shlibpath_var" != no &&
- test "$hardcode_minus_L" != no; then
- # Linking always hardcodes the temporary library directory.
- hardcode_action=relink
- else
- # We can link without hardcoding, and we can hardcode nonexisting dirs.
- hardcode_action=immediate
- fi
-else
- # We cannot hardcode anything, or else we can only hardcode existing
- # directories.
- hardcode_action=unsupported
-fi
-echo "$as_me:$LINENO: result: $hardcode_action" >&5
-echo "${ECHO_T}$hardcode_action" >&6
-
-striplib=
-old_striplib=
-echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
-echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6
-if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
-else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-# PORTME Fill in your ld.so characteristics
-echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
-echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-
-case $host_os in
-aix3*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix $libname.a'
- shlibpath_var=LIBPATH
-
- # AIX has no versioning support, so we append a major version to the name.
- soname_spec='${libname}${release}.so$major'
- ;;
-
-aix4* | aix5*)
- version_type=linux
- if test "$host_cpu" = ia64; then
- # AIX 5 supports IA64
- library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- else
- # With GCC up to 2.95.x, collect2 would create an import file
- # for dependence libraries. The import file would start with
- # the line `#! .'. This would cause the generated library to
- # depend on `.', always an invalid library. This was fixed in
- # development snapshots of GCC prior to 3.0.
- case $host_os in
- aix4 | aix4.[01] | aix4.[01].*)
- if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
- echo ' yes '
- echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
- :
- else
- can_build_shared=no
- fi
- ;;
- esac
- # AIX (on Power*) has no versioning support, so currently we can
- # not hardcode correct soname into executable. Probably we can
- # add versioning support to collect2, so additional links can
- # be useful in future.
- if test "$aix_use_runtimelinking" = yes; then
- # If using run time linking (on AIX 4.2 or later) use lib<name>.so
- # instead of lib<name>.a to let people know that these are not
- # typical AIX shared libraries.
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- else
- # We preserve .a as extension for shared libraries through AIX4.2
- # and later when we are not doing run time linking.
- library_names_spec='${libname}${release}.a $libname.a'
- soname_spec='${libname}${release}.so$major'
- fi
- shlibpath_var=LIBPATH
- fi
- ;;
-
-amigaos*)
- library_names_spec='$libname.ixlibrary $libname.a'
- # Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done'
- ;;
-
-beos*)
- library_names_spec='${libname}.so'
- dynamic_linker="$host_os ld.so"
- shlibpath_var=LIBRARY_PATH
- ;;
-
-bsdi4*)
- version_type=linux
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
- sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
- export_dynamic_flag_spec=-rdynamic
- # the default ld.so.conf also contains /usr/contrib/lib and
- # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
- # libtool to hard-code these into programs
- ;;
-
-cygwin* | mingw* | pw32*)
- version_type=windows
- need_version=no
- need_lib_prefix=no
- case $GCC,$host_os in
- yes,cygwin*)
- library_names_spec='$libname.dll.a'
- soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll'
- postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog .libs/$dlname \$dldir/$dlname'
- postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $rm \$dlpath'
- ;;
- yes,mingw*)
- library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll'
- sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"`
- ;;
- yes,pw32*)
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/./-/g'`${versuffix}.dll'
- ;;
- *)
- library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib'
- ;;
- esac
- dynamic_linker='Win32 ld.exe'
- # FIXME: first we should search . and the directory the executable is in
- shlibpath_var=PATH
- ;;
-
-darwin* | rhapsody*)
- dynamic_linker="$host_os dyld"
- version_type=darwin
- need_lib_prefix=no
- need_version=no
- # FIXME: Relying on posixy $() will cause problems for
- # cross-compilation, but unfortunately the echo tests do not
- # yet detect zsh echo's removal of \ escapes.
- library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)'
- soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)'
- shlibpath_overrides_runpath=yes
- shlibpath_var=DYLD_LIBRARY_PATH
- ;;
-
-freebsd1*)
- dynamic_linker=no
- ;;
-
-freebsd*)
- objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
- version_type=freebsd-$objformat
- case $version_type in
- freebsd-elf*)
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
- need_version=no
- need_lib_prefix=no
- ;;
- freebsd-*)
- library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix'
- need_version=yes
- ;;
- esac
- shlibpath_var=LD_LIBRARY_PATH
- case $host_os in
- freebsd2*)
- shlibpath_overrides_runpath=yes
- ;;
- *)
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
- esac
- ;;
-
-gnu*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- hardcode_into_libs=yes
- ;;
-
-hpux9* | hpux10* | hpux11*)
- # Give a soname corresponding to the major version so that dld.sl refuses to
- # link against other versions.
- dynamic_linker="$host_os dld.sl"
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- shlibpath_var=SHLIB_PATH
- shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl'
- soname_spec='${libname}${release}.sl$major'
- # HP-UX runs *really* slowly unless shared libraries are mode 555.
- postinstall_cmds='chmod 555 $lib'
- ;;
-
-irix5* | irix6*)
- version_type=irix
- need_lib_prefix=no
- need_version=no
- soname_spec='${libname}${release}.so$major'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so'
- case $host_os in
- irix5*)
- libsuff= shlibsuff=
- ;;
- *)
- case $LD in # libtool.m4 will add one of these switches to LD
- *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;;
- *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;;
- *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;;
- *) libsuff= shlibsuff= libmagic=never-match;;
- esac
- ;;
- esac
- shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
- sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
- ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*)
- dynamic_linker=no
- ;;
-
-# This must be Linux ELF.
-linux-gnu*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- # This implies no fast_install, which is unacceptable.
- # Some rework will be needed to allow for fast_install
- # before this can be enabled.
- hardcode_into_libs=yes
-
- # We used to test for /lib/ld.so.1 and disable shared libraries on
- # powerpc, because MkLinux only supported shared libraries with the
- # GNU dynamic linker. Since this was broken with cross compilers,
- # most powerpc-linux boxes support dynamic linking these days and
- # people can always --disable-shared, the test was removed, and we
- # assume the GNU/Linux dynamic linker is in use.
- dynamic_linker='GNU/Linux ld.so'
- ;;
-
-netbsd*)
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- dynamic_linker='NetBSD (a.out) ld.so'
- else
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so'
- soname_spec='${libname}${release}.so$major'
- dynamic_linker='NetBSD ld.elf_so'
- fi
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
-
-newsos6)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- ;;
-
-openbsd*)
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- case "$host_os" in
- openbsd2.[89] | openbsd2.[89].*)
- shlibpath_overrides_runpath=no
- ;;
- *)
- shlibpath_overrides_runpath=yes
- ;;
- esac
- else
- shlibpath_overrides_runpath=yes
- fi
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-os2*)
- libname_spec='$name'
- need_lib_prefix=no
- library_names_spec='$libname.dll $libname.a'
- dynamic_linker='OS/2 ld.exe'
- shlibpath_var=LIBPATH
- ;;
-
-osf3* | osf4* | osf5*)
- version_type=osf
- need_version=no
- soname_spec='${libname}${release}.so'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
- ;;
-
-sco3.2v5*)
- version_type=osf
- soname_spec='${libname}${release}.so$major'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-solaris*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- # ldd complains unless libraries are executable
- postinstall_cmds='chmod +x $lib'
- ;;
-
-sunos4*)
- version_type=sunos
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- if test "$with_gnu_ld" = yes; then
- need_lib_prefix=no
- fi
- need_version=yes
- ;;
-
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- case $host_vendor in
- sni)
- shlibpath_overrides_runpath=no
- ;;
- motorola)
- need_lib_prefix=no
- need_version=no
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
- ;;
- esac
- ;;
-
-uts4*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-dgux*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-sysv4*MP*)
- if test -d /usr/nec ;then
- version_type=linux
- library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so'
- soname_spec='$libname.so.$major'
- shlibpath_var=LD_LIBRARY_PATH
- fi
- ;;
-
-*)
- dynamic_linker=no
- ;;
-esac
-echo "$as_me:$LINENO: result: $dynamic_linker" >&5
-echo "${ECHO_T}$dynamic_linker" >&6
-test "$dynamic_linker" = no && can_build_shared=no
-
-# Report the final consequences.
-echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
-echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6
-echo "$as_me:$LINENO: result: $can_build_shared" >&5
-echo "${ECHO_T}$can_build_shared" >&6
-
-echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
-echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6
-test "$can_build_shared" = "no" && enable_shared=no
-
-# On AIX, shared libraries and static libraries use the same namespace, and
-# are all built from PIC.
-case "$host_os" in
-aix3*)
- test "$enable_shared" = yes && enable_static=no
- if test -n "$RANLIB"; then
- archive_cmds="$archive_cmds~\$RANLIB \$lib"
- postinstall_cmds='$RANLIB $lib'
- fi
- ;;
-
-aix4*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
- fi
- ;;
-esac
-echo "$as_me:$LINENO: result: $enable_shared" >&5
-echo "${ECHO_T}$enable_shared" >&6
-
-echo "$as_me:$LINENO: checking whether to build static libraries" >&5
-echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6
-# Make sure either enable_shared or enable_static is yes.
-test "$enable_shared" = yes || enable_static=yes
-echo "$as_me:$LINENO: result: $enable_static" >&5
-echo "${ECHO_T}$enable_static" >&6
-
-if test "$hardcode_action" = relink; then
- # Fast installation is not supported
- enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
- test "$enable_shared" = no; then
- # Fast installation is not necessary
- enable_fast_install=needless
-fi
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-if test "x$enable_dlopen" != xyes; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
- lt_cv_dlopen=no
- lt_cv_dlopen_libs=
-
- case $host_os in
- beos*)
- lt_cv_dlopen="load_add_on"
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
- ;;
-
- cygwin* | mingw* | pw32*)
- lt_cv_dlopen="LoadLibrary"
- lt_cv_dlopen_libs=
- ;;
-
- *)
- echo "$as_me:$LINENO: checking for shl_load" >&5
-echo $ECHO_N "checking for shl_load... $ECHO_C" >&6
-if test "${ac_cv_func_shl_load+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char shl_load (); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char shl_load ();
-char (*f) ();
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub_shl_load) || defined (__stub___shl_load)
-choke me
-#else
-f = shl_load;
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_func_shl_load=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_func_shl_load=no
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
-echo "${ECHO_T}$ac_cv_func_shl_load" >&6
-if test $ac_cv_func_shl_load = yes; then
- lt_cv_dlopen="shl_load"
-else
- echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
-echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
-if test "${ac_cv_lib_dld_shl_load+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char shl_load ();
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-shl_load ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dld_shl_load=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_lib_dld_shl_load=no
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
-echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
-if test $ac_cv_lib_dld_shl_load = yes; then
- lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
-else
- echo "$as_me:$LINENO: checking for dlopen" >&5
-echo $ECHO_N "checking for dlopen... $ECHO_C" >&6
-if test "${ac_cv_func_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char dlopen (); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-char (*f) ();
-
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub_dlopen) || defined (__stub___dlopen)
-choke me
-#else
-f = dlopen;
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_func_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_func_dlopen=no
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
-echo "${ECHO_T}$ac_cv_func_dlopen" >&6
-if test $ac_cv_func_dlopen = yes; then
- lt_cv_dlopen="dlopen"
-else
- echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
-echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
-if test "${ac_cv_lib_dl_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-dlopen ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dl_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_lib_dl_dlopen=no
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
-echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
-if test $ac_cv_lib_dl_dlopen = yes; then
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
-else
- echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
-echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6
-if test "${ac_cv_lib_svld_dlopen+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsvld $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-dlopen ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_svld_dlopen=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_lib_svld_dlopen=no
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
-echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6
-if test $ac_cv_lib_svld_dlopen = yes; then
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
-else
- echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
-echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6
-if test "${ac_cv_lib_dld_dld_link+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dld_link ();
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-dld_link ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_dld_dld_link=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_lib_dld_dld_link=no
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
-echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6
-if test $ac_cv_lib_dld_dld_link = yes; then
- lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
- ;;
- esac
-
- if test "x$lt_cv_dlopen" != xno; then
- enable_dlopen=yes
- else
- enable_dlopen=no
- fi
-
- case $lt_cv_dlopen in
- dlopen)
- save_CPPFLAGS="$CPPFLAGS"
- test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
- save_LDFLAGS="$LDFLAGS"
- eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
- save_LIBS="$LIBS"
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
-echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6
-if test "${lt_cv_dlopen_self+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test "$cross_compiling" = yes; then :
- lt_cv_dlopen_self=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<EOF
-#line 7735 "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" void exit (int);
-#endif
-
-void fnord() { int i=42;}
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- /* dlclose (self); */
- }
-
- exit (status);
-}
-EOF
- if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_unknown|x*) lt_cv_dlopen_self=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
-echo "${ECHO_T}$lt_cv_dlopen_self" >&6
-
- if test "x$lt_cv_dlopen_self" = xyes; then
- LDFLAGS="$LDFLAGS $link_static_flag"
- echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
-echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6
-if test "${lt_cv_dlopen_self_static+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- if test "$cross_compiling" = yes; then :
- lt_cv_dlopen_self_static=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<EOF
-#line 7833 "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" void exit (int);
-#endif
-
-void fnord() { int i=42;}
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- /* dlclose (self); */
- }
-
- exit (status);
-}
-EOF
- if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_unknown|x*) lt_cv_dlopen_self_static=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self_static=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
-echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6
- fi
-
- CPPFLAGS="$save_CPPFLAGS"
- LDFLAGS="$save_LDFLAGS"
- LIBS="$save_LIBS"
- ;;
- esac
-
- case $lt_cv_dlopen_self in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case $lt_cv_dlopen_self_static in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-
-
-if test "$enable_shared" = yes && test "$GCC" = yes; then
- case $archive_cmds in
- *'~'*)
- # FIXME: we may have to deal with multi-command sequences.
- ;;
- '$CC '*)
- # Test whether the compiler implicitly links with -lc since on some
- # systems, -lgcc has to come before -lc. If gcc already passes -lc
- # to ld, don't add -lc before -lgcc.
- echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
-echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6
- if test "${lt_cv_archive_cmds_need_lc+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- $rm conftest*
- echo 'static int dummy;' > conftest.$ac_ext
-
- if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; then
- soname=conftest
- lib=conftest
- libobjs=conftest.$ac_objext
- deplibs=
- wl=$lt_cv_prog_cc_wl
- compiler_flags=-v
- linker_flags=-v
- verstring=
- output_objdir=.
- libname=conftest
- save_allow_undefined_flag=$allow_undefined_flag
- allow_undefined_flag=
- if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
- (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }
- then
- lt_cv_archive_cmds_need_lc=no
- else
- lt_cv_archive_cmds_need_lc=yes
- fi
- allow_undefined_flag=$save_allow_undefined_flag
- else
- cat conftest.err 1>&5
- fi
-fi
-
- echo "$as_me:$LINENO: result: $lt_cv_archive_cmds_need_lc" >&5
-echo "${ECHO_T}$lt_cv_archive_cmds_need_lc" >&6
- ;;
- esac
-fi
-need_lc=${lt_cv_archive_cmds_need_lc-yes}
-
-# The second clause should only fire when bootstrapping the
-# libtool distribution, otherwise you forgot to ship ltmain.sh
-# with your package, and you will get complaints that there are
-# no rules to generate ltmain.sh.
-if test -f "$ltmain"; then
- :
-else
- # If there is no Makefile yet, we rely on a make rule to execute
- # `config.status --recheck' to rerun these tests and create the
- # libtool script then.
- test -f Makefile && make "$ltmain"
-fi
-
-if test -f "$ltmain"; then
- trap "$rm \"${ofile}T\"; exit 1" 1 2 15
- $rm -f "${ofile}T"
-
- echo creating $ofile
-
- # Now quote all the things that may contain metacharacters while being
- # careful not to overquote the AC_SUBSTed values. We take copies of the
- # variables and quote the copies for generation of the libtool script.
- for var in echo old_CC old_CFLAGS \
- AR AR_FLAGS CC LD LN_S NM SHELL \
- reload_flag reload_cmds wl \
- pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \
- thread_safe_flag_spec whole_archive_flag_spec libname_spec \
- library_names_spec soname_spec \
- RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \
- old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \
- postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \
- old_striplib striplib file_magic_cmd export_symbols_cmds \
- deplibs_check_method allow_undefined_flag no_undefined_flag \
- finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \
- global_symbol_to_c_name_address \
- hardcode_libdir_flag_spec hardcode_libdir_separator \
- sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
- compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do
-
- case $var in
- reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \
- old_postinstall_cmds | old_postuninstall_cmds | \
- export_symbols_cmds | archive_cmds | archive_expsym_cmds | \
- extract_expsyms_cmds | old_archive_from_expsyms_cmds | \
- postinstall_cmds | postuninstall_cmds | \
- finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
- # Double-quote double-evaled strings.
- eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
- ;;
- *)
- eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
- ;;
- esac
- done
-
- cat <<__EOF__ > "${ofile}T"
-#! $SHELL
-
-# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-#
-# Copyright (C) 1996-2000 Free Software Foundation, Inc.
-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="sed -e s/^X//"
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
-
-# ### BEGIN LIBTOOL CONFIG
-
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-
-# Shell to use when invoking shell scripts.
-SHELL=$lt_SHELL
-
-# Whether or not to build shared libraries.
-build_libtool_libs=$enable_shared
-
-# Whether or not to build static libraries.
-build_old_libs=$enable_static
-
-# Whether or not to add -lc for building shared libraries.
-build_libtool_need_lc=$need_lc
-
-# Whether or not to optimize for fast installation.
-fast_install=$enable_fast_install
-
-# The host system.
-host_alias=$host_alias
-host=$host
-
-# An echo program that does not interpret backslashes.
-echo=$lt_echo
-
-# The archiver.
-AR=$lt_AR
-AR_FLAGS=$lt_AR_FLAGS
-
-# The default C compiler.
-CC=$lt_CC
-
-# Is the compiler the GNU C compiler?
-with_gcc=$GCC
-
-# The linker used to build libraries.
-LD=$lt_LD
-
-# Whether we need hard or soft links.
-LN_S=$lt_LN_S
-
-# A BSD-compatible nm program.
-NM=$lt_NM
-
-# A symbol stripping program
-STRIP=$STRIP
-
-# Used to examine libraries when file_magic_cmd begins "file"
-MAGIC_CMD=$MAGIC_CMD
-
-# Used on cygwin: DLL creation program.
-DLLTOOL="$DLLTOOL"
-
-# Used on cygwin: object dumper.
-OBJDUMP="$OBJDUMP"
-
-# Used on cygwin: assembler.
-AS="$AS"
-
-# The name of the directory that contains temporary libtool files.
-objdir=$objdir
-
-# How to create reloadable object files.
-reload_flag=$lt_reload_flag
-reload_cmds=$lt_reload_cmds
-
-# How to pass a linker flag through the compiler.
-wl=$lt_wl
-
-# Object file suffix (normally "o").
-objext="$ac_objext"
-
-# Old archive suffix (normally "a").
-libext="$libext"
-
-# Executable file suffix (normally "").
-exeext="$exeext"
-
-# Additional compiler flags for building library objects.
-pic_flag=$lt_pic_flag
-pic_mode=$pic_mode
-
-# Does compiler simultaneously support -c and -o options?
-compiler_c_o=$lt_compiler_c_o
-
-# Can we write directly to a .lo ?
-compiler_o_lo=$lt_compiler_o_lo
-
-# Must we lock files when doing compilation ?
-need_locks=$lt_need_locks
-
-# Do we need the lib prefix for modules?
-need_lib_prefix=$need_lib_prefix
-
-# Do we need a version for libraries?
-need_version=$need_version
-
-# Whether dlopen is supported.
-dlopen_support=$enable_dlopen
-
-# Whether dlopen of programs is supported.
-dlopen_self=$enable_dlopen_self
-
-# Whether dlopen of statically linked programs is supported.
-dlopen_self_static=$enable_dlopen_self_static
-
-# Compiler flag to prevent dynamic linking.
-link_static_flag=$lt_link_static_flag
-
-# Compiler flag to turn off builtin functions.
-no_builtin_flag=$lt_no_builtin_flag
-
-# Compiler flag to allow reflexive dlopens.
-export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
-
-# Compiler flag to generate shared objects directly from archives.
-whole_archive_flag_spec=$lt_whole_archive_flag_spec
-
-# Compiler flag to generate thread-safe objects.
-thread_safe_flag_spec=$lt_thread_safe_flag_spec
-
-# Library versioning type.
-version_type=$version_type
-
-# Format of library name prefix.
-libname_spec=$lt_libname_spec
-
-# List of archive names. First name is the real one, the rest are links.
-# The last name is the one that the linker finds with -lNAME.
-library_names_spec=$lt_library_names_spec
-
-# The coded name of the library, if different from the real name.
-soname_spec=$lt_soname_spec
-
-# Commands used to build and install an old-style archive.
-RANLIB=$lt_RANLIB
-old_archive_cmds=$lt_old_archive_cmds
-old_postinstall_cmds=$lt_old_postinstall_cmds
-old_postuninstall_cmds=$lt_old_postuninstall_cmds
-
-# Create an old-style archive from a shared archive.
-old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
-
-# Create a temporary old-style archive to link instead of a shared archive.
-old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
-
-# Commands used to build and install a shared archive.
-archive_cmds=$lt_archive_cmds
-archive_expsym_cmds=$lt_archive_expsym_cmds
-postinstall_cmds=$lt_postinstall_cmds
-postuninstall_cmds=$lt_postuninstall_cmds
-
-# Commands to strip libraries.
-old_striplib=$lt_old_striplib
-striplib=$lt_striplib
-
-# Method to check whether dependent libraries are shared objects.
-deplibs_check_method=$lt_deplibs_check_method
-
-# Command to use when deplibs_check_method == file_magic.
-file_magic_cmd=$lt_file_magic_cmd
-
-# Flag that allows shared libraries with undefined symbols to be built.
-allow_undefined_flag=$lt_allow_undefined_flag
-
-# Flag that forces no undefined symbols.
-no_undefined_flag=$lt_no_undefined_flag
-
-# Commands used to finish a libtool library installation in a directory.
-finish_cmds=$lt_finish_cmds
-
-# Same as above, but a single script fragment to be evaled but not shown.
-finish_eval=$lt_finish_eval
-
-# Take the output of nm and produce a listing of raw symbols and C names.
-global_symbol_pipe=$lt_global_symbol_pipe
-
-# Transform the output of nm in a proper C declaration
-global_symbol_to_cdecl=$lt_global_symbol_to_cdecl
-
-# Transform the output of nm in a C name address pair
-global_symbol_to_c_name_address=$lt_global_symbol_to_c_name_address
-
-# This is the shared library runtime path variable.
-runpath_var=$runpath_var
-
-# This is the shared library path variable.
-shlibpath_var=$shlibpath_var
-
-# Is shlibpath searched before the hard-coded library search path?
-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
-
-# How to hardcode a shared library path into an executable.
-hardcode_action=$hardcode_action
-
-# Whether we should hardcode library paths into libraries.
-hardcode_into_libs=$hardcode_into_libs
-
-# Flag to hardcode \$libdir into a binary during linking.
-# This must work even if \$libdir does not exist.
-hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
-
-# Whether we need a single -rpath flag with a separated argument.
-hardcode_libdir_separator=$lt_hardcode_libdir_separator
-
-# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
-# resulting binary.
-hardcode_direct=$hardcode_direct
-
-# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
-# resulting binary.
-hardcode_minus_L=$hardcode_minus_L
-
-# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
-# the resulting binary.
-hardcode_shlibpath_var=$hardcode_shlibpath_var
-
-# Variables whose values should be saved in libtool wrapper scripts and
-# restored at relink time.
-variables_saved_for_relink="$variables_saved_for_relink"
-
-# Whether libtool must link a program against all its dependency libraries.
-link_all_deplibs=$link_all_deplibs
-
-# Compile-time system search path for libraries
-sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
-
-# Run-time system search path for libraries
-sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
-
-# Fix the shell variable \$srcfile for the compiler.
-fix_srcfile_path="$fix_srcfile_path"
-
-# Set to yes if exported symbols are required.
-always_export_symbols=$always_export_symbols
-
-# The commands to list exported symbols.
-export_symbols_cmds=$lt_export_symbols_cmds
-
-# The commands to extract the exported symbol list from a shared archive.
-extract_expsyms_cmds=$lt_extract_expsyms_cmds
-
-# Symbols that should not be listed in the preloaded symbols.
-exclude_expsyms=$lt_exclude_expsyms
-
-# Symbols that must always be exported.
-include_expsyms=$lt_include_expsyms
-
-# ### END LIBTOOL CONFIG
-
-__EOF__
-
- case $host_os in
- aix3*)
- cat <<\EOF >> "${ofile}T"
-
-# AIX sometimes has problems with the GCC collect2 program. For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
- COLLECT_NAMES=
- export COLLECT_NAMES
-fi
-EOF
- ;;
- esac
-
- case $host_os in
- cygwin* | mingw* | pw32* | os2*)
- cat <<'EOF' >> "${ofile}T"
- # This is a source program that is used to create dlls on Windows
- # Don't remove nor modify the starting and closing comments
-# /* ltdll.c starts here */
-# #define WIN32_LEAN_AND_MEAN
-# #include <windows.h>
-# #undef WIN32_LEAN_AND_MEAN
-# #include <stdio.h>
-#
-# #ifndef __CYGWIN__
-# # ifdef __CYGWIN32__
-# # define __CYGWIN__ __CYGWIN32__
-# # endif
-# #endif
-#
-# #ifdef __cplusplus
-# extern "C" {
-# #endif
-# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
-# #ifdef __cplusplus
-# }
-# #endif
-#
-# #ifdef __CYGWIN__
-# #include <cygwin/cygwin_dll.h>
-# DECLARE_CYGWIN_DLL( DllMain );
-# #endif
-# HINSTANCE __hDllInstance_base;
-#
-# BOOL APIENTRY
-# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
-# {
-# __hDllInstance_base = hInst;
-# return TRUE;
-# }
-# /* ltdll.c ends here */
- # This is a source program that is used to create import libraries
- # on Windows for dlls which lack them. Don't remove nor modify the
- # starting and closing comments
-# /* impgen.c starts here */
-# /* Copyright (C) 1999-2000 Free Software Foundation, Inc.
-#
-# This file is part of GNU libtool.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-# */
-#
-# #include <stdio.h> /* for printf() */
-# #include <unistd.h> /* for open(), lseek(), read() */
-# #include <fcntl.h> /* for O_RDONLY, O_BINARY */
-# #include <string.h> /* for strdup() */
-#
-# /* O_BINARY isn't required (or even defined sometimes) under Unix */
-# #ifndef O_BINARY
-# #define O_BINARY 0
-# #endif
-#
-# static unsigned int
-# pe_get16 (fd, offset)
-# int fd;
-# int offset;
-# {
-# unsigned char b[2];
-# lseek (fd, offset, SEEK_SET);
-# read (fd, b, 2);
-# return b[0] + (b[1]<<8);
-# }
-#
-# static unsigned int
-# pe_get32 (fd, offset)
-# int fd;
-# int offset;
-# {
-# unsigned char b[4];
-# lseek (fd, offset, SEEK_SET);
-# read (fd, b, 4);
-# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# static unsigned int
-# pe_as32 (ptr)
-# void *ptr;
-# {
-# unsigned char *b = ptr;
-# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# int
-# main (argc, argv)
-# int argc;
-# char *argv[];
-# {
-# int dll;
-# unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
-# unsigned long export_rva, export_size, nsections, secptr, expptr;
-# unsigned long name_rvas, nexp;
-# unsigned char *expdata, *erva;
-# char *filename, *dll_name;
-#
-# filename = argv[1];
-#
-# dll = open(filename, O_RDONLY|O_BINARY);
-# if (dll < 1)
-# return 1;
-#
-# dll_name = filename;
-#
-# for (i=0; filename[i]; i++)
-# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':')
-# dll_name = filename + i +1;
-#
-# pe_header_offset = pe_get32 (dll, 0x3c);
-# opthdr_ofs = pe_header_offset + 4 + 20;
-# num_entries = pe_get32 (dll, opthdr_ofs + 92);
-#
-# if (num_entries < 1) /* no exports */
-# return 1;
-#
-# export_rva = pe_get32 (dll, opthdr_ofs + 96);
-# export_size = pe_get32 (dll, opthdr_ofs + 100);
-# nsections = pe_get16 (dll, pe_header_offset + 4 +2);
-# secptr = (pe_header_offset + 4 + 20 +
-# pe_get16 (dll, pe_header_offset + 4 + 16));
-#
-# expptr = 0;
-# for (i = 0; i < nsections; i++)
-# {
-# char sname[8];
-# unsigned long secptr1 = secptr + 40 * i;
-# unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
-# unsigned long vsize = pe_get32 (dll, secptr1 + 16);
-# unsigned long fptr = pe_get32 (dll, secptr1 + 20);
-# lseek(dll, secptr1, SEEK_SET);
-# read(dll, sname, 8);
-# if (vaddr <= export_rva && vaddr+vsize > export_rva)
-# {
-# expptr = fptr + (export_rva - vaddr);
-# if (export_rva + export_size > vaddr + vsize)
-# export_size = vsize - (export_rva - vaddr);
-# break;
-# }
-# }
-#
-# expdata = (unsigned char*)malloc(export_size);
-# lseek (dll, expptr, SEEK_SET);
-# read (dll, expdata, export_size);
-# erva = expdata - export_rva;
-#
-# nexp = pe_as32 (expdata+24);
-# name_rvas = pe_as32 (expdata+32);
-#
-# printf ("EXPORTS\n");
-# for (i = 0; i<nexp; i++)
-# {
-# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4);
-# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i);
-# }
-#
-# return 0;
-# }
-# /* impgen.c ends here */
-
-EOF
- ;;
- esac
-
- # We use sed instead of cat because bash on DJGPP gets confused if
- # if finds mixed CR/LF and LF-only lines. Since sed operates in
- # text mode, it properly converts lines to CR/LF. This bash problem
- # is reportedly fixed, but why not run on old versions too?
- sed '$q' "$ltmain" >> "${ofile}T" || (rm -f "${ofile}T"; exit 1)
-
- mv -f "${ofile}T" "$ofile" || \
- (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T")
- chmod +x "$ofile"
-fi
-
-
-
-
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-
-# Prevent multiple expansion
-
-
-
-#
-# Check for AViiON Machines running DGUX
-#
-ac_is_dgux=no
-if test "${ac_cv_header_sys_dg_sys_info_h+set}" = set; then
- echo "$as_me:$LINENO: checking for sys/dg_sys_info.h" >&5
-echo $ECHO_N "checking for sys/dg_sys_info.h... $ECHO_C" >&6
-if test "${ac_cv_header_sys_dg_sys_info_h+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-fi
-echo "$as_me:$LINENO: result: $ac_cv_header_sys_dg_sys_info_h" >&5
-echo "${ECHO_T}$ac_cv_header_sys_dg_sys_info_h" >&6
-else
- # Is the header compilable?
-echo "$as_me:$LINENO: checking sys/dg_sys_info.h usability" >&5
-echo $ECHO_N "checking sys/dg_sys_info.h usability... $ECHO_C" >&6
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-$ac_includes_default
-#include <sys/dg_sys_info.h>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest.$ac_objext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_header_compiler=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_header_compiler=no
-fi
-rm -f conftest.$ac_objext conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-echo "${ECHO_T}$ac_header_compiler" >&6
-
-# Is the header present?
-echo "$as_me:$LINENO: checking sys/dg_sys_info.h presence" >&5
-echo $ECHO_N "checking sys/dg_sys_info.h presence... $ECHO_C" >&6
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-#include <sys/dg_sys_info.h>
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
- (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
- ac_status=$?
- egrep -v '^ *\+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } >/dev/null; then
- if test -s conftest.err; then
- ac_cpp_err=$ac_c_preproc_warn_flag
- else
- ac_cpp_err=
- fi
-else
- ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
- ac_header_preproc=yes
-else
- echo "$as_me: failed program was:" >&5
- cat conftest.$ac_ext >&5
- ac_header_preproc=no
-fi
-rm -f conftest.err conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-echo "${ECHO_T}$ac_header_preproc" >&6
-
-# So? What about this header?
-case $ac_header_compiler:$ac_header_preproc in
- yes:no )
- { echo "$as_me:$LINENO: WARNING: sys/dg_sys_info.h: accepted by the compiler, rejected by the preprocessor!" >&5
-echo "$as_me: WARNING: sys/dg_sys_info.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
- { echo "$as_me:$LINENO: WARNING: sys/dg_sys_info.h: proceeding with the preprocessor's result" >&5
-echo "$as_me: WARNING: sys/dg_sys_info.h: proceeding with the preprocessor's result" >&2;};;
- no:yes )
- { echo "$as_me:$LINENO: WARNING: sys/dg_sys_info.h: present but cannot be compiled" >&5
-echo "$as_me: WARNING: sys/dg_sys_info.h: present but cannot be compiled" >&2;}
- { echo "$as_me:$LINENO: WARNING: sys/dg_sys_info.h: check for missing prerequisite headers?" >&5
-echo "$as_me: WARNING: sys/dg_sys_info.h: check for missing prerequisite headers?" >&2;}
- { echo "$as_me:$LINENO: WARNING: sys/dg_sys_info.h: proceeding with the preprocessor's result" >&5
-echo "$as_me: WARNING: sys/dg_sys_info.h: proceeding with the preprocessor's result" >&2;};;
-esac
-echo "$as_me:$LINENO: checking for sys/dg_sys_info.h" >&5
-echo $ECHO_N "checking for sys/dg_sys_info.h... $ECHO_C" >&6
-if test "${ac_cv_header_sys_dg_sys_info_h+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_cv_header_sys_dg_sys_info_h=$ac_header_preproc
-fi
-echo "$as_me:$LINENO: result: $ac_cv_header_sys_dg_sys_info_h" >&5
-echo "${ECHO_T}$ac_cv_header_sys_dg_sys_info_h" >&6
-
-fi
-if test $ac_cv_header_sys_dg_sys_info_h = yes; then
- ac_is_dgux=yes;
-fi
-
-
-
- ## :GOTCHA: we do not check anything but sys/dg_sys_info.h
-if test $ac_is_dgux = yes; then
- if test "$enable_full_debug" = "yes"; then
- CFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
- CXXFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
- else
- CFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
- CXXFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
- fi
-
-
-fi
-
-
-# Check whether --with-target-subdir or --without-target-subdir was given.
-if test "${with_target_subdir+set}" = set; then
- withval="$with_target_subdir"
-
-fi;
-
-# Check whether --with-cross-host or --without-cross-host was given.
-if test "${with_cross_host+set}" = set; then
- withval="$with_cross_host"
-
-fi;
-
-# automake wants to see AC_EXEEXT. But we don't need it. And having
-# it is actually a problem, because the compiler we're passed can't
-# necessarily do a full link. So we fool automake here.
-if false; then
- # autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
- # to nothing, so nothing would remain between `then' and `fi' if it
- # were not for the `:' below.
- :
-
-fi
-
-echo "$as_me:$LINENO: checking whether Solaris gcc optimization fix is necessary" >&5
-echo $ECHO_N "checking whether Solaris gcc optimization fix is necessary... $ECHO_C" >&6
-case "$host" in
- sparc-sun-solaris2*|*aix*)
- if test "$GCC" = yes; then
- echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
- new_CFLAGS=
- for i in $CFLAGS; do
- case "$i" in
- -O*)
- ;;
- *)
- new_CFLAGS="$new_CFLAGS $i"
- ;;
- esac
- done
- CFLAGS="$new_CFLAGS"
- else
- echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
- fi
- ;;
- *) echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6 ;;
-esac
-
-MY_CFLAGS="$CFLAGS"
-
-
-cat >>confdefs.h <<\_ACEOF
-#define SILENT 1
-_ACEOF
-
-cat >>confdefs.h <<\_ACEOF
-#define NO_SIGNALS 1
-_ACEOF
-
-cat >>confdefs.h <<\_ACEOF
-#define NO_EXECUTE_PERMISSION 1
-_ACEOF
-
-cat >>confdefs.h <<\_ACEOF
-#define ALL_INTERIOR_POINTERS 1
-_ACEOF
-
-
-cat >>confdefs.h <<\_ACEOF
-#define JAVA_FINALIZATION 1
-_ACEOF
-
-cat >>confdefs.h <<\_ACEOF
-#define GC_GCJ_SUPPORT 1
-_ACEOF
-
-cat >>confdefs.h <<\_ACEOF
-#define ATOMIC_UNCOLLECTABLE 1
-_ACEOF
-
-
-if test -n "${with_cross_host}"; then
- cat >>confdefs.h <<\_ACEOF
-#define NO_SIGSET 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define NO_CLOCK 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define SMALL_CONFIG 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define NO_DEBUGGING 1
-_ACEOF
-
-fi
-
-UNWINDLIBS=
-# Check whether --enable-full-debug or --disable-full-debug was given.
-if test "${enable_full_debug+set}" = set; then
- enableval="$enable_full_debug"
- if test "$enable_full_debug" = "yes"; then
- { echo "$as_me:$LINENO: WARNING: \"Should define GC_DEBUG and use debug alloc. in clients.\"" >&5
-echo "$as_me: WARNING: \"Should define GC_DEBUG and use debug alloc. in clients.\"" >&2;}
- cat >>confdefs.h <<\_ACEOF
-#define KEEP_BACK_PTRS 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define DBG_HDRS_ALL 1
-_ACEOF
-
- case $host in
- ia64-*-linux* )
- cat >>confdefs.h <<\_ACEOF
-#define MAKE_BACK_GRAPH 1
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define SAVE_CALL_COUNT 8
-_ACEOF
-
- echo "$as_me:$LINENO: checking for backtrace in -lunwind" >&5
-echo $ECHO_N "checking for backtrace in -lunwind... $ECHO_C" >&6
-if test "${ac_cv_lib_unwind_backtrace+set}" = set; then
- echo $ECHO_N "(cached) $ECHO_C" >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lunwind $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-/* Override any gcc2 internal prototype to avoid an error. */
-#ifdef __cplusplus
-extern "C"
-#endif
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char backtrace ();
-#ifdef F77_DUMMY_MAIN
-# ifdef __cplusplus
- extern "C"
-# endif
- int F77_DUMMY_MAIN() { return 1; }
-#endif
-int
-main ()
-{
-backtrace ();
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } &&
- { ac_try='test -s conftest$ac_exeext'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
- ac_cv_lib_unwind_backtrace=yes
-else
- echo "$as_me: failed program was:" >&5
-cat conftest.$ac_ext >&5
-ac_cv_lib_unwind_backtrace=no
-fi
-rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_unwind_backtrace" >&5
-echo "${ECHO_T}$ac_cv_lib_unwind_backtrace" >&6
-if test $ac_cv_lib_unwind_backtrace = yes; then
-
- cat >>confdefs.h <<\_ACEOF
-#define GC_HAVE_BUILTIN_BACKTRACE 1
-_ACEOF
-
- UNWINDLIBS=-lunwind
- { echo "$as_me:$LINENO: WARNING: \"Client code may need to link against libunwind.\"" >&5
-echo "$as_me: WARNING: \"Client code may need to link against libunwind.\"" >&2;}
-
-fi
-
- ;;
- x86-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
- cat >>confdefs.h <<\_ACEOF
-#define MAKE_BACK_GRAPH 1
-_ACEOF
-
- { echo "$as_me:$LINENO: WARNING: \"Client must not use -fomit-frame-pointer.\"" >&5
-echo "$as_me: WARNING: \"Client must not use -fomit-frame-pointer.\"" >&2;}
- cat >>confdefs.h <<\_ACEOF
-#define SAVE_CALL_COUNT 8
-_ACEOF
-
- ;;
- i345686-*-dgux*)
- cat >>confdefs.h <<\_ACEOF
-#define MAKE_BACK_GRAPH 1
-_ACEOF
-
- ;;
- esac
- fi
-fi;
-
-
-
-# Check whether --enable-redirect-malloc or --disable-redirect-malloc was given.
-if test "${enable_redirect_malloc+set}" = set; then
- enableval="$enable_redirect_malloc"
-
-fi;
-
-if test "${enable_redirect_malloc}" = yes; then
- if test "${enable_full_debug}" = yes; then
- cat >>confdefs.h <<\_ACEOF
-#define REDIRECT_MALLOC GC_debug_malloc_replacement
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define REDIRECT_REALLOC GC_debug_realloc_replacement
-_ACEOF
-
- cat >>confdefs.h <<\_ACEOF
-#define REDIRECT_FREE GC_debug_free
-_ACEOF
-
- else
- cat >>confdefs.h <<\_ACEOF
-#define REDIRECT_MALLOC GC_malloc
-_ACEOF
-
- fi
-fi
-
-# Check whether --enable-gc-assertions or --disable-gc-assertions was given.
-if test "${enable_gc_assertions+set}" = set; then
- enableval="$enable_gc_assertions"
-
-fi;
-if test "${enable_gc_assertions}" = yes; then
- cat >>confdefs.h <<\_ACEOF
-#define GC_ASSERTIONS 1
-_ACEOF
-
-fi
-
-
-
-if test -z "$with_cross_host"; then
- USE_LIBDIR_TRUE=
- USE_LIBDIR_FALSE='#'
-else
- USE_LIBDIR_TRUE='#'
- USE_LIBDIR_FALSE=
-fi
-
-
-ac_config_files="$ac_config_files Makefile doc/Makefile include/Makefile"
-ac_config_commands="$ac_config_commands default"
-cat >confcache <<\_ACEOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs, see configure's option --config-cache.
-# It is not useful on other systems. If it contains results you don't
-# want to keep, you may remove or edit it.
-#
-# config.status only pays attention to the cache file if you give it
-# the --recheck option to rerun configure.
-#
-# `ac_cv_env_foo' variables (set or unset) will be overriden when
-# loading this file, other *unset* `ac_cv_foo' will be assigned the
-# following values.
-
-_ACEOF
-
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, don't put newlines in cache variables' values.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-{
- (set) 2>&1 |
- case `(ac_space=' '; set | grep ac_space) 2>&1` in
- *ac_space=\ *)
- # `set' does not quote correctly, so add quotes (double-quote
- # substitution turns \\\\ into \\, and sed turns \\ into \).
- sed -n \
- "s/'/'\\\\''/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
- ;;
- *)
- # `set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n \
- "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
- ;;
- esac;
-} |
- sed '
- t clear
- : clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
- t end
- /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
- : end' >>confcache
-if cmp -s $cache_file confcache; then :; else
- if test -w $cache_file; then
- test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
- cat confcache >$cache_file
- else
- echo "not updating unwritable cache $cache_file"
- fi
-fi
-rm -f confcache
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-# VPATH may cause trouble with some makes, so we remove $(srcdir),
-# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
-# trailing colons and then remove the whole line if VPATH becomes empty
-# (actually we leave an empty line to preserve line numbers).
-if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=/{
-s/:*\$(srcdir):*/:/;
-s/:*\${srcdir}:*/:/;
-s/:*@srcdir@:*/:/;
-s/^\([^=]*=[ ]*\):*/\1/;
-s/:*$//;
-s/^[^=]*=[ ]*$//;
-}'
-fi
-
-# Transform confdefs.h into DEFS.
-# Protect against shell expansion while executing Makefile rules.
-# Protect against Makefile macro expansion.
-#
-# If the first sed substitution is executed (which looks for macros that
-# take arguments), then we branch to the quote section. Otherwise,
-# look for a macro that doesn't take arguments.
-cat >confdef2opt.sed <<\_ACEOF
-t clear
-: clear
-s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g
-t quote
-s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g
-t quote
-d
-: quote
-s,[ `~#$^&*(){}\\|;'"<>?],\\&,g
-s,\[,\\&,g
-s,\],\\&,g
-s,\$,$$,g
-p
-_ACEOF
-# We use echo to avoid assuming a particular line-breaking character.
-# The extra dot is to prevent the shell from consuming trailing
-# line-breaks from the sub-command output. A line-break within
-# single-quotes doesn't work because, if this script is created in a
-# platform that uses two characters for line-breaks (e.g., DOS), tr
-# would break.
-ac_LF_and_DOT=`echo; echo .`
-DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
-rm -f confdef2opt.sed
-
-
-if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
- { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-echo "$as_me: error: conditional \"AMDEP\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
- { (exit 1); exit 1; }; }
-fi
-if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
- { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
- { (exit 1); exit 1; }; }
-fi
-if test -z "${POWERPC_DARWIN_TRUE}" && test -z "${POWERPC_DARWIN_FALSE}"; then
- { { echo "$as_me:$LINENO: error: conditional \"POWERPC_DARWIN\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-echo "$as_me: error: conditional \"POWERPC_DARWIN\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
- { (exit 1); exit 1; }; }
-fi
-if test -z "${CPLUSPLUS_TRUE}" && test -z "${CPLUSPLUS_FALSE}"; then
- { { echo "$as_me:$LINENO: error: conditional \"CPLUSPLUS\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-echo "$as_me: error: conditional \"CPLUSPLUS\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
- { (exit 1); exit 1; }; }
-fi
-if test -z "${USE_LIBDIR_TRUE}" && test -z "${USE_LIBDIR_FALSE}"; then
- { { echo "$as_me:$LINENO: error: conditional \"USE_LIBDIR\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-echo "$as_me: error: conditional \"USE_LIBDIR\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
- { (exit 1); exit 1; }; }
-fi
-
-: ${CONFIG_STATUS=./config.status}
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
-echo "$as_me: creating $CONFIG_STATUS" >&6;}
-cat >$CONFIG_STATUS <<_ACEOF
-#! $SHELL
-# Generated by $as_me.
-# Run this file to recreate the current configuration.
-# Compiler output produced by configure, useful for debugging
-# configure, is in config.log if it exists.
-
-debug=false
-SHELL=\${CONFIG_SHELL-$SHELL}
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF
-
-## --------------------- ##
-## M4sh Initialization. ##
-## --------------------- ##
-
-# Be Bourne compatible
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
- emulate sh
- NULLCMD=:
-elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
- set -o posix
-fi
-
-# NLS nuisances.
-# Support unset when possible.
-if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
- as_unset=unset
-else
- as_unset=false
-fi
-
-(set +x; test -n "`(LANG=C; export LANG) 2>&1`") &&
- { $as_unset LANG || test "${LANG+set}" != set; } ||
- { LANG=C; export LANG; }
-(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") &&
- { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } ||
- { LC_ALL=C; export LC_ALL; }
-(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") &&
- { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } ||
- { LC_TIME=C; export LC_TIME; }
-(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") &&
- { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } ||
- { LC_CTYPE=C; export LC_CTYPE; }
-(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") &&
- { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } ||
- { LANGUAGE=C; export LANGUAGE; }
-(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") &&
- { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } ||
- { LC_COLLATE=C; export LC_COLLATE; }
-(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") &&
- { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } ||
- { LC_NUMERIC=C; export LC_NUMERIC; }
-(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") &&
- { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } ||
- { LC_MESSAGES=C; export LC_MESSAGES; }
-
-
-# Name of the executable.
-as_me=`(basename "$0") 2>/dev/null ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
- X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)$' \| \
- . : '\(.\)' 2>/dev/null ||
-echo X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
- /^X\/\(\/\/\)$/{ s//\1/; q; }
- /^X\/\(\/\).*/{ s//\1/; q; }
- s/.*/./; q'`
-
-# PATH needs CR, and LINENO needs CR and PATH.
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
- echo "#! /bin/sh" >conftest.sh
- echo "exit 0" >>conftest.sh
- chmod +x conftest.sh
- if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then
- PATH_SEPARATOR=';'
- else
- PATH_SEPARATOR=:
- fi
- rm -f conftest.sh
-fi
-
-
- as_lineno_1=$LINENO
- as_lineno_2=$LINENO
- as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
- test "x$as_lineno_1" != "x$as_lineno_2" &&
- test "x$as_lineno_3" = "x$as_lineno_2" || {
- # Find who we are. Look in the path if we contain no path at all
- # relative or not.
- case $0 in
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-done
-
- ;;
- esac
- # We did not find ourselves, most probably we were run as `sh COMMAND'
- # in which case we are not to be found in the path.
- if test "x$as_myself" = x; then
- as_myself=$0
- fi
- if test ! -f "$as_myself"; then
- { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
-echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
- { (exit 1); exit 1; }; }
- fi
- case $CONFIG_SHELL in
- '')
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for as_base in sh bash ksh sh5; do
- case $as_dir in
- /*)
- if ("$as_dir/$as_base" -c '
- as_lineno_1=$LINENO
- as_lineno_2=$LINENO
- as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
- test "x$as_lineno_1" != "x$as_lineno_2" &&
- test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
- CONFIG_SHELL=$as_dir/$as_base
- export CONFIG_SHELL
- exec "$CONFIG_SHELL" "$0" ${1+"$@"}
- fi;;
- esac
- done
-done
-;;
- esac
-
- # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
- # uniformly replaced by the line number. The first 'sed' inserts a
- # line-number line before each line; the second 'sed' does the real
- # work. The second script uses 'N' to pair each line-number line
- # with the numbered line, and appends trailing '-' during
- # substitution so that $LINENO is not a special case at line end.
- # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
- # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
- sed '=' <$as_myself |
- sed '
- N
- s,$,-,
- : loop
- s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
- t loop
- s,-$,,
- s,^['$as_cr_digits']*\n,,
- ' >$as_me.lineno &&
- chmod +x $as_me.lineno ||
- { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
-echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
- { (exit 1); exit 1; }; }
-
- # Don't try to exec as it changes $[0], causing all sort of problems
- # (the dirname of $[0] is not the place where we might find the
- # original and so on. Autoconf is especially sensible to this).
- . ./$as_me.lineno
- # Exit status is that of the last command.
- exit
-}
-
-
-case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
- *c*,-n*) ECHO_N= ECHO_C='
-' ECHO_T=' ' ;;
- *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
- *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
-esac
-
-if expr a : '\(a\)' >/dev/null 2>&1; then
- as_expr=expr
-else
- as_expr=false
-fi
-
-rm -f conf$$ conf$$.exe conf$$.file
-echo >conf$$.file
-if ln -s conf$$.file conf$$ 2>/dev/null; then
- # We could just check for DJGPP; but this test a) works b) is more generic
- # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
- if test -f conf$$.exe; then
- # Don't use ln at all; we don't have any links
- as_ln_s='cp -p'
- else
- as_ln_s='ln -s'
- fi
-elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
-else
- as_ln_s='cp -p'
-fi
-rm -f conf$$ conf$$.exe conf$$.file
-
-as_executable_p="test -f"
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
-
-
-# IFS
-# We need space, tab and new line, in precisely that order.
-as_nl='
-'
-IFS=" $as_nl"
-
-# CDPATH.
-$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; }
-
-exec 6>&1
-
-# Open the log real soon, to keep \$[0] and so on meaningful, and to
-# report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling. Logging --version etc. is OK.
-exec 5>>config.log
-{
- echo
- sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
-} >&5
-cat >&5 <<_CSEOF
-
-This file was extended by gc $as_me 6.3, which was
-generated by GNU Autoconf 2.53. Invocation command line was
-
- CONFIG_FILES = $CONFIG_FILES
- CONFIG_HEADERS = $CONFIG_HEADERS
- CONFIG_LINKS = $CONFIG_LINKS
- CONFIG_COMMANDS = $CONFIG_COMMANDS
- $ $0 $@
-
-_CSEOF
-echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
-echo >&5
-_ACEOF
-
-# Files that config.status was made for.
-if test -n "$ac_config_files"; then
- echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
-fi
-
-if test -n "$ac_config_headers"; then
- echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
-fi
-
-if test -n "$ac_config_links"; then
- echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
-fi
-
-if test -n "$ac_config_commands"; then
- echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
-fi
-
-cat >>$CONFIG_STATUS <<\_ACEOF
-
-ac_cs_usage="\
-\`$as_me' instantiates files from templates according to the
-current configuration.
-
-Usage: $0 [OPTIONS] [FILE]...
-
- -h, --help print this help, then exit
- -V, --version print version number, then exit
- -d, --debug don't remove temporary files
- --recheck update $as_me by reconfiguring in the same conditions
- --file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
-
-Configuration files:
-$config_files
-
-Configuration commands:
-$config_commands
-
-Report bugs to <bug-autoconf@gnu.org>."
-_ACEOF
-
-cat >>$CONFIG_STATUS <<_ACEOF
-ac_cs_version="\\
-gc config.status 6.3
-configured by $0, generated by GNU Autoconf 2.53,
- with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
-
-Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
-Free Software Foundation, Inc.
-This config.status script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it."
-srcdir=$srcdir
-INSTALL="$INSTALL"
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF
-# If no file are specified by the user, then we need to provide default
-# value. By we need to know if files were specified by the user.
-ac_need_defaults=:
-while test $# != 0
-do
- case $1 in
- --*=*)
- ac_option=`expr "x$1" : 'x\([^=]*\)='`
- ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
- shift
- set dummy "$ac_option" "$ac_optarg" ${1+"$@"}
- shift
- ;;
- -*);;
- *) # This is not an option, so the user has probably given explicit
- # arguments.
- ac_need_defaults=false;;
- esac
-
- case $1 in
- # Handling of the options.
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF
- -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
- echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion"
- exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;;
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF
- --version | --vers* | -V )
- echo "$ac_cs_version"; exit 0 ;;
- --he | --h)
- # Conflict between --help and --header
- { { echo "$as_me:$LINENO: error: ambiguous option: $1
-Try \`$0 --help' for more information." >&5
-echo "$as_me: error: ambiguous option: $1
-Try \`$0 --help' for more information." >&2;}
- { (exit 1); exit 1; }; };;
- --help | --hel | -h )
- echo "$ac_cs_usage"; exit 0 ;;
- --debug | --d* | -d )
- debug=: ;;
- --file | --fil | --fi | --f )
- shift
- CONFIG_FILES="$CONFIG_FILES $1"
- ac_need_defaults=false;;
- --header | --heade | --head | --hea )
- shift
- CONFIG_HEADERS="$CONFIG_HEADERS $1"
- ac_need_defaults=false;;
-
- # This is an error.
- -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
-Try \`$0 --help' for more information." >&5
-echo "$as_me: error: unrecognized option: $1
-Try \`$0 --help' for more information." >&2;}
- { (exit 1); exit 1; }; } ;;
-
- *) ac_config_targets="$ac_config_targets $1" ;;
-
- esac
- shift
-done
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<_ACEOF
-#
-# INIT-COMMANDS section.
-#
-
-AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
-srcdir=${srcdir}
-host=${host}
-CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
-CC="${CC}"
-DEFS="$DEFS"
-
-
-_ACEOF
-
-
-
-cat >>$CONFIG_STATUS <<\_ACEOF
-for ac_config_target in $ac_config_targets
-do
- case "$ac_config_target" in
- # Handling of arguments.
- "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
- "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
- "include/Makefile" ) CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
- "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
- "default" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
- *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
-echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
- { (exit 1); exit 1; }; };;
- esac
-done
-
-# If the user did not use the arguments to specify the items to instantiate,
-# then the envvar interface is used. Set only those that are not.
-# We use the long form for the default assignment because of an extremely
-# bizarre bug on SunOS 4.1.3.
-if $ac_need_defaults; then
- test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
- test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
-fi
-
-# Create a temporary directory, and hook for its removal unless debugging.
-$debug ||
-{
- trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
- trap '{ (exit 1); exit 1; }' 1 2 13 15
-}
-
-# Create a (secure) tmp directory for tmp files.
-: ${TMPDIR=/tmp}
-{
- tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` &&
- test -n "$tmp" && test -d "$tmp"
-} ||
-{
- tmp=$TMPDIR/cs$$-$RANDOM
- (umask 077 && mkdir $tmp)
-} ||
-{
- echo "$me: cannot create a temporary directory in $TMPDIR" >&2
- { (exit 1); exit 1; }
-}
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<_ACEOF
-
-#
-# CONFIG_FILES section.
-#
-
-# No need to generate the scripts if there are no CONFIG_FILES.
-# This happens for instance when ./config.status config.h
-if test -n "\$CONFIG_FILES"; then
- # Protect against being on the right side of a sed subst in config.status.
- sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
- s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
-s,@SHELL@,$SHELL,;t t
-s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
-s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
-s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
-s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
-s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
-s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
-s,@exec_prefix@,$exec_prefix,;t t
-s,@prefix@,$prefix,;t t
-s,@program_transform_name@,$program_transform_name,;t t
-s,@bindir@,$bindir,;t t
-s,@sbindir@,$sbindir,;t t
-s,@libexecdir@,$libexecdir,;t t
-s,@datadir@,$datadir,;t t
-s,@sysconfdir@,$sysconfdir,;t t
-s,@sharedstatedir@,$sharedstatedir,;t t
-s,@localstatedir@,$localstatedir,;t t
-s,@libdir@,$libdir,;t t
-s,@includedir@,$includedir,;t t
-s,@oldincludedir@,$oldincludedir,;t t
-s,@infodir@,$infodir,;t t
-s,@mandir@,$mandir,;t t
-s,@build_alias@,$build_alias,;t t
-s,@host_alias@,$host_alias,;t t
-s,@target_alias@,$target_alias,;t t
-s,@DEFS@,$DEFS,;t t
-s,@ECHO_C@,$ECHO_C,;t t
-s,@ECHO_N@,$ECHO_N,;t t
-s,@ECHO_T@,$ECHO_T,;t t
-s,@LIBS@,$LIBS,;t t
-s,@build@,$build,;t t
-s,@build_cpu@,$build_cpu,;t t
-s,@build_vendor@,$build_vendor,;t t
-s,@build_os@,$build_os,;t t
-s,@host@,$host,;t t
-s,@host_cpu@,$host_cpu,;t t
-s,@host_vendor@,$host_vendor,;t t
-s,@host_os@,$host_os,;t t
-s,@target@,$target,;t t
-s,@target_cpu@,$target_cpu,;t t
-s,@target_vendor@,$target_vendor,;t t
-s,@target_os@,$target_os,;t t
-s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
-s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
-s,@INSTALL_DATA@,$INSTALL_DATA,;t t
-s,@PACKAGE@,$PACKAGE,;t t
-s,@VERSION@,$VERSION,;t t
-s,@ACLOCAL@,$ACLOCAL,;t t
-s,@AUTOCONF@,$AUTOCONF,;t t
-s,@AUTOMAKE@,$AUTOMAKE,;t t
-s,@AUTOHEADER@,$AUTOHEADER,;t t
-s,@MAKEINFO@,$MAKEINFO,;t t
-s,@AMTAR@,$AMTAR,;t t
-s,@install_sh@,$install_sh,;t t
-s,@STRIP@,$STRIP,;t t
-s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t
-s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t
-s,@AWK@,$AWK,;t t
-s,@SET_MAKE@,$SET_MAKE,;t t
-s,@GC_VERSION@,$GC_VERSION,;t t
-s,@CC@,$CC,;t t
-s,@CFLAGS@,$CFLAGS,;t t
-s,@LDFLAGS@,$LDFLAGS,;t t
-s,@CPPFLAGS@,$CPPFLAGS,;t t
-s,@ac_ct_CC@,$ac_ct_CC,;t t
-s,@EXEEXT@,$EXEEXT,;t t
-s,@OBJEXT@,$OBJEXT,;t t
-s,@DEPDIR@,$DEPDIR,;t t
-s,@am__include@,$am__include,;t t
-s,@am__quote@,$am__quote,;t t
-s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t
-s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t
-s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t
-s,@CCDEPMODE@,$CCDEPMODE,;t t
-s,@CXX@,$CXX,;t t
-s,@CXXFLAGS@,$CXXFLAGS,;t t
-s,@ac_ct_CXX@,$ac_ct_CXX,;t t
-s,@CXXDEPMODE@,$CXXDEPMODE,;t t
-s,@CCAS@,$CCAS,;t t
-s,@CCASFLAGS@,$CCASFLAGS,;t t
-s,@AR@,$AR,;t t
-s,@ac_ct_AR@,$ac_ct_AR,;t t
-s,@RANLIB@,$RANLIB,;t t
-s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
-s,@MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t
-s,@MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t
-s,@MAINT@,$MAINT,;t t
-s,@GC_CFLAGS@,$GC_CFLAGS,;t t
-s,@THREADLIBS@,$THREADLIBS,;t t
-s,@POWERPC_DARWIN_TRUE@,$POWERPC_DARWIN_TRUE,;t t
-s,@POWERPC_DARWIN_FALSE@,$POWERPC_DARWIN_FALSE,;t t
-s,@EXTRA_TEST_LIBS@,$EXTRA_TEST_LIBS,;t t
-s,@target_all@,$target_all,;t t
-s,@CPLUSPLUS_TRUE@,$CPLUSPLUS_TRUE,;t t
-s,@CPLUSPLUS_FALSE@,$CPLUSPLUS_FALSE,;t t
-s,@INCLUDES@,$INCLUDES,;t t
-s,@CXXINCLUDES@,$CXXINCLUDES,;t t
-s,@addobjs@,$addobjs,;t t
-s,@addincludes@,$addincludes,;t t
-s,@addlibs@,$addlibs,;t t
-s,@addtests@,$addtests,;t t
-s,@LN_S@,$LN_S,;t t
-s,@ECHO@,$ECHO,;t t
-s,@CPP@,$CPP,;t t
-s,@LIBTOOL@,$LIBTOOL,;t t
-s,@MY_CFLAGS@,$MY_CFLAGS,;t t
-s,@UNWINDLIBS@,$UNWINDLIBS,;t t
-s,@USE_LIBDIR_TRUE@,$USE_LIBDIR_TRUE,;t t
-s,@USE_LIBDIR_FALSE@,$USE_LIBDIR_FALSE,;t t
-CEOF
-
-_ACEOF
-
- cat >>$CONFIG_STATUS <<\_ACEOF
- # Split the substitutions into bite-sized pieces for seds with
- # small command number limits, like on Digital OSF/1 and HP-UX.
- ac_max_sed_lines=48
- ac_sed_frag=1 # Number of current file.
- ac_beg=1 # First line for current file.
- ac_end=$ac_max_sed_lines # Line after last line for current file.
- ac_more_lines=:
- ac_sed_cmds=
- while $ac_more_lines; do
- if test $ac_beg -gt 1; then
- sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
- else
- sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
- fi
- if test ! -s $tmp/subs.frag; then
- ac_more_lines=false
- else
- # The purpose of the label and of the branching condition is to
- # speed up the sed processing (if there are no `@' at all, there
- # is no need to browse any of the substitutions).
- # These are the two extra sed commands mentioned above.
- (echo ':t
- /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
- if test -z "$ac_sed_cmds"; then
- ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
- else
- ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
- fi
- ac_sed_frag=`expr $ac_sed_frag + 1`
- ac_beg=$ac_end
- ac_end=`expr $ac_end + $ac_max_sed_lines`
- fi
- done
- if test -z "$ac_sed_cmds"; then
- ac_sed_cmds=cat
- fi
-fi # test -n "$CONFIG_FILES"
-
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF
-for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
- # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
- case $ac_file in
- - | *:- | *:-:* ) # input from stdin
- cat >$tmp/stdin
- ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
- ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
- *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
- ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
- * ) ac_file_in=$ac_file.in ;;
- esac
-
- # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
- ac_dir=`(dirname "$ac_file") 2>/dev/null ||
-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$ac_file" : 'X\(//\)[^/]' \| \
- X"$ac_file" : 'X\(//\)$' \| \
- X"$ac_file" : 'X\(/\)' \| \
- . : '\(.\)' 2>/dev/null ||
-echo X"$ac_file" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
- /^X\(\/\/\)[^/].*/{ s//\1/; q; }
- /^X\(\/\/\)$/{ s//\1/; q; }
- /^X\(\/\).*/{ s//\1/; q; }
- s/.*/./; q'`
- { case "$ac_dir" in
- [\\/]* | ?:[\\/]* ) as_incr_dir=;;
- *) as_incr_dir=.;;
-esac
-as_dummy="$ac_dir"
-for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
- case $as_mkdir_dir in
- # Skip DOS drivespec
- ?:) as_incr_dir=$as_mkdir_dir ;;
- *)
- as_incr_dir=$as_incr_dir/$as_mkdir_dir
- test -d "$as_incr_dir" ||
- mkdir "$as_incr_dir" ||
- { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5
-echo "$as_me: error: cannot create \"$ac_dir\"" >&2;}
- { (exit 1); exit 1; }; }
- ;;
- esac
-done; }
-
- ac_builddir=.
-
-if test "$ac_dir" != .; then
- ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
- # A "../" for each directory in $ac_dir_suffix.
- ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
-else
- ac_dir_suffix= ac_top_builddir=
-fi
-
-case $srcdir in
- .) # No --srcdir option. We are building in place.
- ac_srcdir=.
- if test -z "$ac_top_builddir"; then
- ac_top_srcdir=.
- else
- ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
- fi ;;
- [\\/]* | ?:[\\/]* ) # Absolute path.
- ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir ;;
- *) # Relative path.
- ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_builddir$srcdir ;;
-esac
-# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
-# absolute.
-ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
-ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd`
-ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
-ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
-
-
- case $INSTALL in
- [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
- *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
- esac
-
- if test x"$ac_file" != x-; then
- { echo "$as_me:$LINENO: creating $ac_file" >&5
-echo "$as_me: creating $ac_file" >&6;}
- rm -f "$ac_file"
- fi
- # Let's still pretend it is `configure' which instantiates (i.e., don't
- # use $as_me), people would be surprised to read:
- # /* config.h. Generated by config.status. */
- if test x"$ac_file" = x-; then
- configure_input=
- else
- configure_input="$ac_file. "
- fi
- configure_input=$configure_input"Generated from `echo $ac_file_in |
- sed 's,.*/,,'` by configure."
-
- # First look for the input files in the build tree, otherwise in the
- # src tree.
- ac_file_inputs=`IFS=:
- for f in $ac_file_in; do
- case $f in
- -) echo $tmp/stdin ;;
- [\\/$]*)
- # Absolute (can't be DOS-style, as IFS=:)
- test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
-echo "$as_me: error: cannot find input file: $f" >&2;}
- { (exit 1); exit 1; }; }
- echo $f;;
- *) # Relative
- if test -f "$f"; then
- # Build tree
- echo $f
- elif test -f "$srcdir/$f"; then
- # Source tree
- echo $srcdir/$f
- else
- # /dev/null tree
- { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
-echo "$as_me: error: cannot find input file: $f" >&2;}
- { (exit 1); exit 1; }; }
- fi;;
- esac
- done` || { (exit 1); exit 1; }
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF
- sed "$ac_vpsub
-$extrasub
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF
-:t
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s,@configure_input@,$configure_input,;t t
-s,@srcdir@,$ac_srcdir,;t t
-s,@abs_srcdir@,$ac_abs_srcdir,;t t
-s,@top_srcdir@,$ac_top_srcdir,;t t
-s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
-s,@builddir@,$ac_builddir,;t t
-s,@abs_builddir@,$ac_abs_builddir,;t t
-s,@top_builddir@,$ac_top_builddir,;t t
-s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
-s,@INSTALL@,$ac_INSTALL,;t t
-" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
- rm -f $tmp/stdin
- if test x"$ac_file" != x-; then
- mv $tmp/out $ac_file
- else
- cat $tmp/out
- rm -f $tmp/out
- fi
-
-done
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF
-
-#
-# CONFIG_COMMANDS section.
-#
-for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue
- ac_dest=`echo "$ac_file" | sed 's,:.*,,'`
- ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'`
- ac_dir=`(dirname "$ac_dest") 2>/dev/null ||
-$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$ac_dest" : 'X\(//\)[^/]' \| \
- X"$ac_dest" : 'X\(//\)$' \| \
- X"$ac_dest" : 'X\(/\)' \| \
- . : '\(.\)' 2>/dev/null ||
-echo X"$ac_dest" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
- /^X\(\/\/\)[^/].*/{ s//\1/; q; }
- /^X\(\/\/\)$/{ s//\1/; q; }
- /^X\(\/\).*/{ s//\1/; q; }
- s/.*/./; q'`
- ac_builddir=.
-
-if test "$ac_dir" != .; then
- ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
- # A "../" for each directory in $ac_dir_suffix.
- ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
-else
- ac_dir_suffix= ac_top_builddir=
-fi
-
-case $srcdir in
- .) # No --srcdir option. We are building in place.
- ac_srcdir=.
- if test -z "$ac_top_builddir"; then
- ac_top_srcdir=.
- else
- ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
- fi ;;
- [\\/]* | ?:[\\/]* ) # Absolute path.
- ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir ;;
- *) # Relative path.
- ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_builddir$srcdir ;;
-esac
-# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
-# absolute.
-ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
-ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd`
-ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
-ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
-
-
- { echo "$as_me:$LINENO: executing $ac_dest commands" >&5
-echo "$as_me: executing $ac_dest commands" >&6;}
- case $ac_dest in
- depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do
- # Strip MF so we end up with the name of the file.
- mf=`echo "$mf" | sed -e 's/:.*$//'`
- # Check whether this is an Automake generated Makefile or not.
- # We used to match only the files named `Makefile.in', but
- # some people rename them; so instead we look at the file content.
- # Grep'ing the first line is not enough: some people post-process
- # each Makefile.in and add a new line on top of each file to say so.
- # So let's grep whole file.
- if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
- dirpart=`(dirname "$mf") 2>/dev/null ||
-$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$mf" : 'X\(//\)[^/]' \| \
- X"$mf" : 'X\(//\)$' \| \
- X"$mf" : 'X\(/\)' \| \
- . : '\(.\)' 2>/dev/null ||
-echo X"$mf" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
- /^X\(\/\/\)[^/].*/{ s//\1/; q; }
- /^X\(\/\/\)$/{ s//\1/; q; }
- /^X\(\/\).*/{ s//\1/; q; }
- s/.*/./; q'`
- else
- continue
- fi
- grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue
- # Extract the definition of DEP_FILES from the Makefile without
- # running `make'.
- DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"`
- test -z "$DEPDIR" && continue
- # When using ansi2knr, U may be empty or an underscore; expand it
- U=`sed -n -e '/^U = / s///p' < "$mf"`
- test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR"
- # We invoke sed twice because it is the simplest approach to
- # changing $(DEPDIR) to its actual value in the expansion.
- for file in `sed -n -e '
- /^DEP_FILES = .*\\\\$/ {
- s/^DEP_FILES = //
- :loop
- s/\\\\$//
- p
- n
- /\\\\$/ b loop
- p
- }
- /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \
- sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
- # Make sure the directory exists.
- test -f "$dirpart/$file" && continue
- fdir=`(dirname "$file") 2>/dev/null ||
-$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$file" : 'X\(//\)[^/]' \| \
- X"$file" : 'X\(//\)$' \| \
- X"$file" : 'X\(/\)' \| \
- . : '\(.\)' 2>/dev/null ||
-echo X"$file" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
- /^X\(\/\/\)[^/].*/{ s//\1/; q; }
- /^X\(\/\/\)$/{ s//\1/; q; }
- /^X\(\/\).*/{ s//\1/; q; }
- s/.*/./; q'`
- { case $dirpart/$fdir in
- [\\/]* | ?:[\\/]* ) as_incr_dir=;;
- *) as_incr_dir=.;;
-esac
-as_dummy=$dirpart/$fdir
-for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
- case $as_mkdir_dir in
- # Skip DOS drivespec
- ?:) as_incr_dir=$as_mkdir_dir ;;
- *)
- as_incr_dir=$as_incr_dir/$as_mkdir_dir
- test -d "$as_incr_dir" ||
- mkdir "$as_incr_dir" ||
- { { echo "$as_me:$LINENO: error: cannot create $dirpart/$fdir" >&5
-echo "$as_me: error: cannot create $dirpart/$fdir" >&2;}
- { (exit 1); exit 1; }; }
- ;;
- esac
-done; }
-
- # echo "creating $dirpart/$file"
- echo '# dummy' > "$dirpart/$file"
- done
-done
- ;;
- esac
-done
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF
-
-{ (exit 0); exit 0; }
-_ACEOF
-chmod +x $CONFIG_STATUS
-ac_clean_files=$ac_clean_files_save
-
-
-# configure is writing to config.log, and then calls config.status.
-# config.status does its own redirection, appending to config.log.
-# Unfortunately, on DOS this fails, as config.log is still kept open
-# by configure, so config.status won't be able to write to it; its
-# output is simply discarded. So we exec the FD to /dev/null,
-# effectively closing config.log, so it can be properly (re)opened and
-# appended to by config.status. When coming back to configure, we
-# need to make the FD available again.
-if test "$no_create" != yes; then
- ac_cs_success=:
- exec 5>/dev/null
- $SHELL $CONFIG_STATUS || ac_cs_success=false
- exec 5>>config.log
- # Use ||, not &&, to avoid exiting from the if with $? = 1, which
- # would make configure fail if this is the last instruction.
- $ac_cs_success || { (exit 1); exit 1; }
-fi
-
diff --git a/boehm-gc/configure.ac b/boehm-gc/configure.ac
new file mode 100644
index 00000000000..a33c21e2763
--- /dev/null
+++ b/boehm-gc/configure.ac
@@ -0,0 +1,915 @@
+# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program
+# for any purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+
+dnl Process this file with autoconf to produce configure.
+
+# Initialization
+AC_INIT(gc,7.3alpha3,gc@linux.hpl.hp.com)
+ ## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
+AC_CONFIG_SRCDIR(gcj_mlc.c)
+AC_CONFIG_MACRO_DIR([m4])
+AC_CANONICAL_TARGET
+AC_PREREQ(2.61)
+AC_REVISION($Revision: 1.69 $)
+GC_SET_VERSION
+AM_INIT_AUTOMAKE([foreign dist-bzip2 nostdinc])
+AM_CONFIG_HEADER([include/config.h])
+AM_MAINTAINER_MODE
+
+AC_SUBST(PACKAGE)
+AC_SUBST(GC_VERSION)
+
+AM_PROG_CC_C_O
+AC_PROG_CXX
+
+AM_PROG_AS
+
+AC_PROG_INSTALL
+
+# Special CFLAGS to use when building
+gc_cflags=""
+
+# gc_use_mmap Set to "yes" on platforms where mmap should be used instead
+# of sbrk. This will define USE_MMAP.
+gc_use_mmap=""
+
+# We should set -fexceptions if we are using gcc and might be used
+# inside something like gcj. This is the zeroth approximation:
+if test :"$GCC": = :yes: ; then
+ gc_cflags="${gc_cflags} -fexceptions"
+else
+ case "$host" in
+ hppa*-*-hpux* )
+ if test :$GCC: != :"yes": ; then
+ gc_cflags="${gc_flags} +ESdbgasm"
+ fi
+ # :TODO: actaully we should check using Autoconf if
+ # the compiler supports this option.
+ ;;
+ esac
+fi
+
+case "${host}" in
+ *-linux*)
+ # FIXME: This seems to be no longer needed as configured in gcconfig.h
+ #gc_use_mmap=yes
+ ;;
+esac
+
+# target_optspace --enable-target-optspace ("yes", "no", "")
+case "${target_optspace}:${host}" in
+ yes:*)
+ gc_cflags="${gc_cflags} -Os"
+ ;;
+ :m32r-* | :d10v-* | :d30v-*)
+ gc_cflags="${gc_cflags} -Os"
+ ;;
+ no:* | :*)
+ # Nothing.
+ ;;
+esac
+
+# Set any host dependent compiler flags.
+case "${host}" in
+ mips-tx39-*|mipstx39-unknown-*)
+ gc_cflags="${gc_cflags} -G 0"
+ ;;
+ *)
+ ;;
+esac
+
+
+GC_CFLAGS=${gc_cflags}
+AC_SUBST(GC_CFLAGS)
+
+AC_ARG_ENABLE(threads,
+ [AC_HELP_STRING([--enable-threads=TYPE], [choose threading package])],
+ THREADS=$enableval,
+ [ AC_MSG_CHECKING([for thread model used by GCC])
+ THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
+ if test -z "$THREADS"; then
+ THREADS=no
+ fi
+ if test "$THREADS" = "posix"; then
+ case "$host" in
+ *-*-mingw*)
+ # Adjust thread model if cross-compiling for MinGW.
+ THREADS=win32
+ ;;
+ esac
+ fi
+ AC_MSG_RESULT([$THREADS]) ])
+
+AC_ARG_ENABLE(parallel-mark,
+ [AC_HELP_STRING([--enable-parallel-mark],
+ [parallelize marking and free list construction])],
+ [case "$THREADS" in
+ no | none | single)
+ if test "${enable_parallel_mark}" != no; then
+ AC_MSG_ERROR([Parallel mark requires --enable-threads=x spec])
+ fi
+ ;;
+ esac ]
+)
+
+AC_ARG_ENABLE(cplusplus,
+ [AC_HELP_STRING([--enable-cplusplus], [install C++ support])])
+
+dnl Features which may be selected in the following thread-detection switch.
+AH_TEMPLATE([PARALLEL_MARK], [Define to enable parallel marking.])
+AH_TEMPLATE([THREAD_LOCAL_ALLOC],
+ [Define to enable thread-local allocation optimisation.])
+AH_TEMPLATE([USE_COMPILER_TLS],
+ [Define to use of compiler-support for thread-local variables.])
+
+dnl Thread selection macros.
+AH_TEMPLATE([GC_THREADS], [Define to support platform-specific
+ threads.])
+AH_TEMPLATE([GC_AIX_THREADS], [Define to support IBM AIX threads.])
+AH_TEMPLATE([GC_DARWIN_THREADS], [Define to support Darwin pthreads.])
+AH_TEMPLATE([GC_FREEBSD_THREADS], [Define to support FreeBSD pthreads.])
+AH_TEMPLATE([GC_GNU_THREADS], [Define to support GNU pthreads.])
+AH_TEMPLATE([GC_HPUX_THREADS], [Define to support HP/UX 11 pthreads.])
+AH_TEMPLATE([GC_IRIX_THREADS], [Define to support Irix pthreads.])
+AH_TEMPLATE([GC_LINUX_THREADS], [Define to support pthreads on Linux.])
+AH_TEMPLATE([GC_NETBSD_THREADS], [Define to support NetBSD pthreads.])
+AH_TEMPLATE([GC_OPENBSD_THREADS], [Define to support OpenBSD pthreads.])
+AH_TEMPLATE([GC_OSF1_THREADS], [Define to support Tru64 pthreads.])
+AH_TEMPLATE([GC_SOLARIS_THREADS], [Define to support Solaris pthreads.])
+AH_TEMPLATE([GC_WIN32_THREADS], [Define to support Win32 threads.])
+AH_TEMPLATE([GC_WIN32_PTHREADS], [Define to support win32-pthreads.])
+AH_TEMPLATE([GC_RTEMS_PTHREADS], [Define to support rtems-pthreads.])
+
+dnl System header feature requests.
+AH_TEMPLATE([_POSIX_C_SOURCE], [The POSIX feature macro.])
+AH_TEMPLATE([_PTHREADS], [Indicates the use of pthreads (NetBSD).])
+
+dnl Win32-specific API usage controls.
+AH_TEMPLATE([GC_UNDERSCORE_STDCALL],
+ [Explicitly prefix exported/imported WINAPI symbols with '_'.])
+AH_TEMPLATE([UNICODE],
+ [Use Unicode (W) variant of Win32 API instead of ASCII (A) one.])
+
+dnl GC API symbols export control.
+AH_TEMPLATE([GC_DLL],
+ [Define to build dynamic libraries with only API symbols exposed.])
+
+dnl Check for a flavor of supported inline keyword.
+AC_C_INLINE
+
+THREADDLLIBS=
+need_atomic_ops_asm=false
+## Libraries needed to support dynamic loading and/or threads.
+case "$THREADS" in
+ no | none | single)
+ THREADS=none
+ ;;
+ posix | pthreads)
+ THREADS=posix
+ AC_CHECK_LIB(pthread, pthread_self, THREADDLLIBS="-lpthread",,)
+ case "$host" in
+ x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* \
+ | x86_64-*-linux* | alpha-*-linux* | sparc*-*-linux*)
+ AC_DEFINE(GC_LINUX_THREADS)
+ AC_DEFINE(_REENTRANT)
+ if test "${enable_parallel_mark}" != no; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
+ ;;
+ *-*-linux*)
+ AC_DEFINE(GC_LINUX_THREADS)
+ AC_DEFINE(_REENTRANT)
+ ;;
+ *-*-aix*)
+ AC_DEFINE(GC_AIX_THREADS)
+ AC_DEFINE(_REENTRANT)
+ ;;
+ *-*-hpux11*)
+ AC_MSG_WARN("Only HP/UX 11 POSIX threads are supported.")
+ AC_DEFINE(GC_HPUX_THREADS)
+ AC_DEFINE(_POSIX_C_SOURCE,199506L)
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
+ THREADDLLIBS="-lpthread -lrt"
+ # HPUX needs REENTRANT for the _r calls.
+ AC_DEFINE(_REENTRANT, 1, [Required define if using POSIX threads.])
+ ;;
+ *-*-hpux10*)
+ AC_MSG_WARN("Only HP-UX 11 POSIX threads are supported.")
+ ;;
+ *-*-openbsd*)
+ AC_DEFINE(GC_OPENBSD_THREADS)
+ THREADDLLIBS=-pthread
+ INCLUDES="$INCLUDES -pthread"
+ ;;
+ *-*-freebsd*)
+ AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.")
+ AC_DEFINE(GC_FREEBSD_THREADS)
+ INCLUDES="$INCLUDES -pthread"
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ ;;
+ *-*-kfreebsd*-gnu)
+ AC_DEFINE(GC_FREEBSD_THREADS)
+ INCLUDES="$INCLUDES -pthread"
+ THREADDLLIBS=-pthread
+ AC_DEFINE(_REENTRANT)
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ AC_DEFINE(USE_COMPILER_TLS)
+ ;;
+ *-*-gnu*)
+ AC_DEFINE(GC_GNU_THREADS)
+ AC_DEFINE(_REENTRANT)
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ ;;
+ *-*-netbsd*)
+ AC_MSG_WARN("Only on NetBSD 2.0 or later.")
+ AC_DEFINE(GC_NETBSD_THREADS)
+ AC_DEFINE(_REENTRANT)
+ AC_DEFINE(_PTHREADS)
+ THREADDLLIBS="-lpthread -lrt"
+ ;;
+ *-*-solaris*)
+ AC_DEFINE(GC_SOLARIS_THREADS)
+ if test "${enable_parallel_mark}" != no; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ # Need to use alternate thread library, otherwise gctest hangs
+ # on Solaris 8.
+ multi_os_directory=`$CC -print-multi-os-directory`
+ THREADDLLIBS="-L/usr/lib/lwp/$multi_os_directory \
+ -R/usr/lib/lwp/$multi_os_directory -lpthread -lrt"
+ ;;
+ *-*-irix*)
+ AC_DEFINE(GC_IRIX_THREADS)
+ ;;
+ *-*-cygwin*)
+ AC_DEFINE(GC_WIN32_THREADS)
+ if test "${enable_parallel_mark}" != no; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ # Cygwin doesn't have a real libpthread, so Libtool can't link
+ # against it.
+ THREADDLLIBS=""
+ win32_threads=true
+ ;;
+ *-*-mingw*)
+ AC_DEFINE(GC_WIN32_PTHREADS)
+ # Using win32-pthreads
+ if test "${enable_parallel_mark}" != no; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ THREADDLLIBS="-lpthread"
+ win32_threads=true
+ ;;
+ *-*-darwin*)
+ AC_DEFINE(GC_DARWIN_THREADS)
+ AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
+ # Parallel-mark is not well-tested on Darwin
+ if test "${enable_parallel_mark}" != no; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ darwin_threads=true
+ ;;
+ *-*-osf*)
+ AC_DEFINE(GC_OSF1_THREADS)
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
+ # May want to enable it in other cases, too.
+ # Measurements have not yet been done.
+ fi
+ INCLUDES="$INCLUDES -pthread"
+ THREADDLLIBS="-lpthread -lrt"
+ ;;
+ *)
+ AC_MSG_ERROR("Pthreads not supported by the GC on this platform.")
+ ;;
+ esac
+ case "$host" in
+ sparc*-*-solaris*)
+ if test "$GCC" != yes; then
+ CFLAGS="-O $CFLAGS"
+ need_atomic_ops_asm=true
+ fi
+ ;;
+ esac
+ ;;
+ win32)
+ AC_DEFINE(GC_WIN32_THREADS)
+ if test "${enable_parallel_mark}" != no; then
+ AC_DEFINE(PARALLEL_MARK)
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ else
+ if test "${enable_shared}" != yes || test "${enable_static}" != no; then
+ # Imply THREAD_LOCAL_ALLOC unless GC_DLL.
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ fi
+ fi
+ if test "${enable_win32_dllmain}" = yes; then
+ AC_DEFINE(GC_INSIDE_DLL, 1,
+ [Enable Win32 DllMain-based approach of threads registering.])
+ fi
+ win32_threads=true
+ AC_DEFINE([EMPTY_GETENV_RESULTS], [1],
+ [Wine getenv may not return NULL for missing entry.])
+ ;;
+ dgux386)
+ THREADS=dgux386
+ AC_MSG_RESULT($THREADDLLIBS)
+ # Use pthread GCC switch
+ THREADDLLIBS=-pthread
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
+ AC_DEFINE([GC_DGUX386_THREADS], 1,
+ [Define to enable support for DB/UX threads on i386.])
+ AC_DEFINE([DGUX_THREADS], 1,
+ [Define to enable support for DB/UX threads.])
+ # Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
+ INCLUDES="-pthread $INCLUDES"
+ ;;
+ aix)
+ THREADS=posix
+ THREADDLLIBS=-lpthread
+ AC_DEFINE(GC_AIX_THREADS)
+ AC_DEFINE(_REENTRANT)
+ ;;
+ rtems)
+ THREADS=posix
+ AC_DEFINE(GC_RTEMS_PTHREADS)
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ ;;
+ decosf1 | irix | mach | os2 | solaris | dce | vxworks)
+ AC_MSG_ERROR(thread package $THREADS not yet supported)
+ ;;
+ *)
+ AC_MSG_ERROR($THREADS is an unknown thread package)
+ ;;
+esac
+AC_SUBST(THREADDLLIBS)
+AM_CONDITIONAL(THREADS, test x$THREADS != xnone)
+AM_CONDITIONAL(PTHREADS, test x$THREADS = xposix)
+AM_CONDITIONAL(DARWIN_THREADS, test x$darwin_threads = xtrue)
+AM_CONDITIONAL(WIN32_THREADS, test x$win32_threads = xtrue)
+
+case "$host" in
+ powerpc-*-darwin*)
+ powerpc_darwin=true
+ ;;
+ *-*-wince*)
+ if test "$enable_gc_debug" != "no"; then
+ AC_DEFINE([GC_READ_ENV_FILE], 1,
+ [Read environment variables from the GC 'env' file.])
+ fi
+ ;;
+esac
+
+if test "$GCC" = yes; then
+ # Output all warnings.
+ AC_MSG_CHECKING(for gcc -Wextra)
+ old_CFLAGS="$CFLAGS"
+ CFLAGS="-Wextra $CFLAGS"
+ AC_TRY_COMPILE([],[], [ac_cv_cc_wextra=yes], [ac_cv_cc_wextra=no])
+ CFLAGS="$old_CFLAGS"
+ AC_MSG_RESULT($ac_cv_cc_wextra)
+ AS_IF([test "$ac_cv_cc_wextra" = yes], [WEXTRA="-Wextra"], [WEXTRA="-W"])
+ CFLAGS="-Wall $WEXTRA $CFLAGS"
+fi
+
+AC_MSG_CHECKING(for xlc)
+AC_TRY_COMPILE([],[
+ #ifndef __xlC__
+ # error
+ #endif
+], [compiler_xlc=yes], [compiler_xlc=no])
+AC_MSG_RESULT($compiler_xlc)
+AM_CONDITIONAL(COMPILER_XLC,test $compiler_xlc = yes)
+if test $compiler_xlc = yes -a "$powerpc_darwin" = true; then
+ # the darwin stack-frame-walking code is completely broken on xlc
+ AC_DEFINE([DARWIN_DONT_PARSE_STACK], 1, [See doc/README.macros.])
+fi
+
+if test "$GCC" = yes; then
+ # Disable aliasing optimization unless forced to.
+ AC_MSG_CHECKING([whether gcc supports -fno-strict-aliasing])
+ ac_cv_fno_strict_aliasing=no
+ for cflag in $CFLAGS; do
+ case "$cflag" in
+ -fstrict-aliasing)
+ # Opposite option already present
+ ac_cv_fno_strict_aliasing=skipped
+ break
+ ;;
+ esac
+ done
+ if test "$ac_cv_fno_strict_aliasing" != skipped; then
+ old_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -fno-strict-aliasing"
+ AC_TRY_COMPILE([],[], [ac_cv_fno_strict_aliasing=yes], [])
+ CFLAGS="$old_CFLAGS"
+ AS_IF([test "$ac_cv_fno_strict_aliasing" = yes],
+ [CFLAGS="$CFLAGS -fno-strict-aliasing"], [])
+ fi
+ AC_MSG_RESULT($ac_cv_fno_strict_aliasing)
+fi
+
+case "$host" in
+# While IRIX 6 has libdl for the O32 and N32 ABIs, it's missing for N64
+# and unnecessary everywhere.
+ mips-sgi-irix6*) ;;
+# We never want libdl on darwin. It is a fake libdl that just ends up making
+# dyld calls anyway. The same applies to Cygwin.
+ *-*-darwin*) ;;
+ *-*-cygwin*) ;;
+ *)
+ AC_CHECK_LIB(dl, dlopen, THREADDLLIBS="$THREADDLLIBS -ldl")
+ ;;
+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*)
+ extra_ldflags_libgc=-Wl,-single_module
+ ;;
+esac
+AC_SUBST(extra_ldflags_libgc)
+
+AC_SUBST(EXTRA_TEST_LIBS)
+
+target_all=libgc.la
+AC_SUBST(target_all)
+
+dnl If the target is an eCos system, use the appropriate eCos
+dnl I/O routines.
+dnl FIXME: this should not be a local option but a global target
+dnl system; at present there is no eCos target.
+TARGET_ECOS="no"
+AC_ARG_WITH(ecos,
+[ --with-ecos enable runtime eCos target support],
+TARGET_ECOS="$with_ecos"
+)
+
+addobjs=
+addlibs=
+CXXINCLUDES=
+CXXLIBS=
+
+case "$TARGET_ECOS" in
+ no)
+ ;;
+ *)
+ AC_DEFINE([ECOS], 1, [Define to enable eCos target support.])
+ CXXINCLUDES="-I${TARGET_ECOS}/include"
+ addobjs="$addobjs ecos.lo"
+ ;;
+esac
+
+AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes)
+
+if test "$GCC" = yes; then
+ if test "${enable_cplusplus}" = yes; then
+ case "$host" in
+ *-*-cygwin* | *-*-mingw*)
+ AC_MSG_CHECKING([whether libsupc++ required])
+ SUPC="`$CXX -print-file-name=libsupc++.a 2>/dev/null`"
+ if test -n "$SUPC" -a "$SUPC" != "libsupc++.a"; then
+ AC_MSG_RESULT(yes)
+ CXXLIBS="-lsupc++"
+ else
+ AC_MSG_RESULT(no)
+ fi
+ ;;
+ esac
+ fi
+fi
+
+AC_SUBST(CXX)
+
+AC_SUBST(INCLUDES)
+AC_SUBST(CXXINCLUDES)
+AC_SUBST(CXXLIBS)
+
+# Configuration of shared libraries
+#
+AC_MSG_CHECKING(whether to build shared libraries)
+AC_ENABLE_SHARED
+
+case "$host" in
+ alpha-*-openbsd*)
+ enable_shared=no
+ ;;
+ *)
+ ;;
+esac
+
+AC_MSG_RESULT($enable_shared)
+
+# Compile with GC_DLL defined unless building static libraries.
+if test "${enable_shared}" = yes; then
+ if test "${enable_static}" = no; then
+ AC_DEFINE(GC_DLL)
+ if test "$GCC" = yes; then
+ # Pass -fvisibility=hidden option if supported
+ AC_MSG_CHECKING([whether gcc supports -fvisibility])
+ old_CFLAGS="$CFLAGS"
+ CFLAGS="-Werror -fvisibility=hidden $CFLAGS"
+ AC_TRY_COMPILE([],[], [ac_cv_fvisibility_hidden=yes],
+ [ac_cv_fvisibility_hidden=no])
+ CFLAGS="$old_CFLAGS"
+ AS_IF([test "$ac_cv_fvisibility_hidden" = yes],
+ [CFLAGS="-DGC_VISIBILITY_HIDDEN_SET -fvisibility=hidden $CFLAGS"])
+ AC_MSG_RESULT($ac_cv_fvisibility_hidden)
+ fi
+ fi
+fi
+
+# Configuration of machine-dependent code
+#
+AC_MSG_CHECKING(which machine-dependent code should be used)
+machdep=
+case "$host" in
+ alpha-*-openbsd*)
+ if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
+ AC_MSG_WARN(
+ "OpenBSD/Alpha without dlopen(). Shared library support is disabled.")
+ fi
+ ;;
+ i?86-*-solaris2.[[89]])
+ # PROC_VDB appears to work in 2.8 and 2.9 but not in 2.10+ (for now).
+ AC_DEFINE([SOLARIS25_PROC_VDB_BUG_FIXED], 1,
+ [See the comment in gcconfig.h.])
+ ;;
+ mips-*-*)
+ dnl AC_DEFINE(NO_EXECUTE_PERMISSION)
+ dnl This is now redundant, but it is also important for incremental GC
+ dnl performance under Irix.
+ ;;
+ sparc-*-netbsd*)
+ machdep="src/sparc_netbsd_mach_dep.lo"
+ ;;
+ sparc*-*-linux* | sparc*-*-openbsd* | sparc64-*-netbsd*)
+ machdep="src/sparc_mach_dep.lo"
+ ;;
+ sparc-sun-solaris2.3)
+ machdep="src/sparc_mach_dep.lo"
+ AC_DEFINE(SUNOS53_SHARED_LIB, 1,
+ [Define to work around a Solaris 5.3 bug (see dyn_load.c).])
+ ;;
+ sparc*-sun-solaris2*)
+ machdep="src/sparc_mach_dep.lo"
+ ;;
+ ia64-*-*)
+ machdep="src/ia64_save_regs_in_stack.lo"
+ ;;
+esac
+AC_MSG_RESULT($machdep)
+addobjs="$addobjs $machdep"
+AC_SUBST(addobjs)
+AC_SUBST(addlibs)
+
+AC_PROG_LIBTOOL
+
+dnl We use these options to decide which functions to include.
+AC_ARG_WITH(target-subdir,
+[ --with-target-subdir=SUBDIR
+ configuring with a cross compiler])
+AC_ARG_WITH(cross-host,
+[ --with-cross-host=HOST configuring with a cross compiler])
+
+# automake wants to see AC_EXEEXT. But we don't need it. And having
+# it is actually a problem, because the compiler we're passed can't
+# necessarily do a full link. So we fool automake here.
+if false; then
+ # autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
+ # to nothing, so nothing would remain between `then' and `fi' if it
+ # were not for the `:' below.
+ :
+ AC_EXEEXT
+fi
+
+dnl As of 4.13a2, the collector will not properly work on Solaris when
+dnl built with gcc and -O. So we remove -O in the appropriate case.
+dnl Not needed anymore on Solaris.
+AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
+case "$host" in
+ *aix*)
+ if test "$GCC" = yes; then
+ AC_MSG_RESULT(yes)
+ new_CFLAGS=
+ for i in $CFLAGS; do
+ case "$i" in
+ -O*)
+ ;;
+ *)
+ new_CFLAGS="$new_CFLAGS $i"
+ ;;
+ esac
+ done
+ CFLAGS="$new_CFLAGS"
+ else
+ AC_MSG_RESULT(no)
+ fi
+ ;;
+ *) AC_MSG_RESULT(no) ;;
+esac
+
+dnl Include defines that have become de facto standard.
+dnl ALL_INTERIOR_POINTERS and NO_EXECUTE_PERMISSION can be overridden
+dnl in the startup code.
+AC_DEFINE([NO_EXECUTE_PERMISSION], [1],
+ [Define to make the collector not allocate executable memory
+ by default.])
+AC_DEFINE([ALL_INTERIOR_POINTERS], [1],
+ [Define to recognise all pointers to the interior of objects.])
+
+
+dnl Interface Selection
+dnl -------------------
+dnl
+dnl By default, make the library as general as possible.
+dnl enable_gcj_support=no
+AC_ARG_ENABLE(gcj-support,
+ [AC_HELP_STRING([--disable-gcj-support],
+ [Disable support for gcj.])])
+if test x"$enable_gcj_support" != xno; then
+ AC_DEFINE(GC_GCJ_SUPPORT, 1, [Define to include support for gcj.])
+fi
+
+dnl Debugging
+dnl ---------
+
+AH_TEMPLATE([GC_HAVE_BUILTIN_BACKTRACE],
+ [Define if backtrace information is supported.])
+AH_TEMPLATE([MAKE_BACK_GRAPH], [See doc/README.macros.])
+AH_TEMPLATE([SAVE_CALL_COUNT],
+ [The number of caller frames saved when allocating with the
+ debugging API.])
+UNWINDLIBS=
+AC_ARG_ENABLE(gc-debug,
+[AC_HELP_STRING([--enable-gc-debug],
+ [include full support for pointer backtracing etc.])],
+[ if test "$enable_gc_debug" = "yes"; then
+ AC_MSG_WARN("Should define GC_DEBUG and use debug alloc in clients.")
+ AC_DEFINE([KEEP_BACK_PTRS], 1,
+ [Define to save back-pointers in debugging headers.])
+ keep_back_ptrs=true
+ AC_DEFINE([DBG_HDRS_ALL], 1,
+ [Define to force debug headers on all objects.])
+ AH_TEMPLATE([SHORT_DBG_HDRS],
+ [Shorten the headers to minimize object size at the expense
+ of checking for writes past the end (see doc/README.macros).])
+
+ case $host in
+ ia64-*-linux* )
+ AC_DEFINE(MAKE_BACK_GRAPH)
+ AC_DEFINE(SAVE_CALL_COUNT, 8)
+ AC_CHECK_LIB(unwind, backtrace, [
+ AC_DEFINE(GC_HAVE_BUILTIN_BACKTRACE)
+ UNWINDLIBS=-lunwind
+ AC_MSG_WARN("Client code may need to link against libunwind.")
+ ])
+ ;;
+ x86-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
+ AC_DEFINE(MAKE_BACK_GRAPH)
+ AC_MSG_WARN("Client must not use -fomit-frame-pointer.")
+ AC_DEFINE(SAVE_CALL_COUNT, 8)
+ ;;
+ i[3456]86-*-dgux*)
+ AC_DEFINE(MAKE_BACK_GRAPH)
+ ;;
+ esac ]
+ fi)
+AM_CONDITIONAL([MAKE_BACK_GRAPH], [test x"$enable_gc_debug" = xyes])
+AM_CONDITIONAL([KEEP_BACK_PTRS], [test x"$keep_back_ptrs" = xtrue])
+
+# Check for AViiON Machines running DGUX
+ac_is_dgux=no
+AC_CHECK_HEADER(sys/dg_sys_info.h,
+[ac_is_dgux=yes;])
+
+ ## :GOTCHA: we do not check anything but sys/dg_sys_info.h
+if test $ac_is_dgux = yes; then
+ dgux_spec_opts="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
+ CFLAGS="$dgux_spec_opts $CFLAGS"
+ CXXFLAGS="$dgux_spec_opts $CXXFLAGS"
+ if test "$enable_gc_debug" = "yes"; then
+ CFLAGS="-g -mstandard $CFLAGS"
+ CXXFLAGS="-g -mstandard $CXXFLAGS"
+ fi
+ AC_SUBST(CFLAGS)
+ AC_SUBST(CXXFLAGS)
+fi
+
+AC_ARG_ENABLE(java-finalization,
+ [AC_HELP_STRING([--disable-java-finalization],
+ [Disable support for java finalization.])])
+if test x"$enable_java_finalization" != xno; then
+ AC_DEFINE([JAVA_FINALIZATION], 1, [See doc/README.macros.])
+fi
+
+AC_ARG_ENABLE(atomic-uncollectable,
+ [AC_HELP_STRING([--disable-atomic-uncollectible],
+ [Disable support for atomic uncollectible allocation.])])
+if test x"$enable_atomic_uncollectible" != x"no"; then
+ AC_DEFINE(ATOMIC_UNCOLLECTABLE, 1,
+ [Define to enable atomic uncollectible allocation.])
+fi
+
+AC_ARG_ENABLE(redirect-malloc,
+ [AC_HELP_STRING([--enable-redirect-malloc],
+ [Redirect malloc and friends to GC routines])])
+
+if test "${enable_redirect_malloc}" = yes; then
+ if test "${enable_gc_debug}" = yes; then
+ AC_DEFINE([REDIRECT_MALLOC], GC_debug_malloc_replacement,
+ [If defined, redirect malloc to this function.])
+ AC_DEFINE([REDIRECT_REALLOC], GC_debug_realloc_replacement,
+ [If defined, redirect GC_realloc to this function.])
+ AC_DEFINE([REDIRECT_FREE], GC_debug_free,
+ [If defined, redirect free to this function.])
+ else
+ AC_DEFINE(REDIRECT_MALLOC, GC_malloc)
+ fi
+ AC_DEFINE([GC_USE_DLOPEN_WRAP], 1, [See doc/README.macros.])
+fi
+
+AC_ARG_ENABLE(disclaim,
+ [AC_HELP_STRING([--disable-disclaim],
+ [Disable alternative (more efficient) finalization interface.])])
+if test x"$enable_disclaim" != xno; then
+ AC_DEFINE(ENABLE_DISCLAIM, 1,
+ [Define to enable alternative finalization interface.])
+fi
+AM_CONDITIONAL(ENABLE_DISCLAIM,
+ [test x"$enable_disclaim" != xno])
+
+AC_ARG_ENABLE(large-config,
+ [AC_HELP_STRING([--enable-large-config],
+ [Optimize for large (> 100 MB) heap or root set])])
+
+if test "${enable_large_config}" = yes; then
+ AC_DEFINE(LARGE_CONFIG, 1, [Define to optimize for large heaps or root sets.])
+fi
+
+AC_ARG_ENABLE(handle-fork,
+ [AC_HELP_STRING([--enable-handle-fork],
+ [Attempt to ensure a usable collector after fork() in multi-threaded
+ programs.])])
+
+if test "${enable_handle_fork}" = yes; then
+ AC_DEFINE(HANDLE_FORK, 1,
+ [Define to install pthread_atfork() handlers by default.])
+elif test "${enable_handle_fork}" = no; then
+ AC_DEFINE(NO_HANDLE_FORK, 1,
+ [Prohibit installation of pthread_atfork() handlers.])
+fi
+
+dnl This is something of a hack. When cross-compiling we turn off
+dnl some functionality. We also enable the "small" configuration.
+dnl These is only correct when targetting an embedded system. FIXME.
+if test -n "${with_cross_host}"; then
+ AC_DEFINE([NO_CLOCK], 1, [Define to not use system clock (cross compiling).])
+ AC_DEFINE([SMALL_CONFIG], 1,
+ [Define to tune the collector for small heap sizes.])
+fi
+
+if test "$enable_gc_debug" = "no"; then
+ AC_DEFINE([NO_DEBUGGING], 1,
+ [Disable debugging, like GC_dump and its callees.])
+fi
+
+AC_SUBST(UNWINDLIBS)
+
+AC_ARG_ENABLE(gc-assertions,
+ [AC_HELP_STRING([--enable-gc-assertions],
+ [collector-internal assertion checking])])
+if test "${enable_gc_assertions}" = yes; then
+ AC_DEFINE([GC_ASSERTIONS], 1, [Define to enable internal debug 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)
+if test "${enable_munmap}" != ""; then
+ AC_DEFINE([USE_MMAP], 1,
+ [Define to use mmap instead of sbrk to expand the heap.])
+ case "$host" in
+ *-*-cygwin*)
+ # Workaround for Cygwin: use VirtualAlloc since mmap(PROT_NONE) fails
+ AC_DEFINE([USE_WINALLOC], 1,
+ [Define to use Win32 VirtualAlloc (instead of sbrk or
+ mmap) to expand the heap.])
+ ;;
+ esac
+ AC_DEFINE([USE_MUNMAP], 1,
+ [Define to return memory to OS with munmap calls
+ (see doc/README.macros).])
+ if test "${MUNMAP_THRESHOLD}" = "yes"; then
+ MUNMAP_THRESHOLD=6
+ fi
+ AC_DEFINE_UNQUOTED([MUNMAP_THRESHOLD], [${MUNMAP_THRESHOLD}],
+ [Number of GC cycles to wait before unmapping an unused block.])
+else
+ if test "${gc_use_mmap}" = "yes"; then
+ AC_DEFINE([USE_MMAP], 1,
+ [Define to use mmap instead of sbrk to expand the heap.])
+ fi
+fi
+
+AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
+
+AC_ARG_ENABLE(single-obj-compilation,
+ [AC_HELP_STRING([--enable-single-obj-compilation],
+ [Compile all library .c files into single .o])],
+ [single_obj_compilation=yes])
+AM_CONDITIONAL([SINGLE_GC_OBJ], [test "$single_obj_compilation" = "yes"])
+
+# Atomic Ops
+# ----------
+
+# Do we want to use an external libatomic_ops? By default use it if it's
+# found.
+AC_ARG_WITH([libatomic-ops],
+ [AS_HELP_STRING([--with-libatomic-ops[=yes|no|check]],
+ [Use a external libatomic_ops? (default: check)])],
+ [], [with_libatomic_ops=check])
+
+# Check for an external libatomic_ops if the answer was yes or check. If not
+# found, fail on yes, and convert check to no.
+AS_IF([test x"$with_libatomic_ops" != xno],
+ [ PKG_CHECK_MODULES([ATOMIC_OPS], [atomic_ops], [],
+ [ AS_IF([test x"$with_libatomic_ops" != xcheck],
+ [AC_MSG_ERROR([A external libatomic_ops was not found.])])
+ with_libatomic_ops=no ]) ])
+
+# If we have neither an external or an internal version, offer a useful hint
+# and exit.
+AS_IF([test x"$with_libatomic_ops" = xno -a ! -e "$srcdir/libatomic_ops"],
+ [ AC_MSG_ERROR([libatomic_ops is required. You can either install it on
+ your system, or fetch and unpack a recent version into the
+ source directory and link or rename it to libatomic_ops.]) ])
+
+# Finally, emit the definitions for bundled or external AO.
+AC_MSG_CHECKING([which libatomic_ops to use])
+AS_IF([test x"$with_libatomic_ops" != xno],
+ [ AC_MSG_RESULT([external]) ],
+ [ AC_MSG_RESULT([internal])
+ ATOMIC_OPS_CFLAGS='-I$(top_builddir)/libatomic_ops/src -I$(top_srcdir)/libatomic_ops/src'
+ ATOMIC_OPS_LIBS=""
+ AC_SUBST([ATOMIC_OPS_CFLAGS])
+ AC_CONFIG_SUBDIRS([libatomic_ops])
+ ])
+AM_CONDITIONAL([USE_INTERNAL_LIBATOMIC_OPS],
+ [test x$with_libatomic_ops = xno -a x"$THREADS" != xnone])
+AM_CONDITIONAL([NEED_ATOMIC_OPS_ASM],
+ [test x$with_libatomic_ops = xno -a x$need_atomic_ops_asm = xtrue])
+
+dnl Produce the Files
+dnl -----------------
+
+AC_CONFIG_FILES([Makefile bdw-gc.pc])
+
+AC_CONFIG_COMMANDS([default],,
+ [ srcdir="${srcdir}"
+ host=${host}
+ CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+ CC="${CC}"
+ DEFS="$DEFS" ])
+
+AC_OUTPUT
diff --git a/boehm-gc/configure.host b/boehm-gc/configure.host
deleted file mode 100644
index a98a0a7cb30..00000000000
--- a/boehm-gc/configure.host
+++ /dev/null
@@ -1,61 +0,0 @@
-# configure.host
-
-# This shell script handles all host based configuration for the garbage
-# collector.
-# It sets various shell variables based on the the host and the
-# configuration options. You can modify this shell script without
-# needing to rerun autoconf.
-
-# This shell script should be invoked as
-# . configure.host
-# If it encounters an error, it will exit with a message.
-
-# It uses the following shell variables:
-# host The configuration host
-# host_cpu The configuration host CPU
-# target_optspace --enable-target-optspace ("yes", "no", "")
-# GCC should be "yes" if using gcc
-
-# It sets the following shell variables:
-# gc_cflags Special CFLAGS to use when building
-
-gc_cflags=""
-
-# We should set -fexceptions if we are using gcc and might be used
-# inside something like gcj. This is the zeroth approximation:
-if test :"$GCC": = :yes: ; then
- gc_cflags="${gc_cflags} -fexceptions"
-else
- case "$host" in
- hppa*-*-hpux* )
- if test :$GCC: != :"yes": ; then
- gc_cflags="${gc_flags} +ESdbgasm"
- fi
- # :TODO: actaully we should check using Autoconf if
- # the compiler supports this option.
- ;;
- esac
-fi
-
-case "${target_optspace}:${host}" in
- yes:*)
- gc_cflags="${gc_cflags} -Os"
- ;;
- :m32r-* | :d10v-* | :d30v-*)
- gc_cflags="${gc_cflags} -Os"
- ;;
- no:* | :*)
- # Nothing.
- ;;
-esac
-
-# Set any host dependent compiler flags.
-# THIS TABLE IS SORTED. KEEP IT THAT WAY.
-
-case "${host}" in
- mips-tx39-*|mipstx39-unknown-*)
- gc_cflags="${gc_cflags} -G 0"
- ;;
- *)
- ;;
-esac
diff --git a/boehm-gc/configure.in b/boehm-gc/configure.in
deleted file mode 100644
index 7914692d21a..00000000000
--- a/boehm-gc/configure.in
+++ /dev/null
@@ -1,455 +0,0 @@
-# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
-#
-# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-#
-# Permission is hereby granted to use or copy this program
-# for any purpose, provided the above notices are retained on all copies.
-# Permission to modify the code and to distribute modified code is granted,
-# provided the above notices are retained, and a notice that the code was
-# modified is included with the above copyright notice.
-#
-# Original author: Tom Tromey
-# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
-
-dnl Process this file with autoconf to produce configure.
-
-# Initialization
-# ==============
-
-AC_INIT(gc,6.3,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.2 $)
-GC_SET_VERSION
-AM_INIT_AUTOMAKE
-
-AC_SUBST(PACKAGE)
-AC_SUBST(GC_VERSION)
-
-AC_PROG_CC
-AC_PROG_CXX
-
-AM_PROG_AS
-AC_CHECK_TOOL(AR, ar)
-AC_CHECK_TOOL(RANLIB, ranlib, :) # :)
-
-AC_PROG_INSTALL
-
-AM_MAINTAINER_MODE
-
-. [$]{srcdir}/configure.host
-
-GC_CFLAGS=${gc_cflags}
-AC_SUBST(GC_CFLAGS)
-
-AC_ARG_ENABLE(threads, [ --enable-threads=TYPE choose threading package],
- THREADS=$enableval,
- [ AC_MSG_CHECKING([for thread model used by GCC])
- THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
- if test -z "$THREADS"; then
- THREADS=no
- fi
- AC_MSG_RESULT([$THREADS])])
-
-AC_ARG_ENABLE(parallel-mark,
-[ --enable-parallel-mark parallelize marking and free list construction],
- [case "$THREADS" in
- no | none | single)
- AC_MSG_ERROR([Parallel mark requires --enable-threads=x spec])
- ;;
- esac]
-)
-
-AC_ARG_ENABLE(cplusplus,
-[ --enable-cplusplus install C++ support],
-)
-
-INCLUDES=-I${srcdir}/include
-THREADLIBS=
-case "$THREADS" in
- no | none | single)
- THREADS=none
- ;;
- posix | pthreads)
- THREADS=posix
- THREADLIBS=-lpthread
- case "$host" in
- x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
- AC_DEFINE(GC_LINUX_THREADS)
- AC_DEFINE(_REENTRANT)
- if test "${enable_parallel_mark}" = yes; then
- AC_DEFINE(PARALLEL_MARK)
- fi
- AC_DEFINE(THREAD_LOCAL_ALLOC)
- ;;
- *-*-linux*)
- AC_DEFINE(GC_LINUX_THREADS)
- AC_DEFINE(_REENTRANT)
- ;;
- *-*-aix*)
- AC_DEFINE(GC_AIX_THREADS)
- AC_DEFINE(_REENTRANT)
- ;;
- *-*-hpux*)
- AC_MSG_WARN("Only HP/UX 11 threads are supported.")
- AC_DEFINE(GC_HPUX_THREADS)
- AC_DEFINE(_POSIX_C_SOURCE,199506L)
- if test "${enable_parallel_mark}" = yes; then
- AC_DEFINE(PARALLEL_MARK)
- fi
- AC_DEFINE(THREAD_LOCAL_ALLOC)
- THREADLIBS="-lpthread -lrt"
- ;;
- *-*-freebsd*)
- AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.")
- AC_DEFINE(GC_FREEBSD_THREADS)
- INCLUDES="$INCLUDES -pthread"
- THREADLIBS=-pthread
- ;;
- *-*-solaris*)
- AC_DEFINE(GC_SOLARIS_THREADS)
- AC_DEFINE(GC_SOLARIS_PTHREADS)
- ;;
- *-*-irix*)
- AC_DEFINE(GC_IRIX_THREADS)
- ;;
- *-*-cygwin*)
- AC_DEFINE(GC_WIN32_THREADS)
- ;;
- *-*-darwin*)
- AC_DEFINE(GC_DARWIN_THREADS)
- AC_DEFINE(THREAD_LOCAL_ALLOC)
- if test "${enable_parallel_mark}" = yes; then
- AC_DEFINE(PARALLEL_MARK)
- fi
- ;;
- *-*-osf*)
- AC_DEFINE(GC_OSF1_THREADS)
- if test "${enable_parallel_mark}" = yes; then
- AC_DEFINE(PARALLEL_MARK)
- AC_DEFINE(THREAD_LOCAL_ALLOC)
- # May want to enable it in other cases, too.
- # Measurements havent yet been done.
- fi
- INCLUDES="$INCLUDES -pthread"
- THREADLIBS="-lpthread -lrt"
- ;;
- esac
- ;;
- win32)
- AC_DEFINE(GC_WIN32_THREADS)
- dnl Wine getenv may not return NULL for missing entry
- AC_DEFINE(NO_GETENV)
- ;;
- dgux386)
- THREADS=dgux386
- AC_MSG_RESULT($THREADLIBS)
- # Use pthread GCC switch
- THREADLIBS=-pthread
- if test "${enable_parallel_mark}" = yes; then
- AC_DEFINE(PARALLEL_MARK)
- fi
- AC_DEFINE(THREAD_LOCAL_ALLOC)
- AC_DEFINE(GC_DGUX386_THREADS)
- AC_DEFINE(DGUX_THREADS)
- # Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
- INCLUDES="-pthread $INCLUDES"
- ;;
- aix)
- THREADS=posix
- THREADLIBS=-lpthread
- AC_DEFINE(GC_AIX_THREADS)
- AC_DEFINE(_REENTRANT)
- ;;
- decosf1 | irix | mach | os2 | solaris | dce | vxworks)
- AC_MSG_ERROR(thread package $THREADS not yet supported)
- ;;
- *)
- AC_MSG_ERROR($THREADS is an unknown thread package)
- ;;
-esac
-AC_SUBST(THREADLIBS)
-
-case "$host" in
- powerpc-*-darwin*)
- powerpc_darwin=true
- ;;
-esac
-AM_CONDITIONAL(POWERPC_DARWIN,test x$powerpc_darwin = xtrue)
-
-# We never want libdl on darwin. It is a fake libdl that just ends up making
-# dyld calls anyway
-case "$host" in
- *-*-darwin*) ;;
- *)
- AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl")
- ;;
-esac
-
-AC_SUBST(EXTRA_TEST_LIBS)
-
-target_all=libgc.la
-AC_SUBST(target_all)
-
-dnl If the target is an eCos system, use the appropriate eCos
-dnl I/O routines.
-dnl FIXME: this should not be a local option but a global target
-dnl system; at present there is no eCos target.
-TARGET_ECOS="no"
-AC_ARG_WITH(ecos,
-[ --with-ecos enable runtime eCos target support],
-TARGET_ECOS="$with_ecos"
-)
-
-addobjs=
-addlibs=
-addincludes=
-addtests=
-CXXINCLUDES=
-case "$TARGET_ECOS" in
- no)
- ;;
- *)
- AC_DEFINE(ECOS)
- CXXINCLUDES="-I${TARGET_ECOS}/include"
- addobjs="$addobjs ecos.lo"
- ;;
-esac
-
-if test "${enable_cplusplus}" = yes; then
- addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
- addtests="$addtests test_cpp"
-fi
-
-AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes)
-
-AC_SUBST(CXX)
-
-AC_SUBST(INCLUDES)
-AC_SUBST(CXXINCLUDES)
-
-# Configuration of shared libraries
-#
-AC_MSG_CHECKING(whether to build shared libraries)
-AC_ENABLE_SHARED
-
-case "$host" in
- alpha-*-openbsd*)
- enable_shared=no
- AC_MSG_RESULT(no)
- ;;
- *)
- AC_MSG_RESULT(yes)
- ;;
-esac
-
-# Configuration of machine-dependent code
-#
-AC_MSG_CHECKING(which machine-dependent code should be used)
-machdep=
-case "$host" in
- alpha-*-openbsd*)
- machdep="alpha_mach_dep.lo"
- if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
- AC_MSG_WARN(OpenBSD/Alpha without dlopen(). Shared library support is disabled)
- fi
- ;;
- alpha*-*-linux*)
- machdep="alpha_mach_dep.lo"
- ;;
- i?86-*-solaris2.[[89]] | i?86-*-solaris2.1?)
- AC_DEFINE(SOLARIS25_PROC_VDB_BUG_FIXED)
- ;;
- mipstx39-*-elf*)
- machdep="mips_ultrix_mach_dep.lo"
- AC_DEFINE(STACKBASE, __stackbase)
- AC_DEFINE(DATASTART_IS_ETEXT)
- ;;
- mips-dec-ultrix*)
- machdep="mips_ultrix_mach-dep.lo"
- ;;
- mips-nec-sysv*|mips-unknown-sysv*)
- ;;
- mips*-*-linux*)
- ;;
- mips-*-*)
- machdep="mips_sgi_mach_dep.lo"
- AC_DEFINE(NO_EXECUTE_PERMISSION)
- ;;
- sparc-*-netbsd*)
- machdep="sparc_netbsd_mach_dep.lo"
- ;;
- sparc-sun-solaris2.3)
- machdep="sparc_mach_dep.lo"
- AC_DEFINE(SUNOS53_SHARED_LIB)
- ;;
- sparc-sun-solaris2.*)
- machdep="sparc_mach_dep.lo"
- ;;
- ia64-*-*)
- machdep="mach_dep.lo ia64_save_regs_in_stack.lo"
- ;;
-esac
-if test x"$machdep" = x; then
-AC_MSG_RESULT($machdep)
- machdep="mach_dep.lo"
-fi
-addobjs="$addobjs $machdep"
-AC_SUBST(addobjs)
-AC_SUBST(addincludes)
-AC_SUBST(addlibs)
-AC_SUBST(addtests)
-
-AC_PROG_LIBTOOL
-
-#
-# Check for AViiON Machines running DGUX
-#
-ac_is_dgux=no
-AC_CHECK_HEADER(sys/dg_sys_info.h,
-[ac_is_dgux=yes;])
-
- ## :GOTCHA: we do not check anything but sys/dg_sys_info.h
-if test $ac_is_dgux = yes; then
- if test "$enable_full_debug" = "yes"; then
- CFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
- CXXFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
- else
- CFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
- CXXFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
- fi
- AC_SUBST(CFLAGS)
- AC_SUBST(CXXFLAGS)
-fi
-
-dnl We use these options to decide which functions to include.
-AC_ARG_WITH(target-subdir,
-[ --with-target-subdir=SUBDIR
- configuring with a cross compiler])
-AC_ARG_WITH(cross-host,
-[ --with-cross-host=HOST configuring with a cross compiler])
-
-# automake wants to see AC_EXEEXT. But we don't need it. And having
-# it is actually a problem, because the compiler we're passed can't
-# necessarily do a full link. So we fool automake here.
-if false; then
- # autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
- # to nothing, so nothing would remain between `then' and `fi' if it
- # were not for the `:' below.
- :
- AC_EXEEXT
-fi
-
-dnl As of 4.13a2, the collector will not properly work on Solaris when
-dnl built with gcc and -O. So we remove -O in the appropriate case.
-dnl
-AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
-case "$host" in
- sparc-sun-solaris2*|*aix*)
- if test "$GCC" = yes; then
- AC_MSG_RESULT(yes)
- new_CFLAGS=
- for i in $CFLAGS; do
- case "$i" in
- -O*)
- ;;
- *)
- new_CFLAGS="$new_CFLAGS $i"
- ;;
- esac
- done
- CFLAGS="$new_CFLAGS"
- else
- AC_MSG_RESULT(no)
- fi
- ;;
- *) AC_MSG_RESULT(no) ;;
-esac
-
-dnl We need to override the top-level CFLAGS. This is how we do it.
-MY_CFLAGS="$CFLAGS"
-AC_SUBST(MY_CFLAGS)
-
-dnl Include defines that have become de facto standard.
-dnl ALL_INTERIOR_POINTERS can be overridden in startup code.
-AC_DEFINE(SILENT)
-AC_DEFINE(NO_SIGNALS)
-AC_DEFINE(NO_EXECUTE_PERMISSION)
-AC_DEFINE(ALL_INTERIOR_POINTERS)
-
-dnl By default, make the library as general as possible.
-AC_DEFINE(JAVA_FINALIZATION)
-AC_DEFINE(GC_GCJ_SUPPORT)
-AC_DEFINE(ATOMIC_UNCOLLECTABLE)
-
-dnl This is something of a hack. When cross-compiling we turn off
-dnl some functionality. We also enable the "small" configuration.
-dnl These is only correct when targetting an embedded system. FIXME.
-if test -n "${with_cross_host}"; then
- AC_DEFINE(NO_SIGSET)
- AC_DEFINE(NO_CLOCK)
- AC_DEFINE(SMALL_CONFIG)
- AC_DEFINE(NO_DEBUGGING)
-fi
-
-UNWINDLIBS=
-AC_ARG_ENABLE(full-debug,
-[ --enable-full-debug include full support for pointer backtracing etc.],
-[ if test "$enable_full_debug" = "yes"; then
- AC_MSG_WARN("Should define GC_DEBUG and use debug alloc. in clients.")
- AC_DEFINE(KEEP_BACK_PTRS)
- AC_DEFINE(DBG_HDRS_ALL)
- case $host in
- ia64-*-linux* )
- AC_DEFINE(MAKE_BACK_GRAPH)
- AC_DEFINE(SAVE_CALL_COUNT, 8)
- AC_CHECK_LIB(unwind, backtrace, [
- AC_DEFINE(GC_HAVE_BUILTIN_BACKTRACE)
- UNWINDLIBS=-lunwind
- AC_MSG_WARN("Client code may need to link against libunwind.")
- ])
- ;;
- x86-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
- AC_DEFINE(MAKE_BACK_GRAPH)
- AC_MSG_WARN("Client must not use -fomit-frame-pointer.")
- AC_DEFINE(SAVE_CALL_COUNT, 8)
- ;;
- i[3456]86-*-dgux*)
- AC_DEFINE(MAKE_BACK_GRAPH)
- ;;
- esac ]
- fi)
-
-AC_SUBST(UNWINDLIBS)
-
-AC_ARG_ENABLE(redirect-malloc,
-[ --enable-redirect-malloc redirect malloc and friends to GC routines])
-
-if test "${enable_redirect_malloc}" = yes; then
- if test "${enable_full_debug}" = yes; then
- AC_DEFINE(REDIRECT_MALLOC, GC_debug_malloc_replacement)
- AC_DEFINE(REDIRECT_REALLOC, GC_debug_realloc_replacement)
- AC_DEFINE(REDIRECT_FREE, GC_debug_free)
- else
- AC_DEFINE(REDIRECT_MALLOC, GC_malloc)
- fi
-fi
-
-AC_ARG_ENABLE(gc-assertions,
-[ --enable-gc-assertions collector-internal assertion checking])
-if test "${enable_gc_assertions}" = yes; then
- AC_DEFINE(GC_ASSERTIONS)
-fi
-
-AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
-
-AC_OUTPUT([Makefile doc/Makefile include/Makefile],,
-srcdir=${srcdir}
-host=${host}
-CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
-CC="${CC}"
-DEFS="$DEFS"
-)
diff --git a/boehm-gc/cord/cord.am b/boehm-gc/cord/cord.am
new file mode 100644
index 00000000000..7d3fbe552fc
--- /dev/null
+++ b/boehm-gc/cord/cord.am
@@ -0,0 +1,25 @@
+
+lib_LTLIBRARIES += libcord.la
+
+libcord_la_LIBADD = $(top_builddir)/libgc.la
+libcord_la_LDFLAGS = -version-info 1:3:0 -no-undefined
+libcord_la_CPPFLAGS = $(AM_CPPFLAGS)
+
+libcord_la_SOURCES = \
+ cord/cordbscs.c \
+ cord/cordprnt.c \
+ cord/cordxtra.c
+
+TESTS += cordtest$(EXEEXT)
+check_PROGRAMS += cordtest
+cordtest_SOURCES = cord/tests/cordtest.c
+cordtest_LDADD = $(top_builddir)/libgc.la $(top_builddir)/libcord.la
+
+EXTRA_DIST += \
+ cord/tests/de.c \
+ cord/tests/de_cmds.h \
+ cord/tests/de_win.c \
+ cord/tests/de_win.h \
+ cord/tests/de_win.rc
+
+pkginclude_HEADERS += include/cord.h
diff --git a/boehm-gc/cord/cordbscs.c b/boehm-gc/cord/cordbscs.c
index d83f4067de7..c7b3b51f220 100644
--- a/boehm-gc/cord/cordbscs.c
+++ b/boehm-gc/cord/cordbscs.c
@@ -9,74 +9,79 @@
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
- *
- * Author: Hans-J. Boehm (boehm@parc.xerox.com)
*/
-/* Boehm, October 3, 1994 5:19 pm PDT */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#ifndef CORD_BUILD
+# define CORD_BUILD
+#endif
+
# include "gc.h"
# include "cord.h"
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
-/* An implementation of the cord primitives. These are the only */
-/* Functions that understand the representation. We perform only */
-/* minimal checks on arguments to these functions. Out of bounds */
-/* arguments to the iteration functions may result in client functions */
-/* invoked on garbage data. In most cases, client functions should be */
-/* programmed defensively enough that this does not result in memory */
-/* smashes. */
+/* An implementation of the cord primitives. These are the only */
+/* Functions that understand the representation. We perform only */
+/* minimal checks on arguments to these functions. Out of bounds */
+/* arguments to the iteration functions may result in client functions */
+/* invoked on garbage data. In most cases, client functions should be */
+/* programmed defensively enough that this does not result in memory */
+/* smashes. */
typedef void (* oom_fn)(void);
oom_fn CORD_oom_fn = (oom_fn) 0;
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
- ABORT("Out of memory\n"); }
+ ABORT("Out of memory\n"); }
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
typedef unsigned long word;
typedef union {
struct Concatenation {
- char null;
- char header;
- char depth; /* concatenation nesting depth. */
- unsigned char left_len;
- /* Length of left child if it is sufficiently */
- /* short; 0 otherwise. */
-# define MAX_LEFT_LEN 255
- word len;
- CORD left; /* length(left) > 0 */
- CORD right; /* length(right) > 0 */
+ char null;
+ char header;
+ char depth; /* concatenation nesting depth. */
+ unsigned char left_len;
+ /* Length of left child if it is sufficiently */
+ /* short; 0 otherwise. */
+# define MAX_LEFT_LEN 255
+ word len;
+ CORD left; /* length(left) > 0 */
+ CORD right; /* length(right) > 0 */
} concatenation;
struct Function {
- char null;
- char header;
- char depth; /* always 0 */
- char left_len; /* always 0 */
- word len;
- CORD_fn fn;
- void * client_data;
+ char null;
+ char header;
+ char depth; /* always 0 */
+ char left_len; /* always 0 */
+ word len;
+ CORD_fn fn;
+ void * client_data;
} function;
struct Generic {
- char null;
- char header;
- char depth;
- char left_len;
- word len;
+ char null;
+ char header;
+ char depth;
+ char left_len;
+ word len;
} generic;
char string[1];
} CordRep;
# define CONCAT_HDR 1
-
+
# define FN_HDR 4
# define SUBSTR_HDR 6
- /* Substring nodes are a special case of function nodes. */
- /* The client_data field is known to point to a substr_args */
- /* structure, and the function is either CORD_apply_access_fn */
- /* or CORD_index_access_fn. */
+ /* Substring nodes are a special case of function nodes. */
+ /* The client_data field is known to point to a substr_args */
+ /* structure, and the function is either CORD_apply_access_fn */
+ /* or CORD_index_access_fn. */
/* The following may be applied only to function and concatenation nodes: */
#define IS_CONCATENATION(s) (((CordRep *)s)->generic.header == CONCAT_HDR)
@@ -90,26 +95,26 @@ typedef union {
#define GEN_LEN(s) (CORD_IS_STRING(s) ? strlen(s) : LEN(s))
#define LEFT_LEN(c) ((c) -> left_len != 0? \
- (c) -> left_len \
- : (CORD_IS_STRING((c) -> left) ? \
- (c) -> len - GEN_LEN((c) -> right) \
- : LEN((c) -> left)))
+ (c) -> left_len \
+ : (CORD_IS_STRING((c) -> left) ? \
+ (c) -> len - GEN_LEN((c) -> right) \
+ : LEN((c) -> left)))
#define SHORT_LIMIT (sizeof(CordRep) - 1)
- /* Cords shorter than this are C strings */
+ /* Cords shorter than this are C strings */
-/* Dump the internal representation of x to stdout, with initial */
-/* indentation level n. */
+/* Dump the internal representation of x to stdout, with initial */
+/* indentation level n. */
void CORD_dump_inner(CORD x, unsigned n)
{
register size_t i;
-
+
for (i = 0; i < (size_t)n; i++) {
fputs(" ", stdout);
}
if (x == 0) {
- fputs("NIL\n", stdout);
+ fputs("NIL\n", stdout);
} else if (CORD_IS_STRING(x)) {
for (i = 0; i <= SHORT_LIMIT; i++) {
if (x[i] == '\0') break;
@@ -119,14 +124,14 @@ void CORD_dump_inner(CORD x, unsigned n)
putchar('\n');
} else if (IS_CONCATENATION(x)) {
register struct Concatenation * conc =
- &(((CordRep *)x) -> concatenation);
+ &(((CordRep *)x) -> concatenation);
printf("Concatenation: %p (len: %d, depth: %d)\n",
x, (int)(conc -> len), (int)(conc -> depth));
CORD_dump_inner(conc -> left, n+1);
CORD_dump_inner(conc -> right, n+1);
} else /* function */{
register struct Function * func =
- &(((CordRep *)x) -> function);
+ &(((CordRep *)x) -> function);
if (IS_SUBSTR(x)) printf("(Substring) ");
printf("Function: %p (len: %d): ", x, (int)(func -> len));
for (i = 0; i < 20 && i < func -> len; i++) {
@@ -137,7 +142,7 @@ void CORD_dump_inner(CORD x, unsigned n)
}
}
-/* Dump the internal representation of x to stdout */
+/* Dump the internal representation of x to stdout */
void CORD_dump(CORD x)
{
CORD_dump_inner(x, 0);
@@ -149,7 +154,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
register size_t result_len;
register size_t lenx;
register int depth;
-
+
if (x == CORD_EMPTY) return(y);
if (leny == 0) return(x);
if (CORD_IS_STRING(x)) {
@@ -157,7 +162,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
result_len = lenx + leny;
if (result_len <= SHORT_LIMIT) {
register char * result = GC_MALLOC_ATOMIC(result_len+1);
-
+
if (result == 0) OUT_OF_MEMORY;
memcpy(result, x, lenx);
memcpy(result + lenx, y, leny);
@@ -167,35 +172,36 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
depth = 1;
}
} else {
- register CORD right;
- register CORD left;
- register char * new_right;
- register size_t right_len;
-
- lenx = LEN(x);
-
+ register CORD right;
+ register CORD left;
+ register char * new_right;
+ register size_t right_len;
+
+ lenx = LEN(x);
+
if (leny <= SHORT_LIMIT/2
- && IS_CONCATENATION(x)
+ && IS_CONCATENATION(x)
&& CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) {
/* Merge y into right part of x. */
if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) {
- right_len = lenx - LEN(left);
+ right_len = lenx - LEN(left);
} else if (((CordRep *)x) -> concatenation.left_len != 0) {
right_len = lenx - ((CordRep *)x) -> concatenation.left_len;
} else {
- right_len = strlen(right);
+ right_len = strlen(right);
}
result_len = right_len + leny; /* length of new_right */
if (result_len <= SHORT_LIMIT) {
- new_right = GC_MALLOC_ATOMIC(result_len + 1);
- memcpy(new_right, right, right_len);
- memcpy(new_right + right_len, y, leny);
- new_right[result_len] = '\0';
- y = new_right;
- leny = result_len;
- x = left;
- lenx -= right_len;
- /* Now fall through to concatenate the two pieces: */
+ new_right = GC_MALLOC_ATOMIC(result_len + 1);
+ if (new_right == 0) OUT_OF_MEMORY;
+ memcpy(new_right, right, right_len);
+ memcpy(new_right + right_len, y, leny);
+ new_right[result_len] = '\0';
+ y = new_right;
+ leny = result_len;
+ x = left;
+ lenx -= right_len;
+ /* Now fall through to concatenate the two pieces: */
}
if (CORD_IS_STRING(x)) {
depth = 1;
@@ -209,21 +215,21 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
}
{
/* The general case; lenx, result_len is known: */
- register struct Concatenation * result;
-
- result = GC_NEW(struct Concatenation);
- if (result == 0) OUT_OF_MEMORY;
- result->header = CONCAT_HDR;
- result->depth = depth;
- if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
- result->len = result_len;
- result->left = x;
- result->right = y;
- if (depth >= MAX_DEPTH) {
- return(CORD_balance((CORD)result));
- } else {
- return((CORD) result);
- }
+ register struct Concatenation * result;
+
+ result = GC_NEW(struct Concatenation);
+ if (result == 0) OUT_OF_MEMORY;
+ result->header = CONCAT_HDR;
+ result->depth = depth;
+ if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
+ result->len = result_len;
+ result->left = x;
+ result->right = y;
+ if (depth >= MAX_DEPTH) {
+ return(CORD_balance((CORD)result));
+ } else {
+ return((CORD) result);
+ }
}
}
@@ -233,7 +239,7 @@ CORD CORD_cat(CORD x, CORD y)
register size_t result_len;
register int depth;
register size_t lenx;
-
+
if (x == CORD_EMPTY) return(y);
if (y == CORD_EMPTY) return(x);
if (CORD_IS_STRING(y)) {
@@ -243,28 +249,28 @@ CORD CORD_cat(CORD x, CORD y)
depth = DEPTH(y) + 1;
} else {
register int depthy = DEPTH(y);
-
+
lenx = LEN(x);
depth = DEPTH(x) + 1;
if (depthy >= depth) depth = depthy + 1;
}
result_len = lenx + LEN(y);
{
- register struct Concatenation * result;
-
- result = GC_NEW(struct Concatenation);
- if (result == 0) OUT_OF_MEMORY;
- result->header = CONCAT_HDR;
- result->depth = depth;
- if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
- result->len = result_len;
- result->left = x;
- result->right = y;
- if (depth >= MAX_DEPTH) {
- return(CORD_balance((CORD)result));
- } else {
- return((CORD) result);
- }
+ register struct Concatenation * result;
+
+ result = GC_NEW(struct Concatenation);
+ if (result == 0) OUT_OF_MEMORY;
+ result->header = CONCAT_HDR;
+ result->depth = depth;
+ if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
+ result->len = result_len;
+ result->left = x;
+ result->right = y;
+ if (depth >= MAX_DEPTH) {
+ return(CORD_balance((CORD)result));
+ } else {
+ return((CORD) result);
+ }
}
}
@@ -278,40 +284,40 @@ CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
register size_t i;
char buf[SHORT_LIMIT+1];
register char c;
-
+
for (i = 0; i < len; i++) {
c = (*fn)(i, client_data);
if (c == '\0') goto gen_case;
buf[i] = c;
}
- buf[i] = '\0';
+
result = GC_MALLOC_ATOMIC(len+1);
if (result == 0) OUT_OF_MEMORY;
- strcpy(result, buf);
+ memcpy(result, buf, len);
result[len] = '\0';
return((CORD) result);
}
gen_case:
{
- register struct Function * result;
-
- result = GC_NEW(struct Function);
- if (result == 0) OUT_OF_MEMORY;
- result->header = FN_HDR;
- /* depth is already 0 */
- result->len = len;
- result->fn = fn;
- result->client_data = client_data;
- return((CORD) result);
+ register struct Function * result;
+
+ result = GC_NEW(struct Function);
+ if (result == 0) OUT_OF_MEMORY;
+ result->header = FN_HDR;
+ /* depth is already 0 */
+ result->len = len;
+ result->fn = fn;
+ result->client_data = client_data;
+ return((CORD) result);
}
}
size_t CORD_len(CORD x)
{
if (x == 0) {
- return(0);
+ return(0);
} else {
- return(GEN_LEN(x));
+ return(GEN_LEN(x));
}
}
@@ -323,7 +329,7 @@ struct substr_args {
char CORD_index_access_fn(size_t i, void * client_data)
{
register struct substr_args *descr = (struct substr_args *)client_data;
-
+
return(((char *)(descr->sa_cord))[i + descr->sa_index]);
}
@@ -331,31 +337,32 @@ char CORD_apply_access_fn(size_t i, void * client_data)
{
register struct substr_args *descr = (struct substr_args *)client_data;
register struct Function * fn_cord = &(descr->sa_cord->function);
-
+
return((*(fn_cord->fn))(i + descr->sa_index, fn_cord->client_data));
}
-/* A version of CORD_substr that simply returns a function node, thus */
-/* postponing its work. The fourth argument is a function that may */
-/* be used for efficient access to the ith character. */
-/* Assumes i >= 0 and i + n < length(x). */
+/* A version of CORD_substr that simply returns a function node, thus */
+/* postponing its work. The fourth argument is a function that may */
+/* be used for efficient access to the ith character. */
+/* Assumes i >= 0 and i + n < length(x). */
CORD CORD_substr_closure(CORD x, size_t i, size_t n, CORD_fn f)
{
register struct substr_args * sa = GC_NEW(struct substr_args);
CORD result;
-
+
if (sa == 0) OUT_OF_MEMORY;
sa->sa_cord = (CordRep *)x;
sa->sa_index = i;
result = CORD_from_fn(f, (void *)sa, n);
+ if (result == CORD_EMPTY) return CORD_EMPTY; /* n == 0 */
((CordRep *)result) -> function.header = SUBSTR_HDR;
return (result);
}
# define SUBSTR_LIMIT (10 * SHORT_LIMIT)
- /* Substrings of function nodes and flat strings shorter than */
- /* this are flat strings. Othewise we use a functional */
- /* representation, which is significantly slower to access. */
+ /* Substrings of function nodes and flat strings shorter than */
+ /* this are flat strings. Othewise we use a functional */
+ /* representation, which is significantly slower to access. */
/* A version of CORD_substr that assumes i >= 0, n > 0, and i + n < length(x).*/
CORD CORD_substr_checked(CORD x, size_t i, size_t n)
@@ -365,56 +372,56 @@ CORD CORD_substr_checked(CORD x, size_t i, size_t n)
return(CORD_substr_closure(x, i, n, CORD_index_access_fn));
} else {
register char * result = GC_MALLOC_ATOMIC(n+1);
-
+
if (result == 0) OUT_OF_MEMORY;
strncpy(result, x+i, n);
result[n] = '\0';
return(result);
}
} else if (IS_CONCATENATION(x)) {
- register struct Concatenation * conc
- = &(((CordRep *)x) -> concatenation);
- register size_t left_len;
- register size_t right_len;
-
- left_len = LEFT_LEN(conc);
- right_len = conc -> len - left_len;
- if (i >= left_len) {
- if (n == right_len) return(conc -> right);
- return(CORD_substr_checked(conc -> right, i - left_len, n));
- } else if (i+n <= left_len) {
- if (n == left_len) return(conc -> left);
- return(CORD_substr_checked(conc -> left, i, n));
- } else {
- /* Need at least one character from each side. */
- register CORD left_part;
- register CORD right_part;
- register size_t left_part_len = left_len - i;
-
- if (i == 0) {
- left_part = conc -> left;
- } else {
- left_part = CORD_substr_checked(conc -> left, i, left_part_len);
- }
- if (i + n == right_len + left_len) {
- right_part = conc -> right;
- } else {
- right_part = CORD_substr_checked(conc -> right, 0,
- n - left_part_len);
- }
- return(CORD_cat(left_part, right_part));
- }
+ register struct Concatenation * conc
+ = &(((CordRep *)x) -> concatenation);
+ register size_t left_len;
+ register size_t right_len;
+
+ left_len = LEFT_LEN(conc);
+ right_len = conc -> len - left_len;
+ if (i >= left_len) {
+ if (n == right_len) return(conc -> right);
+ return(CORD_substr_checked(conc -> right, i - left_len, n));
+ } else if (i+n <= left_len) {
+ if (n == left_len) return(conc -> left);
+ return(CORD_substr_checked(conc -> left, i, n));
+ } else {
+ /* Need at least one character from each side. */
+ register CORD left_part;
+ register CORD right_part;
+ register size_t left_part_len = left_len - i;
+
+ if (i == 0) {
+ left_part = conc -> left;
+ } else {
+ left_part = CORD_substr_checked(conc -> left, i, left_part_len);
+ }
+ if (i + n == right_len + left_len) {
+ right_part = conc -> right;
+ } else {
+ right_part = CORD_substr_checked(conc -> right, 0,
+ n - left_part_len);
+ }
+ return(CORD_cat(left_part, right_part));
+ }
} else /* function */ {
if (n > SUBSTR_LIMIT) {
if (IS_SUBSTR(x)) {
- /* Avoid nesting substring nodes. */
- register struct Function * f = &(((CordRep *)x) -> function);
- register struct substr_args *descr =
- (struct substr_args *)(f -> client_data);
-
- return(CORD_substr_closure((CORD)descr->sa_cord,
- i + descr->sa_index,
- n, f -> fn));
+ /* Avoid nesting substring nodes. */
+ register struct Function * f = &(((CordRep *)x) -> function);
+ register struct substr_args *descr =
+ (struct substr_args *)(f -> client_data);
+
+ return(CORD_substr_closure((CORD)descr->sa_cord,
+ i + descr->sa_index,
+ n, f -> fn));
} else {
return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
}
@@ -426,18 +433,18 @@ CORD CORD_substr_checked(CORD x, size_t i, size_t n)
register char c;
register int j;
register int lim = i + n;
-
+
for (j = i; j < lim; j++) {
- c = (*(f -> fn))(j, f -> client_data);
- if (c == '\0') {
- return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
- }
- *p++ = c;
+ c = (*(f -> fn))(j, f -> client_data);
+ if (c == '\0') {
+ return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
+ }
+ *p++ = c;
}
- *p = '\0';
result = GC_MALLOC_ATOMIC(n+1);
if (result == 0) OUT_OF_MEMORY;
- strcpy(result, buf);
+ memcpy(result, buf, n);
+ result[n] = '\0';
return(result);
}
}
@@ -446,59 +453,54 @@ CORD CORD_substr_checked(CORD x, size_t i, size_t n)
CORD CORD_substr(CORD x, size_t i, size_t n)
{
register size_t len = CORD_len(x);
-
+
if (i >= len || n <= 0) return(0);
- /* n < 0 is impossible in a correct C implementation, but */
- /* quite possible under SunOS 4.X. */
+ /* n < 0 is impossible in a correct C implementation, but */
+ /* quite possible under SunOS 4.X. */
if (i + n > len) n = len - i;
-# ifndef __STDC__
- if (i < 0) ABORT("CORD_substr: second arg. negative");
- /* Possible only if both client and C implementation are buggy. */
- /* But empirically this happens frequently. */
-# endif
return(CORD_substr_checked(x, i, n));
}
-/* See cord.h for definition. We assume i is in range. */
+/* See cord.h for definition. We assume i is in range. */
int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
- CORD_batched_iter_fn f2, void * client_data)
+ CORD_batched_iter_fn f2, void * client_data)
{
if (x == 0) return(0);
if (CORD_IS_STRING(x)) {
- register const char *p = x+i;
-
- if (*p == '\0') ABORT("2nd arg to CORD_iter5 too big");
+ register const char *p = x+i;
+
+ if (*p == '\0') ABORT("2nd arg to CORD_iter5 too big");
if (f2 != CORD_NO_FN) {
return((*f2)(p, client_data));
} else {
- while (*p) {
+ while (*p) {
if ((*f1)(*p, client_data)) return(1);
p++;
- }
- return(0);
+ }
+ return(0);
}
} else if (IS_CONCATENATION(x)) {
- register struct Concatenation * conc
- = &(((CordRep *)x) -> concatenation);
-
-
- if (i > 0) {
- register size_t left_len = LEFT_LEN(conc);
-
- if (i >= left_len) {
- return(CORD_iter5(conc -> right, i - left_len, f1, f2,
- client_data));
- }
- }
- if (CORD_iter5(conc -> left, i, f1, f2, client_data)) {
- return(1);
- }
- return(CORD_iter5(conc -> right, 0, f1, f2, client_data));
+ register struct Concatenation * conc
+ = &(((CordRep *)x) -> concatenation);
+
+
+ if (i > 0) {
+ register size_t left_len = LEFT_LEN(conc);
+
+ if (i >= left_len) {
+ return(CORD_iter5(conc -> right, i - left_len, f1, f2,
+ client_data));
+ }
+ }
+ if (CORD_iter5(conc -> left, i, f1, f2, client_data)) {
+ return(1);
+ }
+ return(CORD_iter5(conc -> right, 0, f1, f2, client_data));
} else /* function */ {
register struct Function * f = &(((CordRep *)x) -> function);
register size_t j;
register size_t lim = f -> len;
-
+
for (j = i; j < lim; j++) {
if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) {
return(1);
@@ -507,7 +509,7 @@ int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
return(0);
}
}
-
+
#undef CORD_iter
int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data)
{
@@ -518,36 +520,36 @@ int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
{
if (x == 0) return(0);
if (CORD_IS_STRING(x)) {
- register const char *p = x + i;
- register char c;
-
- for(;;) {
- c = *p;
- if (c == '\0') ABORT("2nd arg to CORD_riter4 too big");
+ register const char *p = x + i;
+ register char c;
+
+ for(;;) {
+ c = *p;
+ if (c == '\0') ABORT("2nd arg to CORD_riter4 too big");
if ((*f1)(c, client_data)) return(1);
- if (p == x) break;
+ if (p == x) break;
p--;
- }
- return(0);
+ }
+ return(0);
} else if (IS_CONCATENATION(x)) {
- register struct Concatenation * conc
- = &(((CordRep *)x) -> concatenation);
- register CORD left_part = conc -> left;
- register size_t left_len;
-
- left_len = LEFT_LEN(conc);
- if (i >= left_len) {
- if (CORD_riter4(conc -> right, i - left_len, f1, client_data)) {
- return(1);
- }
- return(CORD_riter4(left_part, left_len - 1, f1, client_data));
- } else {
- return(CORD_riter4(left_part, i, f1, client_data));
- }
+ register struct Concatenation * conc
+ = &(((CordRep *)x) -> concatenation);
+ register CORD left_part = conc -> left;
+ register size_t left_len;
+
+ left_len = LEFT_LEN(conc);
+ if (i >= left_len) {
+ if (CORD_riter4(conc -> right, i - left_len, f1, client_data)) {
+ return(1);
+ }
+ return(CORD_riter4(left_part, left_len - 1, f1, client_data));
+ } else {
+ return(CORD_riter4(left_part, i, f1, client_data));
+ }
} else /* function */ {
register struct Function * f = &(((CordRep *)x) -> function);
register size_t j;
-
+
for (j = i; ; j--) {
if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) {
return(1);
@@ -559,7 +561,9 @@ int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data)
{
- return(CORD_riter4(x, CORD_len(x) - 1, f1, client_data));
+ size_t len = CORD_len(x);
+ if (len == 0) return(0);
+ return(CORD_riter4(x, len - 1, f1, client_data));
}
/*
@@ -579,7 +583,7 @@ int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data)
typedef struct {
CORD c;
- size_t len; /* Actual length of c */
+ size_t len; /* Actual length of c */
} ForestElement;
static size_t min_len [ MAX_DEPTH ];
@@ -589,24 +593,24 @@ static int min_len_init = 0;
int CORD_max_len;
typedef ForestElement Forest [ MAX_DEPTH ];
- /* forest[i].len >= fib(i+1) */
- /* The string is the concatenation */
- /* of the forest in order of DECREASING */
- /* indices. */
+ /* forest[i].len >= fib(i+1) */
+ /* The string is the concatenation */
+ /* of the forest in order of DECREASING */
+ /* indices. */
void CORD_init_min_len()
{
register int i;
register size_t last, previous, current;
-
+
min_len[0] = previous = 1;
min_len[1] = last = 2;
for (i = 2; i < MAX_DEPTH; i++) {
- current = last + previous;
- if (current < last) /* overflow */ current = last;
- min_len[i] = current;
- previous = last;
- last = current;
+ current = last + previous;
+ if (current < last) /* overflow */ current = last;
+ min_len[i] = current;
+ previous = last;
+ last = current;
}
CORD_max_len = last - 1;
min_len_init = 1;
@@ -616,48 +620,48 @@ void CORD_init_min_len()
void CORD_init_forest(ForestElement * forest, size_t max_len)
{
register int i;
-
+
for (i = 0; i < MAX_DEPTH; i++) {
- forest[i].c = 0;
- if (min_len[i] > max_len) return;
+ forest[i].c = 0;
+ if (min_len[i] > max_len) return;
}
ABORT("Cord too long");
}
-/* Add a leaf to the appropriate level in the forest, cleaning */
-/* out lower levels as necessary. */
-/* Also works if x is a balanced tree of concatenations; however */
-/* in this case an extra concatenation node may be inserted above x; */
-/* This node should not be counted in the statement of the invariants. */
+/* Add a leaf to the appropriate level in the forest, cleaning */
+/* out lower levels as necessary. */
+/* Also works if x is a balanced tree of concatenations; however */
+/* in this case an extra concatenation node may be inserted above x; */
+/* This node should not be counted in the statement of the invariants. */
void CORD_add_forest(ForestElement * forest, CORD x, size_t len)
{
register int i = 0;
register CORD sum = CORD_EMPTY;
register size_t sum_len = 0;
-
+
while (len > min_len[i + 1]) {
- if (forest[i].c != 0) {
- sum = CORD_cat(forest[i].c, sum);
- sum_len += forest[i].len;
- forest[i].c = 0;
- }
+ if (forest[i].c != 0) {
+ sum = CORD_cat(forest[i].c, sum);
+ sum_len += forest[i].len;
+ forest[i].c = 0;
+ }
i++;
}
- /* Sum has depth at most 1 greter than what would be required */
- /* for balance. */
+ /* Sum has depth at most 1 greter than what would be required */
+ /* for balance. */
sum = CORD_cat(sum, x);
sum_len += len;
- /* If x was a leaf, then sum is now balanced. To see this */
- /* consider the two cases in which forest[i-1] either is or is */
- /* not empty. */
+ /* If x was a leaf, then sum is now balanced. To see this */
+ /* consider the two cases in which forest[i-1] either is or is */
+ /* not empty. */
while (sum_len >= min_len[i]) {
- if (forest[i].c != 0) {
- sum = CORD_cat(forest[i].c, sum);
- sum_len += forest[i].len;
- /* This is again balanced, since sum was balanced, and has */
- /* allowable depth that differs from i by at most 1. */
- forest[i].c = 0;
- }
+ if (forest[i].c != 0) {
+ sum = CORD_cat(forest[i].c, sum);
+ sum_len += forest[i].len;
+ /* This is again balanced, since sum was balanced, and has */
+ /* allowable depth that differs from i by at most 1. */
+ forest[i].c = 0;
+ }
i++;
}
i--;
@@ -670,37 +674,37 @@ CORD CORD_concat_forest(ForestElement * forest, size_t expected_len)
register int i = 0;
CORD sum = 0;
size_t sum_len = 0;
-
+
while (sum_len != expected_len) {
- if (forest[i].c != 0) {
- sum = CORD_cat(forest[i].c, sum);
- sum_len += forest[i].len;
- }
+ if (forest[i].c != 0) {
+ sum = CORD_cat(forest[i].c, sum);
+ sum_len += forest[i].len;
+ }
i++;
}
return(sum);
}
-/* Insert the frontier of x into forest. Balanced subtrees are */
-/* treated as leaves. This potentially adds one to the depth */
-/* of the final tree. */
+/* Insert the frontier of x into forest. Balanced subtrees are */
+/* treated as leaves. This potentially adds one to the depth */
+/* of the final tree. */
void CORD_balance_insert(CORD x, size_t len, ForestElement * forest)
{
register int depth;
-
+
if (CORD_IS_STRING(x)) {
CORD_add_forest(forest, x, len);
} else if (IS_CONCATENATION(x)
&& ((depth = DEPTH(x)) >= MAX_DEPTH
|| len < min_len[depth])) {
- register struct Concatenation * conc
- = &(((CordRep *)x) -> concatenation);
- size_t left_len = LEFT_LEN(conc);
-
- CORD_balance_insert(conc -> left, left_len, forest);
- CORD_balance_insert(conc -> right, len - left_len, forest);
+ register struct Concatenation * conc
+ = &(((CordRep *)x) -> concatenation);
+ size_t left_len = LEFT_LEN(conc);
+
+ CORD_balance_insert(conc -> left, left_len, forest);
+ CORD_balance_insert(conc -> right, len - left_len, forest);
} else /* function or balanced */ {
- CORD_add_forest(forest, x, len);
+ CORD_add_forest(forest, x, len);
}
}
@@ -709,7 +713,7 @@ CORD CORD_balance(CORD x)
{
Forest forest;
register size_t len;
-
+
if (x == 0) return(0);
if (CORD_IS_STRING(x)) return(x);
if (!min_len_init) CORD_init_min_len();
@@ -720,13 +724,13 @@ CORD CORD_balance(CORD x)
}
-/* Position primitives */
+/* Position primitives */
/* Private routines to deal with the hard cases only: */
-/* P contains a prefix of the path to cur_pos. Extend it to a full */
-/* path and set up leaf info. */
-/* Return 0 if past the end of cord, 1 o.w. */
+/* P contains a prefix of the path to cur_pos. Extend it to a full */
+/* path and set up leaf info. */
+/* Return 0 if past the end of cord, 1 o.w. */
void CORD__extend_path(register CORD_pos p)
{
register struct CORD_pe * current_pe = &(p[0].path[p[0].path_len]);
@@ -734,25 +738,25 @@ void CORD__extend_path(register CORD_pos p)
register size_t pos = p[0].cur_pos;
register size_t top_pos = current_pe -> pe_start_pos;
register size_t top_len = GEN_LEN(top);
-
+
/* Fill in the rest of the path. */
while(!CORD_IS_STRING(top) && IS_CONCATENATION(top)) {
- register struct Concatenation * conc =
- &(((CordRep *)top) -> concatenation);
- register size_t left_len;
-
- left_len = LEFT_LEN(conc);
- current_pe++;
- if (pos >= top_pos + left_len) {
- current_pe -> pe_cord = top = conc -> right;
- current_pe -> pe_start_pos = top_pos = top_pos + left_len;
- top_len -= left_len;
- } else {
- current_pe -> pe_cord = top = conc -> left;
- current_pe -> pe_start_pos = top_pos;
- top_len = left_len;
- }
- p[0].path_len++;
+ register struct Concatenation * conc =
+ &(((CordRep *)top) -> concatenation);
+ register size_t left_len;
+
+ left_len = LEFT_LEN(conc);
+ current_pe++;
+ if (pos >= top_pos + left_len) {
+ current_pe -> pe_cord = top = conc -> right;
+ current_pe -> pe_start_pos = top_pos = top_pos + left_len;
+ top_len -= left_len;
+ } else {
+ current_pe -> pe_cord = top = conc -> left;
+ current_pe -> pe_start_pos = top_pos;
+ top_len = left_len;
+ }
+ p[0].path_len++;
}
/* Fill in leaf description for fast access. */
if (CORD_IS_STRING(top)) {
@@ -771,7 +775,7 @@ char CORD__pos_fetch(register CORD_pos p)
struct CORD_pe * pe = &((p)[0].path[(p)[0].path_len]);
CORD leaf = pe -> pe_cord;
register struct Function * f = &(((CordRep *)leaf) -> function);
-
+
if (!IS_FUNCTION(leaf)) ABORT("CORD_pos_fetch: bad leaf");
return ((*(f -> fn))(p[0].cur_pos - pe -> pe_start_pos, f -> client_data));
}
@@ -781,48 +785,48 @@ void CORD__next(register CORD_pos p)
register size_t cur_pos = p[0].cur_pos + 1;
register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
register CORD leaf = current_pe -> pe_cord;
-
+
/* Leaf is not a string or we're at end of leaf */
p[0].cur_pos = cur_pos;
if (!CORD_IS_STRING(leaf)) {
- /* Function leaf */
- register struct Function * f = &(((CordRep *)leaf) -> function);
- register size_t start_pos = current_pe -> pe_start_pos;
- register size_t end_pos = start_pos + f -> len;
-
- if (cur_pos < end_pos) {
- /* Fill cache and return. */
- register size_t i;
- register size_t limit = cur_pos + FUNCTION_BUF_SZ;
- register CORD_fn fn = f -> fn;
- register void * client_data = f -> client_data;
-
- if (limit > end_pos) {
- limit = end_pos;
- }
- for (i = cur_pos; i < limit; i++) {
- p[0].function_buf[i - cur_pos] =
- (*fn)(i - start_pos, client_data);
- }
- p[0].cur_start = cur_pos;
- p[0].cur_leaf = p[0].function_buf;
- p[0].cur_end = limit;
- return;
- }
+ /* Function leaf */
+ register struct Function * f = &(((CordRep *)leaf) -> function);
+ register size_t start_pos = current_pe -> pe_start_pos;
+ register size_t end_pos = start_pos + f -> len;
+
+ if (cur_pos < end_pos) {
+ /* Fill cache and return. */
+ register size_t i;
+ register size_t limit = cur_pos + FUNCTION_BUF_SZ;
+ register CORD_fn fn = f -> fn;
+ register void * client_data = f -> client_data;
+
+ if (limit > end_pos) {
+ limit = end_pos;
+ }
+ for (i = cur_pos; i < limit; i++) {
+ p[0].function_buf[i - cur_pos] =
+ (*fn)(i - start_pos, client_data);
+ }
+ p[0].cur_start = cur_pos;
+ p[0].cur_leaf = p[0].function_buf;
+ p[0].cur_end = limit;
+ return;
+ }
}
- /* End of leaf */
- /* Pop the stack until we find two concatenation nodes with the */
- /* same start position: this implies we were in left part. */
+ /* End of leaf */
+ /* Pop the stack until we find two concatenation nodes with the */
+ /* same start position: this implies we were in left part. */
{
- while (p[0].path_len > 0
- && current_pe[0].pe_start_pos != current_pe[-1].pe_start_pos) {
- p[0].path_len--;
- current_pe--;
- }
- if (p[0].path_len == 0) {
- p[0].path_len = CORD_POS_INVALID;
+ while (p[0].path_len > 0
+ && current_pe[0].pe_start_pos != current_pe[-1].pe_start_pos) {
+ p[0].path_len--;
+ current_pe--;
+ }
+ if (p[0].path_len == 0) {
+ p[0].path_len = CORD_POS_INVALID;
return;
- }
+ }
}
p[0].path_len--;
CORD__extend_path(p);
@@ -831,26 +835,26 @@ void CORD__next(register CORD_pos p)
void CORD__prev(register CORD_pos p)
{
register struct CORD_pe * pe = &(p[0].path[p[0].path_len]);
-
+
if (p[0].cur_pos == 0) {
p[0].path_len = CORD_POS_INVALID;
return;
}
p[0].cur_pos--;
if (p[0].cur_pos >= pe -> pe_start_pos) return;
-
- /* Beginning of leaf */
-
- /* Pop the stack until we find two concatenation nodes with the */
- /* different start position: this implies we were in right part. */
+
+ /* Beginning of leaf */
+
+ /* Pop the stack until we find two concatenation nodes with the */
+ /* different start position: this implies we were in right part. */
{
- register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
-
- while (p[0].path_len > 0
- && current_pe[0].pe_start_pos == current_pe[-1].pe_start_pos) {
- p[0].path_len--;
- current_pe--;
- }
+ register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
+
+ while (p[0].path_len > 0
+ && current_pe[0].pe_start_pos == current_pe[-1].pe_start_pos) {
+ p[0].path_len--;
+ current_pe--;
+ }
}
p[0].path_len--;
CORD__extend_path(p);
@@ -866,7 +870,7 @@ void CORD__prev(register CORD_pos p)
char CORD_pos_fetch(register CORD_pos p)
{
if (p[0].cur_start <= p[0].cur_pos && p[0].cur_pos < p[0].cur_end) {
- return(p[0].cur_leaf[p[0].cur_pos - p[0].cur_start]);
+ return(p[0].cur_leaf[p[0].cur_pos - p[0].cur_start]);
} else {
return(CORD__pos_fetch(p));
}
@@ -875,18 +879,18 @@ char CORD_pos_fetch(register CORD_pos p)
void CORD_next(CORD_pos p)
{
if (p[0].cur_pos < p[0].cur_end - 1) {
- p[0].cur_pos++;
+ p[0].cur_pos++;
} else {
- CORD__next(p);
+ CORD__next(p);
}
}
void CORD_prev(CORD_pos p)
{
if (p[0].cur_end != 0 && p[0].cur_pos > p[0].cur_start) {
- p[0].cur_pos--;
+ p[0].cur_pos--;
} else {
- CORD__prev(p);
+ CORD__prev(p);
}
}
@@ -908,8 +912,8 @@ int CORD_pos_valid(CORD_pos p)
void CORD_set_pos(CORD_pos p, CORD x, size_t i)
{
if (x == CORD_EMPTY) {
- p[0].path_len = CORD_POS_INVALID;
- return;
+ p[0].path_len = CORD_POS_INVALID;
+ return;
}
p[0].path[0].pe_cord = x;
p[0].path[0].pe_start_pos = 0;
diff --git a/boehm-gc/cord/cordprnt.c b/boehm-gc/cord/cordprnt.c
index ad937b02d4e..94c49be87d5 100644
--- a/boehm-gc/cord/cordprnt.c
+++ b/boehm-gc/cord/cordprnt.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -10,17 +10,23 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* An sprintf implementation that understands cords. This is probably */
-/* not terribly portable. It assumes an ANSI stdarg.h. It further */
-/* assumes that I can make copies of va_list variables, and read */
-/* arguments repeatedly by applyting va_arg to the copies. This */
-/* could be avoided at some performance cost. */
-/* We also assume that unsigned and signed integers of various kinds */
-/* have the same sizes, and can be cast back and forth. */
-/* We assume that void * and char * have the same size. */
-/* All this cruft is needed because we want to rely on the underlying */
-/* sprintf implementation whenever possible. */
-/* Boehm, September 21, 1995 6:00 pm PDT */
+/* An sprintf implementation that understands cords. This is probably */
+/* not terribly portable. It assumes an ANSI stdarg.h. It further */
+/* assumes that I can make copies of va_list variables, and read */
+/* arguments repeatedly by applying va_arg to the copies. This */
+/* could be avoided at some performance cost. */
+/* We also assume that unsigned and signed integers of various kinds */
+/* have the same sizes, and can be cast back and forth. */
+/* We assume that void * and char * have the same size. */
+/* All this cruft is needed because we want to rely on the underlying */
+/* sprintf implementation whenever possible. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#ifndef CORD_BUILD
+# define CORD_BUILD
+#endif
#include "cord.h"
#include "ec.h"
@@ -29,11 +35,11 @@
#include <string.h>
#include "gc.h"
-#define CONV_SPEC_LEN 50 /* Maximum length of a single */
- /* conversion specification. */
-#define CONV_RESULT_LEN 50 /* Maximum length of any */
- /* conversion with default */
- /* width and prec. */
+#define CONV_SPEC_LEN 50 /* Maximum length of a single */
+ /* conversion specification. */
+#define CONV_RESULT_LEN 50 /* Maximum length of any */
+ /* conversion with default */
+ /* width and prec. */
static int ec_len(CORD_ec x)
@@ -41,28 +47,28 @@ static int ec_len(CORD_ec x)
return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
}
-/* Possible nonumeric precision values. */
+/* Possible nonumeric precision values. */
# define NONE -1
# define VARIABLE -2
-/* Copy the conversion specification from CORD_pos into the buffer buf */
-/* Return negative on error. */
-/* Source initially points one past the leading %. */
-/* It is left pointing at the conversion type. */
-/* Assign field width and precision to *width and *prec. */
-/* If width or prec is *, VARIABLE is assigned. */
-/* Set *left to 1 if left adjustment flag is present. */
-/* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
-/* -1 if 'h' is present. */
+/* Copy the conversion specification from CORD_pos into the buffer buf */
+/* Return negative on error. */
+/* Source initially points one past the leading %. */
+/* It is left pointing at the conversion type. */
+/* Assign field width and precision to *width and *prec. */
+/* If width or prec is *, VARIABLE is assigned. */
+/* Set *left to 1 if left adjustment flag is present. */
+/* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
+/* -1 if 'h' is present. */
static int extract_conv_spec(CORD_pos source, char *buf,
- int * width, int *prec, int *left, int * long_arg)
+ int * width, int *prec, int *left, int * long_arg)
{
register int result = 0;
register int current_number = 0;
register int saw_period = 0;
- register int saw_number;
+ register int saw_number = 0;
register int chars_so_far = 0;
register char current;
-
+
*width = NONE;
buf[chars_so_far++] = '%';
while(CORD_pos_valid(source)) {
@@ -70,73 +76,73 @@ static int extract_conv_spec(CORD_pos source, char *buf,
current = CORD_pos_fetch(source);
buf[chars_so_far++] = current;
switch(current) {
- case '*':
- saw_number = 1;
- current_number = VARIABLE;
- break;
+ case '*':
+ saw_number = 1;
+ current_number = VARIABLE;
+ break;
case '0':
if (!saw_number) {
/* Zero fill flag; ignore */
break;
} /* otherwise fall through: */
case '1':
- case '2':
- case '3':
- case '4':
- case '5':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
case '6':
- case '7':
- case '8':
- case '9':
- saw_number = 1;
- current_number *= 10;
- current_number += current - '0';
- break;
- case '.':
- saw_period = 1;
- if(saw_number) {
- *width = current_number;
- saw_number = 0;
- }
- current_number = 0;
- break;
- case 'l':
- case 'L':
- *long_arg = 1;
- current_number = 0;
- break;
- case 'h':
- *long_arg = -1;
- current_number = 0;
- break;
- case ' ':
- case '+':
- case '#':
- current_number = 0;
- break;
- case '-':
- *left = 1;
- current_number = 0;
- break;
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- case 'c':
- case 'C':
- case 's':
- case 'S':
- case 'p':
- case 'n':
- case 'r':
- goto done;
+ case '7':
+ case '8':
+ case '9':
+ saw_number = 1;
+ current_number *= 10;
+ current_number += current - '0';
+ break;
+ case '.':
+ saw_period = 1;
+ if(saw_number) {
+ *width = current_number;
+ saw_number = 0;
+ }
+ current_number = 0;
+ break;
+ case 'l':
+ case 'L':
+ *long_arg = 1;
+ current_number = 0;
+ break;
+ case 'h':
+ *long_arg = -1;
+ current_number = 0;
+ break;
+ case ' ':
+ case '+':
+ case '#':
+ current_number = 0;
+ break;
+ case '-':
+ *left = 1;
+ current_number = 0;
+ break;
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'c':
+ case 'C':
+ case 's':
+ case 'S':
+ case 'p':
+ case 'n':
+ case 'r':
+ goto done;
default:
return(-1);
}
@@ -145,14 +151,14 @@ static int extract_conv_spec(CORD_pos source, char *buf,
return(-1);
done:
if (saw_number) {
- if (saw_period) {
- *prec = current_number;
- } else {
- *prec = NONE;
- *width = current_number;
- }
+ if (saw_period) {
+ *prec = current_number;
+ } else {
+ *prec = NONE;
+ *width = current_number;
+ }
} else {
- *prec = NONE;
+ *prec = NONE;
}
buf[chars_so_far] = '\0';
return(result);
@@ -165,168 +171,176 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
register char current;
CORD_pos pos;
char conv_spec[CONV_SPEC_LEN + 1];
-
+
CORD_ec_init(result);
for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
- current = CORD_pos_fetch(pos);
- if (current == '%') {
+ current = CORD_pos_fetch(pos);
+ if (current == '%') {
CORD_next(pos);
if (!CORD_pos_valid(pos)) return(-1);
current = CORD_pos_fetch(pos);
if (current == '%') {
- CORD_ec_append(result, current);
+ CORD_ec_append(result, current);
} else {
- int width, prec;
- int left_adj = 0;
- int long_arg = 0;
- CORD arg;
- size_t len;
-
- if (extract_conv_spec(pos, conv_spec,
- &width, &prec,
- &left_adj, &long_arg) < 0) {
- return(-1);
- }
- current = CORD_pos_fetch(pos);
- switch(current) {
- case 'n':
- /* Assign length to next arg */
- if (long_arg == 0) {
- int * pos_ptr;
- pos_ptr = va_arg(args, int *);
- *pos_ptr = ec_len(result);
- } else if (long_arg > 0) {
- long * pos_ptr;
- pos_ptr = va_arg(args, long *);
- *pos_ptr = ec_len(result);
- } else {
- short * pos_ptr;
- pos_ptr = va_arg(args, short *);
- *pos_ptr = ec_len(result);
- }
- goto done;
- case 'r':
- /* Append cord and any padding */
- if (width == VARIABLE) width = va_arg(args, int);
- if (prec == VARIABLE) prec = va_arg(args, int);
- arg = va_arg(args, CORD);
- len = CORD_len(arg);
- if (prec != NONE && len > prec) {
- if (prec < 0) return(-1);
- arg = CORD_substr(arg, 0, prec);
- len = prec;
- }
- if (width != NONE && len < width) {
- char * blanks = GC_MALLOC_ATOMIC(width-len+1);
+ int width, prec;
+ int left_adj = 0;
+ int long_arg = 0;
+ CORD arg;
+ size_t len;
- memset(blanks, ' ', width-len);
- blanks[width-len] = '\0';
- if (left_adj) {
- arg = CORD_cat(arg, blanks);
- } else {
- arg = CORD_cat(blanks, arg);
- }
- }
- CORD_ec_append_cord(result, arg);
- goto done;
- case 'c':
- if (width == NONE && prec == NONE) {
- register char c;
+ if (extract_conv_spec(pos, conv_spec,
+ &width, &prec,
+ &left_adj, &long_arg) < 0) {
+ return(-1);
+ }
+ current = CORD_pos_fetch(pos);
+ switch(current) {
+ case 'n':
+ /* Assign length to next arg */
+ if (long_arg == 0) {
+ int * pos_ptr;
+ pos_ptr = va_arg(args, int *);
+ *pos_ptr = ec_len(result);
+ } else if (long_arg > 0) {
+ long * pos_ptr;
+ pos_ptr = va_arg(args, long *);
+ *pos_ptr = ec_len(result);
+ } else {
+ short * pos_ptr;
+ pos_ptr = va_arg(args, short *);
+ *pos_ptr = ec_len(result);
+ }
+ goto done;
+ case 'r':
+ /* Append cord and any padding */
+ if (width == VARIABLE) width = va_arg(args, int);
+ if (prec == VARIABLE) prec = va_arg(args, int);
+ arg = va_arg(args, CORD);
+ len = CORD_len(arg);
+ if (prec != NONE && len > (size_t)prec) {
+ if (prec < 0) return(-1);
+ arg = CORD_substr(arg, 0, prec);
+ len = prec;
+ }
+ if (width != NONE && len < (size_t)width) {
+ char * blanks = GC_MALLOC_ATOMIC(width-len+1);
- c = (char)va_arg(args, int);
- CORD_ec_append(result, c);
- goto done;
- }
- break;
- case 's':
- if (width == NONE && prec == NONE) {
- char * str = va_arg(args, char *);
- register char c;
+ memset(blanks, ' ', width-len);
+ blanks[width-len] = '\0';
+ if (left_adj) {
+ arg = CORD_cat(arg, blanks);
+ } else {
+ arg = CORD_cat(blanks, arg);
+ }
+ }
+ CORD_ec_append_cord(result, arg);
+ goto done;
+ case 'c':
+ if (width == NONE && prec == NONE) {
+ register char c;
- while (c = *str++) {
- CORD_ec_append(result, c);
- }
- goto done;
- }
- break;
- default:
- break;
- }
- /* Use standard sprintf to perform conversion */
- {
- register char * buf;
- va_list vsprintf_args;
- int max_size = 0;
- int res;
-# ifdef __va_copy
+ c = (char)va_arg(args, int);
+ CORD_ec_append(result, c);
+ goto done;
+ }
+ break;
+ case 's':
+ if (width == NONE && prec == NONE) {
+ char * str = va_arg(args, char *);
+ register char c;
+
+ while ((c = *str++)) {
+ CORD_ec_append(result, c);
+ }
+ goto done;
+ }
+ break;
+ default:
+ break;
+ }
+ /* Use standard sprintf to perform conversion */
+ {
+ register char * buf;
+ va_list vsprintf_args;
+ int max_size = 0;
+ int res;
+# ifdef __va_copy
__va_copy(vsprintf_args, args);
-# else
-# if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
+# else
+# if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
va_copy(vsprintf_args, args);
-# else
- vsprintf_args = args;
-# endif
-# endif
- if (width == VARIABLE) width = va_arg(args, int);
- if (prec == VARIABLE) prec = va_arg(args, int);
- if (width != NONE) max_size = width;
- if (prec != NONE && prec > max_size) max_size = prec;
- max_size += CONV_RESULT_LEN;
- if (max_size >= CORD_BUFSZ) {
- buf = GC_MALLOC_ATOMIC(max_size + 1);
- } else {
- if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
- < max_size) {
- CORD_ec_flush_buf(result);
- }
- buf = result[0].ec_bufptr;
- }
- switch(current) {
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- case 'c':
- if (long_arg <= 0) {
- (void) va_arg(args, int);
- } else if (long_arg > 0) {
- (void) va_arg(args, long);
- }
- break;
- case 's':
- case 'p':
- (void) va_arg(args, char *);
- break;
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- (void) va_arg(args, double);
- break;
- default:
- return(-1);
- }
- res = vsprintf(buf, conv_spec, vsprintf_args);
- len = (size_t)res;
- if ((char *)(GC_word)res == buf) {
- /* old style vsprintf */
- len = strlen(buf);
- } else if (res < 0) {
- return(-1);
- }
- if (buf != result[0].ec_bufptr) {
- register char c;
+# else
+ vsprintf_args = args;
+# endif
+# endif
+ if (width == VARIABLE) width = va_arg(args, int);
+ if (prec == VARIABLE) prec = va_arg(args, int);
+ if (width != NONE) max_size = width;
+ if (prec != NONE && prec > max_size) max_size = prec;
+ max_size += CONV_RESULT_LEN;
+ if (max_size >= CORD_BUFSZ) {
+ buf = GC_MALLOC_ATOMIC(max_size + 1);
+ } else {
+ if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
+ < max_size) {
+ CORD_ec_flush_buf(result);
+ }
+ buf = result[0].ec_bufptr;
+ }
+ switch(current) {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'c':
+ if (long_arg <= 0) {
+ (void) va_arg(args, int);
+ } else if (long_arg > 0) {
+ (void) va_arg(args, long);
+ }
+ break;
+ case 's':
+ case 'p':
+ (void) va_arg(args, char *);
+ break;
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ (void) va_arg(args, double);
+ break;
+ default:
+# if defined(__va_copy) \
+ || (defined(__GNUC__) && !defined(__DJGPP__))
+ va_end(vsprintf_args);
+# endif
+ return(-1);
+ }
+ res = vsprintf(buf, conv_spec, vsprintf_args);
+# if defined(__va_copy) \
+ || (defined(__GNUC__) && !defined(__DJGPP__))
+ va_end(vsprintf_args);
+# endif
+ len = (size_t)res;
+ if ((char *)(GC_word)res == buf) {
+ /* old style vsprintf */
+ len = strlen(buf);
+ } else if (res < 0) {
+ return(-1);
+ }
+ if (buf != result[0].ec_bufptr) {
+ register char c;
- while (c = *buf++) {
- CORD_ec_append(result, c);
- }
- } else {
- result[0].ec_bufptr = buf + len;
- }
- }
+ while ((c = *buf++)) {
+ CORD_ec_append(result, c);
+ }
+ } else {
+ result[0].ec_bufptr = buf + len;
+ }
+ }
done:;
}
} else {
@@ -342,7 +356,7 @@ int CORD_sprintf(CORD * out, CORD format, ...)
{
va_list args;
int result;
-
+
va_start(args, format);
result = CORD_vsprintf(out, format, args);
va_end(args);
@@ -353,8 +367,8 @@ int CORD_fprintf(FILE * f, CORD format, ...)
{
va_list args;
int result;
- CORD out;
-
+ CORD out = CORD_EMPTY; /* initialized to prevent compiler warning */
+
va_start(args, format);
result = CORD_vsprintf(&out, format, args);
va_end(args);
@@ -365,8 +379,8 @@ int CORD_fprintf(FILE * f, CORD format, ...)
int CORD_vfprintf(FILE * f, CORD format, va_list args)
{
int result;
- CORD out;
-
+ CORD out = CORD_EMPTY;
+
result = CORD_vsprintf(&out, format, args);
if (result > 0) CORD_put(out, f);
return(result);
@@ -376,8 +390,8 @@ int CORD_printf(CORD format, ...)
{
va_list args;
int result;
- CORD out;
-
+ CORD out = CORD_EMPTY;
+
va_start(args, format);
result = CORD_vsprintf(&out, format, args);
va_end(args);
@@ -388,8 +402,8 @@ int CORD_printf(CORD format, ...)
int CORD_vprintf(CORD format, va_list args)
{
int result;
- CORD out;
-
+ CORD out = CORD_EMPTY;
+
result = CORD_vsprintf(&out, format, args);
if (result > 0) CORD_put(out, stdout);
return(result);
diff --git a/boehm-gc/cord/cordxtra.c b/boehm-gc/cord/cordxtra.c
index b0a746226cb..b00a482cc32 100644
--- a/boehm-gc/cord/cordxtra.c
+++ b/boehm-gc/cord/cordxtra.c
@@ -9,32 +9,40 @@
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
- *
- * Author: Hans-J. Boehm (boehm@parc.xerox.com)
*/
+
/*
* These are functions on cords that do not need to understand their
* implementation. They serve also serve as example client code for
* cord_basics.
*/
-/* Boehm, December 8, 1995 1:53 pm PST */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#ifndef CORD_BUILD
+# define CORD_BUILD
+#endif
+
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <stdarg.h>
+
# include "cord.h"
# include "ec.h"
-# define I_HIDE_POINTERS /* So we get access to allocation lock. */
- /* We use this for lazy file reading, */
- /* so that we remain independent */
- /* of the threads primitives. */
+
+# define I_HIDE_POINTERS /* So we get access to allocation lock. */
+ /* We use this for lazy file reading, */
+ /* so that we remain independent */
+ /* of the threads primitives. */
# include "gc.h"
-/* For now we assume that pointer reads and writes are atomic, */
-/* i.e. another thread always sees the state before or after */
-/* a write. This might be false on a Motorola M68K with */
-/* pointers that are not 32-bit aligned. But there probably */
-/* aren't too many threads packages running on those. */
+/* For now we assume that pointer reads and writes are atomic, */
+/* i.e. another thread always sees the state before or after */
+/* a write. This might be false on a Motorola M68K with */
+/* pointers that are not 32-bit aligned. But there probably */
+/* aren't too many threads packages running on those. */
# define ATOMIC_WRITE(x,y) (x) = (y)
# define ATOMIC_READ(x) (*(x))
@@ -46,19 +54,25 @@
# define SEEK_END 2
# endif
-# define BUFSZ 2048 /* Size of stack allocated buffers when */
- /* we want large buffers. */
+# define BUFSZ 2048 /* Size of stack allocated buffers when */
+ /* we want large buffers. */
typedef void (* oom_fn)(void);
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
- ABORT("Out of memory\n"); }
+ ABORT("Out of memory\n"); }
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# define CORD_ATTR_UNUSED __attribute__((__unused__))
+#else
+# define CORD_ATTR_UNUSED /* empty */
+#endif
+
CORD CORD_cat_char(CORD x, char c)
{
register char * string;
-
+
if (c == '\0') return(CORD_cat(x, CORD_nul(1)));
string = GC_MALLOC_ATOMIC(2);
if (string == 0) OUT_OF_MEMORY;
@@ -83,22 +97,22 @@ CORD CORD_catn(int nargs, ...)
}
typedef struct {
- size_t len;
- size_t count;
- char * buf;
+ size_t len;
+ size_t count;
+ char * buf;
} CORD_fill_data;
int CORD_fill_proc(char c, void * client_data)
{
register CORD_fill_data * d = (CORD_fill_data *)client_data;
register size_t count = d -> count;
-
+
(d -> buf)[count] = c;
d -> count = ++count;
if (count >= d -> len) {
- return(1);
+ return(1);
} else {
- return(0);
+ return(0);
}
}
@@ -109,7 +123,7 @@ int CORD_batched_fill_proc(const char * s, void * client_data)
register size_t max = d -> len;
register char * buf = d -> buf;
register const char * t = s;
-
+
while((buf[count] = *t++) != '\0') {
count++;
if (count >= max) {
@@ -121,12 +135,12 @@ int CORD_batched_fill_proc(const char * s, void * client_data)
return(0);
}
-/* Fill buf with len characters starting at i. */
-/* Assumes len characters are available. */
+/* Fill buf with len characters starting at i. */
+/* Assumes len characters are available. */
void CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
{
CORD_fill_data fd;
-
+
fd.len = len;
fd.buf = buf;
fd.count = 0;
@@ -138,7 +152,7 @@ int CORD_cmp(CORD x, CORD y)
CORD_pos xpos;
CORD_pos ypos;
register size_t avail, yavail;
-
+
if (y == CORD_EMPTY) return(x != CORD_EMPTY);
if (x == CORD_EMPTY) return(-1);
if (CORD_IS_STRING(y) && CORD_IS_STRING(x)) return(strcmp(x,y));
@@ -147,7 +161,7 @@ int CORD_cmp(CORD x, CORD y)
for(;;) {
if (!CORD_pos_valid(xpos)) {
if (CORD_pos_valid(ypos)) {
- return(-1);
+ return(-1);
} else {
return(0);
}
@@ -163,12 +177,12 @@ int CORD_cmp(CORD x, CORD y)
CORD_next(xpos);
CORD_next(ypos);
} else {
- /* process as many characters as we can */
+ /* process as many characters as we can */
register int result;
-
+
if (avail > yavail) avail = yavail;
result = strncmp(CORD_pos_cur_char_addr(xpos),
- CORD_pos_cur_char_addr(ypos), avail);
+ CORD_pos_cur_char_addr(ypos), avail);
if (result != 0) return(result);
CORD_pos_advance(xpos, avail);
CORD_pos_advance(ypos, avail);
@@ -182,13 +196,13 @@ int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
CORD_pos ypos;
register size_t count;
register long avail, yavail;
-
+
CORD_set_pos(xpos, x, x_start);
CORD_set_pos(ypos, y, y_start);
for(count = 0; count < len;) {
if (!CORD_pos_valid(xpos)) {
if (CORD_pos_valid(ypos)) {
- return(-1);
+ return(-1);
} else {
return(0);
}
@@ -205,14 +219,14 @@ int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
CORD_next(ypos);
count++;
} else {
- /* process as many characters as we can */
+ /* process as many characters as we can */
register int result;
-
+
if (avail > yavail) avail = yavail;
count += avail;
if (count > len) avail -= (count - len);
result = strncmp(CORD_pos_cur_char_addr(xpos),
- CORD_pos_cur_char_addr(ypos), (size_t)avail);
+ CORD_pos_cur_char_addr(ypos), (size_t)avail);
if (result != 0) return(result);
CORD_pos_advance(xpos, (size_t)avail);
CORD_pos_advance(ypos, (size_t)avail);
@@ -225,7 +239,7 @@ char * CORD_to_char_star(CORD x)
{
register size_t len = CORD_len(x);
char * result = GC_MALLOC_ATOMIC(len + 1);
-
+
if (result == 0) OUT_OF_MEMORY;
CORD_fill_buf(x, 0, len, result);
result[len] = '\0';
@@ -254,7 +268,7 @@ const char * CORD_to_const_char_star(CORD x)
char CORD_fetch(CORD x, size_t i)
{
CORD_pos xpos;
-
+
CORD_set_pos(xpos, x, i);
if (!CORD_pos_valid(xpos)) ABORT("bad index?");
return(CORD_pos_fetch(xpos));
@@ -264,36 +278,36 @@ char CORD_fetch(CORD x, size_t i)
int CORD_put_proc(char c, void * client_data)
{
register FILE * f = (FILE *)client_data;
-
+
return(putc(c, f) == EOF);
}
int CORD_batched_put_proc(const char * s, void * client_data)
{
register FILE * f = (FILE *)client_data;
-
+
return(fputs(s, f) == EOF);
}
-
+
int CORD_put(CORD x, FILE * f)
{
if (CORD_iter5(x, 0, CORD_put_proc, CORD_batched_put_proc, f)) {
return(EOF);
} else {
- return(1);
+ return(1);
}
}
typedef struct {
- size_t pos; /* Current position in the cord */
- char target; /* Character we're looking for */
+ size_t pos; /* Current position in the cord */
+ char target; /* Character we're looking for */
} chr_data;
int CORD_chr_proc(char c, void * client_data)
{
register chr_data * d = (chr_data *)client_data;
-
+
if (c == d -> target) return(1);
(d -> pos) ++;
return(0);
@@ -302,7 +316,7 @@ int CORD_chr_proc(char c, void * client_data)
int CORD_rchr_proc(char c, void * client_data)
{
register chr_data * d = (chr_data *)client_data;
-
+
if (c == d -> target) return(1);
(d -> pos) --;
return(0);
@@ -312,48 +326,48 @@ int CORD_batched_chr_proc(const char *s, void * client_data)
{
register chr_data * d = (chr_data *)client_data;
register char * occ = strchr(s, d -> target);
-
+
if (occ == 0) {
- d -> pos += strlen(s);
- return(0);
+ d -> pos += strlen(s);
+ return(0);
} else {
- d -> pos += occ - s;
- return(1);
+ d -> pos += occ - s;
+ return(1);
}
}
size_t CORD_chr(CORD x, size_t i, int c)
{
chr_data d;
-
+
d.pos = i;
d.target = c;
if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) {
return(d.pos);
} else {
- return(CORD_NOT_FOUND);
+ return(CORD_NOT_FOUND);
}
}
size_t CORD_rchr(CORD x, size_t i, int c)
{
chr_data d;
-
+
d.pos = i;
d.target = c;
if (CORD_riter4(x, i, CORD_rchr_proc, &d)) {
return(d.pos);
} else {
- return(CORD_NOT_FOUND);
+ return(CORD_NOT_FOUND);
}
}
-/* Find the first occurrence of s in x at position start or later. */
-/* This uses an asymptotically poor algorithm, which should typically */
-/* perform acceptably. We compare the first few characters directly, */
-/* and call CORD_ncmp whenever there is a partial match. */
-/* This has the advantage that we allocate very little, or not at all. */
-/* It's very fast if there are few close misses. */
+/* Find the first occurrence of s in x at position start or later. */
+/* This uses an asymptotically poor algorithm, which should typically */
+/* perform acceptably. We compare the first few characters directly, */
+/* and call CORD_ncmp whenever there is a partial match. */
+/* This has the advantage that we allocate very little, or not at all. */
+/* It's very fast if there are few close misses. */
size_t CORD_str(CORD x, size_t start, CORD s)
{
CORD_pos xpos;
@@ -361,14 +375,14 @@ size_t CORD_str(CORD x, size_t start, CORD s)
size_t slen;
register size_t start_len;
const char * s_start;
- unsigned long s_buf = 0; /* The first few characters of s */
- unsigned long x_buf = 0; /* Start of candidate substring. */
- /* Initialized only to make compilers */
- /* happy. */
+ unsigned long s_buf = 0; /* The first few characters of s */
+ unsigned long x_buf = 0; /* Start of candidate substring. */
+ /* Initialized only to make compilers */
+ /* happy. */
unsigned long mask = 0;
register size_t i;
register size_t match_pos;
-
+
if (s == CORD_EMPTY) return(start);
if (CORD_IS_STRING(s)) {
s_start = s;
@@ -391,17 +405,17 @@ size_t CORD_str(CORD x, size_t start, CORD s)
CORD_next(xpos);
}
for (match_pos = start; ; match_pos++) {
- if ((x_buf & mask) == s_buf) {
- if (slen == start_len ||
- CORD_ncmp(x, match_pos + start_len,
- s, start_len, slen - start_len) == 0) {
- return(match_pos);
- }
- }
- if ( match_pos == xlen - slen ) {
- return(CORD_NOT_FOUND);
- }
- x_buf <<= 8;
+ if ((x_buf & mask) == s_buf) {
+ if (slen == start_len ||
+ CORD_ncmp(x, match_pos + start_len,
+ s, start_len, slen - start_len) == 0) {
+ return(match_pos);
+ }
+ }
+ if ( match_pos == xlen - slen ) {
+ return(CORD_NOT_FOUND);
+ }
+ x_buf <<= 8;
x_buf |= (unsigned char)CORD_pos_fetch(xpos);
CORD_next(xpos);
}
@@ -426,8 +440,7 @@ void CORD_ec_append_cord(CORD_ec x, CORD s)
x[0].ec_cord = CORD_cat(x[0].ec_cord, s);
}
-/*ARGSUSED*/
-char CORD_nul_func(size_t i, void * client_data)
+char CORD_nul_func(size_t i CORD_ATTR_UNUSED, void * client_data)
{
return((char)(unsigned long)client_data);
}
@@ -442,16 +455,16 @@ CORD CORD_from_file_eager(FILE * f)
{
register int c;
CORD_ec ecord;
-
+
CORD_ec_init(ecord);
for(;;) {
c = getc(f);
if (c == 0) {
- /* Append the right number of NULs */
- /* Note that any string of NULs is rpresented in 4 words, */
- /* independent of its length. */
+ /* Append the right number of NULs */
+ /* Note that any string of NULs is rpresented in 4 words, */
+ /* independent of its length. */
register size_t count = 1;
-
+
CORD_ec_flush_buf(ecord);
while ((c = getc(f)) == 0) count++;
ecord[0].ec_cord = CORD_cat(ecord[0].ec_cord, CORD_nul(count));
@@ -463,18 +476,18 @@ CORD CORD_from_file_eager(FILE * f)
return(CORD_balance(CORD_ec_to_cord(ecord)));
}
-/* The state maintained for a lazily read file consists primarily */
-/* of a large direct-mapped cache of previously read values. */
-/* We could rely more on stdio buffering. That would have 2 */
-/* disadvantages: */
-/* 1) Empirically, not all fseek implementations preserve the */
-/* buffer whenever they could. */
-/* 2) It would fail if 2 different sections of a long cord */
-/* were being read alternately. */
-/* We do use the stdio buffer for read ahead. */
-/* To guarantee thread safety in the presence of atomic pointer */
-/* writes, cache lines are always replaced, and never modified in */
-/* place. */
+/* The state maintained for a lazily read file consists primarily */
+/* of a large direct-mapped cache of previously read values. */
+/* We could rely more on stdio buffering. That would have 2 */
+/* disadvantages: */
+/* 1) Empirically, not all fseek implementations preserve the */
+/* buffer whenever they could. */
+/* 2) It would fail if 2 different sections of a long cord */
+/* were being read alternately. */
+/* We do use the stdio buffer for read ahead. */
+/* To guarantee thread safety in the presence of atomic pointer */
+/* writes, cache lines are always replaced, and never modified in */
+/* place. */
# define LOG_CACHE_SZ 14
# define CACHE_SZ (1 << LOG_CACHE_SZ)
@@ -484,12 +497,12 @@ CORD CORD_from_file_eager(FILE * f)
typedef struct {
size_t tag;
char data[LINE_SZ];
- /* data[i%LINE_SZ] = ith char in file if tag = i/LINE_SZ */
+ /* data[i%LINE_SZ] = ith char in file if tag = i/LINE_SZ */
} cache_line;
typedef struct {
FILE * lf_file;
- size_t lf_current; /* Current file pointer value */
+ size_t lf_current; /* Current file pointer value */
cache_line * volatile lf_cache[CACHE_SZ/LINE_SZ];
} lf_state;
@@ -501,13 +514,12 @@ typedef struct {
typedef struct {
lf_state * state;
- size_t file_pos; /* Position of needed character. */
+ size_t file_pos; /* Position of needed character. */
cache_line * new_cache;
} refill_data;
/* Executed with allocation lock. */
-static char refill_cache(client_data)
-refill_data * client_data;
+static char refill_cache(refill_data * client_data)
{
register lf_state * state = client_data -> state;
register size_t file_pos = client_data -> file_pos;
@@ -515,14 +527,14 @@ refill_data * client_data;
size_t line_start = LINE_START(file_pos);
size_t line_no = DIV_LINE_SZ(MOD_CACHE_SZ(file_pos));
cache_line * new_cache = client_data -> new_cache;
-
+
if (line_start != state -> lf_current
&& fseek(f, line_start, SEEK_SET) != 0) {
- ABORT("fseek failed");
+ ABORT("fseek failed");
}
if (fread(new_cache -> data, sizeof(char), LINE_SZ, f)
- <= file_pos - line_start) {
- ABORT("fread failed");
+ <= file_pos - line_start) {
+ ABORT("fread failed");
}
new_cache -> tag = DIV_LINE_SZ(file_pos);
/* Store barrier goes here. */
@@ -535,47 +547,49 @@ char CORD_lf_func(size_t i, void * client_data)
{
register lf_state * state = (lf_state *)client_data;
register cache_line * volatile * cl_addr =
- &(state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))]);
+ &(state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))]);
register cache_line * cl = (cache_line *)ATOMIC_READ(cl_addr);
-
+
if (cl == 0 || cl -> tag != DIV_LINE_SZ(i)) {
- /* Cache miss */
- refill_data rd;
-
+ /* Cache miss */
+ refill_data rd;
+
rd.state = state;
rd.file_pos = i;
rd.new_cache = GC_NEW_ATOMIC(cache_line);
if (rd.new_cache == 0) OUT_OF_MEMORY;
return((char)(GC_word)
- GC_call_with_alloc_lock((GC_fn_type) refill_cache, &rd));
+ GC_call_with_alloc_lock((GC_fn_type) refill_cache, &rd));
}
return(cl -> data[MOD_LINE_SZ(i)]);
-}
+}
-/*ARGSUSED*/
-void CORD_lf_close_proc(void * obj, void * client_data)
+void CORD_lf_close_proc(void * obj, void * client_data CORD_ATTR_UNUSED)
{
if (fclose(((lf_state *)obj) -> lf_file) != 0) {
- ABORT("CORD_lf_close_proc: fclose failed");
+ ABORT("CORD_lf_close_proc: fclose failed");
}
-}
+}
CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
{
register lf_state * state = GC_NEW(lf_state);
register int i;
-
+
if (state == 0) OUT_OF_MEMORY;
if (len != 0) {
- /* Dummy read to force buffer allocation. */
- /* This greatly increases the probability */
- /* of avoiding deadlock if buffer allocation */
- /* is redirected to GC_malloc and the */
- /* world is multithreaded. */
- char buf[1];
-
- (void) fread(buf, 1, 1, f);
- rewind(f);
+ /* Dummy read to force buffer allocation. */
+ /* This greatly increases the probability */
+ /* of avoiding deadlock if buffer allocation */
+ /* is redirected to GC_malloc and the */
+ /* world is multithreaded. */
+ char buf[1];
+
+ if (fread(buf, 1, 1, f) > 1) {
+ /* Just to suppress "unused result" compiler warning. */
+ ABORT("fread unexpected result");
+ }
+ rewind(f);
}
state -> lf_file = f;
for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
@@ -589,7 +603,7 @@ CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
CORD CORD_from_file_lazy(FILE * f)
{
register long len;
-
+
if (fseek(f, 0l, SEEK_END) != 0) {
ABORT("Bad fd argument - fseek failed");
}
@@ -605,7 +619,7 @@ CORD CORD_from_file_lazy(FILE * f)
CORD CORD_from_file(FILE * f)
{
register long len;
-
+
if (fseek(f, 0l, SEEK_END) != 0) {
ABORT("Bad fd argument - fseek failed");
}
diff --git a/boehm-gc/cord/de_win.ICO b/boehm-gc/cord/de_win.ICO
deleted file mode 100644
index b20ac3ee16a..00000000000
--- a/boehm-gc/cord/de_win.ICO
+++ /dev/null
Binary files differ
diff --git a/boehm-gc/cord/de_win.h b/boehm-gc/cord/de_win.h
deleted file mode 100644
index 57a47b45c41..00000000000
--- a/boehm-gc/cord/de_win.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/* Boehm, May 19, 1994 2:25 pm PDT */
-
-/* cord.h, de_cmds.h, and windows.h should be included before this. */
-
-
-# define OTHER_FLAG 0x100
-# define EDIT_CMD_FLAG 0x200
-# define REPEAT_FLAG 0x400
-
-# define CHAR_CMD(i) ((i) & 0xff)
-
-/* MENU: DE */
-#define IDM_FILESAVE (EDIT_CMD_FLAG + WRITE)
-#define IDM_FILEEXIT (OTHER_FLAG + 1)
-#define IDM_HELPABOUT (OTHER_FLAG + 2)
-#define IDM_HELPCONTENTS (OTHER_FLAG + 3)
-
-#define IDM_EDITPDOWN (REPEAT_FLAG + EDIT_CMD_FLAG + DOWN)
-#define IDM_EDITPUP (REPEAT_FLAG + EDIT_CMD_FLAG + UP)
-#define IDM_EDITUNDO (EDIT_CMD_FLAG + UNDO)
-#define IDM_EDITLOCATE (EDIT_CMD_FLAG + LOCATE)
-#define IDM_EDITDOWN (EDIT_CMD_FLAG + DOWN)
-#define IDM_EDITUP (EDIT_CMD_FLAG + UP)
-#define IDM_EDITLEFT (EDIT_CMD_FLAG + LEFT)
-#define IDM_EDITRIGHT (EDIT_CMD_FLAG + RIGHT)
-#define IDM_EDITBS (EDIT_CMD_FLAG + BS)
-#define IDM_EDITDEL (EDIT_CMD_FLAG + DEL)
-#define IDM_EDITREPEAT (EDIT_CMD_FLAG + REPEAT)
-#define IDM_EDITTOP (EDIT_CMD_FLAG + TOP)
-
-
-
-
-/* Windows UI stuff */
-
-LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
- UINT wParam, LONG lParam);
-
-LRESULT CALLBACK AboutBox( HWND hDlg, UINT message,
- UINT wParam, LONG lParam );
-
-
-/* Screen dimensions. Maintained by de_win.c. */
-extern int LINES;
-extern int COLS;
-
-/* File being edited. */
-extern char * arg_file_name;
-
-/* Current display position in file. Maintained by de.c */
-extern int dis_line;
-extern int dis_col;
-
-/* Current cursor position in file. */
-extern int line;
-extern int col;
-
-/*
- * Calls from de_win.c to de.c
- */
-
-CORD retrieve_screen_line(int i);
- /* Get the contents of i'th screen line. */
- /* Relies on COLS. */
-
-void set_position(int x, int y);
- /* Set column, row. Upper left of window = (0,0). */
-
-void do_command(int);
- /* Execute an editor command. */
- /* Agument is a command character or one */
- /* of the IDM_ commands. */
-
-void generic_init(void);
- /* OS independent initialization */
-
-
-/*
- * Calls from de.c to de_win.c
- */
-
-void move_cursor(int column, int line);
- /* Physically move the cursor on the display, */
- /* so that it appears at */
- /* (column, line). */
-
-void invalidate_line(int line);
- /* Invalidate line i on the screen. */
-
-void de_error(char *s);
- /* Display error message. */ \ No newline at end of file
diff --git a/boehm-gc/cord/cordtest.c b/boehm-gc/cord/tests/cordtest.c
index 8f4836a2333..cf5c696659a 100644
--- a/boehm-gc/cord/cordtest.c
+++ b/boehm-gc/cord/tests/cordtest.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -10,18 +10,18 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, August 24, 1994 11:58 am PDT */
-# include "gc.h" /* For GC_INIT() only */
+
+# include "gc.h" /* For GC_INIT() only */
# include "cord.h"
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
-/* This is a very incomplete test of the cord package. It knows about */
-/* a few internals of the package (e.g. when C strings are returned) */
-/* that real clients shouldn't rely on. */
+/* This is a very incomplete test of the cord package. It knows about */
+/* a few internals of the package (e.g. when C strings are returned) */
+/* that real clients shouldn't rely on. */
# define ABORT(string) \
-{ int x = 0; fprintf(stderr, "FAILED: %s\n", string); x = 1 / x; abort(); }
+ { int x = 0; fprintf(stderr, "FAILED: %s\n", string); x = 1 / x; abort(); }
int count;
@@ -45,63 +45,69 @@ int test_fn(char c, void * client_data)
char id_cord_fn(size_t i, void * client_data)
{
+ if (client_data != 0) ABORT("id_cord_fn: bad client data");
return((char)i);
}
-void test_basics()
+void test_basics(void)
{
CORD x = CORD_from_char_star("ab");
register int i;
char c;
CORD y;
CORD_pos p;
-
+
x = CORD_cat(x,x);
+ if (x == CORD_EMPTY) ABORT("CORD_cat(x,x) returned empty cord");
if (!CORD_IS_STRING(x)) ABORT("short cord should usually be a string");
if (strcmp(x, "abab") != 0) ABORT("bad CORD_cat result");
-
+
for (i = 1; i < 16; i++) {
x = CORD_cat(x,x);
}
x = CORD_cat(x,"c");
if (CORD_len(x) != 128*1024+1) ABORT("bad length");
-
+
count = 0;
if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) {
ABORT("CORD_iter5 failed");
}
if (count != 64*1024 + 2) ABORT("CORD_iter5 failed");
-
+
count = 0;
CORD_set_pos(p, x, 64*1024-1);
while(CORD_pos_valid(p)) {
- (void) test_fn(CORD_pos_fetch(p), (void *)13);
- CORD_next(p);
+ (void) test_fn(CORD_pos_fetch(p), (void *)13);
+ CORD_next(p);
}
if (count != 64*1024 + 2) ABORT("Position based iteration failed");
-
+
y = CORD_substr(x, 1023, 5);
+ if (!y) ABORT("CORD_substr returned NULL");
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
-
+
y = CORD_substr(x, 1024, 8);
+ if (!y) ABORT("CORD_substr returned NULL");
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
if (strcmp(y, "abababab") != 0) ABORT("bad CORD_substr result");
-
+
y = CORD_substr(x, 128*1024-1, 8);
+ if (!y) ABORT("CORD_substr returned NULL");
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
if (strcmp(y, "bc") != 0) ABORT("bad CORD_substr result");
-
+
x = CORD_balance(x);
if (CORD_len(x) != 128*1024+1) ABORT("bad length");
-
+
count = 0;
if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) {
ABORT("CORD_iter5 failed");
}
if (count != 64*1024 + 2) ABORT("CORD_iter5 failed");
-
+
y = CORD_substr(x, 1023, 5);
+ if (!y) ABORT("CORD_substr returned NULL");
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
y = CORD_from_fn(id_cord_fn, 0, 13);
@@ -109,31 +115,23 @@ void test_basics()
CORD_set_pos(p, y, i);
while(CORD_pos_valid(p)) {
c = CORD_pos_fetch(p);
- if(c != i) ABORT("Traversal of function node failed");
- CORD_next(p); i++;
+ if(c != i) ABORT("Traversal of function node failed");
+ CORD_next(p); i++;
}
if (i != 13) ABORT("Bad apparent length for function node");
}
-void test_extras()
+void test_extras(void)
{
-# if defined(__OS2__) || defined(__DJGPP__)
-# define FNAME1 "tmp1"
-# define FNAME2 "tmp2"
-# elif defined(AMIGA)
-# define FNAME1 "T:tmp1"
-# define FNAME2 "T:tmp2"
-# else
-# define FNAME1 "/tmp/cord_test"
-# define FNAME2 "/tmp/cord_test2"
-# endif
+# define FNAME1 "cordtst1.tmp" /* short name (8+3) for portability */
+# define FNAME2 "cordtst2.tmp"
register int i;
CORD y = "abcdefghijklmnopqrstuvwxyz0123456789";
CORD x = "{}";
CORD w, z;
FILE *f;
FILE *f1a, *f1b, *f2;
-
+
w = CORD_cat(CORD_cat(y,y),y);
z = CORD_catn(3,y,y,y);
if (CORD_cmp(w,z) != 0) ABORT("CORD_catn comparison wrong");
@@ -148,12 +146,16 @@ void test_extras()
if ((f = fopen(FNAME1, "w")) == 0) ABORT("open failed");
if (CORD_put(z,f) == EOF) ABORT("CORD_put failed");
if (fclose(f) == EOF) ABORT("fclose failed");
- w = CORD_from_file(f1a = fopen(FNAME1, "rb"));
+ f1a = fopen(FNAME1, "rb");
+ if (!f1a) ABORT("Unable to open " FNAME1);
+ w = CORD_from_file(f1a);
if (CORD_len(w) != CORD_len(z)) ABORT("file length wrong");
if (CORD_cmp(w,z) != 0) ABORT("file comparison wrong");
if (CORD_cmp(CORD_substr(w, 50*36+2, 36), y) != 0)
- ABORT("file substr wrong");
- z = CORD_from_file_lazy(f1b = fopen(FNAME1, "rb"));
+ ABORT("file substr wrong");
+ f1b = fopen(FNAME1, "rb");
+ if (!f1b) ABORT("2nd open failed: " FNAME1);
+ z = CORD_from_file_lazy(f1b);
if (CORD_cmp(w,z) != 0) ABORT("File conversions differ");
if (CORD_chr(w, 0, '9') != 37) ABORT("CORD_chr failed 1");
if (CORD_chr(w, 3, 'a') != 38) ABORT("CORD_chr failed 2");
@@ -169,46 +171,53 @@ void test_extras()
# endif
if (CORD_put(x,f) == EOF) ABORT("CORD_put failed");
if (fclose(f) == EOF) ABORT("fclose failed");
- w = CORD_from_file(f2 = fopen(FNAME2, "rb"));
+ f2 = fopen(FNAME2, "rb");
+ if (!f2) ABORT("Unable to open " FNAME2);
+ w = CORD_from_file(f2);
if (CORD_len(w) != CORD_len(x)) ABORT("file length wrong");
if (CORD_cmp(w,x) != 0) ABORT("file comparison wrong");
if (CORD_cmp(CORD_substr(w, 1000*36, 36), y) != 0)
- ABORT("file substr wrong");
+ ABORT("file substr wrong");
if (strcmp(CORD_to_char_star(CORD_substr(w, 1000*36, 36)), y) != 0)
- ABORT("char * file substr wrong");
+ ABORT("char * file substr wrong");
if (strcmp(CORD_substr(w, 1000*36, 2), "ab") != 0)
- ABORT("short file substr wrong");
+ ABORT("short file substr wrong");
if (CORD_str(x,1,"9a") != 35) ABORT("CORD_str failed 1");
if (CORD_str(x,0,"9abcdefghijk") != 35) ABORT("CORD_str failed 2");
if (CORD_str(x,0,"9abcdefghijx") != CORD_NOT_FOUND)
- ABORT("CORD_str failed 3");
+ ABORT("CORD_str failed 3");
if (CORD_str(x,0,"9>") != CORD_NOT_FOUND) ABORT("CORD_str failed 4");
+ /* Note: f1a, f1b, f2 handles are closed lazily by CORD library. */
+ /* TODO: Propose and use CORD_fclose. */
+ *(CORD volatile *)&w = CORD_EMPTY;
+ *(CORD volatile *)&z = CORD_EMPTY;
+ GC_gcollect();
+ GC_invoke_finalizers();
+ /* Of course, this does not guarantee the files are closed. */
if (remove(FNAME1) != 0) {
- /* On some systems, e.g. OS2, this may fail if f1 is still open. */
- if ((fclose(f1a) == EOF) & (fclose(f1b) == EOF))
- ABORT("fclose(f1) failed");
- if (remove(FNAME1) != 0) ABORT("remove 1 failed");
+ /* On some systems, e.g. OS2, this may fail if f1 is still open. */
+ /* But we cannot call fclose as it might lead to double close. */
+ fprintf(stderr, "WARNING: remove(FNAME1) failed\n");
}
if (remove(FNAME2) != 0) {
- if (fclose(f2) == EOF) ABORT("fclose(f2) failed");
- if (remove(FNAME2) != 0) ABORT("remove 2 failed");
+ fprintf(stderr, "WARNING: remove(FNAME2) failed\n");
}
}
-void test_printf()
+void test_printf(void)
{
CORD result;
char result2[200];
- long l;
- short s;
+ long l = -1;
+ short s = (short)-1;
CORD x;
-
+
if (CORD_sprintf(&result, "%7.2f%ln", 3.14159F, &l) != 7)
- ABORT("CORD_sprintf failed 1");
+ ABORT("CORD_sprintf failed 1");
if (CORD_cmp(result, " 3.14") != 0)ABORT("CORD_sprintf goofed 1");
if (l != 7) ABORT("CORD_sprintf goofed 2");
if (CORD_sprintf(&result, "%-7.2s%hn%c%s", "abcd", &s, 'x', "yz") != 10)
- ABORT("CORD_sprintf failed 2");
+ ABORT("CORD_sprintf failed 2");
if (CORD_cmp(result, "ab xyz") != 0)ABORT("CORD_sprintf goofed 3");
if (s != 7) ABORT("CORD_sprintf goofed 4");
x = "abcdefghij";
@@ -216,12 +225,14 @@ void test_printf()
x = CORD_cat(x,x);
x = CORD_cat(x,x);
if (CORD_sprintf(&result, "->%-120.78r!\n", x) != 124)
- ABORT("CORD_sprintf failed 3");
- (void) sprintf(result2, "->%-120.78s!\n", CORD_to_char_star(x));
+ ABORT("CORD_sprintf failed 3");
+ (void)snprintf(result2, sizeof(result2), "->%-120.78s!\n",
+ CORD_to_char_star(x));
+ result2[sizeof(result2) - 1] = '\0';
if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
}
-main()
+int main(void)
{
# ifdef THINK_C
printf("cordtest:\n");
@@ -230,6 +241,6 @@ main()
test_basics();
test_extras();
test_printf();
- CORD_fprintf(stderr, "SUCCEEDED\n");
+ CORD_fprintf(stdout, "SUCCEEDED\n");
return(0);
}
diff --git a/boehm-gc/cord/de.c b/boehm-gc/cord/tests/de.c
index 989e19a8881..068848c44f5 100644
--- a/boehm-gc/cord/de.c
+++ b/boehm-gc/cord/tests/de.c
@@ -9,26 +9,23 @@
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
- *
- * Author: Hans-J. Boehm (boehm@parc.xerox.com)
*/
+
/*
* A really simple-minded text editor based on cords.
* Things it does right:
- * No size bounds.
- * Inbounded undo.
- * Shouldn't crash no matter what file you invoke it on (e.g. /vmunix)
- * (Make sure /vmunix is not writable before you try this.)
- * Scrolls horizontally.
+ * No size bounds.
+ * Inbounded undo.
+ * Shouldn't crash no matter what file you invoke it on (e.g. /vmunix)
+ * (Make sure /vmunix is not writable before you try this.)
+ * Scrolls horizontally.
* Things it does wrong:
- * It doesn't handle tabs reasonably (use "expand" first).
- * The command set is MUCH too small.
- * The redisplay algorithm doesn't let curses do the scrolling.
- * The rule for moving the window over the file is suboptimal.
+ * It doesn't handle tabs reasonably (use "expand" first).
+ * The command set is MUCH too small.
+ * The redisplay algorithm doesn't let curses do the scrolling.
+ * The rule for moving the window over the file is suboptimal.
*/
-/* Boehm, February 6, 1995 12:27 pm PST */
-/* Boehm, May 19, 1994 2:20 pm PDT */
#include <stdio.h>
#include "gc.h"
#include "cord.h"
@@ -38,9 +35,9 @@
#include <ctype.h>
#endif
-#if defined(__BORLANDC__) && !defined(WIN32)
- /* If this is DOS or win16, we'll fail anyway. */
- /* Might as well assume win32. */
+#if (defined(__BORLANDC__) || defined(__CYGWIN__)) && !defined(WIN32)
+ /* If this is DOS or win16, we'll fail anyway. */
+ /* Might as well assume win32. */
# define WIN32
#endif
@@ -48,22 +45,22 @@
# include <windows.h>
# include "de_win.h"
#elif defined(MACINTOSH)
-# include <console.h>
+# include <console.h>
/* curses emulation. */
-# define initscr()
-# define endwin()
-# define nonl()
-# define noecho() csetmode(C_NOECHO, stdout)
-# define cbreak() csetmode(C_CBREAK, stdout)
-# define refresh()
-# define addch(c) putchar(c)
-# define standout() cinverse(1, stdout)
-# define standend() cinverse(0, stdout)
-# define move(line,col) cgotoxy(col + 1, line + 1, stdout)
-# define clrtoeol() ccleol(stdout)
-# define de_error(s) { fprintf(stderr, s); getchar(); }
-# define LINES 25
-# define COLS 80
+# define initscr()
+# define endwin()
+# define nonl()
+# define noecho() csetmode(C_NOECHO, stdout)
+# define cbreak() csetmode(C_CBREAK, stdout)
+# define refresh()
+# define addch(c) putchar(c)
+# define standout() cinverse(1, stdout)
+# define standend() cinverse(0, stdout)
+# define move(line,col) cgotoxy(col + 1, line + 1, stdout)
+# define clrtoeol() ccleol(stdout)
+# define de_error(s) { fprintf(stderr, s); getchar(); }
+# define LINES 25
+# define COLS 80
#else
# include <curses.h>
# define de_error(s) { fprintf(stderr, s); sleep(2); }
@@ -71,7 +68,7 @@
#include "de_cmds.h"
/* List of line number to position mappings, in descending order. */
-/* There may be holes. */
+/* There may be holes. */
typedef struct LineMapRep {
int line;
size_t pos;
@@ -82,16 +79,16 @@ typedef struct LineMapRep {
typedef struct HistoryRep {
CORD file_contents;
struct HistoryRep * previous;
- line_map map; /* Invalid for first record "now" */
+ line_map map; /* Invalid for first record "now" */
} * history;
history now = 0;
-CORD current; /* == now -> file_contents. */
-size_t current_len; /* Current file length. */
-line_map current_map = 0; /* Current line no. to pos. map */
-size_t current_map_size = 0; /* Number of current_map entries. */
- /* Not always accurate, but reset */
- /* by prune_map. */
+CORD current; /* == now -> file_contents. */
+size_t current_len; /* Current file length. */
+line_map current_map = 0; /* Current line no. to pos. map */
+size_t current_map_size = 0; /* Number of current_map entries. */
+ /* Not always accurate, but reset */
+ /* by prune_map. */
# define MAX_MAP_SIZE 3000
/* Current display position */
@@ -100,13 +97,13 @@ int dis_col = 0;
# define ALL -1
# define NONE - 2
-int need_redisplay = 0; /* Line that needs to be redisplayed. */
+int need_redisplay = 0; /* Line that needs to be redisplayed. */
/* Current cursor position. Always within file. */
-int line = 0;
+int line = 0;
int col = 0;
-size_t file_pos = 0; /* Character position corresponding to cursor. */
+size_t file_pos = 0; /* Character position corresponding to cursor. */
/* Invalidate line map for lines > i */
void invalidate_map(int i)
@@ -118,25 +115,25 @@ void invalidate_map(int i)
}
/* Reduce the number of map entries to save space for huge files. */
-/* This also affects maps in histories. */
+/* This also affects maps in histories. */
void prune_map()
{
line_map map = current_map;
int start_line = map -> line;
-
+
current_map_size = 0;
for(; map != 0; map = map -> previous) {
- current_map_size++;
- if (map -> line < start_line - LINES && map -> previous != 0) {
- map -> previous = map -> previous -> previous;
- }
+ current_map_size++;
+ if (map -> line < start_line - LINES && map -> previous != 0) {
+ map -> previous = map -> previous -> previous;
+ }
}
}
/* Add mapping entry */
void add_map(int line, size_t pos)
{
line_map new_map = GC_NEW(struct LineMapRep);
-
+
if (current_map_size >= MAX_MAP_SIZE) prune_map();
new_map -> line = line;
new_map -> pos = pos;
@@ -149,20 +146,20 @@ void add_map(int line, size_t pos)
/* Return position of column *c of ith line in */
/* current file. Adjust *c to be within the line.*/
-/* A 0 pointer is taken as 0 column. */
-/* Returns CORD_NOT_FOUND if i is too big. */
-/* Assumes i > dis_line. */
+/* A 0 pointer is taken as 0 column. */
+/* Returns CORD_NOT_FOUND if i is too big. */
+/* Assumes i > dis_line. */
size_t line_pos(int i, int *c)
{
int j;
size_t cur;
size_t next;
line_map map = current_map;
-
+
while (map -> line > i) map = map -> previous;
if (map -> line < i - 2) /* rebuild */ invalidate_map(i);
for (j = map -> line, cur = map -> pos; j < i;) {
- cur = CORD_chr(current, cur, '\n');
+ cur = CORD_chr(current, cur, '\n');
if (cur == current_len-1) return(CORD_NOT_FOUND);
cur++;
if (++j > current_map -> line) add_map(j, cur);
@@ -181,7 +178,7 @@ size_t line_pos(int i, int *c)
void add_hist(CORD s)
{
history new_file = GC_NEW(struct HistoryRep);
-
+
new_file -> file_contents = current = s;
current_len = CORD_len(s);
new_file -> previous = now;
@@ -197,23 +194,23 @@ void del_hist(void)
current_len = CORD_len(current);
}
-/* Current screen_contents; a dynamically allocated array of CORDs */
+/* Current screen_contents; a dynamically allocated array of CORDs */
CORD * screen = 0;
int screen_size = 0;
# ifndef WIN32
-/* Replace a line in the curses stdscr. All control characters are */
-/* displayed as upper case characters in standout mode. This isn't */
-/* terribly appropriate for tabs. */
+/* Replace a line in the curses stdscr. All control characters are */
+/* displayed as upper case characters in standout mode. This isn't */
+/* terribly appropriate for tabs. */
void replace_line(int i, CORD s)
{
register int c;
CORD_pos p;
size_t len = CORD_len(s);
-
+
if (screen == 0 || LINES > screen_size) {
screen_size = LINES;
- screen = (CORD *)GC_MALLOC(screen_size * sizeof(CORD));
+ screen = (CORD *)GC_MALLOC(screen_size * sizeof(CORD));
}
# if !defined(MACINTOSH)
/* A gross workaround for an apparent curses bug: */
@@ -227,27 +224,27 @@ void replace_line(int i, CORD s)
CORD_FOR (p, s) {
c = CORD_pos_fetch(p) & 0x7f;
if (iscntrl(c)) {
- standout(); addch(c + 0x40); standend();
+ standout(); addch(c + 0x40); standend();
} else {
- addch(c);
- }
- }
- screen[i] = s;
+ addch(c);
+ }
+ }
+ screen[i] = s;
}
}
#else
# define replace_line(i,s) invalidate_line(i)
#endif
-/* Return up to COLS characters of the line of s starting at pos, */
-/* returning only characters after the given column. */
+/* Return up to COLS characters of the line of s starting at pos, */
+/* returning only characters after the given column. */
CORD retrieve_line(CORD s, size_t pos, unsigned column)
{
CORD candidate = CORD_substr(s, pos, column + COLS);
- /* avoids scanning very long lines */
- int eol = CORD_chr(candidate, 0, '\n');
+ /* avoids scanning very long lines */
+ size_t eol = CORD_chr(candidate, 0, '\n');
int len;
-
+
if (eol == CORD_NOT_FOUND) eol = CORD_len(candidate);
len = (int)eol - (int)column;
if (len < 0) len = 0;
@@ -259,25 +256,25 @@ CORD retrieve_line(CORD s, size_t pos, unsigned column)
CORD retrieve_screen_line(int i)
{
- register size_t pos;
-
- invalidate_map(dis_line + LINES); /* Prune search */
- pos = line_pos(dis_line + i, 0);
- if (pos == CORD_NOT_FOUND) return(CORD_EMPTY);
- return(retrieve_line(current, pos, dis_col));
+ register size_t pos;
+
+ invalidate_map(dis_line + LINES); /* Prune search */
+ pos = line_pos(dis_line + i, 0);
+ if (pos == CORD_NOT_FOUND) return(CORD_EMPTY);
+ return(retrieve_line(current, pos, dis_col));
}
# endif
-/* Display the visible section of the current file */
+/* Display the visible section of the current file */
void redisplay(void)
{
register int i;
-
- invalidate_map(dis_line + LINES); /* Prune search */
+
+ invalidate_map(dis_line + LINES); /* Prune search */
for (i = 0; i < LINES; i++) {
if (need_redisplay == ALL || need_redisplay == i) {
register size_t pos = line_pos(dis_line + i, 0);
-
+
if (pos == CORD_NOT_FOUND) break;
replace_line(i, retrieve_line(current, pos, dis_col));
if (need_redisplay == i) goto done;
@@ -291,13 +288,13 @@ done:
int dis_granularity;
-/* Update dis_line, dis_col, and dis_pos to make cursor visible. */
-/* Assumes line, col, dis_line, dis_pos are in bounds. */
+/* Update dis_line, dis_col, and dis_pos to make cursor visible. */
+/* Assumes line, col, dis_line, dis_pos are in bounds. */
void normalize_display()
{
int old_line = dis_line;
int old_col = dis_col;
-
+
dis_granularity = 1;
if (LINES > 15 && COLS > 15) dis_granularity = 2;
while (dis_line > line) dis_line -= dis_granularity;
@@ -311,13 +308,13 @@ void normalize_display()
# if defined(WIN32)
# elif defined(MACINTOSH)
-# define move_cursor(x,y) cgotoxy(x + 1, y + 1, stdout)
+# define move_cursor(x,y) cgotoxy(x + 1, y + 1, stdout)
# else
-# define move_cursor(x,y) move(y,x)
+# define move_cursor(x,y) move(y,x)
# endif
-/* Adjust display so that cursor is visible; move cursor into position */
-/* Update screen if necessary. */
+/* Adjust display so that cursor is visible; move cursor into position */
+/* Update screen if necessary. */
void fix_cursor(void)
{
normalize_display();
@@ -329,57 +326,53 @@ void fix_cursor(void)
# endif
}
-/* Make sure line, col, and dis_pos are somewhere inside file. */
-/* Recompute file_pos. Assumes dis_pos is accurate or past eof */
+/* Make sure line, col, and dis_pos are somewhere inside file. */
+/* Recompute file_pos. Assumes dis_pos is accurate or past eof */
void fix_pos()
{
int my_col = col;
-
+
if ((size_t)line > current_len) line = current_len;
file_pos = line_pos(line, &my_col);
if (file_pos == CORD_NOT_FOUND) {
for (line = current_map -> line, file_pos = current_map -> pos;
file_pos < current_len;
line++, file_pos = CORD_chr(current, file_pos, '\n') + 1);
- line--;
+ line--;
file_pos = line_pos(line, &col);
} else {
- col = my_col;
+ col = my_col;
}
}
#if defined(WIN32)
-# define beep() Beep(1000 /* Hz */, 300 /* msecs */)
+# define beep() Beep(1000 /* Hz */, 300 /* msecs */)
#elif defined(MACINTOSH)
-# define beep() SysBeep(1)
+# define beep() SysBeep(1)
#else
/*
* beep() is part of some curses packages and not others.
* We try to match the type of the builtin one, if any.
*/
-#ifdef __STDC__
- int beep(void)
-#else
- int beep()
-#endif
-{
+ int beep(void)
+ {
putc('\007', stderr);
return(0);
-}
-#endif
+ }
+#endif /* !WIN32 && !MACINTOSH */
# define NO_PREFIX -1
# define BARE_PREFIX -2
-int repeat_count = NO_PREFIX; /* Current command prefix. */
+int repeat_count = NO_PREFIX; /* Current command prefix. */
-int locate_mode = 0; /* Currently between 2 ^Ls */
-CORD locate_string = CORD_EMPTY; /* Current search string. */
+int locate_mode = 0; /* Currently between 2 ^Ls */
+CORD locate_string = CORD_EMPTY; /* Current search string. */
char * arg_file_name;
#ifdef WIN32
-/* Change the current position to whatever is currently displayed at */
-/* the given SCREEN coordinates. */
+/* Change the current position to whatever is currently displayed at */
+/* the given SCREEN coordinates. */
void set_position(int c, int l)
{
line = l + dis_line;
@@ -389,21 +382,21 @@ void set_position(int c, int l)
}
#endif /* WIN32 */
-/* Perform the command associated with character c. C may be an */
-/* integer > 256 denoting a windows command, one of the above control */
-/* characters, or another ASCII character to be used as either a */
-/* character to be inserted, a repeat count, or a search string, */
-/* depending on the current state. */
+/* Perform the command associated with character c. C may be an */
+/* integer > 256 denoting a windows command, one of the above control */
+/* characters, or another ASCII character to be used as either a */
+/* character to be inserted, a repeat count, or a search string, */
+/* depending on the current state. */
void do_command(int c)
{
int i;
int need_fix_pos;
FILE * out;
-
+
if ( c == '\r') c = '\n';
if (locate_mode) {
size_t new_pos;
-
+
if (c == LOCATE) {
locate_mode = 0;
locate_string = CORD_EMPTY;
@@ -411,27 +404,27 @@ void do_command(int c)
}
locate_string = CORD_cat_char(locate_string, (char)c);
new_pos = CORD_str(current, file_pos - CORD_len(locate_string) + 1,
- locate_string);
+ locate_string);
if (new_pos != CORD_NOT_FOUND) {
need_redisplay = ALL;
new_pos += CORD_len(locate_string);
for (;;) {
- file_pos = line_pos(line + 1, 0);
- if (file_pos > new_pos) break;
- line++;
+ file_pos = line_pos(line + 1, 0);
+ if (file_pos > new_pos) break;
+ line++;
}
col = new_pos - line_pos(line, 0);
file_pos = new_pos;
fix_cursor();
} else {
locate_string = CORD_substr(locate_string, 0,
- CORD_len(locate_string) - 1);
+ CORD_len(locate_string) - 1);
beep();
}
return;
}
if (c == REPEAT) {
- repeat_count = BARE_PREFIX; return;
+ repeat_count = BARE_PREFIX; return;
} else if (c < 0x100 && isdigit(c)){
if (repeat_count == BARE_PREFIX) {
repeat_count = c - '0'; return;
@@ -441,7 +434,7 @@ void do_command(int c)
}
if (repeat_count == NO_PREFIX) repeat_count = 1;
if (repeat_count == BARE_PREFIX && (c == UP || c == DOWN)) {
- repeat_count = LINES - dis_granularity;
+ repeat_count = LINES - dis_granularity;
}
if (repeat_count == BARE_PREFIX) repeat_count = 8;
need_fix_pos = 0;
@@ -453,80 +446,80 @@ void do_command(int c)
case TOP:
line = col = file_pos = 0;
break;
- case UP:
- if (line != 0) {
- line--;
- need_fix_pos = 1;
- }
- break;
- case DOWN:
- line++;
- need_fix_pos = 1;
- break;
- case LEFT:
- if (col != 0) {
- col--; file_pos--;
- }
- break;
- case RIGHT:
- if (CORD_fetch(current, file_pos) == '\n') break;
- col++; file_pos++;
- break;
- case UNDO:
- del_hist();
- need_redisplay = ALL; need_fix_pos = 1;
- break;
- case BS:
- if (col == 0) {
- beep();
- break;
- }
- col--; file_pos--;
- /* fall through: */
- case DEL:
- if (file_pos == current_len-1) break;
- /* Can't delete trailing newline */
- if (CORD_fetch(current, file_pos) == '\n') {
- need_redisplay = ALL; need_fix_pos = 1;
- } else {
- need_redisplay = line - dis_line;
- }
- add_hist(CORD_cat(
- CORD_substr(current, 0, file_pos),
- CORD_substr(current, file_pos+1, current_len)));
- invalidate_map(line);
- break;
- case WRITE:
- {
- CORD name = CORD_cat(CORD_from_char_star(arg_file_name),
- ".new");
-
- if ((out = fopen(CORD_to_const_char_star(name), "wb")) == NULL
- || CORD_put(current, out) == EOF) {
- de_error("Write failed\n");
- need_redisplay = ALL;
+ case UP:
+ if (line != 0) {
+ line--;
+ need_fix_pos = 1;
+ }
+ break;
+ case DOWN:
+ line++;
+ need_fix_pos = 1;
+ break;
+ case LEFT:
+ if (col != 0) {
+ col--; file_pos--;
+ }
+ break;
+ case RIGHT:
+ if (CORD_fetch(current, file_pos) == '\n') break;
+ col++; file_pos++;
+ break;
+ case UNDO:
+ del_hist();
+ need_redisplay = ALL; need_fix_pos = 1;
+ break;
+ case BS:
+ if (col == 0) {
+ beep();
+ break;
+ }
+ col--; file_pos--;
+ /* fall through: */
+ case DEL:
+ if (file_pos == current_len-1) break;
+ /* Can't delete trailing newline */
+ if (CORD_fetch(current, file_pos) == '\n') {
+ need_redisplay = ALL; need_fix_pos = 1;
+ } else {
+ need_redisplay = line - dis_line;
+ }
+ add_hist(CORD_cat(
+ CORD_substr(current, 0, file_pos),
+ CORD_substr(current, file_pos+1, current_len)));
+ invalidate_map(line);
+ break;
+ case WRITE:
+ {
+ CORD name = CORD_cat(CORD_from_char_star(arg_file_name),
+ ".new");
+
+ if ((out = fopen(CORD_to_const_char_star(name), "wb")) == NULL
+ || CORD_put(current, out) == EOF) {
+ de_error("Write failed\n");
+ need_redisplay = ALL;
} else {
fclose(out);
}
- }
+ }
break;
- default:
- {
- CORD left_part = CORD_substr(current, 0, file_pos);
- CORD right_part = CORD_substr(current, file_pos, current_len);
-
- add_hist(CORD_cat(CORD_cat_char(left_part, (char)c),
- right_part));
- invalidate_map(line);
- if (c == '\n') {
- col = 0; line++; file_pos++;
- need_redisplay = ALL;
- } else {
- col++; file_pos++;
- need_redisplay = line - dis_line;
- }
- break;
- }
+ default:
+ {
+ CORD left_part = CORD_substr(current, 0, file_pos);
+ CORD right_part = CORD_substr(current, file_pos, current_len);
+
+ add_hist(CORD_cat(CORD_cat_char(left_part, (char)c),
+ right_part));
+ invalidate_map(line);
+ if (c == '\n') {
+ col = 0; line++; file_pos++;
+ need_redisplay = ALL;
+ } else {
+ col++; file_pos++;
+ need_redisplay = line - dis_line;
+ }
+ break;
+ }
}
}
if (need_fix_pos) fix_pos();
@@ -540,9 +533,9 @@ void generic_init(void)
{
FILE * f;
CORD initial;
-
+
if ((f = fopen(arg_file_name, "rb")) == NULL) {
- initial = "\n";
+ initial = "\n";
} else {
initial = CORD_from_file(f);
if (initial == CORD_EMPTY
@@ -567,12 +560,12 @@ char ** argv;
int c;
#if defined(MACINTOSH)
- console_options.title = "\pDumb Editor";
- cshow(stdout);
- argc = ccommand(&argv);
+ console_options.title = "\pDumb Editor";
+ cshow(stdout);
+ argc = ccommand(&argv);
#endif
GC_INIT();
-
+
if (argc != 2) goto usage;
arg_file_name = argv[1];
setvbuf(stdout, GC_MALLOC_ATOMIC(8192), _IOFBF, 8192);
@@ -580,8 +573,8 @@ char ** argv;
noecho(); nonl(); cbreak();
generic_init();
while ((c = getchar()) != QUIT) {
- if (c == EOF) break;
- do_command(c);
+ if (c == EOF) break;
+ do_command(c);
}
done:
move(LINES-1, 0);
diff --git a/boehm-gc/cord/de_cmds.h b/boehm-gc/cord/tests/de_cmds.h
index f42ddcf2da7..2a69594ef06 100644
--- a/boehm-gc/cord/de_cmds.h
+++ b/boehm-gc/cord/tests/de_cmds.h
@@ -10,24 +10,22 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:24 pm PDT */
#ifndef DE_CMDS_H
# define DE_CMDS_H
-# define UP 16 /* ^P */
-# define DOWN 14 /* ^N */
-# define LEFT 2 /* ^B */
-# define RIGHT 6 /* ^F */
-# define DEL 127 /* ^? */
-# define BS 8 /* ^H */
-# define UNDO 21 /* ^U */
-# define WRITE 23 /* ^W */
-# define QUIT 4 /* ^D */
-# define REPEAT 18 /* ^R */
-# define LOCATE 12 /* ^L */
-# define TOP 20 /* ^T */
+# define UP 16 /* ^P */
+# define DOWN 14 /* ^N */
+# define LEFT 2 /* ^B */
+# define RIGHT 6 /* ^F */
+# define DEL 127 /* ^? */
+# define BS 8 /* ^H */
+# define UNDO 21 /* ^U */
+# define WRITE 23 /* ^W */
+# define QUIT 4 /* ^D */
+# define REPEAT 18 /* ^R */
+# define LOCATE 12 /* ^L */
+# define TOP 20 /* ^T */
#endif
-
diff --git a/boehm-gc/cord/de_win.c b/boehm-gc/cord/tests/de_win.c
index 0bbd676a335..1179b8f7e52 100644
--- a/boehm-gc/cord/de_win.c
+++ b/boehm-gc/cord/tests/de_win.c
@@ -10,18 +10,15 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, February 6, 1995 12:29 pm PST */
/*
- * The MS Windows specific part of de.
+ * The MS Windows specific part of de.
* This started as the generic Windows application template
- * made available by Rob Haack (rhaack@polaris.unm.edu), but
- * significant parts didn't survive to the final version.
+ * but significant parts didn't survive to the final version.
*
* This was written by a nonexpert windows programmer.
*/
-
#include "windows.h"
#include "gc.h"
#include "cord.h"
@@ -51,6 +48,11 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
WNDCLASS wndclass;
HANDLE hAccel;
+# ifdef THREAD_LOCAL_ALLOC
+ GC_INIT(); /* Required if GC is built with THREAD_LOCAL_ALLOC */
+ /* Always safe, but this is used as a GC test. */
+# endif
+
if (!hPrevInstance)
{
wndclass.style = CS_HREDRAW | CS_VREDRAW;
@@ -66,51 +68,53 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
if (RegisterClass (&wndclass) == 0) {
char buf[50];
-
- sprintf(buf, "RegisterClass: error code: 0x%X", GetLastError());
- de_error(buf);
- return(0);
+
+ sprintf(buf, "RegisterClass: error code: 0x%X",
+ (unsigned)GetLastError());
+ de_error(buf);
+ return(0);
}
}
-
+
/* Empirically, the command line does not include the command name ...
if (command_line != 0) {
while (isspace(*command_line)) command_line++;
while (*command_line != 0 && !isspace(*command_line)) command_line++;
while (isspace(*command_line)) command_line++;
} */
-
+
if (command_line == 0 || *command_line == 0) {
de_error("File name argument required");
return( 0 );
} else {
char *p = command_line;
-
+
while (*p != 0 && !isspace(*p)) p++;
- arg_file_name = CORD_to_char_star(
- CORD_substr(command_line, 0, p - command_line));
+ arg_file_name = CORD_to_char_star(
+ CORD_substr(command_line, 0, p - command_line));
}
hwnd = CreateWindow (szAppName,
- FullAppName,
- WS_OVERLAPPEDWINDOW | WS_CAPTION, /* Window style */
- CW_USEDEFAULT, 0, /* default pos. */
- CW_USEDEFAULT, 0, /* default width, height */
- NULL, /* No parent */
- NULL, /* Window class menu */
- hInstance, NULL);
+ FullAppName,
+ WS_OVERLAPPEDWINDOW | WS_CAPTION, /* Window style */
+ CW_USEDEFAULT, 0, /* default pos. */
+ CW_USEDEFAULT, 0, /* default width, height */
+ NULL, /* No parent */
+ NULL, /* Window class menu */
+ hInstance, NULL);
if (hwnd == NULL) {
- char buf[50];
-
- sprintf(buf, "CreateWindow: error code: 0x%X", GetLastError());
- de_error(buf);
- return(0);
+ char buf[50];
+
+ sprintf(buf, "CreateWindow: error code: 0x%X",
+ (unsigned)GetLastError());
+ de_error(buf);
+ return(0);
}
ShowWindow (hwnd, nCmdShow);
hAccel = LoadAccelerators( hInstance, szAppName );
-
+
while (GetMessage (&msg, NULL, 0, 0))
{
if( !TranslateAccelerator( hwnd, hAccel, &msg ) )
@@ -122,12 +126,12 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
return msg.wParam;
}
-/* Return the argument with all control characters replaced by blanks. */
+/* Return the argument with all control characters replaced by blanks. */
char * plain_chars(char * text, size_t len)
{
char * result = GC_MALLOC_ATOMIC(len + 1);
register size_t i;
-
+
for (i = 0; i < len; i++) {
if (iscntrl(text[i])) {
result[i] = ' ';
@@ -139,13 +143,13 @@ char * plain_chars(char * text, size_t len)
return(result);
}
-/* Return the argument with all non-control-characters replaced by */
-/* blank, and all control characters c replaced by c + 32. */
+/* Return the argument with all non-control-characters replaced by */
+/* blank, and all control characters c replaced by c + 32. */
char * control_chars(char * text, size_t len)
{
char * result = GC_MALLOC_ATOMIC(len + 1);
register size_t i;
-
+
for (i = 0; i < len; i++) {
if (iscntrl(text[i])) {
result[i] = text[i] + 0x40;
@@ -168,16 +172,42 @@ void get_line_rect(int line, int win_width, RECT * rectp)
rectp -> right = win_width;
}
-int caret_visible = 0; /* Caret is currently visible. */
+int caret_visible = 0; /* Caret is currently visible. */
-int screen_was_painted = 0;/* Screen has been painted at least once. */
+int screen_was_painted = 0;/* Screen has been painted at least once. */
void update_cursor(void);
+INT_PTR CALLBACK AboutBoxCallback( HWND hDlg, UINT message,
+ WPARAM wParam, LPARAM lParam )
+{
+ (void)lParam;
+ switch( message )
+ {
+ case WM_INITDIALOG:
+ SetFocus( GetDlgItem( hDlg, IDOK ) );
+ break;
+
+ case WM_COMMAND:
+ switch( wParam )
+ {
+ case IDOK:
+ EndDialog( hDlg, TRUE );
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog( hDlg, TRUE );
+ return TRUE;
+
+ }
+ return FALSE;
+}
+
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
- static FARPROC lpfnAboutBox;
static HANDLE hInstance;
HDC dc;
PAINTSTRUCT ps;
@@ -192,7 +222,6 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
{
case WM_CREATE:
hInstance = ( (LPCREATESTRUCT) lParam)->hInstance;
- lpfnAboutBox = MakeProcInstance( (FARPROC) AboutBox, hInstance );
dc = GetDC(hwnd);
SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(dc, &tm);
@@ -200,44 +229,44 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
char_width = tm.tmAveCharWidth;
char_height = tm.tmHeight + tm.tmExternalLeading;
GetClientRect(hwnd, &client_area);
- COLS = (client_area.right - client_area.left)/char_width;
- LINES = (client_area.bottom - client_area.top)/char_height;
- generic_init();
+ COLS = (client_area.right - client_area.left)/char_width;
+ LINES = (client_area.bottom - client_area.top)/char_height;
+ generic_init();
return(0);
case WM_CHAR:
- if (wParam == QUIT) {
- SendMessage( hwnd, WM_CLOSE, 0, 0L );
- } else {
- do_command(wParam);
- }
- return(0);
-
+ if (wParam == QUIT) {
+ SendMessage( hwnd, WM_CLOSE, 0, 0L );
+ } else {
+ do_command((int)wParam);
+ }
+ return(0);
+
case WM_SETFOCUS:
- CreateCaret(hwnd, NULL, char_width, char_height);
- ShowCaret(hwnd);
- caret_visible = 1;
- update_cursor();
- return(0);
-
+ CreateCaret(hwnd, NULL, char_width, char_height);
+ ShowCaret(hwnd);
+ caret_visible = 1;
+ update_cursor();
+ return(0);
+
case WM_KILLFOCUS:
- HideCaret(hwnd);
- DestroyCaret();
- caret_visible = 0;
- return(0);
-
+ HideCaret(hwnd);
+ DestroyCaret();
+ caret_visible = 0;
+ return(0);
+
case WM_LBUTTONUP:
- {
- unsigned xpos = LOWORD(lParam); /* From left */
- unsigned ypos = HIWORD(lParam); /* from top */
-
- set_position( xpos/char_width, ypos/char_height );
- return(0);
- }
-
+ {
+ unsigned xpos = LOWORD(lParam); /* From left */
+ unsigned ypos = HIWORD(lParam); /* from top */
+
+ set_position( xpos/char_width, ypos/char_height );
+ return(0);
+ }
+
case WM_COMMAND:
- id = LOWORD(wParam);
- if (id & EDIT_CMD_FLAG) {
+ id = LOWORD(wParam);
+ if (id & EDIT_CMD_FLAG) {
if (id & REPEAT_FLAG) do_command(REPEAT);
do_command(CHAR_CMD(id));
return( 0 );
@@ -249,17 +278,17 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
case IDM_HELPABOUT:
if( DialogBox( hInstance, "ABOUTBOX",
- hwnd, lpfnAboutBox ) )
+ hwnd, AboutBoxCallback ) )
InvalidateRect( hwnd, NULL, TRUE );
return( 0 );
- case IDM_HELPCONTENTS:
- de_error(
- "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n"
- "Undo: ^U Write: ^W Quit:^D Repeat count: ^R[n]\n"
- "Top: ^T Locate (search, find): ^L text ^L\n");
- return( 0 );
- }
- }
+ case IDM_HELPCONTENTS:
+ de_error(
+ "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n"
+ "Undo: ^U Write: ^W Quit:^D Repeat count: ^R[n]\n"
+ "Top: ^T Locate (search, find): ^L text ^L\n");
+ return( 0 );
+ }
+ }
break;
case WM_CLOSE:
@@ -268,44 +297,45 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
case WM_DESTROY:
PostQuitMessage (0);
- GC_win32_free_heap();
+ GC_win32_free_heap();
return 0;
-
+
case WM_PAINT:
- dc = BeginPaint(hwnd, &ps);
- GetClientRect(hwnd, &client_area);
- COLS = (client_area.right - client_area.left)/char_width;
- LINES = (client_area.bottom - client_area.top)/char_height;
- SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
- for (i = 0; i < LINES; i++) {
- get_line_rect(i, client_area.right, &this_line);
- if (IntersectRect(&dummy, &this_line, &ps.rcPaint)) {
- CORD raw_line = retrieve_screen_line(i);
- size_t len = CORD_len(raw_line);
- char * text = CORD_to_char_star(raw_line);
- /* May contain embedded NULLs */
- char * plain = plain_chars(text, len);
- char * blanks = CORD_to_char_star(CORD_chars(' ',
- COLS - len));
- char * control = control_chars(text, len);
-# define RED RGB(255,0,0)
-
- SetBkMode(dc, OPAQUE);
- SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
-
- TextOut(dc, this_line.left, this_line.top,
- plain, len);
- TextOut(dc, this_line.left + len * char_width, this_line.top,
- blanks, COLS - len);
- SetBkMode(dc, TRANSPARENT);
- SetTextColor(dc, RED);
- TextOut(dc, this_line.left, this_line.top,
- control, strlen(control));
- }
- }
- EndPaint(hwnd, &ps);
- screen_was_painted = 1;
- return 0;
+ dc = BeginPaint(hwnd, &ps);
+ GetClientRect(hwnd, &client_area);
+ COLS = (client_area.right - client_area.left)/char_width;
+ LINES = (client_area.bottom - client_area.top)/char_height;
+ SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
+ for (i = 0; i < LINES; i++) {
+ get_line_rect(i, client_area.right, &this_line);
+ if (IntersectRect(&dummy, &this_line, &ps.rcPaint)) {
+ CORD raw_line = retrieve_screen_line(i);
+ size_t len = CORD_len(raw_line);
+ char * text = CORD_to_char_star(raw_line);
+ /* May contain embedded NULLs */
+ char * plain = plain_chars(text, len);
+ char * blanks = CORD_to_char_star(CORD_chars(' ',
+ COLS - len));
+ char * control = control_chars(text, len);
+# define RED RGB(255,0,0)
+
+ SetBkMode(dc, OPAQUE);
+ SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
+
+ TextOut(dc, this_line.left, this_line.top,
+ plain, (int)len);
+ TextOut(dc, this_line.left + (int)len * char_width,
+ this_line.top,
+ blanks, (int)(COLS - len));
+ SetBkMode(dc, TRANSPARENT);
+ SetTextColor(dc, RED);
+ TextOut(dc, this_line.left, this_line.top,
+ control, (int)strlen(control));
+ }
+ }
+ EndPaint(hwnd, &ps);
+ screen_was_painted = 1;
+ return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
@@ -317,7 +347,7 @@ void move_cursor(int c, int l)
{
last_col = c;
last_line = l;
-
+
if (caret_visible) update_cursor();
}
@@ -330,37 +360,10 @@ void update_cursor(void)
void invalidate_line(int i)
{
RECT line;
-
+
if (!screen_was_painted) return;
- /* Invalidating a rectangle before painting seems result in a */
- /* major performance problem. */
+ /* Invalidating a rectangle before painting seems result in a */
+ /* major performance problem. */
get_line_rect(i, COLS*char_width, &line);
InvalidateRect(hwnd, &line, FALSE);
}
-
-LRESULT CALLBACK AboutBox( HWND hDlg, UINT message,
- WPARAM wParam, LPARAM lParam )
-{
- switch( message )
- {
- case WM_INITDIALOG:
- SetFocus( GetDlgItem( hDlg, IDOK ) );
- break;
-
- case WM_COMMAND:
- switch( wParam )
- {
- case IDOK:
- EndDialog( hDlg, TRUE );
- break;
- }
- break;
-
- case WM_CLOSE:
- EndDialog( hDlg, TRUE );
- return TRUE;
-
- }
- return FALSE;
-}
-
diff --git a/boehm-gc/cord/tests/de_win.h b/boehm-gc/cord/tests/de_win.h
new file mode 100644
index 00000000000..a6a02f39164
--- /dev/null
+++ b/boehm-gc/cord/tests/de_win.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* cord.h, de_cmds.h, and windows.h should be included before this. */
+
+# define OTHER_FLAG 0x100
+# define EDIT_CMD_FLAG 0x200
+# define REPEAT_FLAG 0x400
+
+# define CHAR_CMD(i) ((i) & 0xff)
+
+/* MENU: DE */
+#define IDM_FILESAVE (EDIT_CMD_FLAG + WRITE)
+#define IDM_FILEEXIT (OTHER_FLAG + 1)
+#define IDM_HELPABOUT (OTHER_FLAG + 2)
+#define IDM_HELPCONTENTS (OTHER_FLAG + 3)
+
+#define IDM_EDITPDOWN (REPEAT_FLAG + EDIT_CMD_FLAG + DOWN)
+#define IDM_EDITPUP (REPEAT_FLAG + EDIT_CMD_FLAG + UP)
+#define IDM_EDITUNDO (EDIT_CMD_FLAG + UNDO)
+#define IDM_EDITLOCATE (EDIT_CMD_FLAG + LOCATE)
+#define IDM_EDITDOWN (EDIT_CMD_FLAG + DOWN)
+#define IDM_EDITUP (EDIT_CMD_FLAG + UP)
+#define IDM_EDITLEFT (EDIT_CMD_FLAG + LEFT)
+#define IDM_EDITRIGHT (EDIT_CMD_FLAG + RIGHT)
+#define IDM_EDITBS (EDIT_CMD_FLAG + BS)
+#define IDM_EDITDEL (EDIT_CMD_FLAG + DEL)
+#define IDM_EDITREPEAT (EDIT_CMD_FLAG + REPEAT)
+#define IDM_EDITTOP (EDIT_CMD_FLAG + TOP)
+
+
+
+
+/* Windows UI stuff */
+
+LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
+ UINT wParam, LONG lParam);
+
+LRESULT CALLBACK AboutBox( HWND hDlg, UINT message,
+ UINT wParam, LONG lParam );
+
+
+/* Screen dimensions. Maintained by de_win.c. */
+extern int LINES;
+extern int COLS;
+
+/* File being edited. */
+extern char * arg_file_name;
+
+/* Current display position in file. Maintained by de.c */
+extern int dis_line;
+extern int dis_col;
+
+/* Current cursor position in file. */
+extern int line;
+extern int col;
+
+/*
+ * Calls from de_win.c to de.c
+ */
+
+CORD retrieve_screen_line(int i);
+ /* Get the contents of i'th screen line. */
+ /* Relies on COLS. */
+
+void set_position(int x, int y);
+ /* Set column, row. Upper left of window = (0,0). */
+
+void do_command(int);
+ /* Execute an editor command. */
+ /* Agument is a command character or one */
+ /* of the IDM_ commands. */
+
+void generic_init(void);
+ /* OS independent initialization */
+
+
+/*
+ * Calls from de.c to de_win.c
+ */
+
+void move_cursor(int column, int line);
+ /* Physically move the cursor on the display, */
+ /* so that it appears at */
+ /* (column, line). */
+
+void invalidate_line(int line);
+ /* Invalidate line i on the screen. */
+
+void de_error(char *s);
+ /* Display error message. */
diff --git a/boehm-gc/cord/de_win.RC b/boehm-gc/cord/tests/de_win.rc
index 554a3004389..3d1c59fb10b 100644
--- a/boehm-gc/cord/de_win.RC
+++ b/boehm-gc/cord/tests/de_win.rc
@@ -7,26 +7,24 @@
* Permission is hereby granted to copy this garbage collector for any purpose,
* provided the above notices are retained on all copies.
*/
-/* Boehm, May 13, 1994 9:50 am PDT */
#include "windows.h"
#include "de_cmds.h"
#include "de_win.h"
-
ABOUTBOX DIALOG 19, 21, 163, 47
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About Demonstration Text Editor"
BEGIN
- ICON "DE", -1, 8, 8, 13, 13, WS_CHILD | WS_VISIBLE
+ /* ICON "DE", -1, 8, 8, 13, 13, WS_CHILD | WS_VISIBLE */
LTEXT "Demonstration Text Editor", -1, 44, 8, 118, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
LTEXT "Version 4.1", -1, 44, 16, 60, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
PUSHBUTTON "OK", IDOK, 118, 27, 24, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
END
-DE MENU
+DE MENU
BEGIN
POPUP "&File"
BEGIN
@@ -48,19 +46,19 @@ BEGIN
MENUITEM "Delete F&orward\tDEL", IDM_EDITDEL
MENUITEM "&Top\t^T", IDM_EDITTOP
END
-
+
POPUP "&Help"
BEGIN
MENUITEM "&Contents", IDM_HELPCONTENTS
MENUITEM "&About...", IDM_HELPABOUT
END
-
+
MENUITEM "Page_&Down", IDM_EDITPDOWN
MENUITEM "Page_&Up", IDM_EDITPUP
END
-DE ACCELERATORS
+DE ACCELERATORS
BEGIN
"^R", IDM_EDITREPEAT
"^N", IDM_EDITDOWN
@@ -74,5 +72,4 @@ BEGIN
END
-DE ICON cord\de_win.ICO
-
+/* DE ICON cord\de_win.ICO */
diff --git a/boehm-gc/darwin_stop_world.c b/boehm-gc/darwin_stop_world.c
new file mode 100644
index 00000000000..a63d64e574d
--- /dev/null
+++ b/boehm-gc/darwin_stop_world.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2010 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#include "private/pthread_support.h"
+
+/* This probably needs more porting work to ppc64. */
+
+#if defined(GC_DARWIN_THREADS)
+
+/* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
+ Page 49:
+ "The space beneath the stack pointer, where a new stack frame would normally
+ be allocated, is called the red zone. This area as shown in Figure 3-2 may
+ be used for any purpose as long as a new stack frame does not need to be
+ added to the stack."
+
+ Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
+ it must set up a stack frame just like routines that call other routines."
+*/
+#ifdef POWERPC
+# if CPP_WORDSZ == 32
+# define PPC_RED_ZONE_SIZE 224
+# elif CPP_WORDSZ == 64
+# define PPC_RED_ZONE_SIZE 320
+# endif
+#endif
+
+#ifndef DARWIN_DONT_PARSE_STACK
+
+typedef struct StackFrame {
+ unsigned long savedSP;
+ unsigned long savedCR;
+ unsigned long savedLR;
+ unsigned long reserved[2];
+ unsigned long savedRTOC;
+} StackFrame;
+
+GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
+{
+ StackFrame *frame;
+
+# ifdef POWERPC
+ if (stack_start == 0) {
+# if CPP_WORDSZ == 32
+ __asm__ __volatile__ ("lwz %0,0(r1)" : "=r" (frame));
+# else
+ __asm__ __volatile__ ("ld %0,0(r1)" : "=r" (frame));
+# endif
+ } else
+# else
+ GC_ASSERT(stack_start != 0); /* not implemented */
+# endif /* !POWERPC */
+ /* else */ {
+ frame = (StackFrame *)stack_start;
+ }
+
+# ifdef DEBUG_THREADS
+ /* GC_log_printf("FindTopOfStack start at sp = %p\n", frame); */
+# endif
+ while (frame->savedSP != 0) {
+ /* if there are no more stack frames, stop */
+
+ frame = (StackFrame*)frame->savedSP;
+
+ /* we do these next two checks after going to the next frame
+ because the LR for the first stack frame in the loop
+ is not set up on purpose, so we shouldn't check it. */
+ if ((frame->savedLR & ~0x3) == 0 || (frame->savedLR & ~0x3) == ~0x3U)
+ break; /* if the next LR is bogus, stop */
+ }
+# ifdef DEBUG_THREADS
+ /* GC_log_printf("FindTopOfStack finish at sp = %p\n", frame); */
+# endif
+ return (ptr_t)frame;
+}
+
+#endif /* !DARWIN_DONT_PARSE_STACK */
+
+/* GC_query_task_threads controls whether to obtain the list of */
+/* the threads from the kernel or to use GC_threads table. */
+#ifdef GC_NO_THREADS_DISCOVERY
+# define GC_query_task_threads FALSE
+#elif defined(GC_DISCOVER_TASK_THREADS)
+# define GC_query_task_threads TRUE
+#else
+ STATIC GC_bool GC_query_task_threads = FALSE;
+#endif /* !GC_NO_THREADS_DISCOVERY */
+
+/* Use implicit threads registration (all task threads excluding the GC */
+/* special ones are stoped and scanned). Should be called before */
+/* GC_INIT() (or, at least, before going multi-threaded). Deprecated. */
+GC_API void GC_CALL GC_use_threads_discovery(void)
+{
+# if defined(GC_NO_THREADS_DISCOVERY) || defined(DARWIN_DONT_PARSE_STACK)
+ ABORT("Darwin task-threads-based stop and push unsupported");
+# else
+ GC_ASSERT(!GC_need_to_lock);
+# ifndef GC_DISCOVER_TASK_THREADS
+ GC_query_task_threads = TRUE;
+# endif
+ GC_init_parallel(); /* just to be consistent with Win32 one */
+# endif
+}
+
+/* Evaluates the stack range for a given thread. Returns the lower */
+/* bound and sets *phi to the upper one. */
+STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
+ GC_bool thread_blocked, mach_port_t my_thread)
+{
+ ptr_t lo;
+ if (thread == my_thread) {
+ GC_ASSERT(!thread_blocked);
+ lo = GC_approx_sp();
+# ifndef DARWIN_DONT_PARSE_STACK
+ *phi = GC_FindTopOfStack(0);
+# endif
+
+ } else if (thread_blocked) {
+ lo = p->stop_info.stack_ptr;
+# ifndef DARWIN_DONT_PARSE_STACK
+ *phi = p->topOfStack;
+# endif
+
+ } else {
+ /* MACHINE_THREAD_STATE_COUNT does not seem to be defined */
+ /* everywhere. Hence we use our own version. Alternatively, */
+ /* we could use THREAD_STATE_MAX (but seems to be not optimal). */
+ kern_return_t kern_result;
+ mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT;
+ GC_THREAD_STATE_T state;
+
+ /* Get the thread state (registers, etc) */
+ kern_result = thread_get_state(thread, GC_MACH_THREAD_STATE,
+ (natural_t *)&state,
+ &thread_state_count);
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread_get_state returns value = %d\n", kern_result);
+# endif
+ if (kern_result != KERN_SUCCESS)
+ ABORT("thread_get_state failed");
+
+# if defined(I386)
+ lo = (void *)state.THREAD_FLD(esp);
+# ifndef DARWIN_DONT_PARSE_STACK
+ *phi = GC_FindTopOfStack(state.THREAD_FLD(esp));
+# endif
+ GC_push_one(state.THREAD_FLD(eax));
+ GC_push_one(state.THREAD_FLD(ebx));
+ GC_push_one(state.THREAD_FLD(ecx));
+ GC_push_one(state.THREAD_FLD(edx));
+ GC_push_one(state.THREAD_FLD(edi));
+ GC_push_one(state.THREAD_FLD(esi));
+ GC_push_one(state.THREAD_FLD(ebp));
+
+# elif defined(X86_64)
+ lo = (void *)state.THREAD_FLD(rsp);
+# ifndef DARWIN_DONT_PARSE_STACK
+ *phi = GC_FindTopOfStack(state.THREAD_FLD(rsp));
+# endif
+ GC_push_one(state.THREAD_FLD(rax));
+ GC_push_one(state.THREAD_FLD(rbx));
+ GC_push_one(state.THREAD_FLD(rcx));
+ GC_push_one(state.THREAD_FLD(rdx));
+ GC_push_one(state.THREAD_FLD(rdi));
+ GC_push_one(state.THREAD_FLD(rsi));
+ GC_push_one(state.THREAD_FLD(rbp));
+ /* GC_push_one(state.THREAD_FLD(rsp)); */
+ GC_push_one(state.THREAD_FLD(r8));
+ GC_push_one(state.THREAD_FLD(r9));
+ GC_push_one(state.THREAD_FLD(r10));
+ GC_push_one(state.THREAD_FLD(r11));
+ GC_push_one(state.THREAD_FLD(r12));
+ GC_push_one(state.THREAD_FLD(r13));
+ GC_push_one(state.THREAD_FLD(r14));
+ GC_push_one(state.THREAD_FLD(r15));
+
+# elif defined(POWERPC)
+ lo = (void *)(state.THREAD_FLD(r1) - PPC_RED_ZONE_SIZE);
+# ifndef DARWIN_DONT_PARSE_STACK
+ *phi = GC_FindTopOfStack(state.THREAD_FLD(r1));
+# endif
+ GC_push_one(state.THREAD_FLD(r0));
+ GC_push_one(state.THREAD_FLD(r2));
+ GC_push_one(state.THREAD_FLD(r3));
+ GC_push_one(state.THREAD_FLD(r4));
+ GC_push_one(state.THREAD_FLD(r5));
+ GC_push_one(state.THREAD_FLD(r6));
+ GC_push_one(state.THREAD_FLD(r7));
+ GC_push_one(state.THREAD_FLD(r8));
+ GC_push_one(state.THREAD_FLD(r9));
+ GC_push_one(state.THREAD_FLD(r10));
+ GC_push_one(state.THREAD_FLD(r11));
+ GC_push_one(state.THREAD_FLD(r12));
+ GC_push_one(state.THREAD_FLD(r13));
+ GC_push_one(state.THREAD_FLD(r14));
+ GC_push_one(state.THREAD_FLD(r15));
+ GC_push_one(state.THREAD_FLD(r16));
+ GC_push_one(state.THREAD_FLD(r17));
+ GC_push_one(state.THREAD_FLD(r18));
+ GC_push_one(state.THREAD_FLD(r19));
+ GC_push_one(state.THREAD_FLD(r20));
+ GC_push_one(state.THREAD_FLD(r21));
+ GC_push_one(state.THREAD_FLD(r22));
+ GC_push_one(state.THREAD_FLD(r23));
+ GC_push_one(state.THREAD_FLD(r24));
+ GC_push_one(state.THREAD_FLD(r25));
+ GC_push_one(state.THREAD_FLD(r26));
+ GC_push_one(state.THREAD_FLD(r27));
+ GC_push_one(state.THREAD_FLD(r28));
+ GC_push_one(state.THREAD_FLD(r29));
+ GC_push_one(state.THREAD_FLD(r30));
+ GC_push_one(state.THREAD_FLD(r31));
+
+# elif defined(ARM32)
+ lo = (void *)state.__sp;
+# ifndef DARWIN_DONT_PARSE_STACK
+ *phi = GC_FindTopOfStack(state.__sp);
+# endif
+ GC_push_one(state.__r[0]);
+ GC_push_one(state.__r[1]);
+ GC_push_one(state.__r[2]);
+ GC_push_one(state.__r[3]);
+ GC_push_one(state.__r[4]);
+ GC_push_one(state.__r[5]);
+ GC_push_one(state.__r[6]);
+ GC_push_one(state.__r[7]);
+ GC_push_one(state.__r[8]);
+ GC_push_one(state.__r[9]);
+ GC_push_one(state.__r[10]);
+ GC_push_one(state.__r[11]);
+ GC_push_one(state.__r[12]);
+ /* GC_push_one(state.__sp); */
+ GC_push_one(state.__lr);
+ /* GC_push_one(state.__pc); */
+ GC_push_one(state.__cpsr);
+
+# else
+# error FIXME for non-x86 || ppc || arm architectures
+# endif
+ } /* thread != my_thread */
+
+# ifdef DARWIN_DONT_PARSE_STACK
+ /* p is guaranteed to be non-NULL regardless of GC_query_task_threads. */
+ *phi = (p->flags & MAIN_THREAD) != 0 ? GC_stackbottom : p->stack_end;
+# endif
+# ifdef DEBUG_THREADS
+ GC_log_printf("Darwin: Stack for thread %p = [%p,%p)\n",
+ (void *)thread, lo, *phi);
+# endif
+ return lo;
+}
+
+GC_INNER void GC_push_all_stacks(void)
+{
+ int i;
+ ptr_t lo, hi;
+ task_t my_task = current_task();
+ mach_port_t my_thread = mach_thread_self();
+ GC_bool found_me = FALSE;
+ int nthreads = 0;
+ word total_size = 0;
+ mach_msg_type_number_t listcount = (mach_msg_type_number_t)THREAD_TABLE_SZ;
+ if (!EXPECT(GC_thr_initialized, TRUE))
+ GC_thr_init();
+
+# ifndef DARWIN_DONT_PARSE_STACK
+ if (GC_query_task_threads) {
+ kern_return_t kern_result;
+ thread_act_array_t act_list = 0;
+
+ /* Obtain the list of the threads from the kernel. */
+ kern_result = task_threads(my_task, &act_list, &listcount);
+ if (kern_result != KERN_SUCCESS)
+ ABORT("task_threads failed");
+
+ for (i = 0; i < (int)listcount; i++) {
+ thread_act_t thread = act_list[i];
+ lo = GC_stack_range_for(&hi, thread, NULL, FALSE, my_thread);
+ GC_ASSERT((word)lo <= (word)hi);
+ total_size += hi - lo;
+ GC_push_all_stack(lo, hi);
+ nthreads++;
+ if (thread == my_thread)
+ found_me = TRUE;
+ mach_port_deallocate(my_task, thread);
+ } /* for (i=0; ...) */
+
+ vm_deallocate(my_task, (vm_address_t)act_list,
+ sizeof(thread_t) * listcount);
+ } else
+# endif /* !DARWIN_DONT_PARSE_STACK */
+ /* else */ {
+ for (i = 0; i < (int)listcount; i++) {
+ GC_thread p;
+ for (p = GC_threads[i]; p != NULL; p = p->next)
+ if ((p->flags & FINISHED) == 0) {
+ thread_act_t thread = (thread_act_t)p->stop_info.mach_thread;
+ lo = GC_stack_range_for(&hi, thread, p, (GC_bool)p->thread_blocked,
+ my_thread);
+ GC_ASSERT((word)lo <= (word)hi);
+ total_size += hi - lo;
+ GC_push_all_stack_sections(lo, hi, p->traced_stack_sect);
+ nthreads++;
+ if (thread == my_thread)
+ found_me = TRUE;
+ }
+ } /* for (i=0; ...) */
+ }
+
+ mach_port_deallocate(my_task, my_thread);
+ GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks\n", nthreads);
+ if (!found_me && !GC_in_thread_creation)
+ ABORT("Collecting from unknown thread");
+ GC_total_stacksize = total_size;
+}
+
+#ifndef GC_NO_THREADS_DISCOVERY
+
+# ifdef MPROTECT_VDB
+ STATIC mach_port_t GC_mach_handler_thread = 0;
+ STATIC GC_bool GC_use_mach_handler_thread = FALSE;
+
+ GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread)
+ {
+ GC_mach_handler_thread = thread;
+ GC_use_mach_handler_thread = TRUE;
+ }
+# endif /* MPROTECT_VDB */
+
+# ifndef GC_MAX_MACH_THREADS
+# define GC_MAX_MACH_THREADS THREAD_TABLE_SZ
+# endif
+
+ struct GC_mach_thread {
+ thread_act_t thread;
+ GC_bool already_suspended;
+ };
+
+ struct GC_mach_thread GC_mach_threads[GC_MAX_MACH_THREADS];
+ STATIC int GC_mach_threads_count = 0;
+ /* FIXME: it is better to implement GC_mach_threads as a hash set. */
+
+/* returns true if there's a thread in act_list that wasn't in old_list */
+STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
+ thread_act_array_t old_list,
+ int old_count, mach_port_t my_thread)
+{
+ int i;
+ int j = -1;
+ GC_bool changed = FALSE;
+
+ for (i = 0; i < count; i++) {
+ thread_act_t thread = act_list[i];
+ GC_bool found;
+ struct thread_basic_info info;
+ mach_msg_type_number_t outCount;
+ kern_return_t kern_result;
+
+ if (thread == my_thread
+# ifdef MPROTECT_VDB
+ || (GC_mach_handler_thread == thread && GC_use_mach_handler_thread)
+# endif
+ ) {
+ /* Don't add our and the handler threads. */
+ continue;
+ }
+# ifdef PARALLEL_MARK
+ if (GC_is_mach_marker(thread))
+ continue; /* ignore the parallel marker threads */
+# endif
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("Attempting to suspend thread %p\n", (void *)thread);
+# endif
+ /* find the current thread in the old list */
+ found = FALSE;
+ {
+ int last_found = j; /* remember the previous found thread index */
+
+ /* Search for the thread starting from the last found one first. */
+ while (++j < old_count)
+ if (old_list[j] == thread) {
+ found = TRUE;
+ break;
+ }
+ if (!found) {
+ /* If not found, search in the rest (beginning) of the list. */
+ for (j = 0; j < last_found; j++)
+ if (old_list[j] == thread) {
+ found = TRUE;
+ break;
+ }
+
+ if (!found) {
+ /* add it to the GC_mach_threads list */
+ if (GC_mach_threads_count == GC_MAX_MACH_THREADS)
+ ABORT("Too many threads");
+ GC_mach_threads[GC_mach_threads_count].thread = thread;
+ /* default is not suspended */
+ GC_mach_threads[GC_mach_threads_count].already_suspended = FALSE;
+ changed = TRUE;
+ }
+ }
+ }
+
+ outCount = THREAD_INFO_MAX;
+ kern_result = thread_info(thread, THREAD_BASIC_INFO,
+ (thread_info_t)&info, &outCount);
+ if (kern_result != KERN_SUCCESS) {
+ /* The thread may have quit since the thread_threads() call we */
+ /* mark already suspended so it's not dealt with anymore later. */
+ if (!found)
+ GC_mach_threads[GC_mach_threads_count++].already_suspended = TRUE;
+ continue;
+ }
+# ifdef DEBUG_THREADS
+ GC_log_printf("Thread state for %p = %d\n", (void *)thread, info.run_state);
+# endif
+ if (info.suspend_count != 0) {
+ /* thread is already suspended. */
+ if (!found)
+ GC_mach_threads[GC_mach_threads_count++].already_suspended = TRUE;
+ continue;
+ }
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("Suspending %p\n", (void *)thread);
+# endif
+ kern_result = thread_suspend(thread);
+ if (kern_result != KERN_SUCCESS) {
+ /* The thread may have quit since the thread_threads() call we */
+ /* mark already suspended so it's not dealt with anymore later. */
+ if (!found)
+ GC_mach_threads[GC_mach_threads_count++].already_suspended = TRUE;
+ continue;
+ }
+ if (!found)
+ GC_mach_threads_count++;
+ }
+ return changed;
+}
+
+#endif /* !GC_NO_THREADS_DISCOVERY */
+
+/* Caller holds allocation lock. */
+GC_INNER void GC_stop_world(void)
+{
+ unsigned i;
+ task_t my_task = current_task();
+ mach_port_t my_thread = mach_thread_self();
+ kern_return_t kern_result;
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("Stopping the world from thread %p\n", (void *)my_thread);
+# endif
+# ifdef PARALLEL_MARK
+ if (GC_parallel) {
+ /* Make sure all free list construction has stopped before we */
+ /* start. No new construction can start, since free list */
+ /* construction is required to acquire and release the GC lock */
+ /* before it starts, and we have the lock. */
+ GC_acquire_mark_lock();
+ GC_ASSERT(GC_fl_builder_count == 0);
+ /* We should have previously waited for it to become zero. */
+ }
+# endif /* PARALLEL_MARK */
+
+ if (GC_query_task_threads) {
+# ifndef GC_NO_THREADS_DISCOVERY
+ GC_bool changed;
+ thread_act_array_t act_list, prev_list;
+ mach_msg_type_number_t listcount, prevcount;
+
+ /* Clear out the mach threads list table. We do not need to */
+ /* really clear GC_mach_threads[] as it is used only in the range */
+ /* from 0 to GC_mach_threads_count-1, inclusive. */
+ GC_mach_threads_count = 0;
+
+ /* Loop stopping threads until you have gone over the whole list */
+ /* twice without a new one appearing. thread_create() won't */
+ /* return (and thus the thread stop) until the new thread exists, */
+ /* so there is no window whereby you could stop a thread, */
+ /* recognize it is stopped, but then have a new thread it created */
+ /* before stopping show up later. */
+ changed = TRUE;
+ prev_list = NULL;
+ prevcount = 0;
+ do {
+ kern_result = task_threads(my_task, &act_list, &listcount);
+
+ if (kern_result == KERN_SUCCESS) {
+ changed = GC_suspend_thread_list(act_list, listcount, prev_list,
+ prevcount, my_thread);
+
+ if (prev_list != NULL) {
+ for (i = 0; i < prevcount; i++)
+ mach_port_deallocate(my_task, prev_list[i]);
+
+ vm_deallocate(my_task, (vm_address_t)prev_list,
+ sizeof(thread_t) * prevcount);
+ }
+
+ /* Repeat while having changes. */
+ prev_list = act_list;
+ prevcount = listcount;
+ }
+ } while (changed);
+
+ GC_ASSERT(prev_list != 0);
+ for (i = 0; i < prevcount; i++)
+ mach_port_deallocate(my_task, prev_list[i]);
+ vm_deallocate(my_task, (vm_address_t)act_list,
+ sizeof(thread_t) * listcount);
+# endif /* !GC_NO_THREADS_DISCOVERY */
+
+ } else {
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ GC_thread p;
+
+ for (p = GC_threads[i]; p != NULL; p = p->next) {
+ if ((p->flags & FINISHED) == 0 && !p->thread_blocked &&
+ p->stop_info.mach_thread != my_thread) {
+
+ kern_result = thread_suspend(p->stop_info.mach_thread);
+ if (kern_result != KERN_SUCCESS)
+ ABORT("thread_suspend failed");
+ }
+ }
+ }
+ }
+
+# ifdef MPROTECT_VDB
+ if(GC_incremental) {
+ GC_mprotect_stop();
+ }
+# endif
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_release_mark_lock();
+# endif
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("World stopped from %p\n", (void *)my_thread);
+# endif
+ mach_port_deallocate(my_task, my_thread);
+}
+
+GC_INLINE void GC_thread_resume(thread_act_t thread)
+{
+ kern_return_t kern_result;
+# if defined(DEBUG_THREADS) || defined(GC_ASSERTIONS)
+ struct thread_basic_info info;
+ mach_msg_type_number_t outCount = THREAD_INFO_MAX;
+ kern_result = thread_info(thread, THREAD_BASIC_INFO,
+ (thread_info_t)&info, &outCount);
+ if (kern_result != KERN_SUCCESS)
+ ABORT("thread_info failed");
+# endif
+# ifdef DEBUG_THREADS
+ GC_log_printf("Resuming thread %p with state %d\n", (void *)thread,
+ info.run_state);
+# endif
+ /* Resume the thread */
+ kern_result = thread_resume(thread);
+ if (kern_result != KERN_SUCCESS)
+ ABORT("thread_resume failed");
+}
+
+/* Caller holds allocation lock, and has held it continuously since */
+/* the world stopped. */
+GC_INNER void GC_start_world(void)
+{
+ task_t my_task = current_task();
+ int i;
+# ifdef DEBUG_THREADS
+ GC_log_printf("World starting\n");
+# endif
+# ifdef MPROTECT_VDB
+ if(GC_incremental) {
+ GC_mprotect_resume();
+ }
+# endif
+
+ if (GC_query_task_threads) {
+# ifndef GC_NO_THREADS_DISCOVERY
+ int j = GC_mach_threads_count;
+ kern_return_t kern_result;
+ thread_act_array_t act_list;
+ mach_msg_type_number_t listcount;
+
+ kern_result = task_threads(my_task, &act_list, &listcount);
+ if (kern_result != KERN_SUCCESS)
+ ABORT("task_threads failed");
+
+ for (i = 0; i < (int)listcount; i++) {
+ thread_act_t thread = act_list[i];
+ int last_found = j; /* The thread index found during the */
+ /* previous iteration (count value */
+ /* means no thread found yet). */
+
+ /* Search for the thread starting from the last found one first. */
+ while (++j < GC_mach_threads_count) {
+ if (GC_mach_threads[j].thread == thread)
+ break;
+ }
+ if (j >= GC_mach_threads_count) {
+ /* If not found, search in the rest (beginning) of the list. */
+ for (j = 0; j < last_found; j++) {
+ if (GC_mach_threads[j].thread == thread)
+ break;
+ }
+ }
+
+ if (j != last_found) {
+ /* The thread is found in GC_mach_threads. */
+ if (GC_mach_threads[j].already_suspended) {
+# ifdef DEBUG_THREADS
+ GC_log_printf("Not resuming already suspended thread %p\n",
+ (void *)thread);
+# endif
+ } else {
+ GC_thread_resume(thread);
+ }
+ }
+
+ mach_port_deallocate(my_task, thread);
+ }
+ vm_deallocate(my_task, (vm_address_t)act_list,
+ sizeof(thread_t) * listcount);
+# endif /* !GC_NO_THREADS_DISCOVERY */
+
+ } else {
+ mach_port_t my_thread = mach_thread_self();
+
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ GC_thread p;
+ for (p = GC_threads[i]; p != NULL; p = p->next) {
+ if ((p->flags & FINISHED) == 0 && !p->thread_blocked &&
+ p->stop_info.mach_thread != my_thread)
+ GC_thread_resume(p->stop_info.mach_thread);
+ }
+ }
+
+ mach_port_deallocate(my_task, my_thread);
+ }
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("World started\n");
+# endif
+}
+
+#endif /* GC_DARWIN_THREADS */
diff --git a/boehm-gc/dbg_mlc.c b/boehm-gc/dbg_mlc.c
index aacbb7a1b63..9422b71f2f3 100644
--- a/boehm-gc/dbg_mlc.c
+++ b/boehm-gc/dbg_mlc.c
@@ -1,8 +1,9 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
* Copyright (c) 1997 by Silicon Graphics. All rights reserved.
* Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2007 Free Software Foundation, Inc
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -16,50 +17,48 @@
#include "private/dbg_mlc.h"
-void GC_default_print_heap_obj_proc();
-GC_API void GC_register_finalizer_no_order
- GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
- GC_finalization_proc *ofn, GC_PTR *ocd));
-
+#ifndef MSWINCE
+# include <errno.h>
+#endif
+#include <string.h>
#ifndef SHORT_DBG_HDRS
-/* Check whether object with base pointer p has debugging info */
-/* p is assumed to point to a legitimate object in our part */
-/* of the heap. */
-/* This excludes the check as to whether the back pointer is */
-/* odd, which is added by the GC_HAS_DEBUG_INFO macro. */
-/* Note that if DBG_HDRS_ALL is set, uncollectable objects */
-/* on free lists may not have debug information set. Thus it's */
-/* not always safe to return TRUE, even if the client does */
-/* its part. */
-GC_bool GC_has_other_debug_info(p)
-ptr_t p;
-{
- register oh * ohdr = (oh *)p;
- register ptr_t body = (ptr_t)(ohdr + 1);
- register word sz = GC_size((ptr_t) ohdr);
-
- if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
+ /* Check whether object with base pointer p has debugging info. */
+ /* p is assumed to point to a legitimate object in our part */
+ /* of the heap. */
+ /* This excludes the check as to whether the back pointer is */
+ /* odd, which is added by the GC_HAS_DEBUG_INFO macro. */
+ /* Note that if DBG_HDRS_ALL is set, uncollectable objects */
+ /* on free lists may not have debug information set. Thus it's */
+ /* not always safe to return TRUE (1), even if the client does */
+ /* its part. Return -1 if the object with debug info has been */
+ /* marked as deallocated. */
+ GC_INNER int GC_has_other_debug_info(ptr_t p)
+ {
+ ptr_t body = (ptr_t)((oh *)p + 1);
+ word sz = GC_size(p);
+
+ if (HBLKPTR(p) != HBLKPTR((ptr_t)body)
|| sz < DEBUG_BYTES + EXTRA_BYTES) {
- return(FALSE);
+ return 0;
}
- if (ohdr -> oh_sz == sz) {
- /* Object may have had debug info, but has been deallocated */
- return(FALSE);
+ if (((oh *)p) -> oh_sf != (START_FLAG ^ (word)body)
+ && ((word *)p)[BYTES_TO_WORDS(sz)-1] != (END_FLAG ^ (word)body)) {
+ return 0;
}
- if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
- if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
- return(TRUE);
+ if (((oh *)p)->oh_sz == sz) {
+ /* Object may have had debug info, but has been deallocated */
+ return -1;
}
- return(FALSE);
-}
-#endif
+ return 1;
+ }
+#endif /* !SHORT_DBG_HDRS */
#ifdef KEEP_BACK_PTRS
# include <stdlib.h>
-# if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
+# if defined(__GLIBC__) || defined(SOLARIS) \
|| defined(HPUX) || defined(IRIX5) || defined(OSF1)
# define RANDOM() random()
# else
@@ -67,52 +66,61 @@ ptr_t p;
# endif
/* Store back pointer to source in dest, if that appears to be possible. */
- /* This is not completely safe, since we may mistakenly conclude that */
- /* dest has a debugging wrapper. But the error probability is very */
- /* small, and this shouldn't be used in production code. */
+ /* This is not completely safe, since we may mistakenly conclude that */
+ /* dest has a debugging wrapper. But the error probability is very */
+ /* small, and this shouldn't be used in production code. */
/* We assume that dest is the real base pointer. Source will usually */
- /* be a pointer to the interior of an object. */
- void GC_store_back_pointer(ptr_t source, ptr_t dest)
+ /* be a pointer to the interior of an object. */
+ GC_INNER void GC_store_back_pointer(ptr_t source, ptr_t dest)
{
if (GC_HAS_DEBUG_INFO(dest)) {
((oh *)dest) -> oh_back_ptr = HIDE_BACK_PTR(source);
}
}
- void GC_marked_for_finalization(ptr_t dest) {
+ GC_INNER void GC_marked_for_finalization(ptr_t dest)
+ {
GC_store_back_pointer(MARKED_FOR_FINALIZATION, dest);
}
- /* Store information about the object referencing dest in *base_p */
- /* and *offset_p. */
- /* source is root ==> *base_p = address, *offset_p = 0 */
- /* source is heap object ==> *base_p != 0, *offset_p = offset */
- /* Returns 1 on success, 0 if source couldn't be determined. */
- /* Dest can be any address within a heap object. */
- GC_ref_kind GC_get_back_ptr_info(void *dest, void **base_p, size_t *offset_p)
+ /* Store information about the object referencing dest in *base_p */
+ /* and *offset_p. */
+ /* source is root ==> *base_p = address, *offset_p = 0 */
+ /* source is heap object ==> *base_p != 0, *offset_p = offset */
+ /* Returns 1 on success, 0 if source couldn't be determined. */
+ /* Dest can be any address within a heap object. */
+ GC_API GC_ref_kind GC_CALL GC_get_back_ptr_info(void *dest, void **base_p,
+ size_t *offset_p)
{
oh * hdr = (oh *)GC_base(dest);
ptr_t bp;
ptr_t bp_base;
+
+# ifdef LINT2
+ /* Explicitly instruct the code analysis tool that */
+ /* GC_get_back_ptr_info is not expected to be called with an */
+ /* incorrect "dest" value. */
+ if (!hdr) ABORT("Invalid GC_get_back_ptr_info argument");
+# endif
if (!GC_HAS_DEBUG_INFO((ptr_t) hdr)) return GC_NO_SPACE;
- bp = REVEAL_POINTER(hdr -> oh_back_ptr);
+ bp = GC_REVEAL_POINTER(hdr -> oh_back_ptr);
if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD;
if (MARKED_FROM_REGISTER == bp) return GC_REFD_FROM_REG;
if (NOT_MARKED == bp) return GC_UNREFERENCED;
# if ALIGNMENT == 1
- /* Heuristically try to fix off by 1 errors we introduced by */
- /* insisting on even addresses. */
+ /* Heuristically try to fix off by 1 errors we introduced by */
+ /* insisting on even addresses. */
{
- ptr_t alternate_ptr = bp + 1;
- ptr_t target = *(ptr_t *)bp;
- ptr_t alternate_target = *(ptr_t *)alternate_ptr;
-
- if (alternate_target >= GC_least_plausible_heap_addr
- && alternate_target <= GC_greatest_plausible_heap_addr
- && (target < GC_least_plausible_heap_addr
- || target > GC_greatest_plausible_heap_addr)) {
- bp = alternate_ptr;
- }
+ ptr_t alternate_ptr = bp + 1;
+ ptr_t target = *(ptr_t *)bp;
+ ptr_t alternate_target = *(ptr_t *)alternate_ptr;
+
+ if ((word)alternate_target >= (word)GC_least_plausible_heap_addr
+ && (word)alternate_target <= (word)GC_greatest_plausible_heap_addr
+ && ((word)target < (word)GC_least_plausible_heap_addr
+ || (word)target > (word)GC_greatest_plausible_heap_addr)) {
+ bp = alternate_ptr;
+ }
}
# endif
bp_base = GC_base(bp);
@@ -128,50 +136,51 @@ ptr_t p;
}
}
- /* Generate a random heap address. */
- /* The resulting address is in the heap, but */
- /* not necessarily inside a valid object. */
- void *GC_generate_random_heap_address(void)
+ /* Generate a random heap address. */
+ /* The resulting address is in the heap, but */
+ /* not necessarily inside a valid object. */
+ GC_API void * GC_CALL GC_generate_random_heap_address(void)
{
- int i;
- long heap_offset = RANDOM();
+ size_t i;
+ size_t size;
+ word heap_offset = RANDOM();
+
if (GC_heapsize > RAND_MAX) {
- heap_offset *= RAND_MAX;
- heap_offset += RANDOM();
+ heap_offset *= RAND_MAX;
+ heap_offset += RANDOM();
}
heap_offset %= GC_heapsize;
- /* This doesn't yield a uniform distribution, especially if */
- /* e.g. RAND_MAX = 1.5* GC_heapsize. But for typical cases, */
- /* it's not too bad. */
- for (i = 0; i < GC_n_heap_sects; ++ i) {
- int size = GC_heap_sects[i].hs_bytes;
- if (heap_offset < size) {
- return GC_heap_sects[i].hs_start + heap_offset;
- } else {
- heap_offset -= size;
- }
- }
- ABORT("GC_generate_random_heap_address: size inconsistency");
- /*NOTREACHED*/
- return 0;
+ /* This doesn't yield a uniform distribution, especially if */
+ /* e.g. RAND_MAX = 1.5* GC_heapsize. But for typical cases, */
+ /* it's not too bad. */
+ for (i = 0;; ++i) {
+ if (i >= GC_n_heap_sects)
+ ABORT("GC_generate_random_heap_address: size inconsistency");
+
+ size = GC_heap_sects[i].hs_bytes;
+ if (heap_offset < size) {
+ break;
+ } else {
+ heap_offset -= size;
+ }
+ }
+ return GC_heap_sects[i].hs_start + heap_offset;
}
/* Generate a random address inside a valid marked heap object. */
- void *GC_generate_random_valid_address(void)
+ GC_API void * GC_CALL GC_generate_random_valid_address(void)
{
ptr_t result;
ptr_t base;
- for (;;) {
- result = GC_generate_random_heap_address();
- base = GC_base(result);
- if (0 == base) continue;
- if (!GC_is_marked(base)) continue;
- return result;
- }
+ do {
+ result = GC_generate_random_heap_address();
+ base = GC_base(result);
+ } while (base == 0 || !GC_is_marked(base));
+ return result;
}
/* Print back trace for p */
- void GC_print_backtrace(void *p)
+ GC_API void GC_CALL GC_print_backtrace(void *p)
{
void *current = p;
int i;
@@ -180,76 +189,74 @@ ptr_t p;
void *base;
GC_print_heap_obj(GC_base(current));
- GC_err_printf0("\n");
+
for (i = 0; ; ++i) {
source = GC_get_back_ptr_info(current, &base, &offset);
if (GC_UNREFERENCED == source) {
- GC_err_printf0("Reference could not be found\n");
- goto out;
+ GC_err_printf("Reference could not be found\n");
+ goto out;
}
if (GC_NO_SPACE == source) {
- GC_err_printf0("No debug info in object: Can't find reference\n");
- goto out;
+ GC_err_printf("No debug info in object: Can't find reference\n");
+ goto out;
}
- GC_err_printf1("Reachable via %d levels of pointers from ",
- (unsigned long)i);
+ GC_err_printf("Reachable via %d levels of pointers from ", i);
switch(source) {
- case GC_REFD_FROM_ROOT:
- GC_err_printf1("root at 0x%lx\n\n", (unsigned long)base);
- goto out;
- case GC_REFD_FROM_REG:
- GC_err_printf0("root in register\n\n");
- goto out;
- case GC_FINALIZER_REFD:
- GC_err_printf0("list of finalizable objects\n\n");
- goto out;
- case GC_REFD_FROM_HEAP:
- GC_err_printf1("offset %ld in object:\n", (unsigned long)offset);
- /* Take GC_base(base) to get real base, i.e. header. */
- GC_print_heap_obj(GC_base(base));
- GC_err_printf0("\n");
- break;
+ case GC_REFD_FROM_ROOT:
+ GC_err_printf("root at %p\n\n", base);
+ goto out;
+ case GC_REFD_FROM_REG:
+ GC_err_printf("root in register\n\n");
+ goto out;
+ case GC_FINALIZER_REFD:
+ GC_err_printf("list of finalizable objects\n\n");
+ goto out;
+ case GC_REFD_FROM_HEAP:
+ GC_err_printf("offset %ld in object:\n", (long)offset);
+ /* Take GC_base(base) to get real base, i.e. header. */
+ GC_print_heap_obj(GC_base(base));
+ break;
+ default:
+ GC_err_printf("INTERNAL ERROR: UNEXPECTED SOURCE!!!!\n");
+ goto out;
}
current = base;
}
out:;
}
- /* Force a garbage collection and generate a backtrace from a */
- /* random heap address. */
- void GC_generate_random_backtrace_no_gc(void)
+ /* Force a garbage collection and generate/print a backtrace */
+ /* from a random heap address. */
+ GC_INNER void GC_generate_random_backtrace_no_gc(void)
{
void * current;
current = GC_generate_random_valid_address();
- GC_printf1("\n****Chose address 0x%lx in object\n", (unsigned long)current);
+ GC_printf("\n****Chosen address %p in object\n", current);
GC_print_backtrace(current);
}
-
- void GC_generate_random_backtrace(void)
+
+ GC_API void GC_CALL GC_generate_random_backtrace(void)
{
- GC_gcollect();
+ if (GC_try_to_collect(GC_never_stop_func) == 0) {
+ GC_err_printf("Cannot generate a backtrace: "
+ "garbage collection is disabled!\n");
+ return;
+ }
GC_generate_random_backtrace_no_gc();
}
-
+
#endif /* KEEP_BACK_PTRS */
# define CROSSES_HBLK(p, sz) \
- (((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
-/* Store debugging info into p. Return displaced pointer. */
-/* Assumes we don't hold allocation lock. */
-ptr_t GC_store_debug_info(p, sz, string, integer)
-register ptr_t p; /* base pointer */
-word sz; /* bytes */
-GC_CONST char * string;
-word integer;
+ (((word)((p) + sizeof(oh) + (sz) - 1) ^ (word)(p)) >= HBLKSIZE)
+
+/* Store debugging info into p. Return displaced pointer. */
+/* This version assumes we do hold the allocation lock. */
+STATIC ptr_t GC_store_debug_info_inner(ptr_t p, word sz GC_ATTR_UNUSED,
+ const char *string, int linenum)
{
- register word * result = (word *)((oh *)p + 1);
- DCL_LOCK_STATE;
-
- /* There is some argument that we should dissble signals here. */
- /* But that's expensive. And this way things should only appear */
- /* inconsistent while we're in the handler. */
- LOCK();
+ word * result = (word *)((oh *)p + 1);
+
GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
# ifdef KEEP_BACK_PTRS
@@ -259,60 +266,36 @@ word integer;
((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
# endif
((oh *)p) -> oh_string = string;
- ((oh *)p) -> oh_int = integer;
+ ((oh *)p) -> oh_int = (word)linenum;
# ifndef SHORT_DBG_HDRS
((oh *)p) -> oh_sz = sz;
((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
# endif
- UNLOCK();
return((ptr_t)result);
}
-#ifdef DBG_HDRS_ALL
-/* Store debugging info into p. Return displaced pointer. */
-/* This version assumes we do hold the allocation lock. */
-ptr_t GC_store_debug_info_inner(p, sz, string, integer)
-register ptr_t p; /* base pointer */
-word sz; /* bytes */
-char * string;
-word integer;
+GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *string,
+ int linenum)
{
- register word * result = (word *)((oh *)p + 1);
-
- /* There is some argument that we should disable signals here. */
- /* But that's expensive. And this way things should only appear */
- /* inconsistent while we're in the handler. */
- GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
- GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
-# ifdef KEEP_BACK_PTRS
- ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
-# endif
-# ifdef MAKE_BACK_GRAPH
- ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
-# endif
- ((oh *)p) -> oh_string = string;
- ((oh *)p) -> oh_int = integer;
-# ifndef SHORT_DBG_HDRS
- ((oh *)p) -> oh_sz = sz;
- ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
- ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
- result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
-# endif
- return((ptr_t)result);
+ ptr_t result;
+ DCL_LOCK_STATE;
+
+ LOCK();
+ result = GC_store_debug_info_inner(p, sz, string, linenum);
+ UNLOCK();
+ return result;
}
-#endif
#ifndef SHORT_DBG_HDRS
-/* Check the object with debugging info at ohdr */
-/* return NIL if it's OK. Else return clobbered */
-/* address. */
-ptr_t GC_check_annotated_obj(ohdr)
-register oh * ohdr;
-{
- register ptr_t body = (ptr_t)(ohdr + 1);
- register word gc_sz = GC_size((ptr_t)ohdr);
+ /* Check the object with debugging info at ohdr. */
+ /* Return NULL if it's OK. Else return clobbered */
+ /* address. */
+ STATIC ptr_t GC_check_annotated_obj(oh *ohdr)
+ {
+ ptr_t body = (ptr_t)(ohdr + 1);
+ word gc_sz = GC_size((ptr_t)ohdr);
if (ohdr -> oh_sz + DEBUG_BYTES > gc_sz) {
return((ptr_t)(&(ohdr -> oh_sz)));
}
@@ -324,550 +307,555 @@ register oh * ohdr;
}
if (((word *)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)]
!= (END_FLAG ^ (word)body)) {
- return((ptr_t)((word *)body + SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)));
+ return((ptr_t)((word *)body + SIMPLE_ROUNDED_UP_WORDS(ohdr->oh_sz)));
}
return(0);
-}
+ }
#endif /* !SHORT_DBG_HDRS */
-static GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
+STATIC GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
-void GC_register_describe_type_fn(kind, fn)
-int kind;
-GC_describe_type_fn fn;
+GC_API void GC_CALL GC_register_describe_type_fn(int kind,
+ GC_describe_type_fn fn)
{
GC_describe_type_fns[kind] = fn;
}
-/* Print a type description for the object whose client-visible address */
-/* is p. */
-void GC_print_type(p)
-ptr_t p;
+#define GET_OH_LINENUM(ohdr) ((int)(ohdr)->oh_int)
+
+#ifndef SHORT_DBG_HDRS
+# define IF_NOT_SHORTDBG_HDRS(x) x
+# define COMMA_IFNOT_SHORTDBG_HDRS(x) /* comma */, x
+#else
+# define IF_NOT_SHORTDBG_HDRS(x) /* empty */
+# define COMMA_IFNOT_SHORTDBG_HDRS(x) /* empty */
+#endif
+
+/* Print a human-readable description of the object to stderr. */
+/* p points to somewhere inside an object with the debugging info. */
+STATIC void GC_print_obj(ptr_t p)
{
- hdr * hhdr = GC_find_header(p);
+ oh * ohdr = (oh *)GC_base(p);
+ ptr_t q;
+ hdr * hhdr;
+ int kind;
+ char *kind_str;
char buffer[GC_TYPE_DESCR_LEN + 1];
- int kind = hhdr -> hb_obj_kind;
-
- if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) {
- /* This should preclude free list objects except with */
- /* thread-local allocation. */
- buffer[GC_TYPE_DESCR_LEN] = 0;
- (GC_describe_type_fns[kind])(p, buffer);
- GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
- GC_err_puts(buffer);
+
+ GC_ASSERT(I_DONT_HOLD_LOCK());
+# ifdef LINT2
+ if (!ohdr) ABORT("Invalid GC_print_obj argument");
+# endif
+
+ q = (ptr_t)(ohdr + 1);
+ /* Print a type description for the object whose client-visible */
+ /* address is q. */
+ hhdr = GC_find_header(q);
+ kind = hhdr -> hb_obj_kind;
+ if (0 != GC_describe_type_fns[kind] && GC_is_marked(ohdr)) {
+ /* This should preclude free list objects except with */
+ /* thread-local allocation. */
+ buffer[GC_TYPE_DESCR_LEN] = 0;
+ (GC_describe_type_fns[kind])(q, buffer);
+ GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
+ kind_str = buffer;
} else {
- switch(kind) {
- case PTRFREE:
- GC_err_puts("PTRFREE");
- break;
- case NORMAL:
- GC_err_puts("NORMAL");
- break;
- case UNCOLLECTABLE:
- GC_err_puts("UNCOLLECTABLE");
- break;
-# ifdef ATOMIC_UNCOLLECTABLE
- case AUNCOLLECTABLE:
- GC_err_puts("ATOMIC UNCOLLECTABLE");
- break;
-# endif
- case STUBBORN:
- GC_err_puts("STUBBORN");
- break;
- default:
- GC_err_printf2("kind %ld, descr 0x%lx", kind, hhdr -> hb_descr);
- }
+ switch(kind) {
+ case PTRFREE:
+ kind_str = "PTRFREE";
+ break;
+ case NORMAL:
+ kind_str = "NORMAL";
+ break;
+ case UNCOLLECTABLE:
+ kind_str = "UNCOLLECTABLE";
+ break;
+# ifdef ATOMIC_UNCOLLECTABLE
+ case AUNCOLLECTABLE:
+ kind_str = "ATOMIC_UNCOLLECTABLE";
+ break;
+# endif
+ case STUBBORN:
+ kind_str = "STUBBORN";
+ break;
+ default:
+ kind_str = NULL;
+ /* The alternative is to use snprintf(buffer) but it is */
+ /* not quite portable (see vsnprintf in misc.c). */
+ }
}
-}
-
-
-void GC_print_obj(p)
-ptr_t p;
-{
- register oh * ohdr = (oh *)GC_base(p);
-
- GC_ASSERT(!I_HOLD_LOCK());
- GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
- GC_err_puts(ohdr -> oh_string);
-# ifdef SHORT_DBG_HDRS
- GC_err_printf1(":%ld, ", (unsigned long)(ohdr -> oh_int));
-# else
- GC_err_printf2(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int),
- (unsigned long)(ohdr -> oh_sz));
-# endif
- GC_print_type((ptr_t)(ohdr + 1));
- GC_err_puts(")\n");
+ if (NULL != kind_str) {
+ GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,") " %s)\n",
+ (ptr_t)ohdr + sizeof(oh),
+ ohdr->oh_string, GET_OH_LINENUM(ohdr) /*, */
+ COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
+ kind_str);
+ } else {
+ GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,")
+ " kind=%d descr=0x%lx)\n", (ptr_t)ohdr + sizeof(oh),
+ ohdr->oh_string, GET_OH_LINENUM(ohdr) /*, */
+ COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
+ kind, (unsigned long)hhdr->hb_descr);
+ }
PRINT_CALL_CHAIN(ohdr);
}
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_debug_print_heap_obj_proc(ptr_t p)
-# else
- void GC_debug_print_heap_obj_proc(p)
- ptr_t p;
-# endif
+STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
{
- GC_ASSERT(!I_HOLD_LOCK());
+ GC_ASSERT(I_DONT_HOLD_LOCK());
if (GC_HAS_DEBUG_INFO(p)) {
- GC_print_obj(p);
+ GC_print_obj(p);
} else {
- GC_default_print_heap_obj_proc(p);
+ GC_default_print_heap_obj_proc(p);
}
}
#ifndef SHORT_DBG_HDRS
-void GC_print_smashed_obj(p, clobbered_addr)
-ptr_t p, clobbered_addr;
-{
- register oh * ohdr = (oh *)GC_base(p);
-
- GC_ASSERT(!I_HOLD_LOCK());
- GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
- (unsigned long)p);
- if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
+ /* 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. */
+ STATIC void GC_print_smashed_obj(const char *msg, ptr_t p,
+ ptr_t clobbered_addr)
+ {
+ oh * ohdr = (oh *)GC_base(p);
+
+ GC_ASSERT(I_DONT_HOLD_LOCK());
+# ifdef LINT2
+ if (!ohdr) ABORT("Invalid GC_print_smashed_obj argument");
+# endif
+ if ((word)clobbered_addr <= (word)(&ohdr->oh_sz)
|| ohdr -> oh_string == 0) {
- GC_err_printf1("<smashed>, appr. sz = %ld)\n",
- (GC_size((ptr_t)ohdr) - DEBUG_BYTES));
+ GC_err_printf(
+ "%s %p in or near object at %p(<smashed>, appr. sz = %lu)\n",
+ msg, clobbered_addr, p,
+ (unsigned long)(GC_size((ptr_t)ohdr) - DEBUG_BYTES));
} else {
- if (ohdr -> oh_string[0] == '\0') {
- GC_err_puts("EMPTY(smashed?)");
- } else {
- GC_err_puts(ohdr -> oh_string);
- }
- GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
- (unsigned long)(ohdr -> oh_sz));
+ GC_err_printf("%s %p in or near object at %p (%s:%d, sz=%lu)\n",
+ msg, clobbered_addr, p,
+ (word)(ohdr -> oh_string) < HBLKSIZE ? "(smashed string)" :
+ ohdr -> oh_string[0] == '\0' ? "EMPTY(smashed?)" :
+ ohdr -> oh_string,
+ GET_OH_LINENUM(ohdr), (unsigned long)(ohdr -> oh_sz));
PRINT_CALL_CHAIN(ohdr);
}
-}
+ }
#endif
-void GC_check_heap_proc GC_PROTO((void));
-
-void GC_print_all_smashed_proc GC_PROTO((void));
+#ifndef SHORT_DBG_HDRS
+ STATIC void GC_check_heap_proc (void);
+ STATIC void GC_print_all_smashed_proc (void);
+#else
+ STATIC void GC_do_nothing(void) {}
+#endif
-void GC_do_nothing() {}
+STATIC void GC_start_debugging_inner(void)
+{
+ GC_ASSERT(I_HOLD_LOCK());
+# ifndef SHORT_DBG_HDRS
+ GC_check_heap = GC_check_heap_proc;
+ GC_print_all_smashed = GC_print_all_smashed_proc;
+# else
+ GC_check_heap = GC_do_nothing;
+ GC_print_all_smashed = GC_do_nothing;
+# endif
+ GC_print_heap_obj = GC_debug_print_heap_obj_proc;
+ GC_debugging_started = TRUE;
+ GC_register_displacement_inner((word)sizeof(oh));
+}
-void GC_start_debugging()
+GC_INNER void GC_start_debugging(void)
{
-# ifndef SHORT_DBG_HDRS
- GC_check_heap = GC_check_heap_proc;
- GC_print_all_smashed = GC_print_all_smashed_proc;
-# else
- GC_check_heap = GC_do_nothing;
- GC_print_all_smashed = GC_do_nothing;
-# endif
- GC_print_heap_obj = GC_debug_print_heap_obj_proc;
- GC_debugging_started = TRUE;
- GC_register_displacement((word)sizeof(oh));
+ DCL_LOCK_STATE;
+
+ LOCK();
+ GC_start_debugging_inner();
+ UNLOCK();
}
size_t GC_debug_header_size = sizeof(oh);
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_debug_register_displacement(GC_word offset)
-# else
- void GC_debug_register_displacement(offset)
- GC_word offset;
-# endif
+GC_API void GC_CALL GC_debug_register_displacement(size_t offset)
{
- GC_register_displacement(offset);
- GC_register_displacement((word)sizeof(oh) + offset);
+ DCL_LOCK_STATE;
+
+ LOCK();
+ GC_register_displacement_inner(offset);
+ GC_register_displacement_inner((word)sizeof(oh) + offset);
+ UNLOCK();
}
-# ifdef __STDC__
- GC_PTR GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
-# else
- GC_PTR GC_debug_malloc(lb, s, i)
- size_t lb;
- char * s;
- int i;
-# ifdef GC_ADD_CALLER
- --> GC_ADD_CALLER not implemented for K&R C
-# endif
-# endif
+GC_API void * GC_CALL GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
{
- GC_PTR result = GC_malloc(lb + DEBUG_BYTES);
-
+ void * result;
+ /* Note that according to malloc() specification, if size is 0 then */
+ /* malloc() returns either NULL, or a unique pointer value that can */
+ /* later be successfully passed to free(). We always do the latter. */
+ result = GC_malloc(lb + DEBUG_BYTES);
+
if (result == 0) {
- GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
- (unsigned long) lb);
- GC_err_puts(s);
- GC_err_printf1(":%ld)\n", (unsigned long)i);
+ GC_err_printf("GC_debug_malloc(%lu) returning NULL (%s:%d)\n",
+ (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
- GC_start_debugging();
+ GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
-# ifdef __STDC__
- GC_PTR GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
-# else
- GC_PTR GC_debug_malloc_ignore_off_page(lb, s, i)
- size_t lb;
- char * s;
- int i;
-# ifdef GC_ADD_CALLER
- --> GC_ADD_CALLER not implemented for K&R C
-# endif
-# endif
+GC_API void * GC_CALL GC_debug_malloc_ignore_off_page(size_t lb,
+ GC_EXTRA_PARAMS)
{
- GC_PTR result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
-
+ void * result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
+
if (result == 0) {
- GC_err_printf1("GC_debug_malloc_ignore_off_page(%ld) returning NIL (",
- (unsigned long) lb);
- GC_err_puts(s);
- GC_err_printf1(":%ld)\n", (unsigned long)i);
+ GC_err_printf("GC_debug_malloc_ignore_off_page(%lu)"
+ " returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
- GC_start_debugging();
+ GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
-# ifdef __STDC__
- GC_PTR GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
-# else
- GC_PTR GC_debug_malloc_atomic_ignore_off_page(lb, s, i)
- size_t lb;
- char * s;
- int i;
-# ifdef GC_ADD_CALLER
- --> GC_ADD_CALLER not implemented for K&R C
-# endif
-# endif
+GC_API void * GC_CALL GC_debug_malloc_atomic_ignore_off_page(size_t lb,
+ GC_EXTRA_PARAMS)
{
- GC_PTR result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
-
+ void * result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
+
if (result == 0) {
- GC_err_printf1("GC_debug_malloc_atomic_ignore_off_page(%ld)"
- " returning NIL (", (unsigned long) lb);
- GC_err_puts(s);
- GC_err_printf1(":%ld)\n", (unsigned long)i);
+ GC_err_printf("GC_debug_malloc_atomic_ignore_off_page(%lu)"
+ " returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
- GC_start_debugging();
+ GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
-# ifdef DBG_HDRS_ALL
-/*
- * An allocation function for internal use.
- * Normally internally allocated objects do not have debug information.
- * But in this case, we need to make sure that all objects have debug
- * headers.
- * We assume debugging was started in collector initialization,
- * and we already hold the GC lock.
- */
- GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k)
+#ifdef DBG_HDRS_ALL
+ /* An allocation function for internal use. Normally internally */
+ /* allocated objects do not have debug information. But in this */
+ /* case, we need to make sure that all objects have debug headers. */
+ /* We assume debugging was started in collector initialization, and */
+ /* we already hold the GC lock. */
+ GC_INNER void * GC_debug_generic_malloc_inner(size_t lb, int k)
{
- GC_PTR result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
-
+ void * result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
+
if (result == 0) {
- GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
- (unsigned long) lb);
+ GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
+ (unsigned long) lb);
return(0);
}
+ if (!GC_debugging_started) {
+ GC_start_debugging_inner();
+ }
ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
- return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
+ return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0));
}
- GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, int k)
+ GC_INNER void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
+ int k)
{
- GC_PTR result = GC_generic_malloc_inner_ignore_off_page(
- lb + DEBUG_BYTES, k);
-
+ void * result = GC_generic_malloc_inner_ignore_off_page(
+ lb + DEBUG_BYTES, k);
+
if (result == 0) {
- GC_err_printf1("GC internal allocation (%ld bytes) returning NIL\n",
- (unsigned long) lb);
+ GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
+ (unsigned long) lb);
return(0);
}
+ if (!GC_debugging_started) {
+ GC_start_debugging_inner();
+ }
ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
- return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
+ return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0));
}
-# endif
+#endif /* DBG_HDRS_ALL */
#ifdef STUBBORN_ALLOC
-# ifdef __STDC__
- GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
-# else
- GC_PTR GC_debug_malloc_stubborn(lb, s, i)
- size_t lb;
- char * s;
- int i;
-# endif
-{
- GC_PTR result = GC_malloc_stubborn(lb + DEBUG_BYTES);
-
+ GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
+ {
+ void * result = GC_malloc_stubborn(lb + DEBUG_BYTES);
+
if (result == 0) {
- GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
- (unsigned long) lb);
- GC_err_puts(s);
- GC_err_printf1(":%ld)\n", (unsigned long)i);
+ GC_err_printf("GC_debug_malloc_stubborn(%lu)"
+ " returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
- GC_start_debugging();
+ GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
-}
+ return (GC_store_debug_info(result, (word)lb, s, i));
+ }
+
+ GC_API void GC_CALL GC_debug_change_stubborn(const void *p)
+ {
+ const void * q = GC_base_C(p);
+ hdr * hhdr;
-void GC_debug_change_stubborn(p)
-GC_PTR p;
-{
- register GC_PTR q = GC_base(p);
- register hdr * hhdr;
-
if (q == 0) {
- GC_err_printf1("Bad argument: 0x%lx to GC_debug_change_stubborn\n",
- (unsigned long) p);
+ GC_err_printf("Bad argument: %p to GC_debug_change_stubborn\n", p);
ABORT("GC_debug_change_stubborn: bad arg");
}
hhdr = HDR(q);
if (hhdr -> hb_obj_kind != STUBBORN) {
- GC_err_printf1("GC_debug_change_stubborn arg not stubborn: 0x%lx\n",
- (unsigned long) p);
+ GC_err_printf("GC_debug_change_stubborn arg not stubborn: %p\n", p);
ABORT("GC_debug_change_stubborn: arg not stubborn");
}
GC_change_stubborn(q);
-}
+ }
+
+ GC_API void GC_CALL GC_debug_end_stubborn_change(const void *p)
+ {
+ const void * q = GC_base_C(p);
+ hdr * hhdr;
-void GC_debug_end_stubborn_change(p)
-GC_PTR p;
-{
- register GC_PTR q = GC_base(p);
- register hdr * hhdr;
-
if (q == 0) {
- GC_err_printf1("Bad argument: 0x%lx to GC_debug_end_stubborn_change\n",
- (unsigned long) p);
+ GC_err_printf("Bad argument: %p to GC_debug_end_stubborn_change\n", p);
ABORT("GC_debug_end_stubborn_change: bad arg");
}
hhdr = HDR(q);
if (hhdr -> hb_obj_kind != STUBBORN) {
- GC_err_printf1("debug_end_stubborn_change arg not stubborn: 0x%lx\n",
- (unsigned long) p);
+ GC_err_printf("debug_end_stubborn_change arg not stubborn: %p\n", p);
ABORT("GC_debug_end_stubborn_change: arg not stubborn");
}
GC_end_stubborn_change(q);
-}
+ }
#else /* !STUBBORN_ALLOC */
-# ifdef __STDC__
- GC_PTR GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
-# else
- GC_PTR GC_debug_malloc_stubborn(lb, s, i)
- size_t lb;
- char * s;
- int i;
-# endif
-{
+ GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
+ {
return GC_debug_malloc(lb, OPT_RA s, i);
-}
-
-void GC_debug_change_stubborn(p)
-GC_PTR p;
-{
-}
+ }
-void GC_debug_end_stubborn_change(p)
-GC_PTR p;
-{
-}
+ GC_API void GC_CALL GC_debug_change_stubborn(
+ const void * p GC_ATTR_UNUSED) {}
+ GC_API void GC_CALL GC_debug_end_stubborn_change(
+ const void * p GC_ATTR_UNUSED) {}
#endif /* !STUBBORN_ALLOC */
-# ifdef __STDC__
- GC_PTR GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
-# else
- GC_PTR GC_debug_malloc_atomic(lb, s, i)
- size_t lb;
- char * s;
- int i;
-# endif
+GC_API void * GC_CALL GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
{
- GC_PTR result = GC_malloc_atomic(lb + DEBUG_BYTES);
-
+ void * result = GC_malloc_atomic(lb + DEBUG_BYTES);
+
if (result == 0) {
- GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
- (unsigned long) lb);
- GC_err_puts(s);
- GC_err_printf1(":%ld)\n", (unsigned long)i);
+ GC_err_printf("GC_debug_malloc_atomic(%lu) returning NULL (%s:%d)\n",
+ (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
-# ifdef __STDC__
- GC_PTR GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS)
-# else
- GC_PTR GC_debug_malloc_uncollectable(lb, s, i)
- size_t lb;
- char * s;
- int i;
-# endif
+GC_API char * GC_CALL GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
+{
+ char *copy;
+ size_t lb;
+ if (str == NULL) {
+ if (GC_find_leak)
+ GC_err_printf("strdup(NULL) behavior is undefined\n");
+ return NULL;
+ }
+
+ lb = strlen(str) + 1;
+ copy = GC_debug_malloc_atomic(lb, OPT_RA s, i);
+ if (copy == NULL) {
+# ifndef MSWINCE
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+ BCOPY(str, copy, lb);
+ return copy;
+}
+
+GC_API char * GC_CALL GC_debug_strndup(const char *str, size_t size,
+ GC_EXTRA_PARAMS)
{
- GC_PTR result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
-
+ char *copy;
+ size_t len = strlen(str); /* str is expected to be non-NULL */
+ if (len > size)
+ len = size;
+ copy = GC_debug_malloc_atomic(len + 1, OPT_RA s, i);
+ if (copy == NULL) {
+# ifndef MSWINCE
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+ BCOPY(str, copy, len);
+ copy[len] = '\0';
+ return copy;
+}
+
+#ifdef GC_REQUIRE_WCSDUP
+# include <wchar.h> /* for wcslen() */
+
+ GC_API wchar_t * GC_CALL GC_debug_wcsdup(const wchar_t *str, GC_EXTRA_PARAMS)
+ {
+ size_t lb = (wcslen(str) + 1) * sizeof(wchar_t);
+ wchar_t *copy = GC_debug_malloc_atomic(lb, OPT_RA s, i);
+ if (copy == NULL) {
+# ifndef MSWINCE
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+ BCOPY(str, copy, lb);
+ return copy;
+ }
+#endif /* GC_REQUIRE_WCSDUP */
+
+GC_API void * GC_CALL GC_debug_malloc_uncollectable(size_t lb,
+ GC_EXTRA_PARAMS)
+{
+ void * result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
+
if (result == 0) {
- GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
- (unsigned long) lb);
- GC_err_puts(s);
- GC_err_printf1(":%ld)\n", (unsigned long)i);
+ GC_err_printf("GC_debug_malloc_uncollectable(%lu)"
+ " returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
#ifdef ATOMIC_UNCOLLECTABLE
-# ifdef __STDC__
- GC_PTR GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
-# else
- GC_PTR GC_debug_malloc_atomic_uncollectable(lb, s, i)
- size_t lb;
- char * s;
- int i;
-# endif
-{
- GC_PTR result =
- GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
-
+ GC_API void * GC_CALL GC_debug_malloc_atomic_uncollectable(size_t lb,
+ GC_EXTRA_PARAMS)
+ {
+ void * result =
+ GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
+
if (result == 0) {
- GC_err_printf1(
- "GC_debug_malloc_atomic_uncollectable(%ld) returning NIL (",
- (unsigned long) lb);
- GC_err_puts(s);
- GC_err_printf1(":%ld)\n", (unsigned long)i);
+ GC_err_printf("GC_debug_malloc_atomic_uncollectable(%lu)"
+ " returning NULL (%s:%d)\n", (unsigned long)lb, s, i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
-}
+ return (GC_store_debug_info(result, (word)lb, s, i));
+ }
#endif /* ATOMIC_UNCOLLECTABLE */
-# ifdef __STDC__
- void GC_debug_free(GC_PTR p)
+#ifndef GC_FREED_MEM_MARKER
+# if CPP_WORDSZ == 32
+# define GC_FREED_MEM_MARKER 0xdeadbeef
# else
- void GC_debug_free(p)
- GC_PTR p;
+# define GC_FREED_MEM_MARKER GC_WORD_C(0xEFBEADDEdeadbeef)
# endif
+#endif
+
+GC_API void GC_CALL GC_debug_free(void * p)
{
- register GC_PTR base;
- register ptr_t clobbered;
-
+ ptr_t base;
if (0 == p) return;
+
base = GC_base(p);
if (base == 0) {
- GC_err_printf1("Attempt to free invalid pointer %lx\n",
- (unsigned long)p);
- ABORT("free(invalid pointer)");
+ GC_err_printf("Attempt to free invalid pointer %p\n", p);
+ ABORT("Invalid pointer passed to free()");
}
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
- GC_err_printf1(
- "GC_debug_free called on pointer %lx wo debugging info\n",
- (unsigned long)p);
+ GC_err_printf(
+ "GC_debug_free called on pointer %p w/o debugging info\n", p);
} else {
# ifndef SHORT_DBG_HDRS
- clobbered = GC_check_annotated_obj((oh *)base);
+ ptr_t clobbered = GC_check_annotated_obj((oh *)base);
+ word sz = GC_size(base);
if (clobbered != 0) {
- if (((oh *)base) -> oh_sz == GC_size(base)) {
- GC_err_printf0(
- "GC_debug_free: found previously deallocated (?) object at ");
+ GC_have_errors = TRUE;
+ if (((oh *)base) -> oh_sz == sz) {
+ GC_print_smashed_obj(
+ "GC_debug_free: found previously deallocated (?) object at",
+ p, clobbered);
+ return; /* ignore double free */
} else {
- GC_err_printf0("GC_debug_free: found smashed location at ");
+ GC_print_smashed_obj("GC_debug_free: found smashed location at",
+ p, clobbered);
}
- GC_print_smashed_obj(p, clobbered);
}
- /* Invalidate size */
- ((oh *)base) -> oh_sz = GC_size(base);
+ /* Invalidate size (mark the object as deallocated) */
+ ((oh *)base) -> oh_sz = sz;
# endif /* SHORT_DBG_HDRS */
}
- if (GC_find_leak) {
- GC_free(base);
+ if (GC_find_leak
+# ifndef SHORT_DBG_HDRS
+ && ((ptr_t)p - (ptr_t)base != sizeof(oh) || !GC_findleak_delay_free)
+# endif
+ ) {
+ GC_free(base);
} else {
- register hdr * hhdr = HDR(p);
- GC_bool uncollectable = FALSE;
-
- if (hhdr -> hb_obj_kind == UNCOLLECTABLE) {
- uncollectable = TRUE;
- }
-# ifdef ATOMIC_UNCOLLECTABLE
- if (hhdr -> hb_obj_kind == AUNCOLLECTABLE) {
- uncollectable = TRUE;
- }
-# endif
- if (uncollectable) {
- GC_free(base);
- } else {
- size_t i;
- size_t obj_sz = hhdr -> hb_sz - BYTES_TO_WORDS(sizeof(oh));
-
- for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = 0xdeadbeef;
- GC_ASSERT((word *)p + i == (word *)base + hhdr -> hb_sz);
- }
+ hdr * hhdr = HDR(p);
+ if (hhdr -> hb_obj_kind == UNCOLLECTABLE
+# ifdef ATOMIC_UNCOLLECTABLE
+ || hhdr -> hb_obj_kind == AUNCOLLECTABLE
+# endif
+ ) {
+ GC_free(base);
+ } else {
+ size_t i;
+ size_t obj_sz = BYTES_TO_WORDS(hhdr -> hb_sz - sizeof(oh));
+
+ for (i = 0; i < obj_sz; ++i)
+ ((word *)p)[i] = GC_FREED_MEM_MARKER;
+ GC_ASSERT((word *)p + i == (word *)(base + hhdr -> hb_sz));
+ }
} /* !GC_find_leak */
}
-#ifdef THREADS
-
-extern void GC_free_inner(GC_PTR p);
-
-/* Used internally; we assume it's called correctly. */
-void GC_debug_free_inner(GC_PTR p)
-{
- GC_free_inner(GC_base(p));
-}
+#if defined(THREADS) && defined(DBG_HDRS_ALL)
+ /* Used internally; we assume it's called correctly. */
+ GC_INNER void GC_debug_free_inner(void * p)
+ {
+ ptr_t base = GC_base(p);
+ GC_ASSERT((ptr_t)p - (ptr_t)base == sizeof(oh));
+# ifdef LINT2
+ if (!base) ABORT("Invalid GC_debug_free_inner argument");
+# endif
+# ifndef SHORT_DBG_HDRS
+ /* Invalidate size */
+ ((oh *)base) -> oh_sz = GC_size(base);
+# endif
+ GC_free_inner(base);
+ }
#endif
-# ifdef __STDC__
- GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, GC_EXTRA_PARAMS)
-# else
- GC_PTR GC_debug_realloc(p, lb, s, i)
- GC_PTR p;
- size_t lb;
- char *s;
- int i;
-# endif
+GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
{
- register GC_PTR base = GC_base(p);
- register ptr_t clobbered;
- register GC_PTR result;
- register size_t copy_sz = lb;
- register size_t old_sz;
- register hdr * hhdr;
-
- if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i));
+ void * base;
+ void * result;
+ hdr * hhdr;
+ if (p == 0)
+ return(GC_debug_malloc(lb, OPT_RA s, i));
+
+ base = GC_base(p);
if (base == 0) {
- GC_err_printf1(
- "Attempt to reallocate invalid pointer %lx\n", (unsigned long)p);
- ABORT("realloc(invalid pointer)");
+ GC_err_printf("Attempt to reallocate invalid pointer %p\n", p);
+ ABORT("Invalid pointer passed to realloc()");
}
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
- GC_err_printf1(
- "GC_debug_realloc called on pointer %lx wo debugging info\n",
- (unsigned long)p);
+ GC_err_printf(
+ "GC_debug_realloc called on pointer %p w/o debugging info\n", p);
return(GC_realloc(p, lb));
}
hhdr = HDR(base);
@@ -884,177 +872,186 @@ void GC_debug_free_inner(GC_PTR p)
result = GC_debug_malloc_atomic(lb, OPT_RA s, i);
break;
case UNCOLLECTABLE:
- result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
- break;
+ result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
+ break;
# ifdef ATOMIC_UNCOLLECTABLE
case AUNCOLLECTABLE:
- result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
- break;
+ result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
+ break;
# endif
default:
- GC_err_printf0("GC_debug_realloc: encountered bad kind\n");
- ABORT("bad kind");
+ result = NULL; /* initialized to prevent warning. */
+ GC_err_printf("GC_debug_realloc: encountered bad kind\n");
+ ABORT_RET("Bad kind");
+ }
+
+ if (result != NULL) {
+ size_t old_sz;
+# ifdef SHORT_DBG_HDRS
+ old_sz = GC_size(base) - sizeof(oh);
+# else
+ old_sz = ((oh *)base) -> oh_sz;
+# endif
+ BCOPY(p, result, old_sz < lb ? old_sz : lb);
+ GC_debug_free(p);
}
-# ifdef SHORT_DBG_HDRS
- old_sz = GC_size(base) - sizeof(oh);
-# else
- clobbered = GC_check_annotated_obj((oh *)base);
- if (clobbered != 0) {
- GC_err_printf0("GC_debug_realloc: found smashed location at ");
- GC_print_smashed_obj(p, clobbered);
- }
- old_sz = ((oh *)base) -> oh_sz;
-# endif
- if (old_sz < copy_sz) copy_sz = old_sz;
- if (result == 0) return(0);
- BCOPY(p, result, copy_sz);
- GC_debug_free(p);
return(result);
}
#ifndef SHORT_DBG_HDRS
-/* List of smashed objects. We defer printing these, since we can't */
-/* always print them nicely with the allocation lock held. */
-/* We put them here instead of in GC_arrays, since it may be useful to */
-/* be able to look at them with the debugger. */
-#define MAX_SMASHED 20
-ptr_t GC_smashed[MAX_SMASHED];
-unsigned GC_n_smashed = 0;
-
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_add_smashed(ptr_t smashed)
-# else
- void GC_add_smashed(smashed)
- ptr_t smashed;
+/* List of smashed (clobbered) locations. We defer printing these, */
+/* since we can't always print them nicely with the allocation lock */
+/* held. We put them here instead of in GC_arrays, since it may be */
+/* useful to be able to look at them with the debugger. */
+#ifndef MAX_SMASHED
+# define MAX_SMASHED 20
#endif
+STATIC ptr_t GC_smashed[MAX_SMASHED] = {0};
+STATIC unsigned GC_n_smashed = 0;
+
+STATIC void GC_add_smashed(ptr_t smashed)
{
GC_ASSERT(GC_is_marked(GC_base(smashed)));
+ /* FIXME: Prevent adding an object while printing smashed list. */
GC_smashed[GC_n_smashed] = smashed;
if (GC_n_smashed < MAX_SMASHED - 1) ++GC_n_smashed;
- /* In case of overflow, we keep the first MAX_SMASHED-1 */
- /* entries plus the last one. */
+ /* In case of overflow, we keep the first MAX_SMASHED-1 */
+ /* entries plus the last one. */
GC_have_errors = TRUE;
}
-/* Print all objects on the list. Clear the list. */
-void GC_print_all_smashed_proc ()
+/* Print all objects on the list. Clear the list. */
+STATIC void GC_print_all_smashed_proc(void)
{
unsigned i;
- GC_ASSERT(!I_HOLD_LOCK());
+ GC_ASSERT(I_DONT_HOLD_LOCK());
if (GC_n_smashed == 0) return;
- GC_err_printf0("GC_check_heap_block: found smashed heap objects:\n");
+ GC_err_printf("GC_check_heap_block: found %u smashed heap objects:\n",
+ GC_n_smashed);
for (i = 0; i < GC_n_smashed; ++i) {
- GC_print_smashed_obj(GC_base(GC_smashed[i]), GC_smashed[i]);
- GC_smashed[i] = 0;
+ ptr_t base = (ptr_t)GC_base(GC_smashed[i]);
+
+# ifdef LINT2
+ if (!base) ABORT("Invalid GC_smashed element");
+# endif
+ GC_print_smashed_obj("", base + sizeof(oh), GC_smashed[i]);
+ GC_smashed[i] = 0;
}
GC_n_smashed = 0;
}
-/* Check all marked objects in the given block for validity */
-/*ARGSUSED*/
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_check_heap_block(register struct hblk *hbp, word dummy)
-# else
- void GC_check_heap_block(hbp, dummy)
- register struct hblk *hbp; /* ptr to current heap block */
- word dummy;
-# endif
+/* Check all marked objects in the given block for validity */
+/* Avoid GC_apply_to_each_object for performance reasons. */
+STATIC void GC_check_heap_block(struct hblk *hbp, word dummy GC_ATTR_UNUSED)
{
- register struct hblkhdr * hhdr = HDR(hbp);
- register word sz = hhdr -> hb_sz;
- register int word_no;
- register word *p, *plim;
-
- p = (word *)(hbp->hb_body);
- word_no = 0;
- if (sz > MAXOBJSZ) {
- plim = p;
+ struct hblkhdr * hhdr = HDR(hbp);
+ size_t sz = hhdr -> hb_sz;
+ size_t bit_no;
+ char *p, *plim;
+
+ p = hbp->hb_body;
+ if (sz > MAXOBJBYTES) {
+ plim = p;
} else {
- plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz));
+ plim = hbp->hb_body + HBLKSIZE - sz;
}
/* go through all words in block */
- while( p <= plim ) {
- if( mark_bit_from_hdr(hhdr, word_no)
- && GC_HAS_DEBUG_INFO((ptr_t)p)) {
- ptr_t clobbered = GC_check_annotated_obj((oh *)p);
-
- if (clobbered != 0) GC_add_smashed(clobbered);
- }
- word_no += sz;
- p += sz;
- }
+ for (bit_no = 0; (word)p <= (word)plim;
+ bit_no += MARK_BIT_OFFSET(sz), p += sz) {
+ if (mark_bit_from_hdr(hhdr, bit_no) && GC_HAS_DEBUG_INFO((ptr_t)p)) {
+ ptr_t clobbered = GC_check_annotated_obj((oh *)p);
+ if (clobbered != 0)
+ GC_add_smashed(clobbered);
+ }
+ }
}
+/* This assumes that all accessible objects are marked, and that */
+/* I hold the allocation lock. Normally called by collector. */
+STATIC void GC_check_heap_proc(void)
+{
+ GC_STATIC_ASSERT((sizeof(oh) & (GRANULE_BYTES - 1)) == 0);
+ /* FIXME: Should we check for twice that alignment? */
+ GC_apply_to_all_blocks(GC_check_heap_block, 0);
+}
-/* This assumes that all accessible objects are marked, and that */
-/* I hold the allocation lock. Normally called by collector. */
-void GC_check_heap_proc()
+GC_INNER GC_bool GC_check_leaked(ptr_t base)
{
-# ifndef SMALL_CONFIG
-# ifdef ALIGN_DOUBLE
- GC_STATIC_ASSERT((sizeof(oh) & (2 * sizeof(word) - 1)) == 0);
-# else
- GC_STATIC_ASSERT((sizeof(oh) & (sizeof(word) - 1)) == 0);
+ size_t i;
+ size_t obj_sz;
+ word *p;
+
+ if (
+# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
+ (*(word *)base & 1) != 0 &&
# endif
-# endif
- GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
+ GC_has_other_debug_info(base) >= 0)
+ return TRUE; /* object has leaked */
+
+ /* Validate freed object's content. */
+ p = (word *)(base + sizeof(oh));
+ obj_sz = BYTES_TO_WORDS(HDR(base)->hb_sz - sizeof(oh));
+ for (i = 0; i < obj_sz; ++i)
+ if (p[i] != GC_FREED_MEM_MARKER) {
+ GC_set_mark_bit(base); /* do not reclaim it in this cycle */
+ GC_add_smashed((ptr_t)(&p[i])); /* alter-after-free detected */
+ break; /* don't report any other smashed locations in the object */
+ }
+
+ return FALSE; /* GC_debug_free() has been called */
}
#endif /* !SHORT_DBG_HDRS */
+#ifndef GC_NO_FINALIZATION
+
struct closure {
GC_finalization_proc cl_fn;
- GC_PTR cl_data;
+ void * cl_data;
};
-# ifdef __STDC__
- void * GC_make_closure(GC_finalization_proc fn, void * data)
-# else
- GC_PTR GC_make_closure(fn, data)
- GC_finalization_proc fn;
- GC_PTR data;
-# endif
+STATIC void * GC_make_closure(GC_finalization_proc fn, void * data)
{
struct closure * result =
# ifdef DBG_HDRS_ALL
(struct closure *) GC_debug_malloc(sizeof (struct closure),
- GC_EXTRAS);
+ GC_EXTRAS);
# else
(struct closure *) GC_malloc(sizeof (struct closure));
# endif
-
- result -> cl_fn = fn;
- result -> cl_data = data;
- return((GC_PTR)result);
+ if (result != 0) {
+ result -> cl_fn = fn;
+ result -> cl_data = data;
+ }
+ return((void *)result);
}
-# ifdef __STDC__
- void GC_debug_invoke_finalizer(void * obj, void * data)
-# else
- void GC_debug_invoke_finalizer(obj, data)
- char * obj;
- char * data;
-# endif
+/* An auxiliary fns to make finalization work correctly with displaced */
+/* pointers introduced by the debugging allocators. */
+STATIC void GC_CALLBACK GC_debug_invoke_finalizer(void * obj, void * data)
{
- register struct closure * cl = (struct closure *) data;
-
- (*(cl -> cl_fn))((GC_PTR)((char *)obj + sizeof(oh)), cl -> cl_data);
-}
-
-/* Set ofn and ocd to reflect the values we got back. */
-static void store_old (obj, my_old_fn, my_old_cd, ofn, ocd)
-GC_PTR obj;
-GC_finalization_proc my_old_fn;
-struct closure * my_old_cd;
-GC_finalization_proc *ofn;
-GC_PTR *ocd;
+ struct closure * cl = (struct closure *) data;
+ (*(cl -> cl_fn))((void *)((char *)obj + sizeof(oh)), cl -> cl_data);
+}
+
+/* Special finalizer_proc value to detect GC_register_finalizer() failure. */
+#define OFN_UNSET (GC_finalization_proc)(signed_word)-1
+
+/* Set ofn and ocd to reflect the values we got back. */
+static void store_old(void *obj, GC_finalization_proc my_old_fn,
+ struct closure *my_old_cd, GC_finalization_proc *ofn,
+ void **ocd)
{
if (0 != my_old_fn) {
+ if (my_old_fn == OFN_UNSET) {
+ /* register_finalizer() failed; (*ofn) and (*ocd) are unchanged. */
+ return;
+ }
if (my_old_fn != GC_debug_invoke_finalizer) {
- GC_err_printf1("Debuggable object at 0x%lx had non-debug finalizer.\n",
- obj);
+ GC_err_printf("Debuggable object at %p had a non-debug finalizer\n",
+ obj);
/* This should probably be fatal. */
} else {
if (ofn) *ofn = my_old_cd -> cl_fn;
@@ -1066,120 +1063,130 @@ GC_PTR *ocd;
}
}
-# ifdef __STDC__
- void GC_debug_register_finalizer(GC_PTR obj, GC_finalization_proc fn,
- GC_PTR cd, GC_finalization_proc *ofn,
- GC_PTR *ocd)
-# else
- void GC_debug_register_finalizer(obj, fn, cd, ofn, ocd)
- GC_PTR obj;
- GC_finalization_proc fn;
- GC_PTR cd;
- GC_finalization_proc *ofn;
- GC_PTR *ocd;
-# endif
+GC_API void GC_CALL GC_debug_register_finalizer(void * obj,
+ GC_finalization_proc fn,
+ void * cd, GC_finalization_proc *ofn,
+ void * *ocd)
{
- GC_finalization_proc my_old_fn;
- GC_PTR my_old_cd;
+ GC_finalization_proc my_old_fn = OFN_UNSET;
+ void * my_old_cd;
ptr_t base = GC_base(obj);
- if (0 == base) return;
+ if (0 == base) {
+ /* We won't collect it, hence finalizer wouldn't be run. */
+ if (ocd) *ocd = 0;
+ if (ofn) *ofn = 0;
+ return;
+ }
if ((ptr_t)obj - base != sizeof(oh)) {
- GC_err_printf1(
- "GC_debug_register_finalizer called with non-base-pointer 0x%lx\n",
- obj);
+ GC_err_printf("GC_debug_register_finalizer called with"
+ " non-base-pointer %p\n", obj);
}
if (0 == fn) {
GC_register_finalizer(base, 0, 0, &my_old_fn, &my_old_cd);
} else {
+ cd = GC_make_closure(fn, cd);
+ if (cd == 0) return; /* out of memory */
GC_register_finalizer(base, GC_debug_invoke_finalizer,
- GC_make_closure(fn,cd), &my_old_fn, &my_old_cd);
+ cd, &my_old_fn, &my_old_cd);
}
store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
}
-# ifdef __STDC__
- void GC_debug_register_finalizer_no_order
- (GC_PTR obj, GC_finalization_proc fn,
- GC_PTR cd, GC_finalization_proc *ofn,
- GC_PTR *ocd)
-# else
- void GC_debug_register_finalizer_no_order
- (obj, fn, cd, ofn, ocd)
- GC_PTR obj;
- GC_finalization_proc fn;
- GC_PTR cd;
- GC_finalization_proc *ofn;
- GC_PTR *ocd;
-# endif
+GC_API void GC_CALL GC_debug_register_finalizer_no_order
+ (void * obj, GC_finalization_proc fn,
+ void * cd, GC_finalization_proc *ofn,
+ void * *ocd)
{
- GC_finalization_proc my_old_fn;
- GC_PTR my_old_cd;
+ GC_finalization_proc my_old_fn = OFN_UNSET;
+ void * my_old_cd;
ptr_t base = GC_base(obj);
- if (0 == base) return;
+ if (0 == base) {
+ /* We won't collect it, hence finalizer wouldn't be run. */
+ if (ocd) *ocd = 0;
+ if (ofn) *ofn = 0;
+ return;
+ }
if ((ptr_t)obj - base != sizeof(oh)) {
- GC_err_printf1(
- "GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
- obj);
+ GC_err_printf("GC_debug_register_finalizer_no_order called with"
+ " non-base-pointer %p\n", obj);
}
if (0 == fn) {
GC_register_finalizer_no_order(base, 0, 0, &my_old_fn, &my_old_cd);
} else {
+ cd = GC_make_closure(fn, cd);
+ if (cd == 0) return; /* out of memory */
GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
- GC_make_closure(fn,cd), &my_old_fn,
- &my_old_cd);
+ cd, &my_old_fn, &my_old_cd);
}
store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
- }
+}
-# ifdef __STDC__
- void GC_debug_register_finalizer_ignore_self
- (GC_PTR obj, GC_finalization_proc fn,
- GC_PTR cd, GC_finalization_proc *ofn,
- GC_PTR *ocd)
-# else
- void GC_debug_register_finalizer_ignore_self
- (obj, fn, cd, ofn, ocd)
- GC_PTR obj;
- GC_finalization_proc fn;
- GC_PTR cd;
- GC_finalization_proc *ofn;
- GC_PTR *ocd;
-# endif
+GC_API void GC_CALL GC_debug_register_finalizer_unreachable
+ (void * obj, GC_finalization_proc fn,
+ void * cd, GC_finalization_proc *ofn,
+ void * *ocd)
+{
+ GC_finalization_proc my_old_fn = OFN_UNSET;
+ void * my_old_cd;
+ ptr_t base = GC_base(obj);
+ if (0 == base) {
+ /* We won't collect it, hence finalizer wouldn't be run. */
+ if (ocd) *ocd = 0;
+ if (ofn) *ofn = 0;
+ return;
+ }
+ if ((ptr_t)obj - base != sizeof(oh)) {
+ GC_err_printf("GC_debug_register_finalizer_unreachable called with"
+ " non-base-pointer %p\n", obj);
+ }
+ if (0 == fn) {
+ GC_register_finalizer_unreachable(base, 0, 0, &my_old_fn, &my_old_cd);
+ } else {
+ cd = GC_make_closure(fn, cd);
+ if (cd == 0) return; /* out of memory */
+ GC_register_finalizer_unreachable(base, GC_debug_invoke_finalizer,
+ cd, &my_old_fn, &my_old_cd);
+ }
+ store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
+}
+
+GC_API void GC_CALL GC_debug_register_finalizer_ignore_self
+ (void * obj, GC_finalization_proc fn,
+ void * cd, GC_finalization_proc *ofn,
+ void * *ocd)
{
- GC_finalization_proc my_old_fn;
- GC_PTR my_old_cd;
+ GC_finalization_proc my_old_fn = OFN_UNSET;
+ void * my_old_cd;
ptr_t base = GC_base(obj);
- if (0 == base) return;
+ if (0 == base) {
+ /* We won't collect it, hence finalizer wouldn't be run. */
+ if (ocd) *ocd = 0;
+ if (ofn) *ofn = 0;
+ return;
+ }
if ((ptr_t)obj - base != sizeof(oh)) {
- GC_err_printf1(
- "GC_debug_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
- obj);
+ GC_err_printf("GC_debug_register_finalizer_ignore_self called with"
+ " non-base-pointer %p\n", obj);
}
if (0 == fn) {
GC_register_finalizer_ignore_self(base, 0, 0, &my_old_fn, &my_old_cd);
} else {
+ cd = GC_make_closure(fn, cd);
+ if (cd == 0) return; /* out of memory */
GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer,
- GC_make_closure(fn,cd), &my_old_fn,
- &my_old_cd);
+ cd, &my_old_fn, &my_old_cd);
}
store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
}
-#ifdef GC_ADD_CALLER
-# define RA GC_RETURN_ADDR,
-#else
-# define RA
-#endif
+#endif /* !GC_NO_FINALIZATION */
-GC_PTR GC_debug_malloc_replacement(lb)
-size_t lb;
+GC_API void * GC_CALL GC_debug_malloc_replacement(size_t lb)
{
- return GC_debug_malloc(lb, RA "unknown", 0);
+ return GC_debug_malloc(lb, GC_DBG_RA "unknown", 0);
}
-GC_PTR GC_debug_realloc_replacement(p, lb)
-GC_PTR p;
-size_t lb;
+GC_API void * GC_CALL GC_debug_realloc_replacement(void *p, size_t lb)
{
- return GC_debug_realloc(p, lb, RA "unknown", 0);
+ return GC_debug_realloc(p, lb, GC_DBG_RA "unknown", 0);
}
diff --git a/boehm-gc/digimars.mak b/boehm-gc/digimars.mak
index 9778feee976..383df5c434c 100644
--- a/boehm-gc/digimars.mak
+++ b/boehm-gc/digimars.mak
@@ -3,7 +3,7 @@
# Written by Walter Bright
-DEFINES=-DNDEBUG -DSILENT -DGC_BUILD -D_WINDOWS -DGC_DLL -DALL_INTERIOR_POINTERS -D__STDC__ -DWIN32_THREADS
+DEFINES=-DNDEBUG -DGC_BUILD -D_WINDOWS -DGC_DLL -DALL_INTERIOR_POINTERS -DWIN32_THREADS
CFLAGS=-Iinclude $(DEFINES) -wx -g
LFLAGS=/ma/implib/co
CC=sc
@@ -20,6 +20,7 @@ OBJS= \
blacklst.obj\
checksums.obj\
dbg_mlc.obj\
+ fnlz_mlc.obj\
dyn_load.obj\
finalize.obj\
gc_cpp.obj\
@@ -61,7 +62,7 @@ gctest.exe : gc.lib tests\test.obj
sc -ogctest.exe tests\test.obj gc.lib
tests\test.obj : tests\test.c
- $(CC) -c -g -DNDEBUG -DSILENT -DGC_BUILD -D_WINDOWS -DGC_DLL \
+ $(CC) -c -g -DNDEBUG -DGC_BUILD -D_WINDOWS -DGC_DLL \
-DALL_INTERIOR_POINTERS -DWIN32_THREADS \
-Iinclude tests\test.c -otests\test.obj
@@ -72,6 +73,7 @@ checksums.obj: checksums.c
dbg_mlc.obj: dbg_mlc.c
dyn_load.obj: dyn_load.c
finalize.obj: finalize.c
+fnlz_mlc.obj: fnlz_mlc.c
gc_cpp.obj: gc_cpp.cpp
headers.obj: headers.c
mach_dep.obj: mach_dep.c
diff --git a/boehm-gc/doc/README.DGUX386 b/boehm-gc/doc/README.DGUX386
new file mode 100644
index 00000000000..0aa89bdfca0
--- /dev/null
+++ b/boehm-gc/doc/README.DGUX386
@@ -0,0 +1,45 @@
+ Garbage Collector (parallel iversion) for ix86 DG/UX Release R4.20MU07
+
+
+ *READ* the file README.QUICK.
+
+ You need the GCC-3.0.3 rev (DG/UX) compiler to build this tree.
+ This compiler has the new "dgux386" threads package implemented.
+ It also supports the switch "-pthread" needed to link correctly
+ the DG/UX's -lrte -lthread with -lgcc and the system's -lc.
+ Finally we support parralleli-mark for the SMP DG/UX machines.
+ To build the garbage collector do:
+
+ ./configure --enable-parallel-mark
+ make
+ make gctest
+
+ Before you run "gctest" you need to set your LD_LIBRARY_PATH
+ correctly so that "gctest" can find the shared library libgc.
+ Alternatively you can do a configuration
+
+ ./configure --enable-parallel-mark --disable-shared
+
+ to build only the static version of libgc.
+
+ To enable debugging messages please do:
+ 1) Add the "--enable-gc-debug" flag during configuration.
+ 2) Edit the file linux-threads.c and uncomment the line:
+
+ /* #define DEBUG_THREADS 1 */ to --->
+
+ #define DEBUG_THREADS 1
+
+ Then give "make" as usual.
+
+ In a machine with 4 CPUs (my own machine) the option parallel
+ mark (aka --enable-parallel-mark) makes a BIG difference.
+
+ Takis Psarogiannakopoulos
+
+Note (HB):
+ The integration of this patch is currently not complete.
+ The following patches against 6.1alpha3 where hard to move
+ to alpha4, and are not integrated. There may also be minor
+ problems with stylistic corrections made by me.
+[The diff for ltconfig and ltmain.sh was removed from this file on 2011-08-22]
diff --git a/boehm-gc/doc/README.Mac b/boehm-gc/doc/README.Mac
index 04f468251a1..c1bb132f460 100644
--- a/boehm-gc/doc/README.Mac
+++ b/boehm-gc/doc/README.Mac
@@ -1,3 +1,8 @@
+The contents of this file are old and pertain to pre-MacOSX versions.
+You probably really wanted README.darwin.
+
+---------------------------------------------
+
Patrick Beard's Notes for building GC v4.12 with CodeWarrior Pro 2:
----------------------------------------------------------------------------
The current build environment for the collector is CodeWarrior Pro 2.
@@ -6,8 +11,8 @@ are distributed in the file Mac_projects.sit.hqx. The project file
:Mac_projects:gc.prj builds static library versions of the collector.
:Mac_projects:gctest.prj builds the GC test suite.
-Configuring the collector is still done by editing the files
-:Mac_files:MacOS_config.h and :Mac_files:MacOS_Test_config.h.
+Configuring the collector is still done by editing the file
+:extra:Mac_files:MacOS_config.h.
Lars Farm's suggestions on building the collector:
----------------------------------------------------------------------------
@@ -34,12 +39,6 @@ provide a supported port of the GC to MacOS. It works for me. If it works
for you, great. If it doesn't, sorry, try again...;-) Still, if you find
errors, please let me know.
- mailto: lars.farm@ite.mh.se
-
- address: Lars Farm
- Krönvägen 33b
- 856 44 Sundsvall
- Sweden
Porting to MacOS is a bit more complex than it first seems. Which MacOS?
68K/PowerPC? Which compiler? Each supports both 68K and PowerPC and offer a
@@ -58,14 +57,12 @@ As for target settings the major obstacles may be:
- PPC Processor: uncheck "Store Static Data in TOC".
What you need to do:
-===================
-
1) Build the GC as a library
2) Test that the library works with 'test.c'.
3) Test that the C++ interface 'gc_cpp.cc/h' works with 'test_cpp.cc'.
-1) The Libraries:
-=================
+== 1. The Libraries ==
+
I made one project with four targets (68K/PPC tempmem or appheap). One target
will suffice if you're able to decide which one you want. I wasn't...
@@ -157,19 +154,13 @@ of every source file. I used these:
#if macintosh
#define MSL_USE_PRECOMPILED_HEADERS 0
#include <ansi_prefix.mac.h>
- #ifndef __STDC__
- #define __STDC__ 0
- #endif
// See list of #defines to configure the library in: 'MakeFile'
// see also README
- #define SILENT // no collection messages. In case
- // of trouble you might want this off
#define ALL_INTERIOR_POINTERS // follows interior pointers.
//#define DONT_ADD_BYTE_AT_END // disables the padding if defined.
//#define SMALL_CONFIG // whether to use a smaller heap.
- #define NO_SIGNALS // signals aren't real on the Macintosh.
#define ATOMIC_UNCOLLECTABLE // GC_malloc_atomic_uncollectable()
// define either or none as per personal preference
@@ -232,8 +223,7 @@ Files to build the GC libraries:
-- throw std::bad_alloc when out of memory
-- gc_cpp.cc works just fine too
-2) Test that the library works with 'test.c'.
-=============================================
+== 2. Test that the library works with 'test.c' ==
The test app is just an ordinary ANSI-C console app. Make sure settings
match the library you're testing.
@@ -251,10 +241,10 @@ prefix:
#include <ansi_prefix.mac.h>
#undef NDEBUG
-#define ALL_INTERIOR_POINTERS /* for GC_priv.h */
+#define ALL_INTERIOR_POINTERS /* for GC_priv.h */
---- ( cut here ) ----
-3) Test that the C++ interface 'gc_cpp.cc/h' works with 'test_cpp.cc'.
+== 3. Test that the C++ interface 'gc_cpp.cc/h' works with 'test_cpp.cc' ==
The test app is just an ordinary ANSI-C console app. Make sure settings match
the library you're testing.
@@ -283,8 +273,8 @@ delete if you're freeing other resources than RAM. See gc_cpp.h. You can
also keep coding as always with delete/free. That works too. If you want,
"include <gc.h> and tweak it's use a bit.
-Symantec SPM
-============
+== Symantec SPM ==
+
It has been a while since I tried the GC in SPM, but I think that the above
instructions should be sufficient to guide you through in SPM too. SPM
needs to know where the global data is. Use the files 'datastart.c' and
@@ -293,17 +283,9 @@ at the bottom of your project so that all data is surrounded. This is not
needed in Codewarrior because it provides intrinsic variables
__datastart__, __data_end__ that wraps all globals.
-Source Changes (GC 4.12a2)
-==========================
-Very few. Just one tiny in the GC, not strictly needed.
-- MacOS.c line 131 in routine GC_MacFreeTemporaryMemory()
- change # if !defined(SHARED_LIBRARY_BUILD)
- to # if !defined(SILENT) && !defined(SHARED_LIBRARY_BUILD)
- To turn off a message when the application quits (actually, I faked
- this change by #defining SHARED_LIBRARY_BUILD in a statically linked
- library for more than a year without ill effects but perhaps this is
- better).
+== Source Changes (GC 4.12a2) ==
+Very few. Just one tiny in the GC, not strictly needed.
- test_cpp.cc
made the first lines of main() look like this:
------------
@@ -330,7 +312,6 @@ Very few. Just one tiny in the GC, not strictly needed.
It worked for me, hope it works for you.
Lars Farm
- 18 July 1997
----------------------------------------------------------------------------
@@ -345,41 +326,38 @@ Configuration
To configure the collector, under both development systems, a prefix file
is used to set preprocessor directives. This file is called "MacOS_config.h".
-Also to test the collector, "MacOS_Test_config.h" is provided.
Testing
-------
To test the collector (always a good idea), build one of the gctest projects,
-gctest.¹ (Symantec C++/THINK C), mw/gctest.68K.¹, or mw/gctest.PPC.¹. The
+gctest. (Symantec C++/THINK C), mw/gctest.68K, or mw/gctest.PPC. The
test will ask you how many times to run; 1 should be sufficient.
-Building
+Building
--------
For your convenience project files for the major Macintosh development
systems are provided.
-For Symantec C++/THINK C, you must build the two projects gclib-1.¹ and
-gclib-2.¹. It has to be split up because the collector has more than 32k
+For Symantec C++/THINK C, you must build the two projects gclib-1 and
+gclib-2. It has to be split up because the collector has more than 32k
of static data and no library can have more than this in the Symantec
environment. (Future versions will probably fix this.)
-For Metrowerks C/C++ 4.5 you build gc.68K.¹/gc.PPC.¹ and the result will
+For Metrowerks C/C++ 4.5 you build gc.68K/PPC and the result will
be a library called gc.68K.lib/gc.PPC.lib.
Using
-----
-Under Symantec C++/THINK C, you can just add the gclib-1.¹ and gclib-2.¹
+Under Symantec C++/THINK C, you can just add the gclib-1 and gclib-2
projects to your own project. Under Metrowerks, you add gc.68K.lib or
gc.PPC.lib and two additional files. You add the files called datastart.c
and dataend.c to your project, bracketing all files that use the collector.
-See mw/gctest.¹ for an example.
+See mw/gctest for an example.
Include the projects/libraries you built above into your own project,
#include "gc.h", and call GC_malloc. You don't have to call GC_free.
-
Patrick C. Beard
-January 4, 1995
diff --git a/boehm-gc/doc/README.MacOSX b/boehm-gc/doc/README.MacOSX
deleted file mode 100644
index f5333d51ad6..00000000000
--- a/boehm-gc/doc/README.MacOSX
+++ /dev/null
@@ -1 +0,0 @@
-See README.darwin for the latest Darwin/MacOSX information.
diff --git a/boehm-gc/doc/README.amiga b/boehm-gc/doc/README.amiga
index 730dce3fe96..ea2a2f681b3 100644
--- a/boehm-gc/doc/README.amiga
+++ b/boehm-gc/doc/README.amiga
@@ -1,6 +1,5 @@
-===========================================================================
Kjetil S. Matheussen's notes (28-11-2000)
-===========================================================================
+
Compiles under SAS/C again. Should allso still compile under other
amiga compilers without big changes. I haven't checked if it still
works under gcc, because I don't have gcc for amiga. But I have
@@ -45,7 +44,7 @@ WHATS NEW:
no effect if this flag is set.
GC_AMIGA_GC - If gc returns NULL, do a GC_gcollect, and try again. This
- usually is a success with the standard GC configuration.
+ usually is a success with the standard GC configuration.
It is allso the most important flag to set to prevent
GC from returning chip-mem. Beware that it slows down a lot
when a program is rapidly allocating/deallocating when
@@ -133,16 +132,10 @@ BEWARE!
tested with software: Radium, http://www.stud.ifi.uio.no/~ksvalast/radium/
-
tested with hardware: MC68060
--ksvalast@ifi.uio.no
-
-
-===========================================================================
- Martin Tauchmann's notes (1-Apr-99)
-===========================================================================
+ Martin Tauchmann's notes (1-Apr-99)
Works now, also with the GNU-C compiler V2.7.2.1. <ftp://ftp.unina.it/pub/amiga/geekgadgets/amiga/m68k/snapshots/971125/amiga-bin/>
Modify the `Makefile`
@@ -183,14 +176,8 @@ TESTED WITH HARDWARE
MC68030
-CONTACT
+ Michel Schinz's notes
-Please, contact me at <martintauchmann@bigfoot.com>, when you change the
-Amiga port. <http://martintauchmann.home.pages.de>
-
-===========================================================================
- Michel Schinz's notes
-===========================================================================
WHO DID WHAT
The original Amiga port was made by Jesper Peterson. I (Michel Schinz)
@@ -228,15 +215,8 @@ In addition to Jesper's notes, I have the following to say:
is loaded in memory, whether a segment is a code or a data segment,
please let me know.
-PROBLEMS
-
-If you have any problem with this version, please contact me at
-schinz@alphanet.ch (but do *not* send long files, since we pay for
-every mail!).
-===========================================================================
- Jesper Peterson's notes
-===========================================================================
+ Jesper Peterson's notes
ADDITIONAL NOTES FOR AMIGA PORT
@@ -309,14 +289,3 @@ compares favourably with an HP9000 with similar architecture (a 325
with a 68030 I think).
-----------------------------------------------------------------------
-
-The Amiga port has been brought to you by:
-
-Jesper Peterson.
-
-jep@mtiame.mtia.oz.au (preferred, but 1 week turnaround)
-jep@orca1.vic.design.telecom.au (that's orca<one>, 1 day turnaround)
-
-At least one of these addresses should be around for a while, even
-though I don't work for either of the companies involved.
-
diff --git a/boehm-gc/doc/README.arm.cross b/boehm-gc/doc/README.arm.cross
new file mode 100644
index 00000000000..0ededbd9bb3
--- /dev/null
+++ b/boehm-gc/doc/README.arm.cross
@@ -0,0 +1,62 @@
+From: Margaret Fleck
+
+Here's the key details of what worked for me, in case anyone else needs them.
+There may well be better ways to do some of this, but ....
+ -- Margaret
+
+
+The badge4 has a StrongArm-1110 processor and a StrongArm-1111 coprocessor.
+
+Assume that the garbage collector distribution is unpacked into /home/arm/gc6.0,
+which is visible to both the ARM machine and a linux desktop (e.g. via NFS mounting).
+
+Assume that you have a file /home/arm/config.site with contents something like the
+example attached below. Notice that our local ARM toolchain lives in
+/skiff/local.
+
+Go to /home/arm/gc6.0 directory. Do
+ CONFIG_SITE=/home/arm/config.site ./configure --target=arm-linux
+--prefix=/home/arm/gc6.0
+
+On your desktop, do:
+ make
+ make install
+The main garbage collector library should now be in ../gc6.0/lib/libgc.so.
+
+To test the garbage collector, first do the following on your desktop
+ make gctest
+ ./gctest
+Then do the following on the ARM machine
+ cd .libs
+ ./lt-gctest
+
+Do not try to do "make test" (the usual way of running the test
+program). This does not work and seems to erase some of the important
+files.
+
+The gctest program claims to have succeeded. Haven't run any further tests
+with it, though I'll be doing so in the near future.
+
+-------------------------------
+# config.site for configure
+
+HOSTCC=gcc
+
+# Names of the cross-compilers
+CC=/skiff/local/bin/arm-linux-gcc
+CXX=/skiff/local/bin/arm-linux-gcc
+
+# The cross compiler specific options
+CFLAGS="-O2 -fno-exceptions"
+CXXFLAGS="-O2 -fno-exceptions"
+CPPFLAGS="-O2 -fno-exceptions"
+LDFLAGS=""
+
+# Some other programs
+AR=/skiff/local/bin/arm-linux-ar
+RANLIB=/skiff/local/bin/arm-linux-ranlib
+NM=/skiff/local/bin/arm-linux-nm
+ac_cv_path_NM=/skiff/local/bin/arm-linux-nm
+ac_cv_func_setpgrp_void=yes
+x_includes=/skiff/local/arm-linux/include/X11
+x_libraries=/skiff/local/arm-linux/lib/X11
diff --git a/boehm-gc/doc/README.autoconf b/boehm-gc/doc/README.autoconf
index 53fcf5a50b3..e89287310f0 100644
--- a/boehm-gc/doc/README.autoconf
+++ b/boehm-gc/doc/README.autoconf
@@ -1,4 +1,4 @@
-As of GC6.0alpha8, we attempt to support GNU-style builds based on automake,
+Starting from GC v6.0, we support GNU-style builds based on automake,
autoconf and libtool. This is based almost entirely on Tom Tromey's work
with gcj.
@@ -35,9 +35,9 @@ The distribution should contain all files needed to run "configure" and "make",
as well as the sources needed to regenerate the derived files. (If I missed
some, please let me know.)
-Note that the distribution comes with a "Makefile" which will be overwritten
-by "configure" with one that is not at all equiavelent to the original. The
-distribution contains a copy of the original "Makefile" in "Makefile.direct".
+Note that the distribution comes without "Makefile" which is generated by
+"configure". The distribution also contains "Makefile.direct" which is not
+always equivalent to the generated one.
Important options to configure:
@@ -47,7 +47,9 @@ Important options to configure:
[same as prefix]
--enable-threads=TYPE choose threading package
--enable-parallel-mark parallelize marking and free list construction
- --enable-full-debug include full support for pointer backtracing etc.
+ --enable-gc-debug (--enable-full-debug before about 7.0)
+ include full support for pointer back-tracing etc.
+
Unless --prefix is set (or --exec-prefix or one of the more obscure options),
make install will install libgc.a and libgc.so in /usr/local/bin, which
@@ -55,5 +57,3 @@ would typically require the "make install" to be run as root.
Most commonly --enable-threads=posix or will be needed. --enable-parallel-mark
is recommended for multiprocessors if it is supported on the platform.
-
-
diff --git a/boehm-gc/doc/README.changes b/boehm-gc/doc/README.changes
deleted file mode 100644
index e27e7d635b6..00000000000
--- a/boehm-gc/doc/README.changes
+++ /dev/null
@@ -1,2134 +0,0 @@
-This is a rough history of garbage collector bugs and versions.
-
-This has been maintained with varying diligence over the years.
-
-I made an attempt to include recent contributors here. I apologize for any
-omissions.
-
--------------------------
-
- Version 1.3 and immediately preceding versions contained spurious
-assembly language assignments to TMP_SP. Only the assignment in the PC/RT
-code is necessary. On other machines, with certain compiler options,
-the assignments can lead to an unsaved register being overwritten.
-Known to cause problems under SunOS 3.5 WITHOUT the -O option. (With
--O the compiler recognizes it as dead code. It probably shouldn't,
-but that's another story.)
-
- Version 1.4 and earlier versions used compile time determined values
-for the stack base. This no longer works on Sun 3s, since Sun 3/80s use
-a different stack base. We now use a straightforward heuristic on all
-machines on which it is known to work (incl. Sun 3s) and compile-time
-determined values for the rest. There should really be library calls
-to determine such values.
-
- Version 1.5 and earlier did not ensure 8 byte alignment for objects
-allocated on a sparc based machine.
-
- Version 1.8 added ULTRIX support in gc_private.h.
-
- Version 1.9 fixed a major bug in gc_realloc.
-
- Version 2.0 introduced a consistent naming convention for collector
-routines and added support for registering dynamic library data segments
-in the standard mark_roots.c. Most of the data structures were revamped.
-The treatment of interior pointers was completely changed. Finalization
-was added. Support for locking was added. Object kinds were added.
-We added a black listing facility to avoid allocating at addresses known
-to occur as integers somewhere in the address space. Much of this
-was accomplished by adapting ideas and code from the PCR collector.
-The test program was changed and expanded.
-
- Version 2.1 was the first stable version since 1.9, and added support
-for PPCR.
-
- Version 2.2 added debugging allocation, and fixed various bugs. Among them:
-- GC_realloc could fail to extend the size of the object for certain large object sizes.
-- A blatant subscript range error in GC_printf, which unfortunately
- wasn't exercised on machines with sufficient stack alignment constraints.
-- GC_register_displacement did the wrong thing if it was called after
- any allocation had taken place.
-- The leak finding code would eventually break after 2048 byte
- byte objects leaked.
-- interface.c didn't compile.
-- The heap size remained much too small for large stacks.
-- The stack clearing code behaved badly for large stacks, and perhaps
- on HP/PA machines.
-
- Version 2.3 added ALL_INTERIOR_POINTERS and fixed the following bugs:
-- Missing declaration of etext in the A/UX version.
-- Some PCR root-finding problems.
-- Blacklisting was not 100% effective, because the plausible future
- heap bounds were being miscalculated.
-- GC_realloc didn't handle out-of-memory correctly.
-- GC_base could return a nonzero value for addresses inside free blocks.
-- test.c wasn't really thread safe, and could erroneously report failure
- in a multithreaded environment. (The locking primitives need to be
- replaced for other threads packages.)
-- GC_CONS was thoroughly broken.
-- On a SPARC with dynamic linking, signals stayed diabled while the
- client code was running.
- (Thanks to Manuel Serrano at INRIA for reporting the last two.)
-
- Version 2.4 added GC_free_space_divisor as a tuning knob, added
- support for OS/2 and linux, and fixed the following bugs:
-- On machines with unaligned pointers (e.g. Sun 3), every 128th word could
- fail to be considered for marking.
-- Dynamic_load.c erroneously added 4 bytes to the length of the data and
- bss sections of the dynamic library. This could result in a bad memory
- reference if the actual length was a multiple of a page. (Observed on
- Sun 3. Can probably also happen on a Sun 4.)
- (Thanks to Robert Brazile for pointing out that the Sun 3 version
- was broken. Dynamic library handling is still broken on Sun 3s
- under 4.1.1U1, but apparently not 4.1.1. If you have such a machine,
- use -Bstatic.)
-
- Version 2.5 fixed the following bugs:
-- Removed an explicit call to exit(1)
-- Fixed calls to GC_printf and GC_err_printf, so the correct number of
- arguments are always supplied. The OS/2 C compiler gets confused if
- the number of actuals and the number of formals differ. (ANSI C
- doesn't require this to work. The ANSI sanctioned way of doing things
- causes too many compatibility problems.)
-
- Version 3.0 added generational/incremental collection and stubborn
- objects.
-
- Version 3.1 added the following features:
-- A workaround for a SunOS 4.X SPARC C compiler
- misfeature that caused problems when the collector was turned into
- a dynamic library.
-- A fix for a bug in GC_base that could result in a memory fault.
-- A fix for a performance bug (and several other misfeatures) pointed
- out by Dave Detlefs and Al Dosser.
-- Use of dirty bit information for static data under Solaris 2.X.
-- DEC Alpha/OSF1 support (thanks to Al Dosser).
-- Incremental collection on more platforms.
-- A more refined heap expansion policy. Less space usage by default.
-- Various minor enhancements to reduce space usage, and to reduce
- the amount of memory scanned by the collector.
-- Uncollectable allocation without per object overhead.
-- More conscientious handling of out-of-memory conditions.
-- Fixed a bug in debugging stubborn allocation.
-- Fixed a bug that resulted in occasional erroneous reporting of smashed
- objects with debugging allocation.
-- Fixed bogus leak reports of size 4096 blocks with FIND_LEAK.
-
- Version 3.2 fixed a serious and not entirely repeatable bug in
- the incremental collector. It appeared only when dirty bit info
- on the roots was available, which is normally only under Solaris.
- It also added GC_general_register_disappearing_link, and some
- testing code. Interface.c disappeared.
-
- Version 3.3 fixes several bugs and adds new ports:
-- PCR-specific bugs.
-- Missing locking in GC_free, redundant FASTUNLOCK
- in GC_malloc_stubborn, and 2 bugs in
- GC_unregister_disappearing_link.
- All of the above were pointed out by Neil Sharman
- (neil@cs.mu.oz.au).
-- Common symbols allocated by the SunOS4.X dynamic loader
- were not included in the root set.
-- Bug in GC_finalize (reported by Brian Beuning and Al Dosser)
-- Merged Amiga port from Jesper Peterson (untested)
-- Merged NeXT port from Thomas Funke (significantly
- modified and untested)
-
- Version 3.4:
-- Fixed a performance bug in GC_realloc.
-- Updated the amiga port.
-- Added NetBSD and 386BSD ports.
-- Added cord library.
-- Added trivial performance enhancement for
- ALL_INTERIOR_POINTERS. (Don't scan last word.)
-
- Version 3.5
-- Minor collections now mark from roots only once, if that
- doesn't cause an excessive pause.
-- The stack clearing heuristic was refined to prevent anomalies
- with very heavily recursive programs and sparse stacks.
-- Fixed a bug that prevented mark stack growth in some cases.
- GC_objects_are_marked should be set to TRUE after a call
- to GC_push_roots and as part of GC_push_marked, since
- both can now set mark bits. I think this is only a performance
- bug, but I wouldn't bet on it. It's certainly very hard to argue
- that the old version was correct.
-- Fixed an incremental collection bug that prevented it from
- working at all when HBLKSIZE != getpagesize()
-- Changed dynamic_loading.c to include gc_priv.h before testing
- DYNAMIC_LOADING. SunOS dynamic library scanning
- must have been broken in 3.4.
-- Object size rounding now adapts to program behavior.
-- Added a workaround (provided by Manuel Serrano and
- colleagues) to a long-standing SunOS 4.X (and 3.X?) ld bug
- that I had incorrectly assumed to have been squished.
- The collector was broken if the text segment size was within
- 32 bytes of a multiple of 8K bytes, and if the beginning of
- the data segment contained interesting roots. The workaround
- assumes a demand-loadable executable. The original may have
- have "worked" in some other cases.
-- Added dynamic library support under IRIX5.
-- Added support for EMX under OS/2 (thanks to Ari Huttunen).
-
-Version 3.6:
-- fixed a bug in the mark stack growth code that was introduced
- in 3.4.
-- fixed Makefile to work around DEC AXP compiler tail recursion
- bug.
-
-Version 3.7:
-- Added a workaround for an HP/UX compiler bug.
-- Fixed another stack clearing performance bug. Reworked
- that code once more.
-
-Version 4.0:
-- Added support for Solaris threads (which was possible
- only by reimplementing some fraction of Solaris threads,
- since Sun doesn't currently make the thread debugging
- interface available).
-- Added non-threads win32 and win32S support.
-- (Grudgingly, with suitable muttering of obscenities) renamed
- files so that the collector distribution could live on a FAT
- file system. Files that are guaranteed to be useless on
- a PC still have long names. Gc_inline.h and gc_private.h
- still exist, but now just include gc_inl.h and gc_priv.h.
-- Fixed a really obscure bug in finalization that could cause
- undetected mark stack overflows. (I would be surprised if
- any real code ever tickled this one.)
-- Changed finalization code to dynamically resize the hash
- tables it maintains. (This probably does not matter for well-
- -written code. It no doubt does for C++ code that overuses
- destructors.)
-- Added typed allocation primitives. Rewrote the marker to
- accommodate them with more reasonable efficiency. This
- change should also speed up marking for GC_malloc allocated
- objects a little. See gc_typed.h for new primitives.
-- Improved debugging facilities slightly. Allocation time
- stack traces are now kept by default on SPARC/SUNOS4.
- (Thanks to Scott Schwartz.)
-- Added better support for small heap applications.
-- Significantly extended cord package. Fixed a bug in the
- implementation of lazily read files. Printf and friends now
- have cord variants. Cord traversals are a bit faster.
-- Made ALL_INTERIOR_POINTERS recognition the default.
-- Fixed de so that it can run in constant space, independent
- of file size. Added simple string searching to cords and de.
-- Added the Hull-Ellis C++ interface.
-- Added dynamic library support for OSF/1.
- (Thanks to Al Dosser and Tim Bingham at DEC.)
-- Changed argument to GC_expand_hp to be expressed
- in units of bytes instead of heap blocks. (Necessary
- since the heap block size now varies depending on
- configuration. The old version was never very clean.)
-- Added GC_get_heap_size(). The previous "equivalent"
- was broken.
-- Restructured the Makefile a bit.
-
-Since version 4.0:
-- Changed finalization implementation to guarantee that
- finalization procedures are called outside of the allocation
- lock, making direct use of the interface a little less dangerous.
- MAY BREAK EXISTING CLIENTS that assume finalizers
- are protected by a lock. Since there seem to be few multithreaded
- clients that use finalization, this is hopefully not much of
- a problem.
-- Fixed a gross bug in CORD_prev.
-- Fixed a bug in blacklst.c that could result in unbounded
- heap growth during startup on machines that do not clear
- memory obtained from the OS (e.g. win32S).
-- Ported de editor to win32/win32S. (This is now the only
- version with a mouse-sensitive UI.)
-- Added GC_malloc_ignore_off_page to allocate large arrays
- in the presence of ALL_INTERIOR_POINTERS.
-- Changed GC_call_with_alloc_lock to not disable signals in
- the single-threaded case.
-- Reduced retry count in GC_collect_or_expand for garbage
- collecting when out of memory.
-- Made uncollectable allocations bypass black-listing, as they
- should.
-- Fixed a bug in typed_test in test.c that could cause (legitimate)
- GC crashes.
-- Fixed some potential synchronization problems in finalize.c
-- Fixed a real locking problem in typd_mlc.c.
-- Worked around an AIX 3.2 compiler feature that results in
- out of bounds memory references.
-- Partially worked around an IRIX5.2 beta problem (which may
- or may not persist to the final release).
-- Fixed a bug in the heap integrity checking code that could
- result in explicitly deallocated objects being identified as
- smashed. Fixed a bug in the dbg_mlc stack saving code
- that caused old argument pointers to be considered live.
-- Fixed a bug in CORD_ncmp (and hence CORD_str).
-- Repaired the OS2 port, which had suffered from bit rot
- in 4.0. Worked around what appears to be CSet/2 V1.0
- optimizer bug.
-- Fixed a Makefile bug for target "c++".
-
-Since version 4.1:
-- Multiple bug fixes/workarounds in the Solaris threads version.
- (It occasionally failed to locate some register contents for
- marking. It also turns out that thr_suspend and friends are
- unreliable in Solaris 2.3. Dirty bit reads appear
- to be unreliable under some weird
- circumstances. My stack marking code
- contained a serious performance bug. The new code is
- extremely defensive, and has not failed in several cpu
- hours of testing. But no guarantees ...)
-- Added MacOS support (thanks to Patrick Beard.)
-- Fixed several syntactic bugs in gc_c++.h and friends. (These
- didn't bother g++, but did bother most other compilers.)
- Fixed gc_c++.h finalization interface. (It didn't.)
-- 64 bit alignment for allocated objects was not guaranteed in a
- few cases in which it should have been.
-- Added GC_malloc_atomic_ignore_off_page.
-- Added GC_collect_a_little.
-- Added some prototypes to gc.h.
-- Some other minor bug fixes (notably in Makefile).
-- Fixed OS/2 / EMX port (thanks to Ari Huttunen).
-- Fixed AmigaDOS port. (thanks to Michel Schinz).
-- Fixed the DATASTART definition under Solaris. There
- was a 1 in 16K chance of the collector missing the first
- 64K of static data (and thus crashing).
-- Fixed some blatant anachronisms in the README file.
-- Fixed PCR-Makefile for upcoming PPCR release.
-
-Since version 4.2:
-- Fixed SPARC alignment problem with GC_DEBUG.
-- Fixed Solaris threads /proc workaround. The real
- problem was an interaction with mprotect.
-- Incorporated fix from Patrick Beard for gc_c++.h (now gc_cpp.h).
-- Slightly improved allocator space utilization by
- fixing the GC_size_map mechanism.
-- Integrated some Sony News and MIPS RISCos 4.51
- patches. (Thanks to Nobuyuki Hikichi of
- Software Research Associates, Inc. Japan)
-- Fixed HP_PA alignment problem. (Thanks to
- xjam@cork.cs.berkeley.edu.)
-- Added GC_same_obj and friends. Changed GC_base
- to return 0 for pointers past the end of large objects.
- Improved GC_base performance with ALL_INTERIOR_POINTERS
- on machines with a slow integer mod operation.
- Added GC_PTR_ADD, GC_PTR_STORE, etc. to prepare
- for preprocessor.
-- changed the default on most UNIX machines to be that
- signals are not disabled during critical GC operations.
- This is still ANSI-conforming, though somewhat dangerous
- in the presence of signal handlers. But the performance
- cost of the alternative is sometimes problematic.
- Can be changed back with a minor Makefile edit.
-- renamed IS_STRING in gc.h, to CORD_IS_STRING, thus
- following my own naming convention. Added the function
- CORD_to_const_char_star.
-- Fixed a gross bug in GC_finalize. Symptom: occasional
- address faults in that function. (Thanks to Anselm
- Baird-Smith (Anselm.BairdSmith@inria.fr)
-- Added port to ICL DRS6000 running DRS/NX. Restructured
- things a bit to factor out common code, and remove obsolete
- code. Collector should now run under SUNOS5 with either
- mprotect or /proc dirty bits. (Thanks to Douglas Steel
- (doug@wg.icl.co.uk)).
-- More bug fixes and workarounds for Solaris 2.X. (These were
- mostly related to putting the collector in a dynamic library,
- which didn't really work before. Also SOLARIS_THREADS
- didn't interact well with dl_open.) Thanks to btlewis@eng.sun.com.
-- Fixed a serious performance bug on the DEC Alpha. The text
- segment was getting registered as part of the root set.
- (Amazingly, the result was still fast enough that the bug
- was not conspicuous.) The fix works on OSF/1, version 1.3.
- Hopefully it also works on other versions of OSF/1 ...
-- Fixed a bug in GC_clear_roots.
-- Fixed a bug in GC_generic_malloc_words_small that broke
- gc_inl.h. (Reported by Antoine de Maricourt. I broke it
- in trying to tweak the Mac port.)
-- Fixed some problems with cord/de under Linux.
-- Fixed some cord problems, notably with CORD_riter4.
-- Added DG/UX port.
- Thanks to Ben A. Mesander (ben@piglet.cr.usgs.gov)
-- Added finalization registration routines with weaker ordering
- constraints. (This is necessary for C++ finalization with
- multiple inheritance, since the compiler often adds self-cycles.)
-- Filled the holes in the SCO port. (Thanks to Michael Arnoldus
- <chime@proinf.dk>.)
-- John Ellis' additions to the C++ support: From John:
-
-* I completely rewrote the documentation in the interface gc_c++.h
-(later renamed gc_cpp.h). I've tried to make it both clearer and more
-precise.
-
-* The definition of accessibility now ignores pointers from an
-finalizable object (an object with a clean-up function) to itself.
-This allows objects with virtual base classes to be finalizable by the
-collector. Compilers typically implement virtual base classes using
-pointers from an object to itself, which under the old definition of
-accessibility prevented objects with virtual base classes from ever
-being collected or finalized.
-
-* gc_cleanup now includes gc as a virtual base. This was enabled by
-the change in the definition of accessibility.
-
-* I added support for operator new[]. Since most (all?) compilers
-don't yet support operator new[], it is conditionalized on
--DOPERATOR_NEW_ARRAY. The code is untested, but its trivial and looks
-correct.
-
-* The test program test_gc_c++ (later renamed test_cpp.cc)
-tries to test for the C++-specific functionality not tested by the
-other programs.
-- Added <unistd.h> include to misc.c. (Needed for ppcr.)
-- Added PowerMac port. (Thanks to Patrick Beard again.)
-- Fixed "srcdir"-related Makefile problems. Changed things so
- that all externally visible include files always appear in the
- include subdirectory of the source. Made gc.h directly
- includable from C++ code. (These were at Per
- Bothner's suggestion.)
-- Changed Intel code to also mark from ebp (Kevin Warne's
- suggestion).
-- Renamed C++ related files so they could live in a FAT
- file system. (Charles Fiterman's suggestion.)
-- Changed Windows NT Makefile to include C++ support in
- gc.lib. Added C++ test as Makefile target.
-
-Since version 4.3:
- - ASM_CLEAR_CODE was erroneously defined for HP
- PA machines, resulting in a compile error.
- - Fixed OS/2 Makefile to create a library. (Thanks to
- Mark Boulter (mboulter@vnet.ibm.com)).
- - Gc_cleanup objects didn't work if they were created on
- the stack. Fixed.
- - One copy of Gc_cpp.h in the distribution was out of
- synch, and failed to document some known compiler
- problems with explicit destructor invocation. Partially
- fixed. There are probably other compilers on which
- gc_cleanup is miscompiled.
- - Fixed Makefile to pass C compiler flags to C++ compiler.
- - Added Mac fixes.
- - Fixed os_dep.c to work around what appears to be
- a new and different VirtualQuery bug under newer
- versions of win32S.
- - GC_non_gc_bytes was not correctly maintained by
- GC_free. Fixed. Thanks to James Clark (jjc@jclark.com).
- - Added GC_set_max_heap_size.
- - Changed allocation code to ignore blacklisting if it is preventing
- use of a very large block of memory. This has the advantage
- that naive code allocating very large objects is much more
- likely to work. The downside is you might no
- longer find out that such code should really use
- GC_malloc_ignore_off_page.
- - Changed GC_printf under win32 to close and reopen the file
- between calls. FAT file systems otherwise make the log file
- useless for debugging.
- - Added GC_try_to_collect and GC_get_bytes_since_gc. These
- allow starting an abortable collection during idle times.
- This facility does not require special OS support. (Thanks to
- Michael Spertus of Geodesic Systems for suggesting this. It was
- actually an easy addition. Kumar Srikantan previously added a similar
- facility to a now ancient version of the collector. At the time
- this was much harder, and the result was less convincing.)
- - Added some support for the Borland development environment. (Thanks
- to John Ellis and Michael Spertus.)
- - Removed a misfeature from checksums.c that caused unexpected
- heap growth. (Thanks to Scott Schwartz.)
- - Changed finalize.c to call WARN if it encounters a finalization cycle.
- WARN is defined in gc_priv.h to write a message, usually to stdout.
- In many environments, this may be inappropriate.
- - Renamed NO_PARAMS in gc.h to GC_NO_PARAMS, thus adhering to my own
- naming convention.
- - Added GC_set_warn_proc to intercept warnings.
- - Fixed Amiga port. (Thanks to Michel Schinz (schinz@alphanet.ch).)
- - Fixed a bug in mark.c that could result in an access to unmapped
- memory from GC_mark_from_mark_stack on machines with unaligned
- pointers.
- - Fixed a win32 specific performance bug that could result in scanning of
- objects allocated with the system malloc.
- - Added REDIRECT_MALLOC.
-
-Since version 4.4:
- - Fixed many minor and one major README bugs. (Thanks to Franklin Chen
- (chen@adi.com) for pointing out many of them.)
- - Fixed ALPHA/OSF/1 dynamic library support. (Thanks to Jonathan Bachrach
- (jonathan@harlequin.com)).
- - Added incremental GC support (MPROTECT_VDB) for Linux (with some
- help from Bruno Haible).
- - Altered SPARC recognition tests in gc.h and config.h (mostly as
- suggested by Fergus Henderson).
- - Added basic incremental GC support for win32, as implemented by
- Windows NT and Windows 95. GC_enable_incremental is a noop
- under win32s, which doesn't implement enough of the VM interface.
- - Added -DLARGE_CONFIG.
- - Fixed GC_..._ignore_off_page to also function without
- -DALL_INTERIOR_POINTERS.
- - (Hopefully) fixed RS/6000 port. (Only the test was broken.)
- - Fixed a performance bug in the nonincremental collector running
- on machines supporting incremental collection with MPROTECT_VDB
- (e.g. SunOS 4, DEC AXP). This turned into a correctness bug under
- win32s with win32 incremental collection. (Not all memory protection
- was disabled.)
- - Fixed some ppcr related bit rot.
- - Caused dynamic libraries to be unregistered before reregistering.
- The old way turned out to be a performance bug on some machines.
- - GC_root_size was not properly maintained under MSWIN32.
- - Added -DNO_DEBUGGING and GC_dump.
- - Fixed a couple of bugs arising with SOLARIS_THREADS +
- REDIRECT_MALLOC.
- - Added NetBSD/M68K port. (Thanks to Peter Seebach
- <seebs@taniemarie.solon.com>.)
- - Fixed a serious realloc bug. For certain object sizes, the collector
- wouldn't scan the expanded part of the object. (Thanks to Clay Spence
- (cds@peanut.sarnoff.com) for noticing the problem, and helping me to
- track it down.)
-
-Since version 4.5:
- - Added Linux ELF support. (Thanks to Arrigo Triulzi <arrigo@ic.ac.uk>.)
- - GC_base crashed if it was called before any other GC_ routines.
- This could happen if a gc_cleanup object was allocated outside the heap
- before any heap allocation.
- - The heap expansion heuristic was not stable if all objects had finalization
- enabled. Fixed finalize.c to count memory in finalization queue and
- avoid explicit deallocation. Changed alloc.c to also consider this count.
- (This is still not recommended. It's expensive if nothing else.) Thanks
- to John Ellis for pointing this out.
- - GC_malloc_uncollectable(0) was broken. Thanks to Phong Vo for pointing
- this out.
- - The collector didn't compile under Linux 1.3.X. (Thanks to Fred Gilham for
- pointing this out.) The current workaround is ugly, but expected to be
- temporary.
- - Fixed a formatting problem for SPARC stack traces.
- - Fixed some '=='s in os_dep.c that should have been assignments.
- Fortunately these were in code that should never be executed anyway.
- (Thanks to Fergus Henderson.)
- - Fixed the heap block allocator to only drop blacklisted blocks in small
- chunks. Made BL_LIMIT self adjusting. (Both of these were in response
- to heap growth observed by Paul Graham.)
- - Fixed the Metrowerks/68K Mac code to also mark from a6. (Thanks
- to Patrick Beard.)
- - Significantly updated README.debugging.
- - Fixed some problems with longjmps out of signal handlers, especially under
- Solaris. Added a workaround for the fact that siglongjmp doesn't appear to
- do the right thing with -lthread under Solaris.
- - Added MSDOS/djgpp port. (Thanks to Mitch Harris (maharri@uiuc.edu).)
- - Added "make reserved_namespace" and "make user_namespace". The
- first renames ALL "GC_xxx" identifiers as "_GC_xxx". The second is the
- inverse transformation. Note that doing this is guaranteed to break all
- clients written for the other names.
- - descriptor field for kind NORMAL in GC_obj_kinds with ADD_BYTE_AT_END
- defined should be -ALIGNMENT not WORDS_TO_BYTES(-1). This is
- a serious bug on machines with pointer alignment of less than a word.
- - GC_ignore_self_finalize_mark_proc didn't handle pointers to very near the
- end of the object correctly. Caused failures of the C++ test on a DEC Alpha
- with g++.
- - gc_inl.h still had problems. Partially fixed. Added warnings at the
- beginning to hopefully specify the remaining dangers.
- - Added DATAEND definition to config.h.
- - Fixed some of the .h file organization. Fixed "make floppy".
-
-Since version 4.6:
- - Fixed some compilation problems with -DCHECKSUMS (thanks to Ian Searle)
- - Updated some Mac specific files to synchronize with Patrick Beard.
- - Fixed a serious bug for machines with non-word-aligned pointers.
- (Thanks to Patrick Beard for pointing out the problem. The collector
- should fail almost any conceivable test immediately on such machines.)
-
-Since version 4.7:
- - Changed a "comment" in a MacOS specific part of mach-dep.c that caused
- gcc to fail on other platforms.
-
-Since version 4.8
- - More README.debugging fixes.
- - Objects ready for finalization, but not finalized in the same GC
- cycle, could be prematurely collected. This occasionally happened
- in test_cpp.
- - Too little memory was obtained from the system for very large
- objects. That could cause a heap explosion if these objects were
- not contiguous (e.g. under PCR), and too much of them was blacklisted.
- - Due to an improper initialization, the collector was too hesitant to
- allocate blacklisted objects immediately after system startup.
- - Moved GC_arrays from the data into the bss segment by not explicitly
- initializing it to zero. This significantly
- reduces the size of executables, and probably avoids some disk accesses
- on program startup. It's conceivable that it might break a port that I
- didn't test.
- - Fixed EMX_MAKEFILE to reflect the gc_c++.h to gc_cpp.h renaming which
- occurred a while ago.
-
-Since 4.9:
- - Fixed a typo around a call to GC_collect_or_expand in alloc.c. It broke
- handling of out of memory. (Thanks to Patrick Beard for noticing.)
-
-Since 4.10:
- - Rationalized (hopefully) GC_try_to_collect in an incremental collection
- environment. It appeared to not handle a call while a collection was in
- progress, and was otherwise too conservative.
- - Merged GC_reclaim_or_delete_all into GC_reclaim_all to get rid of some
- code.
- - Added Patrick Beard's Mac fixes, with substantial completely untested
- modifications.
- - Fixed the MPROTECT_VDB code to deal with large pages and imprecise
- fault addresses (as on an UltraSPARC running Solaris 2.5). Note that this
- was not a problem in the default configuration, which uses PROC_VDB.
- - The DEC Alpha assembly code needed to restore $gp between calls.
- Thanks to Fergus Henderson for tracking this down and supplying a
- patch.
- - The write command for "de" was completely broken for large files.
- I used the easiest portable fix, which involved changing the semantics
- so that f.new is written instead of overwriting f. That's safer anyway.
- - Added README.solaris2 with a discussion of the possible problems of
- mixing the collector's sbrk allocation with malloc/realloc.
- - Changed the data segment starting address for SGI machines. The
- old code failed under IRIX6.
- - Required double word alignment for MIPS.
- - Various minor fixes to remove warnings.
- - Attempted to fix some Solaris threads problems reported by Zhiying Chen.
- In particular, the collector could try to fork a thread with the
- world stopped as part of GC_thr_init. It also failed to deal with
- the case in which the original thread terminated before the whole
- process did.
- - Added -DNO_EXECUTE_PERMISSION. This has a major performance impact
- on the incremental collector under Irix, and perhaps under other
- operating systems.
- - Added some code to support allocating the heap with mmap. This may
- be preferable under some circumstances.
- - Integrated dynamic library support for HP.
- (Thanks to Knut Tvedten <knuttv@ifi.uio.no>.)
- - Integrated James Clark's win32 threads support, and made a number
- of changes to it, many of which were suggested by Pontus Rydin.
- This is still not 100% solid.
- - Integrated Alistair Crooks' support for UTS4 running on an Amdahl
- 370-class machine.
- - Fixed a serious bug in explicitly typed allocation. Objects requiring
- large descriptors where handled in a way that usually resulted in
- a segmentation fault in the marker. (Thanks to Jeremy Fitzhardinge
- for helping to track this down.)
- - Added partial support for GNU win32 development. (Thanks to Fergus
- Henderson.)
- - Added optional support for Java-style finalization semantics. (Thanks
- to Patrick Bridges.) This is recommended only for Java implementations.
- - GC_malloc_uncollectable faulted instead of returning 0 when out of
- memory. (Thanks to dan@math.uiuc.edu for noticing.)
- - Calls to GC_base before the collector was initialized failed on a
- DEC Alpha. (Thanks to Matthew Flatt.)
- - Added base pointer checking to GC_REGISTER_FINALIZER in debugging
- mode, at the suggestion of Jeremy Fitzhardinge.
- - GC_debug_realloc failed for uncollectable objects. (Thanks to
- Jeremy Fitzhardinge.)
- - Explicitly typed allocation could crash if it ran out of memory.
- (Thanks to Jeremy Fitzhardinge.)
- - Added minimal support for a DEC Alpha running Linux.
- - Fixed a problem with allocation of objects whose size overflowed
- ptrdiff_t. (This now fails unconditionally, as it should.)
- - Added the beginning of Irix pthread support.
- - Integrated Xiaokun Zhu's fixes for djgpp 2.01.
- - Added SGI-style STL allocator support (gc_alloc.h).
- - Fixed a serious bug in README.solaris2. Multithreaded programs must include
- gc.h with SOLARIS_THREADS defined.
- - Changed GC_free so it actually deallocates uncollectable objects.
- (Thanks to Peter Chubb for pointing out the problem.)
- - Added Linux ELF support for dynamic libararies. (Thanks again to
- Patrick Bridges.)
- - Changed the Borland cc configuration so that the assembler is not
- required.
- - Fixed a bug in the C++ test that caused it to fail in 64-bit
- environments.
-
-Since 4.11:
- - Fixed ElfW definition in dyn_load.c. (Thanks to Fergus Henderson.)
- This prevented the dynamic library support from compiling on some
- older ELF Linux systems.
- - Fixed UTS4 port (which I apparently mangled during the integration)
- (Thanks to again to Alistair Crooks.)
- - "Make C++" failed on Suns with SC4.0, due to a problem with "bool".
- Fixed in gc_priv.h.
- - Added more pieces for GNU win32. (Thanks to Timothy N. Newsham.)
- The current state of things should suffice for at least some
- applications.
- - Changed the out of memory retry count handling as suggested by
- Kenjiro Taura. (This matters only if GC_max_retries > 0, which
- is no longer the default.)
- - If a /proc read failed repeatedly, GC_written_pages was not updated
- correctly. (Thanks to Peter Chubb for diagnosing this.)
- - Under unlikely circumstances, the allocator could infinite loop in
- an out of memory situation. (Thanks again to Kenjiro Taura for
- identifying the problem and supplying a fix.)
- - Fixed a syntactic error in the DJGPP code. (Thanks to Fergus
- Henderson for finding this by inspection.) Also fixed a test program
- problem with DJGPP (Thanks to Peter Monks.)
- - Atomic uncollectable objects were not treated correctly by the
- incremental collector. This resulted in weird log statistics and
- occasional performance problems. (Thanks to Peter Chubb for pointing
- this out.)
- - Fixed some problems resulting from compilers that dont define
- __STDC__. In this case void * and char * were used inconsistently
- in some cases. (Void * should not have been used at all. If
- you have an ANSI superset compiler that does not define __STDC__,
- please compile with -D__STDC__=0. Thanks to Manuel Serrano and others
- for pointing out the problem.)
- - Fixed a compilation problem on Irix with -n32 and -DIRIX_THREADS.
- Also fixed some other IRIX_THREADS problems which may or may not have
- had observable symptoms.
- - Fixed an HP PA compilation problem in dyn_load.c. (Thanks to
- Philippe Queinnec.)
- - SEGV fault handlers sometimes did not get reset correctly. (Thanks
- to David Pickens.)
- - Added a fix for SOLARIS_THREADS on Intel. (Thanks again to David
- Pickens.) This probably needs more work to become functional.
- - Fixed struct sigcontext_struct in os_dep.c for compilation under
- Linux 2.1.X. (Thanks to Fergus Henderson.)
- - Changed the DJGPP STACKBOTTOM and DATASTART values to those suggested
- by Kristian Kristensen. These may still not be right, but it is
- it is likely to work more often than what was there before. They may
- even be exactly right.
- - Added a #include <string.h> to test_cpp.cc. This appears to help
- with HP/UX and gcc. (Thanks to assar@sics.se.)
- - Version 4.11 failed to run in incremental mode on recent 64-bit Irix
- kernels. This was a problem related to page unaligned heap segments.
- Changed the code to page align heap sections on all platforms.
- (I had mistakenly identified this as a kernel problem earlier.
- It was not.)
- - Version 4.11 did not make allocated storage executable, except on
- one or two platforms, due to a bug in a #if test. (Thanks to Dave
- Grove for pointing this out.)
- - Added sparc_sunos4_mach_dep.s to support Sun's compilers under SunOS4.
- - Added GC_exclude_static_roots.
- - Fixed the object size mapping algorithm. This shouldn't matter,
- but the old code was ugly.
- - Heap checking code could die if one of the allocated objects was
- larger than its base address. (Unsigned underflow problem. Thanks
- to Clay Spence for isolating the problem.)
- - Added RS6000 (AIX) dynamic library support and fixed STACK_BOTTOM.
- (Thanks to Fred Stearns.)
- - Added Fergus Henderson's patches for improved robustness with large
- heaps and lots of blacklisting.
- - Added Peter Chubb's changes to support Solaris Pthreads, to support
- MMAP allocation in Solaris, to allow Solaris to find dynamic libraries
- through /proc, to add malloc_typed_ignore_off_page, and a few other
- minor features and bug fixes.
- - The Solaris 2 port should not use sbrk. I received confirmation from
- Sun that the use of sbrk and malloc in the same program is not
- supported. The collector now defines USE_MMAP by default on Solaris.
- - Replaced the djgpp makefile with Gary Leavens' version.
- - Fixed MSWIN32 detection test.
- - Added Fergus Henderson's patches to allow putting the collector into
- a DLL under GNU win32.
- - Added Ivan V. Demakov's port to Watcom C on X86.
- - Added Ian Piumarta's Linux/PowerPC port.
- - On Brian Burton's suggestion added PointerFreeGC to the placement
- options in gc_cpp.h. This is of course unsafe, and may be controversial.
- On the other hand, it seems to be needed often enough that it's worth
- adding as a standard facility.
-
-Since 4.12:
- - Fixed a crucial bug in the Watcom port. There was a redundant decl
- of GC_push_one in gc_priv.h.
- - Added FINALIZE_ON_DEMAND.
- - Fixed some pre-ANSI cc problems in test.c.
- - Removed getpagesize() use for Solaris. It seems to be missing in one
- or two versions.
- - Fixed bool handling for SPARCCompiler version 4.2.
- - Fixed some files in include that had gotten unlinked from the main
- copy.
- - Some RS/6000 fixes (missing casts). Thanks to Toralf Foerster.
- - Fixed several problems in GC_debug_realloc, affecting mostly the
- FIND_LEAK case.
- - GC_exclude_static_roots contained a buggy unsigned comparison to
- terminate a loop. (Thanks to Wilson Ho.)
- - CORD_str failed if the substring occurred at the last possible position.
- (Only affects cord users.)
- - Fixed Linux code to deal with RedHat 5.0 and integrated Peter Bigot's
- os_dep.c code for dealing with various Linux versions.
- - Added workaround for Irix pthreads sigaction bug and possible signal
- misdirection problems.
-Since alpha1:
- - Changed RS6000 STACKBOTTOM.
- - Integrated Patrick Beard's Mac changes.
- - Alpha1 didn't compile on Irix m.n, m < 6.
- - Replaced Makefile.dj with a new one from Gary Leavens.
- - Added Andrew Stitcher's changes to support SCO OpenServer.
- - Added PRINT_BLACK_LIST, to allow debugging of high densities of false
- pointers.
- - Added code to debug allocator to keep track of return address
- in GC_malloc caller, thus giving a bit more context.
- - Changed default behavior of large block allocator to more
- aggressively avoid fragmentation. This is likely to slow down the
- collector when it succeeds at reducing space cost.
- - Integrated Fergus Henderson's CYGWIN32 changes. They are untested,
- but needed for newer versions.
- - USE_MMAP had some serious bugs. This caused the collector to fail
- consistently on Solaris with -DSMALL_CONFIG.
- - Added Linux threads support, thanks largely to Fergus Henderson.
-Since alpha2:
- - Fixed more Linux threads problems.
- - Changed default GC_free_space_divisor to 3 with new large block allocation.
- (Thanks to Matthew Flatt for some measurements that suggest the old
- value sometimes favors space too much over time.)
- - More CYGWIN32 fixes.
- - Integrated Tyson-Dowd's Linux-M68K port.
- - Minor HP PA and DEC UNIX fixes from Fergus Henderson.
- - Integrated Christoffe Raffali's Linux-SPARC changes.
- - Allowed for one more GC fixup iteration after a full GC in incremental
- mode. Some quick measurements suggested that this significantly
- reduces pause times even with smaller GC_RATE values.
- - Moved some more GC data structures into GC_arrays. This decreases
- pause times and GC overhead, but makes debugging slightly less convenient.
- - Fixed namespace pollution problem ("excl_table").
- - Made GC_incremental a constant for -DSMALL_CONFIG, hopefully shrinking
- that slightly.
- - Added some win32 threads fixes.
- - Integrated Ivan Demakov and David Stes' Watcom fixes.
- - Various other minor fixes contributed by many people.
- - Renamed config.h to gcconfig.h, since config.h tends to be used for
- many other things.
- - Integrated Matthew Flatt's support for 68K MacOS "far globals".
- - Fixed up some of the dynamic library Makefile targets for consistency
- across platforms.
- - Fixed a USE_MMAP typo that caused out-of-memory handling to fail
- on Solaris.
- - Added code to test.c to test thread creation a bit more.
- - Integrated GC_win32_free_heap, as suggested by Ivan Demakov.
- - Fixed Solaris 2.7 stack base finding problem. (This may actually
- have been done in an earlier alpha release.)
-Since alpha3:
- - Fixed MSWIN32 recognition test, which interfered with cygwin.
- - Removed unnecessary gc_watcom.asm from distribution. Removed
- some obsolete README.win32 text.
- - Added Alpha Linux incremental GC support. (Thanks to Philipp Tomsich
- for code for retrieving the fault address in a signal handler.)
- Changed Linux signal handler context argument to be a pointer.
- - Took care of some new warnings generated by the 7.3 SGI compiler.
- - Integrated Phillip Musumeci's FreeBSD/ELF fixes.
- - -DIRIX_THREADS was broken with the -o32 ABI (typo in gc_priv.h>
-
-Since 4.13:
- - Fixed GC_print_source_ptr to not use a prototype.
- - generalized CYGWIN test.
- - gc::new did the wrong thing with PointerFreeGC placement.
- (Thanks to Rauli Ruohonen.)
- - In the ALL_INTERIOR_POINTERS (default) case, some callee-save register
- values could fail to be scanned if the register was saved and
- reused in a GC frame. This showed up in verbose mode with gctest
- compiled with an unreleased SGI compiler. I vaguely recall an old
- bug report that may have been related. The bug was probably quite old.
- (The problem was that the stack scanning could be deferred until
- after the relevant frame was overwritten, and the new save location
- might be outside the scanned area. Fixed by more eager stack scanning.)
- - PRINT_BLACK_LIST had some problems. A few source addresses were garbage.
- - Replaced Makefile.dj and added -I flags to cord make targets.
- (Thanks to Gary Leavens.)
- - GC_try_to_collect was broken with the nonincremental collector.
- - gc_cleanup destructors could pass the wrong address to
- GC_register_finalizer_ignore_self in the presence of multiple
- inheritance. (Thanks to Darrell Schiebel.)
- - Changed PowerPC Linux stack finding code.
-
-Since 4.14alpha1
- - -DSMALL_CONFIG did not work reliably with large (> 4K) pages.
- Recycling the mark stack during expansion could result in a size
- zero heap segment, which confused things. (This was probably also an
- issue with the normal config and huge pages.)
- - Did more work to make sure that callee-save registers were scanned
- completely, even with the setjmp-based code. Added USE_GENERIC_PUSH_REGS
- macro to facilitate testing on machines I have access to.
- - Added code to explicitly push register contents for win32 threads.
- This seems to be necessary. (Thanks to Pierre de Rop.)
-
-Since 4.14alpha2
- - changed STACKBOTTOM for DJGPP (Thanks to Salvador Eduardo Tropea).
-
-Since 4.14
- - Reworked large block allocator. Now uses multiple doubly linked free
- lists to approximate best fit.
- - Changed heap expansion heuristic. Entirely free blocks are no longer
- counted towards the heap size. This seems to have a major impact on
- heap size stability; the old version could expand the heap way too
- much in the presence of large block fragmentation.
- - added -DGC_ASSERTIONS and some simple assertions inside the collector.
- This is mainlyt for collector debugging.
- - added -DUSE_MUNMAP to allow the heap to shrink. Suupported on only
- a few UNIX-like platforms for now.
- - added GC_dump_regions() for debugging of fragmentation issues.
- - Changed PowerPC pointer alignment under Linux to 4. (This needs
- checking by someone who has one. The suggestions came to me via a
- rather circuitous path.)
- - Changed the Linux/Alpha port to walk the data segment backwards until
- it encounters a SIGSEGV. The old way to find the start of the data
- segment broke with a recent release.
- - cordxtra.c needed to call GC_REGISTER_FINALIZER instead of
- GC_register_finalizer, so that it would continue to work with GC_DEBUG.
- - allochblk sometimes cleared the wrong block for debugging purposes
- when it dropped blacklisted blocks. This could result in spurious
- error reports with GC_DEBUG.
- - added MACOS X Server support. (Thanks to Andrew Stone.)
- - Changed the Solaris threads code to ignore stack limits > 8 MB with
- a warning. Empirically, it is not safe to access arbitrary pages
- in such large stacks. And the dirty bit implementation does not
- guarantee that none of them will be accessed.
- - Integrated Martin Tauchmann's Amiga changes.
- - Integrated James Dominy's OpenBSD/SPARC port.
-
-Since 5.0alpha1
- - Fixed bugs introduced in alpha1 (OpenBSD & large block initialization).
- - Added -DKEEP_BACK_PTRS and backptr.h interface. (The implementation
- idea came from Al Demers.)
-
-Since 5.0alpha2
- - Added some highly incomplete code to support a copied young generation.
- Comments on nursery.h are appreciated.
- - Changed -DFIND_LEAK, -DJAVA_FINALIZATION, and -DFINALIZE_ON_DEMAND,
- so the same effect could be obtained with a runtime switch. This is
- a step towards standardizing on a single dynamic GC library.
- - Significantly changed the way leak detection is handled, as a consequence
- of the above.
-
-Since 5.0 alpha3
- - Added protection fault handling patch for Linux/M68K from Fergus
- Henderson and Roman Hodek.
- - Removed the tests for SGI_SOURCE in new_gc_alloc.h. This was causing that
- interface to fail on nonSGI platforms.
- - Changed the Linux stack finding code to use /proc, after changing it
- to use HEURISTIC1. (Thanks to David Mossberger for pointing out the
- /proc hook.)
- - Added HP/UX incremental GC support and HP/UX 11 thread support.
- Thread support is currently still flakey.
- - Added basic Linux/IA64 support.
- - Integrated Anthony Green's PicoJava support.
- - Integrated Scott Ananian's StrongARM/NetBSD support.
- - Fixed some fairly serious performance bugs in the incremental
- collector. These have probably been there essentially forever.
- (Mark bits were sometimes set before scanning dirty pages.
- The reclaim phase unnecessarily dirtied full small object pages.)
- - Changed the reclaim phase to ignore nearly full pages to avoid
- touching them.
- - Limited GC_black_list_spacing to roughly the heap growth increment.
- - Changed full collection triggering heuristic to decrease full GC
- frequency by default, but to explicitly trigger full GCs during
- heap growth. This doesn't always improve things, but on average it's
- probably a win.
- - GC_debug_free(0, ...) failed. Thanks to Fergus Henderson for the
- bug report and fix.
-
-Since 5.0 alpha4
- - GC_malloc_explicitly_typed and friends sometimes failed to
- initialize first word.
- - Added allocation routines and support in the marker for mark descriptors
- in a type structure referenced by the first word of an object. This was
- introduced to support gcj, but hopefully in a way that makes it
- generically useful.
- - Added GC_requested_heapsize, and inhibited collections in nonincremental
- mode if the actual used heap size is less than what was explicitly
- requested.
- - The Solaris pthreads version of GC_pthread_create didn't handle a NULL
- attribute pointer. Solaris thread support used the wrong default thread
- stack size. (Thanks to Melissa O'Neill for the patch.)
- - Changed PUSH_CONTENTS macro to no longer modify first parameter.
- This usually doesn't matter, but it was certainly an accident waiting
- to happen ...
- - Added GC_register_finalizer_no_order and friends to gc.h. They're
- needed by Java implementations.
- - Integrated a fix for a win32 deadlock resulting from clock() calling
- malloc. (Thanks to Chris Dodd.)
- - Integrated Hiroshi Kawashima's port to Linux/MIPS. This was designed
- for a handheld platform, and may or may not be sufficient for other
- machines.
- - Fixed a va_arg problem with the %c specifier in cordprnt.c. It appears
- that this was always broken, but recent versions of gcc are the first to
- report the (statically detectable) bug.
- - Added an attempt at a more general solution to dlopen races/deadlocks.
- GC_dlopen now temporarily disables collection. Still not ideal, but ...
- - Added -DUSE_I686_PREFETCH, -DUSE_3DNOW_PREFETCH, and support for IA64
- prefetch instructions. May improve performance measurably, but I'm not
- sure the code will run correctly on processors that don't support the
- instruction. Won't build except with very recent gcc.
- - Added caching for header lookups in the marker. This seems to result
- in a barely measurable performance gain. Added support for interleaved
- lookups of two pointers, but unconfigured that since the performance
- gain is currently near zero, and it adds to code size.
- - Changed Linux DATA_START definition to check both data_start and
- __data_start, since nothing else seems to be portable.
- - Added -DUSE_LD_WRAP to optionally take advantage of the GNU ld function
- wrapping mechanism. Probably currently useful only on Linux.
- - Moved some variables for the scratch allocator into GC_arrays, on
- Martin Hirzel's suggestion.
- - Fixed a win32 threads bug that caused the collector to not look for
- interior pointers from one of the thread stacks without
- ALL_INTERIOR_POINTERS. (Thanks to Jeff Sturm.)
- - Added Mingw32 support. (Thanks again to Jeff Sturm for the patch.)
- - Changed the alpha port to use the generic register scanning code instead
- of alpha_mach_dep.s. Alpha_mach_dep.s doesn't look for pointers in fp
- registers, but gcc sometimes spills pointers there. (Thanks to Manuel
- Serrano for helping me debug this by email.) Changed the IA64 code to
- do something similar for similar reasons.
-
-[5.0alpha5 doesn't really exist, but it may have escaped.]
-
-Since 5.0alpha6:
- - -DREDIRECT_MALLOC was broken in alpha6. Fixed.
- - Cleaned up gc_ccp.h slightly, thus also causing the HP C++ compiler to
- accept it.
- - Removed accidental reference to dbg_mlc.c, which caused dbg_mlc.o to be
- linked into every executable.
- - Added PREFETCH to bitmap marker. Changed it to use the header cache.
- - GC_push_marked sometimes pushed one object too many, resulting in a
- segmentation fault in GC_mark_from_mark_stack. This was probably an old
- bug. It finally showed up in gctest on win32.
- - Gc_priv.h erroneously #defined GC_incremental to be TRUE instead of FALSE
- when SMALL_CONFIG was defined. This was no doubt a major performance bug for
- the default win32 configuration.
- - Removed -DSMALL_CONFIG from NT_MAKEFILE. It seemed like an anchronism now
- that the average PC has 64MB or so.
- - Integrated Bryce McKinley's patches for linux threads and dynamic loading
- from the libgcj tree. Turned on dynamic loading support for Linux/PPC.
- - Changed the stack finding code to use environ on HP/UX. (Thanks
- to Gustavo Rodriguez-Rivera for the suggestion.) This should probably
- be done on other platforms, too. Since I can't test those, that'll
- wait until after 5.0.
-
-Since 5.0alpha7:
- - Fixed threadlibs.c for linux threads. -DUSE_LD_WRAP was broken and
- -ldl was omitted. Fixed Linux stack finding code to handle
- -DUSE_LD_WRAP correctly.
- - Added MSWIN32 exception handler around marker, so that the collector
- can recover from root segments that are unmapped during the collection.
- This caused occasional failures under Windows 98, and may also be
- an issue under Windows NT/2000.
-
-Since 5.0
- - Fixed a gc.h header bug which showed up under Irix. (Thanks to
- Dan Sullivan.)
- - Fixed a typo in GC_double_descr in typd_mlc.c.
- This probably could result in objects described by array descriptors not
- getting traced correctly. (Thanks to Ben Hutchings for pointing this out.)
- - The block nearly full tests in reclaim.c were not correct for 64 bit
- environments. This could result in unnecessary heap growth under unlikely
- conditions.
-
-Since 5.1
- - dyn_load.c declared GC_scratch_last_end_ptr as an extern even if it
- was defined as a macro. This prevented the collector from building on
- Irix.
- - We quietly assumed that indirect mark descriptors were never 0.
- Our own typed allocation interface violated that. This could result
- in segmentation faults in the marker with typed allocation.
- - Fixed a _DUSE_MUNMAP bug in the heap block allocation code.
- (Thanks to Ben Hutchings for the patch.)
- - Taught the collector about VC++ handling array operator new.
- (Thanks again to Ben Hutchings for the patch.)
- - The two copies of gc_hdrs.h had diverged. Made one a link to the other
- again.
-
-Since 5.2 (A few 5.2 patches are not in 6.0alpha1)
- - Fixed _end declaration for OSF1.
- - There were lots of spurious leak reports in leak detection mode, caused
- by the fact that some pages were not being swept, and hence unmarked
- objects weren't making it onto free lists. (This bug dated back to 5.0.)
- - Fixed a typo in the liblinuxgc.so Makefile rule.
- - Added the GetExitCodeThread to Win32 GC_stop_world to (mostly) work
- around a Windows 95 GetOpenFileName problem. (Thanks to Jacob Navia.)
-
-Since 5.3
- - Fixed a typo that prevented compilation with -DUSE_3DNOW_PREFETCH.
- (Thanks to Shawn Wagner for actually testing this.)
- - Fixed GC_is_thread_stack in solaris_threads.c. It forgot to return a value
- in the common case. I wonder why nobody noticed?
- - Fixed another silly syntax problem in GC_double_descr. (Thanks to
- Fergus Henderson for finding it.)
- - Fixed a GC_gcj_malloc bug: It tended to release the allocator lock twice.
-
-Since 5.4 (A few 5.3 patches are not in 6.0alpha2)
- - Added HP/PA prefetch support.
- - Added -DDBG_HDRS_ALL and -DSHORT_DBG_HDRS to reduce the cost and improve
- the reliability of generating pointer backtrace information, e.g. in
- the Bigloo environment.
- - Added parallel marking support (-DPARALLEL_MARK). This currently
- works only under IA32 and IA64 Linux, but it shouldn't be hard to adapt
- to other platforms. This is intended to be a lighter-weight (less
- new code, probably not as scalable) solution than the work by Toshio Endo
- et al, at the University of Tokyo. A number of their ideas were
- reused, though the code wasn't, and the underlying data structure
- is significantly different. In particular, we keep the global mark
- stack as a single shared data structure, but most of the work is done
- on smaller thread-local mark stacks.
- - Changed GC_malloc_many to be cheaper, and to require less mutual exclusion
- with -DPARALLEL_MARK.
- - Added full support for thread local allocation under Linux
- (-DTHREAD_LOCAL_ALLOC). This is a thin veneer on GC_malloc_many, and
- should be easily portable to other platforms, especially those that
- support pthreads.
- - CLEAR_DOUBLE was not always getting invoked when it should have been.
- - GC_gcj_malloc and friends used different out of memory handling than
- everything else, probably because I forgot about one when I implemented
- the other. They now both call GC_oom_fn(), not GC_oom_action().
- - Integrated Jakub Jelinek's fixes for Linux/SPARC.
- - Moved GC_objfreelist, GC_aobjfreelist, and GC_words_allocd out of
- GC_arrays, and separately registered the first two as excluded roots.
- This makes code compiled with gc_inl.h less dependent on the
- collector version. (It would be nice to remove the inclusion of
- gc_priv.h by gc_inl.h completely, but we're not there yet. The
- locking definitions in gc_priv.h are still referenced.)
- This change was later coniditoned on SEPARATE_GLOBALS, which
- is not defined by default, since it involves a performance hit.
- - Register GC_obj_kinds separately as an excluded root region. The
- attempt to register it with GC_arrays was usually failing. (This wasn't
- serious, but seemed to generate some confusion.)
- - Moved backptr.h to gc_backptr.h.
-
-Since 6.0alpha1
- - Added USE_MARK_BYTES to reduce the need for compare-and-swap on platforms
- for which that's expensive.
- - Fixed a locking bug ib GC_gcj_malloc and some locking assertion problems.
- - Added a missing volatile to OR_WORD and renamed the parameter to
- GC_compare_and_swap so it's not a C++ reserved word. (Thanks to
- Toshio Endo for pointing out both of those.)
- - Changed Linux dynamic library registration code to look at /proc/self/maps
- instead of the rld data structures when REDIRECT_MALLOC is defined.
- Otherwise some of the rld data data structures may be prematurely garbage
- collected. (Thanks to Eric Benson for helping to track this down.)
- - Fixed USE_LD_WRAP a bit more, so it should now work without threads.
- - Renamed XXX_THREADS macros to GC_XXX_THREADS for namespace correctness.
- Tomporarily added some backward compatibility definitions. Renamed
- USE_LD_WRAP to GC_USE_LD_WRAP.
- - Many MACOSX POWERPC changes, some additions to the gctest output, and
- a few minor generic bug fixes. (Thanks to Dietmar Planitzer.)
-
-Since 6.0 alpha2
- - Fixed the /proc/self/maps code to not seek, since that apparently is not
- reliable across all interesting kernels.
- - Fixed some compilation problems in the absence of PARALLEL_MARK
- (introduced in alpha2).
- - Fixed an algorithmic problem with PARALLEL_MARK. If work needs to
- be given back to the main mark "stack", the BOTTOM entries of the local
- stack should be given away, not the top ones. This has substantial
- performance impact, especially for > 2 processors, from what I can tell.
- - Extracted gc_lock.h from gc_priv.h. This should eventually make it a
- bit easier to avoid including gc_priv.h in clients.
- - Moved all include files to include/ and removed duplicate links to the
- same file. The old scheme was a bad idea because it was too easy to get the
- copies out of sync, and many systems don't support hard links.
- Unfortunately, it's likely that I broke some of the non-Unix Makefiles in
- the process, although I tried to update them appropriately.
- - Removed the partial support for a copied nursery. It's not clear that
- this would be a tremendous win, since we don't consistently lose to
- generational copying collectors. And it would significantly complicate
- many things. May be reintroduced if/when it really turns out to win.
- - Removed references to IRIX_JDK_THREADS, since I believe there never
- were and never will be any clients.
- - Added some code to linux_threads.c to possibly support HPUX threads
- using the Linux code. Unfortunately, it doesn't work yet, and is
- currently disabled.
- - Added support under Linux/X86 for saving the call chain, both in (debug)
- objects for client debugging, and in GC_arrays._last_stack for GC
- debugging. This was previously supported only under Solaris. It is
- not enabled by default under X86, since it requires that code be compiled
- to explicitly dave frame pointers on the call stack. (With gcc this
- currently happens by default, but is often turned off explicitly.)
- To turn it on, define SAVE_CALL_CHAIN.
-
-Since 6.0 alpha3
- - Moved up the detection of mostly full blocks to the initiatiation of the
- sweep phase. This eliminates some lock conention in the PARALLEL_MARK case,
- as multiple threads try to look at mostly full blocks concurrently.
- - Restored the code in GC_malloc_many that grabs a prefix of the global
- free list. This avoids the case in which every GC_malloc_many call
- tries and fails to allocate a new heap block, and the returns a single
- object from the global free list.
- - Some minor fixes in new_hblk.c. (Attempted to build free lists in order
- of increasing addresses instead of decreasing addresses for cache performance
- reasons. But this seems to be only a very minor gain with -DEAGER_SWEEP,
- and a loss in other cases. So the change was backed out.)
- - Fixed some of the documentation. (Thanks in large part to Fergus
- Henderson.)
- - Fixed the Linux USE_PROC_FOR_LIBRARIES code to deal with apps that perform
- large numbers of mmaps. (Thanks to Eric Benson.) Also fixed that code to
- deal with short reads.
- - Added GC_get_total_bytes().
- - Fixed leak detection mode to avoid spurious messages under linuxthreads.
- (This should also now be easy for the other supported threads packages.
- But the code is tricky enough that I'm hesitant to do it without being able
- to test. Everything allocated in the GC thread support itself should be
- explicitly deallocated.)
- - Made it possible (with luck) to redirect malloc to GC_local_malloc.
-
-Since 6.0 alpha4
- - Changed the definition of GC_pause in linux_threads.c to use a volatile
- asm. Some versions of gcc apparently optimize away writes to local volatile
- variables. This caused poor locking behaviour starting at about
- 4 processors.
- - Added GC_start_blocking(), GC_end_blocking() calls and wrapper for sleep
- to linux_threads.c.
- The first two calls could be used to generally avoid sending GC signals to
- blocked threads, avoiding both premature wakeups and unnecessary overhead.
- - Fixed a serious bug in thread-local allocation. At thread termination,
- GC_free could get called on small integers. Changed the code for thread
- termination to more efficiently return left-over free-lists.
- - Integrated Kjetil Matheussen's BeOS support.
- - Rearranged the directory structure to create the doc and tests
- subdirectories.
- - Sort of integrated Eric Benson's patch for OSF1. This provided basic
- OSF1 thread support by suitably extending hpux_irix_threads.c. Based
- on earlier email conversations with David Butenhof, I suspect that it
- will be more reliable in the long run to base this on linux_threads.c
- instead. Thus I attempted to patch up linux_threads.c based on Eric's code.
- The result is almost certainly broken, but hopefully close enough that
- someone with access to a machine can pick it up.
- - Integrated lots of minor changes from the NetBSD distribution. (These
- were supplied by David Brownlee. I'm not sure about the original
- authors.)
- - Hacked a bit more on the HP/UX thread-support in linux_threads.c. It
- now appears to work in the absence of incremental collection. Renamed
- hpux_irix_threads.c back to irix_threads.c, and removed the attempt to
- support HPUX there.
- - Changed gc.h to define _REENTRANT in cases in which it should already
- have been defined. It is still safer to also define it on the command
- line.
-
-Since 6.0alpha5:
- - Changed the definition of DATASTART on ALPHA and IA64, where data_start
- and __data_start are not defined by earlier versions of glibc. This might
- need to be fixed on other platforms as well.
- - Changed the way the stack base and backing store base are found on IA64.
- This should now remain reliable on future kernels. But since it relies
- on /proc, it will no longer work in the simulated NUE environment.
- - Made the call to random() in dbg_mlc.c with -DKEEP_BACK_PTRS dependent
- on the OS. On non-Unix systems, rand() should be used instead. Handled
- small RAND_MAX. (Thanks to Peter Ross for pointing this out.)
- - Fixed the cord make rules to create the cord subdirectory, if necessary.
- (Thanks to Doug Moen.)
- - Changed fo_object_size calculation in finalize.c. Turned finalization
- of nonheap object into a no-op. Removed anachronism from GC_size()
- implementation.
- - Changed GC_push_dirty call in solaris_threads.c to GC_push_selected.
- It was missed in a previous renaming. (Thanks to Vladimir Tsichevski
- for pointing this out.)
- - Arranged to not not mask SIGABRT in linux_threads.c. (Thanks to Bryce
- McKinlay.)
- - Added GC_no_dls hook for applications that want to register their own
- roots.
- - Integrated Kjetil Matheussen's Amiga changes.
- - Added FREEBSD_STACKBOTTOM. Changed the X86/FreeBSD port to use it.
- (Thanks to Matthew Flatt.)
- - Added pthread_detach interception for platforms supported by linux_threads.c
- and irix_threads.c. Should also be added for Solaris?
- - Changed the USE_MMAP code to check for the case in which we got the
- high end of the address space, i.e. mem_ptr + mem_sz == 0. It appears
- that this can happen under Solaris 7. It seems to be allowed by what
- I would claim is an oversight in the mmap specification. (Thanks to Toshio
- Endo for pointing out the problem.)
- - Cleanup of linux_threads.c. Some code was originally cloned from
- irix_threads.c and now unnecessary. Some comments were obviously wrong.
- - (Mostly) fixed a longstanding problem with setting of dirty bits from
- a signal handler. In the presence of threads, dirty bits could get lost,
- since the etting of a bit in the bit vector was not atomic with respect
- to other updates. The fix is 100% correct only for platforms for which
- GC_test_and_set is defined. The goal is to make that all platforms with
- thread support. Matters only if incremental GC and threads are both
- enabled.
- - made GC_all_interior_pointers (a.k.a. ALL_INTERIOR_POINTERS) an
- initialization time, instead of build-time option. This is a
- nontrivial, high risk change. It should slow down the code measurably
- only if MERGE_SIZES is not defined, which is a very nonstandard
- configuration.
- - Added doc/README.environment, and implemented what it describes. This
- allows a number of additional configuration options to be set through
- the environment. It documents a few previously undocumented options.
- - Integrated Eric Benson's leak testing improvements.
- - Removed the option to throw away the beginning of each page (DISCARD_WORDS).
- This became less and less useful as processors enforce stricter alignment.
- And it hadn't been tested in ages, and was thus probably broken anyway.
-
-Since 6.0alpha6:
- - Added GC_finalizer_notifier. Fixed GC_finalize_on_demand. (The variable
- actually wasn't being tested at the right points. The build-time flag
- was.)
- - Added Tom Tromey's S390 Linux patch.
- - Added code to push GC_finalize_now in GC_push_finalizer_structures.
- (Thanks to Matthew Flatt.)
- - Added GC_push_gc_structures() to push all GC internal roots.
- - Integrated some FreeBSD changes from Matthew Flatt.
- - It looks like USRSTACK is not always correctly defined under Solaris.
- Hacked gcconfig.h to attempt to work around the problem. The result
- is not well tested. (Thanks again to Matthew Flatt for pointing this
- out. The gross hack is mine. - HB)
- - Added Ji-Yong Chung's win32 threads and C++ fixes.
- - Arranged for hpux_test_and_clear.s to no longer be needed or built.
- It was causing build problems with gas, and it's not clear this is
- better than the pthreads alternative on this platform.
- - Some MINGW32 fixes from Hubert Garavel.
- - Added Initial Hitachi SH4 port from Kaz Kojima.
- - Ported thread-local allocation and parallel mark code to HP/UX on PA_RISC.
- - Made include/gc_mark.h more public and separated out the really private
- pieces. This is probably still not quite sufficient for clients that
- want to supply their own kind of type information. But it's a start.
- This involved lots of identifier renaming to make it namespace clean.
- - Added GC_dont_precollect for clients that need complete control over
- the root set.
- - GC_is_visible didn't do the right thing with gcj objects. (Not that
- many people are likely to care, but ...)
- - Don't redefine read with GC_USE_LD_WRAP.
- - Initial port to LINUX/HP_PA. Incremental collection and threads are not
- yet supported. (Incremental collection should work if you have the
- right kernel. Threads may work with a sufficiently patched pthread
- library.)
- - Changed gcconfig.h to recognize __i386__ as an alternative to i386 in
- many places. (Thanks to Benjamin Lerman.)
- - Made win32_threads.c more tolerant of detaching a thread that it didn't
- know about. (Thanks to Paul Nash.)
- - Added Makefile.am and configure.in from gcc to the distribution, with
- minimal changes. For the moment, those are just placeholders. In the
- future, we're planning to switch to a GNU-style build environment for
- Un*x-like systems, though the old Makefile will remain as a backup.
- - Turned off STUBBORN_ALLOC by default, and added it back as a Makefile
- option.
- - Redistributed some functions between malloc.c and mallocx.c, so that
- simple statically linked apps no longer pull in mallocx.o.
- - Changed large object allocation to clear the first and last few words
- of each block before releassing the lock. Otherwise the marker could see
- objects with nonsensical type descriptors.
- - Fixed a couple of subtle problems that could result in not recognizing
- interior pointers from the stack. (I believe these were introduced
- in 6.0alpha6.)
- - GC_debug_free_inner called GC_free, which tried to reacquire the
- allocator lock, and hence deadlocked. (DBG_HDRS_ALL probably never worked
- with threads?)
- - Fixed several problems with back traces. Accidental references to a free
- list could cause the free list pointer to be overwritten by a back pointer.
- There seemed to be some problems with the encoding of root and finalizer
- references.
-
-Since 6.0alpha7:
- - Changed GC_debug_malloc_replacement and GC_debug_realloc_replacement
- so that they compile under Irix. (Thanks to Dave Love.)
- - Updated powerpc_macosx_mach_dep.s so that it works if the collector
- is in a dynamic library. (Thanks to Andrew Begel.)
- - Transformed README.debugging into debugging.html, updating and
- expanding it in the process. Added gcdescr.html and tree.html
- from the web site to the GC distribution.
- - Fixed several problems related to PRINT_BLACK_LIST. This involved
- restructuring some of the marker macros.
- - Fixed some problems with the sizing of objects with debug information.
- Finalization was broken KEEP_BACK_PTRS or PRINT_BLACK_LIST. Reduced the
- object size with SHORT_DEBUG_HDRS by another word.
- - The "Needed to allocate blacklisted ..." warning had inadvertently
- been turned off by default, due to a buggy test in allchblk.c. Turned
- it back on.
- - Removed the marker macros to deal with 2 pointers in interleaved fashion.
- They were messy and the performance improvement seemed minimal. We'll
- leave such scheduling issues to the compiler.
- - Changed Linux/PowerPC test to also check for __powerpc__ in response
- to a discussion on the gcc mailing list.
- - On Matthew Flatt's suggestion removed the "static" from the jmp_buf
- declaration in GC_generic_push_regs. This was causing problems in
- systems that register all of their own roots. It looks far more correct
- to me without the "static" anyway.
- - Fixed several problems with thread local allocation of pointerfree or
- typed objects. The collector was reclaiming thread-local free lists, since
- it wasn't following the link fields.
- - There was apparently a long-standing race condition related to multithreaded
- incremental collection. A collection could be started and a thread stopped
- between the memory unprotect system call and the setting of the
- corresponding dirt bit. I believe this did not affect Solaris or PCR, which
- use a different dirty-bit implementation. Fixed this by installing
- signal handlers with sigaction instead of signal, and disabling the thread
- suspend signal while in the write-protect handler. (It is unclear
- whether this scenario ever actually occurred. I found it while tracking
- down the following:)
- - Incremental collection did not cooperate correctly with the PARALLEL_MARK
- implementation of GC_malloc_many or the local_malloc primitves. It still
- doesn't work well, but it shouldn't lose memory anymore.
- - Integrated some changes from the gcc source tree that I had previously
- missed. (Thanks to Bryce McKinley for the reminder/diff.)
- - Added Makefile.direct as a copy of the default Makefile, which would
- normally be overwritten if configure is run.
- - Changed the gc.tar target in Makefile.direct to embed the version number
- in the gc directory name. This will affect future tar file distributions.
- - Changed the Irix dynamic library finding code to no longer try to
- eliminate writable text segments under Irix6.x, since that is probably no
- longer necessary, and can apparently be unsafe on occasion. (Thanks to
- Shiro Kawai for pointing this out.)
- - GC_cleanup with GC_DEBUG enabled passed a real object base address to
- GC_debug_register_finalizer_ignore_self, which expected a pointer past the
- debug header. Call GC_register_finalizer_ignore_self instead, even with
- debugging enabled. (Thanks to Jean-Daniel Fekete for catching this.)
- - The collector didn't build with call chain saving enabled but NARGS=0.
- (Thanks to Maarten Thibaut.)
- - Fixed up the GNU-style build files enough so that they work in some
- obvious cases.
- - Added initial port to Digital Mars compiler for win32. (Thanks to Walter
- Bright.)
-
-Since 6.0alpha8:
- - added README.macros.
- - Made gc.mak a symbolic link to work around winzip's tendency to ignore
- hard links.
- - Simplified the setting of NEED_FIND_LIMIT in os_dep.c, possibly breaking
- it on untested platforms.
- - Integrated initial GNU HURD port. (Thanks to Chris Lingard and Igor
- Khavkine.)
- - A few more fixes for Digital Mars compiler (Walter Bright).
- - Fixed gcc version recognition. Renamed OPERATOR_NEW_ARRAY to
- GC_OPERATOR_NEW_ARRAY. Changed GC_OPERATOR_NEW_ARRAY to be the default.
- It can be overridden with -DGC_NO_OPERATOR_NEW_ARRAY. (Thanks to
- Cesar Eduardo Barros.)
- - Changed the byte size to free-list mapping in thread local allocation
- so that size 0 allocations are handled correctly.
- - Fixed Linux/MIPS stackbottom for new toolchain. (Thanks to Ryan Murray.)
- - Changed finalization registration to invoke GC_oom_fn when it runs out
- of memory.
- - Removed lvalue cast in finalize.c. This caused some debug configurations
- not to build with some non-gcc compilers.
-
-Since 6.0alpha9:
- - Two more bug fixes for KEEP_BACK_PTRS and DBG_HDRS_ALL.
- - Fixed a stack clearing problem that resulted in SIGILL with a
- misaligned stack pointer for multithreaded SPARC builds.
- - Integrated another HURD patch (thanks to Igor Khavkine).
-
-Since 6.0:
- - Non-debug, atomic allocations could result in bogus smashed object
- reports with debugging on. (Thanks to Patrick Doyle for the small
- test case.)
- - Fixed GC_get_register_stack_base (Itanium only) to work around a glibc
- 2.2.4 bug.
- - Initial port to HP/UX on Itanium. Thread support and both 32 and 64
- bit ABIs appear to work. Parallel mark support doesn't yet, due to
- some inline assembly code issues. Thread local allocation does appear
- to work.
- - ifdef'ed out glibc2.1/Itanium workaround. I suspect nobody is using
- that combination anymore.
- - Added a patch to make new_gc_alloc.h usable with gcc3.0. (Thanks to
- Dimitris Vyzovitis for the patch.)
- - Debugged 64-bit support on HP/UX PA-RISC.
- - Turned on dynamic loading support for FreeBSD/ELF. (Thanks to Peter
- Housel.)
- - Unregistering of finalizers with debugging allocation was broken.
- (Thanks to Jani Kajala for the test case.)
- - Old finalizers were not returned correctly from GC_debug_register_finalizer.
- - Disabled MPROTECT_VDB for Linux/M68K based on a report that it doesn't work.
- - Cleaned up some statistics gathering code in reclaim.c (Thanks to Walter
- Bright.)
- - Added some support for OpenBSD/ELF/Linux. (Thanks to Suzuki Toshiya.)
- - Added Jakub Jelinek's patch to use dl_iterate_phdr for dynamic library
- traversal to dyn_load.c. Changed it to weakly reference dl_iterate_phdr,
- so that the old code is stilll used with old versions of glibc.
- - Cleaned up feature test macros for various threads packages and
- integrated (partially functional) FreeBSD threads code from Loren Rittle.
- It's likely that the cleanup broke something, since it touched lots of
- code. It's also likelly that it fixed some unreported bugs in the
- less common thread implementations, since some of the original code
- didn't stand up to close scrutiny. Support for the next pthreads
- implementation should be easier to add.
-
-Since 6.1alpha1:
- - No longer wrap read by default in multithreaded applications. It was
- pointed out on the libgcj list that this holds the allocation lock for
- way too long if the read blocks. For now, reads into the heap are
- broken with incremental collection. It's possible to turn this back on
- if you make sure that read calls don't block (e.g. by calling select
- first).
- - Fix ifdef in Solaris_threads.h to refer to GC_SOLARIS_THREADS.
- - Added check for environment variable GC_IGNORE_GCJ_INFO.
- - Added printing of stop-the-world GC times if GC_PRINT_STATS environment
- variable is set.
- - The calloc definition in leak_detector.h was missing parentheses, and
- realloc was missing a second argument to GC_REALLOC.
- (Thanks to Elrond (elrond<at>samba-tng.org).)
- - Added GC_PRINT_BACK_HEIGHT environment variable and associated
- code, mostly in the new file backgraph.c. See doc/README.environment.
- - Added -DUSE_GLOBAL_ALLOC to work around a Windows NT issue. (Thanks to
- Jonathan Clark.)
- - Integrated port to NEC EWS4800 (MIPS-based workstation, with somewhat
- different address-space layout). This may help for other machines with
- holes in the data segment. (Thanks to Hironori Sakamoto.)
- - Changed the order in which GC_push_roots and friends push things onto
- the mark stack. GC_push_all calls need to come first, since we can't
- necessarily recovere if those overflow the mark stack. (Thanks to
- Matthew Flatt for tracking down the problem.)
- - Some minor cleanups to mostly support the Intel compiler on Linux/IA64.
-
-Since 6.1 alpha2:
- - Minor cleanup on the gcconfig.h section for SPARC.
- - Minor fix to support Intel compiler for I386/Linux. (Thanks to Sven
- Hartrumpf.)
- - Added SPARC V9 (64-bit) support. (Thanks to Jeff Sturm.)
- - Restructured the way in which we determine whether or not to keep
- call stacks for debug allocation. By default SAVE_CALL_COUNT is
- now zero on all platforms. Added SAVE_CALL_NARGS parameters.
- If possible, use execinfo.h to capture call stack. (This should
- add support for a number of new platforms, though often at
- considerable runtime expense.)
- - Try to print symbolic information for call stacks. On Linux, we
- do this with a combination of execinfo.h and running addr2line in
- a separate process. This is both much more expensive and much more
- useful. Amazingly, it seems to be fast enough for most purposes.
- - Redefined strdup if -DREDIRECT_MALLOC is given.
- - Changed incremental collector and MPROTECT_VDB implementation so that,
- under favorable conditions, pointerfree objects are not protected.
- Added GC_incremental_protection_needs() to determine ahead of time whether
- pointerfree objects may be protected. Replaced GC_write_hint() with
- GC_remove_protection().
- - Added test for GC_ENABLE_INCREMENTAL environment variable.
- - Made GC_time_limit runtime configurable. Added GC_PAUSE_TIME_TARGET
- environment variable.
- - Eliminated GC_page_sz, a duplicate of GC_page_size.
- - Caused the Solaris and Irix thread creation primitives to call
- GC_init_inner().
-
-Since 6.1alpha3:
- - Fixed typo in sparc_mach_dep.S, preventing the 64-bit version from
- building. Increased 64-bit heap size limit in test.c slightly, since
- a functional SPARC collector seems to slightly exceed the old limits.
- (Thanks again to Jeff Sturm.)
- - Use NPRGREG in solaris_threads.c, thus printing all registers if things
- go wrong.
- - Added GC_MARKERS environment variable to allow use of a single marker
- thread on an MP without confusing the lock implementation.
- - Collect much less aggressively in incremental mode with GC_TIME_UNLIMITED.
- This is really a purely generational mode, and we can afford to
- postpone the collection until the heap is (nearly) full.
- - Remove read() wrapper for MPROTECT_VDB. It was causing more harm than
- good. It is often no longer needed if system calls avoid writing to
- pointerfull heap objects.
- - Fix MACOSX test in gcconfig.h. (Thanks to John Clements.)
- - Change GC_test_and_set so that it consistently has one argument.
- Add spaces to ::: in powerpc assembly code in gc_locks.h.
- (Thanks to Ryan Murray.)
- - Fixed a formatting error in dbg_mlc.c. Added prototype to GC_abort()
- declaration. (Thanks to Michael Smith.)
- - Removed "source" argument to GC_find_start(). Eliminate GC_FIND_START().
- - Added win32 recognition code in configure.in. Changed some of the
- dllimport/export defines in gc.h. (Thanks to Adam Megacz.)
- - GC_malloc_many didn't set hb_last_reclaimed when it called
- GC_reclaim_generic. (I'm not sure this matters much, but ...)
- - Allocating uncollectable objects with debug information sometimes
- allocated objects that were one byte too small, since uncollectable
- objects don't have the extra byte added at the end. (Thanks to
- Wink Saville for pointing this out.)
- - Added a bit more assertion checking to make sure that gcj objects
- on free lists never have a nonzero second word.
- - Replaced BCC_MAKEFILE with an up-to-date one. (Thanks to
- Andre Leiradella.)
- - Upgraded libtool, cinfigure.in and some related files to hopefully
- support NetBSD/SPARC. (Thanks to Adrian Bunk.) Unfortunately,
- libtool 1.4.2 seemed to be buggy due to missing quotes in several
- "test" invocations. Fixed those in the ltmain.sh script.
- - Some win32-specific patches, including the introduction of
- GC_CreateThread. (Thanks to Adam Megacz.)
- - Merged in gcj changes from Anthony Green to support embedded systems.
- - Tried to consistently rename preprocessed assembly files with a capital
- .S extension.
- - Use alpha_mach_dep.S on ALPHA again. It doesn't really matter, but this
- makes our distribution consistent with the gcc one, avoiding future merge
- problems.
- - Move GET_MEM definition into gcconfig.h. Include gcconfig.h slightly
- later in gc_priv.h to avoid forward references to ptr_t.
- - Add some testing of local allocation to test.c.
- - Change definition of INVALID_QTID in specific.h. The -1 value was used
- inconsistently, and too likely to collide with a valid stack address.
- Some general clean-up of specific.[ch]. Added assertions. (Thanks
- to Michael Smith for tracking down an intermittent bug to this
- general area. I'm not sure it has been squashed yet, however.)
- - On Pthread systems it was not safe to call GC_malloc() between fork()
- and exec(). According to the applicable standards, it doesn't appear
- to be safe to call malloc() or many other libc functions either, thus
- it's not clear this is fixable. Added experimental support for
- -DHANDLE_FORK in linux_threads.c which tries to support it. It may
- succeed if libc does the right thing. I'm not sure whether it does.
- (Thanks to Kenneth Schalk for pointing out this issue.)
- - Documented thread local allocation primitives to require an
- explicit GC_init call. GC_init_parallel is no longer declared to
- be a constructor function, since that isn't portable and often
- seems to lead to initialization order problems.
- - Changed gc_cpp.cc and gc_cpp.h in one more attempt to make them
- compatible with Visual C++ 6. (Thanks to Wink Saville for the
- patch.)
- - Some more patches for Linux on HP PA-RISC.
- - Added include/gc_allocator.h. It implements (hopefully) standard
- conforming (as opposed to SGI-style) allocators that allocate
- collectable (gc_allocator) or GC-traceable, but not collectable
- (traceable_allocator) objects. This borrows heavily from libstc++,
- which borrows heavily from the SGI implementation, this part of
- which was written by Matt Austern. Changed test_cpp.cc to very
- minimally test this.
- - On Linux/X86, retry mmap with a different start argument. That should
- allow the collector to use more (closer to 3GB) of the address space.
- (Thanks to Jeffrey Mark Siskind for tracking this down.)
- - Force 64 bit alignment with GCJ support. (Reflects Bryce McKinley's
- patch to the gcc tree.)
- - Refined the choice of sa_handler vs. sa_sigaction in GC_dirty_init
- to accomodate some glibc5 systems. (Thanks to Dan Fandrich for the
- patch.)
- - Compensated for the fact that current versions of glibc set
- __libc_stack_end incorrectly on Linux/IA64 while initialization code
- is running. This could cause the collector to miss 16 bytes of
- the memory stack if GC_malloc or friends where called before main().
- - Mostly integrated Takis Psarogiannakopoulos' port to DG/UX Inix 86.
- This will probably take another iteration to work, since his
- patch conflicted with the libtool upgrade.
- - Added README.arm.cross containing some information about cross-
- compiling to an ARM processor from Margaret Fleck.
-
-Since 6.1alpha4:
- - Added GC_finalizer_mem_freed, and changed some of the code that
- decided on heap expansion to look at it. Memory explicitly
- deallocated by finalizers essentially needs to be counted as reclaimed
- by the GC. Otherwise there are cases in which the heap can grow
- unboundedly. (Thanks to Mark Reichert for the test case.)
- - Integrated Adam Megacz patches to not scan dynamic libraries if
- we are compiling with gcc on win32. Otherwise we need structured
- exception handling to deal with asynchronously unmapped root
- segments, and gcc doesn't directly support that.
- - Integrated Anthony Green's patch to support Wine.
- - GC_OPERATOR_NEW_ARRAY was misspelled OPERATOR_NEW_ARRAY in several
- places, including gc_cpp.cc. (Thanks to Wink Saville for pointing
- this out.)
- - Integrated Loren James Rittle's Alpha FreeBSD patches. In
- response to Richard Henderson's suggestion, these also
- changed the declarations of symbols like _end on many platforms to
- that they wouldn't mistakenly be declared as short data symbols.
- - Integrated changes from the Debian distribution. (Thanks to Ryan Murray
- for pointing these out.) Fix C++ comments in POWERPC port. Add ARM32
- incremental GC support. Get rid of USE_GENERIC_PUSH_REGS for alpha/Linux,
- this time for real. Use va_copy to get rid of cord printf problems
- (finally).
- - Close file descriptor used to count cpus. Thanks to Jeff Sturm for
- pointing out the omission.
- - Don't just drop gcj free lists in GC_start_reclaim, since that can
- eventually cause the marker to see a bogus mark descriptor in the
- dropped objects. The usual symptom was a very intermittent segmentation
- fault in the marker. This mattered only if one of the GC_gcj_malloc
- variants was used. (Thanks to Michael Smith, Jeff Sturm, Bryce
- McKinley and Tom Tromey for helping to track this down.)
- - Fixed Linux and Solaris/64 SPARC configuration. (Thanks to David Miller,
- Jeff Sturm, Tom Tromey, and Christian Joensson.)
- - Fixed a typo in strdup definition. (Thanks to Gerard A Allan.)
- - Changed Makefile.direct to invoke $(CC) to assemble alpha_mach_dep.S.
- This is needed on Linux. I'm not sure whether it's better or worse
- on Tru64.
- - Changed gc_cpp.h once more to declare operator new and friends only in
- a Microsoft environment. This may need further fine tuning. (Thanks to
- Johannes Schmidt for pointing out that the older code breaks on gcc3.0.4.)
- - Don't ever override strdup if it's already macro defined. (Thanks to
- Adnan Ali for pointing out the problem.)
- - Changed gc_cpp.h yet again to also overload placement new. Due to the
- C++ overloading rules, the other overloaded new operations otherwise hide
- placement new, which causes many STL uses to break. (Thanks to Reza
- Shahidi for reporting this, and to Matt Austern for proposing a fix.)
- - Integrated cygwin pthreads support from Dan Bonachea.
- - Turn on DYNAMIC_LOADING for NetBSD. (Thanks to Krister Walfridsson.)
- - Changed printing code to print more complete GC times.
- - Applied Mark Mitchell's Irix patch to correct some bitrot.
- - Clarified which object-printing routines in dbg_mlc.c should hold
- the allocation lock. Restructured the code to allow reasonable object
- printing with -DREDIRECT_MALLOC.
- - Fix the Linux mmap code to always start with 0x1000 as the initial hint.
- Minor patches for 64-bit AIX, particularly to STACKBOTTOM.
- (Thanks again to Jeffrey Mark Siskind.)
- - Renamed "SUSPENDED" flag for Solaris threads support to avoid a conflict
- with a system header. (Thanks to Philp Brown.)
- - Cause win32_threads.c to handle an out of range stack pointer correctly,
- though currently with a warning. (Thanks to Jonathan Clark for
- observing that win32 applications may temporarily use the stack
- pointer for other purposes, and suggesting a fix. Unfortunately, it's
- not clear that there is a complete solution to this problem.)
-
-Since 6.1alpha5:
- - Added GC_MAXIMUM_HEAP_SIZE environment variable.
- - Fix configure.in for MIPS/LINUX. (Thanks to H.J. Lu.)
- - Double page hash table size for -DLARGE_CONFIG.
- - Integrated Bo Thorsen's X86-64 support.
- - STACKBOTTOM definition for LINUX/MIPS was partially changed back.
- (Thanks to H.J. Lu and Hiroshi Kawashima for resolving this.)
- - Replaced all occurrences of LINUX_DATA_START in gcconfig.h with
- SEARCH_FOR_DATA_START. It doesn't hurt to falll back to a search.
- And __data_start doesn't seem to get defined correctly of the GC
- library is loaded with LD_PRELOAD, e.g. for leak detection.
- - If the GC_find_leak environment variable is set, do a
- atexit(GC_gcollect) to give us at least one chance to detect leaks.
- This may report some very benign leaks, but ...
- - Addeded REDIRECT_FREE. It's necessary if we want leak detection with
- LD_PRELOAD.
- - Defer printing of leaked objects, as for smashed objects.
- - Fixed process and descriptor leak in GC_print_callers. Try for
- line number even if we got function name.)
- - Ported parallel GC support and thread local allocation to Alpha.
- Not yet well-tested.
- - Added GC_DUMP_REGULARLY and added finalization statistics to GC_dump().
- - Fixed Makefile.am to mention alpha_mach_dep.S instead of the defunct
- alpha_mach_dep.s. (Thanks to Fergus Henderson.)
- - Incorporated a change to new_gc_alloc.h, suggested by Johannes Schmidt,
- which should make it work with gcc3.1. (I would still like to encourage
- use of gc_allocator.h instead.)
- - Use alpha_mach_dep.S only on Linux. (It's not clear that this is
- optimal, but it otherwise didn't build on Tru64. Thanks to Fergus
- Henderson.)
- - Added ifdef to guard free() in os_dep.c. Otherwise we get a
- compilation error on Irix. (Thanks to Dai Sato.)
- - Added an experimental version of GC_memalign to mallocx.c. This can't
- always work, since we don't handle alignment requests in the hblk-level
- allocator, and we can't handle arbitrary pointer displacements unless
- GC_all_interior_pointers is enabled. But it should work for alignment
- requests up to HBLKSIZE. This is not yet documented in the standard
- places.
- - Finally debugged the OSF1/Tru64 thread support. This needs more testing,
- since I needed to add a somewhat unconvincing workaround for signal
- delivery issues that I don't yet completely understand. But it does
- pass my tests, even in parallel GC mode. Incremental GC support is
- disabled if thread support is enabled, due to the signal issues.
- - Eliminated name-space-incorrect definition of _cdecl from gc_cpp.h.
- - Added GC_debug_malloc_replacement and GC_debug_realloc_replacement
- declarations to gc.h. On IA64, this is required for REDIRECT_MALLOC
- to work correctly with these.
- - Fixed Linux USE_PROC_FOR_LIBRARIES to work with a 64-bit /proc format.
-
-Since 6.1:
- - Guard the test for GC_DUMP_REGULARLY in misc.c with
- "#ifndef NO_DEBUGGING". Otherwise it fails to build with NO_DEBUGGING
- defined. (Thanks to Manuel Serrano.)
- - Message about retrying suspend signals was incorrectly generated even when
- flag was not set.
- - Cleaned up MACOSX/NEXT root registration code. There was apparently a
- separate ifdef case in GC_register_data_segments() for no reason.
- - Removed MPROTECT_VDB for MACOSX port, based on one negative report.
- - Arrange for gc.h and friends to be correctly installed with GNU-style
- "make install".
- - Enable the GNU-style build facility include C++ support in the library
- with --enable-cplusplus. (Thanks to Thomas Maier for some of the patch.)
- - Mark from GC_thread_key in linux_threads.c, in case that's allocated
- from the garbage collected heap, as it is with our own thread-specific
- storage implementation. (Thanks to Jeff Sturm.)
- - Mark all free list header blocks if they are heap allocated. This avoids
- some unnecessary tracing. And it remains correct if we clear the
- root set. (Thanks to Jeff Sturm for identifying the bug.)
- - Improved S390/Linux support. Add S390/Linux 64-bit support. (Thanks
- to Ulrich Weigand.)
- - Corrected the spelling of GC_{M,C}ALLOC_EXPLICTLY_TYPED to
- GC_{M,C}ALLOC_EXPLICITLY_TYPED in gc_typed.h. This is technically
- an interface change. Based on the fact that nobody reported this,
- I suspect/hope there were no clients.
- - Cleaned up gc_typed.h so that (1) it adds an extern "C" declaration
- when appropriate, (2) doesn't generate references to undefined internal
- macros, and (3) allows easier manual construction of descriptors.
- - Close the file descriptor used by GC_print_address_map().
- - Set the "close-on-exec" bit for various file descriptors maintained
- for the collector's internal use.
- - Added a hack to find memory segments owned by the system allocator
- under win32. Based on my tests, this tends to eventually find all
- segments, though it may take a while. There appear to be cleaner,
- but slower solutions under NT/XP. But they rely on an API that's
- unsupported under 9X.
- - Changed Linux PowerPC stack finding to LINUX_STACKBOTTOM. (Thanks
- to Akira Tagoh for pointing out that HEURISTIC1 doesn't work on
- 64-bit kernels.)
- - Added GC_set_free_space_divisor to avoid some Windows dll issues.
- - Added FIXUP_POINTER, POINTER_SHIFT, POINTER_MASK to allow preprocessing
- of candidate pointers for tagging, etc.
- - Always lock around GC_notify_full_gc(). Simplified code for
- invoking GC_notify_full_gc().
- - Changed the way DATASTART is defined on FreeBSD to be robust against
- an unmapped page after etext. (Thanks to Hironori Sakamoto for
- tracking down the intermittent failure.)
- - Made GC_enable() and GC_disable() official. Deprecated direct update
- of GC_dont_gc. Changed GC_gcollect to be a noop when garbage collection
- is disabled.
- - Call GC_register_dynamic_libraries before stopping the world on Linux,
- in order to avoid a potential deadlock due to the dl_iterate_phdr lock.
- - Introduced a more general mechanism for platform-dependent code to
- decide whether the main data segment should be handled separately
- from dynamic libraries, or registered by GC_register_dynamic_libraries.
- The latter is more reliable and easier on Linux with dl_iterate_phdr.
-
-Since 6.2alpha1:
- - Fixed the completely broken FreeBSD code in 6.2alpha1. (Thanks to
- Hironori Sakamoto for the patch.)
- - Changed IRIX reference in dbg_mlc.c to IRIX5. (Thanks to Marcus Herbert.)
- - Attempted to work around the problems with .S filenames and the SGI
- compiler. (Reported by several people. Untested.)
- - Worked around an HP/UX make issue with the GNU-style build process.
- - Fixed the --enable-cplusplus build machinery to allow builds without
- a C++ compiler. (That was always the intent ...)
- - Changed the debugging allocation macros to explicitly pass the return
- address for Linux and XXXBSD on hardware for which we can't get stack
- traces. Use __builtin_return_address(0) to generate it when possible.
- Some of the configuration work was cleaned up (good) and moved to gc.h
- (bad, but necessary). This should make leak detection more useful
- on a number of platforms. (Thanks to Fabian Thylman for the suggestion.)
- - Fixed compilation problems in dbg_mlc.c with GC_ADD_CALLER.
- - Bumped revision number for dynamic library.
-
-Since 6.2alpha2:
- - Don't include execinfo.h in os_dep.c when it's not needed, and may not exist.
-
-Since 6.2alpha3:
- - Use LINUX_STACKBOTTOM for >= glibc2.2 on Linux/MIPS. (See Debian bug
- # 177204)
- - Integrated Jeff Sturm and Jesse Rosenstock's MACOSX threads patches.
- - Integrated Grzegorz Jakacki's substantial GNU build patch. "Make dist"
- should now work for the GNU build process. Documentation files
- are installed under share/gc.
- - Tweaked gc_cpp.h to again support the Borland compiler. (Thanks to
- Rene Girard for pointing out the problems.)
- - Updated BCC_MAKEFILE (thanks to Rene Girard).
- - Added GC_ASSERT check for minimum thread stack size.
- - Added --enable-gc-assertions.
- - Added some web documentation to the distribution. Updated it in the
- process.
- - Separate gc_conf_macros.h from gc.h.
- - Added generic GC_THREADS client-defined macro to set the appropriate
- GC_XXX_THREADS internal macro. (gc_config_macros.h.)
- - Add debugging versions of _ignore_off_page allocation primitves.
- - Moved declarations of GC_make_closure and GC_debug_invoke_finalizer
- from gc.h to gc_priv.h.
- - Reset GC_fail_count even if only a small allocation succeeds.
- - Integrated Brian Alliet's patch for dynamic library support on Darwin.
- - gc_cpp.h's gc_cleanup destructor called GC_REGISTER_FINALIZER_IGNORE_SELF
- when it should have called the lower case version, since it was
- explicitly computing a base pointer.
-
-Since 6.2alpha4:
- - GC_invoke_finalizers could, under rare conditions, set
- GC_finalizer_mem_freed to an essentially random value. This could
- possibly cause unbounded heap growth for long-running applications
- under some conditions. (The bug was introduced in 6.1alpha5, and
- is not in gcc3.3. Thanks to Ben Hutchings for finding it.)
- - Attempted to sanitize the various DLL macros. GC_USE_DLL disappeared.
- GC_DLL is used instead. All internal tests are now on GC_DLL.
- README.macros is now more precise about the intended meaning.
- - Include DllMain in the multithreaded win32 version only if the
- collector is actually built as a dll. (Thanks to Mohan Embar for
- a version of the patch.)
- - Hide the cygwin threadAttach/Detach functions. They were violating our
- namespace rules.
- - Fixed an assertion in GC_check_heap_proc. Added GC_STATIC_ASSERT.
- (Thanks again to Ben Hutchings.)
- - Removed some obsolete definitions for Linux/PowerPC in gcconfig.h.
- - CORD_cat was not rebalancing unbalanced trees in some cases, violating
- a CORD invariant. Also tweaked the rebalancing rule for
- CORD_cat_char_star. (Thanks to Alexandr Petrosian for the bug report
- and patch.)
- - Added hand-coded structured exception handling support to mark.c.
- This should enable support of dynamic libraries under win32 with
- gcc-compiled code. (Thanks to Ranjit Mathew for the patch.)
- Turned on dynamic library scanning for win32/gcc.
- - Removed some remnants of read wrapping. (Thanks to Kenneth Schalk.)
- GC_USE_LD_WRAP ws probably broken in recent versions.
- - The build could fail on some platforms since gcconfig.h could include
- declarations mentioning ptr_t, which was not defined, e.g. when if_mach
- was built. (Thanks to Yann Dirson for pointing this out.) Also
- cleaned up tests for GC_PRIVATE_H in gcconfig.h a bit.
- - The GC_LOOP_ON_ABORT environment variable interfered with incremental
- collection, since the write fault handler was erroneously overridden.
- Handlers are now set up in the correct order.
- - It used to be possible to call GC_mark_thread_local_free_lists() while
- the world was not stopped during an incremental GC. This was not safe.
- Fortunately, it was also unnecessary. Added GC_world_stopped flag
- to avoid it. (This caused occasional crashes in GC_set_fl_marks
- with thread local allocation and incremental GC. This probably happened
- primarily on old, slow multiprocessors.)
- - Allowed overriding of MAX_THREADS in win32_threads.c from the build
- command line. (Patch from Yannis Bres.)
- - Taught the IA64/linux code to determine the register backing store base from
- /proc/self/maps after checking the __libc symbol, but before guessing.
- (__libc symbols are on the endangered list, and the guess is likely to not
- always be right for 2.6 kernels.) Restructured the code to read and parse
- /proc/self/maps so it only exists in one place (all platforms).
- - The -DUSE_PROC_FOR_LIBRARIES code was broken on Linux. It claimed that it
- also registered the main data segment, but didn't actually do so. (I don't
- think anyone actually uses this configuration, but ...)
- - Made another attempt to get --enablecplusplus to do the right thing.
- Since there are unavoidable problems with C programs linking against a
- dynamic library that includes C++ code, I separated out the c++ code into
- libgccpp.
-
-Since 6.2alpha5:
- - There was an extra underscore in the name of GC_save_registers_in_stack
- for NetBSD/SPARC. (Thanks to Jaap Boender for the patch.)
- - Integrated Brian Alliet's patch for Darwin. This restructured the
- linuxthreads/pthreads support to separate generic pthreads support
- from more the system-dependent thread-stopping code. I believe this
- should make it easier to eliminate the code duplication between
- pthreads platforms in the future. The patch included some other
- code cleanups.
- - Integrated Dan Bonachea's patch to support AIX threads. This required
- substantial manual integration, mostly due to conflicts with other
- recent threads changes. It may take another iteration to
- get it to work.
- - Removed HPUX/PA-RISC support from aix_irix_threads.c. It wasn't used
- anyway and it cluttered up the code. And anything we can do to migrate
- towards generic pthreads support is a good thing.
- - Added a more explicit test for tracing of function arguments to test.c.
- (Thanks to Dan Grayson.)
- - Added Akira Tagoh's PowerPC64 patch.
- - Fixed some bit rot in the Cygwin port. (Thanks to Dan Bonachea for
- pointing it out.) Gc.h now includes just windows.h, not winbase.h.
- - Declared GC_save_regs_in_stack() in gc_priv.h. Remove other declarations.
- - Changed --enable-cplusplus to use automake consitionals. The old way
- confused libtool. "Make install" didn't work correctly for the old version.
- Previously --enable-cplusplus was broken on cygwin.
- - Changed the C version of GC_push_regs to fail at compile time if it is
- generated with an empty body. This seems to have been the cause of one
- or two subtle failures on unusual platforms. Those failures should
- now occur at build time and be easily fixable.
-
-Since 6.2alpha6:
- - Integrated a second round of Irix/AIX patches from Dan Bonachea.
- Renamed mips_sgi_mach_dep.S back to mips_sgi_mach_dep.s, since it requires
- the Irix assembler to do the C preprocessing; gcc -E doesn't work.
- - Fixed Makefile.direct for DARWIN. (Thanks to Manuel Serrano.)
- - There was a race between GC_pthread_detach and thread exit that could
- result in a thread structure being deallocated by GC_pthread_detach
- eventhough it was still needed by the thread exit code. (Thanks to
- Dick Porter for the small test case that allowed this to be debugged.)
- - Fixed version parsing for non-alpha versions in acinclude.m4 and
- version checking in version.h.
-
-Since 6.2:
- - Integrated some NetBSD patches forwarded to me by Marc Recht. These
- were already in the NetBSD package.
- - GC_pthread_create waited for the semaphore even if pthread_create failed.
- Thanks to Dick Porter for the pthread_support.c patch. Applied the
- analogous fix for aix_irix_threads.c.
- - Added Rainer Orth's Tru64 fixes.
- - The check for exceeding the thread table size in win32 threadDetach
- was incorrect. (Thanks to Alexandr Petrosian for the patch.)
- - Applied Andrew Begel's patch to correct some reentrancy issues
- with dynamic loading on Darwin.
- - GC_CreateThread() was neglecting to duplicate the thread handle in
- the table. (Thanks to Tum Nguyen for the patch.)
- - Pass +ESdbgasm only on PA-RISC machines with vendor compiler.
- (Thanks to Roger Sayle for the patch.)
- - Applied more AIX threads patches from Scott Ananian.
-
-Since 6.3alpha1:
- - Reenabled I_HOLD_LOCK assertion in aix_irix_threads.h.
- - Put back the WINABI qualifier for GC_CreateThread. (Thanks to
- Danny Smith for the patch. 6.3alpha1 had the qualifier in one place
- but not elsewhere, which was clearly wrong.)
- - Sometimes explicitly define __private_extern__ before DARWIN dyld.h
- include. (Thanks to Andreas Tobker for postting the patch.)
- - Included signal.h from pthread_support.c. Removed GC_looping_handler,
- which was dead code.
- - GC_find_start was misdeclared by gc_pmark.h if PRINT_BLACK_LIST was
- defined. (Thanks to Glauco Masotti for testing and reporting this.)
- Changed GC_find_start to never just return 0. According to its
- comment it doesn't, and it's unclear that's correct.
- - GC_alloc_large had several largely compensating bugs in the
- computation of GC_words_wasted. (It was confused about bytes vs.
- words in two places.)
- - Integrated Slava Sysoltev's patch to support more recent versions of
- the Intel compiler on IA64/Linux.
- - Changed win32 spinlock initialization to conditionally set a spin count.
- (Emmanual Stumpf pointed out that enabling this makes a large performance
- difference on win32 multiprocessors.) Also cleaned up the win32 spinlock
- initialization code a bit.
- - Fixed thread support for HP/UX/IA64. The register backing store base for
- the main thread was sometimes not set correctly. (Thanks to Laurent
- Morichetti.)
- - Added -DEMPTY_GETENV_RESULTS flag to work around Wine problem.
- - Declare GC_stack_alloc and GC_stack_free in solaris_threads.h to
- avoid 64-bit size mismatches. (Thanks to Bernie Solomon.)
- - Fixed GC_generic_push_regs to avoid a potential and very unfortunate
- tail call optimization. This could lead to prematurely reclaimed
- objects on configurations that used the generic routine and the new
- build infrastructure (which potentially optimizes mach_dep.c).
- This was a serious bug, but it's unclear whether it has resulted in
- any real failures.
- - Fixed CORD_str to deal with signed characters. (Thanks to Alexandr
- Petrosian for noticing the problem and supplying the patch.)
- - Merged a couple of NOSYS/ECOS tests into os_dep.c from gcj. (Thanks
- to Anthony Green.)
- - Partially merged a win32 patch from Ben Hutchings, and substantially
- revised other parts of win32_threads.c. It had several problems.
- Under MinGW with a statically linked library, the main thread was
- not registered. Cygwin detached threads leaked thread descriptors.
- There were several race conditions. For now, unfortunately the
- static threads limit remains, though we increased it, and made table
- traversal cost depend on the actual thread count.
- There is also still some code duplication with pthread_support.c.
- (Thread descriptors did become much smaller, since Ben Hutchings
- removed the thread context from them.)
- - Integrated a Solaris configure.in patch from Rainer Orth.
- - Added GC_IGNORE_FB and associated warning to very partially address
- the issue of the collector treating a mapped frame buffer as part
- of the root set. (Thanks to David Peroutka for providing some
- insight. More would be helpful. Is there anything that can be used
- to at least partially identify such memory segments?)
-
-Since 6.3alpha2:
- - Removed -DSMALL_CONFIG from BCC_MAKEFILE.
- - Changed macros to test for an ARM processor (Patch from Richard Earnshaw.)
- - Mostly applied a DJGPP patch from Doug Kaufman. Especially Makefile.dj
- had suffered from serious bit rot.
- - Rewrote GC_apply_to_maps, eliminating an off-by-one subscript error,
- and a call to alloca (for lcc compatibility).
- - Changed USE_MUNMAP behavior on posixy platforms to immediately remap
- the memory with PROT_NONE instead of unmapping it. The latter risks
- an intervening mmap grabbing the address space out from underneath us.
- Updated this code to reflect a cleaner patch from Ulrich Drepper.
- - Replaced _T with _Tp in new_gc_alloc.h to avoid a MACOS X conflict.
- (Patch from Andrew Begel.)
- - Dynamically choose whether or not lock should spin on win32. (Thanks
- to Maurizio Vairani for the patch.) This may be a significant performance
- improvement for win32.
- - Fix Makefile.direct to actually include NT_STATIC_THREADS_MAKEFILE
- in the distribution. (Again thanks to Maurizio Vairani.)
- - Maybe_install_looping_handler() was accidentally exported, violating
- our name space convention.
- - Made os_dep.c use sigsetjmp and SA_NODEFER for NetBSD. (Thanks to
- Christian Limpach.) (I generalized the patch to use sigsetjmp on all
- UNIX_LIKE platforms, admittedly a slightly risky move. But it may avoid
- similar problems on some other platforms. I also cleaned up the defn
- of UNIX_LIKE a bit. - Hans)
- - Integrated Andrew Begel's Darwin threads patch, adjusted according to
- some of Fergus Hendersons's comments. (Patch didn't apply cleanly,
- errors are possible.)
- - Added another test or two for the Intel 8.0 compiler to avoid
- confusing it with gcc. The single-threaded collector should now build
- with icc, at least on ia64.
-
-Since 6.3alpha3:
- - USE_MMAP was broken by confusion in the code dealing with USE_MMAP_ANON.
- (This was pointed out, and fixes were suggested by several other people.)
- - Darwin supprt was broken in alpha3 as a result of my misintegration of
- Andrew Begel's patches. Fixed with another patch from Andrew Begel.
- - A new sanity check in pthread_stop_world.c:GC_push_all_stacks() was
- overly aggressive. We may collect from an unregistered thread during
- thread creation. Fixed by explicitly checking for that case. (Added
- GC_in_thread_creation.)
-
-Since 6.3alpha4:
- - Fix & vs && typo in GC_generic_malloc and
- GC_generic_malloc_ignore_off_page. (Propagated from the gcc tree.)
- - Removed SA_NODEFER hack from NetBSD and Solaris write-protect handler.
- (According to Christian Limpach, the NetBSD problem is fixed.
- Presumably so is the Solaris 2.3 problem.)
- - Removed placement delete from gc_cpp.h for the SGI compiler.
- (Thanks to Simon Gornall for the patch.)
- - Changed semantics of the GC_IGNORE_FB environment variable, based
- on experimentation by Nicolas Cannasse pointing out that the old
- interpretation was useless. We still need help in identifying win32
- graphics memory mappings. The current "solution" is a hack.
- - Removed "MAKEOVERRIDES =" from Makefile.am and thus Makefile.in.
- It probably made more sense in the gcc context.
- - Explicitly ensure that NEED_FIND_LIMIT is defined for {Open,Net}BSD/ELF.
- - Replaced USE_HPUX_TLS macro by USE_COMPILER_TLS, since gcc often
- supports the same extension on various platforms.
- - Added some basic (completely untested) defines for win64, in support
- of future work.
- - Declared GC_jmp_buf in os_dep.s as JMP_BUF instead of jmp_buf, fixing
- a memory overwrite bug on Solaris and perhaps other platforms.
- - Added 0 != __libc_stack_end test to GC_linux_stack_base. (Thanks to Jakub
- Jelinek, both for the patch, and for explaining the problem to me.)
- Otherwise "prelink"ing could cause the collector to fail.
- - Changed default thread local storage implementation to USE_PTHREAD_SPECIFIC
- for HP/UX with gcc. The compiler-based implementation appears to work
- only with the vendor compiler.
- - Export GC_debug_header_size and GC_USR_PTR_FROM_BASE from gc_mark.h,
- making client mark code cleaner and less dependent on GC version.
- - Export several new procedures and GC_generic_malloc from gc_mark.h
- to support user-defined kinds. Use the new procedures to replace existing
- code in gcj_mlc.c and typd_mlc.c.
- - Added support for GC_BACKTRACES.
- - Fixed a remaining problem in CORD_str with signed characters. (Thanks
- to Alexandr Petrosian for the patch.)
- - Removed supposedly redundant, but very buggy, definitions of finalizer
- macros from javaxfc.h. Fortunately this file probably has no users.
- The correct declarations were already in gc.h.
- - Also need to set GC_in_thread_creation while waiting for GC during
- thread termination, since it is also possible to collect from an
- unregistered thread in that case.
- - Define NO_GETENV for Windows CE, since getenv doesn't appear to exist.
- + some other minor WinCE fixes. (Thanks to Alain Novak.)
- - Added GC_register_describe_type_fn.
- - Arrange for debugging finalizer registration to ignore non-heap
- registrations, since the regular version of the routine also behaves
- that way.
- - GC_gcj_malloc and friends need to check for finalizers waiting to be run.
- One of the more obscure allocation routines with missing a LOCK() call.
- - Fixed cvtres invocations in NT_MAKEFILE and NT_STATIC_THREADS_MAKEFILE
- to work with VS.NET.
- - Cleaned up GC_INIT calls in test. Updated gc.man to encourage GC_INIT
- use in portable code.
- - Taught the GC to use libunwind if --enable-full-debug is specified on
- IA64 and libunwind is present.
- - The USE_MUNMAP code could get confused about the age of a block and
- prematurely unmap it. GC_unmap_old had a bug related to wrapping of
- GC_gc_no. GC_freehblk and GC_merge_unmapped didn't maintain
- hb_last_reclaimed reasonably when blocks were merged. The code was
- fixed to reflect original intent, but that may not always be an
- improvement. See todo list item.
-
-Since 6.3alpha5:
- - Define USE_GENERIC_PUSH_REGS for NetBSD/M68K.
- - Fixed the X86_64 PREFETCH macros to correctly handle ia32e (which uses
- different prefetch instructions from AMD64). (Thanks to H.J. Lu.)
- - GC_config_macros.h did not correctly define GC_WIN32_THREADS from
- GC_THREADS.
- - Added simple_example.html.
- - Merged Andrew Gray's patch to correctly restore signal handlers on
- FreeBSD.
- - Merged a patch from Andreas Jaeger to deal with prefetch-related warnings
- on x86-64. Added some other casts so that the PREFETCH macros
- always get a ptr_t argument. Removed some casts inthe PREFETCH
- implementations.
- - At Jesse Jones suggestion: Added a header guard for gc_allocator.h
- and changed GC_debug_free to clobber contents of deallocated object.
- - The signal masking code in pthread_stop_world.c contained some errors.
- In particular SIGSEGV was masked in the handler, in spite of the fact that
- it wrote to the heap. This could lead to an uncaught SIGSEGV, which
- apparently became much more likely in Linux 2.6. Also fixed some
- typos, and reduced code duplication in the same area.
- - Remove ltconfig, clean up configure messages for DGUX (thanks to
- Adrian Bunk for the patches).
- - Integrated NetBSD/OpenBSD patches from Marc Recht and Matthias Drochner.
-
-Since gc6.3alpha6:
- - Compile test_cpp.cc with CXXCOMPILE instead of COMPILE.
- - Very large allocations could cause a collector hang. Correct
- calculation of GC_collect_at_heapsize.
- - GC_print_hblkfreelist printed some bogus results if USE_MUNMAP
- was defined.
- - The generic GC_THREADS macro didn't work correctly on Solaris,
- since the implementation failed to include gc_config_macros.h
- before deciding whether or not to compile the rest of the file.
- - Threadlibs.c failed to expand the generic GC_THREADS macro.
- - Correct MacOSX thread stop code. (Thanks to Dick Porter.)
- - SMALL_OBJ definition was off by one. This could cause crashes
- at startup. (Thanks to Zoltan Varga for narrowing this down to
- a trivial test case.)
- - Integrate Paolo Molara's patch to deal with a race in the Darwin
- thread stopping code.
- - Changed X86_64 implementation to use SA_SIGINFO in the MPROTECT_VDB
- implementation. The old approach appears to have been broken by
- recent kernels.
- - Add GC_ATTR_UNUSED to eliminate a warning in gc_allocator.h. (Thanks
- to Andrew Begel.)
- - Fix GC_task_self declaration in os_dep.c. (Thanks to Andrew Pinski.)
- - Increase INITIAL_BUF_SZ in os_dep.c for Solaris /proc reads.
-
-To do:
- - The USE_MUNMAP code should really use a separate data structure
- indexed by physical page to keep track of time since last use of
- a page. Using hblk headers means we lose track of ages when
- blocks are merged, and we can't unmap pages that have been allocated and
- dropped by the blacklisting code. I suspect both of these matter.
- - A dynamic libgc.so references dlopen unconditionally, but doesn't link
- against libdl.
- - GC_proc_fd for Solaris is not correctly updated in response to a
- fork() call. Thus incremental collection in the child won't work
- correctly. (Thanks to Ben Cottrell for pointing this out.)
- - --enable-redirect-malloc is mostly untested and known not to work
- on some platforms.
- - There seem to be outstanding issues on Solaris/X86, possibly with
- finding the data segment starting address. Information/patches would
- be appreciated.
- - Very large root set sizes (> 16 MB or so) could cause the collector
- to abort with an unexpected mark stack overflow. (Thanks again to
- Peter Chubb.) NOT YET FIXED. Workaround is to increase the initial
- size.
- - The SGI version of the collector marks from mmapped pages, even
- if they are not part of dynamic library static data areas. This
- causes performance problems with some SGI libraries that use mmap
- as a bitmap allocator. NOT YET FIXED. It may be possible to turn
- off DYNAMIC_LOADING in the collector as a workaround. It may also
- be possible to conditionally intercept mmap and use GC_exclude_static_roots.
- The real fix is to walk rld data structures, which looks possible.
- - Incremental collector should handle large objects better. Currently,
- it looks like the whole object is treated as dirty if any part of it
- is.
-
diff --git a/boehm-gc/doc/README.cmake b/boehm-gc/doc/README.cmake
new file mode 100644
index 00000000000..3eb347c06a5
--- /dev/null
+++ b/boehm-gc/doc/README.cmake
@@ -0,0 +1,50 @@
+
+CMAKE
+-----
+
+Win32 binaries (both 32- and 64-bit) can be built using CMake. CMake is an
+open-source tool like automake - it generates makefiles.
+
+Some preliminary work has been done to make this work on other platforms, but
+the support is not yet complete.
+
+CMake will generate:
+
+ Borland Makefiles
+ MSYS Makefiles
+ MinGW Makefiles
+ NMake Makefiles
+ Unix Makefiles
+ . Visual Studio project files
+ Visual Studio 6
+ Visual Studio 7
+ Visual Studio 7 .NET 2003
+ Visual Studio 8 2005
+ Visual Studio 8 2005 Win64
+ Visual Studio 9 2008
+ Visual Studio 9 2008 Win64
+ Watcom WMake
+
+
+BUILD PROCESS
+-------------
+
+ . install cmake (cmake.org)
+ . add directory containing cmake.exe to %PATH%
+ . run cmake from the gc root directory, passing the target with -G:
+ eg.
+ > cmake -G "Visual Studio 8 2005"
+ use the gc.sln file generated by cmake to build gc
+ . you can also run cmake from a build directory to build outside of
+ the source tree. Just specify the path to the source tree:
+ eg.
+ > mkdir build
+ > cd build
+ > cmake .. -G "Visual Studio 8 2005"
+
+
+INPUT
+-----
+
+The main input to cmake are the CMakeLists.txt files in each directory. For
+help, goto cmake.org.
diff --git a/boehm-gc/doc/README.contributors b/boehm-gc/doc/README.contributors
deleted file mode 100644
index fd5c95f2297..00000000000
--- a/boehm-gc/doc/README.contributors
+++ /dev/null
@@ -1,57 +0,0 @@
-This is an attempt to acknowledge early contributions to the garbage
-collector. Later contributions should instead be mentioned in
-README.changes.
-
-HISTORY -
-
- Early versions of this collector were developed as a part of research
-projects supported in part by the National Science Foundation
-and the Defense Advance Research Projects Agency.
-
-The garbage collector originated as part of the run-time system for
-the Russell programming language implementation. The first version of the
-garbage collector was written primarily by Al Demers. It was then refined
-and mostly rewritten, primarily by Hans-J. Boehm, at Cornell U.,
-the University of Washington, Rice University (where it was first used for
-C and assembly code), Xerox PARC, SGI, and HP Labs. However, significant
-contributions have also been made by many others.
-
-Some other contributors:
-
-More recent contributors are mentioned in the modification history in
-README.changes. My apologies for any omissions.
-
-The SPARC specific code was originally contributed by Mark Weiser.
-The Encore Multimax modifications were supplied by
-Kevin Kenny (kenny@m.cs.uiuc.edu). The adaptation to the IBM PC/RT is largely
-due to Vernon Lee, on machines made available to Rice by IBM.
-Much of the HP specific code and a number of good suggestions for improving the
-generic code are due to Walter Underwood.
-Robert Brazile (brazile@diamond.bbn.com) originally supplied the ULTRIX code.
-Al Dosser (dosser@src.dec.com) and Regis Cridlig (Regis.Cridlig@cl.cam.ac.uk)
-subsequently provided updates and information on variation between ULTRIX
-systems. Parag Patel (parag@netcom.com) supplied the A/UX code.
-Jesper Peterson(jep@mtiame.mtia.oz.au), Michel Schinz, and
-Martin Tauchmann (martintauchmann@bigfoot.com) supplied the Amiga port.
-Thomas Funke (thf@zelator.in-berlin.de(?)) and
-Brian D.Carlstrom (bdc@clark.lcs.mit.edu) supplied the NeXT ports.
-Douglas Steel (doug@wg.icl.co.uk) provided ICL DRS6000 code.
-Bill Janssen (janssen@parc.xerox.com) supplied the SunOS dynamic loader
-specific code. Manuel Serrano (serrano@cornas.inria.fr) supplied linux and
-Sony News specific code. Al Dosser provided Alpha/OSF/1 code. He and
-Dave Detlefs(detlefs@src.dec.com) also provided several generic bug fixes.
-Alistair G. Crooks(agc@uts.amdahl.com) supplied the NetBSD and 386BSD ports.
-Jeffrey Hsu (hsu@soda.berkeley.edu) provided the FreeBSD port.
-Brent Benson (brent@jade.ssd.csd.harris.com) ported the collector to
-a Motorola 88K processor running CX/UX (Harris NightHawk).
-Ari Huttunen (Ari.Huttunen@hut.fi) generalized the OS/2 port to
-nonIBM development environments (a nontrivial task).
-Patrick Beard (beard@cs.ucdavis.edu) provided the initial MacOS port.
-David Chase, then at Olivetti Research, suggested several improvements.
-Scott Schwartz (schwartz@groucho.cse.psu.edu) supplied some of the
-code to save and print call stacks for leak detection on a SPARC.
-Jesse Hull and John Ellis supplied the C++ interface code.
-Zhong Shao performed much of the experimentation that led to the
-current typed allocation facility. (His dynamic type inference code hasn't
-made it into the released version of the collector, yet.)
-
diff --git a/boehm-gc/doc/README.cords b/boehm-gc/doc/README.cords
index 3485e0145af..5730a7f8307 100644
--- a/boehm-gc/doc/README.cords
+++ b/boehm-gc/doc/README.cords
@@ -9,8 +9,7 @@ Permission to modify the code and to distribute modified code is granted,
provided the above notices are retained, and a notice that the code was
modified is included with the above copyright notice.
-Please send bug reports to Hans-J. Boehm (Hans_Boehm@hp.com or
-boehm@acm.org).
+Please send bug reports to Hans-J. Boehm.
This is a string packages that uses a tree-based representation.
See cord.h for a description of the functions provided. Ec.h describes
@@ -32,7 +31,7 @@ http://www.sgi.com/tech/stl/ropeimpl.html is missing a figure.)
All of these are descendents of the "ropes" in Xerox Cedar.
-de.c is a very dumb text editor that illustrates the use of cords.
+cord/tests/de.c is a very dumb text editor that illustrates the use of cords.
It maintains a list of file versions. Each version is simply a
cord representing the file contents. Nonetheless, standard
editing operations are efficient, even on very large files.
@@ -50,4 +49,3 @@ of arguments in non-standard-conforming ways. This code is known to
break on some platforms, notably PowerPC. It should be possible to
build the remainder of the library (everything but cordprnt.c) on
any platform that supports the collector.
-
diff --git a/boehm-gc/doc/README.darwin b/boehm-gc/doc/README.darwin
new file mode 100644
index 00000000000..7de01e87a48
--- /dev/null
+++ b/boehm-gc/doc/README.darwin
@@ -0,0 +1,144 @@
+Darwin/MacOSX Support - December 16, 2003
+
+== Build Notes ==
+
+Building can be done with autoconf as normal. If you want to build
+a Universal library using autoconf, you need to disable dependency
+tracking and specify your desired architectures in CFLAGS:
+
+CFLAGS="-arch ppc -arch i386 -arch x86_64" ./configure --disable-dependency-tracking
+
+
+== Important Usage Notes ==
+
+GC_init() MUST be called before calling any other GC functions. This
+is necessary to properly register segments in dynamic libraries. This
+call is required even if you code does not use dynamic libraries as the
+dyld code handles registering all data segments.
+
+When your use of the garbage collector is confined to dylibs and you
+cannot call GC_init() before your libraries' static initializers have
+run and perhaps called GC_malloc(), create an initialization routine
+for each library to call GC_init():
+
+#include <gc/gc.h>
+extern "C" void my_library_init() { GC_init(); }
+
+Compile this code into a my_library_init.o, and link it into your
+dylib. When you link the dylib, pass the -init argument with
+_my_library_init (e.g. gcc -dynamiclib -o my_library.dylib a.o b.o c.o
+my_library_init.o -init _my_library_init). This causes
+my_library_init() to be called before any static initializers, and
+will initialize the garbage collector properly.
+
+Note: It doesn't hurt to call GC_init() more than once, so it's best,
+if you have an application or set of libraries that all use the
+garbage collector, to create an initialization routine for each of
+them that calls GC_init(). Better safe than sorry.
+
+The incremental collector is still a bit flaky on darwin. It seems to
+work reliably with workarounds for a few possible bugs in place however
+these workaround may not work correctly in all cases. There may also
+be additional problems that I have not found.
+
+Thread-local GC allocation will not work with threads that are not
+created using the GC-provided override of pthread_create(). Threads
+created without the GC-provided pthread_create() do not have the
+necessary data structures in the GC to store this data.
+
+
+== Implementation Information ==
+
+Darwin/MacOSX support is nearly complete. Thread support is reliable on
+Darwin 6.x (MacOSX 10.2) and there have been reports of success on older
+Darwin versions (MacOSX 10.1). Shared library support had also been
+added and the gc can be run from a shared library.
+
+Thread support is implemented in terms of mach thread_suspend and
+thread_resume calls. These provide a very clean interface to thread
+suspension. This implementation doesn't rely on pthread_kill so the
+code works on Darwin < 6.0 (MacOSX 10.1). All the code to stop and
+start the world is located in darwin_stop_world.c.
+
+Since not all uses of the GC enable clients to override pthread_create()
+before threads have been created, the code for stopping the world has
+been rewritten to look for threads using Mach kernel calls. Each
+thread identified in this way is suspended and resumed as above. In
+addition, since Mach kernel threads do not contain pointers to their
+stacks, a stack-walking function has been written to find the stack
+limits. Given an initial stack pointer (for the current thread, a
+pointer to a stack-allocated local variable will do; for a non-active
+thread, we grab the value of register 1 (on PowerPC)), it
+will walk the PPC Mach-O-ABI compliant stack chain until it reaches the
+top of the stack. This appears to work correctly for GCC-compiled C,
+C++, Objective-C, and Objective-C++ code, as well as for Java
+programs that use JNI. If you run code that does not follow the stack
+layout or stack pointer conventions laid out in the PPC Mach-O ABI,
+then this will likely crash the garbage collector.
+
+The original incremental collector support unfortunately no longer works
+on recent Darwin versions. It also relied on some undocumented kernel
+structures. Mach, however, does have a very clean interface to exception
+handing. The current implementation uses Mach's exception handling.
+
+Much thanks goes to Andrew Stone, Dietmar Planitzer, Andrew Begel,
+Jeff Sturm, and Jesse Rosenstock for all their work on the
+Darwin/OS X port.
+
+-Brian Alliet
+
+== gc_cpp.h usage ==
+
+Replacement of operator new and delete is apparently not supported with
+dynamic libraries. This means that applications using gc_cpp.h
+(including the built-in test) will probably not work correctly with
+the collector in a dynamic library, unless special care is taken.
+
+See
+http://article.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/1421
+for some details.
+
+- Hans Boehm (based on information from Andrew Begel)
+
+
+== Older Information (Most of this no longer applies to the current code) ==
+
+While the GC should work on MacOS X Server, MacOS X and Darwin, I only tested
+it on MacOS X Server.
+I've added a PPC assembly version of GC_push_regs(), thus the setjmp() hack is
+no longer necessary. Incremental collection is supported via mprotect/signal.
+The current solution isn't really optimal because the signal handler must decode
+the faulting PPC machine instruction in order to find the correct heap address.
+Further, it must poke around in the register state which the kernel saved away
+in some obscure register state structure before it calls the signal handler -
+needless to say the layout of this structure is no where documented.
+Threads and dynamic libraries are not yet supported (adding dynamic library
+support via the low-level dyld API shouldn't be that hard).
+
+The original MacOS X port was brought to you by Andrew Stone.
+
+
+June, 1 2000
+
+Dietmar Planitzer
+
+Note from Andrew Begel:
+
+One more fix to enable gc.a to link successfully into a shared library for
+MacOS X. You have to add -fno-common to the CFLAGS in the Makefile. MacOSX
+disallows common symbols in anything that eventually finds its way into a
+shared library. (I don't completely understand why, but -fno-common seems to
+work and doesn't mess up the garbage collector's functionality).
+
+Feb 26, 2003
+
+Jeff Sturm and Jesse Rosenstock provided a patch that adds thread support.
+GC_MACOSX_THREADS should be defined in the build and in clients. Real
+dynamic library support is still missing, i.e. dynamic library data segments
+are still not scanned. Code that stores pointers to the garbage collected
+heap in statically allocated variables should not reside in a dynamic
+library. This still doesn't appear to be 100% reliable.
+
+Mar 10, 2003
+Brian Alliet contributed dynamic library support for MacOSX. It could also
+use more testing.
diff --git a/boehm-gc/doc/README.dj b/boehm-gc/doc/README.dj
index 613bc423cb1..786e81a743d 100644
--- a/boehm-gc/doc/README.dj
+++ b/boehm-gc/doc/README.dj
@@ -1,12 +1,9 @@
-[Original version supplied by Xiaokun Zhu <xiaokun@aero.gla.ac.uk>]
-[This version came mostly from Gary Leavens. ]
Look first at Makefile.dj, and possibly change the definitions of
RM and MV if you don't have rm and mv installed.
Then use Makefile.dj to compile the garbage collector.
For example, you can do:
- make -f Makefile.dj test
+ make -f Makefile.dj test
All the tests should work fine.
-
diff --git a/boehm-gc/doc/README.environment b/boehm-gc/doc/README.environment
index 97a13dc3e45..79752f7834a 100644
--- a/boehm-gc/doc/README.environment
+++ b/boehm-gc/doc/README.environment
@@ -1,150 +1,187 @@
-The garbage collector looks at a number of environment variables which are
-then used to affect its operation. These are examined only on Un*x-like
-platforms and win32.
+The garbage collector looks at a number of environment variables which are,
+then, used to affect its operation.
-GC_INITIAL_HEAP_SIZE=<bytes> - Initial heap size in bytes. May speed up
- process start-up.
+GC_INITIAL_HEAP_SIZE=<bytes> - Initial heap size in bytes. May speed up
+ process start-up. Optionally, may be
+ specified with a multiplier ('k', 'M' or 'G')
+ suffix.
-GC_MAXIMUM_HEAP_SIZE=<bytes> - Maximum collected heap size.
+GC_MAXIMUM_HEAP_SIZE=<bytes> - Maximum collected heap size. Allows
+ a multiplier suffix.
GC_LOOP_ON_ABORT - Causes the collector abort routine to enter a tight loop.
- This may make it easier to debug, such a process, especially
- for multithreaded platforms that don't produce usable core
- files, or if a core file would be too large. On some
- platforms, this also causes SIGSEGV to be caught and
- result in an infinite loop in a handler, allowing
- similar debugging techniques.
-
-GC_PRINT_STATS - Turn on as much logging as is easily feasible without
- adding signifcant runtime overhead. Doesn't work if
- the collector is built with SMALL_CONFIG. Overridden
- by setting GC_quiet. On by default if the collector
- was built without -DSILENT.
+ This may make it easier to debug, such a process, especially
+ for multi-threaded platforms that don't produce usable core
+ files, or if a core file would be too large. On some
+ platforms, this also causes SIGSEGV to be caught and
+ result in an infinite loop in a handler, allowing
+ similar debugging techniques.
+
+GC_PRINT_STATS - Turn on GC logging. Not functional with SMALL_CONFIG.
+
+GC_LOG_FILE - The name of the log file. Stderr by default. Not functional
+ with SMALL_CONFIG.
+
+GC_ONLY_LOG_TO_FILE - Turns off redirection of GC stdout and stderr to the log
+ file specified by GC_LOG_FILE. Has no effect unless
+ GC_LOG_FILE is set. Not functional with SMALL_CONFIG.
+
+GC_PRINT_VERBOSE_STATS - Turn on even more logging. Not functional with
+ SMALL_CONFIG.
GC_DUMP_REGULARLY - Generate a GC debugging dump GC_dump() on startup
- and during every collection. Very verbose. Useful
- if you have a bug to report, but please include only the
- last complete dump.
-
-GC_BACKTRACES=<n> - Generate n random backtraces (for heap profiling) after
- each GC. Collector must have been built with
- KEEP_BACK_PTRS. This won't generate useful output unless
- most objects in the heap were allocated through debug
- allocators. This is intended to be only a statistical
- sample; individual traces may be erroneous due to
- concurrent heap mutation.
+ and during every collection. Very verbose. Useful
+ if you have a bug to report, but please include only the
+ last complete dump.
+
+GC_COLLECT_AT_MALLOC=<n> - Override the default value specified by
+ GC_COLLECT_AT_MALLOC macro. Has no effect unless
+ GC is built with GC_COLLECT_AT_MALLOC defined.
+
+GC_BACKTRACES=<n> - Generate n random back-traces (for heap profiling) after
+ each GC. Collector must have been built with
+ KEEP_BACK_PTRS. This won't generate useful output unless
+ most objects in the heap were allocated through debug
+ allocators. This is intended to be only a statistical
+ sample; individual traces may be erroneous due to
+ concurrent heap mutation.
GC_PRINT_ADDRESS_MAP - Linux only. Dump /proc/self/maps, i.e. various address
- maps for the process, to stderr on every GC. Useful for
- mapping root addresses to source for deciphering leak
- reports.
+ maps for the process, to stderr on every GC. Useful for
+ mapping root addresses to source for deciphering leak
+ reports.
GC_NPROCS=<n> - Linux w/threads only. Explicitly sets the number of processors
- that the GC should expect to use. Note that setting this to 1
- when multiple processors are available will preserve
- correctness, but may lead to really horrible performance,
- since the lock implementation will immediately yield without
- first spinning.
+ that the GC should expect to use. Note that setting this to 1
+ when multiple processors are available will preserve
+ correctness, but may lead to really horrible performance,
+ since the lock implementation will immediately yield without
+ first spinning.
-GC_MARKERS=<n> - Linux w/threads and parallel marker only. Set the number
- of marker threads. This is normaly set to the number of
- processors. It is safer to adjust GC_MARKERS than GC_NPROCS,
- since GC_MARKERS has no impact on the lock implementation.
+GC_MARKERS=<n> - Only if compiled with PARALLEL_MARK. Set the number
+ of marker threads. This is normally set to the number of
+ processors. It is safer to adjust GC_MARKERS than GC_NPROCS,
+ since GC_MARKERS has no impact on the lock implementation.
GC_NO_BLACKLIST_WARNING - Prevents the collector from issuing
- warnings about allocations of very large blocks.
- Deprecated. Use GC_LARGE_ALLOC_WARN_INTERVAL instead.
+ warnings about allocations of very large blocks.
+ Deprecated. Use GC_LARGE_ALLOC_WARN_INTERVAL instead.
GC_LARGE_ALLOC_WARN_INTERVAL=<n> - Print every nth warning about very large
- block allocations, starting with the nth one. Small values
- of n are generally benign, in that a bounded number of
- such warnings generally indicate at most a bounded leak.
- For best results it should be set at 1 during testing.
- Default is 5. Very large numbers effectively disable the
- warning.
+ block allocations, starting with the nth one. Small values
+ of n are generally benign, in that a bounded number of
+ such warnings generally indicate at most a bounded leak.
+ For best results it should be set at 1 during testing.
+ Default is 5. Very large numbers effectively disable the
+ warning.
GC_IGNORE_GCJ_INFO - Ignore the type descriptors implicitly supplied by
- GC_gcj_malloc and friends. This is useful for debugging
- descriptor generation problems, and possibly for
- temporarily working around such problems. It forces a
- fully conservative scan of all heap objects except
- those known to be pointerfree, and may thus have other
- adverse effects.
+ GC_gcj_malloc and friends. This is useful for debugging
+ descriptor generation problems, and possibly for
+ temporarily working around such problems. It forces a
+ fully conservative scan of all heap objects except
+ those known to be pointer-free, and may thus have other
+ adverse effects.
GC_PRINT_BACK_HEIGHT - Print max length of chain through unreachable objects
- ending in a reachable one. If this number remains
- bounded, then the program is "GC robust". This ensures
- that a fixed number of misidentified pointers can only
- result in a bounded space leak. This currently only
- works if debugging allocation is used throughout.
- It increases GC space and time requirements appreciably.
- This feature is still somewhat experimental, and requires
- that the collector have been built with MAKE_BACK_GRAPH
- defined. For details, see Boehm, "Bounding Space Usage
- of Conservative Garbage Collectors", POPL 2001, or
- http://lib.hpl.hp.com/techpubs/2001/HPL-2001-251.html .
+ ending in a reachable one. If this number remains
+ bounded, then the program is "GC robust". This ensures
+ that a fixed number of misidentified pointers can only
+ result in a bounded space leak. This currently only
+ works if debugging allocation is used throughout.
+ It increases GC space and time requirements appreciably.
+ This feature is still somewhat experimental, and requires
+ that the collector have been built with MAKE_BACK_GRAPH
+ defined. For details, see Boehm, "Bounding Space Usage
+ of Conservative Garbage Collectors", POPL 2001, or
+ http://lib.hpl.hp.com/techpubs/2001/HPL-2001-251.html .
GC_RETRY_SIGNALS, GC_NO_RETRY_SIGNALS - Try to compensate for lost
- thread suspend signals in linux_threads.c. On by
- default for GC_OSF1_THREADS, off otherwise. Note
- that this does not work around a possible loss of
- thread restart signals. This seems to be necessary for
- some versions of Tru64. Since we've previously seen
- similar issues on some other operating systems, it
- was turned into a runtime flag to enable last-minute
- work-arounds.
-
-GC_IGNORE_FB[=<n>] - (Win32 only.) Try to avoid treating a mapped
- frame buffer as part of the root set. Certain (higher end?)
- graphics cards seems to result in the graphics memory mapped
- into the user address space as writable memory.
- Unfortunately, there seems to be no systematic way to
- identify such memory. Setting the environment variable to n
- causes the collector to ignore mappings longer than n MB.
- The default value of n is currently 15. (This should cover
- a 16 MB graphics card, since the mapping appears to be slightly
- shorter than all of graphics memory. It will fail if a dll
- writes pointers to collectable objects into a data segment
- whose length is >= 15MB. Empirically that's rare, but
- certainly possible.) WARNING: Security sensitive applications
- should probably disable this feature by setting
- GC_disallow_ignore_fb, or by building with -DNO_GETENV,
- since small values could force collection of reachable
- objects, which is conceivably a (difficult to exploit)
- security hole. GC_IGNORE_FB values less than 3 MB
- are never honored, eliminating this risk for most,
- but not all, applications. This feature is likely to disappear
- if/when we find a less disgusting "solution".
+ thread suspend signals in linux_threads.c. On by
+ default for GC_OSF1_THREADS, off otherwise. Note
+ that this does not work around a possible loss of
+ thread restart signals. This seems to be necessary for
+ some versions of Tru64. Since we've previously seen
+ similar issues on some other operating systems, it
+ was turned into a runtime flag to enable last-minute
+ work-arounds.
+
+GC_USE_GETWRITEWATCH=<n> - Only if MPROTECT_VDB and GWW_VDB are both defined
+ (Win32 only). Explicitly specify which strategy of
+ keeping track of dirtied pages should be used.
+ If n=0 then GetWriteWatch() is not used (falling back to
+ protecting pages and catching memory faults strategy)
+ else the collector tries to use GetWriteWatch-based
+ strategy (GWW_VDB) first if available.
+
+GC_DISABLE_INCREMENTAL - Ignore runtime requests to enable incremental GC.
+ Useful for debugging.
The following turn on runtime flags that are also program settable. Checked
only during initialization. We expect that they will usually be set through
other means, but this may help with debugging and testing:
GC_ENABLE_INCREMENTAL - Turn on incremental collection at startup. Note that,
- depending on platform and collector configuration, this
- may involve write protecting pieces of the heap to
- track modifications. These pieces may include pointerfree
- objects or not. Although this is intended to be
- transparent, it may cause unintended system call failures.
- Use with caution.
+ depending on platform and collector configuration, this
+ may involve write protecting pieces of the heap to
+ track modifications. These pieces may include
+ pointer-free objects or not. Although this is intended
+ to be transparent, it may cause unintended system call
+ failures. Use with caution.
GC_PAUSE_TIME_TARGET - Set the desired garbage collector pause time in msecs.
- This only has an effect if incremental collection is
- enabled. If a collection requires appreciably more time
- than this, the client will be restarted, and the collector
- will need to do additional work to compensate. The
- special value "999999" indicates that pause time is
- unlimited, and the incremental collector will behave
- completely like a simple generational collector. If
- the collector is configured for parallel marking, and
- run on a multiprocessor, incremental collection should
- only be used with unlimited pause time.
+ This only has an effect if incremental collection is
+ enabled. If a collection requires appreciably more time
+ than this, the client will be restarted, and the collector
+ will need to do additional work to compensate. The
+ special value "999999" indicates that pause time is
+ unlimited, and the incremental collector will behave
+ completely like a simple generational collector. If
+ the collector is configured for parallel marking, and
+ run on a multiprocessor, incremental collection should
+ only be used with unlimited pause time.
+
+GC_FULL_FREQUENCY - Set the desired number of partial collections between full
+ collections. Matters only if GC_incremental is set.
+ Not functional with SMALL_CONFIG.
+
+GC_FREE_SPACE_DIVISOR - Set GC_free_space_divisor to the indicated value.
+ Setting it to larger values decreases space consumption
+ and increases GC frequency.
+
+GC_UNMAP_THRESHOLD - Set the desired memory blocks unmapping threshold (the
+ number of sequential garbage collections for which
+ a candidate block for unmapping should remain free). The
+ special value "0" completely disables unmapping.
+
+GC_FORCE_UNMAP_ON_GCOLLECT - Turn "unmap as much as possible on explicit GC"
+ mode on (overrides the default value). Has no effect on
+ implicitly-initiated garbage collections. Has no effect if
+ memory unmapping is disabled (or not compiled in) or if the
+ unmapping threshold is 1.
GC_FIND_LEAK - Turns on GC_find_leak and thus leak detection. Forces a
- collection at program termination to detect leaks that would
- otherwise occur after the last GC.
+ collection at program termination to detect leaks that would
+ otherwise occur after the last GC.
+
+GC_FINDLEAK_DELAY_FREE - Turns on deferred freeing of objects in the
+ leak-finding mode (see the corresponding macro
+ description for more information).
+
+GC_ABORT_ON_LEAK - Causes the application to be terminated once leaked or
+ smashed objects are found.
GC_ALL_INTERIOR_POINTERS - Turns on GC_all_interior_pointers and thus interior
- pointer recognition.
+ pointer recognition.
GC_DONT_GC - Turns off garbage collection. Use cautiously.
+
+GC_USE_ENTIRE_HEAP - Set desired GC_use_entire_heap value at start-up. See
+ the similar macro description in README.macros.
+
+GC_TRACE=addr - Intended for collector debugging. Requires that the collector
+ have been built with ENABLE_TRACE defined. Causes the debugger
+ to log information about the tracing of address ranges
+ containing addr. Typically addr is the address that contains
+ a pointer to an object that mysteriously failed to get marked.
+ Addr must be specified as a hexadecimal integer.
diff --git a/boehm-gc/doc/README.ews4800 b/boehm-gc/doc/README.ews4800
new file mode 100644
index 00000000000..d4ea32aa14d
--- /dev/null
+++ b/boehm-gc/doc/README.ews4800
@@ -0,0 +1,80 @@
+GC on EWS4800
+-------------
+
+1. About EWS4800
+ EWS4800 is 32bit/64bit workstation.
+
+ Vender: NEC Corporation
+ OS: UX/4800 R9.* - R13.* (SystemV R4.2)
+ CPU: R4000, R4400, R10000 (MIPS)
+
+2. Compiler
+
+ 32bit:
+ Use ANSI C compiler.
+ CC = /usr/abiccs/bin/cc
+
+ 64bit:
+ Use 64bit ANSI C compiler.
+ CC = /usr/ccs64/bin/cc
+ AR = /usr/ccs64/bin/ar
+
+3. ELF file format
+ *** Caution: The following infomation is empirical. ***
+
+ 32bit:
+ ELF file has an unique format. (See a.out(4) and end(3C).)
+
+ &_start
+ : text segment
+ &etext
+ DATASTART
+ : data segment (initialized)
+ &edata
+ DATASTART2
+ : data segment (uninitialized)
+ &end
+
+ Here, DATASTART and DATASTART2 are macros of GC, and are defined as
+ the following equations. (See include/private/gcconfig.h.)
+ The algorithm for DATASTART is similar with the function
+ GC_SysVGetDataStart() in os_dep.c.
+
+ DATASTART = ((&etext + 0x3ffff) & ~0x3ffff) + (&etext & 0xffff)
+
+ Dynamically linked:
+ DATASTART2 = (&_gp + 0x8000 + 0x3ffff) & ~0x3ffff
+
+ Statically linked:
+ DATASTART2 = &edata
+
+ GC has to check addresses both between DATASTART and &edata, and
+ between DATASTART2 and &end. If a program accesses between &etext
+ and DATASTART, or between &edata and DATASTART2, the segmentation
+ error occurs and the program stops.
+
+ If a program is statically linked, there is not a gap between
+ &edata and DATASTART2. The global symbol &_DYNAMIC_LINKING is used
+ for the detection.
+
+ 64bit:
+ ELF file has a simple format. (See end(3C).)
+
+ _ftext
+ : text segment
+ _etext
+ _fdata = DATASTART
+ : data segment (initialized)
+ _edata
+ _fbss
+ : data segment (uninitialized)
+ _end = DATAEND
+
+--
+Hironori SAKAMOTO
+
+
+When using the new "configure; make" build process, please
+run configure with the --disable-shared option. "Make check" does not
+yet pass with dynamic libraries. Ther reasons for that are not yet
+understood. (HB, paraphrasing message from Hironori SAKAMOTO.)
diff --git a/boehm-gc/doc/README.linux b/boehm-gc/doc/README.linux
index 1d0fd4c3fb6..dc0fa543dc2 100644
--- a/boehm-gc/doc/README.linux
+++ b/boehm-gc/doc/README.linux
@@ -11,7 +11,7 @@ Incremental GC is generally supported.
Dynamic libraries are supported on an ELF system. A static executable
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
-The collector appears to work reliably with Linux threads, but beware
+The collector appears to work reliably with Linux threads, but beware
of older versions of glibc and gdb.
The garbage collector uses SIGPWR and SIGXCPU if it is used with
@@ -19,17 +19,17 @@ Linux threads. These should not be touched by the client program.
To use threads, you need to abide by the following requirements:
-1) You need to use LinuxThreads (which are included in libc6).
+1) You need to use LinuxThreads or NPTL (which are included in libc6).
The collector relies on some implementation details of the LinuxThreads
- package. It is unlikely that this code will work on other
+ package. This code may not work on other
pthread implementations (in particular it will *not* work with
MIT pthreads).
-2) You must compile the collector with -DGC_LINUX_THREADS and -D_REENTRANT
- specified in the Makefile.
+2) You must compile the collector with -DGC_LINUX_THREADS (or
+ just -DGC_THREADS) and -D_REENTRANT specified in the Makefile.
-3a) Every file that makes thread calls should define GC_LINUX_THREADS and
+3a) Every file that makes thread calls should define GC_LINUX_THREADS and
_REENTRANT and then include gc.h. Gc.h redefines some of the
pthread primitives as macros which also provide the collector with
information it requires.
@@ -37,14 +37,14 @@ To use threads, you need to abide by the following requirements:
3b) A new alternative to (3a) is to build the collector and compile GC clients
with -DGC_USE_LD_WRAP, and to link the final program with
- (for ld) --wrap read --wrap dlopen --wrap pthread_create \
- --wrap pthread_join --wrap pthread_detach \
- --wrap pthread_sigmask --wrap sleep
+ (for ld) --wrap dlopen --wrap pthread_create \
+ --wrap pthread_join --wrap pthread_detach \
+ --wrap pthread_sigmask --wrap pthread_exit --wrap pthread_cancel
- (for gcc) -Wl,--wrap -Wl,read -Wl,--wrap -Wl,dlopen -Wl,--wrap \
- -Wl,pthread_create -Wl,--wrap -Wl,pthread_join -Wl,--wrap \
- -Wl,pthread_detach -Wl,--wrap -Wl,pthread_sigmask \
- -Wl,--wrap -Wl,sleep
+ (for gcc) -Wl,--wrap -Wl,dlopen -Wl,--wrap -Wl,pthread_create \
+ -Wl,--wrap -Wl,pthread_join -Wl,--wrap -Wl,pthread_detach \
+ -Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,pthread_exit \
+ -Wl,--wrap -Wl,pthread_cancel
In any case, _REENTRANT should be defined during compilation.
@@ -55,17 +55,16 @@ To use threads, you need to abide by the following requirements:
conditions, this may cause unexpected heap growth.
5) The combination of GC_LINUX_THREADS, REDIRECT_MALLOC, and incremental
- collection fails in seemingly random places. This hasn't been tracked
- down yet, but is perhaps not completely astonishing. The thread package
- uses malloc, and thus can presumably get SIGSEGVs while inside the
- package. There is no real guarantee that signals are handled properly
- at that point.
+ collection is probably not fully reliable, though it now seems to work
+ in simple cases.
6) Thread local storage may not be viewed as part of the root set by the
collector. This probably depends on the linuxthreads version. For the
time being, any collectable memory referenced by thread local storage should
also be referenced from elsewhere, or be allocated as uncollectable.
- (This is really a bug that should be fixed somehow.)
+ (This is really a bug that should be fixed somehow. The current GC
+ version probably gets things right if there are not too many tls locations
+ and if dlopen is not used.)
M68K LINUX:
@@ -76,7 +75,7 @@ patches to correct the problem in 68040 buserror handler but it is not
yet in any standard kernel.
Here is a simple test program to detect whether the kernel has the
-problem. It could be run as a separate check in configure or tested
+problem. It could be run as a separate check in configure or tested
upon startup. If it fails (return !0) than mprotect can't be used
on that system.
@@ -128,5 +127,3 @@ main()
fprintf(stderr,"vmtest Ok\n");
exit(0);
}
-
-
diff --git a/boehm-gc/doc/README.macros b/boehm-gc/doc/README.macros
index df0ef2cda93..a822f0f47cd 100644
--- a/boehm-gc/doc/README.macros
+++ b/boehm-gc/doc/README.macros
@@ -1,7 +1,7 @@
The collector uses a large amount of conditional compilation in order to
deal with platform dependencies. This violates a number of known coding
standards. On the other hand, it seems to be the only practical way to
-support this many platforms without excessive code duplication.
+support this many platforms without excessive code duplication.
A few guidelines have mostly been followed in order to keep this manageable:
@@ -14,81 +14,563 @@ In my opinion, it's still well worth it, for the same reason that we indent
ordinary "if" statements.
2) Whenever possible, tests are performed on the macros defined in gcconfig.h
-instead of directly testing patform-specific predefined macros. This makes it
-relatively easy to adapt to new compilers with a different set of predefined
-macros. Currently these macros generally identify platforms instead of
-features. In many cases, this is a mistake.
-
-3) The code currently avoids #elif, eventhough that would make it more
-readable. This was done since #elif would need to be understood by ALL
-compilers used to build the collector, and that hasn't always been the case.
-It makes sense to reconsider this decision at some point, since #elif has been
-standardized at least since 1989.
+instead of directly testing platform-specific predefined macros. This makes
+it relatively easy to adapt to new compilers with a different set of
+predefined macros. Currently these macros generally identify platforms
+instead of features. In many cases, this is a mistake.
Many of the tested configuration macros are at least somewhat defined in
either include/private/gcconfig.h or in Makefile.direct. Here is an attempt
-at defining some of the remainder: (Thanks to Walter Bright for suggesting
+at documenting these macros: (Thanks to Walter Bright for suggesting
this. This is a work in progress)
-MACRO EXPLANATION
------ -----------
+MACRO EXPLANATION
+----- -----------
+
+GC_DEBUG Tested by gc.h. Causes all-upper-case macros to
+ expand to calls to debug versions of collector routines.
+
+GC_NAMESPACE Tested by gc_cpp.h. Causes gc_cpp symbols to be defined
+ in "boehmgc" namespace.
+
+GC_DEBUG_REPLACEMENT Tested by gc.h. Causes GC_MALLOC/REALLOC() to be
+ defined as GC_debug_malloc/realloc_replacement().
-__DMC__ Always #define'd by the Digital Mars compiler. Expands
- to the compiler version number in hex, i.e. 0x810 is
- version 8.1b0
+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.
+
+GC_UNDERSCORE_STDCALL Tested by gc.h. Explicitly prefix exported/imported
+ WINAPI (__stdcall) symbols with '_' (underscore). Could be
+ used with MinGW (for x86) compiler (in conjunction with
+ GC_DLL) to follow MS conventions for __stdcall symbols naming.
_ENABLE_ARRAYNEW
- #define'd by the Digital Mars C++ compiler when
- operator new[] and delete[] are separately
- overloadable. Used in gc_cpp.h.
-
-_MSC_VER Expands to the Visual C++ compiler version. Assumed to
- not be defined for other compilers (at least if they behave
- appreciably differently).
-
-_DLL Defined by Visual C++ if dynamic libraries are being built
- or used. Used to test whether __declspec(dllimport) or
- __declspec(dllexport) needs to be added to declarations
- to support the case in which the collector is in a dll.
-
-GC_DLL User-settable macro that forces the effect of _DLL. Set
- by gc.h if _DLL is defined and GC_NOT_DLL is undefined.
- This is the macro that is tested internally to determine
- whether the GC is in its own dynamic library. May need
- to be set by clients before including gc.h. Note that
- inside the GC implementation it indicates that the
- collector is in its own dynamic library, should export
- its symbols, etc. But in clients it indicates that the
- GC resides in a different DLL, its entry points should
- be referenced accordingly, and precautions may need to
- be taken to properly deal with statically allocated
- variables in the main program. Used only for MS Windows.
-
-GC_NOT_DLL User-settable macro that overrides _DLL, e.g. if dynamic
- libraries are used, but the collector is in a static library.
-
-__STDC__ Assumed to be defined only by compilers that understand
- prototypes and other C89 features. Its value is generally
- not used, since we are fine with most nonconforming extensions.
-
-SUNOS5SIGS Solaris-like signal handling. This is probably misnamed,
- since it really doesn't guarantee much more than Posix.
- Currently set only for Solaris2.X, HPUX, and DRSNX. Should
- probably be set for some other platforms.
-
-PCR Set if the collector is being built as part of the Xerox
- Portable Common Runtime.
-
-SRC_M3 Set if the collector is being built as a replacement of the
- one in the DEC/Compaq SRC Modula-3 runtime. I suspect this
- was last used around 1994, and no doubt broke a long time ago.
- It's there primarily incase someone wants to port to a similar
- system.
-
-USE_COMPILER_TLS Assume the existence of __thread-style thread-local
- storage. Set automatically for thread-local allocation with
- the HP/UX vendor compiler. Usable with gcc on sufficiently
- up-to-date ELF platforms.
+ #define'd by the Digital Mars C++ compiler when
+ operator new[] and delete[] are separately
+ overloadable. Used in gc_cpp.h.
+
+_DLL Tested by gc_config_macros.h. Defined by Visual C++ if runtime
+ dynamic libraries are in use. Used (only if none of GC_DLL,
+ GC_NOT_DLL, __GNUC__ are defined) to test whether
+ __declspec(dllimport) needs to be added to declarations
+ to support the case in which the collector is in a DLL.
+
+GC_DLL Defined by user if dynamic libraries are being built
+ or used. Also set by gc.h if _DLL is defined (except for
+ mingw) while GC_NOT_DLL and __GNUC__ are both undefined.
+ This is the macro that is tested internally to determine
+ whether the GC is in its own dynamic library. May need
+ to be set by clients before including gc.h. Note that
+ inside the GC implementation it indicates that the
+ collector is in its own dynamic library, should export
+ its symbols, etc. But in clients it indicates that the
+ GC resides in a different DLL, its entry points should
+ be referenced accordingly, and precautions may need to
+ be taken to properly deal with statically allocated
+ variables in the main program. Used for MS Windows.
+ Also used by GCC v4+ (only when the dynamic shared library
+ is being built) to hide internally used symbols.
+
+GC_NOT_DLL User-settable macro that overrides _DLL, e.g. if runtime
+ dynamic libraries are used, but the collector is in a static
+ library. Tested by gc_config_macros.h.
+
+GC_REQUIRE_WCSDUP Force GC to export GC_wcsdup() (the Unicode version
+ of GC_strdup); could be useful in the leak-finding mode.
+
+
+These define arguments influence the collector configuration:
+
+FIND_LEAK Causes GC_find_leak to be initially set. This causes the
+ collector to assume that all inaccessible objects should have been
+ explicitly deallocated, and reports exceptions. Finalization and the test
+ program are not usable in this mode.
+
+GC_FINDLEAK_DELAY_FREE Turns on deferred freeing of objects in the
+ leak-finding mode letting the collector to detect alter-object-after-free
+ errors as well as detect leaked objects sooner (instead of only when program
+ terminates). Has no effect if SHORT_DBG_HDRS.
+
+GC_ABORT_ON_LEAK Causes the application to be terminated once leaked or
+ smashed (corrupted on use-after-free) objects are found (after printing the
+ information about that objects).
+
+SUNOS5SIGS Solaris-like signal handling. This is probably misnamed,
+ since it really doesn't guarantee much more than POSIX. Currently set only
+ for Solaris2.X, HPUX, and DRSNX. Should probably be set for some other
+ platforms.
+
+PCR Set if the collector is being built as part of the Xerox Portable
+ Common Runtime.
+
+USE_COMPILER_TLS Assume the existence of __thread-style thread-local storage.
+ Set automatically for thread-local allocation with the HP/UX vendor
+ compiler. Usable with gcc on sufficiently up-to-date ELF platforms.
+
+IMPORTANT: Any of the _THREADS options must normally also be defined in
+ the client before including gc.h. This redefines thread primitives to
+ invoke the GC_ versions instead. Alternatively, linker-based symbol
+ interception can be used on a few platforms.
+
+GC_THREADS Should set the appropriate one of the below macros,
+ except GC_WIN32_PTHREADS, which must be set explicitly. Tested by gc.h.
+
+GC_SOLARIS_THREADS Enables support for Solaris pthreads.
+ Must also define _REENTRANT.
+
+GC_IRIX_THREADS Enables support for Irix pthreads. See README.sgi.
+
+GC_HPUX_THREADS Enables support for HP/UX 11 pthreads.
+ Also requires _REENTRANT or _POSIX_C_SOURCE=199506L. See README.hp.
+
+GC_LINUX_THREADS Enables support for Xavier Leroy's Linux threads
+ or NPTL threads. See README.linux. _REENTRANT may also be required.
+
+GC_OSF1_THREADS Enables support for Tru64 pthreads.
+
+GC_FREEBSD_THREADS Enables support for FreeBSD pthreads.
+ Appeared to run into some underlying thread problems.
+
+GC_NETBSD_THREADS Enables support for NetBSD pthreads.
+
+GC_OPENBSD_THREADS Enables support for OpenBSD pthreads.
+
+GC_DARWIN_THREADS Enables support for Mac OS X pthreads.
+
+GC_AIX_THREADS Enables support for IBM AIX threads.
+
+GC_DGUX386_THREADS Enables support for DB/UX on I386 threads.
+ See README.DGUX386. (Probably has not been tested recently.)
+
+GC_WIN32_THREADS Enables support for Win32 threads. That makes sense
+ for this Makefile only under Cygwin.
+
+GC_WIN32_PTHREADS Enables support for Ming32 pthreads. This cannot be
+ enabled automatically by GC_THREADS, which would assume Win32 native
+ threads.
+
+PTW32_STATIC_LIB Causes the static version of the Mingw pthreads
+ library to be used. Requires GC_WIN32_PTHREADS.
+
+GC_PTHREADS_PARAMARK Causes pthread-based parallel mark implementation
+ to be used even if GC_WIN32_PTHREADS is undefined. (Useful for WinCE.)
+
+ALL_INTERIOR_POINTERS Allows all pointers to the interior of objects to be
+ recognized. (See gc_priv.h for consequences.) Alternatively,
+ GC_all_interior_pointers can be set at process initialization time.
+
+SMALL_CONFIG Tries to tune the collector for small heap sizes,
+ usually causing it to use less space in such situations. Incremental
+ collection no longer works in this case. Also, removes some
+ statistic-printing code. Turns off some optimization algorithms (like data
+ prefetching in the mark routine).
+
+GC_DISABLE_INCREMENTAL Turn off the incremental collection support.
+
+NO_INCREMENTAL Causes the gctest program to not invoke the incremental
+ collector. This has no impact on the generated library, only on the test
+ program. (This is often useful for debugging failures unrelated to
+ incremental GC.)
+
+LARGE_CONFIG Tunes the collector for unusually large heaps.
+ Necessary for heaps larger than about 4 GiB on most (64-bit) machines.
+ Recommended for heaps larger than about 500 MiB. Not recommended for
+ embedded systems. Could be used in conjunction with SMALL_CONFIG to
+ generate smaller code (by disabling incremental collection support,
+ statistic printing and some optimization algorithms).
+
+DONT_ADD_BYTE_AT_END Meaningful only with ALL_INTERIOR_POINTERS or
+ GC_all_interior_pointers = 1. Normally ALL_INTERIOR_POINTERS
+ causes all objects to be padded so that pointers just past the end of
+ an object can be recognized. This can be expensive. (The padding
+ is normally more than one byte due to alignment constraints.)
+ DONT_ADD_BYTE_AT_END disables the padding.
+
+NO_EXECUTE_PERMISSION May cause some or all of the heap to not
+ have execute permission, i.e. it may be impossible to execute
+ code from the heap. Currently this only affects the incremental
+ collector on UNIX machines. It may greatly improve its performance,
+ since this may avoid some expensive cache synchronization. Alternatively,
+ GC_set_pages_executable can be called at the process initialization time.
+
+GC_NO_OPERATOR_NEW_ARRAY Declares that the C++ compiler does not
+ support the new syntax "operator new[]" for allocating and deleting arrays.
+ See gc_cpp.h for details. No effect on the C part of the collector.
+ This is defined implicitly in a few environments. Must also be defined
+ by clients that use gc_cpp.h.
+
+REDIRECT_MALLOC=<X> Causes malloc to be defined as alias for X.
+ Unless the following macros are defined, realloc is also redirected
+ to GC_realloc, and free is redirected to GC_free.
+ Calloc and str[n]dup are redefined in terms of the new malloc. X should
+ be either GC_malloc or GC_malloc_uncollectable, or
+ GC_debug_malloc_replacement. (The latter invokes GC_debug_malloc
+ with dummy source location information, but still results in
+ properly remembered call stacks on Linux/X86 and Solaris/SPARC.
+ It requires that the following two macros also be used.)
+ The former is occasionally useful for working around leaks in code
+ you don't want to (or can't) look at. It may not work for
+ existing code, but it often does. Neither works on all platforms,
+ since some ports use malloc or calloc to obtain system memory.
+ (Probably works for UNIX, and Win32.) If you build with DBG_HDRS_ALL,
+ you should only use GC_debug_malloc_replacement as a malloc
+ replacement.
+
+REDIRECT_REALLOC=<X> Causes GC_realloc to be redirected to X.
+ The canonical use is REDIRECT_REALLOC=GC_debug_realloc_replacement,
+ together with REDIRECT_MALLOC=GC_debug_malloc_replacement to
+ generate leak reports with call stacks for both malloc and realloc.
+ This also requires REDIRECT_FREE.
+
+REDIRECT_FREE=<X> Causes free to be redirected to X. The canonical use
+ is REDIRECT_FREE=GC_debug_free.
+
+IGNORE_FREE Turns calls to free into a no-op. Only useful with
+ REDIRECT_MALLOC.
+
+NO_DEBUGGING Removes GC_dump and the debugging routines it calls.
+ Reduces code size slightly at the expense of debuggability.
+
+DEBUG_THREADS Turn on printing additional thread-support debugging
+ information.
+
+GC_COLLECT_AT_MALLOC=<n> Force garbage collection at every
+ GC_malloc_* call with the size greater than the specified value.
+ (Might be useful for application debugging or in find-leak mode.)
+
+JAVA_FINALIZATION Makes it somewhat safer to finalize objects out of
+ order by specifying a nonstandard finalization mark procedure (see
+ finalize.c). Objects reachable from finalizable objects will be marked
+ in a separate post-pass, and hence their memory won't be reclaimed.
+ Not recommended unless you are implementing a language that specifies
+ these semantics. Since 5.0, determines only the initial value
+ of GC_java_finalization variable.
+
+FINALIZE_ON_DEMAND Causes finalizers to be run only in response
+ to explicit GC_invoke_finalizers() calls.
+ In 5.0 this became runtime adjustable, and this only determines the
+ initial value of GC_finalize_on_demand.
+
+GC_NO_FINALIZATION Exclude finalization support (for smaller code size)
+
+ATOMIC_UNCOLLECTABLE Includes code for GC_malloc_atomic_uncollectable.
+ This is useful if either the vendor malloc implementation is poor,
+ or if REDIRECT_MALLOC is used.
+
+MARK_BIT_PER_GRANULE Requests that a mark bit (or often byte)
+ be allocated for each allocation granule, as opposed to each object.
+ This often improves speed, possibly at some cost in space and/or
+ cache footprint. Normally it is best to let this decision be
+ made automatically depending on platform.
+
+MARK_BIT_PER_OBJ Requests that a mark bit be allocated for each
+ object instead of allocation granule. The opposite of
+ MARK_BIT_PER_GRANULE.
+
+HBLKSIZE=<ddd> Explicitly sets the heap block size (where ddd is a power of
+ 2 between 512 and 16384). Each heap block is devoted to a single size and
+ kind of object. For the incremental collector it makes sense to match
+ the most likely page size. Otherwise large values result in more
+ fragmentation, but generally better performance for large heaps.
+
+USE_MMAP Use MMAP instead of sbrk to get new memory.
+ Works for Linux, FreeBSD, Cygwin, Solaris and Irix.
+
+USE_MUNMAP Causes memory to be returned to the OS under the right
+ circumstances. This currently disables VM-based incremental collection
+ (except for Win32 with GetWriteWatch() available).
+ Works under some Unix, Linux and Windows versions.
+ Requires USE_MMAP except for Windows.
+
+USE_WINALLOC (Cygwin only) Use Win32 VirtualAlloc (instead of sbrk or mmap)
+ to get new memory. Useful if memory unmapping (USE_MUNMAP) is enabled.
+
+MUNMAP_THRESHOLD=<value> Set the desired memory blocks unmapping
+ threshold (the number of sequential garbage collections for which
+ a candidate block for unmapping should remain free).
+
+GC_FORCE_UNMAP_ON_GCOLLECT Set "unmap as much as possible on explicit GC"
+ mode on by default. The mode could be changed at run-time. Has no effect
+ unless unmapping is turned on. Has no effect on implicitly-initiated
+ garbage collections.
+
+PRINT_BLACK_LIST Whenever a black list entry is added, i.e. whenever
+ the garbage collector detects a value that looks almost, but not quite,
+ like a pointer, print both the address containing the value, and the
+ value of the near-bogus-pointer. Can be used to identify regions of
+ memory that are likely to contribute misidentified pointers.
+
+KEEP_BACK_PTRS Add code to save back pointers in debugging headers
+ for objects allocated with the debugging allocator. If all objects
+ through GC_MALLOC with GC_DEBUG defined, this allows the client
+ to determine how particular or randomly chosen objects are reachable
+ for debugging/profiling purposes. The gc_backptr.h interface is
+ implemented only if this is defined.
+
+GC_ASSERTIONS Enable some internal GC assertion checking. Currently
+ this facility is only used in a few places. It is intended primarily
+ for debugging of the garbage collector itself, but could also...
+
+DBG_HDRS_ALL Make sure that all objects have debug headers. Increases
+ the reliability (from 99.9999% to 100% mod. bugs) of some of the debugging
+ code (especially KEEP_BACK_PTRS). Makes SHORT_DBG_HDRS possible.
+ Assumes that all client allocation is done through debugging allocators.
+
+SHORT_DBG_HDRS Assume that all objects have debug headers. Shorten
+ the headers to minimize object size, at the expense of checking for
+ writes past the end of an object. This is intended for environments
+ in which most client code is written in a "safe" language, such as
+ Scheme or Java. Assumes that all client allocation is done using
+ 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 could be useful for debugging of client code. Slows down the
+ collector somewhat, but not drastically.
+
+SAVE_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
+ on which we can quickly generate call stacks, currently Linux/(X86 & SPARC)
+ and Solaris/SPARC and platforms that provide execinfo.h.
+ Default is zero. On X86, client
+ code should NOT be compiled with -fomit-frame-pointer.
+
+SAVE_CALL_NARGS=<n> Set the number of functions arguments to be saved
+ with each call frame. Default is zero. Ignored if we don't know how to
+ retrieve arguments on the platform.
+
+CHECKSUMS Reports on erroneously clear dirty bits, and unexpectedly
+ altered stubborn objects, at substantial performance cost. Use only for
+ debugging of the incremental collector. Not compatible with USE_MUNMAP
+ or threads.
+
+GC_GCJ_SUPPORT Includes support for gcj (and possibly other systems
+ that include a pointer to a type descriptor in each allocated object).
+ Building this way requires an ANSI C compiler.
+
+USE_I686_PREFETCH Causes the collector to issue Pentium III style
+ prefetch instructions. No effect except on X86 Linux platforms.
+ Assumes a very recent gcc-compatible compiler and assembler.
+ (Gas prefetcht0 support was added around May 1999.)
+ Empirically the code appears to still run correctly on Pentium II
+ processors, though with no performance benefit. May not run on other
+ X86 processors? In some cases this improves performance by
+ 15% or so.
+
+USE_3DNOW_PREFETCH Causes the collector to issue AMD 3DNow style
+ prefetch instructions. Same restrictions as USE_I686_PREFETCH.
+ Minimally tested. Didn't appear to be an obvious win on a K6-2/500.
+
+USE_PPC_PREFETCH Causes the collector to issue PowerPC style
+ prefetch instructions. No effect except on PowerPC OS X platforms.
+ Performance impact untested.
+
+GC_USE_LD_WRAP In combination with the old flags listed in README.linux
+ causes the collector some system and pthread calls in a more transparent
+ fashion than the usual macro-based approach. Requires GNU ld, and
+ currently probably works only with Linux.
+
+GC_USE_DLOPEN_WRAP Causes the collector to redefine malloc and
+ intercepted pthread routines with their real names, and causes it to use
+ dlopen and dlsym to refer to the original versions. This makes it possible
+ to build an LD_PRELOADable malloc replacement library.
+
+THREAD_LOCAL_ALLOC Defines GC_malloc(), GC_malloc_atomic() and
+ GC_gcj_malloc() to use a per-thread set of free-lists. These then allocate
+ in a way that usually does not involve acquisition of a global lock.
+ Recommended for multiprocessors. Requires explicit GC_INIT() call, unless
+ REDIRECT_MALLOC is defined and GC_malloc is used first.
+
+USE_COMPILER_TLS Causes thread local allocation to use
+ the compiler-supported "__thread" thread-local variables. This is the
+ default in HP/UX. It may help performance on recent Linux installations.
+ (It failed for me on RedHat 8, but appears to work on RedHat 9.)
+
+PARALLEL_MARK Allows the marker to run in multiple threads. Recommended
+ for multiprocessors.
+
+DONT_USE_SIGNALANDWAIT (Win32 only) Use an alternate implementation for
+ marker threads (if PARALLEL_MARK defined) synchronization routines based
+ on InterlockedExchange() (instead of AO_fetch_and_add()) and on multiple
+ event objects (one per each marker instead of that based on Win32
+ SignalObjectAndWait() using a single event object). This is the default
+ for WinCE.
+
+GC_WINMAIN_REDIRECT (Win32 only) Redirect (rename) an application
+ WinMain to GC_WinMain; implement the "real" WinMain which starts a new
+ thread to call GC_WinMain after initializing the GC. Useful for WinCE.
+ Incompatible with GC_DLL.
+
+GC_REGISTER_MEM_PRIVATE (Win32 only) Force to register MEM_PRIVATE R/W
+ sections as data roots. Might be needed for some WinCE 6.0+ custom builds.
+ (May result in numerous "Data Abort" messages logged to WinCE debugging
+ console.) Incompatible with GCC toolchains for WinCE.
+
+NO_GETENV Prevents the collector from looking at environment variables.
+ These may otherwise alter its configuration, or turn off GC altogether.
+ I don't know of a reason to disable this, except possibly if the resulting
+ process runs as a privileged user. (This is on by default for WinCE.)
+
+EMPTY_GETENV_RESULTS Define to workaround a reputed Wine bug in getenv
+ (getenv() may return an empty string instead of NULL for a missing entry).
+
+GC_READ_ENV_FILE (Win32 only) Read environment variables from the GC "env"
+ file (named as the program name plus ".gc.env" extension). Useful for WinCE
+ targets (which have no getenv()). In the file, every variable is specified
+ in a separate line and the format is as "<name>=<value>" (without spaces).
+ A comment line may start with any character except for the Latin letters,
+ the digits and the underscore ('_'). The file encoding is Latin-1.
+
+USE_GLOBAL_ALLOC (Win32 only) Use GlobalAlloc() instead of VirtualAlloc()
+ to allocate the heap. May be needed to work around a Windows NT/2000 issue.
+ Incompatible with USE_MUNMAP. See README.win32 for details.
+
+MAKE_BACK_GRAPH Enable GC_PRINT_BACK_HEIGHT environment variable.
+ See README.environment for details. Experimental. Limited platform
+ support. Implies DBG_HDRS_ALL. All allocation should be done using
+ the debug interface.
+
+GC_PRINT_BACK_HEIGHT Permanently turn on back-height printing mode
+ (useful when NO_GETENV). See the similar environment variable description
+ in README.environment. Requires MAKE_BACK_GRAPH defined.
+
+STUBBORN_ALLOC Allows allocation of "hard to change" objects, and thus
+ makes incremental collection easier. Was enabled by default until 6.0.
+ Rarely used, to my knowledge.
+
+HANDLE_FORK (Unix and Cygwin only) Attempt by default to make GC_malloc()
+ work in a child process fork()'ed from a multi-threaded parent. Not fully
+ POSIX-compliant and could be disabled at runtime (before GC_INIT).
+
+TEST_WITH_SYSTEM_MALLOC Causes gctest to allocate (and leak) large
+ chunks of memory with the standard system malloc. This will cause the root
+ set and collected heap to grow significantly if malloc'ed memory is somehow
+ getting traced by the collector. This has no impact on the generated
+ library; it only affects the test.
+
+POINTER_MASK=<0x...> Causes candidate pointers to be AND'ed with the given
+ mask before being considered. If either this or the following macro is
+ defined, it will be assumed that all pointers stored in the heap need to be
+ processed this way. Stack and register pointers will be considered both
+ with and without processing. These macros are normally needed only to
+ support systems that use high-order pointer tags. EXPERIMENTAL.
+
+POINTER_SHIFT=<n> Causes the collector to left shift candidate pointers
+ by the indicated amount before trying to interpret them. Applied after
+ POINTER_MASK. EXPERIMENTAL. See also the preceding macro.
+
+ENABLE_TRACE Enables the GC_TRACE=addr environment setting to do its job.
+ By default this is not supported in order to keep the marker as fast as
+ possible.
+
+DARWIN_DONT_PARSE_STACK Causes the Darwin port to discover thread
+ stack bounds in the same way as other pthread ports, without trying to
+ walk the frames on the stack. This is recommended only as a fall-back for
+ applications that don't support proper stack unwinding.
+
+GC_NO_THREADS_DISCOVERY (Darwin and Win32+DLL only) Exclude DllMain-based
+ (on Windows) and task-threads-based (on Darwin) thread registration support.
+
+GC_INSIDE_DLL (Win32 only) Enable DllMain-based approach of threads
+ registering even in case GC_DLL is not defined.
+
+GC_DISCOVER_TASK_THREADS (Darwin and Win32+DLL only) Compile the collector
+ with the implicitly turned on task-threads-based (on Darwin) or
+ DllMain-based (on Windows) approach of threads registering. Only for
+ compatibility and for the case when it is not possible to call
+ GC_use_threads_discovery() early (before other GC calls).
+
+USE_PROC_FOR_LIBRARIES Causes the Linux collector to treat writable
+ memory mappings (as reported by /proc) as roots, if it doesn't have
+ other information about them. It no longer traverses dynamic loader
+ data structures to find dynamic library static data. This may be
+ required for applications that store pointers in mmapped segments without
+ informing the collector. But it typically performs poorly, especially
+ since it will scan inactive but cached NPTL thread stacks completely.
+
+IGNORE_DYNAMIC_LOADING Don't define DYNAMIC_LOADING even if supported by the
+ platform (that is, build the collector with disabled tracing of dynamic
+ library data roots).
+
+NO_PROC_STAT Causes the collector to avoid relying on Linux
+ "/proc/self/stat".
+
+NO_GETCONTEXT Causes the collector to not assume the existence of the
+ getcontext() function on linux-like platforms. This currently happens
+ implicitly on Darwin, Hurd, or ARM or MIPS hardware. It is explicitly
+ needed for some old versions of FreeBSD.
+
+STATIC=static Causes various GC_ symbols that could logically be declared
+ static to be declared (this is the default if NO_DEBUGGING is specified).
+ Reduces the number of visible symbols (letting the optimizer do its work
+ better), which is probably cleaner, but may make some kinds of debugging
+ and profiling harder.
+
+GC_DLL Build dynamic-link library (or dynamic shared object). For Unix this
+ causes the exported symbols to have 'default' visibility (ignored unless
+ GCC v4+) and the internal ones to have 'hidden' visibility.
+
+DONT_USE_USER32_DLL (Win32 only) Don't use "user32" DLL import library
+ (containing MessageBox() entry); useful for a static GC library.
+
+GC_PREFER_MPROTECT_VDB Choose MPROTECT_VDB manually in case of multiple
+ virtual dirty bit strategies are implemented (at present useful on Win32 and
+ Solaris to force MPROTECT_VDB strategy instead of the default GWW_VDB or
+ PROC_VDB ones).
+
+GC_IGNORE_GCJ_INFO Disable GCJ-style type information (useful for
+ debugging on WinCE).
+
+GC_PRINT_VERBOSE_STATS Permanently turn on verbose logging (useful for
+ debugging and profiling on WinCE).
+
+GC_ONLY_LOG_TO_FILE Don't redirect GC stdout and stderr to the log file
+ specified by GC_LOG_FILE environment variable. Has effect only when the
+ variable is set (to anything other than "0").
+
+GC_ANDROID_LOG (Android only) Output error/debug information to Android log.
+
+GC_DONT_EXPAND Don't expand the heap unless explicitly requested or forced to.
+
+GC_USE_ENTIRE_HEAP Causes the non-incremental collector to use the
+ entire heap before collecting. This sometimes results in more large block
+ fragmentation, since very large blocks will tend to get broken up during
+ each GC cycle. It is likely to result in a larger working set, but lower
+ collection frequencies, and hence fewer instructions executed in the
+ collector. This macro controls only the default GC_use_entire_heap value.
+
+GC_INITIAL_HEAP_SIZE=<value> Set the desired default initial heap size
+ in bytes.
+
+GC_FREE_SPACE_DIVISOR=<value> Set alternate default GC_free_space_divisor
+ value.
+
+GC_TIME_LIMIT=<milliseconds> Set alternate default GC_time_limit value
+ (setting this to GC_TIME_UNLIMITED will essentially disable incremental
+ collection while leaving generational collection enabled).
+
+GC_FULL_FREQ=<value> Set alternate default number of partial collections
+ between full collections (matters only if incremental collection is on).
+
+NO_CANCEL_SAFE (Posix platforms with threads only) Don't bother trying
+ to make the collector safe for thread cancellation; cancellation is not
+ used. (Note that if cancellation is used anyway, threads may end up
+ getting cancelled in unexpected places.) Even without this option,
+ PTHREAD_CANCEL_ASYNCHRONOUS is never safe with the collector. (We could
+ argue about its safety without the collector.)
+
+UNICODE (Win32 only) Use the Unicode variant ('W') of the Win32 API instead
+ of ANSI/ASCII one ('A'). Useful for WinCE.
+PLATFORM_ANDROID (or __ANDROID__) Compile for Android NDK platform.
+SN_TARGET_PS3 Compile for Sony PS/3.
+USE_GET_STACKBASE_FOR_MAIN (Linux only) Use pthread_attr_getstack() instead
+ of __libc_stack_end (or instead of any hard-coded value) for getting the
+ primordial thread stack base (useful if the client modifies the program's
+ address space).
diff --git a/boehm-gc/doc/README.sgi b/boehm-gc/doc/README.sgi
index 7bdb50a4ef9..d9e989388ff 100644
--- a/boehm-gc/doc/README.sgi
+++ b/boehm-gc/doc/README.sgi
@@ -15,7 +15,7 @@ Pthreads support is provided. This requires that:
1) You compile the collector with -DGC_IRIX_THREADS specified in the Makefile.
-2) You have the latest pthreads patches installed.
+2) You have the latest pthreads patches installed.
(Though the collector makes only documented pthread calls,
it relies on signal/threads interactions working just right in ways
@@ -38,4 +38,3 @@ performance with the collector. (Increasing the heap size may help.)
6) The collector should not be compiled with -DREDIRECT_MALLOC. This
confuses some library calls made by the pthreads implementation, which
expect the standard malloc.
-
diff --git a/boehm-gc/doc/README.solaris2 b/boehm-gc/doc/README.solaris2
index 6ed61dc83dc..2f3b511aee5 100644
--- a/boehm-gc/doc/README.solaris2
+++ b/boehm-gc/doc/README.solaris2
@@ -13,37 +13,40 @@ not safe: "Many library routines use malloc() internally, so use brk()
and sbrk() only when you know that malloc() definitely will not be used by
any library routine." This doesn't make a lot of sense to me, since there
seems to be no documentation as to which routines can transitively call malloc.
-Nonetheless, under Solaris2, the collector now (since 4.12) allocates
+Nonetheless, under Solaris2, the collector now allocates
memory using mmap by default. (It defines USE_MMAP in gcconfig.h.)
You may want to reverse this decisions if you use -DREDIRECT_MALLOC=...
+Note:
+Before you run "make check", you need to set your LD_LIBRARY_PATH correctly
+(eg., to "/usr/local/lib") so that tests can find the shared library
+libgcc_s.so.1. Alternatively, you can configure with --disable-shared.
SOLARIS THREADS:
-The collector must be compiled with -DGC_SOLARIS_THREADS (thr_ functions)
-or -DGC_SOLARIS_PTHREADS (pthread_ functions) to be thread safe.
-It is also essential that gc.h be included in files that call thr_create,
-thr_join, thr_suspend, thr_continue, or dlopen. Gc.h macro defines
-these to also do GC bookkeeping, etc. Gc.h must be included with
-one or both of these macros defined, otherwise
-these replacements are not visible.
-A collector built in this way way only be used by programs that are
-linked with the threads library.
-
-In this mode, the collector contains various workarounds for older Solaris
-bugs. Mostly, these should not be noticeable unless you look at system
-call traces. However, it cannot protect a guard page at the end of
-a thread stack. If you know that you will only be running Solaris2.5
-or later, it should be possible to fix this by compiling the collector
-with -DSOLARIS23_MPROTECT_BUG_FIXED.
+Threads support is enabled by configure "--enable-threads=posix" option.
+(In case of GCC compiler, multi-threading support is on by default.)
+This causes the collector to be compiled with -D GC_THREADS (or
+-D GC_SOLARIS_THREADS) ensuring thread safety.
+This assumes use of the pthread_ interface. Old style Solaris threads
+are no longer supported.
+Thread-local allocation is now on by default. Parallel marking is on by
+default starting from GC v7.3 but it could be enabled or disabled manually
+by the corresponding "--enable/disable-parallel-mark" options.
+
+It is also essential that gc.h be included in files that call pthread_create,
+pthread_join, pthread_detach, or dlopen. gc.h macro defines these to also do
+GC bookkeeping, etc. gc.h must be included with one or both of these macros
+defined, otherwise these replacements are not visible. A collector built in
+this way way only be used by programs that are linked with the threads library.
Since 5.0 alpha5, dlopen disables collection temporarily,
unless USE_PROC_FOR_LIBRARIES is defined. In some unlikely cases, this
can result in unpleasant heap growth. But it seems better than the
race/deadlock issues we had before.
-If solaris_threads are used on an X86 processor with malloc redirected to
-GC_malloc, it is necessary to call GC_thr_init explicitly before forking the
+If threads are used on an X86 processor with malloc redirected to
+GC_malloc, it is necessary to call GC_INIT explicitly before forking the
first thread. (This avoids a deadlock arising from calling GC_thr_init
with the allocation lock held.)
@@ -51,12 +54,19 @@ It appears that there is a problem in using gc_cpp.h in conjunction with
Solaris threads and Sun's C++ runtime. Apparently the overloaded new operator
is invoked by some iostream initialization code before threads are correctly
initialized. As a result, call to thr_self() in garbage collector
-initialization segfaults. Currently the only known workaround is to not
+initialization SEGV faults. Currently the only known workaround is to not
invoke the garbage collector from a user defined global operator new, or to
have it invoke the garbage-collector's allocators only after main has started.
(Note that the latter requires a moderately expensive test in operator
delete.)
+I encountered "symbol <unknown>: offet .... is non-aligned" errors. These
+appear to be traceable to the use of the GNU assembler with the Sun linker.
+The former appears to generate a relocation not understood by the latter.
+The fix appears to be to use a consistent tool chain. (As a non-Solaris-expert
+my solution involved hacking the libtool script, but I'm sure you can
+do something less ugly.)
+
Hans-J. Boehm
(The above contains my personal opinions, which are probably not shared
by anyone else.)
diff --git a/boehm-gc/doc/README.symbian b/boehm-gc/doc/README.symbian
new file mode 100644
index 00000000000..50658c31778
--- /dev/null
+++ b/boehm-gc/doc/README.symbian
@@ -0,0 +1,13 @@
+Instructions for Symbian:
+1. base version: libgc 7.1
+2. Build: use libgc.mmp
+3. Limitations
+3.1.No multi-threaded support
+
+3.2. Be careful with limitation that emulator introduces: Static roots are not
+dynamically accessible (there are Symbian APIs for this purpose but are just
+stubs, returning irrelevant values).
+Consequently, on emulator, you can only use dlls or exe, and retrieve static
+roots by calling global_init_static_root per dll (or exe).
+On target, only libs are supported, because static roots are retrieved by
+linker flags, by calling global_init_static_root in main exe.
diff --git a/boehm-gc/doc/README.win32 b/boehm-gc/doc/README.win32
index 6f57db11764..d14686dd5df 100644
--- a/boehm-gc/doc/README.win32
+++ b/boehm-gc/doc/README.win32
@@ -6,8 +6,8 @@ broken in the meantime. Patches are appreciated.
For historical reasons,
the collector test program "gctest" is linked as a GUI application,
-but does not open any windows. Its output appears in the file
-"gc.log". It may be started from the file manager. The hour glass
+but does not open any windows. Its output normally appears in the file
+"gctest.gc.log". It may be started from the file manager. The hour glass
cursor may appear as long as it's running. If it is started from the
command line, it will usually run in the background. Wait a few
minutes (a few seconds on a modern machine) before you check the output.
@@ -37,6 +37,8 @@ This is currently incompatible with -DUSE_MUNMAP. (Thanks to Jonathan
Clark for tracking this down. There's some chance this may be fixed
in 6.1alpha4, since we now separate heap sections with an unused page.)
+[Threads and incremental collection are discussed near the end, below.]
+
Microsoft Tools
---------------
For Microsoft development tools, rename NT_MAKEFILE as
@@ -47,14 +49,14 @@ client code should include gc_cpp.h.
For historical reasons,
the collector test program "gctest" is linked as a GUI application,
but does not open any windows. Its output appears in the file
-"gc.log". It may be started from the file manager. The hour glass
+"gctest.gc.log". It may be started from the file manager. The hour glass
cursor may appear as long as it's running. If it is started from the
command line, it will usually run in the background. Wait a few
minutes (a few seconds on a modern machine) before you check the output.
You should see either a failure indication or a "Collector appears to
work" message.
-If you would prefer a VC++.NET project file, ask boehm@acm.org. One has
+If you would prefer a VC++ .NET project file, ask Hans Boehm. One has
been contributed, but it seems to contain some absolute paths etc., so
it can presumably only be a starting point, and is not in the standard
distribution. It is unclear (to me, Hans Boehm) whether it is feasible to
@@ -66,16 +68,17 @@ absence of thread support).
GNU Tools
---------
-For GNU-win32, use the regular makefile, possibly after uncommenting
-the line "include Makefile.DLLs". The latter should be necessary only
-if you want to package the collector as a DLL.
-[Is the following sentence obsolete? -HB] The GNU-win32 port is
-believed to work only for b18, not b19, probably due to linker changes
-in b19. This is probably fixable with a different definition of
-DATASTART and DATAEND in gcconfig.h.
+The collector should be buildable under Cygwin with the
+"./configure; make check" machinery.
+
+MinGW builds (including for x86_64) are available via cross-compilation, e.g.
+"./configure --host=i686-pc-mingw32; make check"
-The collector should also be buildable under Cygwin with either the
-old standard Makefile, or with the "configure;make" machinery.
+To build the collector as a DLL, pass "--enable-shared --disable-static" to
+configure (this will instruct make compile with -D GC_DLL).
+
+Parallel marker could be enabled via "--enable-parallel-mark".
+Memory unmapping could be enabled via "--enable-munmap".
Borland Tools
-------------
@@ -95,65 +98,12 @@ version, change the line near the top. By default, it does not
require the assembler. If you do have the assembler, I recommend
removing the -DUSE_GENERIC.
-Incremental Collection
-----------------------
-There is some support for incremental collection. This is
-currently pretty simple-minded. Pages are protected. Protection
-faults are caught by a handler installed at the bottom of the handler
-stack. This is both slow and interacts poorly with a debugger.
-Whenever possible, I recommend adding a call to
-GC_enable_incremental at the last possible moment, after most
-debugging is complete. Unlike the UNIX versions, no system
-calls are wrapped by the collector itself. It may be necessary
-to wrap ReadFile calls that use a buffer in the heap, so that the
-call does not encounter a protection fault while it's running.
-(As usual, none of this is an issue unless GC_enable_incremental
-is called.)
-
-Note that incremental collection is disabled with -DSMALL_CONFIG.
-
-Threads
--------
-
-James Clark has contributed the necessary code to support win32 threads
-with the collector in a DLL.
-Use NT_THREADS_MAKEFILE (a.k.a gc.mak) instead of NT_MAKEFILE
-to build this version. Note that this requires some files whose names
-are more than 8 + 3 characters long. Thus you should unpack the tar file
-so that long file names are preserved. To build the garbage collector
-test with VC++ from the command line, use
-
-nmake /F ".\gc.mak" CFG="gctest - Win32 Release"
-
-This requires that the subdirectory gctest\Release exist.
-The test program and DLL will reside in the Release directory.
-
-This version relies on the collector residing in a dll.
-
-This version currently supports incremental collection only if it is
-enabled before any additional threads are created.
-
-Since 6.3alpha2, threads are also better supported in static library builds
-with Microsoft tools (use NT_STATIC_THREADS_MAKEFILE) and with the GNU
-tools. In all cases,the collector must be built with GC_WIN32_THREADS
-defined, even if the Cygwin pthreads interface is used.
-(NT_STATIC_THREADS_MAKEFILE does this implicitly. Under Cygwin,
-./configure --enable-threads=posix defines GC_WIN32_THREADS.) Threads must be
-created with GC_CreateThread. This can be accomplished by
-including gc.h and then calling CreateThread, which is redefined
-by gc.h.
-
-For the statically linked versions, it is required that GC_init()
-be called before other GC calls, since there seems to be no implicit way
-to initialize the allocation lock. The easiest way to ensure this in
-portable code is to call GC_INIT() from the main executable (not
-a dynamic library) before calling any other GC_ routines.
-
-We strongly advise against using the TerminateThread() win32 API call,
-especially with the garbage collector. Any use is likely to provoke a
-crash in the GC, since it makes it impossible for the collector to
-correctly track threads.
+Digital Mars compiler
+---------------------
+Same as MS Visual C++ but might require
+-DAO_OLD_STYLE_INTERLOCKED_COMPARE_EXCHANGE option to compile with the
+parallel marker enabled.
Watcom compiler
---------------
@@ -188,28 +138,85 @@ If the gc is compiled as dll, the macro ``GC_DLL'' should be defined before
including "gc.h" (for example, with -DGC_DLL compiler option). It's
important, otherwise resulting programs will not run.
-Ivan Demakov (email: ivan@tgrad.nsk.su)
-Win32S
-------
+Special note for OpenWatcom users: the C (unlike the C++) compiler (of the
+latest stable release, not sure for older ones) doesn't force pointer global
+variables (i.e. not struct fields, not sure for locals) to be aligned unless
+optimizing for speed (eg. "-ot" option is set); the "-zp" option (or align
+pragma) only controls alignment for structs; I don't know whether it's a bug or
+a feature (see an old report of same kind -
+http://bugzilla.openwatcom.org/show_bug.cgi?id=664), so You are warned.
+
+
+Incremental Collection
+----------------------
+There is some support for incremental collection. By default, the
+collector chooses between explicit page protection, and GetWriteWatch-based
+write tracking automatically, depending on the platform.
+
+The former is slow and interacts poorly with a debugger.
+Pages are protected. Protection faults are caught by a handler
+installed at the bottom of the handler
+stack. Whenever possible, I recommend adding a call to
+GC_enable_incremental at the last possible moment, after most
+debugging is complete. No system
+calls are wrapped by the collector itself. It may be necessary
+to wrap ReadFile calls that use a buffer in the heap, so that the
+call does not encounter a protection fault while it's running.
+(As usual, none of this is an issue unless GC_enable_incremental
+is called.)
+
+Note that incremental collection is disabled with -DSMALL_CONFIG.
+
+Threads
+-------
+
+This version of the collector by default handles threads similarly
+to other platforms. James Clark's code which tracks threads attached
+to the collector DLL still exists, but requires that both
+- the collector is built in a DLL with GC_DLL defined, and
+- GC_use_threads_discovery() is called before GC initialization, which
+ in turn must happen before creating additional threads.
+We generally recommend avoiding this if possible, since it seems to
+be less than 100% reliable.
+
+Use gc.mak (a.k.a NT_THREADS_MAKEFILE) instead of NT_MAKEFILE
+to build a version that supports both kinds of thread tracking.
+To build the garbage collector
+test with VC++ from the command line, use
+
+nmake /F ".\gc.mak" CFG="gctest - Win32 Release"
+
+This requires that the subdirectory gctest\Release exist.
+The test program and DLL will reside in the Release directory.
+
+This version currently supports incremental collection only if it is
+enabled before any additional threads are created.
+
+Since 6.3alpha2, threads are also better supported in static library builds
+with Microsoft tools (use NT_STATIC_THREADS_MAKEFILE) and with the GNU
+tools. The collector must be built with GC_THREADS defined.
+(NT_STATIC_THREADS_MAKEFILE does this implicitly. Under Cygwin,
+./configure --enable-threads=posix should be used.)
+
+For the normal, non-dll-based thread tracking to work properly,
+threads should be created with GC_CreateThread or GC_beginthreadex,
+and exit normally or call GC_endthreadex or GC_ExitThread. (For
+Cygwin, use standard pthread calls instead.) As in the pthread
+case, including gc.h will redefine CreateThread, _beginthreadex,
+_endthreadex, and ExitThread to call the GC_ versions instead.
-[The following is probably obsolete. The win32s support is still in the
-collector, but I doubt anyone cares, or has tested it recently.]
+Note that, as usual, GC_CreateThread tends to introduce resource leaks
+that are avoided by GC_beginthreadex. There is currently no equivalent of
+_beginthread, and it should not be used.
-The collector runs under both win32s and win32, but with different semantics.
-Under win32, all writable pages outside of the heaps and stack are
-scanned for roots. Thus the collector sees pointers in DLL data
-segments. Under win32s, only the main data segment is scanned.
-(The main data segment should always be scanned. Under some
-versions of win32s, other regions may also be scanned.)
-Thus all accessible objects should be accessible from local variables
-or variables in the main data segment. Alternatively, other data
-segments (e.g. in DLLs) may be registered with the collector by
-calling GC_init() and then GC_register_root_section(a), where
-a is the address of some variable inside the data segment. (Duplicate
-registrations are ignored, but not terribly quickly.)
+GC_INIT should be called from the main executable before other GC calls.
-(There are two reasons for this. We didn't want to see many 16:16
-pointers. And the VirtualQuery call has different semantics under
-the two systems, and under different versions of win32s.)
+We strongly advise against using the TerminateThread() win32 API call,
+especially with the garbage collector. Any use is likely to provoke a
+crash in the GC, since it makes it impossible for the collector to
+correctly track threads.
+To build the collector for Mingw32 Pthreads, use Makefile.direct and
+explicitly set GC_WIN32_PTHREADS. Use -DPTW32_STATIC_LIB for the static
+threads library.
diff --git a/boehm-gc/doc/README.win64 b/boehm-gc/doc/README.win64
new file mode 100644
index 00000000000..416f0348cf2
--- /dev/null
+++ b/boehm-gc/doc/README.win64
@@ -0,0 +1,26 @@
+64-bit Windows on AMD64/Intel EM64T is somewhat supported in the 7.0
+and later release. A collector can be built with Microsoft Visual C++ 2005
+or with mingw-w64 gcc.
+More testing would clearly be helpful.
+
+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 collector is
+at least somewhat functional, run gctest.exe. This should create
+gctest.gc.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.
+
+VC++ note: to suppress warnings use -D_CRT_SECURE_NO_DEPRECATE.
+
+gcc note: -fno-strict-aliasing should be used if optimizing.
diff --git a/boehm-gc/doc/barrett_diagram b/boehm-gc/doc/barrett_diagram
index 27e80dc15cd..6f7d2fe3541 100644
--- a/boehm-gc/doc/barrett_diagram
+++ b/boehm-gc/doc/barrett_diagram
@@ -1,15 +1,15 @@
This is an ASCII diagram of the data structure used to check pointer
-validity. It was provided by Dave Barrett <barrett@asgard.cs.colorado.edu>,
+validity. It was provided by Dave Barrett,
and should be of use to others attempting to understand the code.
The data structure in GC4.X is essentially the same. -HB
- Data Structure used by GC_base in gc3.7:
- 21-Apr-94
-
-
+ Data Structure used by GC_base in gc3.7:
+ 21-Apr-94
+
+
63 LOG_TOP_SZ[11] LOG_BOTTOM_SZ[10] LOG_HBLKSIZE[13]
@@ -17,82 +17,82 @@ The data structure in GC4.X is essentially the same. -HB
p:| | TL_HASH(hi) | | HBLKDISPL(p) |
+------------------+----------------+------------------+------------------+
\-----------------------HBLKPTR(p)-------------------/
- \------------hi-------------------/
+ \------------hi-------------------/
\______ ________/ \________ _______/ \________ _______/
V V V
| | |
- GC_top_index[] | | |
- --- +--------------+ | | |
- ^ | | | | |
- | | | | | |
- TOP +--------------+<--+ | |
- _SZ +-<| [] | * | |
-(items)| +--------------+ if 0 < bi< HBLKSIZE | |
- | | | | then large object | |
- | | | | starts at the bi'th | |
- v | | | HBLK before p. | i |
- --- | +--------------+ | (word- |
- v | aligned) |
- bi= |GET_BI(p){->hash_link}->key==hi | |
- v | |
- | (bottom_index) \ scratch_alloc'd | |
- | ( struct bi ) / by get_index() | |
- --- +->+--------------+ | |
+ GC_top_index[] | | |
+ --- +--------------+ | | |
+ ^ | | | | |
+ | | | | | |
+ TOP +--------------+<--+ | |
+ _SZ +-<| [] | * | |
+(items)| +--------------+ if 0 < bi< HBLKSIZE | |
+ | | | | then large object | |
+ | | | | starts at the bi'th | |
+ v | | | HBLK before p. | i |
+ --- | +--------------+ | (word- |
+ v | aligned) |
+ bi= |GET_BI(p){->hash_link}->key==hi | |
+ v | |
+ | (bottom_index) \ scratch_alloc'd | |
+ | ( struct bi ) / by get_index() | |
+ --- +->+--------------+ | |
^ | | | |
^ | | | |
BOTTOM | | ha=GET_HDR_ADDR(p) | |
_SZ(items)+--------------+<----------------------+ +-------+
- | +--<| index[] | |
- | | +--------------+ GC_obj_map: v
- | | | | from / +-+-+-----+-+-+-+-+ ---
- v | | | GC_add < 0| | | | | | | | ^
- --- | +--------------+ _map_entry \ +-+-+-----+-+-+-+-+ |
+ | +--<| index[] | |
+ | | +--------------+ GC_obj_map: v
+ | | | | from / +-+-+-----+-+-+-+-+ ---
+ v | | | GC_add < 0| | | | | | | | ^
+ --- | +--------------+ _map_entry \ +-+-+-----+-+-+-+-+ |
| | asc_link | +-+-+-----+-+-+-+-+ MAXOBJSZ
- | +--------------+ +-->| | | j | | | | | +1
- | | key | | +-+-+-----+-+-+-+-+ |
- | +--------------+ | +-+-+-----+-+-+-+-+ |
- | | hash_link | | | | | | | | | | v
+ | +--------------+ +-->| | | j | | | | | +1
+ | | key | | +-+-+-----+-+-+-+-+ |
+ | +--------------+ | +-+-+-----+-+-+-+-+ |
+ | | hash_link | | | | | | | | | | v
| +--------------+ | +-+-+-----+-+-+-+-+ ---
- | | |<--MAX_OFFSET--->|
+ | | |<--MAX_OFFSET--->|
| | (bytes)
-HDR(p)| GC_find_header(p) | |<--MAP_ENTRIES-->|
- | \ from | =HBLKSIZE/WORDSZ
+HDR(p)| GC_find_header(p) | |<--MAP_ENTRIES-->|
+ | \ from | =HBLKSIZE/WORDSZ
| (hdr) (struct hblkhdr) / alloc_hdr() | (1024 on Alpha)
+-->+----------------------+ | (8/16 bits each)
-GET_HDR(p)| word hb_sz (words) | |
- +----------------------+ |
+GET_HDR(p)| word hb_sz (words) | |
+ +----------------------+ |
| struct hblk *hb_next | |
- +----------------------+ |
+ +----------------------+ |
|mark_proc hb_mark_proc| |
+----------------------+ |
| char * hb_map |>-------------+
- +----------------------+
- | ushort hb_obj_kind |
- +----------------------+
- | hb_last_reclaimed |
- --- +----------------------+
+ +----------------------+
+ | ushort hb_obj_kind |
+ +----------------------+
+ | hb_last_reclaimed |
+ --- +----------------------+
^ | |
MARK_BITS| hb_marks[] | *if hdr is free, hb_sz + DISCARD_WORDS
_SZ(words)| | is the size of a heap chunk (struct hblk)
v | | of at least MININCR*HBLKSIZE bytes (below),
--- +----------------------+ otherwise, size of each object in chunk.
-Dynamic data structures above are interleaved throughout the heap in blocks of
+Dynamic data structures above are interleaved throughout the heap in blocks of
size MININCR * HBLKSIZE bytes as done by gc_scratch_alloc which cannot be
freed; free lists are used (e.g. alloc_hdr). HBLKs's below are collected.
- (struct hblk)
+ (struct hblk)
--- +----------------------+ < HBLKSIZE --- --- DISCARD_
^ |garbage[DISCARD_WORDS]| aligned ^ ^ HDR_BYTES WORDS
| | | | v (bytes) (words)
- | +-----hb_body----------+ < WORDSZ | --- ---
+ | +-----hb_body----------+ < WORDSZ | --- ---
| | | aligned | ^ ^
| | Object 0 | | hb_sz |
| | | i |(word- (words)|
| | | (bytes)|aligned) v |
| + - - - - - - - - - - -+ --- | --- |
| | | ^ | ^ |
- n * | | j (words) | hb_sz BODY_SZ
+ n * | | j (words) | hb_sz BODY_SZ
HBLKSIZE | Object 1 | v v | (words)
(bytes) | |--------------- v MAX_OFFSET
| + - - - - - - - - - - -+ --- (bytes)
diff --git a/boehm-gc/doc/debugging.html b/boehm-gc/doc/debugging.html
index 7c65f2bb40a..cc51d7f3ee8 100644
--- a/boehm-gc/doc/debugging.html
+++ b/boehm-gc/doc/debugging.html
@@ -1,5 +1,7 @@
-<HTML>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html lang="en-us">
<HEAD>
+<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII" >
<TITLE>Debugging Garbage Collector Related Problems</title>
</head>
<BODY>
@@ -80,9 +82,9 @@ void * big_realloc(void *p, size_t new_size)
{
size_t old_size = GC_size(p);
void * result;
-
- if (new_size <= 10000) return(GC_realloc(p, new_size));
- if (new_size <= old_size) return(p);
+
+ if (new_size &lt;= 10000) return(GC_realloc(p, new_size));
+ if (new_size &lt;= old_size) return(p);
result = GC_malloc_ignore_off_page(new_size);
if (result == 0) return(0);
memcpy(result,p,old_size);
@@ -186,7 +188,8 @@ primitives is <TT>gc_typed.h</tt>, or separate out the pointerfree component.
to allocate large objects. (See <TT>gc.h</tt> and above for details.
Large means &gt; 100K in most environments.)
<LI> If your heap size is larger than 100MB or so, build the collector with
--DLARGE_CONFIG. This allows the collector to keep more precise black-list
+<TT>-DLARGE_CONFIG</tt>.
+This allows the collector to keep more precise black-list
information.
<LI> If you are using heaps close to, or larger than, a gigabyte on a 32-bit
machine, you may want to consider moving to a platform with 64-bit pointers.
@@ -300,7 +303,3 @@ the collector can avoid scanning them.
</ol>
</body>
</html>
-
-
-
-
diff --git a/boehm-gc/doc/doc.am b/boehm-gc/doc/doc.am
new file mode 100644
index 00000000000..df69a5c4cf8
--- /dev/null
+++ b/boehm-gc/doc/doc.am
@@ -0,0 +1,51 @@
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program
+# for any purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+
+## Process this file with automake to produce Makefile.in.
+
+# installed documentation
+#
+dist_pkgdata_DATA = \
+ AUTHORS \
+ README \
+ doc/README.DGUX386 \
+ doc/README.Mac \
+ doc/README.OS2 \
+ doc/README.amiga \
+ doc/README.arm.cross \
+ doc/README.autoconf \
+ doc/README.cmake \
+ doc/README.cords \
+ doc/README.darwin \
+ doc/README.dj \
+ doc/README.environment \
+ doc/README.ews4800 \
+ doc/README.hp \
+ doc/README.linux \
+ doc/README.macros \
+ doc/README.rs6000 \
+ doc/README.sgi \
+ doc/README.solaris2 \
+ doc/README.symbian \
+ doc/README.uts \
+ doc/README.win32 \
+ doc/README.win64 \
+ doc/barrett_diagram \
+ doc/debugging.html \
+ doc/finalization.html \
+ doc/gc.man \
+ doc/gcdescr.html \
+ doc/gcinterface.html \
+ doc/leak.html \
+ doc/overview.html \
+ doc/porting.html \
+ doc/scale.html \
+ doc/simple_example.html \
+ doc/tree.html
diff --git a/boehm-gc/doc/finalization.html b/boehm-gc/doc/finalization.html
new file mode 100644
index 00000000000..3733c0c4992
--- /dev/null
+++ b/boehm-gc/doc/finalization.html
@@ -0,0 +1,190 @@
+<!DOCTYPE HTML>
+<HEAD>
+<TITLE>Finalization in the Boehm-Demers-Weiser collector </TITLE>
+</HEAD>
+<BODY>
+<H1>Finalization</h1>
+Many garbage collectors provide a facility for executing user code
+just before an object is collected. This can be used to reclaim any
+system resources or non-garbage-collected memory associated with the
+object.
+Experience has shown that this can be a useful facility.
+It is indispensable in cases in which system resources are embedded
+in complex data structures (<I>e.g.</i> file descriptors
+in the <A type="text/plain" HREF="../include/cord.h">cord package</a>).
+<P>
+Our collector provides the necessary functionality through
+<TT>GC_register_finalizer</tt> in
+<A type="text/plain" HREF="../include/gc.h">gc.h</a>, or by
+inheriting from <TT>gc_cleanup</tt>
+in <A type="text/plain" HREF="../include/gc_cpp.h">gc_cpp.h</a>.
+<P>
+However, finalization should not be used in the same way as C++
+destructors. In well-written programs there will typically be
+very few uses of finalization. (Garbage collected programs that
+interact with explicitly memory-managed libraries may be an exception.)
+<P>
+In general the following guidelines should be followed:
+<UL>
+<LI>
+Actions that must be executed promptly do not belong in finalizers.
+They should be handled by explicit calls in the code (or C++
+destructors if you prefer). If you expect the action to occur at
+a specific point, this is probably not hard.
+<LI>
+Finalizers are intended for resource reclamation.
+<LI>
+Scarce system resources should be managed explicitly whenever
+convenient. Use finalizers only as a backup mechanism for the
+cases that would be hard to handle explicitly.
+<LI>
+If scarce resources are managed with finalization, the allocation
+routine for that resource (<I>e.g.</i> open for file handles) should force
+a garbage collection (two if that doesn't suffice) if it finds itself
+short of the resource.
+<LI>
+If extremely scarce resources are managed by finalization (<I>e.g.</i>
+file descriptors on systems which have a limit of 20 open files),
+it may be necessary to introduce a descriptor caching scheme to
+hide the resource limit.
+(<I>E.g.</i>, the program would keep real file descriptors
+for the 20 most recently used logically open files.
+Any other needed files would be closed after saving their state.
+They would then be reopened on demand.
+Finalization would logically close the file, closing the
+real descriptor only if it happened to be cached.)
+Note that most modern systems (<I>e.g.</i> Irix&#174;) allow hundreds or
+thousands of open files, and this is typically not an issue.
+<LI>
+Finalization code may
+be run anyplace an allocation or other call to the collector
+takes place.
+In multi-threaded programs, finalizers have to obey the normal
+locking conventions to ensure safety.
+Code run directly from finalizers should not acquire locks that may
+be held during allocation. This restriction can be easily circumvented
+by registering a finalizer which enqueues the real action for execution
+in a separate thread.
+<P>
+In single-threaded code, it is also often easiest to have finalizers
+queue actions, which are then explicitly run during an
+explicit call by the user's program.
+</ul>
+<H1>Topologically Ordered Finalization</h1>
+Our <A HREF="overview.html">conservative garbage collector</a> supports
+a form of finalization
+(with <TT>GC_register_finalizer</tt>)
+in which objects are finalized in topological
+order. If <I>A</i> points to <I>B</i>, and both are registered for
+finalization, it is guaranteed the <I>A</i> will be finalized first.
+This usually guarantees that finalization procedures see only
+unfinalized objects.
+<P>
+This decision is often questioned, particularly since it has an obvious
+disadvantage. The current implementation finalizes long chains of
+finalizable objects one per collection. This is hard to avoid, since
+the first finalizer invoked may store a pointer to the rest of the chain
+in a global variable, making it accessible again. Or it may mutate the
+rest of the chain.
+<P>
+Cycles involving one or more finalizable objects are never finalized.
+<H1>
+Why topological ordering?
+</h1>
+It is important to keep in mind that the choice of finalization ordering
+matters only in relatively rare cases. In spite of the fact that it has
+received a lot of discussion, it is not one of the more important
+decisions in designing a system. Many, especially smaller, applications
+will never notice the difference. Nonetheless, we believe that topologically
+ordered finalization is the right choice.
+<P>
+To understand the justification, observe that if <I>A</i>s
+finalization procedure does not refer to <I>B</i>, we could fairly easily have
+avoided the dependency. We could have split <I>A</i> into <I>A'</i>
+and <I>A''</i> such that any references to <I>A</i> become references to
+<I>A'</i>, <I>A'</i> points to <I>A''</i> but not vice-versa, only fields
+needed for finalization are stored in <I>A''</i>, and <I>A''</i> is enabled
+for finalization. (<TT>GC_register_disappearing_link</tt> provides an
+alternative mechanism that does not require breaking up objects.)
+<P>
+Thus assume that <I>A</i> actually does need access to <I>B</i> during
+finalization. To make things concrete, assume that <I>B</i> is
+finalizable because it holds a pointer to a C object, which must be
+explicitly deallocated. (This is likely to be one of the most common
+uses of finalization.) If <I>B</i> happens to be finalized first,
+<I>A</i> will see a dangling pointer during its finalization. But a
+principal goal of garbage collection was to avoid dangling pointers.
+<P>
+Note that the client program could enforce topological ordering
+even if the system didn't. A pointer to <I>B</i> could be stored in
+some globally visible place, where it is cleared only by <I>A</i>s
+finalizer. But this puts the burden to ensure safety back on the
+programmer.
+<P>
+With topologically ordered finalization, the programmer
+can fail to split an object, thus leaving an accidental cycle. This
+results in a leak, which is arguably less dangerous than a dangling
+pointer. More importantly, it is <I>much</i> easier to diagnose,
+since the garbage collector would have to go out of its way not to
+notice finalization cycles. It can trivially report them.
+<P>
+Furthermore unordered finalization does not really solve the problem
+of cycles. Consider the above case in which <I>A</i>s
+finalization procedure depends on <I>B</i>, and thus a pointer to <I>B</i>
+is stored in a global data structure, to be cleared by <I>A</i>s finalizer.
+If there is an accidental pointer from <I>B</i> back to <I>A</i>, and
+thus a cycle, neither <I>B</i> nor <I>A</i> will become unreachable.
+The leak is there, just as in the topologically ordered case, but it is
+hidden from easy diagnosis.
+<P>
+A number of alternative finalization orderings have been proposed, e.g.
+based on statically assigned priorities. In our opinion, these are much
+more likely to require complex programming discipline to use in a large
+modular system. (Some of them, e.g. Guardians proposed by Dybvig,
+Bruggeman, and Eby, do avoid some problems which arise in combination
+with certain other collection algorithms.)
+<P>
+Fundamentally, a garbage collector assumes that objects reachable
+via pointer chains may be accessed, and thus should be preserved.
+Topologically ordered finalization simply extends this to object finalization;
+an finalizable object reachable from another finalizer via a pointer chain
+is presumed to be accessible by the finalizer, and thus should not be
+finalized.
+
+<H1>Programming with topological finalization</h1>
+Experience with Cedar has shown that cycles or long chains of finalizable
+objects are typically not a problem.
+Finalizable objects are typically rare.
+There are several ways to reduce spurious dependencies between finalizable
+objects. Splitting objects as discussed above is one technique.
+The collector also provides <TT>GC_register_disappearing_link</tt>, which
+explicitly nils a pointer before determining finalization ordering.
+<P>
+Some so-called "operating systems" fail to clean up some resources associated
+with a process. These resources must be deallocated at all cost before
+process exit whether or not they are still referenced. Probably the best
+way to deal with those is by not relying exclusively on finalization.
+They should be registered in a table of weak pointers (implemented as
+disguised pointers cleared by the finalization procedure that deallocates
+the resource). If any references are still left at process exit, they
+can be explicitly deallocated then.
+
+<H1>Getting around topological finalization ordering</h1>
+There are certain situations in which cycles between finalizable objects are
+genuinely unavoidable. Most notably, C++ compilers introduce self-cycles
+to represent inheritance. <TT>GC_register_finalizer_ignore_self</tt> tells the
+finalization part of the collector to ignore self cycles.
+This is used by the C++ interface.
+<P>
+Finalize.c actually contains an intentionally undocumented mechanism
+for registering a finalizable object with user-defined dependencies.
+The problem is that this dependency information is also used for memory
+reclamation, not just finalization ordering. Thus misuse can result in
+dangling pointers even if finalization doesn't create any.
+The risk of dangling pointers can be eliminated by building the collector
+with -DJAVA_FINALIZATION. This forces objects reachable from finalizers
+to be marked, even though this dependency is not considered for finalization
+ordering.
+
+</body>
+</html>
diff --git a/boehm-gc/doc/gc.man b/boehm-gc/doc/gc.man
index 2a550c71247..ef1592890ef 100644
--- a/boehm-gc/doc/gc.man
+++ b/boehm-gc/doc/gc.man
@@ -30,7 +30,13 @@ instead of calling GC_malloc and friends directly. This allows debugging
versions of the routines to be substituted by defining GC_DEBUG before
including gc.h.
.LP
-See the documentation in the include file gc_cpp.h for an alternate, C++ specific interface to the garbage collector.
+See the documentation in the include files gc_cpp.h and gc_allocator.h,
+as well as the gcinterface.html file in the distribution,
+for an alternate, C++ specific interface to the garbage collector.
+Note that C++ programs generally
+need to be careful to ensure that all allocated memory (whether via new,
+malloc, or STL allocators) that may point to garbage collected memory
+is either itself garbage collected, or at least traced by the collector.
.LP
Unlike the standard implementations of malloc,
.I
@@ -71,7 +77,7 @@ Fully portable code should call
GC_INIT
from the main program before making any other GC calls.
On most platforms this does nothing and the collector is initialized on first use.
-On a few platforms explicit initialization is necessary. And it can never hurt.
+On a few platforms explicit initialization is necessary. And it can never hurt.
.LP
Debugging versions of many of the above routines are provided as macros. Their names are identical to the above, but consist of all capital letters. If GC_DEBUG is defined before gc.h is included, these routines do additional checking, and allow the leak detecting version of the collector to produce slightly more useful output. Without GC_DEBUG defined, they behave exactly like the lower-case versions.
.LP
diff --git a/boehm-gc/doc/gcdescr.html b/boehm-gc/doc/gcdescr.html
index cab6bde4fba..7879ef496e3 100644
--- a/boehm-gc/doc/gcdescr.html
+++ b/boehm-gc/doc/gcdescr.html
@@ -1,7 +1,7 @@
<HTML>
<HEAD>
<TITLE> Conservative GC Algorithmic Overview </TITLE>
- <AUTHOR> Hans-J. Boehm, HP Labs (Much of this was written at SGI)</author>
+ <AUTHOR> Hans-J. Boehm, HP Labs (Some of this was written at SGI)</author>
</HEAD>
<BODY>
<H1> <I>This is under construction, and may always be.</i> </h1>
@@ -112,8 +112,19 @@ is significantly complicated by black-listing issues
<P>
Small blocks are allocated in chunks of size <TT>HBLKSIZE</tt>.
Each chunk is
-dedicated to only one object size and kind. The allocator maintains
+dedicated to only one object size and kind.
+<P>
+The allocator maintains
separate free lists for each size and kind of object.
+Associated with each kind is an array of free list pointers,
+with entry <TT>freelist[</tt><I>i</i><TT>]</tt> pointing to
+a free list of size <I>i</i> objects.
+In recent versions of the
+collector, index <TT>i</tt> is expressed in granules, which are the
+minimum allocatable unit, typically 8 or 16 bytes.
+The free lists themselves are
+linked through the first word in each object (see <TT>obj_link()</tt>
+macro).
<P>
Once a large block is split for use in smaller objects, it can only
be used for objects of that size, unless the collector discovers a completely
@@ -131,7 +142,8 @@ the requested size, subject to alignment constraints.
See <TT>GC_init_size_map</tt> for details.
<P>
The actual size rounding operation during small object allocation is
-implemented as a table lookup in <TT>GC_size_map</tt>.
+implemented as a table lookup in <TT>GC_size_map</tt> which maps
+a requested allocation size in bytes to a number of granules.
<P>
Both collector initialization and computation of allocated sizes are
handled carefully so that they do not slow down the small object fast
@@ -156,7 +168,7 @@ fragmentation. In particular:
<UL>
<LI> Programs with a large root set size and
little live heap memory will expand the heap to amortize the cost of
-scanning the roots.
+scanning the roots.
<LI> Versions 5.x of the collector actually collect more frequently in
nonincremental mode. The large block allocator usually refuses to split
large heap blocks once the garbage collection threshold is
@@ -206,7 +218,7 @@ between <TT>DATASTART</tt> and <TT>DATAEND</tt>, as defined in
<TT>gcconfig.h</tt>. However, in most cases, this will also involve
static data regions associated with dynamic libraries. These are
identified by the mostly platform-specific code in <TT>dyn_load.c</tt>.
-</ul>
+</ul>
The marker maintains an explicit stack of memory regions that are known
to be accessible, but that have not yet been searched for contained pointers.
Each stack entry contains the starting address of the block to be scanned,
@@ -381,7 +393,7 @@ Both <TT>GC_register_disappearing_link</tt> and
table. The hash table is allocated out of collected memory, but
the reference to the finalizable object is hidden from the collector.
Currently finalization requests are processed non-incrementally at the
-end of a mark cycle.
+end of a mark cycle.
<P>
The collector makes an initial pass over the table of finalizable objects,
pushing the contents of unmarked objects onto the mark stack.
@@ -395,7 +407,7 @@ object itself becomes marked, we have uncovered
a cycle involving the object. This usually results in a warning from the
collector. Such objects are not finalized, since it may be
unsafe to do so. See the more detailed
-<A HREF="http://www.hpl.hp.com/personal/Hans_Boehm/gc/finalization.html"> discussion of finalization semantics</a>.
+<A HREF="finalization.html"> discussion of finalization semantics</a>.
<P>
Any objects remaining unmarked at the end of this process are added to
a queue of objects whose finalizers can be run. Depending on collector
@@ -438,7 +450,7 @@ bytes of allocation have taken place.
After <TT>GC_full_freq</tt> minor collections a major collection
is started.
<P>
-All collections initially run interrupted until a predetermined
+All collections initially run uninterrupted until a predetermined
amount of time (50 msecs by default) has expired. If this allows
the collection to complete entirely, we can avoid correcting
for data structure modifications during the collection. If it does
@@ -467,7 +479,7 @@ may actually be better with mprotect and signals.)
(<TT>PCR_VDB</tt>) By relying on an external dirty bit implementation, in this
case the one in Xerox PCR.
<LI>
-(<TT>DEFAULT_VDB</tt>) By treating all pages as dirty. This is the default if
+(<TT>DEFAULT_VDB</tt>) By treating all pages as dirty. This is the default if
none of the other techniques is known to be usable, and
<TT>GC_malloc_stubborn</tt> is not used. Practical only for testing, or if
the vast majority of objects use <TT>GC_malloc_stubborn</tt>.
@@ -487,7 +499,7 @@ to a currently unallocated page inside the heap. Pages that have been
the targets of such near misses are likely to be the targets of
misidentified ``pointers'' in the future. To minimize the future
damage caused by such misidentifications they will be allocated only to
-small pointerfree objects.
+small pointerfree objects.
<P>
The collector understands two different kinds of black-listing. A
page may be black listed for interior pointer references
@@ -546,12 +558,72 @@ accomplished with <TT># define</tt>'s in <TT>gc.h</tt>
(really <TT>gc_pthread_redirects.h</tt>), or optionally
by using ld's function call wrapping mechanism under Linux.
<P>
-Recent versions of the collector support several facilites to enhance
+Recent versions of the collector support several facilities to enhance
the processor-scalability and thread performance of the collector.
These are discussed in more detail <A HREF="scale.html">here</a>.
+We briefly outline the data approach to thread-local allocation in the
+next section.
+<H2>Thread-local allocation</h2>
+If thread-local allocation is enabled, the collector keeps separate
+arrays of free lists for each thread. Thread-local allocation
+is currently only supported on a few platforms.
+<P>
+The free list arrays associated
+with each thread are only used to satisfy requests for objects that
+are both very small, and belong to one of a small number of well-known
+kinds. These currently include "normal" and pointer-free objects.
+Depending on the configuration, "gcj" objects may also be included.
+<P>
+Thread-local free list entries contain either a pointer to the first
+element of a free list, or they contain a counter of the number of
+allocation granules, corresponding to objects of this size,
+allocated so far. Initially they contain the
+value one, i.e. a small counter value.
+<P>
+Thread-local allocation allocates directly through the global
+allocator, if the object is of a size or kind not covered by the
+local free lists.
+<P>
+If there is an appropriate local free list, the allocator checks whether it
+contains a sufficiently small counter value. If so, the counter is simply
+incremented by the counter value, and the global allocator is used.
+In this way, the initial few allocations of a given size bypass the local
+allocator. A thread that only allocates a handful of objects of a given
+size will not build up its own free list for that size. This avoids
+wasting space for unpopular objects sizes or kinds.
+<P>
+Once the counter passes a threshold, <TT>GC_malloc_many</tt> is called
+to allocate roughly <TT>HBLKSIZE</tt> space and put it on the corresponding
+local free list. Further allocations of that size and kind then use
+this free list, and no longer need to acquire the allocation lock.
+The allocation procedure is otherwise similar to the global free lists.
+The local free lists are also linked using the first word in the object.
+In most cases this means they require considerably less time.
+<P>
+Local free lists are treated buy most of the rest of the collector
+as though they were in-use reachable data. This requires some care,
+since pointer-free objects are not normally traced, and hence a special
+tracing procedure is required to mark all objects on pointer-free and
+gcj local free lists.
+<P>
+On thread exit, any remaining thread-local free list entries are
+transferred back to the global free list.
+<P>
+Note that if the collector is configured for thread-local allocation,
+GC versions before 7 do not invoke the thread-local allocator by default.
+<TT>GC_malloc</tt> only uses thread-local allocation in version 7 and later.
+<P>
+For some more details see <A HREF="scale.html">here</a>, and the
+technical report entitled
+<A HREF="http://www.hpl.hp.com/techreports/2000/HPL-2000-165.html">
+``Fast Multiprocessor Memory Allocation and Garbage Collection''
+</a>
+<P>
+<HR>
<P>
Comments are appreciated. Please send mail to
-<A HREF="mailto:boehm@acm.org"><TT>boehm@acm.org</tt></a> or
+<A HREF="mailto:gc@linux.hpl.hp.com"><tt>gc@linux.hpl.hp.com</tt></a>
+(GC mailing list) or
<A HREF="mailto:Hans.Boehm@hp.com"><TT>Hans.Boehm@hp.com</tt></a>
<P>
This is a modified copy of a page written while the author was at SGI.
diff --git a/boehm-gc/doc/gcinterface.html b/boehm-gc/doc/gcinterface.html
new file mode 100644
index 00000000000..eaa038c4a8a
--- /dev/null
+++ b/boehm-gc/doc/gcinterface.html
@@ -0,0 +1,283 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html lang="en-us">
+<HEAD>
+<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII" >
+<TITLE>Garbage Collector Interface</TITLE>
+</HEAD>
+<BODY>
+<H1>C Interface</h1>
+On many platforms, a single-threaded garbage collector library can be built
+to act as a plug-in malloc replacement.
+(Build with <TT>-DREDIRECT_MALLOC=GC_malloc -DIGNORE_FREE</tt>.)
+This is often the best way to deal with third-party libraries
+which leak or prematurely free objects.
+<TT>-DREDIRECT_MALLOC=GC_malloc</tt> is intended
+primarily as an easy way to adapt old code, not for new development.
+<P>
+New code should use the interface discussed below.
+<P>
+Code must be linked against the GC library. On most UNIX platforms,
+depending on how the collector is built, this will be <TT>gc.a</tt>
+or <TT>libgc.{a,so}</tt>.
+<P>
+The following describes the standard C interface to the garbage collector.
+It is not a complete definition of the interface. It describes only the
+most commonly used functionality, approximately in decreasing order of
+frequency of use.
+The full interface is described in
+<A type="text/plain" HREF="../include/gc.h">gc.h</a>
+or <TT>gc.h</tt> in the distribution.
+<P>
+Clients should include <TT>gc.h</tt>.
+<P>
+In the case of multithreaded code,
+<TT>gc.h</tt> should be included after the threads header file, and
+after defining the appropriate <TT>GC_</tt><I>XXXX</i><TT>_THREADS</tt> macro.
+(For 6.2alpha4 and later, simply defining <TT>GC_THREADS</tt> should suffice.)
+The header file <TT>gc.h</tt> must be included
+in files that use either GC or threads primitives, since threads primitives
+will be redefined to cooperate with the GC on many platforms.
+<P>
+Thread users should also be aware that on many platforms objects reachable
+only from thread-local variables may be prematurely reclaimed.
+Thus objects pointed to by thread-local variables should also be pointed to
+by a globally visible data structure. (This is viewed as a bug, but as
+one that is exceedingly hard to fix without some libc hooks.)
+<DL>
+<DT> <B>void * GC_MALLOC(size_t <I>nbytes</i>)</b>
+<DD>
+Allocates and clears <I>nbytes</i> of storage.
+Requires (amortized) time proportional to <I>nbytes</i>.
+The resulting object will be automatically deallocated when unreferenced.
+References from objects allocated with the system malloc are usually not
+considered by the collector. (See <TT>GC_MALLOC_UNCOLLECTABLE</tt>, however.
+Building the collector with <TT>-DREDIRECT_MALLOC=GC_malloc_uncollectable
+is often a way around this.)
+<TT>GC_MALLOC</tt> is a macro which invokes <TT>GC_malloc</tt> by default or,
+if <TT>GC_DEBUG</tt>
+is defined before <TT>gc.h</tt> is included, a debugging version that checks
+occasionally for overwrite errors, and the like.
+<DT> <B>void * GC_MALLOC_ATOMIC(size_t <I>nbytes</i>)</b>
+<DD>
+Allocates <I>nbytes</i> of storage.
+Requires (amortized) time proportional to <I>nbytes</i>.
+The resulting object will be automatically deallocated when unreferenced.
+The client promises that the resulting object will never contain any pointers.
+The memory is not cleared.
+This is the preferred way to allocate strings, floating point arrays,
+bitmaps, etc.
+More precise information about pointer locations can be communicated to the
+collector using the interface in
+<A type="text/plain" HREF="../include/gc_typed.h">gc_typed.h</a> in the distribution.
+<DT> <B>void * GC_MALLOC_UNCOLLECTABLE(size_t <I>nbytes</i>)</b>
+<DD>
+Identical to <TT>GC_MALLOC</tt>,
+except that the resulting object is not automatically
+deallocated. Unlike the system-provided malloc, the collector does
+scan the object for pointers to garbage-collectable memory, even if the
+block itself does not appear to be reachable. (Objects allocated in this way
+are effectively treated as roots by the collector.)
+<DT> <B> void * GC_REALLOC(void *<I>old</i>, size_t <I>new_size</i>) </b>
+<DD>
+Allocate a new object of the indicated size and copy (a prefix of) the
+old object into the new object. The old object is reused in place if
+convenient. If the original object was allocated with
+<TT>GC_MALLOC_ATOMIC</tt>,
+the new object is subject to the same constraints. If it was allocated
+as an uncollectable object, then the new object is uncollectable, and
+the old object (if different) is deallocated.
+<DT> <B> void GC_FREE(void *<I>dead</i>) </b>
+<DD>
+Explicitly deallocate an object. Typically not useful for small
+collectable objects.
+<DT> <B> void * GC_MALLOC_IGNORE_OFF_PAGE(size_t <I>nbytes</i>) </b>
+<DD>
+<DT> <B> void * GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(size_t <I>nbytes</i>) </b>
+<DD>
+Analogous to <TT>GC_MALLOC</tt> and <TT>GC_MALLOC_ATOMIC</tt>,
+except that the client
+guarantees that as long
+as the resulting object is of use, a pointer is maintained to someplace
+inside the first 512 bytes of the object. This pointer should be declared
+volatile to avoid interference from compiler optimizations.
+(Other nonvolatile pointers to the object may exist as well.)
+This is the
+preferred way to allocate objects that are likely to be &gt; 100KBytes in size.
+It greatly reduces the risk that such objects will be accidentally retained
+when they are no longer needed. Thus space usage may be significantly reduced.
+<DT> <B> void GC_INIT(void) </b>
+<DD>
+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. 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>
+<DD>
+Explicitly force a garbage collection.
+<DT> <B> void GC_enable_incremental(void) </b>
+<DD>
+Cause the garbage collector to perform a small amount of work
+every few invocations of <TT>GC_MALLOC</tt> or the like, instead of performing
+an entire collection at once. This is likely to increase total
+running time. It will improve response on a platform that either has
+suitable support in the garbage collector (Linux and most Unix
+versions, win32 if the collector was suitably built) or if "stubborn"
+allocation is used (see
+<A type="text/plain" HREF="../include/gc.h">gc.h</a>).
+On many platforms this interacts poorly with system calls
+that write to the garbage collected heap.
+<DT> <B> GC_warn_proc GC_set_warn_proc(GC_warn_proc <I>p</i>) </b>
+<DD>
+Replace the default procedure used by the collector to print warnings.
+The collector
+may otherwise write to stderr, most commonly because GC_malloc was used
+in a situation in which GC_malloc_ignore_off_page would have been more
+appropriate. See <A type="text/plain" HREF="../include/gc.h">gc.h</a> for details.
+<DT> <B> void GC_REGISTER_FINALIZER(...) </b>
+<DD>
+Register a function to be called when an object becomes inaccessible.
+This is often useful as a backup method for releasing system resources
+(<I>e.g.</i> closing files) when the object referencing them becomes
+inaccessible.
+It is not an acceptable method to perform actions that must be performed
+in a timely fashion.
+See <A type="text/plain" HREF="../include/gc.h">gc.h</a> for details of the interface.
+See <A HREF="finalization.html">here</a> for a more detailed discussion
+of the design.
+<P>
+Note that an object may become inaccessible before client code is done
+operating on objects referenced by its fields.
+Suitable synchronization is usually required.
+See <A HREF="http://portal.acm.org/citation.cfm?doid=604131.604153">here</a>
+or <A HREF="http://www.hpl.hp.com/techreports/2002/HPL-2002-335.html">here</a>
+for details.
+</dl>
+<P>
+If you are concerned with multiprocessor performance and scalability,
+you should consider enabling and using thread local allocation.
+<P>
+If your platform
+supports it, you should build the collector with parallel marking support
+(<TT>-DPARALLEL_MARK</tt>, or <TT>--enable-parallel-mark</tt>).
+<P>
+If the collector is used in an environment in which pointer location
+information for heap objects is easily available, this can be passed on
+to the collector using the interfaces in either <TT>gc_typed.h</tt>
+or <TT>gc_gcj.h</tt>.
+<P>
+The collector distribution also includes a <B>string package</b> that takes
+advantage of the collector. For details see
+<A type="text/plain" HREF="../include/cord.h">cord.h</a>
+
+<H1>C++ Interface</h1>
+The C++ interface is implemented as a thin layer on the C interface.
+Unfortunately, this thin layer appears to be very sensitive to variations
+in C++ implementations, particularly since it tries to replace the global
+::new operator, something that appears to not be well-standardized.
+Your platform may need minor adjustments in this layer (gc_cpp.cc, gc_cpp.h,
+and possibly gc_allocator.h). Such changes do not require understanding
+of collector internals, though they may require a good understanding of
+your platform. (Patches enhancing portability are welcome.
+But it's easy to break one platform by fixing another.)
+<P>
+Usage of the collector from C++ is also complicated by the fact that there
+are many "standard" ways to allocate memory in C++. The default ::new
+operator, default malloc, and default STL allocators allocate memory
+that is not garbage collected, and is not normally "traced" by the
+collector. This means that any pointers in memory allocated by these
+default allocators will not be seen by the collector. Garbage-collectable
+memory referenced only by pointers stored in such default-allocated
+objects is likely to be reclaimed prematurely by the collector.
+<P>
+It is the programmers responsibility to ensure that garbage-collectable
+memory is referenced by pointers stored in one of
+<UL>
+<LI> Program variables
+<LI> Garbage-collected objects
+<LI> Uncollected but "traceable" objects
+</ul>
+"Traceable" objects are not necessarily reclaimed by the collector,
+but are scanned for pointers to collectable objects.
+They are usually allocated by <TT>GC_MALLOC_UNCOLLECTABLE</tt>, as described
+above, and through some interfaces described below.
+<P>
+(On most platforms, the collector may not trace correctly from in-flight
+exception objects. Thus objects thrown as exceptions should only
+point to otherwise reachable memory. This is another bug whose
+proper repair requires platform hooks.)
+<P>
+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. 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 include a hopefully standard-conforming
+allocator implementation in <TT>gc_allocator.h</tt>. It defines
+<UL>
+<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.
+The former allocates uncollectable but traced memory.
+The latter allocates garbage-collected memory.
+<P>
+These should work with any fully standard-conforming C++ compiler.
+<P>
+Users of the <A HREF="http://www.sgi.com/tech/stl">SGI extended STL</a>
+or its derivatives (including most g++ versions)
+may instead be able to include <TT>new_gc_alloc.h</tt> before including
+STL header files. This is increasingly discouraged.
+<P>
+This defines SGI-style allocators
+<UL>
+<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 <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 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
+inherit from class gc.
+For details see <A type="text/plain" HREF="../include/gc_cpp.h">gc_cpp.h</a>.
+<P>
+Linking against libgccpp in addition to the gc library overrides
+::new (and friends) to allocate traceable memory but uncollectable
+memory, making it safe to refer to collectable objects from the resulting
+memory.
+<DT> <B> C interface </b>
+<DD>
+It is also possible to use the C interface from
+<A type="text/plain" HREF="../include/gc.h">gc.h</a> directly.
+On platforms which use malloc to implement ::new, it should usually be possible
+to use a version of the collector that has been compiled as a malloc
+replacement. It is also possible to replace ::new and other allocation
+functions suitably, as is done by libgccpp.
+<P>
+Note that user-implemented small-block allocation often works poorly with
+an underlying garbage-collected large block allocator, since the collector
+has to view all objects accessible from the user's free list as reachable.
+This is likely to cause problems if <TT>GC_MALLOC</tt>
+is used with something like
+the original HP version of STL.
+This approach works well with the SGI versions of the STL only if the
+<TT>malloc_alloc</tt> allocator is used.
+</dl>
+</body>
+</html>
diff --git a/boehm-gc/doc/leak.html b/boehm-gc/doc/leak.html
new file mode 100644
index 00000000000..7751a1315be
--- /dev/null
+++ b/boehm-gc/doc/leak.html
@@ -0,0 +1,208 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html lang="en-us">
+<HEAD>
+<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII" >
+<TITLE>Using the Garbage Collector as Leak Detector</title>
+</head>
+<BODY>
+<H1>Using the Garbage Collector as Leak Detector</h1>
+The garbage collector may be used as a leak detector.
+In this case, the primary function of the collector is to report
+objects that were allocated (typically with <TT>GC_MALLOC</tt>),
+not deallocated (normally with <TT>GC_FREE</tt>), but are
+no longer accessible. Since the object is no longer accessible,
+there in normally no way to deallocate the object at a later time;
+thus it can safely be assumed that the object has been "leaked".
+<P>
+This is substantially different from counting leak detectors,
+which simply verify that all allocated objects are eventually
+deallocated. A garbage-collector based leak detector can provide
+somewhat more precise information when an object was leaked.
+More importantly, it does not report objects that are never
+deallocated because they are part of "permanent" data structures.
+Thus it does not require all objects to be deallocated at process
+exit time, a potentially useless activity that often triggers
+large amounts of paging.
+<P>
+All non-ancient versions of the garbage collector provide
+leak detection support. Version 5.3 adds the following
+features:
+<OL>
+<LI> Leak detection mode can be initiated at run-time by
+setting <TT>GC_find_leak</tt> instead of building the
+collector with <TT>FIND_LEAK</tt>
+defined. This variable should be set to a nonzero value
+at program startup.
+<LI> Leaked objects should be reported and then correctly garbage collected.
+Prior versions either reported leaks or functioned as a garbage collector.
+</ol>
+For the rest of this description we will give instructions that work
+with any reasonable version of the collector.
+<P>
+To use the collector as a leak detector, follow the following steps:
+<OL>
+<LI> Build the collector with <TT>-DFIND_LEAK</tt>. Otherwise use default
+build options.
+<LI> Change the program so that all allocation and deallocation goes
+through the garbage collector.
+<LI> Arrange to call <TT>GC_gcollect</tt> at appropriate points to check
+for leaks.
+(For sufficiently long running programs, this will happen implicitly,
+but probably not with sufficient frequency.)
+</ol>
+The second step can usually be accomplished with the
+<TT>-DREDIRECT_MALLOC=GC_malloc</tt> option when the collector is built,
+or by defining <TT>malloc</tt>, <TT>calloc</tt>,
+<TT>realloc</tt> and <TT>free</tt>
+to call the corresponding garbage collector functions.
+But this, by itself, will not yield very informative diagnostics,
+since the collector does not keep track of information about
+how objects were allocated. The error reports will include
+only object addresses.
+<P>
+For more precise error reports, as much of the program as possible
+should use the all uppercase variants of these functions, after
+defining <TT>GC_DEBUG</tt>, and then including <TT>gc.h</tt>.
+In this environment <TT>GC_MALLOC</tt> is a macro which causes
+at least the file name and line number at the allocation point to
+be saved as part of the object. Leak reports will then also include
+this information.
+<P>
+Many collector features (<I>e.g</i> stubborn objects, finalization,
+and disappearing links) are less useful in this context, and are not
+fully supported. Their use will usually generate additional bogus
+leak reports, since the collector itself drops some associated objects.
+<P>
+The same is generally true of thread support. However, as of 6.0alpha4,
+correct leak reports should be generated with linuxthreads.
+<P>
+On a few platforms (currently Solaris/SPARC, Irix, and, with -DSAVE_CALL_CHAIN,
+Linux/X86), <TT>GC_MALLOC</tt>
+also causes some more information about its call stack to be saved
+in the object. Such information is reproduced in the error
+reports in very non-symbolic form, but it can be very useful with the
+aid of a debugger.
+<H2>An Example</h2>
+The following header file <TT>leak_detector.h</tt> is included in the
+"include" subdirectory of the distribution:
+<PRE>
+#define GC_DEBUG
+#include "gc.h"
+#define malloc(n) GC_MALLOC(n)
+#define calloc(m,n) GC_MALLOC((m)*(n))
+#define free(p) GC_FREE(p)
+#define realloc(p,n) GC_REALLOC((p),(n))
+#define CHECK_LEAKS() GC_gcollect()
+</pre>
+<P>
+Assume the collector has been built with <TT>-DFIND_LEAK</tt>. (For
+newer versions of the collector, we could instead add the statement
+<TT>GC_find_leak = 1</tt> as the first statement in <TT>main()</tt>.
+<P>
+The program to be tested for leaks can then look like:
+<PRE>
+#include "leak_detector.h"
+
+main() {
+ int *p[10];
+ int i;
+ /* GC_find_leak = 1; for new collector versions not */
+ /* compiled with -DFIND_LEAK. */
+ for (i = 0; i &lt; 10; ++i) {
+ p[i] = malloc(sizeof(int)+i);
+ }
+ for (i = 1; i &lt; 10; ++i) {
+ free(p[i]);
+ }
+ for (i = 0; i &lt; 9; ++i) {
+ p[i] = malloc(sizeof(int)+i);
+ }
+ CHECK_LEAKS();
+}
+</pre>
+<P>
+On an Intel X86 Linux system this produces on the stderr stream:
+<PRE>
+Leaked composite object at 0x806dff0 (leak_test.c:8, sz=4)
+</pre>
+(On most unmentioned operating systems, the output is similar to this.
+If the collector had been built on Linux/X86 with -DSAVE_CALL_CHAIN,
+the output would be closer to the Solaris example. For this to work,
+the program should not be compiled with -fomit_frame_pointer.)
+<P>
+On Irix it reports
+<PRE>
+Leaked composite object at 0x10040fe0 (leak_test.c:8, sz=4)
+ Caller at allocation:
+ ##PC##= 0x10004910
+</pre>
+and on Solaris the error report is
+<PRE>
+Leaked composite object at 0xef621fc8 (leak_test.c:8, sz=4)
+ Call chain at allocation:
+ args: 4 (0x4), 200656 (0x30FD0)
+ ##PC##= 0x14ADC
+ args: 1 (0x1), -268436012 (0xEFFFFDD4)
+ ##PC##= 0x14A64
+</pre>
+In the latter two cases some additional information is given about
+how malloc was called when the leaked object was allocated. For
+Solaris, the first line specifies the arguments to <TT>GC_debug_malloc</tt>
+(the actual allocation routine), The second the program counter inside
+main, the third the arguments to <TT>main</tt>, and finally the program
+counter inside the caller to main (i.e. in the C startup code).
+<P>
+In the Irix case, only the address inside the caller to main is given.
+<P>
+In many cases, a debugger is needed to interpret the additional information.
+On systems supporting the "adb" debugger, the <TT>tools/callprocs.sh</tt>
+script can be used to replace program counter values with symbolic names.
+As of version 6.1, the collector tries to generate symbolic names for
+call stacks if it knows how to do so on the platform. This is true on
+Linux/X86, but not on most other platforms.
+<H2>Simplified leak detection under Linux</h2>
+Since version 6.1, it should be possible to run the collector in leak
+detection mode on a program a.out under Linux/X86 as follows:
+<OL>
+<LI> <I>Ensure that a.out is a single-threaded executable, or you are using
+a very recent (7.0alpha7+) collector version on Linux.</i>
+On most platforms this does not
+work at all for multithreaded programs.
+<LI> If possible, ensure that the <TT>addr2line</tt> program is installed in
+<TT>/usr/bin</tt>. (It comes with most Linux distributions.)
+<LI> If possible, compile your program, which we'll call <TT>a.out</tt>,
+with full debug information.
+This will improve the quality of the leak reports. With this approach, it is
+no longer necessary to call <TT>GC_</tt> routines explicitly,
+though that can also
+improve the quality of the leak reports.
+<LI> Build the collector and install it in directory <I>foo</i> as follows:
+<UL>
+<LI> <TT>configure --prefix=<I>foo</i> --enable-gc-debug --enable-redirect-malloc
+--disable-threads</tt>
+<LI> <TT>make</tt>
+<LI> <TT>make install</tt>
+</ul>
+With a very recent collector on Linux, it may sometimes be safe to omit
+the <TT>--disable-threads</tt>. But the combination of thread support
+and <TT>malloc</tt> replacement is not yet rock solid.
+<LI> Set environment variables as follows:
+<UL>
+<LI> <TT>LD_PRELOAD=</tt><I>foo</i><TT>/lib/libgc.so</tt>
+<LI> <TT>GC_FIND_LEAK</tt>
+<LI> You may also want to set <TT>GC_PRINT_STATS</tt>
+(to confirm that the collector is running) and/or
+<TT>GC_LOOP_ON_ABORT</tt> (to facilitate debugging from another
+window if something goes wrong).
+</ul>
+<LI> Simply run <TT>a.out</tt> as you normally would. Note that if you run anything
+else (<I>e.g.</i> your editor) with those environment variables set,
+it will also be leak tested. This may or may not be useful and/or
+embarrassing. It can generate
+mountains of leak reports if the application wasn't designed to avoid leaks,
+<I>e.g.</i> because it's always short-lived.
+</ol>
+This has not yet been thoroughly tested on large applications, but it's known
+to do the right thing on at least some small ones.
+</body>
+</html>
diff --git a/boehm-gc/doc/overview.html b/boehm-gc/doc/overview.html
new file mode 100644
index 00000000000..8c562bf4299
--- /dev/null
+++ b/boehm-gc/doc/overview.html
@@ -0,0 +1,446 @@
+<!DOCTYPE HTML>
+<html><head><title>A garbage collector for C and C++</title></head>
+<body>
+<table bgcolor="#f0f0ff" cellpadding="10%">
+ <tbody><tr>
+ <td><a href="gcinterface.html">Interface Overview</a></td>
+ <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/04tutorial.pdf">Tutorial Slides</a></td>
+ <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/faq.html">FAQ</a></td>
+ <td><a href="simple_example.html">Example</a></td>
+ <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source">Download</a></td>
+ <td><a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/license.txt">License</a></td>
+ </tr>
+</tbody></table>
+<h1>A garbage collector for C and C++</h1>
+<ul>
+<li><a href="#platforms">Platforms</a>
+</li><li><a href="#multiprocessors">Scalable multiprocessor versions</a>
+</li><li><a href="#details">Some collector details</a>
+</li><li><a href="#further">Further reading</a>
+</li><li><a href="#users">Current users</a>
+</li><li><a href="#collector">Local Links for this collector</a>
+</li><li><a href="#background">Local Background Links</a>
+</li><li><a href="#contacts">Contacts and Mailing List</a>
+</li></ul>
+[ This is an updated version of the page formerly at
+<tt>http://reality.sgi.com/boehm/gc.html</tt>
+and before that at
+<a href="ftp://parcftp.xerox.com/pub/gc/gc.html">
+<tt>ftp://parcftp.xerox.com/pub/gc/gc.html</tt></a>.]
+<p>
+The <a href="http://www.hpl.hp.com/personal/Hans_Boehm">Boehm</a>-<a href="http://www.cs.cornell.edu/annual_report/00-01/bios.htm#demers">Demers</a>-<a href="http://www-sul.stanford.edu/weiser/">Weiser</a>
+conservative garbage collector can
+be used as a garbage collecting
+replacement for C <tt>malloc</tt> or C++ <tt>new</tt>.
+It allows you to allocate memory basically as you normally would,
+without explicitly deallocating memory that is no longer useful.
+The collector automatically recycles memory when it determines
+that it can no longer be otherwise accessed.
+A simple example of such a use is given
+<a href="simple_example.html">here</a>.
+</p><p>
+The collector is also used by a number of programming language
+implementations that either use C as intermediate code, want
+to facilitate easier interoperation with C libraries, or
+just prefer the simple collector interface.
+For a more detailed description of the interface, see
+<a href="gcinterface.html">here</a>.
+</p><p>
+Alternatively, the garbage collector may be used as
+a <a href="leak.html">leak detector</a>
+for C or C++ programs, though that is not its primary goal.
+</p><p>
+Typically several versions will be available.
+Usually you should first try to use
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/gc.tar.gz"><tt>gc_source/gc.tar.gz</tt></a>,
+which is normally an older, more stable version.
+</p><p>
+If that fails, try the latest explicitly numbered version
+in <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source/">
+<tt>gc_source/</tt></a>.
+Later versions may contain additional features, platform support,
+or bug fixes, but are likely to be less well tested.
+Note that versions containing the letters <tt>alpha</tt> are even less
+well tested than others, especially on non-HP platforms.
+</p><p>
+A slightly older version of the garbage collector is now also
+included as part of the
+<a href="http://gcc.gnu.org/">GNU compiler</a>
+distribution. The source
+code for that version is available for browsing
+<a href="http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/boehm-gc/">here</a>.
+</p><p>
+The arguments for and against conservative garbage collection
+in C and C++ are briefly
+discussed in
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/issues.html">issues.html</a>. The beginnings of
+a frequently-asked-questions list are <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/faq.html">here</a>.
+</p><p>
+The garbage collector code is copyrighted by
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm">Hans-J. Boehm</a>,
+Alan J. Demers,
+<a href="http://www.xerox.com/">Xerox Corporation</a>,
+<a href="http://www.sgi.com/">Silicon Graphics</a>,
+and
+<a href="http://www.hp.com/">Hewlett-Packard Company</a>.
+It may be used and copied without payment of a fee under minimal restrictions.
+See the README file in the distribution or the
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/license.txt">license</a> for more details.
+<b>IT IS PROVIDED AS IS,
+WITH ABSOLUTELY NO WARRANTY EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK</b>.
+</p><p>
+Empirically, this collector works with most unmodified C programs,
+simply by replacing
+<tt>malloc</tt> with <tt>GC_malloc</tt> calls,
+replacing <tt>realloc</tt> with <tt>GC_realloc</tt> calls, and removing
+free calls. Exceptions are discussed
+in <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/issues.html">issues.html</a>.
+</p><h2><a name="platforms">Platforms</a></h2>
+The collector is not completely portable, but the distribution
+includes ports to most standard PC and UNIX/Linux platforms.
+The collector should work on Linux, *BSD, recent Windows versions,
+MacOS X, HP/UX, Solaris,
+Tru64, Irix and a few other operating systems.
+Some ports are more polished than others.
+<p>
+Irix pthreads, Linux threads, Win32 threads, Solaris threads
+(pthreads only),
+HP/UX 11 pthreads, Tru64 pthreads, and MacOS X threads are supported
+in recent versions.
+</p><h3>Separately distributed ports</h3>
+For MacOS 9/Classic use, Patrick Beard's latest port is available from
+<a href="http://homepage.mac.com/pcbeard/gc/">
+<tt>http://homepage.mac.com/pcbeard/gc/</tt></a>.
+(Unfortunately, that's now quite dated.
+I'm not in a position to test under MacOS. Although I try to
+incorporate changes, it is impossible for
+me to update the project file.)
+<p>
+Precompiled versions of the collector for NetBSD are available
+<a href="ftp://ftp.netbsd.org/pub/NetBSD/packages/pkgsrc/devel/boehm-gc/README.html">here</a>
+or
+<a href="http://www.netbsd.org/packages/devel/boehm-gc/README.html">here</a>.
+</p><p>
+<a href="http://www.debian.org/">Debian Linux</a> includes prepackaged
+versions of the collector.
+</p><h2><a name="multiprocessors">Scalable multiprocessor versions</a></h2>
+Kenjiro Taura, Toshio Endo, and Akinori Yonezawa have made available
+a <a href="http://www.yl.is.s.u-tokyo.ac.jp/gc/">parallel collector</a>
+based on this one. Their collector takes advantage of multiple processors
+during a collection. Starting with collector version 6.0alpha1
+we also do this, though with more modest processor scalability goals.
+Our approach is discussed briefly in
+<a href="scale.html"><tt>scale.html</tt></a>.
+<h2><a name="details">Some Collector Details</a></h2>
+The collector uses a <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/complexity.html">mark-sweep</a> algorithm.
+It provides incremental and generational
+collection under operating systems which provide the right kind of
+virtual memory support. (Currently this includes SunOS[45], IRIX,
+OSF/1, Linux, and Windows, with varying restrictions.)
+It allows <a href="finalization.html"><i>finalization</i></a> code
+to be invoked when an object is collected.
+It can take advantage of type information to locate pointers if such
+information is provided, but it is usually used without such information.
+ee the README and
+<tt>gc.h</tt> files in the distribution for more details.
+<p>
+For an overview of the implementation, see <a href="gcdescr.html">here</a>.
+</p><p>
+The garbage collector distribution includes a C string
+(<a type="text/plain" href="../include/cord.h"><i>cord</i></a>) package that provides
+for fast concatenation and substring operations on long strings.
+A simple curses- and win32-based editor that represents the entire file
+as a cord is included as a
+sample application.
+</p><p>
+Performance of the nonincremental collector is typically competitive
+with malloc/free implementations. Both space and time overhead are
+likely to be only slightly higher
+for programs written for malloc/free
+(see Detlefs, Dosser and Zorn's
+<a href="ftp://ftp.cs.colorado.edu/pub/techreports/zorn/CU-CS-665-93.ps.Z">Memory Allocation Costs in Large C and C++ Programs</a>.)
+For programs allocating primarily very small objects, the collector
+may be faster; for programs allocating primarily large objects it will
+be slower. If the collector is used in a multithreaded environment
+and configured for thread-local allocation, it may in some cases
+significantly outperform malloc/free allocation in time.
+</p><p>
+We also expect that in many cases any additional overhead
+will be more than compensated for by decreased copying etc.
+if programs are written
+and tuned for garbage collection.
+</p><h1><a name="further">Further Reading:</a></h1>
+<b>The beginnings of a frequently asked questions list for this
+collector are <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/faq.html">here</a></b>.
+<p>
+<b>The following provide information on garbage collection in general</b>:
+</p><p>
+Paul Wilson's <a href="ftp://ftp.cs.utexas.edu/pub/garbage">garbage collection ftp archive</a> and <a href="ftp://ftp.cs.utexas.edu/pub/garbage/gcsurvey.ps">GC survey</a>.
+</p><p>
+The Ravenbrook <a href="http://www.memorymanagement.org/">
+Memory Management Reference</a>.
+</p><p>
+David Chase's
+<a href="http://www.iecc.com/gclist/GC-faq.html">GC FAQ</a>.
+</p><p>
+Richard Jones'
+<a href="http://www.ukc.ac.uk/computer_science/Html/Jones/gc.html">
+GC page</a> and
+<a href="http://www.cs.kent.ac.uk/people/staff/rej/gcbook/gcbook.html">
+his book</a>.
+</p><p>
+<b>The following papers describe the collector algorithms we use
+and the underlying design decisions at
+a higher level.</b>
+</p><p>
+(Some of the lower level details can be found
+<a href="gcdescr.html">here</a>.)
+</p><p>
+The first one is not available
+electronically due to copyright considerations. Most of the others are
+subject to ACM copyright.
+</p><p>
+Boehm, H., "Dynamic Memory Allocation and Garbage Collection", <i>Computers in Physics
+9</i>, 3, May/June 1995, pp. 297-303. This is directed at an otherwise sophisticated
+audience unfamiliar with memory allocation issues. The algorithmic details differ
+from those in the implementation. There is a related letter to the editor and a minor
+correction in the next issue.
+</p><p>
+Boehm, H., and <a href="http://www.ubiq.com/hypertext/weiser/weiser.html">M. Weiser</a>,
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/spe_gc_paper">"Garbage Collection in an Uncooperative Environment"</a>,
+<i>Software Practice &amp; Experience</i>, September 1988, pp. 807-820.
+</p><p>
+Boehm, H., A. Demers, and S. Shenker, <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi91.ps.Z">"Mostly Parallel Garbage Collection"</a>, Proceedings
+of the ACM SIGPLAN '91 Conference on Programming Language Design and Implementation,
+<i>SIGPLAN Notices 26</i>, 6 (June 1991), pp. 157-164.
+</p><p>
+Boehm, H., <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi93.ps.Z">"Space Efficient Conservative Garbage Collection"</a>, Proceedings of the ACM
+SIGPLAN '93 Conference on Programming Language Design and Implementation, <i>SIGPLAN
+Notices 28</i>, 6 (June 1993), pp. 197-206.
+</p><p>
+Boehm, H., "Reducing Garbage Collector Cache Misses",
+<i> Proceedings of the 2000 International Symposium on Memory Management </i>.
+<a href="http://portal.acm.org/citation.cfm?doid=362422.362438">
+Official version.</a>
+<a href="http://www.hpl.hp.com/techreports/2000/HPL-2000-99.html">
+Technical report version.</a> Describes the prefetch strategy
+incorporated into the collector for some platforms. Explains why
+the sweep phase of a "mark-sweep" collector should not really be
+a distinct phase.
+</p><p>
+M. Serrano, H. Boehm,
+"Understanding Memory Allocation of Scheme Programs",
+<i>Proceedings of the Fifth ACM SIGPLAN International Conference on
+Functional Programming</i>, 2000, Montreal, Canada, pp. 245-256.
+<a href="http://www.acm.org/pubs/citations/proceedings/fp/351240/p245-serrano/">
+Official version.</a>
+<a href="http://www.hpl.hp.com/techreports/2000/HPL-2000-62.html">
+Earlier Technical Report version.</a> Includes some discussion of the
+collector debugging facilities for identifying causes of memory retention.
+</p><p>
+Boehm, H.,
+"Fast Multiprocessor Memory Allocation and Garbage Collection",
+<a href="http://www.hpl.hp.com/techreports/2000/HPL-2000-165.html">
+HP Labs Technical Report HPL 2000-165</a>. Discusses the parallel
+collection algorithms, and presents some performance results.
+</p><p>
+Boehm, H., "Bounding Space Usage of Conservative Garbage Collectors",
+<i>Proceeedings of the 2002 ACM SIGPLAN-SIGACT Symposium on Principles of
+Programming Languages</i>, Jan. 2002, pp. 93-100.
+<a href="http://portal.acm.org/citation.cfm?doid=503272.503282">
+Official version.</a>
+<a href="http://www.hpl.hp.com/techreports/2001/HPL-2001-251.html">
+Technical report version.</a>
+Includes a discussion of a collector facility to much more reliably test for
+the potential of unbounded heap growth.
+</p><p>
+<b>The following papers discuss language and compiler restrictions necessary to guaranteed
+safety of conservative garbage collection.</b>
+</p><p>
+We thank John Levine and JCLT for allowing
+us to make the second paper available electronically, and providing PostScript for the final
+version.
+</p><p>
+Boehm, H., <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi96.ps.gz">``Simple
+Garbage-Collector-Safety''</a>, Proceedings
+of the ACM SIGPLAN '96 Conference on Programming Language Design
+and Implementation.
+</p><p>
+Boehm, H., and D. Chase, <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/boecha.ps.gz">
+``A Proposal for Garbage-Collector-Safe C Compilation''</a>,
+<i>Journal of C Language Translation 4</i>, 2 (Decemeber 1992), pp. 126-141.
+</p><p>
+<b>Other related information: </b>
+</p><p>
+The Detlefs, Dosser and Zorn's <a href="ftp://ftp.cs.colorado.edu/pub/techreports/zorn/CU-CS-665-93.ps.Z">Memory Allocation Costs in Large C and C++ Programs</a>.
+ This is a performance comparison of the Boehm-Demers-Weiser collector to malloc/free,
+using programs written for malloc/free.
+</p><p>
+Joel Bartlett's <a href="ftp://ftp.digital.com/pub/DEC/CCgc">mostly copying conservative garbage collector for C++</a>.
+</p><p>
+John Ellis and David Detlef's <a href="ftp://parcftp.xerox.com/pub/ellis/gc/gc.ps">Safe Efficient Garbage Collection for C++</a> proposal.
+</p><p>
+Henry Baker's <a href="http://home.pipeline.com/%7Ehbaker1/">paper collection</a>.
+</p><p>
+Slides for Hans Boehm's <a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/myths.ps">Allocation and GC Myths</a> talk.
+</p><h1><a name="users">Current users:</a></h1>
+Known current users of some variant of this collector include:
+<p>
+The runtime system for <a href="http://gcc.gnu.org/java">GCJ</a>,
+the static GNU java compiler.
+</p><p>
+<a href="http://w3m.sourceforge.net/">W3m</a>, a text-based web browser.
+</p><p>
+Some versions of the Xerox DocuPrint printer software.
+</p><p>
+The <a href="http://www.mozilla.org/">Mozilla</a> project, as leak
+detector.
+</p><p>
+The <a href="http://www.go-mono.com/">Mono</a> project,
+an open source implementation of the .NET development framework.
+</p><p>
+The <a href="http://www.gnu.org/projects/dotgnu/">DotGNU Portable.NET
+project</a>, another open source .NET implementation.
+</p><p>
+The <a href="http://irssi.org/">Irssi IRC client</a>.
+</p><p>
+<a href="http://titanium.cs.berkeley.edu/">The Berkeley Titanium project</a>.
+</p><p>
+<a href="http://www.nag.co.uk/nagware_fortran_compilers.asp">The NAGWare f90 Fortran 90 compiler</a>.
+</p><p>
+Elwood Corporation's <a href="http://www.elwood.com/eclipse-info/index.htm">
+Eclipse</a> Common Lisp system, C library, and translator.
+</p><p>
+The <a href="http://www-sop.inria.fr/mimosa/fp/Bigloo/">Bigloo
+Scheme</a>
+and <a href="http://kaolin.unice.fr/%7Eserrano/camloo.html">Camloo ML
+compilers</a>
+written by Manuel Serrano and others.
+</p><p>
+Brent Benson's <a href="http://ftp.cs.indiana.edu/pub/scheme-repository/imp/">libscheme</a>.
+</p><p>
+The <a href="http://www.cs.rice.edu/CS/PLT/packages/mzscheme/index.html">MzScheme</a> scheme implementation.
+</p><p>
+The <a href="http://www.cs.washington.edu/research/projects/cecil/www/cecil-home.html">University of Washington Cecil Implementation</a>.
+</p><p>
+<a href="http://www.icsi.berkeley.edu/Sather/">The Berkeley Sather implementation</a>.
+</p><p>
+<a href="http://www.cs.berkeley.edu/%7Eharmonia/">The Berkeley Harmonia Project</a>.
+</p><p>
+The <a href="http://www.cs.arizona.edu/sumatra/toba/">Toba</a> Java Virtual
+Machine to C translator.
+</p><p>
+The <a href="http://www.gwydiondylan.org/">Gwydion Dylan compiler</a>.
+</p><p>
+The <a href="http://gcc.gnu.org/onlinedocs/gcc/Objective-C.html">
+GNU Objective C runtime</a>.
+</p><p>
+<a href="http://www.math.uiuc.edu/Macaulay2">Macaulay 2</a>, a system to support
+research in algebraic geometry and commutative algebra.
+</p><p>
+The <a href="http://www.vestasys.org/">Vesta</a> configuration management
+system.
+</p><p>
+<a href="http://www.visual-prolog.com/vip6">Visual Prolog 6</a>.
+</p><p>
+<a href="http://asymptote.sf.net/">Asymptote LaTeX-compatible
+vector graphics language.</a>
+
+</p><h1><a name="collector">More collector information at this site</a></h1>
+<a href="simple_example.html">A simple illustration of how to build and
+use the collector.</a>.
+<p>
+<a href="gcinterface.html">Description of alternate interfaces to the
+garbage collector.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/04tutorial.pdf">Slides from an ISMM 2004 tutorial about the GC.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/faq.html">A FAQ (frequently asked questions) list.</a>
+</p><p>
+<a href="leak.html">How to use the garbage collector as a leak detector.</a>
+</p><p>
+<a href="debugging.html">Some hints on debugging garbage collected
+applications.</a>
+</p><p>
+<a href="gcdescr.html">An overview of the implementation of the
+garbage collector.</a>
+</p><p>
+<a href="tree.html">The data structure used for fast pointer lookups.</a>
+</p><p>
+<a href="scale.html">Scalability of the collector to multiprocessors.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source">Directory containing garbage collector source.</a>
+
+</p><h1><a name="background">More background information at this site</a></h1>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/bounds.html">An attempt to establish a bound on space usage of
+conservative garbage collectors.</a>
+<p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/complexity.html">Mark-sweep versus copying garbage collectors
+and their complexity.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/conservative.html">Pros and cons of conservative garbage collectors,
+in comparison to other collectors.
+</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/issues.html">Issues related to garbage collection vs.
+manual memory management in C/C++.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/example.html">An example of a case in which garbage collection
+results in a much faster implementation as a result of reduced
+synchronization.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/nonmoving">Slide set discussing performance of nonmoving
+garbage collectors.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/popl03/web">
+Slide set discussing <i>Destructors, Finalizers, and Synchronization</i>
+(POPL 2003).</a>
+</p><p>
+<a href="http://portal.acm.org/citation.cfm?doid=604131.604153">
+Paper corresponding to above slide set.</a>
+(<a href="http://www.hpl.hp.com/techreports/2002/HPL-2002-335.html">
+Technical Report version</a>.)
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_bench.html">A Java/Scheme/C/C++ garbage collection benchmark.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/myths.ps">Slides for talk on memory allocation myths.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/gctalk.ps">Slides for OOPSLA 98 garbage collection talk.</a>
+</p><p>
+<a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers">Related papers.</a>
+</p><h1><a name="contacts">Contacts and Mailing List</a><a></a></h1>
+<a>We have recently set up two mailing list for collector announcements
+and discussions:
+</a><ul>
+<li><a href="mailto:gc-announce@linux.hpl.hp.com">gc-announce@linux.hpl.hp.com</a>
+is used for announcements of new versions. Postings are restricted.
+We expect this to always remain a very low volume list.
+</li><li><a href="mailto:gc@linux.hpl.hp.com">gc@linux.hpl.hp.com</a> is used for
+discussions, bug reports, and the like. Subscribers may post.
+On-topic posts by nonsubscribers will usually also be accepted, but
+it may take some time to review them.
+</li></ul>
+To subscribe to these lists, send a mail message containing the
+word "subscribe" to
+<a href="mailto:gc-announce-request@linux.hpl.hp.com?subject=subscribe">gc-announce-request@linux.hpl.hp.com</a>
+or to
+<a href="mailto:gc-request@linux.hpl.hp.com?subject=subscribe">gc-request@linux.hpl.hp.com</a>.
+(Please ignore the instructions about web-based subscription.
+The listed web site is behind the HP firewall.)
+<p>
+The archives for these lists appear
+<a href="http://www.hpl.hp.com/hosted/linux/mail-archives">here</a>.
+The gc list archive may also be read at
+<a href="http://dir.gmane.org/gmane.comp.programming.garbage-collection.boehmgc">gmane.org</a>.
+</p><p>
+Some prior discussion of the collector has taken place on the gcc
+java mailing list, whose archives appear
+<a href="http://gcc.gnu.org/ml/java/">here</a>, and also on
+<a href="http://lists.tunes.org/mailman/listinfo/gclist">gclist@iecc.com</a>.
+</p><p>
+Comments and bug reports may also be sent to
+(<a href="mailto:Hans.Boehm@hp.com">Hans.Boehm@hp.com</a>) or
+(<a href="mailto:boehm@acm.org">boehm@acm.org</a>), but the gc
+mailing list is usually preferred.
+
+</p></body></html>
diff --git a/boehm-gc/doc/porting.html b/boehm-gc/doc/porting.html
new file mode 100644
index 00000000000..5a06c228e5f
--- /dev/null
+++ b/boehm-gc/doc/porting.html
@@ -0,0 +1,333 @@
+<HTML>
+<HEAD>
+ <TITLE>Conservative GC Porting Directions</TITLE>
+</HEAD>
+<BODY>
+<H1>Conservative GC Porting Directions</h1>
+The collector is designed to be relatively easy to port, but is not
+portable code per se. The collector inherently has to perform operations,
+such as scanning the stack(s), that are not possible in portable C code.
+<P>
+All of the following assumes that the collector is being ported to a
+byte-addressable 32- or 64-bit machine. Currently all successful ports
+to 64-bit machines involve LP64 targets. The code base includes some
+provisions for P64 targets (notably win64), but that has not been tested.
+You are hereby discouraged from attempting a port to non-byte-addressable,
+or 8-bit, or 16-bit machines.
+<P>
+The difficulty of porting the collector varies greatly depending on the needed
+functionality. In the simplest case, only some small additions are needed
+for the <TT>include/private/gcconfig.h</tt> file. This is described in the
+following section. Later sections discuss some of the optional features,
+which typically involve more porting effort.
+<P>
+Note that the collector makes heavy use of <TT>ifdef</tt>s. Unlike
+some other software projects, we have concluded repeatedly that this is preferable
+to system dependent files, with code duplicated between the files.
+However, to keep this manageable, we do strongly believe in indenting
+<TT>ifdef</tt>s correctly (for historical reasons usually without the leading
+sharp sign). (Separate source files are of course fine if they don't result in
+code duplication.)
+<H2>Adding Platforms to <TT>gcconfig.h</tt></h2>
+If neither thread support, nor tracing of dynamic library data is required,
+these are often the only changes you will need to make.
+<P>
+The <TT>gcconfig.h</tt> file consists of three sections:
+<OL>
+<LI> A section that defines GC-internal macros
+that identify the architecture (e.g. <TT>IA64</tt> or <TT>I386</tt>)
+and operating system (e.g. <TT>LINUX</tt> or <TT>MSWIN32</tt>).
+This is usually done by testing predefined macros. By defining
+our own macros instead of using the predefined ones directly, we can
+impose a bit more consistency, and somewhat isolate ourselves from
+compiler differences.
+<P>
+It is relatively straightforward to add a new entry here. But please try
+to be consistent with the existing code. In particular, 64-bit variants
+of 32-bit architectures general are <I>not</i> treated as a new architecture.
+Instead we explicitly test for 64-bit-ness in the few places in which it
+matters. (The notable exception here is <TT>I386</tt> and <TT>X86_64</tt>.
+This is partially historical, and partially justified by the fact that there
+are arguably more substantial architecture and ABI differences here than
+for RISC variants.)
+<P>
+on GNU-based systems, <TT>cpp -dM empty_source_file.c</tt> seems to generate
+a set of predefined macros. On some other systems, the "verbose"
+compiler option may do so, or the manual page may list them.
+<LI>
+A section that defines a small number of platform-specific macros, which are
+then used directly by the collector. For simple ports, this is where most of
+the effort is required. We describe the macros below.
+<P>
+This section contains a subsection for each architecture (enclosed in a
+suitable <TT>ifdef</tt>. Each subsection usually contains some
+architecture-dependent defines, followed by several sets of OS-dependent
+defines, again enclosed in <TT>ifdef</tt>s.
+<LI>
+A section that fills in defaults for some macros left undefined in the preceding
+section, and defines some other macros that rarely need adjustment for
+new platforms. You will typically not have to touch these.
+If you are porting to an OS that
+was previously completely unsupported, it is likely that you will
+need to add another clause to the definition of <TT>GET_MEM</tt>.
+</ol>
+The following macros must be defined correctly for each architecture and operating
+system:
+<DL>
+<DT><TT>MACH_TYPE</tt>
+<DD>
+Defined to a string that represents the machine architecture. Usually
+just the macro name used to identify the architecture, but enclosed in quotes.
+<DT><TT>OS_TYPE</tt>
+<DD>
+Defined to a string that represents the operating system name. Usually
+just the macro name used to identify the operating system, but enclosed in quotes.
+<DT><TT>CPP_WORDSZ</tt>
+<DD>
+The word size in bits as a constant suitable for preprocessor tests,
+i.e. without casts or sizeof expressions. Currently always defined as
+either 64 or 32. For platforms supporting both 32- and 64-bit ABIs,
+this should be conditionally defined depending on the current ABI.
+There is a default of 32.
+<DT><TT>ALIGNMENT</tt>
+<DD>
+Defined to be the largest <TT>N</tt>, such that
+all pointer are guaranteed to be aligned on <TT>N</tt>-byte boundaries.
+defining it to be 1 will always work, but perform poorly.
+For all modern 32-bit platforms, this is 4. For all modern 64-bit
+platforms, this is 8. Whether or not X86 qualifies as a modern
+architecture here is compiler- and OS-dependent.
+<DT><TT>DATASTART</tt>
+<DD>
+The beginning of the main data segment. The collector will trace all
+memory between <TT>DATASTART</tt> and <TT>DATAEND</tt> for root pointers.
+On some platforms,this can be defined to a constant address,
+though experience has shown that to be risky. Ideally the linker will
+define a symbol (e.g. <TT>_data</tt> whose address is the beginning
+of the data segment. Sometimes the value can be computed using
+the <TT>GC_SysVGetDataStart</tt> function. Not used if either
+the next macro is defined, or if dynamic loading is supported, and the
+dynamic loading support defines a function
+<TT>GC_register_main_static_data()</tt> which returns false.
+<DT><TT>SEARCH_FOR_DATA_START</tt>
+<DD>
+If this is defined <TT>DATASTART</tt> will be defined to a dynamically
+computed value which is obtained by starting with the address of
+<TT>_end</tt> and walking backwards until non-addressable memory is found.
+This often works on Posix-like platforms. It makes it harder to debug
+client programs, since startup involves generating and catching a
+segmentation fault, which tends to confuse users.
+<DT><TT>DATAEND</tt>
+<DD>
+Set to the end of the main data segment. Defaults to <TT>end</tt>,
+where that is declared as an array. This works in some cases, since
+the linker introduces a suitable symbol.
+<DT><TT>DATASTART2, DATAEND2</tt>
+<DD>
+Some platforms have two discontiguous main data segments, e.g.
+for initialized and uninitialized data. If so, these two macros
+should be defined to the limits of the second main data segment.
+<DT><TT>STACK_GROWS_UP</tt>
+<DD>
+Should be defined if the stack (or thread stacks) grow towards higher
+addresses. (This appears to be true only on PA-RISC. If your architecture
+has more than one stack per thread, and is not already supported, you will
+need to do more work. Grep for "IA64" in the source for an example.)
+<DT><TT>STACKBOTTOM</tt>
+<DD>
+Defined to be the cool end of the stack, which is usually the
+highest address in the stack. It must bound the region of the
+stack that contains pointers into the GC heap. With thread support,
+this must be the cold end of the main stack, which typically
+cannot be found in the same way as the other thread stacks.
+If this is not defined and none of the following three macros
+is defined, client code must explicitly set
+<TT>GC_stackbottom</tt> to an appropriate value before calling
+<TT>GC_INIT()</tt> or any other <TT>GC_</tt> routine.
+<DT><TT>LINUX_STACKBOTTOM</tt>
+<DD>
+May be defined instead of <TT>STACKBOTTOM</tt>.
+If defined, then the cold end of the stack will be determined
+Currently we usually read it from /proc.
+<DT><TT>HEURISTIC1</tt>
+<DD>
+May be defined instead of <TT>STACKBOTTOM</tt>.
+<TT>STACK_GRAN</tt> should generally also be undefined and defined.
+The cold end of the stack is determined by taking an address inside
+<TT>GC_init's frame</tt>, and rounding it up to
+the next multiple of <TT>STACK_GRAN</tt>. This works well if the stack base is
+always aligned to a large power of two.
+(<TT>STACK_GRAN</tt> is predefined to 0x1000000, which is
+rarely optimal.)
+<DT><TT>HEURISTIC2</tt>
+<DD>
+May be defined instead of <TT>STACKBOTTOM</tt>.
+The cold end of the stack is determined by taking an address inside
+GC_init's frame, incrementing it repeatedly
+in small steps (decrement if <TT>STACK_GROWS_UP</tt>), and reading the value
+at each location. We remember the value when the first
+Segmentation violation or Bus error is signalled, round that
+to the nearest plausible page boundary, and use that as the
+stack base.
+<DT><TT>DYNAMIC_LOADING</tt>
+<DD>
+Should be defined if <TT>dyn_load.c</tt> has been updated for this
+platform and tracing of dynamic library roots is supported.
+<DT><TT>MPROTECT_VDB, PROC_VDB</tt>
+<DD>
+May be defined if the corresponding "virtual dirty bit"
+implementation in os_dep.c is usable on this platform. This
+allows incremental/generational garbage collection.
+<TT>MPROTECT_VDB</tt> identifies modified pages by
+write protecting the heap and catching faults.
+<TT>PROC_VDB</tt> uses the /proc primitives to read dirty bits.
+<DT><TT>PREFETCH, PREFETCH_FOR_WRITE</tt>
+<DD>
+The collector uses <TT>PREFETCH</tt>(<I>x</i>) to preload the cache
+with *<I>x</i>.
+This defaults to a no-op.
+<DT><TT>CLEAR_DOUBLE</tt>
+<DD>
+If <TT>CLEAR_DOUBLE</tt> is defined, then
+<TT>CLEAR_DOUBLE</tt>(x) is used as a fast way to
+clear the two words at GC_malloc-aligned address x. By default,
+word stores of 0 are used instead.
+<DT><TT>HEAP_START</tt>
+<DD>
+<TT>HEAP_START</tt> may be defined as the initial address hint for mmap-based
+allocation.
+<DT><TT>ALIGN_DOUBLE</tt>
+<DD>
+Should be defined if the architecture requires double-word alignment
+of <TT>GC_malloc</tt>ed memory, e.g. 8-byte alignment with a
+32-bit ABI. Most modern machines are likely to require this.
+This is no longer needed for GC7 and later.
+</dl>
+<H2>Additional requirements for a basic port</h2>
+In some cases, you may have to add additional platform-specific code
+to other files. A likely candidate is the implementation of
+<TT>GC_with_callee_saves_pushed</tt> in </tt>mach_dep.c</tt>.
+This ensure that register contents that the collector must trace
+from are copied to the stack. Typically this can be done portably,
+but on some platforms it may require assembly code, or just
+tweaking of conditional compilation tests.
+<P>
+For GC7, if your platform supports <TT>getcontext()</tt>, then definining
+the macro <TT>UNIX_LIKE</tt> for your OS in <TT>gcconfig.h</tt>
+(if it isn't defined there already) is likely to solve the problem.
+otherwise, if you are using gcc, <TT>_builtin_unwind_init()</tt>
+will be used, and should work fine. If that is not applicable either,
+the implementation will try to use <TT>setjmp()</tt>. This will work if your
+<TT>setjmp</tt> implementation saves all possibly pointer-valued registers
+into the buffer, as opposed to trying to unwind the stack at
+<TT>longjmp</tt> time. The <TT>setjmp_test</tt> test tries to determine this,
+but often doesn't get it right.
+<P>
+In GC6.x versions of the collector, tracing of registers
+was more commonly handled
+with assembly code. In GC7, this is generally to be avoided.
+<P>
+Most commonly <TT>os_dep.c</tt> will not require attention, but see below.
+<H2>Thread support</h2>
+Supporting threads requires that the collector be able to find and suspend
+all threads potentially accessing the garbage-collected heap, and locate
+any state associated with each thread that must be traced.
+<P>
+The functionality needed for thread support is generally implemented
+in one or more files specific to the particular thread interface.
+For example, somewhat portable pthread support is implemented
+in <TT>pthread_support.c</tt> and <TT>pthread_stop_world.c</tt>.
+The essential functionality consists of
+<DL>
+<DT><TT>GC_stop_world()</tt>
+<DD>
+Stops all threads which may access the garbage collected heap, other
+than the caller.
+<DT><TT>GC_start_world()</tt>
+<DD>
+Restart other threads.
+<DT><TT>GC_push_all_stacks()</tt>
+<DD>
+Push the contents of all thread stacks (or at least of pointer-containing
+regions in the thread stacks) onto the mark stack.
+</dl>
+These very often require that the garbage collector maintain its
+own data structures to track active threads.
+<P>
+In addition, <TT>LOCK</tt> and <TT>UNLOCK</tt> must be implemented
+in <TT>gc_locks.h</tt>
+<P>
+The easiest case is probably a new pthreads platform
+on which threads can be stopped
+with signals. In this case, the changes involve:
+<OL>
+<LI>Introducing a suitable <TT>GC_</tt><I>X</i><TT>_THREADS</tt> macro, which should
+be automatically defined by <TT>gc_config_macros.h</tt> in the right cases.
+It should also result in a definition of <TT>GC_PTHREADS</tt>, as for the
+existing cases.
+<LI>For GC7+, ensuring that the <TT>atomic_ops</tt> package at least
+minimally supports the platform.
+If incremental GC is needed, or if pthread locks don't
+perform adequately as the allocation lock, you will probably need to
+ensure that a sufficient <TT>atomic_ops</tt> port
+exists for the platform to provided an atomic test and set
+operation. (Current GC7 versions require more<TT>atomic_ops</tt>
+asupport than necessary. This is a bug.) For earlier versions define
+<TT>GC_test_and_set</tt> in <TT>gc_locks.h</tt>.
+<LI>Making any needed adjustments to <TT>pthread_stop_world.c</tt> and
+<TT>pthread_support.c</tt>. Ideally none should be needed. In fact,
+not all of this is as well standardized as one would like, and outright
+bugs requiring workarounds are common.
+</ol>
+Non-preemptive threads packages will probably require further work. Similarly
+thread-local allocation and parallel marking requires further work
+in <TT>pthread_support.c</tt>, and may require better <TT>atomic_ops</tt>
+support.
+<H2>Dynamic library support</h2>
+So long as <TT>DATASTART</tt> and <TT>DATAEND</tt> are defined correctly,
+the collector will trace memory reachable from file scope or <TT>static</tt>
+variables defined as part of the main executable. This is sufficient
+if either the program is statically linked, or if pointers to the
+garbage-collected heap are never stored in non-stack variables
+defined in dynamic libraries.
+<P>
+If dynamic library data sections must also be traced, then
+<UL>
+<LI><TT>DYNAMIC_LOADING</tt> must be defined in the appropriate section
+of <TT>gcconfig.h</tt>.
+<LI>An appropriate versions of the functions
+<TT>GC_register_dynamic_libraries()</tt> should be defined in
+<TT>dyn_load.c</tt>. This function should invoke
+<TT>GC_cond_add_roots(</tt><I>region_start, region_end</i><TT>, TRUE)</tt>
+on each dynamic library data section.
+</ul>
+<P>
+Implementations that scan for writable data segments are error prone, particularly
+in the presence of threads. They frequently result in race conditions
+when threads exit and stacks disappear. They may also accidentally trace
+large regions of graphics memory, or mapped files. On at least
+one occasion they have been known to try to trace device memory that
+could not safely be read in the manner the GC wanted to read it.
+<P>
+It is usually safer to walk the dynamic linker data structure, especially
+if the linker exports an interface to do so. But beware of poorly documented
+locking behavior in this case.
+<H2>Incremental GC support</h2>
+For incremental and generational collection to work, <TT>os_dep.c</tt>
+must contain a suitable "virtual dirty bit" implementation, which
+allows the collector to track which heap pages (assumed to be
+a multiple of the collectors block size) have been written during
+a certain time interval. The collector provides several
+implementations, which might be adapted. The default
+(<TT>DEFAULT_VDB</tt>) is a placeholder which treats all pages
+as having been written. This ensures correctness, but renders
+incremental and generational collection essentially useless.
+<H2>Stack traces for debug support</h2>
+If stack traces in objects are need for debug support,
+<TT>GC_dave_callers</tt> and <TT>GC_print_callers</tt> must be
+implemented.
+<H2>Disclaimer</h2>
+This is an initial pass at porting guidelines. Some things
+have no doubt been overlooked.
+</body>
+</html>
diff --git a/boehm-gc/doc/scale.html b/boehm-gc/doc/scale.html
new file mode 100644
index 00000000000..feb14f1319e
--- /dev/null
+++ b/boehm-gc/doc/scale.html
@@ -0,0 +1,210 @@
+<HTML>
+<HEAD>
+<TITLE>Garbage collector scalability</TITLE>
+</HEAD>
+<BODY>
+<H1>Garbage collector scalability</h1>
+In its default configuration, the Boehm-Demers-Weiser garbage collector
+is not thread-safe. It can be made thread-safe for a number of environments
+by building the collector with the appropriate
+<TT>-D</tt><I>XXX</i><TT>-THREADS</tt> compilation
+flag. This has primarily two effects:
+<OL>
+<LI> It causes the garbage collector to stop all other threads when
+it needs to see a consistent memory state.
+<LI> It causes the collector to acquire a lock around essentially all
+allocation and garbage collection activity.
+</ol>
+Since a single lock is used for all allocation-related activity, only one
+thread can be allocating or collecting at one point. This inherently
+limits performance of multi-threaded applications on multiprocessors.
+<P>
+On most platforms, the allocator/collector lock is implemented as a
+spin lock with exponential back-off. Longer wait times are implemented
+by yielding and/or sleeping. If a collection is in progress, the pure
+spinning stage is skipped. This has the advantage that uncontested and
+thus most uniprocessor lock acquisitions are very cheap. It has the
+disadvantage that the application may sleep for small periods of time
+even when there is work to be done. And threads may be unnecessarily
+woken up for short periods. Nonetheless, this scheme empirically
+outperforms native queue-based mutual exclusion implementations in most
+cases, sometimes drastically so.
+<H2>Options for enhanced scalability</h2>
+Version 6.0 of the collector adds two facilities to enhance collector
+scalability on multiprocessors. As of 6.0alpha1, these are supported
+only under Linux on X86 and IA64 processors, though ports to other
+otherwise supported Pthreads platforms should be straightforward.
+They are intended to be used together.
+<UL>
+<LI>
+Building the collector with <TT>-DPARALLEL_MARK</tt> allows the collector to
+run the mark phase in parallel in multiple threads, and thus on multiple
+processors. The mark phase typically consumes the large majority of the
+collection time. Thus this largely parallelizes the garbage collector
+itself, though not the allocation process. Currently the marking is
+performed by the thread that triggered the collection, together with
+<I>N</i>-1 dedicated
+threads, where <I>N</i> is the number of processors detected by the collector.
+The dedicated threads are created once at initialization time.
+<P>
+A second effect of this flag is to switch to a more concurrent
+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. 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
+threads. The only difference is that, if the thread allocates enough
+memory of a certain kind, it will build a thread-local free list for
+objects of that kind, and allocate from that. This greatly reduces
+locking. The thread-local free lists are refilled using
+<TT>GC_malloc_many</tt>.
+<P>
+An important side effect of this flag is to replace the default
+spin-then-sleep lock to be replace by a spin-then-queue based implementation.
+This <I>reduces performance</i> for the standard allocation functions,
+though it usually improves performance when thread-local allocation is
+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
+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>
+header in each client source file.
+<LI> Invoke <TT>GC_thr_init()</tt> before any allocation.
+<LI> Allocate using <TT>GC_MALLOC</tt>, <TT>GC_MALLOC_ATOMIC</tt>,
+and/or <TT>GC_GCJ_MALLOC</tt>.
+</ol>
+<H2>The Parallel Marking Algorithm</h2>
+We use an algorithm similar to
+<A HREF="http://www.yl.is.s.u-tokyo.ac.jp/gc/">that developed by
+Endo, Taura, and Yonezawa</a> at the University of Tokyo.
+However, the data structures and implementation are different,
+and represent a smaller change to the original collector source,
+probably at the expense of extreme scalability. Some of
+the refinements they suggest, <I>e.g.</i> splitting large
+objects, were also incorporated into out approach.
+<P>
+The global mark stack is transformed into a global work queue.
+Unlike the usual case, it never shrinks during a mark phase.
+The mark threads remove objects from the queue by copying them to a
+local mark stack and changing the global descriptor to zero, indicating
+that there is no more work to be done for this entry.
+This removal
+is done with no synchronization. Thus it is possible for more than
+one worker to remove the same entry, resulting in some work duplication.
+<P>
+The global work queue grows only if a marker thread decides to
+return some of its local mark stack to the global one. This
+is done if the global queue appears to be running low, or if
+the local stack is in danger of overflowing. It does require
+synchronization, but should be relatively rare.
+<P>
+The sequential marking code is reused to process local mark stacks.
+Hence the amount of additional code required for parallel marking
+is minimal.
+<P>
+It should be possible to use generational collection in the presence of the
+parallel collector, by calling <TT>GC_enable_incremental()</tt>.
+This does not result in fully incremental collection, since parallel mark
+phases cannot currently be interrupted, and doing so may be too
+expensive.
+<P>
+Gcj-style mark descriptors do not currently mix with the combination
+of local allocation and incremental collection. They should work correctly
+with one or the other, but not both.
+<P>
+The number of marker threads is set on startup to the number of
+available processors (or to the value of the <TT>GC_NPROCS</tt>
+environment variable). If only a single processor is detected,
+parallel marking is disabled.
+<P>
+Note that setting GC_NPROCS to 1 also causes some lock acquisitions inside
+the collector to immediately yield the processor instead of busy waiting
+first. In the case of a multiprocessor and a client with multiple
+simultaneously runnable threads, this may have disastrous performance
+consequences (e.g. a factor of 10 slowdown).
+<H2>Performance</h2>
+We conducted some simple experiments with a version of
+<A HREF="gc_bench.html">our GC benchmark</a> that was slightly modified to
+run multiple concurrent client threads in the same address space.
+Each client thread does the same work as the original benchmark, but they share
+a heap.
+This benchmark involves very little work outside of memory allocation.
+This was run with GC 6.0alpha3 on a dual processor Pentium III/500 machine
+under Linux 2.2.12.
+<P>
+Running with a thread-unsafe collector, the benchmark ran in 9
+seconds. With the simple thread-safe collector,
+built with <TT>-DLINUX_THREADS</tt>, the execution time
+increased to 10.3 seconds, or 23.5 elapsed seconds with two clients.
+(The times for the <TT>malloc</tt>/i<TT>free</tt> version
+with glibc <TT>malloc</tt>
+are 10.51 (standard library, pthreads not linked),
+20.90 (one thread, pthreads linked),
+and 24.55 seconds respectively. The benchmark favors a
+garbage collector, since most objects are small.)
+<P>
+The following table gives execution times for the collector built
+with parallel marking and thread-local allocation support
+(<TT>-DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC</tt>). We tested
+the client using either one or two marker threads, and running
+one or two client threads. Note that the client uses thread local
+allocation exclusively. With -DTHREAD_LOCAL_ALLOC the collector
+switches to a locking strategy that is better tuned to less frequent
+lock acquisition. The standard allocation primitives thus perform
+slightly worse than without -DTHREAD_LOCAL_ALLOC, and should be
+avoided in time-critical code.
+<P>
+(The results using <TT>pthread_mutex_lock</tt>
+directly for allocation locking would have been worse still, at
+least for older versions of linuxthreads.
+With THREAD_LOCAL_ALLOC, we first repeatedly try to acquire the
+lock with pthread_mutex_try_lock(), busy_waiting between attempts.
+After a fixed number of attempts, we use pthread_mutex_lock().)
+<P>
+These measurements do not use incremental collection, nor was prefetching
+enabled in the marker. We used the C version of the benchmark.
+All measurements are in elapsed seconds on an unloaded machine.
+<P>
+<TABLE BORDER ALIGN="CENTER">
+<TR><TH>Number of threads</th><TH>1 marker thread (secs.)</th>
+<TH>2 marker threads (secs.)</th></tr>
+<TR><TD>1 client</td><TD ALIGN="CENTER">10.45</td><TD ALIGN="CENTER">7.85</td>
+<TR><TD>2 clients</td><TD ALIGN="CENTER">19.95</td><TD ALIGN="CENTER">12.3</td>
+</table>
+<PP>
+The execution time for the single threaded case is slightly worse than with
+simple locking. However, even the single-threaded benchmark runs faster than
+even the thread-unsafe version if a second processor is available.
+The execution time for two clients with thread local allocation time is
+only 1.4 times the sequential execution time for a single thread in a
+thread-unsafe environment, even though it involves twice the client work.
+That represents close to a
+factor of 2 improvement over the 2 client case with the old collector.
+The old collector clearly
+still suffered from some contention overhead, in spite of the fact that the
+locking scheme had been fairly well tuned.
+<P>
+Full linear speedup (i.e. the same execution time for 1 client on one
+processor as 2 clients on 2 processors)
+is probably not achievable on this kind of
+hardware even with such a small number of processors,
+since the memory system is
+a major constraint for the garbage collector,
+the processors usually share a single memory bus, and thus
+the aggregate memory bandwidth does not increase in
+proportion to the number of processors.
+<P>
+These results are likely to be very sensitive to both hardware and OS
+issues. Preliminary experiments with an older Pentium Pro machine running
+an older kernel were far less encouraging.
+
+</body>
+</html>
diff --git a/boehm-gc/doc/simple_example.html b/boehm-gc/doc/simple_example.html
new file mode 100644
index 00000000000..95e49a6b326
--- /dev/null
+++ b/boehm-gc/doc/simple_example.html
@@ -0,0 +1,229 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html lang="en-us">
+<HEAD>
+<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII" >
+<TITLE>Using the Garbage Collector: A simple example</title>
+</head>
+<BODY>
+<H1>Using the Garbage Collector: A simple example</h1>
+The following consists of step-by-step instructions for building and
+using the collector. We'll assume a Linux/gcc platform and
+a single-threaded application. <FONT COLOR=green>The green
+text contains information about other platforms or scenarios.
+It can be skipped, especially on first reading</font>.
+<H2>Building the collector</h2>
+If you haven't already so, unpack the collector and enter
+the newly created directory with
+<PRE>
+tar xvfz gc&lt;version&gt;.tar.gz
+cd gc&lt;version&gt;
+</pre>
+<P>
+You can configure, build, and install the collector in a private
+directory, say /home/xyz/gc, with the following commands:
+<PRE>
+./configure --prefix=/home/xyz/gc --disable-threads
+make
+make check
+make install
+</pre>
+Here the "<TT>make check</tt>" command is optional, but highly recommended.
+It runs a basic correctness test which usually takes well under a minute.
+<H3><FONT COLOR=green>Other platforms</font></h3>
+<FONT COLOR=green>
+On non-Unix, non-Linux platforms, the collector is usually built by copying
+the appropriate makefile (see the platform-specific README in doc/README.xxx
+in the distribution) to the file "Makefile", and then typing "make"
+(or "nmake" or ...). This builds the library in the source tree. You may
+want to move it and the files in the include directory to a more convenient
+place.
+</font>
+<P>
+<FONT COLOR=green>
+If you use a makefile that does not require running a configure script,
+you should first look at the makefile, and adjust any options that are
+documented there.
+</font>
+<P>
+<FONT COLOR=green>
+If your platform provides a "make" utility, that is generally preferred
+to platform- and compiler- dependent "project" files. (At least that is the
+strong preference of the would-be maintainer of those project files.)
+</font>
+<H3><FONT COLOR=green>Threads</font></h3>
+<FONT COLOR=green>
+If you need thread support, configure the collector with
+</font>
+<PRE style="color:green">
+--enable-threads=posix --enable-thread-local-alloc --enable-parallel-mark
+</pre>
+<FONT COLOR=green>
+instead of
+<TT>--disable-threads</tt>
+If your target is a real old-fashioned uniprocessor (no "hyperthreading",
+etc.) you will want to omit <TT>--enable-parallel-mark</tt>.
+</font>
+<H3><FONT COLOR=green>C++</font></h3>
+<FONT COLOR=green>
+You will need to include the C++ support, which unfortunately tends to
+be among the least portable parts of the collector, since it seems
+to rely on some corner cases of the language. On Linux, it
+suffices to add <TT>--enable-cplusplus</tt> to the configure options.
+</font>
+<H2>Writing the program</h2>
+You will need a
+<PRE>
+#include "gc.h"
+</pre>
+at the beginning of every file that allocates memory through the
+garbage collector. Call <TT>GC_MALLOC</tt> wherever you would
+have call <TT>malloc</tt>. This initializes memory to zero like
+<TT>calloc</tt>; there is no need to explicitly clear the
+result.
+<P>
+If you know that an object will not contain pointers to the
+garbage-collected heap, and you don't need it to be initialized,
+call <TT>GC_MALLOC_ATOMIC</tt> instead.
+<P>
+A function <TT>GC_FREE</tt> is provided but need not be called.
+For very small objects, your program will probably perform better if
+you do not call it, and let the collector do its job.
+<P>
+A <TT>GC_REALLOC</tt> function behaves like the C library <TT>realloc</tt>.
+It allocates uninitialized pointer-free memory if the original
+object was allocated that way.
+<P>
+The following program <TT>loop.c</tt> is a trivial example:
+<PRE>
+#include "gc.h"
+#include &lt;assert.h&gt;
+#include &lt;stdio.h&gt;
+
+int main()
+{
+ int i;
+
+ GC_INIT();
+ for (i = 0; i &lt; 10000000; ++i)
+ {
+ int **p = (int **) GC_MALLOC(sizeof(int *));
+ int *q = (int *) GC_MALLOC_ATOMIC(sizeof(int));
+ assert(*p == 0);
+ *p = (int *) GC_REALLOC(q, 2 * sizeof(int));
+ if (i % 100000 == 0)
+ printf("Heap size = %d\n", GC_get_heap_size());
+ }
+ return 0;
+}
+</pre>
+<H3><FONT COLOR=green>Interaction with the system malloc</font></h3>
+<FONT COLOR=green>
+It is usually best not to mix garbage-collected allocation with the system
+<TT>malloc-free</tt>. If you do, you need to be careful not to store
+pointers to the garbage-collected heap in memory allocated with the system
+<TT>malloc</tt>.
+</font>
+
+<H3><FONT COLOR=green>Other Platforms</font></h3>
+<FONT COLOR=green>
+On some other platforms it is necessary to call <TT>GC_INIT()</tt> from the main program,
+which is presumed to be part of the main executable, not a dynamic library.
+This can never hurt, and is thus generally good practice.
+</font>
+
+<H3><FONT COLOR=green>Threads</font></h3>
+<FONT COLOR=green>
+For a multithreaded program some more rules apply:
+</font>
+<UL>
+<LI>
+<FONT COLOR=green>
+Files that either allocate through the GC <I>or make thread-related calls</i>
+should first define the macro <TT>GC_THREADS</tt>, and then
+include <TT>"gc.h"</tt>. On some platforms this will redefine some
+threads primitives, e.g. to let the collector keep track of thread creation.
+</font>
+<LI>
+<FONT COLOR=green>
+To take advantage of fast thread-local allocation in versions before 7.0,
+use the following instead
+of including <TT>gc.h</tt>:
+</font>
+<PRE style="color:green">
+#define GC_REDIRECT_TO_LOCAL
+#include "gc_local_alloc.h"
+</pre>
+<FONT COLOR=green>
+This will cause GC_MALLOC and GC_MALLOC_ATOMIC to keep per-thread allocation
+caches, and greatly reduce the number of lock acquisitions during allocation.
+For versions after 7.0, this happens implicitly if the collector is built
+with thread-local allocation enabled.
+</font>
+</ul>
+
+<H3><FONT COLOR=green>C++</font></h3>
+<FONT COLOR=green>
+In the case of C++, you need to be especially careful not to store pointers
+to the garbage-collected heap in areas that are not traced by the collector.
+The collector includes some <A HREF="gcinterface.html">alternate interfaces</a>
+to make that easier.
+</font>
+
+<H3><FONT COLOR=green>Debugging</font></h3>
+<FONT COLOR=green>
+Additional debug checks can be performed by defining <TT>GC_DEBUG</tt> before
+including <TT>gc.h</tt>. Additional options are available if the collector
+is also built with <TT>--enable-gc-debug</tt> (<TT>--enable-full-debug</tt> in
+some older versions) and all allocations are
+performed with <TT>GC_DEBUG</tt> defined.
+</font>
+
+<H3><FONT COLOR=green>What if I can't rewrite/recompile my program?</font></h3>
+<FONT COLOR=green>
+You may be able to build the collector with <TT>--enable-redirect-malloc</tt>
+and set the <TT>LD_PRELOAD</tt> environment variable to point to the resulting
+library, thus replacing the standard <TT>malloc</tt> with its garbage-collected
+counterpart. This is rather platform dependent. See the
+<A HREF="leak.html">leak detection documentation</a> for some more details.
+</font>
+
+<H2>Compiling and linking</h2>
+
+The above application <TT>loop.c</tt> test program can be compiled and linked
+with
+
+<PRE>
+cc -I/home/xyz/gc/include loop.c /home/xyz/gc/lib/libgc.a -o loop
+</pre>
+
+The <TT>-I</tt> option directs the compiler to the right include
+directory. In this case, we list the static library
+directly on the compile line; the dynamic library could have been
+used instead, provided we arranged for the dynamic loader to find
+it, e.g. by setting <TT>LD_LIBRARY_PATH</tt>.
+
+<H3><FONT COLOR=green>Threads</font></h3>
+<FONT COLOR=green>
+On pthread platforms, you will of course also have to link with
+<TT>-lpthread</tt>,
+and compile with any thread-safety options required by your compiler.
+On some platforms, you may also need to link with <TT>-ldl</tt>
+or <TT>-lrt</tt>.
+Looking at tools/threadlibs.c should give you the appropriate
+list if a plain <TT>-lpthread</tt> doesn't work.
+</font>
+
+<H2>Running the executable</h2>
+
+The executable can of course be run normally, e.g. by typing
+
+<PRE>
+./loop
+</pre>
+
+The operation of the collector is affected by a number of environment variables.
+For example, setting <TT>GC_PRINT_STATS</tt> produces some
+GC statistics on stdout.
+See <TT>README.environment</tt> in the distribution for details.
+</body>
+</html>
diff --git a/boehm-gc/doc/tree.html b/boehm-gc/doc/tree.html
index c46a281cc67..d52e2fa297f 100644
--- a/boehm-gc/doc/tree.html
+++ b/boehm-gc/doc/tree.html
@@ -49,7 +49,7 @@ The high bits are used as an index into the <TT>GC_top_index</tt> (really
<TT>bottom_index</tt> data structure. This structure in turn consists
mostly of an array <TT>index</tt> indexed by the middle bits of
the candidate pointer. The <TT>index</tt> array contains the actual
-<TT>hdr</tt> pointers.
+<TT>hdr</tt> pointers.
<P>
Thus a pointer lookup consists primarily of a handful of memory references,
and can be quite fast:
@@ -97,10 +97,10 @@ The following is an ASCII diagram of the data structure.
This was contributed by Dave Barrett several years ago.
<PRE>
- Data Structure used by GC_base in gc3.7:
- 21-Apr-94
-
-
+ Data Structure used by GC_base in gc3.7:
+ 21-Apr-94
+
+
63 LOG_TOP_SZ[11] LOG_BOTTOM_SZ[10] LOG_HBLKSIZE[13]
@@ -108,82 +108,82 @@ This was contributed by Dave Barrett several years ago.
p:| | TL_HASH(hi) | | HBLKDISPL(p) |
+------------------+----------------+------------------+------------------+
\-----------------------HBLKPTR(p)-------------------/
- \------------hi-------------------/
+ \------------hi-------------------/
\______ ________/ \________ _______/ \________ _______/
V V V
| | |
- GC_top_index[] | | |
- --- +--------------+ | | |
- ^ | | | | |
- | | | | | |
- TOP +--------------+<--+ | |
- _SZ +-<| [] | * | |
-(items)| +--------------+ if 0 < bi< HBLKSIZE | |
- | | | | then large object | |
- | | | | starts at the bi'th | |
- v | | | HBLK before p. | i |
- --- | +--------------+ | (word- |
- v | aligned) |
- bi= |GET_BI(p){->hash_link}->key==hi | |
- v | |
- | (bottom_index) \ scratch_alloc'd | |
- | ( struct bi ) / by get_index() | |
- --- +->+--------------+ | |
+ GC_top_index[] | | |
+ --- +--------------+ | | |
+ ^ | | | | |
+ | | | | | |
+ TOP +--------------+<--+ | |
+ _SZ +-<| [] | * | |
+(items)| +--------------+ if 0 < bi< HBLKSIZE | |
+ | | | | then large object | |
+ | | | | starts at the bi'th | |
+ v | | | HBLK before p. | i |
+ --- | +--------------+ | (word- |
+ v | aligned) |
+ bi= |GET_BI(p){->hash_link}->key==hi | |
+ v | |
+ | (bottom_index) \ scratch_alloc'd | |
+ | ( struct bi ) / by get_index() | |
+ --- +->+--------------+ | |
^ | | | |
^ | | | |
BOTTOM | | ha=GET_HDR_ADDR(p) | |
_SZ(items)+--------------+<----------------------+ +-------+
- | +--<| index[] | |
- | | +--------------+ GC_obj_map: v
- | | | | from / +-+-+-----+-+-+-+-+ ---
- v | | | GC_add < 0| | | | | | | | ^
- --- | +--------------+ _map_entry \ +-+-+-----+-+-+-+-+ |
+ | +--<| index[] | |
+ | | +--------------+ GC_obj_map: v
+ | | | | from / +-+-+-----+-+-+-+-+ ---
+ v | | | GC_add < 0| | | | | | | | ^
+ --- | +--------------+ _map_entry \ +-+-+-----+-+-+-+-+ |
| | asc_link | +-+-+-----+-+-+-+-+ MAXOBJSZ
- | +--------------+ +-->| | | j | | | | | +1
- | | key | | +-+-+-----+-+-+-+-+ |
- | +--------------+ | +-+-+-----+-+-+-+-+ |
- | | hash_link | | | | | | | | | | v
+ | +--------------+ +-->| | | j | | | | | +1
+ | | key | | +-+-+-----+-+-+-+-+ |
+ | +--------------+ | +-+-+-----+-+-+-+-+ |
+ | | hash_link | | | | | | | | | | v
| +--------------+ | +-+-+-----+-+-+-+-+ ---
- | | |<--MAX_OFFSET--->|
+ | | |<--MAX_OFFSET--->|
| | (bytes)
-HDR(p)| GC_find_header(p) | |<--MAP_ENTRIES-->|
- | \ from | =HBLKSIZE/WORDSZ
+HDR(p)| GC_find_header(p) | |<--MAP_ENTRIES-->|
+ | \ from | =HBLKSIZE/WORDSZ
| (hdr) (struct hblkhdr) / alloc_hdr() | (1024 on Alpha)
+-->+----------------------+ | (8/16 bits each)
-GET_HDR(p)| word hb_sz (words) | |
- +----------------------+ |
+GET_HDR(p)| word hb_sz (words) | |
+ +----------------------+ |
| struct hblk *hb_next | |
- +----------------------+ |
+ +----------------------+ |
|mark_proc hb_mark_proc| |
+----------------------+ |
| char * hb_map |>-------------+
- +----------------------+
- | ushort hb_obj_kind |
- +----------------------+
- | hb_last_reclaimed |
- --- +----------------------+
+ +----------------------+
+ | ushort hb_obj_kind |
+ +----------------------+
+ | hb_last_reclaimed |
+ --- +----------------------+
^ | |
MARK_BITS| hb_marks[] | *if hdr is free, hb_sz + DISCARD_WORDS
_SZ(words)| | is the size of a heap chunk (struct hblk)
v | | of at least MININCR*HBLKSIZE bytes (below),
--- +----------------------+ otherwise, size of each object in chunk.
-Dynamic data structures above are interleaved throughout the heap in blocks of
+Dynamic data structures above are interleaved throughout the heap in blocks of
size MININCR * HBLKSIZE bytes as done by gc_scratch_alloc which cannot be
freed; free lists are used (e.g. alloc_hdr). HBLK's below are collected.
- (struct hblk)
+ (struct hblk)
--- +----------------------+ < HBLKSIZE --- --- DISCARD_
^ |garbage[DISCARD_WORDS]| aligned ^ ^ HDR_BYTES WORDS
| | | | v (bytes) (words)
- | +-----hb_body----------+ < WORDSZ | --- ---
+ | +-----hb_body----------+ < WORDSZ | --- ---
| | | aligned | ^ ^
| | Object 0 | | hb_sz |
| | | i |(word- (words)|
| | | (bytes)|aligned) v |
| + - - - - - - - - - - -+ --- | --- |
| | | ^ | ^ |
- n * | | j (words) | hb_sz BODY_SZ
+ n * | | j (words) | hb_sz BODY_SZ
HBLKSIZE | Object 1 | v v | (words)
(bytes) | |--------------- v MAX_OFFSET
| + - - - - - - - - - - -+ --- (bytes)
diff --git a/boehm-gc/dyn_load.c b/boehm-gc/dyn_load.c
index 9bd9e060688..8e07de32181 100644
--- a/boehm-gc/dyn_load.c
+++ b/boehm-gc/dyn_load.c
@@ -10,11 +10,10 @@
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
- *
- * Original author: Bill Janssen
- * Heavily modified by Hans Boehm and others
*/
+#include "private/gc_priv.h"
+
/*
* This is incredibly OS specific code for tracking down data sections in
* dynamic libraries. There appears to be no way of doing this quickly
@@ -26,72 +25,90 @@
* None of this is safe with dlclose and incremental collection.
* But then not much of anything is safe in the presence of dlclose.
*/
-#if defined(__linux__) && !defined(_GNU_SOURCE)
- /* Can't test LINUX, since this must be define before other includes */
-# define _GNU_SOURCE
-#endif
-#if !defined(MACOS) && !defined(_WIN32_WCE)
-# include <sys/types.h>
+
+#if !defined(MACOS) && !defined(_WIN32_WCE) && !defined(__CC_ARM)
+# include <sys/types.h>
#endif
-#include "private/gc_priv.h"
/* BTL: avoid circular redefinition of dlopen if GC_SOLARIS_THREADS defined */
-# if (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)) \
- && defined(dlopen) && !defined(GC_USE_LD_WRAP)
- /* To support threads in Solaris, gc.h interposes on dlopen by */
- /* defining "dlopen" to be "GC_dlopen", which is implemented below. */
- /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */
- /* real system dlopen() in their implementation. We first remove */
- /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
-# undef dlopen
-# define GC_must_restore_redefined_dlopen
-# else
-# undef GC_must_restore_redefined_dlopen
-# endif
-
-#if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
- && !defined(PCR)
-#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
- !defined(MSWIN32) && !defined(MSWINCE) && \
+#undef GC_MUST_RESTORE_REDEFINED_DLOPEN
+#if defined(GC_PTHREADS) && !defined(GC_NO_DLOPEN) \
+ && !defined(GC_NO_THREAD_REDIRECTS) && !defined(GC_USE_LD_WRAP)
+ /* To support threads in Solaris, gc.h interposes on dlopen by */
+ /* defining "dlopen" to be "GC_dlopen", which is implemented below. */
+ /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */
+ /* real system dlopen() in their implementation. We first remove */
+ /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
+# undef dlopen
+# define GC_MUST_RESTORE_REDEFINED_DLOPEN
+#endif /* !GC_NO_DLOPEN */
+
+/* A user-supplied routine (custom filter) that might be called to */
+/* determine whether a DSO really needs to be scanned by the GC. */
+/* 0 means no filter installed. May be unused on some platforms. */
+/* FIXME: Add filter support for more platforms. */
+STATIC GC_has_static_roots_func GC_has_static_roots = 0;
+
+#if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
+ || defined(CYGWIN32)) && !defined(PCR)
+
+#if !defined(SOLARISDL) && !defined(IRIX5) && \
+ !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) && \
!(defined(ALPHA) && defined(OSF1)) && \
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
- !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
+ !defined(AIX) && !defined(SCO_ELF) && !defined(DGUX) && \
!(defined(FREEBSD) && defined(__ELF__)) && \
+ !(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) && \
!(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
- !defined(DARWIN)
+ !defined(DARWIN) && !defined(CYGWIN32)
--> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too
--> hard to add.
#endif
#include <stdio.h>
-#ifdef SUNOS5DL
+#ifdef SOLARISDL
# include <sys/elf.h>
# include <dlfcn.h>
# include <link.h>
#endif
-#ifdef SUNOS4
+
+#if defined(NETBSD)
+# include <sys/param.h>
# include <dlfcn.h>
-# include <link.h>
-# include <a.out.h>
- /* struct link_map field overrides */
-# define l_next lm_next
-# define l_addr lm_addr
-# define l_name lm_name
+# include <machine/elf_machdep.h>
+# define ELFSIZE ARCH_ELFSIZE
#endif
-#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
- (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
- (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
-# include <stddef.h>
+#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
+ || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
+ || defined(NETBSD) || defined(OPENBSD)))
+# include <stddef.h>
+# if !defined(OPENBSD) && !defined(PLATFORM_ANDROID)
+ /* FIXME: Why we exclude it for OpenBSD? */
+ /* Exclude Android because linker.h below includes its own version. */
# include <elf.h>
+# endif
+# ifdef PLATFORM_ANDROID
+ /* The header file is in "bionic/linker" folder of Android sources. */
+ /* If you don't need the "dynamic loading" feature, you may build */
+ /* the collector with -D IGNORE_DYNAMIC_LOADING. */
+# include <linker.h>
+# else
# include <link.h>
+# endif
#endif
/* Newer versions of GNU/Linux define this macro. We
* define it similarly for any ELF systems that don't. */
# ifndef ElfW
-# ifdef __NetBSD__
+# if defined(FREEBSD)
+# if __ELF_WORD_SIZE == 32
+# define ElfW(type) Elf32_##type
+# else
+# define ElfW(type) Elf64_##type
+# endif
+# elif defined(NETBSD) || defined(OPENBSD)
# if ELFSIZE == 32
# define ElfW(type) Elf32_##type
# else
@@ -106,36 +123,36 @@
# endif
# endif
-#if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
+#if defined(SOLARISDL) && !defined(USE_PROC_FOR_LIBRARIES)
#ifdef LINT
Elf32_Dyn _DYNAMIC;
#endif
-static struct link_map *
-GC_FirstDLOpenedLinkMap()
+STATIC struct link_map *
+GC_FirstDLOpenedLinkMap(void)
{
extern ElfW(Dyn) _DYNAMIC;
ElfW(Dyn) *dp;
- struct r_debug *r;
static struct link_map * cachedResult = 0;
static ElfW(Dyn) *dynStructureAddr = 0;
- /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
+ /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
# ifdef SUNOS53_SHARED_LIB
- /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */
- /* up properly in dynamically linked .so's. This means we have */
- /* to use its value in the set of original object files loaded */
- /* at program startup. */
- if( dynStructureAddr == 0 ) {
- void* startupSyms = dlopen(0, RTLD_LAZY);
- dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
- }
+ /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */
+ /* up properly in dynamically linked .so's. This means we have */
+ /* to use its value in the set of original object files loaded */
+ /* at program startup. */
+ if( dynStructureAddr == 0 ) {
+ void* startupSyms = dlopen(0, RTLD_LAZY);
+ dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
+ }
# else
- dynStructureAddr = &_DYNAMIC;
+ dynStructureAddr = &_DYNAMIC;
# endif
- if( dynStructureAddr == 0) {
+ if (dynStructureAddr == 0) {
+ /* _DYNAMIC symbol not resolved. */
return(0);
}
if( cachedResult == 0 ) {
@@ -144,7 +161,7 @@ GC_FirstDLOpenedLinkMap()
if( tag == DT_DEBUG ) {
struct link_map *lm
= ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
- if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
+ if( lm != 0 ) cachedResult = lm->l_next; /* might be NULL */
break;
}
}
@@ -152,90 +169,36 @@ GC_FirstDLOpenedLinkMap()
return cachedResult;
}
-#endif /* SUNOS5DL ... */
+#endif /* SOLARISDL ... */
/* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
-# if defined(GC_must_restore_redefined_dlopen)
+# ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
# define dlopen GC_dlopen
# endif
-#if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
-
-#ifdef LINT
- struct link_dynamic _DYNAMIC;
-#endif
-
-static struct link_map *
-GC_FirstDLOpenedLinkMap()
-{
- extern struct link_dynamic _DYNAMIC;
-
- if( &_DYNAMIC == 0) {
- return(0);
- }
- return(_DYNAMIC.ld_un.ld_1->ld_loaded);
-}
-
-/* Return the address of the ld.so allocated common symbol */
-/* with the least address, or 0 if none. */
-static ptr_t GC_first_common()
-{
- ptr_t result = 0;
- extern struct link_dynamic _DYNAMIC;
- struct rtc_symb * curr_symbol;
-
- if( &_DYNAMIC == 0) {
- return(0);
- }
- curr_symbol = _DYNAMIC.ldd -> ldd_cp;
- for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) {
- if (result == 0
- || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) {
- result = (ptr_t)(curr_symbol -> rtc_sp -> n_value);
- }
- }
- return(result);
-}
+# if defined(SOLARISDL)
-#endif /* SUNOS4 ... */
-
-# if defined(SUNOS4) || defined(SUNOS5DL)
-/* Add dynamic library data sections to the root set. */
+/* Add dynamic library data sections to the root set. */
# if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
-# ifndef SRC_M3
- --> fix mutual exclusion with dlopen
-# endif /* We assume M3 programs don't call dlopen for now */
+ --> fix mutual exclusion with dlopen
# endif
# ifndef USE_PROC_FOR_LIBRARIES
-void GC_register_dynamic_libraries()
+GC_INNER void GC_register_dynamic_libraries(void)
{
- struct link_map *lm = GC_FirstDLOpenedLinkMap();
-
+ struct link_map *lm;
- for (lm = GC_FirstDLOpenedLinkMap();
- lm != (struct link_map *) 0; lm = lm->l_next)
- {
-# ifdef SUNOS4
- struct exec *e;
-
- e = (struct exec *) lm->lm_addr;
- GC_add_roots_inner(
- ((char *) (N_DATOFF(*e) + lm->lm_addr)),
- ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)),
- TRUE);
-# endif
-# ifdef SUNOS5DL
- ElfW(Ehdr) * e;
+ for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next) {
+ ElfW(Ehdr) * e;
ElfW(Phdr) * p;
unsigned long offset;
char * start;
- register int i;
-
- e = (ElfW(Ehdr) *) lm->l_addr;
+ int i;
+
+ e = (ElfW(Ehdr) *) lm->l_addr;
p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
offset = ((unsigned long)(lm->l_addr));
- for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
+ for( i = 0; i < (int)e->e_phnum; i++, p++ ) {
switch( p->p_type ) {
case PT_LOAD:
{
@@ -251,31 +214,16 @@ void GC_register_dynamic_libraries()
default:
break;
}
- }
-# endif
+ }
}
-# ifdef SUNOS4
- {
- static ptr_t common_start = 0;
- ptr_t common_end;
- extern ptr_t GC_find_limit();
-
- if (common_start == 0) common_start = GC_first_common();
- if (common_start != 0) {
- common_end = GC_find_limit(common_start, TRUE);
- GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE);
- }
- }
-# endif
}
# endif /* !USE_PROC ... */
-# endif /* SUNOS */
-
-#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
- (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
- (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
+# endif /* SOLARISDL */
+#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
+ || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
+ || defined(NETBSD) || defined(OPENBSD)))
#ifdef USE_PROC_FOR_LIBRARIES
@@ -287,104 +235,204 @@ void GC_register_dynamic_libraries()
#define MAPS_BUF_SIZE (32*1024)
-extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
- /* Repeatedly read until buffer is filled, or EOF is encountered */
- /* Defined in os_dep.c. */
-
-char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
- char *prot_buf, unsigned int *maj_dev);
-word GC_apply_to_maps(word (*fn)(char *));
- /* 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 collector. Hence we roll our own. Should be */
+/* reasonably fast if the array is already mostly sorted, as we expect */
+/* it to be. */
+static 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 &&
+ (word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start)
+ ++nsorted;
+ if (nsorted == n) break;
+ GC_ASSERT((word)base[nsorted-1].hs_start > (word)base[nsorted].hs_start);
+ i = nsorted - 1;
+ while (i >= 0 && (word)base[i].hs_start > (word)base[i+1].hs_start) {
+ struct HeapSect tmp = base[i];
+ base[i] = base[i+1];
+ base[i+1] = tmp;
+ --i;
+ }
+ GC_ASSERT((word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start);
+ ++nsorted;
+ }
+}
-word GC_register_map_entries(char *maps)
+STATIC word GC_register_map_entries(char *maps)
{
- char prot_buf[5];
+ char *prot;
char *buf_ptr = maps;
- int count;
- word start, end;
+ ptr_t start, end;
unsigned int maj_dev;
- word least_ha, greatest_ha;
+ ptr_t least_ha, greatest_ha;
unsigned i;
- word datastart = (word)(DATASTART);
-
- /* Compute heap bounds. FIXME: Should be done by add_to_heap? */
- least_ha = (word)(-1);
- greatest_ha = 0;
- for (i = 0; i < GC_n_heap_sects; ++i) {
- word sect_start = (word)GC_heap_sects[i].hs_start;
- word sect_end = sect_start + GC_heap_sects[i].hs_bytes;
- if (sect_start < least_ha) least_ha = sect_start;
- if (sect_end > greatest_ha) greatest_ha = sect_end;
- }
- if (greatest_ha < (word)GC_scratch_last_end_ptr)
- greatest_ha = (word)GC_scratch_last_end_ptr;
+ ptr_t datastart;
+
+# ifdef DATASTART_IS_FUNC
+ static ptr_t datastart_cached = (ptr_t)(word)-1;
+
+ /* Evaluate DATASTART only once. */
+ if (datastart_cached == (ptr_t)(word)-1) {
+ datastart_cached = (ptr_t)(DATASTART);
+ }
+ datastart = datastart_cached;
+# else
+ datastart = (ptr_t)(DATASTART);
+# endif
+
+ 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_buf, &maj_dev);
- if (buf_ptr == NULL) return 1;
- if (prot_buf[1] == 'w') {
- /* This is a writable mapping. Add it to */
- /* the root set unless it is already otherwise */
- /* accounted for. */
- if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) {
- /* Stack mapping; discard */
- continue;
- }
-# ifdef THREADS
- if (GC_segment_is_thread_stack(start, end)) continue;
-# endif
- /* We no longer exclude the main data segment. */
- if (start < least_ha && end > least_ha) {
- end = least_ha;
- }
- 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);
- }
+ buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot,
+ &maj_dev, 0);
+ if (buf_ptr == NULL) return 1;
+ if (prot[1] == 'w') {
+ /* This is a writable mapping. Add it to */
+ /* the root set unless it is already otherwise */
+ /* accounted for. */
+ if ((word)start <= (word)GC_stackbottom
+ && (word)end >= (word)GC_stackbottom) {
+ /* Stack mapping; discard */
+ continue;
+ }
+# ifdef THREADS
+ /* This may fail, since a thread may already be */
+ /* unregistered, but its thread stack may still be there. */
+ /* That can fail because the stack may disappear while */
+ /* we're marking. Thus the marker is, and has to be */
+ /* prepared to recover from segmentation faults. */
+
+ if (GC_segment_is_thread_stack(start, end)) continue;
+
+ /* FIXME: 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. */
+ /* 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 ((word)end <= (word)least_ha
+ || (word)start >= (word)greatest_ha) {
+ /* The easy case; just trace entire segment */
+ GC_add_roots_inner((char *)start, (char *)end, TRUE);
+ continue;
+ }
+ /* Add sections that don't belong to us. */
+ i = 0;
+ while ((word)(GC_our_memory[i].hs_start
+ + GC_our_memory[i].hs_bytes) < (word)start)
+ ++i;
+ GC_ASSERT(i < GC_n_memory);
+ if ((word)GC_our_memory[i].hs_start <= (word)start) {
+ start = GC_our_memory[i].hs_start
+ + GC_our_memory[i].hs_bytes;
+ ++i;
+ }
+ while (i < GC_n_memory
+ && (word)GC_our_memory[i].hs_start < (word)end
+ && (word)start < (word)end) {
+ if ((word)start < (word)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 ((word)start < (word)end)
+ GC_add_roots_inner((char *)start, (char *)end, TRUE);
+ }
}
return 1;
}
-void GC_register_dynamic_libraries()
+GC_INNER void GC_register_dynamic_libraries(void)
{
- if (!GC_apply_to_maps(GC_register_map_entries))
- ABORT("Failed to read /proc for library registration.");
+ if (!GC_register_map_entries(GC_get_maps()))
+ ABORT("Failed to read /proc for library registration");
}
/* We now take care of the main data segment ourselves: */
-GC_bool GC_register_main_static_data()
+GC_INNER GC_bool GC_register_main_static_data(void)
{
- return FALSE;
+ return FALSE;
}
-
+
# define HAVE_REGISTER_MAIN_STATIC_DATA
-#endif /* USE_PROC_FOR_LIBRARIES */
+#else /* !USE_PROC_FOR_LIBRARIES */
-#if !defined(USE_PROC_FOR_LIBRARIES)
-/* The following is the preferred way to walk dynamic libraries */
-/* For glibc 2.2.4+. Unfortunately, it doesn't work for older */
-/* versions. Thanks to Jakub Jelinek for most of the code. */
+/* The following is the preferred way to walk dynamic libraries */
+/* For glibc 2.2.4+. Unfortunately, it doesn't work for older */
+/* versions. Thanks to Jakub Jelinek for most of the code. */
-# if defined(LINUX) /* Are others OK here, too? */ \
+#if (defined(LINUX) || defined (__GLIBC__)) /* Are others OK here, too? */ \
&& (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
- || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
-
-/* We have the header files for a glibc that includes dl_iterate_phdr. */
+ || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
+/* We have the header files for a glibc that includes dl_iterate_phdr. */
/* It may still not be available in the library on the target system. */
-/* Thus we also treat it as a weak symbol. */
-#define HAVE_DL_ITERATE_PHDR
+/* Thus we also treat it as a weak symbol. */
+# define HAVE_DL_ITERATE_PHDR
+# pragma weak dl_iterate_phdr
+#endif
+
+#if (defined(FREEBSD) && __FreeBSD__ >= 7)
+ /* On the FreeBSD system, any target system at major version 7 shall */
+ /* have dl_iterate_phdr; therefore, we need not make it weak as above. */
+# define HAVE_DL_ITERATE_PHDR
+# define DL_ITERATE_PHDR_STRONG
+#endif
-static int GC_register_dynlib_callback(info, size, ptr)
- struct dl_phdr_info * info;
- size_t size;
- void * ptr;
+#if defined(HAVE_DL_ITERATE_PHDR)
+
+# ifdef PT_GNU_RELRO
+/* Instead of registering PT_LOAD sections directly, we keep them */
+/* in a temporary list, and filter them by excluding PT_GNU_RELRO */
+/* segments. Processing PT_GNU_RELRO sections with */
+/* GC_exclude_static_roots instead would be superficially cleaner. But */
+/* it runs into trouble if a client registers an overlapping segment, */
+/* which unfortunately seems quite possible. */
+
+# define MAX_LOAD_SEGS MAX_ROOT_SETS
+
+ static struct load_segment {
+ ptr_t start;
+ ptr_t end;
+ /* Room for a second segment if we remove a RELRO segment */
+ /* from the middle. */
+ ptr_t start2;
+ ptr_t end2;
+ } load_segs[MAX_LOAD_SEGS];
+
+ static int n_load_segs;
+# endif /* PT_GNU_RELRO */
+
+STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
+ size_t size, void * ptr)
{
const ElfW(Phdr) * p;
- char * start;
- register int i;
+ ptr_t start, end;
+ int i;
/* Make sure struct dl_phdr_info is at least as big as we need. */
if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
@@ -392,139 +440,256 @@ static int GC_register_dynlib_callback(info, size, ptr)
return -1;
p = info->dlpi_phdr;
- for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
+ for( i = 0; i < (int)info->dlpi_phnum; i++, p++ ) {
switch( p->p_type ) {
+# ifdef PT_GNU_RELRO
+ case PT_GNU_RELRO:
+ /* This entry is known to be constant and will eventually be remapped
+ read-only. However, the address range covered by this entry is
+ typically a subset of a previously encountered `LOAD' segment, so
+ we need to exclude it. */
+ {
+ int j;
+
+ start = ((ptr_t)(p->p_vaddr)) + info->dlpi_addr;
+ end = start + p->p_memsz;
+ for (j = n_load_segs; --j >= 0; ) {
+ if ((word)start >= (word)load_segs[j].start
+ && (word)start < (word)load_segs[j].end) {
+ if (load_segs[j].start2 != 0) {
+ WARN("More than one GNU_RELRO segment per load seg\n",0);
+ } else {
+ GC_ASSERT((word)end <= (word)load_segs[j].end);
+ /* Remove from the existing load segment */
+ load_segs[j].end2 = load_segs[j].end;
+ load_segs[j].end = start;
+ load_segs[j].start2 = end;
+ }
+ break;
+ }
+ if (j == 0) WARN("Failed to find PT_GNU_RELRO segment"
+ " inside PT_LOAD region", 0);
+ }
+ }
+
+ break;
+# endif
+
case PT_LOAD:
- {
- if( !(p->p_flags & PF_W) ) break;
- start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
- GC_add_roots_inner(start, start + p->p_memsz, TRUE);
- }
+ {
+ GC_has_static_roots_func callback = GC_has_static_roots;
+ if( !(p->p_flags & PF_W) ) break;
+ start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
+ end = start + p->p_memsz;
+
+ if (callback != 0 && !callback(info->dlpi_name, start, p->p_memsz))
+ break;
+# ifdef PT_GNU_RELRO
+ if (n_load_segs >= MAX_LOAD_SEGS) ABORT("Too many PT_LOAD segs");
+# if CPP_WORDSZ == 64
+ /* FIXME: GC_push_all eventually does the correct */
+ /* rounding to the next multiple of ALIGNMENT, so, most */
+ /* probably, we should remove the corresponding assertion */
+ /* check in GC_add_roots_inner along with this code line. */
+ /* start pointer value may require aligning */
+ start = (ptr_t)((word)start & ~(sizeof(word) - 1));
+# endif
+ load_segs[n_load_segs].start = start;
+ load_segs[n_load_segs].end = end;
+ load_segs[n_load_segs].start2 = 0;
+ load_segs[n_load_segs].end2 = 0;
+ ++n_load_segs;
+# else
+ GC_add_roots_inner(start, end, TRUE);
+# endif /* PT_GNU_RELRO */
+ }
break;
default:
- break;
+ break;
}
}
- * (int *)ptr = 1; /* Signal that we were called */
+ *(int *)ptr = 1; /* Signal that we were called */
return 0;
-}
-
-/* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
+}
-#pragma weak dl_iterate_phdr
+/* Do we need to separately register the main static data segment? */
+GC_INNER GC_bool GC_register_main_static_data(void)
+{
+# ifdef DL_ITERATE_PHDR_STRONG
+ /* If dl_iterate_phdr is not a weak symbol then don't test against */
+ /* zero (otherwise a compiler might issue a warning). */
+ return FALSE;
+# else
+ return (dl_iterate_phdr == 0); /* implicit conversion to function ptr */
+# endif
+}
-GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
+/* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
+STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
{
- if (dl_iterate_phdr) {
- int did_something = 0;
- dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
- if (!did_something) {
- /* dl_iterate_phdr may forget the static data segment in */
- /* statically linked executables. */
- GC_add_roots_inner(DATASTART, (char *)(DATAEND), TRUE);
-# if defined(DATASTART2)
- GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
-# endif
+ int did_something;
+ if (GC_register_main_static_data())
+ return FALSE;
+
+# ifdef PT_GNU_RELRO
+ {
+ static GC_bool excluded_segs = FALSE;
+ n_load_segs = 0;
+ if (!EXPECT(excluded_segs, TRUE)) {
+ GC_exclude_static_roots_inner((ptr_t)load_segs,
+ (ptr_t)load_segs + sizeof(load_segs));
+ excluded_segs = TRUE;
+ }
}
+# endif
- return TRUE;
+ did_something = 0;
+ dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
+ if (did_something) {
+# ifdef PT_GNU_RELRO
+ int i;
+
+ for (i = 0; i < n_load_segs; ++i) {
+ if ((word)load_segs[i].end > (word)load_segs[i].start) {
+ GC_add_roots_inner(load_segs[i].start, load_segs[i].end, TRUE);
+ }
+ if ((word)load_segs[i].end2 > (word)load_segs[i].start2) {
+ GC_add_roots_inner(load_segs[i].start2, load_segs[i].end2, TRUE);
+ }
+ }
+# endif
} else {
- return FALSE;
- }
-}
+ char *datastart;
+ char *dataend;
+# ifdef DATASTART_IS_FUNC
+ static ptr_t datastart_cached = (ptr_t)(word)-1;
+
+ /* Evaluate DATASTART only once. */
+ if (datastart_cached == (ptr_t)(word)-1) {
+ datastart_cached = (ptr_t)(DATASTART);
+ }
+ datastart = (char *)datastart_cached;
+# else
+ datastart = DATASTART;
+# endif
+# ifdef DATAEND_IS_FUNC
+ {
+ static ptr_t dataend_cached = 0;
+ /* Evaluate DATAEND only once. */
+ if (dataend_cached == 0) {
+ dataend_cached = (ptr_t)(DATAEND);
+ }
+ dataend = (char *)dataend_cached;
+ }
+# else
+ dataend = DATAEND;
+# endif
-/* Do we need to separately register the main static data segment? */
-GC_bool GC_register_main_static_data()
-{
- return (dl_iterate_phdr == 0);
+ /* dl_iterate_phdr may forget the static data segment in */
+ /* statically linked executables. */
+ GC_add_roots_inner(datastart, dataend, TRUE);
+# if defined(DATASTART2)
+ GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
+# endif
+ }
+ return TRUE;
}
-#define HAVE_REGISTER_MAIN_STATIC_DATA
+# define HAVE_REGISTER_MAIN_STATIC_DATA
-# else /* !LINUX || version(glibc) < 2.2.4 */
+#else /* !HAVE_DL_ITERATE_PHDR */
/* Dynamic loading code for Linux running ELF. Somewhat tested on
- * Linux/x86, untested but hopefully should work on Linux/Alpha.
+ * Linux/x86, untested but hopefully should work on Linux/Alpha.
* This code was derived from the Solaris/ELF support. Thanks to
* whatever kind soul wrote that. - Patrick Bridges */
/* This doesn't necessarily work in all cases, e.g. with preloaded
- * dynamic libraries. */
+ * dynamic libraries. */
-#if defined(NETBSD)
-# include <sys/exec_elf.h>
-/* for compatibility with 1.4.x */
-# ifndef DT_DEBUG
-# define DT_DEBUG 21
-# endif
-# ifndef PT_LOAD
-# define PT_LOAD 1
-# endif
-# ifndef PF_W
-# define PF_W 2
-# endif
-#else
+# if defined(NETBSD) || defined(OPENBSD)
+# include <sys/exec_elf.h>
+ /* for compatibility with 1.4.x */
+# ifndef DT_DEBUG
+# define DT_DEBUG 21
+# endif
+# ifndef PT_LOAD
+# define PT_LOAD 1
+# endif
+# ifndef PF_W
+# define PF_W 2
+# endif
+# elif !defined(PLATFORM_ANDROID)
# include <elf.h>
-#endif
-#include <link.h>
+# endif
+# ifndef PLATFORM_ANDROID
+# include <link.h>
# endif
+#endif /* !HAVE_DL_ITERATE_PHDR */
+
#ifdef __GNUC__
# pragma weak _DYNAMIC
#endif
extern ElfW(Dyn) _DYNAMIC[];
-static struct link_map *
-GC_FirstDLOpenedLinkMap()
+STATIC struct link_map *
+GC_FirstDLOpenedLinkMap(void)
{
ElfW(Dyn) *dp;
- struct r_debug *r;
static struct link_map *cachedResult = 0;
- if( _DYNAMIC == 0) {
+ if (0 == (ptr_t)_DYNAMIC) {
+ /* _DYNAMIC symbol not resolved. */
return(0);
}
if( cachedResult == 0 ) {
+# if defined(NETBSD) && defined(RTLD_DI_LINKMAP)
+ struct link_map *lm = NULL;
+ if (!dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lm))
+ cachedResult = lm;
+# else
int tag;
for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
if( tag == DT_DEBUG ) {
struct link_map *lm
= ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
- if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
+ if( lm != 0 ) cachedResult = lm->l_next; /* might be NULL */
break;
}
}
+# endif /* !NETBSD || !RTLD_DI_LINKMAP */
}
return cachedResult;
}
-
-void GC_register_dynamic_libraries()
+GC_INNER void GC_register_dynamic_libraries(void)
{
struct link_map *lm;
-
# ifdef HAVE_DL_ITERATE_PHDR
if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
- return;
+ return;
}
# endif
- lm = GC_FirstDLOpenedLinkMap();
- for (lm = GC_FirstDLOpenedLinkMap();
- lm != (struct link_map *) 0; lm = lm->l_next)
+ for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next)
{
- ElfW(Ehdr) * e;
+ ElfW(Ehdr) * e;
ElfW(Phdr) * p;
unsigned long offset;
char * start;
- register int i;
-
- e = (ElfW(Ehdr) *) lm->l_addr;
+ int i;
+
+ e = (ElfW(Ehdr) *) lm->l_addr;
+# ifdef PLATFORM_ANDROID
+ if (e == NULL)
+ continue;
+# endif
p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
offset = ((unsigned long)(lm->l_addr));
- for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
+ for( i = 0; i < (int)e->e_phnum; i++, p++ ) {
switch( p->p_type ) {
case PT_LOAD:
{
@@ -536,7 +701,7 @@ void GC_register_dynamic_libraries()
default:
break;
}
- }
+ }
}
}
@@ -556,273 +721,204 @@ void GC_register_dynamic_libraries()
# define IRIX6
#endif
-extern void * GC_roots_present();
- /* The type is a lie, since the real type doesn't make sense here, */
- /* and we only test for NULL. */
-
-
-/* We use /proc to track down all parts of the address space that are */
-/* mapped by the process, and throw out regions we know we shouldn't */
-/* worry about. This may also work under other SVR4 variants. */
-void GC_register_dynamic_libraries()
+/* We use /proc to track down all parts of the address space that are */
+/* mapped by the process, and throw out regions we know we shouldn't */
+/* worry about. This may also work under other SVR4 variants. */
+GC_INNER void GC_register_dynamic_libraries(void)
{
static int fd = -1;
char buf[30];
static prmap_t * addr_map = 0;
- static int current_sz = 0; /* Number of records currently in addr_map */
- static int needed_sz; /* Required size of addr_map */
- register int i;
- register long flags;
- register ptr_t start;
- register ptr_t limit;
- ptr_t heap_start = (ptr_t)HEAP_START;
+ static int current_sz = 0; /* Number of records currently in addr_map */
+ static int needed_sz; /* Required size of addr_map */
+ int i;
+ long flags;
+ ptr_t start;
+ ptr_t limit;
+ ptr_t heap_start = HEAP_START;
ptr_t heap_end = heap_start;
-# ifdef SUNOS5DL
+# ifdef SOLARISDL
# define MA_PHYS 0
-# endif /* SUNOS5DL */
+# endif /* SOLARISDL */
if (fd < 0) {
- sprintf(buf, "/proc/%d", getpid());
- /* The above generates a lint complaint, since pid_t varies. */
- /* It's unclear how to improve this. */
+ (void)snprintf(buf, sizeof(buf), "/proc/%ld", (long)getpid());
+ buf[sizeof(buf) - 1] = '\0';
+ /* The above generates a lint complaint, since pid_t varies. */
+ /* It's unclear how to improve this. */
fd = open(buf, O_RDONLY);
if (fd < 0) {
- ABORT("/proc open failed");
+ ABORT("/proc open failed");
}
}
if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
- GC_err_printf2("fd = %d, errno = %d\n", fd, errno);
- ABORT("/proc PIOCNMAP ioctl failed");
+ GC_err_printf("fd = %d, errno = %d\n", fd, errno);
+ ABORT("/proc PIOCNMAP ioctl failed");
}
if (needed_sz >= current_sz) {
current_sz = needed_sz * 2 + 1;
- /* Expansion, plus room for 0 record */
- addr_map = (prmap_t *)GC_scratch_alloc((word)
- (current_sz * sizeof(prmap_t)));
+ /* Expansion, plus room for 0 record */
+ addr_map = (prmap_t *)GC_scratch_alloc(
+ (word)current_sz * sizeof(prmap_t));
+ if (addr_map == NULL)
+ ABORT("Insufficient memory for address map");
}
if (ioctl(fd, PIOCMAP, addr_map) < 0) {
- GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
+ GC_err_printf("fd = %d, errno = %d, needed_sz = %d, addr_map = %p\n",
fd, errno, needed_sz, addr_map);
- ABORT("/proc PIOCMAP ioctl failed");
+ ABORT("/proc PIOCMAP ioctl failed");
};
if (GC_n_heap_sects > 0) {
- heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
- + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
- if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr;
+ heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
+ + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
+ if ((word)heap_end < (word)GC_scratch_last_end_ptr)
+ heap_end = GC_scratch_last_end_ptr;
}
for (i = 0; i < needed_sz; i++) {
flags = addr_map[i].pr_mflags;
- if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant;
+ if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
+ | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
goto irrelevant;
- /* The latter test is empirically useless in very old Irix */
- /* versions. Other than the */
- /* main data and stack segments, everything appears to be */
- /* mapped readable, writable, executable, and shared(!!). */
- /* This makes no sense to me. - HB */
+ /* The latter test is empirically useless in very old Irix */
+ /* versions. Other than the */
+ /* main data and stack segments, everything appears to be */
+ /* mapped readable, writable, executable, and shared(!!). */
+ /* This makes no sense to me. - HB */
start = (ptr_t)(addr_map[i].pr_vaddr);
if (GC_roots_present(start)) goto irrelevant;
- if (start < heap_end && start >= heap_start)
- goto irrelevant;
-# ifdef MMAP_STACKS
- if (GC_is_thread_stack(start)) goto irrelevant;
-# endif /* MMAP_STACKS */
+ if ((word)start < (word)heap_end && (word)start >= (word)heap_start)
+ goto irrelevant;
limit = start + addr_map[i].pr_size;
- /* The following seemed to be necessary for very old versions */
- /* of Irix, but it has been reported to discard relevant */
- /* segments under Irix 6.5. */
-# ifndef IRIX6
- if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
- /* Discard text segments, i.e. 0-offset mappings against */
- /* executable files which appear to have ELF headers. */
- caddr_t arg;
- int obj;
-# define MAP_IRR_SZ 10
- static ptr_t map_irr[MAP_IRR_SZ];
- /* Known irrelevant map entries */
- static int n_irr = 0;
- struct stat buf;
- register int i;
-
- for (i = 0; i < n_irr; i++) {
- if (map_irr[i] == start) goto irrelevant;
- }
- arg = (caddr_t)start;
- obj = ioctl(fd, PIOCOPENM, &arg);
- if (obj >= 0) {
- fstat(obj, &buf);
- close(obj);
- if ((buf.st_mode & 0111) != 0) {
- if (n_irr < MAP_IRR_SZ) {
- map_irr[n_irr++] = start;
- }
- goto irrelevant;
- }
- }
- }
-# endif /* !IRIX6 */
+ /* The following seemed to be necessary for very old versions */
+ /* of Irix, but it has been reported to discard relevant */
+ /* segments under Irix 6.5. */
+# ifndef IRIX6
+ if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
+ /* Discard text segments, i.e. 0-offset mappings against */
+ /* executable files which appear to have ELF headers. */
+ caddr_t arg;
+ int obj;
+# define MAP_IRR_SZ 10
+ static ptr_t map_irr[MAP_IRR_SZ];
+ /* Known irrelevant map entries */
+ static int n_irr = 0;
+ struct stat buf;
+ register int j;
+
+ for (j = 0; j < n_irr; j++) {
+ if (map_irr[j] == start) goto irrelevant;
+ }
+ arg = (caddr_t)start;
+ obj = ioctl(fd, PIOCOPENM, &arg);
+ if (obj >= 0) {
+ fstat(obj, &buf);
+ close(obj);
+ if ((buf.st_mode & 0111) != 0) {
+ if (n_irr < MAP_IRR_SZ) {
+ map_irr[n_irr++] = start;
+ }
+ goto irrelevant;
+ }
+ }
+ }
+# endif /* !IRIX6 */
GC_add_roots_inner(start, limit, TRUE);
irrelevant: ;
}
- /* Dont keep cached descriptor, for now. Some kernels don't like us */
- /* to keep a /proc file descriptor around during kill -9. */
- if (close(fd) < 0) ABORT("Couldnt close /proc file");
- fd = -1;
+ /* Don't keep cached descriptor, for now. Some kernels don't like us */
+ /* to keep a /proc file descriptor around during kill -9. */
+ if (close(fd) < 0) ABORT("Couldn't close /proc file");
+ fd = -1;
}
# endif /* USE_PROC || IRIX5 */
-# if defined(MSWIN32) || defined(MSWINCE)
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
-# define WIN32_LEAN_AND_MEAN
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
# define NOSERVICE
# include <windows.h>
# include <stdlib.h>
- /* We traverse the entire address space and register all segments */
- /* that could possibly have been written to. */
-
- extern GC_bool GC_is_heap_base (ptr_t p);
-
-# ifdef GC_WIN32_THREADS
- extern void GC_get_next_stack(char *start, char **lo, char **hi);
- void GC_cond_add_roots(char *base, char * limit)
- {
+ /* We traverse the entire address space and register all segments */
+ /* that could possibly have been written to. */
+ STATIC void GC_cond_add_roots(char *base, char * limit)
+ {
+# ifdef GC_WIN32_THREADS
char * curr_base = base;
char * next_stack_lo;
char * next_stack_hi;
-
+
if (base == limit) return;
for(;;) {
- GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
- if (next_stack_lo >= limit) break;
- GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
- curr_base = next_stack_hi;
+ GC_get_next_stack(curr_base, limit, &next_stack_lo, &next_stack_hi);
+ if ((word)next_stack_lo >= (word)limit) break;
+ if ((word)next_stack_lo > (word)curr_base)
+ GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
+ curr_base = next_stack_hi;
}
- if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
- }
-# else
- void GC_cond_add_roots(char *base, char * limit)
- {
- char dummy;
+ if ((word)curr_base < (word)limit)
+ GC_add_roots_inner(curr_base, limit, TRUE);
+# else
char * stack_top
- = (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
+ = (char *)((word)GC_approx_sp() &
+ ~(GC_sysinfo.dwAllocationGranularity - 1));
+
if (base == limit) return;
- if (limit > stack_top && base < GC_stackbottom) {
- /* Part of the stack; ignore it. */
- return;
+ if ((word)limit > (word)stack_top
+ && (word)base < (word)GC_stackbottom) {
+ /* Part of the stack; ignore it. */
+ return;
}
GC_add_roots_inner(base, limit, TRUE);
- }
-# endif
-
-# ifdef MSWINCE
- /* Do we need to separately register the main static data segment? */
- GC_bool GC_register_main_static_data()
- {
- return FALSE;
- }
-# else /* win32 */
- extern GC_bool GC_no_win32_dlls;
-
- GC_bool GC_register_main_static_data()
- {
- return GC_no_win32_dlls;
+# endif
}
-# endif /* win32 */
-
-# define HAVE_REGISTER_MAIN_STATIC_DATA
- GC_bool GC_warn_fb = TRUE; /* Warn about traced likely */
- /* graphics memory. */
- GC_bool GC_disallow_ignore_fb = FALSE;
- int GC_ignore_fb_mb; /* Ignore mappings bigger than the */
- /* specified number of MB. */
- GC_bool GC_ignore_fb = FALSE; /* Enable frame buffer */
- /* checking. */
-
- /* Issue warning if tracing apparent framebuffer. */
- /* This limits us to one warning, and it's a back door to */
- /* disable that. */
-
- /* Should [start, start+len) be treated as a frame buffer */
- /* and ignored? */
- /* Unfortunately, we currently have no real way to tell */
- /* automatically, and rely largely on user input. */
- /* FIXME: If we had more data on this phenomenon (e.g. */
- /* is start aligned to a MB multiple?) we should be able to */
- /* do better. */
- /* Based on a very limited sample, it appears that: */
- /* - Frame buffer mappings appear as mappings of length */
- /* 2**n MB - 192K. (We guess the 192K can vary a bit.) */
- /* - Have a stating address at best 64K aligned. */
- /* I'd love more information about the mapping, since I */
- /* can't reproduce the problem. */
- static GC_bool is_frame_buffer(ptr_t start, size_t len)
+#ifdef DYNAMIC_LOADING
+ /* GC_register_main_static_data is not needed unless DYNAMIC_LOADING. */
+ GC_INNER GC_bool GC_register_main_static_data(void)
{
- static GC_bool initialized = FALSE;
-# define MB (1024*1024)
-# define DEFAULT_FB_MB 15
-# define MIN_FB_MB 3
-
- if (GC_disallow_ignore_fb) return FALSE;
- if (!initialized) {
- char * ignore_fb_string = GETENV("GC_IGNORE_FB");
-
- if (0 != ignore_fb_string) {
- while (*ignore_fb_string == ' ' || *ignore_fb_string == '\t')
- ++ignore_fb_string;
- if (*ignore_fb_string == '\0') {
- GC_ignore_fb_mb = DEFAULT_FB_MB;
- } else {
- GC_ignore_fb_mb = atoi(ignore_fb_string);
- if (GC_ignore_fb_mb < MIN_FB_MB) {
- WARN("Bad GC_IGNORE_FB value. Using %ld\n", DEFAULT_FB_MB);
- GC_ignore_fb_mb = DEFAULT_FB_MB;
- }
- }
- GC_ignore_fb = TRUE;
- } else {
- GC_ignore_fb_mb = DEFAULT_FB_MB; /* For warning */
- }
- initialized = TRUE;
- }
- if (len >= ((size_t)GC_ignore_fb_mb << 20)) {
- if (GC_ignore_fb) {
- return TRUE;
- } else {
- if (GC_warn_fb) {
- WARN("Possible frame buffer mapping at 0x%lx: \n"
- "\tConsider setting GC_IGNORE_FB to improve performance.\n",
- start);
- GC_warn_fb = FALSE;
- }
- return FALSE;
- }
- } else {
+# if defined(MSWINCE) || defined(CYGWIN32)
+ /* Do we need to separately register the main static data segment? */
return FALSE;
- }
+# else
+ return GC_no_win32_dlls;
+# endif
}
+# define HAVE_REGISTER_MAIN_STATIC_DATA
+#endif /* DYNAMIC_LOADING */
# ifdef DEBUG_VIRTUALQUERY
void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
{
- GC_printf4("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
- buf -> BaseAddress, buf -> AllocationBase, buf -> RegionSize,
- buf -> RegionSize);
- GC_printf4("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
- "Type = %lx\n",
- buf -> AllocationProtect, buf -> State, buf -> Protect,
- buf -> Type);
+ GC_printf("BaseAddress = 0x%lx, AllocationBase = 0x%lx,"
+ " RegionSize = 0x%lx(%lu)\n", buf -> BaseAddress,
+ buf -> AllocationBase, buf -> RegionSize, buf -> RegionSize);
+ GC_printf("\tAllocationProtect = 0x%lx, State = 0x%lx, Protect = 0x%lx, "
+ "Type = 0x%lx\n", buf -> AllocationProtect, buf -> State,
+ buf -> Protect, buf -> Type);
}
# endif /* DEBUG_VIRTUALQUERY */
- void GC_register_dynamic_libraries()
+# if defined(MSWINCE) || defined(CYGWIN32)
+ /* FIXME: Should we really need to scan MEM_PRIVATE sections? */
+ /* For now, we don't add MEM_PRIVATE sections to the data roots for */
+ /* WinCE because otherwise SEGV fault sometimes happens to occur in */
+ /* GC_mark_from() (and, even if we use WRAP_MARK_SOME, WinCE prints */
+ /* a "Data Abort" message to the debugging console). */
+ /* To workaround that, use -DGC_REGISTER_MEM_PRIVATE. */
+# define GC_wnt TRUE
+# endif
+
+ GC_INNER void GC_register_dynamic_libraries(void)
{
MEMORY_BASIC_INFORMATION buf;
- DWORD result;
+ size_t result;
DWORD protect;
LPVOID p;
char * base;
@@ -832,54 +928,64 @@ void GC_register_dynamic_libraries()
if (GC_no_win32_dlls) return;
# endif
base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
-# if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
- /* Only the first 32 MB of address space belongs to the current process */
- while (p < (LPVOID)0x02000000) {
+ while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress) {
result = VirtualQuery(p, &buf, sizeof(buf));
- if (result == 0) {
- /* Page is free; advance to the next possible allocation base */
- new_limit = (char *)
- (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
- & ~(GC_sysinfo.dwAllocationGranularity-1));
- } else
-# else
- while (p < GC_sysinfo.lpMaximumApplicationAddress) {
- result = VirtualQuery(p, &buf, sizeof(buf));
-# endif
- {
- if (result != sizeof(buf)) {
- ABORT("Weird VirtualQuery result");
- }
- new_limit = (char *)p + buf.RegionSize;
- protect = buf.Protect;
- if (buf.State == MEM_COMMIT
- && (protect == PAGE_EXECUTE_READWRITE
- || protect == PAGE_READWRITE)
- && !GC_is_heap_base(buf.AllocationBase)
- && !is_frame_buffer(p, buf.RegionSize)) {
-# ifdef DEBUG_VIRTUALQUERY
- GC_dump_meminfo(&buf);
-# endif
- if ((char *)p != limit) {
- GC_cond_add_roots(base, limit);
- base = p;
- }
- limit = new_limit;
- }
- }
- if (p > (LPVOID)new_limit /* overflow */) break;
+# ifdef MSWINCE
+ if (result == 0) {
+ /* Page is free; advance to the next possible allocation base */
+ new_limit = (char *)
+ (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
+ & ~(GC_sysinfo.dwAllocationGranularity-1));
+ } else
+# endif
+ /* else */ {
+ if (result != sizeof(buf)) {
+ ABORT("Weird VirtualQuery result");
+ }
+ new_limit = (char *)p + buf.RegionSize;
+ protect = buf.Protect;
+ if (buf.State == MEM_COMMIT
+ && (protect == PAGE_EXECUTE_READWRITE
+ || protect == PAGE_READWRITE)
+ && (buf.Type == MEM_IMAGE
+# ifdef GC_REGISTER_MEM_PRIVATE
+ || (protect == PAGE_READWRITE && buf.Type == MEM_PRIVATE)
+# else
+ /* There is some evidence that we cannot always */
+ /* ignore MEM_PRIVATE sections under Windows ME */
+ /* and predecessors. Hence we now also check for */
+ /* that case. */
+ || (!GC_wnt && buf.Type == MEM_PRIVATE)
+# endif
+ )
+ && !GC_is_heap_base(buf.AllocationBase)) {
+# ifdef DEBUG_VIRTUALQUERY
+ GC_dump_meminfo(&buf);
+# endif
+ if ((char *)p != limit) {
+ GC_cond_add_roots(base, limit);
+ base = p;
+ }
+ limit = new_limit;
+ }
+ }
+ if ((word)p > (word)new_limit /* overflow */) break;
p = (LPVOID)new_limit;
}
GC_cond_add_roots(base, limit);
}
-#endif /* MSWIN32 || MSWINCE */
-
+#endif /* MSWIN32 || MSWINCE || CYGWIN32 */
+
#if defined(ALPHA) && defined(OSF1)
#include <loader.h>
-void GC_register_dynamic_libraries()
+extern char *sys_errlist[];
+extern int sys_nerr;
+extern int errno;
+
+GC_INNER void GC_register_dynamic_libraries(void)
{
int status;
ldr_process_t mypid;
@@ -888,17 +994,17 @@ void GC_register_dynamic_libraries()
ldr_module_t moduleid = LDR_NULL_MODULE;
ldr_module_info_t moduleinfo;
size_t moduleinfosize = sizeof(moduleinfo);
- size_t modulereturnsize;
+ size_t modulereturnsize;
/* region */
- ldr_region_t region;
+ ldr_region_t region;
ldr_region_info_t regioninfo;
size_t regioninfosize = sizeof(regioninfo);
size_t regionreturnsize;
/* Obtain id of this process */
mypid = ldr_my_process();
-
+
/* For each module */
while (TRUE) {
@@ -911,24 +1017,19 @@ void GC_register_dynamic_libraries()
/* Check status AFTER checking moduleid because */
/* of a bug in the non-shared ldr_next_module stub */
- if (status != 0 ) {
- GC_printf1("dynamic_load: status = %ld\n", (long)status);
- {
- extern char *sys_errlist[];
- extern int sys_nerr;
- extern int errno;
- if (errno <= sys_nerr) {
- GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
- } else {
- GC_printf1("dynamic_load: %d\n", (long)errno);
- }
+ if (status != 0) {
+ GC_COND_LOG_PRINTF("dynamic_load: status = %d\n", status);
+ if (errno < sys_nerr) {
+ GC_COND_LOG_PRINTF("dynamic_load: %s\n", sys_errlist[errno]);
+ } else {
+ GC_COND_LOG_PRINTF("dynamic_load: err_code = %d\n", errno);
+ }
+ ABORT("ldr_next_module failed");
}
- ABORT("ldr_next_module failed");
- }
/* Get the module information */
status = ldr_inq_module(mypid, moduleid, &moduleinfo,
- moduleinfosize, &modulereturnsize);
+ moduleinfosize, &modulereturnsize);
if (status != 0 )
ABORT("ldr_inq_module failed");
@@ -936,17 +1037,16 @@ void GC_register_dynamic_libraries()
if (moduleinfo.lmi_flags & LDR_MAIN)
continue; /* skip the main module */
-# ifdef VERBOSE
- GC_printf("---Module---\n");
- GC_printf("Module ID = %16ld\n", moduleinfo.lmi_modid);
- GC_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
- GC_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
- GC_printf("pathname of module = \"%s\"\n", moduleinfo.lmi_name);
+# ifdef DL_VERBOSE
+ GC_log_printf("---Module---\n");
+ GC_log_printf("Module ID\t = %16ld\n", moduleinfo.lmi_modid);
+ GC_log_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
+ GC_log_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
+ GC_log_printf("module pathname\t = \"%s\"\n", moduleinfo.lmi_name);
# endif
/* For each region in this module */
for (region = 0; region < moduleinfo.lmi_nregion; region++) {
-
/* Get the region information */
status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
regioninfosize, &regionreturnsize);
@@ -957,22 +1057,22 @@ void GC_register_dynamic_libraries()
if (! (regioninfo.lri_prot & LDR_W))
continue;
-# ifdef VERBOSE
- GC_printf("--- Region ---\n");
- GC_printf("Region number = %16ld\n",
- regioninfo.lri_region_no);
- GC_printf("Protection flags = %016x\n", regioninfo.lri_prot);
- GC_printf("Virtual address = %16p\n", regioninfo.lri_vaddr);
- GC_printf("Mapped address = %16p\n", regioninfo.lri_mapaddr);
- GC_printf("Region size = %16ld\n", regioninfo.lri_size);
- GC_printf("Region name = \"%s\"\n", regioninfo.lri_name);
+# ifdef DL_VERBOSE
+ GC_log_printf("--- Region ---\n");
+ GC_log_printf("Region number\t = %16ld\n",
+ regioninfo.lri_region_no);
+ GC_log_printf("Protection flags = %016x\n", regioninfo.lri_prot);
+ GC_log_printf("Virtual address\t = %16p\n", regioninfo.lri_vaddr);
+ GC_log_printf("Mapped address\t = %16p\n",
+ regioninfo.lri_mapaddr);
+ GC_log_printf("Region size\t = %16ld\n", regioninfo.lri_size);
+ GC_log_printf("Region name\t = \"%s\"\n", regioninfo.lri_name);
# endif
/* register region as a garbage collection root */
- GC_add_roots_inner (
- (char *)regioninfo.lri_mapaddr,
- (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
- TRUE);
+ GC_add_roots_inner((char *)regioninfo.lri_mapaddr,
+ (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
+ TRUE);
}
}
@@ -984,11 +1084,10 @@ void GC_register_dynamic_libraries()
#include <errno.h>
#include <dl.h>
-extern int errno;
extern char *sys_errlist[];
extern int sys_nerr;
-void GC_register_dynamic_libraries()
+GC_INNER void GC_register_dynamic_libraries(void)
{
int status;
int index = 1; /* Ordinal position in shared library search list */
@@ -1002,82 +1101,82 @@ void GC_register_dynamic_libraries()
/* Check if this is the end of the list or if some error occured */
if (status != 0) {
-# ifdef GC_HPUX_THREADS
- /* I've seen errno values of 0. The man page is not clear */
- /* as to whether errno should get set on a -1 return. */
- break;
-# else
+# ifdef GC_HPUX_THREADS
+ /* I've seen errno values of 0. The man page is not clear */
+ /* as to whether errno should get set on a -1 return. */
+ break;
+# else
if (errno == EINVAL) {
- break; /* Moved past end of shared library list --> finished */
+ break; /* Moved past end of shared library list --> finished */
} else {
- if (errno <= sys_nerr) {
- GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
- } else {
- GC_printf1("dynamic_load: %d\n", (long) errno);
- }
- ABORT("shl_get failed");
+ if (errno < sys_nerr) {
+ GC_COND_LOG_PRINTF("dynamic_load: %s\n", sys_errlist[errno]);
+ } else {
+ GC_COND_LOG_PRINTF("dynamic_load: err_code = %d\n", errno);
+ }
+ ABORT("shl_get failed");
}
-# endif
+# endif
}
-# ifdef VERBOSE
- GC_printf0("---Shared library---\n");
- GC_printf1("\tfilename = \"%s\"\n", shl_desc->filename);
- GC_printf1("\tindex = %d\n", index);
- GC_printf1("\thandle = %08x\n",
- (unsigned long) shl_desc->handle);
- GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
- GC_printf1("\ttext seg. end = %08x\n", shl_desc->tend);
- GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
- GC_printf1("\tdata seg. end = %08x\n", shl_desc->dend);
- GC_printf1("\tref. count = %lu\n", shl_desc->ref_count);
+# ifdef DL_VERBOSE
+ GC_log_printf("---Shared library---\n");
+ GC_log_printf("\tfilename\t= \"%s\"\n", shl_desc->filename);
+ GC_log_printf("\tindex\t\t= %d\n", index);
+ GC_log_printf("\thandle\t\t= %08x\n",
+ (unsigned long) shl_desc->handle);
+ GC_log_printf("\ttext seg.start\t= %08x\n", shl_desc->tstart);
+ GC_log_printf("\ttext seg.end\t= %08x\n", shl_desc->tend);
+ GC_log_printf("\tdata seg.start\t= %08x\n", shl_desc->dstart);
+ GC_log_printf("\tdata seg.end\t= %08x\n", shl_desc->dend);
+ GC_log_printf("\tref.count\t= %lu\n", shl_desc->ref_count);
# endif
/* register shared library's data segment as a garbage collection root */
GC_add_roots_inner((char *) shl_desc->dstart,
- (char *) shl_desc->dend, TRUE);
+ (char *) shl_desc->dend, TRUE);
index++;
}
}
#endif /* HPUX */
-#ifdef RS6000
-#pragma alloca
-#include <sys/ldr.h>
-#include <sys/errno.h>
-void GC_register_dynamic_libraries()
-{
- int len;
- char *ldibuf;
- int ldibuflen;
- struct ld_info *ldi;
-
- ldibuf = alloca(ldibuflen = 8192);
-
- while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
- if (errno != ENOMEM) {
- ABORT("loadquery failed");
- }
- ldibuf = alloca(ldibuflen *= 2);
- }
-
- ldi = (struct ld_info *)ldibuf;
- while (ldi) {
- len = ldi->ldinfo_next;
- GC_add_roots_inner(
- ldi->ldinfo_dataorg,
- (ptr_t)(unsigned long)ldi->ldinfo_dataorg
- + ldi->ldinfo_datasize,
- TRUE);
- ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
- }
-}
-#endif /* RS6000 */
+#ifdef AIX
+# pragma alloca
+# include <sys/ldr.h>
+# include <sys/errno.h>
+ GC_INNER void GC_register_dynamic_libraries(void)
+ {
+ int len;
+ char *ldibuf;
+ int ldibuflen;
+ struct ld_info *ldi;
+
+ ldibuf = alloca(ldibuflen = 8192);
+
+ while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
+ if (errno != ENOMEM) {
+ ABORT("loadquery failed");
+ }
+ ldibuf = alloca(ldibuflen *= 2);
+ }
+
+ ldi = (struct ld_info *)ldibuf;
+ while (ldi) {
+ len = ldi->ldinfo_next;
+ GC_add_roots_inner(
+ ldi->ldinfo_dataorg,
+ (ptr_t)(unsigned long)ldi->ldinfo_dataorg
+ + ldi->ldinfo_datasize,
+ TRUE);
+ ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
+ }
+ }
+#endif /* AIX */
#ifdef DARWIN
-/* __private_extern__ hack required for pre-3.4 gcc versions. */
+/* __private_extern__ hack required for pre-3.4 gcc versions. */
#ifndef __private_extern__
# define __private_extern__ extern
# include <mach-o/dyld.h>
@@ -1089,69 +1188,174 @@ void GC_register_dynamic_libraries()
/*#define DARWIN_DEBUG*/
-const static struct {
- const char *seg;
- const char *sect;
+/* Writable sections generally available on Darwin. */
+STATIC const struct {
+ const char *seg;
+ const char *sect;
} GC_dyld_sections[] = {
- { SEG_DATA, SECT_DATA },
- { SEG_DATA, SECT_BSS },
- { SEG_DATA, SECT_COMMON }
+ { SEG_DATA, SECT_DATA },
+ /* Used by FSF GCC, but not by OS X system tools, so far. */
+ { SEG_DATA, "__static_data" },
+ { SEG_DATA, SECT_BSS },
+ { SEG_DATA, SECT_COMMON },
+ /* FSF GCC - zero-sized object sections for targets */
+ /*supporting section anchors. */
+ { SEG_DATA, "__zobj_data" },
+ { SEG_DATA, "__zobj_bss" }
};
-
-#ifdef DARWIN_DEBUG
-static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
- unsigned long i,c;
+
+/* Additional writable sections: */
+/* GCC on Darwin constructs aligned sections "on demand", where */
+/* the alignment size is embedded in the section name. */
+/* Furthermore, there are distinctions between sections */
+/* containing private vs. public symbols. It also constructs */
+/* sections specifically for zero-sized objects, when the */
+/* target supports section anchors. */
+STATIC const char * const GC_dyld_add_sect_fmts[] = {
+ "__bss%u",
+ "__pu_bss%u",
+ "__zo_bss%u",
+ "__zo_pu_bss%u"
+};
+
+/* Currently, mach-o will allow up to the max of 2^15 alignment */
+/* in an object file. */
+#ifndef L2_MAX_OFILE_ALIGNMENT
+# define L2_MAX_OFILE_ALIGNMENT 15
+#endif
+
+STATIC const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr)
+{
+ unsigned long i, c;
c = _dyld_image_count();
- for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
+ for (i = 0; i < c; i++)
+ if ((const struct GC_MACH_HEADER *)_dyld_get_image_header(i) == hdr)
return _dyld_get_image_name(i);
return NULL;
}
-#endif
-
-/* This should never be called by a thread holding the lock */
-static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
- unsigned long start,end,i;
- const struct section *sec;
- for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
- sec = getsectbynamefromheader(
- hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
- if(sec == NULL || sec->size == 0) continue;
- start = slide + sec->addr;
- end = start + sec->size;
-# ifdef DARWIN_DEBUG
- GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
- start,end,sec->size,GC_dyld_name_for_hdr(hdr));
-# endif
- GC_add_roots((char*)start,(char*)end);
- }
-# ifdef DARWIN_DEBUG
+
+/* This should never be called by a thread holding the lock. */
+STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr,
+ intptr_t slide)
+{
+ unsigned long start, end;
+ unsigned i, j;
+ const struct GC_MACH_SECTION *sec;
+ const char *name;
+ GC_has_static_roots_func callback = GC_has_static_roots;
+ char secnam[16];
+ const char *fmt;
+ DCL_LOCK_STATE;
+
+ if (GC_no_dls) return;
+# ifdef DARWIN_DEBUG
+ name = GC_dyld_name_for_hdr(hdr);
+# else
+ name = callback != 0 ? GC_dyld_name_for_hdr(hdr) : NULL;
+# endif
+ for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
+ sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
+ GC_dyld_sections[i].sect);
+ if (sec == NULL || sec->size < sizeof(word))
+ continue;
+ start = slide + sec->addr;
+ end = start + sec->size;
+ LOCK();
+ /* The user callback is called holding the lock. */
+ if (callback == 0 || callback(name, (void*)start, (size_t)sec->size)) {
+# ifdef DARWIN_DEBUG
+ GC_log_printf(
+ "Adding section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
+ GC_dyld_sections[i].sect, (void*)start, (void*)end,
+ (unsigned long)sec->size, name);
+# endif
+ GC_add_roots_inner((ptr_t)start, (ptr_t)end, FALSE);
+ }
+ UNLOCK();
+ }
+
+ /* Sections constructed on demand. */
+ for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
+ fmt = GC_dyld_add_sect_fmts[j];
+ /* Add our manufactured aligned BSS sections. */
+ for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
+ (void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
+ secnam[sizeof(secnam) - 1] = '\0';
+ sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
+ if (sec == NULL || sec->size == 0)
+ continue;
+ start = slide + sec->addr;
+ end = start + sec->size;
+# ifdef DARWIN_DEBUG
+ GC_log_printf("Adding on-demand section __DATA,%s at"
+ " %p-%p (%lu bytes) from image %s\n",
+ secnam, (void*)start, (void*)end,
+ (unsigned long)sec->size, name);
+# endif
+ GC_add_roots((char*)start, (char*)end);
+ }
+ }
+
+# ifdef DARWIN_DEBUG
GC_print_static_roots();
-# endif
+# endif
}
-/* This should never be called by a thread holding the lock */
-static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
- unsigned long start,end,i;
- const struct section *sec;
- for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
- sec = getsectbynamefromheader(
- hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
- if(sec == NULL || sec->size == 0) continue;
- start = slide + sec->addr;
- end = start + sec->size;
-# ifdef DARWIN_DEBUG
- GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
- start,end,sec->size,GC_dyld_name_for_hdr(hdr));
-# endif
- GC_remove_roots((char*)start,(char*)end);
+/* This should never be called by a thread holding the lock. */
+STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
+ intptr_t slide)
+{
+ unsigned long start, end;
+ unsigned i, j;
+ const struct GC_MACH_SECTION *sec;
+ char secnam[16];
+ const char *fmt;
+
+ for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
+ 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;
+# ifdef DARWIN_DEBUG
+ GC_log_printf(
+ "Removing section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
+ GC_dyld_sections[i].sect, (void*)start, (void*)end,
+ (unsigned long)sec->size, GC_dyld_name_for_hdr(hdr));
+# endif
+ GC_remove_roots((char*)start, (char*)end);
+ }
+
+ /* Remove our on-demand sections. */
+ for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
+ fmt = GC_dyld_add_sect_fmts[j];
+ for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
+ (void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
+ secnam[sizeof(secnam) - 1] = '\0';
+ sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
+ if (sec == NULL || sec->size == 0)
+ continue;
+ start = slide + sec->addr;
+ end = start + sec->size;
+# ifdef DARWIN_DEBUG
+ GC_log_printf("Removing on-demand section __DATA,%s at"
+ " %p-%p (%lu bytes) from image %s\n", secnam,
+ (void*)start, (void*)end, (unsigned long)sec->size,
+ GC_dyld_name_for_hdr(hdr));
+# endif
+ GC_remove_roots((char*)start, (char*)end);
}
-# ifdef DARWIN_DEBUG
+ }
+
+# ifdef DARWIN_DEBUG
GC_print_static_roots();
-# endif
+# endif
}
-void GC_register_dynamic_libraries() {
- /* Currently does nothing. The callbacks are setup by GC_init_dyld()
+GC_INNER void GC_register_dynamic_libraries(void)
+{
+ /* Currently does nothing. The callbacks are setup by GC_init_dyld()
The dyld library takes it from there. */
}
@@ -1160,49 +1364,61 @@ void GC_register_dynamic_libraries() {
Because of this we MUST setup callbacks BEFORE we ever stop the world.
This should be called BEFORE any thread in created and WITHOUT the
allocation lock held. */
-
-void GC_init_dyld() {
+
+GC_INNER void GC_init_dyld(void)
+{
static GC_bool initialized = FALSE;
- char *bind_fully_env = NULL;
-
- if(initialized) return;
-
-# ifdef DARWIN_DEBUG
- GC_printf0("Registering dyld callbacks...\n");
-# endif
-
+
+ if (initialized) return;
+
+# ifdef DARWIN_DEBUG
+ GC_log_printf("Registering dyld callbacks...\n");
+# endif
+
/* Apple's Documentation:
- When you call _dyld_register_func_for_add_image, the dynamic linker runtime
- calls the specified callback (func) once for each of the images that is
- currently loaded into the program. When a new image is added to the program,
- your callback is called again with the mach_header for the new image, and the
- virtual memory slide amount of the new image.
-
- This WILL properly register already linked libraries and libraries
- linked in the future
+ When you call _dyld_register_func_for_add_image, the dynamic linker
+ runtime calls the specified callback (func) once for each of the images
+ that is currently loaded into the program. When a new image is added to
+ the program, your callback is called again with the mach_header for the
+ new image, and the virtual memory slide amount of the new image.
+
+ This WILL properly register already linked libraries and libraries
+ linked in the future.
*/
-
- _dyld_register_func_for_add_image(GC_dyld_image_add);
- _dyld_register_func_for_remove_image(GC_dyld_image_remove);
- /* Set this early to avoid reentrancy issues. */
- initialized = TRUE;
+ _dyld_register_func_for_add_image(GC_dyld_image_add);
+ _dyld_register_func_for_remove_image(GC_dyld_image_remove);
+ /* Ignore 2 compiler warnings here: passing argument 1 of */
+ /* '_dyld_register_func_for_add/remove_image' from incompatible */
+ /* pointer type. */
- bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
-
- if (bind_fully_env == NULL) {
-# ifdef DARWIN_DEBUG
- GC_printf0("Forcing full bind of GC code...\n");
-# endif
-
- if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
- GC_abort("_dyld_bind_fully_image_containing_address failed");
- }
+ /* Set this early to avoid reentrancy issues. */
+ initialized = TRUE;
+# ifdef NO_DYLD_BIND_FULLY_IMAGE
+ /* FIXME: What should we do in this case? */
+# else
+ if (GC_no_dls) return; /* skip main data segment registration */
+
+ /* When the environment variable is set, the dynamic linker binds */
+ /* all undefined symbols the application needs at launch time. */
+ /* This includes function symbols that are normally bound lazily at */
+ /* the time of their first invocation. */
+ if (GETENV("DYLD_BIND_AT_LAUNCH") == 0) {
+ /* The environment variable is unset, so we should bind manually. */
+# ifdef DARWIN_DEBUG
+ GC_log_printf("Forcing full bind of GC code...\n");
+# endif
+ /* FIXME: '_dyld_bind_fully_image_containing_address' is deprecated. */
+ if (!_dyld_bind_fully_image_containing_address(
+ (unsigned long *)GC_malloc))
+ ABORT("_dyld_bind_fully_image_containing_address failed");
+ }
+# endif
}
#define HAVE_REGISTER_MAIN_STATIC_DATA
-GC_bool GC_register_main_static_data()
+GC_INNER GC_bool GC_register_main_static_data(void)
{
/* Already done through dyld callbacks */
return FALSE;
@@ -1210,61 +1426,50 @@ GC_bool GC_register_main_static_data()
#endif /* DARWIN */
-#else /* !DYNAMIC_LOADING */
+#elif defined(PCR)
-#ifdef PCR
+# include "il/PCR_IL.h"
+# include "th/PCR_ThCtl.h"
+# include "mm/PCR_MM.h"
-# include "il/PCR_IL.h"
-# include "th/PCR_ThCtl.h"
-# include "mm/PCR_MM.h"
-
-void GC_register_dynamic_libraries()
-{
- /* Add new static data areas of dynamically loaded modules. */
- {
- PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
- PCR_IL_LoadedSegment * q;
-
- /* Skip uncommited files */
- while (p != NIL && !(p -> lf_commitPoint)) {
- /* The loading of this file has not yet been committed */
- /* Hence its description could be inconsistent. */
- /* Furthermore, it hasn't yet been run. Hence its data */
- /* segments can't possibly reference heap allocated */
- /* objects. */
- p = p -> lf_prev;
- }
- for (; p != NIL; p = p -> lf_prev) {
- for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
- if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
- == PCR_IL_SegFlags_Traced_on) {
- GC_add_roots_inner
- ((char *)(q -> ls_addr),
- (char *)(q -> ls_addr) + q -> ls_bytes,
- TRUE);
- }
- }
- }
+ GC_INNER void GC_register_dynamic_libraries(void)
+ {
+ /* Add new static data areas of dynamically loaded modules. */
+ PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
+ PCR_IL_LoadedSegment * q;
+
+ /* Skip uncommitted files */
+ while (p != NIL && !(p -> lf_commitPoint)) {
+ /* The loading of this file has not yet been committed */
+ /* Hence its description could be inconsistent. */
+ /* Furthermore, it hasn't yet been run. Hence its data */
+ /* segments can't possibly reference heap allocated */
+ /* objects. */
+ p = p -> lf_prev;
+ }
+ for (; p != NIL; p = p -> lf_prev) {
+ for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
+ if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
+ == PCR_IL_SegFlags_Traced_on) {
+ GC_add_roots_inner((char *)(q -> ls_addr),
+ (char *)(q -> ls_addr) + q -> ls_bytes, TRUE);
}
-}
-
-
-#else /* !PCR */
-
-void GC_register_dynamic_libraries(){}
-
-int GC_no_dynamic_loading;
-
-#endif /* !PCR */
-
-#endif /* !DYNAMIC_LOADING */
+ }
+ }
+ }
+#endif /* PCR && !DYNAMIC_LOADING && !MSWIN32 */
-#ifndef HAVE_REGISTER_MAIN_STATIC_DATA
+#if !defined(HAVE_REGISTER_MAIN_STATIC_DATA) && defined(DYNAMIC_LOADING)
+ /* Do we need to separately register the main static data segment? */
+ GC_INNER GC_bool GC_register_main_static_data(void)
+ {
+ return TRUE;
+ }
+#endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
-/* Do we need to separately register the main static data segment? */
-GC_bool GC_register_main_static_data()
+/* Register a routine to filter dynamic library registration. */
+GC_API void GC_CALL GC_register_has_static_roots_callback(
+ GC_has_static_roots_func callback)
{
- return TRUE;
+ GC_has_static_roots = callback;
}
-#endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
-
diff --git a/boehm-gc/AmigaOS.c b/boehm-gc/extra/AmigaOS.c
index f4024a7978f..759b3dfbda6 100644
--- a/boehm-gc/AmigaOS.c
+++ b/boehm-gc/extra/AmigaOS.c
@@ -40,10 +40,10 @@
Find the base of the stack.
******************************************************************/
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base()
{
struct Process *proc = (struct Process*)SysBase->ThisTask;
-
+
/* Reference: Amiga Guru Book Pages: 42,567,574 */
if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS
&& proc->pr_CLI != NULL) {
@@ -99,7 +99,7 @@ ptr_t GC_get_stack_base()
struct CommandLineInterface *cli;
BPTR myseglist;
ULONG *data;
-
+
int num;
@@ -619,5 +619,3 @@ void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
}
#endif //GC_AMIGA_AM
-
-
diff --git a/boehm-gc/MacOS.c b/boehm-gc/extra/MacOS.c
index cc12cd15d98..6cb5edb7f06 100644
--- a/boehm-gc/MacOS.c
+++ b/boehm-gc/extra/MacOS.c
@@ -1,16 +1,16 @@
/*
MacOS.c
-
+
Some routines for the Macintosh OS port of the Hans-J. Boehm, Alan J. Demers
garbage collector.
-
+
<Revision History>
-
+
11/22/94 pcb StripAddress the temporary memory handle for 24-bit mode.
11/30/94 pcb Tracking all memory usage so we can deallocate it all at once.
02/10/96 pcb Added routine to perform a final collection when
unloading shared library.
-
+
by Patrick C. Beard.
*/
/* Boehm, February 15, 1996 2:55 pm PST */
@@ -79,7 +79,7 @@ Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
(**tempMemBlock).nextBlock = theTemporaryMemory;
theTemporaryMemory = tempMemBlock;
}
-
+
# if !defined(SHARED_LIBRARY_BUILD)
// install an exit routine to clean up the memory used at the end.
if (firstTime) {
@@ -87,17 +87,17 @@ Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
firstTime = false;
}
# endif
-
+
return tempPtr;
}
-extern word GC_fo_entries;
+extern word GC_fo_entries;
static void perform_final_collection()
{
unsigned i;
word last_fo_entries = 0;
-
+
/* adjust the stack bottom, because CFM calls us from another stack
location. */
GC_stackbottom = (ptr_t)&i;
@@ -128,10 +128,12 @@ void GC_MacFreeTemporaryMemory()
}
theTemporaryMemory = NULL;
-# if !defined(SILENT) && !defined(SHARED_LIBRARY_BUILD)
- fprintf(stdout, "[total memory used: %ld bytes.]\n",
+# if !defined(SHARED_LIBRARY_BUILD)
+ if (GC_print_stats) {
+ fprintf(stdout, "[total memory used: %ld bytes.]\n",
totalMemoryUsed);
- fprintf(stdout, "[total collections: %ld.]\n", GC_gc_no);
+ fprintf(stdout, "[total collections: %ld.]\n", GC_gc_no);
+ }
# endif
}
}
diff --git a/boehm-gc/extra/Mac_files/MacOS_config.h b/boehm-gc/extra/Mac_files/MacOS_config.h
new file mode 100644
index 00000000000..ec8f82c3bba
--- /dev/null
+++ b/boehm-gc/extra/Mac_files/MacOS_config.h
@@ -0,0 +1,28 @@
+/*
+ MacOS_config.h
+
+ Configuration flags for Macintosh development systems.
+
+ <Revision History>
+
+ 11/16/95 pcb Updated compilation flags to reflect latest 4.6 Makefile.
+
+ by Patrick C. Beard.
+ */
+/* Boehm, November 17, 1995 12:10 pm PST */
+
+#ifdef __MWERKS__
+
+// for CodeWarrior Pro with Metrowerks Standard Library (MSL).
+// #define MSL_USE_PRECOMPILED_HEADERS 0
+#include <ansi_prefix.mac.h>
+#endif /* __MWERKS__ */
+
+// these are defined again in gc_priv.h.
+#undef TRUE
+#undef FALSE
+
+#define ALL_INTERIOR_POINTERS // follows interior pointers.
+//#define DONT_ADD_BYTE_AT_END // no padding.
+//#define SMALL_CONFIG // whether to use a smaller heap.
+#define USE_TEMPORARY_MEMORY // use Macintosh temporary memory.
diff --git a/boehm-gc/Mac_files/dataend.c b/boehm-gc/extra/Mac_files/dataend.c
index a3e3fe8446f..09d47b39d84 100644
--- a/boehm-gc/Mac_files/dataend.c
+++ b/boehm-gc/extra/Mac_files/dataend.c
@@ -1,8 +1,8 @@
/*
dataend.c
-
+
A hack to get the extent of global data for the Macintosh.
-
+
by Patrick C. Beard.
*/
diff --git a/boehm-gc/Mac_files/datastart.c b/boehm-gc/extra/Mac_files/datastart.c
index a9e0dd59410..ec9f9af7ab5 100644
--- a/boehm-gc/Mac_files/datastart.c
+++ b/boehm-gc/extra/Mac_files/datastart.c
@@ -1,8 +1,8 @@
/*
datastart.c
-
+
A hack to get the extent of global data for the Macintosh.
-
+
by Patrick C. Beard.
*/
diff --git a/boehm-gc/extra/gc.c b/boehm-gc/extra/gc.c
new file mode 100644
index 00000000000..9c16d2066be
--- /dev/null
+++ b/boehm-gc/extra/gc.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* This file could be used for the following purposes: */
+/* - get the complete GC as a single link object file (module); */
+/* - enable more compiler optimizations. */
+
+/* Tip: to get the highest level of compiler optimizations, the typical */
+/* compiler options (GCC) to use are: */
+/* -O3 -fno-strict-aliasing -march=native -Wall -fprofile-generate/use */
+
+/* Warning: GCC for Linux (for C++ clients only): Use -fexceptions both */
+/* for GC and the client otherwise GC_thread_exit_proc() is not */
+/* guaranteed to be invoked (see the comments in pthread_start.c). */
+
+
+#define GC_INNER STATIC
+#define GC_EXTERN GC_INNER
+ /* STATIC is defined in gcconfig.h. */
+
+/* Small files go first... */
+#include "../backgraph.c"
+#include "../blacklst.c"
+#include "../checksums.c"
+#include "../gcj_mlc.c"
+#include "../headers.c"
+#include "../malloc.c"
+#include "../new_hblk.c"
+#include "../obj_map.c"
+#include "../ptr_chck.c"
+#include "../stubborn.c"
+
+#include "../allchblk.c"
+#include "../alloc.c"
+#include "../dbg_mlc.c"
+#include "../finalize.c"
+#include "../fnlz_mlc.c"
+#include "../mallocx.c"
+#include "../mark.c"
+#include "../mark_rts.c"
+#include "../reclaim.c"
+#include "../typd_mlc.c"
+
+#include "../misc.c"
+#include "../os_dep.c"
+#include "../thread_local_alloc.c"
+
+/* Most platform-specific files go here... */
+#include "../darwin_stop_world.c"
+#include "../dyn_load.c"
+#include "../gc_dlopen.c"
+#include "../mach_dep.c"
+#include "../pcr_interface.c"
+#include "../pthread_stop_world.c"
+#include "../pthread_support.c"
+#include "../specific.c"
+#include "../win32_threads.c"
+
+#include "../pthread_start.c"
+
+/* Restore pthread calls redirection (if altered in */
+/* pthread_stop_world.c, pthread_support.c or win32_threads.c). */
+/* This is only useful if directly included from application */
+/* (instead of linking gc). */
+#ifndef GC_NO_THREAD_REDIRECTS
+# include "gc_pthread_redirects.h"
+#endif
+
+/* real_malloc.c, extra/MacOS.c, extra/msvc_dbg.c are not included. */
diff --git a/boehm-gc/extra/msvc_dbg.c b/boehm-gc/extra/msvc_dbg.c
new file mode 100644
index 00000000000..7884ecdd9a8
--- /dev/null
+++ b/boehm-gc/extra/msvc_dbg.c
@@ -0,0 +1,381 @@
+/*
+ Copyright (c) 2004 Andrei Polushin
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#if !defined(_M_AMD64) && defined(_MSC_VER)
+
+/* X86_64 is currently missing some meachine-dependent code below. */
+
+#include "private/msvc_dbg.h"
+
+#include "gc.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#pragma pack(push, 8)
+#include <imagehlp.h>
+#pragma pack(pop)
+
+#pragma comment(lib, "dbghelp.lib")
+#pragma optimize("gy", off)
+
+typedef GC_word word;
+#define GC_ULONG_PTR word
+
+#ifdef _WIN64
+ typedef GC_ULONG_PTR ULONG_ADDR;
+#else
+ typedef ULONG ULONG_ADDR;
+#endif
+
+static HANDLE GetSymHandle()
+{
+ static HANDLE symHandle = NULL;
+ if (!symHandle) {
+ BOOL bRet = SymInitialize(symHandle = GetCurrentProcess(), NULL, FALSE);
+ if (bRet) {
+ DWORD dwOptions = SymGetOptions();
+ dwOptions &= ~SYMOPT_UNDNAME;
+ dwOptions |= SYMOPT_LOAD_LINES;
+ SymSetOptions(dwOptions);
+ }
+ }
+ return symHandle;
+}
+
+static void* CALLBACK FunctionTableAccess(HANDLE hProcess,
+ ULONG_ADDR dwAddrBase)
+{
+ return SymFunctionTableAccess(hProcess, dwAddrBase);
+}
+
+static ULONG_ADDR CALLBACK GetModuleBase(HANDLE hProcess, ULONG_ADDR dwAddress)
+{
+ MEMORY_BASIC_INFORMATION memoryInfo;
+ ULONG_ADDR dwAddrBase = SymGetModuleBase(hProcess, dwAddress);
+ if (dwAddrBase) {
+ return dwAddrBase;
+ }
+ if (VirtualQueryEx(hProcess, (void*)(GC_ULONG_PTR)dwAddress, &memoryInfo,
+ sizeof(memoryInfo))) {
+ char filePath[_MAX_PATH];
+ char curDir[_MAX_PATH];
+ char exePath[_MAX_PATH];
+ DWORD size = GetModuleFileNameA((HINSTANCE)memoryInfo.AllocationBase,
+ filePath, sizeof(filePath));
+
+ /* Save and restore current directory around SymLoadModule, see KB */
+ /* article Q189780. */
+ GetCurrentDirectoryA(sizeof(curDir), curDir);
+ GetModuleFileNameA(NULL, exePath, sizeof(exePath));
+#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);
+#endif
+ SymLoadModule(hProcess, NULL, size ? filePath : NULL, NULL,
+ (ULONG_ADDR)(GC_ULONG_PTR)memoryInfo.AllocationBase, 0);
+ SetCurrentDirectoryA(curDir);
+ }
+ return (ULONG_ADDR)(GC_ULONG_PTR)memoryInfo.AllocationBase;
+}
+
+static ULONG_ADDR CheckAddress(void* address)
+{
+ ULONG_ADDR dwAddress = (ULONG_ADDR)(GC_ULONG_PTR)address;
+ GetModuleBase(GetSymHandle(), dwAddress);
+ return dwAddress;
+}
+
+size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames)
+{
+ HANDLE hProcess = GetSymHandle();
+ HANDLE hThread = GetCurrentThread();
+ CONTEXT context;
+ context.ContextFlags = CONTEXT_FULL;
+ if (!GetThreadContext(hThread, &context)) {
+ return 0;
+ }
+ /* GetThreadContext might return invalid context for the current thread. */
+#if defined(_M_IX86)
+ __asm mov context.Ebp, ebp
+#endif
+ return GetStackFramesFromContext(hProcess, hThread, &context, skip + 1,
+ frames, maxFrames);
+}
+
+size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread,
+ CONTEXT* context, size_t skip,
+ void* frames[], size_t maxFrames)
+{
+ size_t frameIndex;
+ DWORD machineType;
+ STACKFRAME stackFrame = { 0 };
+ stackFrame.AddrPC.Mode = AddrModeFlat;
+#if defined(_M_IX86)
+ machineType = IMAGE_FILE_MACHINE_I386;
+ stackFrame.AddrPC.Offset = context->Eip;
+ stackFrame.AddrStack.Mode = AddrModeFlat;
+ stackFrame.AddrStack.Offset = context->Esp;
+ stackFrame.AddrFrame.Mode = AddrModeFlat;
+ stackFrame.AddrFrame.Offset = context->Ebp;
+#elif defined(_M_MRX000)
+ machineType = IMAGE_FILE_MACHINE_R4000;
+ stackFrame.AddrPC.Offset = context->Fir;
+#elif defined(_M_ALPHA)
+ machineType = IMAGE_FILE_MACHINE_ALPHA;
+ stackFrame.AddrPC.Offset = (unsigned long)context->Fir;
+#elif defined(_M_PPC)
+ machineType = IMAGE_FILE_MACHINE_POWERPC;
+ stackFrame.AddrPC.Offset = context->Iar;
+#elif defined(_M_IA64)
+ machineType = IMAGE_FILE_MACHINE_IA64;
+ stackFrame.AddrPC.Offset = context->StIIP;
+#elif defined(_M_ALPHA64)
+ machineType = IMAGE_FILE_MACHINE_ALPHA64;
+ stackFrame.AddrPC.Offset = context->Fir;
+#else
+#error Unknown CPU
+#endif
+ for (frameIndex = 0; frameIndex < maxFrames; ) {
+ BOOL bRet = StackWalk(machineType, hProcess, hThread, &stackFrame,
+ &context, NULL, FunctionTableAccess, GetModuleBase, NULL);
+ if (!bRet) {
+ break;
+ }
+ if (skip) {
+ skip--;
+ } else {
+ frames[frameIndex++] = (void*)(GC_ULONG_PTR)stackFrame.AddrPC.Offset;
+ }
+ }
+ return frameIndex;
+}
+
+size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size)
+{
+ if (size) *moduleName = 0;
+ {
+ const char* sourceName;
+ IMAGEHLP_MODULE moduleInfo = { sizeof (moduleInfo) };
+ if (!SymGetModuleInfo(GetSymHandle(), CheckAddress(address),
+ &moduleInfo)) {
+ return 0;
+ }
+ sourceName = strrchr(moduleInfo.ImageName, '\\');
+ if (sourceName) {
+ sourceName++;
+ } else {
+ sourceName = moduleInfo.ImageName;
+ }
+ if (size) {
+ strncpy(moduleName, sourceName, size)[size - 1] = 0;
+ }
+ return strlen(sourceName);
+ }
+}
+
+size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size)
+{
+ void* address = NULL;
+ GetStackFrames(skip + 1, &address, 1);
+ if (address) {
+ return GetModuleNameFromAddress(address, moduleName, size);
+ }
+ return 0;
+}
+
+size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size,
+ size_t* offsetBytes)
+{
+ if (size) *symbolName = 0;
+ if (offsetBytes) *offsetBytes = 0;
+ __try {
+ ULONG_ADDR dwOffset = 0;
+ union {
+ IMAGEHLP_SYMBOL sym;
+ char symNameBuffer[sizeof(IMAGEHLP_SYMBOL) + MAX_SYM_NAME];
+ } u;
+ u.sym.SizeOfStruct = sizeof(u.sym);
+ u.sym.MaxNameLength = sizeof(u.symNameBuffer) - sizeof(u.sym);
+
+ if (!SymGetSymFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset,
+ &u.sym)) {
+ return 0;
+ } else {
+ const char* sourceName = u.sym.Name;
+ char undName[1024];
+ if (UnDecorateSymbolName(u.sym.Name, undName, sizeof(undName),
+ UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS)) {
+ sourceName = undName;
+ } else if (SymUnDName(&u.sym, undName, sizeof(undName))) {
+ sourceName = undName;
+ }
+ if (offsetBytes) {
+ *offsetBytes = dwOffset;
+ }
+ if (size) {
+ strncpy(symbolName, sourceName, size)[size - 1] = 0;
+ }
+ return strlen(sourceName);
+ }
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ SetLastError(GetExceptionCode());
+ }
+ return 0;
+}
+
+size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size,
+ size_t* offsetBytes)
+{
+ void* address = NULL;
+ GetStackFrames(skip + 1, &address, 1);
+ if (address) {
+ return GetSymbolNameFromAddress(address, symbolName, size, offsetBytes);
+ }
+ return 0;
+}
+
+size_t GetFileLineFromAddress(void* address, char* fileName, size_t size,
+ size_t* lineNumber, size_t* offsetBytes)
+{
+ if (size) *fileName = 0;
+ if (lineNumber) *lineNumber = 0;
+ if (offsetBytes) *offsetBytes = 0;
+ {
+ char* sourceName;
+ IMAGEHLP_LINE line = { sizeof (line) };
+ GC_ULONG_PTR dwOffset = 0;
+ if (!SymGetLineFromAddr(GetSymHandle(), CheckAddress(address), &dwOffset,
+ &line)) {
+ return 0;
+ }
+ if (lineNumber) {
+ *lineNumber = line.LineNumber;
+ }
+ if (offsetBytes) {
+ *offsetBytes = dwOffset;
+ }
+ sourceName = line.FileName;
+ /* TODO: resolve relative filenames, found in 'source directories' */
+ /* registered with MSVC IDE. */
+ if (size) {
+ strncpy(fileName, sourceName, size)[size - 1] = 0;
+ }
+ return strlen(sourceName);
+ }
+}
+
+size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size,
+ size_t* lineNumber, size_t* offsetBytes)
+{
+ void* address = NULL;
+ GetStackFrames(skip + 1, &address, 1);
+ if (address) {
+ return GetFileLineFromAddress(address, fileName, size, lineNumber,
+ offsetBytes);
+ }
+ return 0;
+}
+
+size_t GetDescriptionFromAddress(void* address, const char* format,
+ char* buffer, size_t size)
+{
+ char*const begin = buffer;
+ char*const end = buffer + size;
+ size_t line_number = 0;
+ char str[128];
+
+ if (size) {
+ *buffer = 0;
+ }
+ buffer += GetFileLineFromAddress(address, buffer, size, &line_number, NULL);
+ size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
+
+ if (line_number) {
+ wsprintf(str, "(%d) : ", line_number);
+ if (size) {
+ strncpy(buffer, str, size)[size - 1] = 0;
+ }
+ buffer += strlen(str);
+ size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
+ }
+
+ if (size) {
+ strncpy(buffer, "at ", size)[size - 1] = 0;
+ }
+ buffer += strlen("at ");
+ size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
+
+ buffer += GetSymbolNameFromAddress(address, buffer, size, NULL);
+ size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
+
+ if (size) {
+ strncpy(buffer, " in ", size)[size - 1] = 0;
+ }
+ buffer += strlen(" in ");
+ size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
+
+ buffer += GetModuleNameFromAddress(address, buffer, size);
+ size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
+
+ return buffer - begin;
+}
+
+size_t GetDescriptionFromStack(void* const frames[], size_t count,
+ const char* format, char* description[],
+ size_t size)
+{
+ char*const begin = (char*)description;
+ char*const end = begin + size;
+ char* buffer = begin + (count + 1) * sizeof(char*);
+ size_t i;
+ for (i = 0; i < count; ++i) {
+ if (description) description[i] = buffer;
+ size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
+ buffer += 1 + GetDescriptionFromAddress(frames[i], NULL, buffer, size);
+ }
+ if (description) description[count] = NULL;
+ return buffer - begin;
+}
+
+/* Compatibility with <execinfo.h> */
+
+int backtrace(void* addresses[], int count)
+{
+ return GetStackFrames(1, addresses, count);
+}
+
+char** backtrace_symbols(void*const* addresses, int count)
+{
+ size_t size = GetDescriptionFromStack(addresses, count, NULL, NULL, 0);
+ char** symbols = (char**)malloc(size);
+ GetDescriptionFromStack(addresses, count, NULL, symbols, size);
+ return symbols;
+}
+
+#endif /* !_M_AMD64 */
diff --git a/boehm-gc/extra/symbian.cpp b/boehm-gc/extra/symbian.cpp
new file mode 100644
index 00000000000..29a960d83d8
--- /dev/null
+++ b/boehm-gc/extra/symbian.cpp
@@ -0,0 +1,55 @@
+
+#include <e32cmn.h>
+#include <e32std.h>
+#include <f32file.h>
+#include <aknutils.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int GC_get_main_symbian_stack_base()
+ {
+ TThreadStackInfo aInfo;
+ TInt err = RThread().StackInfo(aInfo);
+ if ( !err )
+ {
+ return aInfo.iBase;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+char* GC_get_private_path_and_zero_file()
+ {
+ // always on c: drive
+ RFs fs;
+ fs.Connect();
+ fs.CreatePrivatePath( EDriveC );
+ TFileName path;
+ fs.PrivatePath( path );
+ fs.Close();
+ _LIT( KCDrive, "c:" );
+ path.Insert( 0, KCDrive );
+
+
+ //convert to char*, assume ascii
+ TBuf8<KMaxFileName> path8;
+ path8.Copy( path );
+ _LIT8( KZero8, "zero" );
+ path8.Append( KZero8 );
+
+ size_t size = path8.Length() + 1;
+ char* copyChar = (char*) malloc( size );
+ memcpy( copyChar, path8.PtrZ(), size );
+
+ return copyChar; // ownership passed
+ }
+
+#ifdef __cplusplus
+ }
+#endif
diff --git a/boehm-gc/extra/symbian/global_end.cpp b/boehm-gc/extra/symbian/global_end.cpp
new file mode 100644
index 00000000000..3e2e6d5974a
--- /dev/null
+++ b/boehm-gc/extra/symbian/global_end.cpp
@@ -0,0 +1,16 @@
+// Symbian-specific file.
+
+// INCLUDE FILES
+#include "private/gcconfig.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int winscw_data_end;
+
+#ifdef __cplusplus
+ }
+#endif
+
+// End Of File
diff --git a/boehm-gc/extra/symbian/global_start.cpp b/boehm-gc/extra/symbian/global_start.cpp
new file mode 100644
index 00000000000..c6d67c3c8a3
--- /dev/null
+++ b/boehm-gc/extra/symbian/global_start.cpp
@@ -0,0 +1,16 @@
+// Symbian-specific file.
+
+// INCLUDE FILES
+#include "private/gcconfig.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int winscw_data_start;
+
+#ifdef __cplusplus
+ }
+#endif
+
+// End Of File
diff --git a/boehm-gc/extra/symbian/init_global_static_roots.cpp b/boehm-gc/extra/symbian/init_global_static_roots.cpp
new file mode 100644
index 00000000000..092d34151df
--- /dev/null
+++ b/boehm-gc/extra/symbian/init_global_static_roots.cpp
@@ -0,0 +1,33 @@
+// Symbian-specific file.
+
+// INCLUDE FILES
+#include <e32def.h>
+
+#include "private/gcconfig.h"
+#include "gc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void GC_init_global_static_roots()
+{
+ ptr_t dataStart = NULL;
+ ptr_t dataEnd = NULL;
+# if defined (__WINS__)
+ extern int winscw_data_start, winscw_data_end;
+ dataStart = ((ptr_t)&winscw_data_start);
+ dataEnd = ((ptr_t)&winscw_data_end);
+# else
+ extern int Image$$RW$$Limit[], Image$$RW$$Base[];
+ dataStart = ((ptr_t)Image$$RW$$Base);
+ dataEnd = ((ptr_t)Image$$RW$$Limit);
+# endif
+
+ GC_add_roots(dataStart, dataEnd);
+
+}
+
+#ifdef __cplusplus
+ }
+#endif
diff --git a/boehm-gc/finalize.c b/boehm-gc/finalize.c
index e103228c2af..32c9394e58d 100644
--- a/boehm-gc/finalize.c
+++ b/boehm-gc/finalize.c
@@ -2,6 +2,7 @@
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
+ * Copyright (C) 2007 Free Software Foundation, Inc
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -12,120 +13,108 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, February 1, 1996 1:19 pm PST */
-# define I_HIDE_POINTERS
-# include "private/gc_pmark.h"
-
-# ifdef FINALIZE_ON_DEMAND
- int GC_finalize_on_demand = 1;
-# else
- int GC_finalize_on_demand = 0;
-# endif
-
-# ifdef JAVA_FINALIZATION
- int GC_java_finalization = 1;
-# else
- int GC_java_finalization = 0;
-# endif
-
-/* Type of mark procedure used for marking from finalizable object. */
-/* This procedure normally does not mark the object, only its */
-/* descendents. */
-typedef void finalization_mark_proc(/* ptr_t finalizable_obj_ptr */);
-
-# define HASH3(addr,size,log_size) \
- ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \
- & ((size) - 1))
-#define HASH2(addr,log_size) HASH3(addr, 1 << log_size, log_size)
+
+#include "private/gc_pmark.h"
+
+#ifndef GC_NO_FINALIZATION
+
+/* Type of mark procedure used for marking from finalizable object. */
+/* This procedure normally does not mark the object, only its */
+/* descendents. */
+typedef void (* finalization_mark_proc)(ptr_t /* finalizable_obj_ptr */);
+
+#define HASH3(addr,size,log_size) \
+ ((((word)(addr) >> 3) ^ ((word)(addr) >> (3 + (log_size)))) \
+ & ((size) - 1))
+#define HASH2(addr,log_size) HASH3(addr, 1 << (log_size), log_size)
struct hash_chain_entry {
word hidden_key;
struct hash_chain_entry * next;
};
-unsigned GC_finalization_failures = 0;
- /* Number of finalization requests that failed for lack of memory. */
-
-static struct disappearing_link {
+STATIC struct disappearing_link {
struct hash_chain_entry prolog;
# define dl_hidden_link prolog.hidden_key
- /* Field to be cleared. */
+ /* Field to be cleared. */
# define dl_next(x) (struct disappearing_link *)((x) -> prolog.next)
-# define dl_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
+# define dl_set_next(x,y) ((x)->prolog.next = (struct hash_chain_entry *)(y))
- word dl_hidden_obj; /* Pointer to object base */
-} **dl_head = 0;
+ word dl_hidden_obj; /* Pointer to object base */
+} **GC_dl_head = 0;
static signed_word log_dl_table_size = -1;
- /* Binary log of */
- /* current size of array pointed to by dl_head. */
- /* -1 ==> size is 0. */
+ /* Binary log of current size of array pointed */
+ /* to by GC_dl_head. If -1 then size is 0. */
-word GC_dl_entries = 0; /* Number of entries currently in disappearing */
- /* link table. */
+STATIC word GC_dl_entries = 0;
+ /* Number of entries currently in disappearing */
+ /* link table. */
-static struct finalizable_object {
+STATIC struct finalizable_object {
struct hash_chain_entry prolog;
# define fo_hidden_base prolog.hidden_key
- /* Pointer to object base. */
- /* No longer hidden once object */
- /* is on finalize_now queue. */
+ /* Pointer to object base. */
+ /* No longer hidden once object */
+ /* is on finalize_now queue. */
# define fo_next(x) (struct finalizable_object *)((x) -> prolog.next)
-# define fo_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
- GC_finalization_proc fo_fn; /* Finalizer. */
+# define fo_set_next(x,y) ((x)->prolog.next = (struct hash_chain_entry *)(y))
+ GC_finalization_proc fo_fn; /* Finalizer. */
ptr_t fo_client_data;
- word fo_object_size; /* In bytes. */
- finalization_mark_proc * fo_mark_proc; /* Mark-through procedure */
-} **fo_head = 0;
+ word fo_object_size; /* In bytes. */
+ finalization_mark_proc fo_mark_proc; /* Mark-through procedure */
+} **GC_fo_head = 0;
-struct finalizable_object * GC_finalize_now = 0;
- /* LIst of objects that should be finalized now. */
+STATIC struct finalizable_object * GC_finalize_now = 0;
+ /* List of objects that should be finalized now. */
static signed_word log_fo_table_size = -1;
-word GC_fo_entries = 0;
-
-void GC_push_finalizer_structures GC_PROTO((void))
+GC_INNER void GC_push_finalizer_structures(void)
{
- GC_push_all((ptr_t)(&dl_head), (ptr_t)(&dl_head) + sizeof(word));
- GC_push_all((ptr_t)(&fo_head), (ptr_t)(&fo_head) + sizeof(word));
+ GC_ASSERT((word)&GC_dl_head % sizeof(word) == 0);
+ GC_ASSERT((word)&GC_fo_head % sizeof(word) == 0);
+ GC_ASSERT((word)&GC_finalize_now % sizeof(word) == 0);
+
+ GC_push_all((ptr_t)(&GC_dl_head), (ptr_t)(&GC_dl_head) + sizeof(word));
+ GC_push_all((ptr_t)(&GC_fo_head), (ptr_t)(&GC_fo_head) + sizeof(word));
GC_push_all((ptr_t)(&GC_finalize_now),
- (ptr_t)(&GC_finalize_now) + sizeof(word));
+ (ptr_t)(&GC_finalize_now) + sizeof(word));
}
-/* Double the size of a hash table. *size_ptr is the log of its current */
-/* size. May be a noop. */
-/* *table is a pointer to an array of hash headers. If we succeed, we */
-/* update both *table and *log_size_ptr. */
-/* Lock is held. Signals are disabled. */
-void GC_grow_table(table, log_size_ptr)
-struct hash_chain_entry ***table;
-signed_word * log_size_ptr;
+/* Double the size of a hash table. *size_ptr is the log of its current */
+/* size. May be a no-op. */
+/* *table is a pointer to an array of hash headers. If we succeed, we */
+/* update both *table and *log_size_ptr. */
+/* Lock is held. */
+STATIC void GC_grow_table(struct hash_chain_entry ***table,
+ signed_word *log_size_ptr)
{
register word i;
register struct hash_chain_entry *p;
- int log_old_size = *log_size_ptr;
- register int log_new_size = log_old_size + 1;
+ signed_word log_old_size = *log_size_ptr;
+ signed_word log_new_size = log_old_size + 1;
word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
- register word new_size = 1 << log_new_size;
+ word new_size = (word)1 << log_new_size;
+ /* FIXME: Power of 2 size often gets rounded up to one more page. */
struct hash_chain_entry **new_table = (struct hash_chain_entry **)
- GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
- (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
-
+ GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
+ (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
+
if (new_table == 0) {
- if (table == 0) {
- ABORT("Insufficient space for initial table allocation");
- } else {
- return;
- }
+ if (*table == 0) {
+ ABORT("Insufficient space for initial table allocation");
+ } else {
+ return;
+ }
}
for (i = 0; i < old_size; i++) {
p = (*table)[i];
while (p != 0) {
- register ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
- register struct hash_chain_entry *next = p -> next;
- register int new_hash = HASH3(real_key, new_size, log_new_size);
-
+ ptr_t real_key = GC_REVEAL_POINTER(p -> hidden_key);
+ struct hash_chain_entry *next = p -> next;
+ size_t new_hash = HASH3(real_key, new_size, log_new_size);
+
p -> next = new_table[new_hash];
new_table[new_hash] = p;
p = next;
@@ -135,385 +124,394 @@ signed_word * log_size_ptr;
*table = new_table;
}
-# if defined(__STDC__) || defined(__cplusplus)
- int GC_register_disappearing_link(GC_PTR * link)
-# else
- int GC_register_disappearing_link(link)
- GC_PTR * link;
-# endif
+GC_API int GC_CALL GC_register_disappearing_link(void * * link)
{
ptr_t base;
-
- base = (ptr_t)GC_base((GC_PTR)link);
+
+ base = (ptr_t)GC_base(link);
if (base == 0)
- ABORT("Bad arg to GC_register_disappearing_link");
+ ABORT("Bad arg to GC_register_disappearing_link");
return(GC_general_register_disappearing_link(link, base));
}
-# if defined(__STDC__) || defined(__cplusplus)
- int GC_general_register_disappearing_link(GC_PTR * link,
- GC_PTR obj)
-# else
- int GC_general_register_disappearing_link(link, obj)
- GC_PTR * link;
- GC_PTR obj;
-# endif
-
+GC_API int GC_CALL GC_general_register_disappearing_link(void * * link,
+ const void * obj)
{
struct disappearing_link *curr_dl;
- int index;
+ size_t index;
struct disappearing_link * new_dl;
DCL_LOCK_STATE;
-
- if ((word)link & (ALIGNMENT-1))
- ABORT("Bad arg to GC_general_register_disappearing_link");
-# ifdef THREADS
- DISABLE_SIGNALS();
- LOCK();
-# endif
+
+ if (((word)link & (ALIGNMENT-1)) || link == NULL)
+ ABORT("Bad arg to GC_general_register_disappearing_link");
+ LOCK();
+ GC_ASSERT(obj != NULL && GC_base_C(obj) == obj);
if (log_dl_table_size == -1
|| GC_dl_entries > ((word)1 << log_dl_table_size)) {
-# ifndef THREADS
- DISABLE_SIGNALS();
-# endif
- GC_grow_table((struct hash_chain_entry ***)(&dl_head),
- &log_dl_table_size);
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Grew dl table to %lu entries\n",
- (unsigned long)(1 << log_dl_table_size));
- }
-# endif
-# ifndef THREADS
- ENABLE_SIGNALS();
-# endif
+ GC_grow_table((struct hash_chain_entry ***)&GC_dl_head,
+ &log_dl_table_size);
+ GC_COND_LOG_PRINTF("Grew dl table to %u entries\n",
+ 1 << (unsigned)log_dl_table_size);
}
index = HASH2(link, log_dl_table_size);
- curr_dl = dl_head[index];
- for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
- if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
- curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
-# ifdef THREADS
- UNLOCK();
- ENABLE_SIGNALS();
-# endif
- return(1);
+ for (curr_dl = GC_dl_head[index]; curr_dl != 0;
+ curr_dl = dl_next(curr_dl)) {
+ if (curr_dl -> dl_hidden_link == GC_HIDE_POINTER(link)) {
+ curr_dl -> dl_hidden_obj = GC_HIDE_POINTER(obj);
+ UNLOCK();
+ return GC_DUPLICATE;
}
}
new_dl = (struct disappearing_link *)
- GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL);
+ GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL);
if (0 == new_dl) {
-# ifdef THREADS
- UNLOCK();
- ENABLE_SIGNALS();
-# endif
+ GC_oom_func oom_fn = GC_oom_fn;
+ UNLOCK();
new_dl = (struct disappearing_link *)
- GC_oom_fn(sizeof(struct disappearing_link));
+ (*oom_fn)(sizeof(struct disappearing_link));
if (0 == new_dl) {
- GC_finalization_failures++;
- return(0);
+ return GC_NO_MEMORY;
}
/* It's not likely we'll make it here, but ... */
-# ifdef THREADS
- DISABLE_SIGNALS();
- LOCK();
-# endif
+ LOCK();
+ /* Recalculate index since the table may grow. */
+ index = HASH2(link, log_dl_table_size);
+ /* Check again that our disappearing link not in the table. */
+ for (curr_dl = GC_dl_head[index]; curr_dl != 0;
+ curr_dl = dl_next(curr_dl)) {
+ if (curr_dl -> dl_hidden_link == GC_HIDE_POINTER(link)) {
+ curr_dl -> dl_hidden_obj = GC_HIDE_POINTER(obj);
+ UNLOCK();
+# ifndef DBG_HDRS_ALL
+ /* Free unused new_dl returned by GC_oom_fn() */
+ GC_free((void *)new_dl);
+# endif
+ return GC_DUPLICATE;
+ }
+ }
}
- new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
- new_dl -> dl_hidden_link = HIDE_POINTER(link);
- dl_set_next(new_dl, dl_head[index]);
- dl_head[index] = new_dl;
+ new_dl -> dl_hidden_obj = GC_HIDE_POINTER(obj);
+ new_dl -> dl_hidden_link = GC_HIDE_POINTER(link);
+ dl_set_next(new_dl, GC_dl_head[index]);
+ GC_dl_head[index] = new_dl;
GC_dl_entries++;
-# ifdef THREADS
- UNLOCK();
- ENABLE_SIGNALS();
-# endif
- return(0);
+ UNLOCK();
+ return GC_SUCCESS;
}
-# if defined(__STDC__) || defined(__cplusplus)
- int GC_unregister_disappearing_link(GC_PTR * link)
-# else
- int GC_unregister_disappearing_link(link)
- GC_PTR * link;
-# endif
+GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
{
struct disappearing_link *curr_dl, *prev_dl;
- int index;
+ size_t index;
DCL_LOCK_STATE;
-
- DISABLE_SIGNALS();
+
+ if (((word)link & (ALIGNMENT-1)) != 0) return(0); /* Nothing to do. */
+
LOCK();
index = HASH2(link, log_dl_table_size);
- if (((unsigned long)link & (ALIGNMENT-1))) goto out;
- prev_dl = 0; curr_dl = dl_head[index];
- while (curr_dl != 0) {
- if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
+ prev_dl = 0;
+ for (curr_dl = GC_dl_head[index]; curr_dl != 0;
+ curr_dl = dl_next(curr_dl)) {
+ if (curr_dl -> dl_hidden_link == GC_HIDE_POINTER(link)) {
if (prev_dl == 0) {
- dl_head[index] = dl_next(curr_dl);
+ GC_dl_head[index] = dl_next(curr_dl);
} else {
dl_set_next(prev_dl, dl_next(curr_dl));
}
GC_dl_entries--;
UNLOCK();
- ENABLE_SIGNALS();
-# ifdef DBG_HDRS_ALL
- dl_set_next(curr_dl, 0);
-# else
- GC_free((GC_PTR)curr_dl);
-# endif
+# ifdef DBG_HDRS_ALL
+ dl_set_next(curr_dl, 0);
+# else
+ GC_free((void *)curr_dl);
+# endif
return(1);
}
prev_dl = curr_dl;
- curr_dl = dl_next(curr_dl);
}
-out:
UNLOCK();
- ENABLE_SIGNALS();
return(0);
}
-/* Possible finalization_marker procedures. Note that mark stack */
-/* overflow is handled by the caller, and is not a disaster. */
-GC_API void GC_normal_finalize_mark_proc(p)
-ptr_t p;
+#ifndef GC_MOVE_DISAPPEARING_LINK_NOT_NEEDED
+ GC_API int GC_CALL GC_move_disappearing_link(void **link, void **new_link)
+ {
+ struct disappearing_link *curr_dl, *prev_dl, *new_dl;
+ size_t curr_index, new_index;
+ word curr_hidden_link;
+ word new_hidden_link;
+ DCL_LOCK_STATE;
+
+ if (((word)new_link & (ALIGNMENT-1)) != 0 || new_link == NULL)
+ ABORT("Bad new_link arg to GC_move_disappearing_link");
+ if (((word)link & (ALIGNMENT-1)) != 0)
+ return GC_NOT_FOUND; /* Nothing to do. */
+
+ LOCK();
+ /* Find current link. */
+ curr_index = HASH2(link, log_dl_table_size);
+ curr_hidden_link = GC_HIDE_POINTER(link);
+ prev_dl = 0;
+ for (curr_dl = GC_dl_head[curr_index]; curr_dl != 0;
+ curr_dl = dl_next(curr_dl)) {
+ if (curr_dl -> dl_hidden_link == curr_hidden_link)
+ break;
+ prev_dl = curr_dl;
+ }
+
+ if (curr_dl == 0) {
+ UNLOCK();
+ return GC_NOT_FOUND;
+ }
+
+ if (link == new_link) {
+ UNLOCK();
+ return GC_SUCCESS; /* Nothing to do. */
+ }
+
+ /* link found; now check new_link not present. */
+ new_index = HASH2(new_link, log_dl_table_size);
+ new_hidden_link = GC_HIDE_POINTER(new_link);
+ for (new_dl = GC_dl_head[new_index]; new_dl != 0;
+ new_dl = dl_next(new_dl)) {
+ if (new_dl -> dl_hidden_link == new_hidden_link) {
+ /* Target already registered; bail. */
+ UNLOCK();
+ return GC_DUPLICATE;
+ }
+ }
+
+ /* Remove from old, add to new, update link. */
+ if (prev_dl == 0) {
+ GC_dl_head[curr_index] = dl_next(curr_dl);
+ } else {
+ dl_set_next(prev_dl, dl_next(curr_dl));
+ }
+ curr_dl -> dl_hidden_link = new_hidden_link;
+ dl_set_next(curr_dl, GC_dl_head[new_index]);
+ GC_dl_head[new_index] = curr_dl;
+ UNLOCK();
+ return GC_SUCCESS;
+ }
+#endif /* !GC_MOVE_DISAPPEARING_LINK_NOT_NEEDED */
+
+/* Possible finalization_marker procedures. Note that mark stack */
+/* overflow is handled by the caller, and is not a disaster. */
+STATIC void GC_normal_finalize_mark_proc(ptr_t p)
{
hdr * hhdr = HDR(p);
-
- PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
- &(GC_mark_stack[GC_mark_stack_size]));
+
+ PUSH_OBJ(p, hhdr, GC_mark_stack_top,
+ &(GC_mark_stack[GC_mark_stack_size]));
}
-/* This only pays very partial attention to the mark descriptor. */
-/* It does the right thing for normal and atomic objects, and treats */
-/* most others as normal. */
-GC_API void GC_ignore_self_finalize_mark_proc(p)
-ptr_t p;
+/* This only pays very partial attention to the mark descriptor. */
+/* It does the right thing for normal and atomic objects, and treats */
+/* most others as normal. */
+STATIC void GC_ignore_self_finalize_mark_proc(ptr_t p)
{
hdr * hhdr = HDR(p);
word descr = hhdr -> hb_descr;
- ptr_t q, r;
+ ptr_t q;
+ word r;
ptr_t scan_limit;
- ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
-
+ ptr_t target_limit = p + hhdr -> hb_sz - 1;
+
if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
scan_limit = p + descr - sizeof(word);
} else {
scan_limit = target_limit + 1 - sizeof(word);
}
- for (q = p; q <= scan_limit; q += ALIGNMENT) {
- r = *(ptr_t *)q;
- if (r < p || r > target_limit) {
- GC_PUSH_ONE_HEAP((word)r, q);
- }
+ for (q = p; (word)q <= (word)scan_limit; q += ALIGNMENT) {
+ r = *(word *)q;
+ if (r < (word)p || r > (word)target_limit) {
+ GC_PUSH_ONE_HEAP(r, q, GC_mark_stack_top);
+ }
}
}
-/*ARGSUSED*/
-GC_API void GC_null_finalize_mark_proc(p)
-ptr_t p;
-{
-}
+STATIC void GC_null_finalize_mark_proc(ptr_t p GC_ATTR_UNUSED) {}
+/* Possible finalization_marker procedures. Note that mark stack */
+/* overflow is handled by the caller, and is not a disaster. */
+/* GC_unreachable_finalize_mark_proc is an alias for normal marking, */
+/* but it is explicitly tested for, and triggers different */
+/* behavior. Objects registered in this way are not finalized */
+/* if they are reachable by other finalizable objects, even if those */
+/* other objects specify no ordering. */
+STATIC void GC_unreachable_finalize_mark_proc(ptr_t p)
+{
+ GC_normal_finalize_mark_proc(p);
+}
-/* Register a finalization function. See gc.h for details. */
-/* in the nonthreads case, we try to avoid disabling signals, */
-/* since it can be expensive. Threads packages typically */
-/* make it cheaper. */
-/* The last parameter is a procedure that determines */
-/* marking for finalization ordering. Any objects marked */
-/* by that procedure will be guaranteed to not have been */
-/* finalized when this finalizer is invoked. */
-GC_API void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
-GC_PTR obj;
-GC_finalization_proc fn;
-GC_PTR cd;
-GC_finalization_proc * ofn;
-GC_PTR * ocd;
-finalization_mark_proc * mp;
+/* Register a finalization function. See gc.h for details. */
+/* The last parameter is a procedure that determines */
+/* marking for finalization ordering. Any objects marked */
+/* by that procedure will be guaranteed to not have been */
+/* finalized when this finalizer is invoked. */
+STATIC void GC_register_finalizer_inner(void * obj,
+ GC_finalization_proc fn, void *cd,
+ GC_finalization_proc *ofn, void **ocd,
+ finalization_mark_proc mp)
{
ptr_t base;
struct finalizable_object * curr_fo, * prev_fo;
- int index;
- struct finalizable_object *new_fo;
- hdr *hhdr;
+ size_t index;
+ struct finalizable_object *new_fo = 0;
+ hdr *hhdr = NULL; /* initialized to prevent warning. */
+ GC_oom_func oom_fn;
DCL_LOCK_STATE;
-# ifdef THREADS
- DISABLE_SIGNALS();
- LOCK();
-# endif
+ LOCK();
if (log_fo_table_size == -1
|| GC_fo_entries > ((word)1 << log_fo_table_size)) {
-# ifndef THREADS
- DISABLE_SIGNALS();
-# endif
- GC_grow_table((struct hash_chain_entry ***)(&fo_head),
- &log_fo_table_size);
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Grew fo table to %lu entries\n",
- (unsigned long)(1 << log_fo_table_size));
- }
-# endif
-# ifndef THREADS
- ENABLE_SIGNALS();
-# endif
+ GC_grow_table((struct hash_chain_entry ***)&GC_fo_head,
+ &log_fo_table_size);
+ GC_COND_LOG_PRINTF("Grew fo table to %u entries\n",
+ 1 << (unsigned)log_fo_table_size);
}
- /* in the THREADS case signals are disabled and we hold allocation */
- /* lock; otherwise neither is true. Proceed carefully. */
+ /* in the THREADS case we hold allocation lock. */
base = (ptr_t)obj;
- index = HASH2(base, log_fo_table_size);
- prev_fo = 0; curr_fo = fo_head[index];
- while (curr_fo != 0) {
- if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
- /* Interruption by a signal in the middle of this */
- /* should be safe. The client may see only *ocd */
- /* updated, but we'll declare that to be his */
- /* problem. */
- if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
- if (ofn) *ofn = curr_fo -> fo_fn;
- /* Delete the structure for base. */
- if (prev_fo == 0) {
- fo_head[index] = fo_next(curr_fo);
- } else {
- fo_set_next(prev_fo, fo_next(curr_fo));
- }
- if (fn == 0) {
- GC_fo_entries--;
- /* May not happen if we get a signal. But a high */
- /* estimate will only make the table larger than */
- /* necessary. */
-# if !defined(THREADS) && !defined(DBG_HDRS_ALL)
- GC_free((GC_PTR)curr_fo);
-# endif
+ for (;;) {
+ index = HASH2(base, log_fo_table_size);
+ prev_fo = 0;
+ curr_fo = GC_fo_head[index];
+ while (curr_fo != 0) {
+ GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
+ if (curr_fo -> fo_hidden_base == GC_HIDE_POINTER(base)) {
+ /* Interruption by a signal in the middle of this */
+ /* should be safe. The client may see only *ocd */
+ /* updated, but we'll declare that to be his problem. */
+ if (ocd) *ocd = (void *) (curr_fo -> fo_client_data);
+ if (ofn) *ofn = curr_fo -> fo_fn;
+ /* Delete the structure for base. */
+ if (prev_fo == 0) {
+ GC_fo_head[index] = fo_next(curr_fo);
+ } else {
+ fo_set_next(prev_fo, fo_next(curr_fo));
+ }
+ if (fn == 0) {
+ GC_fo_entries--;
+ /* May not happen if we get a signal. But a high */
+ /* estimate will only make the table larger than */
+ /* necessary. */
+# if !defined(THREADS) && !defined(DBG_HDRS_ALL)
+ GC_free((void *)curr_fo);
+# endif
+ } else {
+ curr_fo -> fo_fn = fn;
+ curr_fo -> fo_client_data = (ptr_t)cd;
+ curr_fo -> fo_mark_proc = mp;
+ /* Reinsert it. We deleted it first to maintain */
+ /* consistency in the event of a signal. */
+ if (prev_fo == 0) {
+ GC_fo_head[index] = curr_fo;
} else {
- curr_fo -> fo_fn = fn;
- curr_fo -> fo_client_data = (ptr_t)cd;
- curr_fo -> fo_mark_proc = mp;
- /* Reinsert it. We deleted it first to maintain */
- /* consistency in the event of a signal. */
- if (prev_fo == 0) {
- fo_head[index] = curr_fo;
- } else {
- fo_set_next(prev_fo, curr_fo);
- }
+ fo_set_next(prev_fo, curr_fo);
}
-# ifdef THREADS
- UNLOCK();
- ENABLE_SIGNALS();
-# endif
- return;
+ }
+ UNLOCK();
+# ifndef DBG_HDRS_ALL
+ if (EXPECT(new_fo != 0, FALSE)) {
+ /* Free unused new_fo returned by GC_oom_fn() */
+ GC_free((void *)new_fo);
+ }
+# endif
+ return;
}
prev_fo = curr_fo;
curr_fo = fo_next(curr_fo);
- }
- if (ofn) *ofn = 0;
- if (ocd) *ocd = 0;
- if (fn == 0) {
-# ifdef THREADS
- UNLOCK();
- ENABLE_SIGNALS();
-# endif
+ }
+ if (EXPECT(new_fo != 0, FALSE)) {
+ /* new_fo is returned by GC_oom_fn(), so fn != 0 and hhdr != 0. */
+ break;
+ }
+ if (fn == 0) {
+ if (ocd) *ocd = 0;
+ if (ofn) *ofn = 0;
+ UNLOCK();
return;
- }
- GET_HDR(base, hhdr);
- if (0 == hhdr) {
- /* We won't collect it, hence finalizer wouldn't be run. */
-# ifdef THREADS
- UNLOCK();
- ENABLE_SIGNALS();
-# endif
- return;
- }
- new_fo = (struct finalizable_object *)
- GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
- if (0 == new_fo) {
-# ifdef THREADS
- UNLOCK();
- ENABLE_SIGNALS();
-# endif
+ }
+ GET_HDR(base, hhdr);
+ if (EXPECT(0 == hhdr, FALSE)) {
+ /* We won't collect it, hence finalizer wouldn't be run. */
+ if (ocd) *ocd = 0;
+ if (ofn) *ofn = 0;
+ UNLOCK();
+ return;
+ }
+ new_fo = (struct finalizable_object *)
+ GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
+ if (EXPECT(new_fo != 0, TRUE))
+ break;
+ oom_fn = GC_oom_fn;
+ UNLOCK();
new_fo = (struct finalizable_object *)
- GC_oom_fn(sizeof(struct finalizable_object));
+ (*oom_fn)(sizeof(struct finalizable_object));
if (0 == new_fo) {
- GC_finalization_failures++;
- return;
+ /* No enough memory. *ocd and *ofn remains unchanged. */
+ return;
}
/* It's not likely we'll make it here, but ... */
-# ifdef THREADS
- DISABLE_SIGNALS();
- LOCK();
-# endif
+ LOCK();
+ /* Recalculate index since the table may grow and */
+ /* check again that our finalizer is not in the table. */
}
- new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
+ GC_ASSERT(GC_size(new_fo) >= sizeof(struct finalizable_object));
+ if (ocd) *ocd = 0;
+ if (ofn) *ofn = 0;
+ new_fo -> fo_hidden_base = GC_HIDE_POINTER(base);
new_fo -> fo_fn = fn;
new_fo -> fo_client_data = (ptr_t)cd;
new_fo -> fo_object_size = hhdr -> hb_sz;
new_fo -> fo_mark_proc = mp;
- fo_set_next(new_fo, fo_head[index]);
+ fo_set_next(new_fo, GC_fo_head[index]);
GC_fo_entries++;
- fo_head[index] = new_fo;
-# ifdef THREADS
- UNLOCK();
- ENABLE_SIGNALS();
-# endif
+ GC_fo_head[index] = new_fo;
+ UNLOCK();
}
-# if defined(__STDC__)
- void GC_register_finalizer(void * obj,
- GC_finalization_proc fn, void * cd,
- GC_finalization_proc *ofn, void ** ocd)
-# else
- void GC_register_finalizer(obj, fn, cd, ofn, ocd)
- GC_PTR obj;
- GC_finalization_proc fn;
- GC_PTR cd;
- GC_finalization_proc * ofn;
- GC_PTR * ocd;
-# endif
+GC_API void GC_CALL GC_register_finalizer(void * obj,
+ GC_finalization_proc fn, void * cd,
+ GC_finalization_proc *ofn, void ** ocd)
{
GC_register_finalizer_inner(obj, fn, cd, ofn,
- ocd, GC_normal_finalize_mark_proc);
+ ocd, GC_normal_finalize_mark_proc);
}
-# if defined(__STDC__)
- void GC_register_finalizer_ignore_self(void * obj,
- GC_finalization_proc fn, void * cd,
- GC_finalization_proc *ofn, void ** ocd)
-# else
- void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
- GC_PTR obj;
- GC_finalization_proc fn;
- GC_PTR cd;
- GC_finalization_proc * ofn;
- GC_PTR * ocd;
-# endif
+GC_API void GC_CALL GC_register_finalizer_ignore_self(void * obj,
+ GC_finalization_proc fn, void * cd,
+ GC_finalization_proc *ofn, void ** ocd)
{
GC_register_finalizer_inner(obj, fn, cd, ofn,
- ocd, GC_ignore_self_finalize_mark_proc);
+ ocd, GC_ignore_self_finalize_mark_proc);
}
-# if defined(__STDC__)
- void GC_register_finalizer_no_order(void * obj,
- GC_finalization_proc fn, void * cd,
- GC_finalization_proc *ofn, void ** ocd)
-# else
- void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
- GC_PTR obj;
- GC_finalization_proc fn;
- GC_PTR cd;
- GC_finalization_proc * ofn;
- GC_PTR * ocd;
-# endif
+GC_API void GC_CALL GC_register_finalizer_no_order(void * obj,
+ GC_finalization_proc fn, void * cd,
+ GC_finalization_proc *ofn, void ** ocd)
{
GC_register_finalizer_inner(obj, fn, cd, ofn,
- ocd, GC_null_finalize_mark_proc);
+ ocd, GC_null_finalize_mark_proc);
}
-#ifndef NO_DEBUGGING
-void GC_dump_finalization()
+static GC_bool need_unreachable_finalization = FALSE;
+ /* Avoid the work if this isn't used. */
+
+GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
+ GC_finalization_proc fn, void * cd,
+ GC_finalization_proc *ofn, void ** ocd)
{
+ need_unreachable_finalization = TRUE;
+ GC_ASSERT(GC_java_finalization);
+ GC_register_finalizer_inner(obj, fn, cd, ofn,
+ ocd, GC_unreachable_finalize_mark_proc);
+}
+
+#ifndef NO_DEBUGGING
+ void GC_dump_finalization(void)
+ {
struct disappearing_link * curr_dl;
struct finalizable_object * curr_fo;
ptr_t real_ptr, real_link;
@@ -521,51 +519,91 @@ void GC_dump_finalization()
int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
int i;
- GC_printf0("Disappearing links:\n");
+ GC_printf("Disappearing links:\n");
for (i = 0; i < dl_size; i++) {
- for (curr_dl = dl_head[i]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
- real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
- real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
- GC_printf2("Object: 0x%lx, Link:0x%lx\n", real_ptr, real_link);
+ for (curr_dl = GC_dl_head[i]; curr_dl != 0;
+ curr_dl = dl_next(curr_dl)) {
+ real_ptr = GC_REVEAL_POINTER(curr_dl -> dl_hidden_obj);
+ real_link = GC_REVEAL_POINTER(curr_dl -> dl_hidden_link);
+ GC_printf("Object: %p, Link:%p\n", real_ptr, real_link);
}
}
- GC_printf0("Finalizers:\n");
+ GC_printf("Finalizers:\n");
for (i = 0; i < fo_size; i++) {
- for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
- real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
- GC_printf1("Finalizable object: 0x%lx\n", real_ptr);
+ for (curr_fo = GC_fo_head[i]; curr_fo != 0;
+ curr_fo = fo_next(curr_fo)) {
+ real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
+ GC_printf("Finalizable object: %p\n", real_ptr);
}
}
-}
+ }
+#endif /* !NO_DEBUGGING */
+
+#ifndef SMALL_CONFIG
+ STATIC word GC_old_dl_entries = 0; /* for stats printing */
#endif
-/* Called with world stopped. Cause disappearing links to disappear, */
-/* and invoke finalizers. */
-void GC_finalize()
+#ifndef THREADS
+ /* Global variables to minimize the level of recursion when a client */
+ /* finalizer allocates memory. */
+ STATIC int GC_finalizer_nested = 0;
+ /* Only the lowest byte is used, the rest is */
+ /* padding for proper global data alignment */
+ /* required for some compilers (like Watcom). */
+ STATIC unsigned GC_finalizer_skipped = 0;
+
+ /* Checks and updates the level of finalizers recursion. */
+ /* Returns NULL if GC_invoke_finalizers() should not be called by the */
+ /* collector (to minimize the risk of a deep finalizers recursion), */
+ /* otherwise returns a pointer to GC_finalizer_nested. */
+ STATIC unsigned char *GC_check_finalizer_nested(void)
+ {
+ unsigned nesting_level = *(unsigned char *)&GC_finalizer_nested;
+ if (nesting_level) {
+ /* We are inside another GC_invoke_finalizers(). */
+ /* Skip some implicitly-called GC_invoke_finalizers() */
+ /* depending on the nesting (recursion) level. */
+ if (++GC_finalizer_skipped < (1U << nesting_level)) return NULL;
+ GC_finalizer_skipped = 0;
+ }
+ *(char *)&GC_finalizer_nested = (char)(nesting_level + 1);
+ return (unsigned char *)&GC_finalizer_nested;
+ }
+#endif /* THREADS */
+
+/* Called with held lock (but the world is running). */
+/* Cause disappearing links to disappear and unreachable objects to be */
+/* enqueued for finalization. */
+GC_INNER void GC_finalize(void)
{
struct disappearing_link * curr_dl, * prev_dl, * next_dl;
struct finalizable_object * curr_fo, * prev_fo, * next_fo;
ptr_t real_ptr, real_link;
- register int i;
- int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
- int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
-
+ size_t i;
+ size_t dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
+ size_t fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
+
+# ifndef SMALL_CONFIG
+ /* Save current GC_dl_entries value for stats printing */
+ GC_old_dl_entries = GC_dl_entries;
+# endif
+
/* Make disappearing links disappear */
for (i = 0; i < dl_size; i++) {
- curr_dl = dl_head[i];
+ curr_dl = GC_dl_head[i];
prev_dl = 0;
while (curr_dl != 0) {
- real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
- real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
+ real_ptr = GC_REVEAL_POINTER(curr_dl -> dl_hidden_obj);
+ real_link = GC_REVEAL_POINTER(curr_dl -> dl_hidden_link);
if (!GC_is_marked(real_ptr)) {
*(word *)real_link = 0;
next_dl = dl_next(curr_dl);
if (prev_dl == 0) {
- dl_head[i] = next_dl;
+ GC_dl_head[i] = next_dl;
} else {
dl_set_next(prev_dl, next_dl);
}
- GC_clear_mark_bit((ptr_t)curr_dl);
+ GC_clear_mark_bit(curr_dl);
GC_dl_entries--;
curr_dl = next_dl;
} else {
@@ -574,52 +612,54 @@ void GC_finalize()
}
}
}
- /* Mark all objects reachable via chains of 1 or more pointers */
- /* from finalizable objects. */
+ /* Mark all objects reachable via chains of 1 or more pointers */
+ /* from finalizable objects. */
GC_ASSERT(GC_mark_state == MS_NONE);
for (i = 0; i < fo_size; i++) {
- for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
- real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
+ for (curr_fo = GC_fo_head[i]; curr_fo != 0;
+ curr_fo = fo_next(curr_fo)) {
+ GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
+ real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
if (!GC_is_marked(real_ptr)) {
- GC_MARKED_FOR_FINALIZATION(real_ptr);
+ GC_MARKED_FOR_FINALIZATION(real_ptr);
GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
if (GC_is_marked(real_ptr)) {
- WARN("Finalization cycle involving %lx\n", real_ptr);
+ WARN("Finalization cycle involving %p\n", real_ptr);
}
}
}
}
- /* Enqueue for finalization all objects that are still */
- /* unreachable. */
- GC_words_finalized = 0;
+ /* Enqueue for finalization all objects that are still */
+ /* unreachable. */
+ GC_bytes_finalized = 0;
for (i = 0; i < fo_size; i++) {
- curr_fo = fo_head[i];
+ curr_fo = GC_fo_head[i];
prev_fo = 0;
while (curr_fo != 0) {
- real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
+ real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
if (!GC_is_marked(real_ptr)) {
- if (!GC_java_finalization) {
+ if (!GC_java_finalization) {
GC_set_mark_bit(real_ptr);
- }
+ }
/* Delete from hash table */
next_fo = fo_next(curr_fo);
if (prev_fo == 0) {
- fo_head[i] = next_fo;
+ GC_fo_head[i] = next_fo;
} else {
fo_set_next(prev_fo, next_fo);
}
GC_fo_entries--;
- /* Add to list of objects awaiting finalization. */
+ /* Add to list of objects awaiting finalization. */
fo_set_next(curr_fo, GC_finalize_now);
GC_finalize_now = curr_fo;
- /* unhide object pointer so any future collections will */
- /* see it. */
- curr_fo -> fo_hidden_base =
- (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
- GC_words_finalized +=
- ALIGNED_WORDS(curr_fo -> fo_object_size)
- + ALIGNED_WORDS(sizeof(struct finalizable_object));
- GC_ASSERT(GC_is_marked(GC_base((ptr_t)curr_fo)));
+ /* unhide object pointer so any future collections will */
+ /* see it. */
+ curr_fo -> fo_hidden_base =
+ (word)GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
+ GC_bytes_finalized +=
+ curr_fo -> fo_object_size
+ + sizeof(struct finalizable_object);
+ GC_ASSERT(GC_is_marked(GC_base(curr_fo)));
curr_fo = next_fo;
} else {
prev_fo = curr_fo;
@@ -631,32 +671,68 @@ void GC_finalize()
if (GC_java_finalization) {
/* make sure we mark everything reachable from objects finalized
using the no_order mark_proc */
- for (curr_fo = GC_finalize_now;
- curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
- real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
- if (!GC_is_marked(real_ptr)) {
- if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
- GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
- }
- GC_set_mark_bit(real_ptr);
- }
+ for (curr_fo = GC_finalize_now;
+ curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
+ real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
+ if (!GC_is_marked(real_ptr)) {
+ if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
+ GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
+ }
+ if (curr_fo -> fo_mark_proc != GC_unreachable_finalize_mark_proc) {
+ GC_set_mark_bit(real_ptr);
+ }
+ }
+ }
+
+ /* now revive finalize-when-unreachable objects reachable from
+ other finalizable objects */
+ if (need_unreachable_finalization) {
+ curr_fo = GC_finalize_now;
+ prev_fo = 0;
+ while (curr_fo != 0) {
+ next_fo = fo_next(curr_fo);
+ if (curr_fo -> fo_mark_proc == GC_unreachable_finalize_mark_proc) {
+ real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
+ if (!GC_is_marked(real_ptr)) {
+ GC_set_mark_bit(real_ptr);
+ } else {
+ if (prev_fo == 0)
+ GC_finalize_now = next_fo;
+ else
+ fo_set_next(prev_fo, next_fo);
+
+ curr_fo -> fo_hidden_base =
+ GC_HIDE_POINTER(curr_fo -> fo_hidden_base);
+ GC_bytes_finalized -=
+ curr_fo->fo_object_size + sizeof(struct finalizable_object);
+
+ i = HASH2(real_ptr, log_fo_table_size);
+ fo_set_next (curr_fo, GC_fo_head[i]);
+ GC_fo_entries++;
+ GC_fo_head[i] = curr_fo;
+ curr_fo = prev_fo;
+ }
+ }
+ prev_fo = curr_fo;
+ curr_fo = next_fo;
+ }
}
}
/* Remove dangling disappearing links. */
for (i = 0; i < dl_size; i++) {
- curr_dl = dl_head[i];
+ curr_dl = GC_dl_head[i];
prev_dl = 0;
while (curr_dl != 0) {
- real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
+ real_link = GC_base(GC_REVEAL_POINTER(curr_dl -> dl_hidden_link));
if (real_link != 0 && !GC_is_marked(real_link)) {
next_dl = dl_next(curr_dl);
if (prev_dl == 0) {
- dl_head[i] = next_dl;
+ GC_dl_head[i] = next_dl;
} else {
dl_set_next(prev_dl, next_dl);
}
- GC_clear_mark_bit((ptr_t)curr_dl);
+ GC_clear_mark_bit(curr_dl);
GC_dl_entries--;
curr_dl = next_dl;
} else {
@@ -665,233 +741,237 @@ void GC_finalize()
}
}
}
+ if (GC_fail_count) {
+ /* Don't prevent running finalizers if there has been an allocation */
+ /* failure recently. */
+# ifdef THREADS
+ GC_reset_finalizer_nested();
+# else
+ GC_finalizer_nested = 0;
+# endif
+ }
}
#ifndef JAVA_FINALIZATION_NOT_NEEDED
-/* Enqueue all remaining finalizers to be run - Assumes lock is
- * held, and signals are disabled */
-void GC_enqueue_all_finalizers()
-{
+ /* Enqueue all remaining finalizers to be run - Assumes lock is held. */
+ STATIC void GC_enqueue_all_finalizers(void)
+ {
struct finalizable_object * curr_fo, * prev_fo, * next_fo;
ptr_t real_ptr;
register int i;
int fo_size;
-
+
fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
- GC_words_finalized = 0;
+ GC_bytes_finalized = 0;
for (i = 0; i < fo_size; i++) {
- curr_fo = fo_head[i];
+ curr_fo = GC_fo_head[i];
prev_fo = 0;
while (curr_fo != 0) {
- real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
+ real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
GC_set_mark_bit(real_ptr);
-
+
/* Delete from hash table */
next_fo = fo_next(curr_fo);
if (prev_fo == 0) {
- fo_head[i] = next_fo;
+ GC_fo_head[i] = next_fo;
} else {
fo_set_next(prev_fo, next_fo);
}
GC_fo_entries--;
- /* Add to list of objects awaiting finalization. */
+ /* Add to list of objects awaiting finalization. */
fo_set_next(curr_fo, GC_finalize_now);
GC_finalize_now = curr_fo;
- /* unhide object pointer so any future collections will */
- /* see it. */
- curr_fo -> fo_hidden_base =
- (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
-
- GC_words_finalized +=
- ALIGNED_WORDS(curr_fo -> fo_object_size)
- + ALIGNED_WORDS(sizeof(struct finalizable_object));
+ /* unhide object pointer so any future collections will */
+ /* see it. */
+ curr_fo -> fo_hidden_base =
+ (word)GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
+ GC_bytes_finalized +=
+ curr_fo -> fo_object_size + sizeof(struct finalizable_object);
curr_fo = next_fo;
}
}
+ }
- return;
-}
-
-/* Invoke all remaining finalizers that haven't yet been run.
- * This is needed for strict compliance with the Java standard,
- * which can make the runtime guarantee that all finalizers are run.
- * Unfortunately, the Java standard implies we have to keep running
- * finalizers until there are no more left, a potential infinite loop.
- * YUCK.
- * Note that this is even more dangerous than the usual Java
- * finalizers, in that objects reachable from static variables
- * may have been finalized when these finalizers are run.
- * Finalizers run at this point must be prepared to deal with a
- * mostly broken world.
- * This routine is externally callable, so is called without
- * the allocation lock.
- */
-GC_API void GC_finalize_all()
-{
+ /* Invoke all remaining finalizers that haven't yet been run.
+ * This is needed for strict compliance with the Java standard,
+ * which can make the runtime guarantee that all finalizers are run.
+ * Unfortunately, the Java standard implies we have to keep running
+ * finalizers until there are no more left, a potential infinite loop.
+ * YUCK.
+ * Note that this is even more dangerous than the usual Java
+ * finalizers, in that objects reachable from static variables
+ * may have been finalized when these finalizers are run.
+ * Finalizers run at this point must be prepared to deal with a
+ * mostly broken world.
+ * This routine is externally callable, so is called without
+ * the allocation lock.
+ */
+ GC_API void GC_CALL GC_finalize_all(void)
+ {
DCL_LOCK_STATE;
- DISABLE_SIGNALS();
LOCK();
while (GC_fo_entries > 0) {
GC_enqueue_all_finalizers();
UNLOCK();
- ENABLE_SIGNALS();
- GC_INVOKE_FINALIZERS();
- DISABLE_SIGNALS();
+ GC_invoke_finalizers();
+ /* Running the finalizers in this thread is arguably not a good */
+ /* idea when we should be notifying another thread to run them. */
+ /* But otherwise we don't have a great way to wait for them to */
+ /* run. */
LOCK();
}
UNLOCK();
- ENABLE_SIGNALS();
-}
-#endif
+ }
+
+#endif /* !JAVA_FINALIZATION_NOT_NEEDED */
-/* Returns true if it is worth calling GC_invoke_finalizers. (Useful if */
-/* finalizers can only be called from some kind of `safe state' and */
-/* getting into that safe state is expensive.) */
-int GC_should_invoke_finalizers GC_PROTO((void))
+/* Returns true if it is worth calling GC_invoke_finalizers. (Useful if */
+/* finalizers can only be called from some kind of `safe state' and */
+/* getting into that safe state is expensive.) */
+GC_API int GC_CALL GC_should_invoke_finalizers(void)
{
return GC_finalize_now != 0;
}
-/* Invoke finalizers for all objects that are ready to be finalized. */
-/* Should be called without allocation lock. */
-int GC_invoke_finalizers()
+/* Invoke finalizers for all objects that are ready to be finalized. */
+/* Should be called without allocation lock. */
+GC_API int GC_CALL GC_invoke_finalizers(void)
{
struct finalizable_object * curr_fo;
int count = 0;
- word mem_freed_before;
+ word bytes_freed_before = 0; /* initialized to prevent warning. */
DCL_LOCK_STATE;
-
+
while (GC_finalize_now != 0) {
-# ifdef THREADS
- DISABLE_SIGNALS();
- LOCK();
-# endif
- if (count == 0) {
- mem_freed_before = GC_mem_freed;
- }
- curr_fo = GC_finalize_now;
-# ifdef THREADS
- if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
- UNLOCK();
- ENABLE_SIGNALS();
- if (curr_fo == 0) break;
-# else
- GC_finalize_now = fo_next(curr_fo);
-# endif
- fo_set_next(curr_fo, 0);
- (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
- curr_fo -> fo_client_data);
- curr_fo -> fo_client_data = 0;
- ++count;
-# ifdef UNDEFINED
- /* This is probably a bad idea. It throws off accounting if */
- /* nearly all objects are finalizable. O.w. it shouldn't */
- /* matter. */
- GC_free((GC_PTR)curr_fo);
-# endif
+# ifdef THREADS
+ LOCK();
+# endif
+ if (count == 0) {
+ bytes_freed_before = GC_bytes_freed;
+ /* Don't do this outside, since we need the lock. */
+ }
+ curr_fo = GC_finalize_now;
+# ifdef THREADS
+ if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
+ UNLOCK();
+ if (curr_fo == 0) break;
+# else
+ GC_finalize_now = fo_next(curr_fo);
+# endif
+ fo_set_next(curr_fo, 0);
+ (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
+ curr_fo -> fo_client_data);
+ curr_fo -> fo_client_data = 0;
+ ++count;
+# ifdef UNDEFINED
+ /* This is probably a bad idea. It throws off accounting if */
+ /* nearly all objects are finalizable. O.w. it shouldn't */
+ /* matter. */
+ GC_free((void *)curr_fo);
+# endif
}
- if (count != 0 && mem_freed_before != GC_mem_freed) {
+ /* bytes_freed_before is initialized whenever count != 0 */
+ if (count != 0 && bytes_freed_before != GC_bytes_freed) {
LOCK();
- GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
- UNLOCK();
+ GC_finalizer_bytes_freed += (GC_bytes_freed - bytes_freed_before);
+ UNLOCK();
}
return count;
}
-void (* GC_finalizer_notifier)() = (void (*) GC_PROTO((void)))0;
-
static GC_word last_finalizer_notification = 0;
-#ifdef KEEP_BACK_PTRS
-void GC_generate_random_backtrace_no_gc(void);
-#endif
-
-void GC_notify_or_invoke_finalizers GC_PROTO((void))
+GC_INNER void GC_notify_or_invoke_finalizers(void)
{
+ GC_finalizer_notifier_proc notifier_fn = 0;
+# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
+ static word last_back_trace_gc_no = 1; /* Skip first one. */
+# endif
+ DCL_LOCK_STATE;
+
+# if defined(THREADS) && !defined(KEEP_BACK_PTRS) \
+ && !defined(MAKE_BACK_GRAPH)
+ /* Quick check (while unlocked) for an empty finalization queue. */
+ if (GC_finalize_now == 0) return;
+# endif
+ LOCK();
+
/* This is a convenient place to generate backtraces if appropriate, */
- /* since that code is not callable with the allocation lock. */
-# ifdef KEEP_BACK_PTRS
- if (GC_backtraces > 0) {
- static word last_back_trace_gc_no = 3; /* Skip early ones. */
- long i;
-
- LOCK();
- if (GC_gc_no > last_back_trace_gc_no) {
- /* Stops when GC_gc_no wraps; that's OK. */
- last_back_trace_gc_no = (word)(-1); /* disable others. */
- for (i = 0; i < GC_backtraces; ++i) {
- /* FIXME: This tolerates concurrent heap mutation, */
- /* which may cause occasional mysterious results. */
- /* We need to release the GC lock, since GC_print_callers */
- /* acquires it. It probably shouldn't. */
- UNLOCK();
- GC_generate_random_backtrace_no_gc();
- LOCK();
- }
- last_back_trace_gc_no = GC_gc_no;
- }
- UNLOCK();
+ /* since that code is not callable with the allocation lock. */
+# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
+ if (GC_gc_no > last_back_trace_gc_no) {
+# ifdef KEEP_BACK_PTRS
+ long i;
+ /* Stops when GC_gc_no wraps; that's OK. */
+ last_back_trace_gc_no = (word)(-1); /* disable others. */
+ for (i = 0; i < GC_backtraces; ++i) {
+ /* FIXME: This tolerates concurrent heap mutation, */
+ /* which may cause occasional mysterious results. */
+ /* We need to release the GC lock, since GC_print_callers */
+ /* acquires it. It probably shouldn't. */
+ UNLOCK();
+ GC_generate_random_backtrace_no_gc();
+ LOCK();
+ }
+ last_back_trace_gc_no = GC_gc_no;
+# endif
+# ifdef MAKE_BACK_GRAPH
+ if (GC_print_back_height) {
+ UNLOCK();
+ GC_print_back_graph_stats();
+ LOCK();
+ }
+# endif
}
# endif
- if (GC_finalize_now == 0) return;
- if (!GC_finalize_on_demand) {
- (void) GC_invoke_finalizers();
-# ifndef THREADS
- GC_ASSERT(GC_finalize_now == 0);
-# endif /* Otherwise GC can run concurrently and add more */
- return;
- }
- if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
- && last_finalizer_notification != GC_gc_no) {
- last_finalizer_notification = GC_gc_no;
- GC_finalizer_notifier();
+ if (GC_finalize_now == 0) {
+ UNLOCK();
+ return;
}
-}
-# ifdef __STDC__
- GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
- GC_PTR client_data)
-# else
- GC_PTR GC_call_with_alloc_lock(fn, client_data)
- GC_fn_type fn;
- GC_PTR client_data;
-# endif
-{
- GC_PTR result;
- DCL_LOCK_STATE;
-
-# ifdef THREADS
- DISABLE_SIGNALS();
- LOCK();
- SET_LOCK_HOLDER();
-# endif
- result = (*fn)(client_data);
-# ifdef THREADS
-# ifndef GC_ASSERTIONS
- UNSET_LOCK_HOLDER();
-# endif /* o.w. UNLOCK() does it implicitly */
+ if (!GC_finalize_on_demand) {
+ unsigned char *pnested = GC_check_finalizer_nested();
UNLOCK();
- ENABLE_SIGNALS();
-# endif
- return(result);
-}
+ /* Skip GC_invoke_finalizers() if nested */
+ if (pnested != NULL) {
+ (void) GC_invoke_finalizers();
+ *pnested = 0; /* Reset since no more finalizers. */
+# ifndef THREADS
+ GC_ASSERT(GC_finalize_now == 0);
+# endif /* Otherwise GC can run concurrently and add more */
+ }
+ return;
+ }
-#if !defined(NO_DEBUGGING)
+ /* These variables require synchronization to avoid data races. */
+ if (last_finalizer_notification != GC_gc_no) {
+ last_finalizer_notification = GC_gc_no;
+ notifier_fn = GC_finalizer_notifier;
+ }
+ UNLOCK();
+ if (notifier_fn != 0)
+ (*notifier_fn)(); /* Invoke the notifier */
+}
-void GC_print_finalization_stats()
-{
+#ifndef SMALL_CONFIG
+ GC_INNER void GC_print_finalization_stats(void)
+ {
struct finalizable_object *fo = GC_finalize_now;
- size_t ready = 0;
+ unsigned long ready = 0;
- GC_printf2("%lu finalization table entries; %lu disappearing links\n",
- GC_fo_entries, GC_dl_entries);
+ GC_stats_log_printf(
+ "%lu finalization table entries; %lu disappearing links alive\n",
+ (unsigned long)GC_fo_entries, (unsigned long)GC_dl_entries);
for (; 0 != fo; fo = fo_next(fo)) ++ready;
- GC_printf1("%lu objects are eligible for immediate finalization\n", ready);
-}
+ GC_stats_log_printf("%lu objects are eligible for immediate finalization;"
+ " %ld links cleared\n",
+ ready, (long)GC_old_dl_entries - (long)GC_dl_entries);
+ }
+#endif /* !SMALL_CONFIG */
-#endif /* NO_DEBUGGING */
+#endif /* !GC_NO_FINALIZATION */
diff --git a/boehm-gc/fnlz_mlc.c b/boehm-gc/fnlz_mlc.c
new file mode 100644
index 00000000000..0dad28a629a
--- /dev/null
+++ b/boehm-gc/fnlz_mlc.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011 by Hewlett-Packard Company. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+#include "private/gc_priv.h"
+
+#ifdef ENABLE_DISCLAIM
+
+#include "gc_disclaim.h"
+
+#ifdef THREAD_LOCAL_ALLOC
+# include "private/thread_local_alloc.h"
+#else
+ STATIC ptr_t * GC_finalized_objfreelist = NULL;
+#endif /* !THREAD_LOCAL_ALLOC */
+
+STATIC int GC_finalized_kind = 0;
+
+STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj)
+{
+ void **fc_addr;
+ const struct GC_finalizer_closure *fc;
+
+ fc_addr = &((void **)obj)[GC_size(obj) / sizeof(void *) - 1];
+ fc = *fc_addr;
+ if (fc != NULL) {
+ /* [1] The disclaim function may be passed fragments from the */
+ /* free-list, on which it should not run finalization. */
+ /* To recognize this case, we use the fact that the first word */
+ /* on such fragments are always even (a link to the next */
+ /* fragment, or NULL). If it is desirable to have a finalizer */
+ /* which does not use the first word for storing finalization */
+ /* info, GC_reclaim_with_finalization must be extended to clear */
+ /* fragments so that the assumption holds for the selected word. */
+ (*fc->proc)(obj, fc->cd);
+ *fc_addr = NULL;
+ }
+ return 0;
+}
+
+static GC_bool done_init = FALSE;
+
+GC_API void GC_CALL GC_init_finalized_malloc(void)
+{
+ DCL_LOCK_STATE;
+
+ GC_init(); /* In case it's not already done. */
+ LOCK();
+ if (done_init) {
+ UNLOCK();
+ return;
+ }
+ done_init = TRUE;
+
+ GC_finalized_objfreelist = (ptr_t *)GC_new_free_list_inner();
+ GC_finalized_kind = GC_new_kind_inner((void **)GC_finalized_objfreelist,
+ GC_DS_LENGTH, TRUE, TRUE);
+ GC_register_disclaim_proc(GC_finalized_kind, GC_finalized_disclaim, TRUE);
+ UNLOCK();
+}
+
+GC_API void GC_CALL GC_register_disclaim_proc(int kind, GC_disclaim_proc proc,
+ int mark_unconditionally)
+{
+ GC_ASSERT((unsigned)kind < MAXOBJKINDS);
+ GC_obj_kinds[kind].ok_disclaim_proc = proc;
+ GC_obj_kinds[kind].ok_mark_unconditionally = (GC_bool)mark_unconditionally;
+}
+
+#ifdef THREAD_LOCAL_ALLOC
+ STATIC void * GC_core_finalized_malloc(size_t lb,
+ const struct GC_finalizer_closure *fclos)
+#else
+ GC_API void * GC_CALL GC_finalized_malloc(size_t lb,
+ const struct GC_finalizer_closure *fclos)
+#endif
+{
+ ptr_t op;
+ ptr_t *opp;
+ word lg;
+ DCL_LOCK_STATE;
+
+ lb += sizeof(void *);
+ GC_ASSERT(done_init);
+ if (SMALL_OBJ(lb)) {
+ GC_DBG_COLLECT_AT_MALLOC(lb);
+ lg = GC_size_map[lb];
+ opp = &GC_finalized_objfreelist[lg];
+ LOCK();
+ op = *opp;
+ if (EXPECT(0 == op, FALSE)) {
+ UNLOCK();
+ op = GC_generic_malloc((word)lb, GC_finalized_kind);
+ if (NULL == op)
+ return NULL;
+ /* GC_generic_malloc has extended the size map for us. */
+ lg = GC_size_map[lb];
+ } else {
+ *opp = obj_link(op);
+ obj_link(op) = 0;
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+ UNLOCK();
+ }
+ GC_ASSERT(lg > 0);
+ ((const void **)op)[GRANULES_TO_WORDS(lg) - 1] = fclos;
+ } else {
+ size_t op_sz;
+
+ op = GC_generic_malloc((word)lb, GC_finalized_kind);
+ if (NULL == op)
+ return NULL;
+ op_sz = GC_size(op);
+ GC_ASSERT(op_sz >= lb);
+ ((const void **)op)[op_sz / sizeof(void *) - 1] = fclos;
+ }
+ return GC_clear_stack(op);
+}
+
+#ifdef THREAD_LOCAL_ALLOC
+ GC_API void * GC_CALL GC_finalized_malloc(size_t client_lb,
+ const struct GC_finalizer_closure *fclos)
+ {
+ size_t lb = client_lb + sizeof(void *);
+ size_t lg = ROUNDED_UP_GRANULES(lb);
+ GC_tlfs tsd;
+ void *result;
+ void **tiny_fl, **my_fl, *my_entry;
+ void *next;
+
+ if (EXPECT(lg >= GC_TINY_FREELISTS, FALSE))
+ return GC_core_finalized_malloc(client_lb, fclos);
+
+ tsd = GC_getspecific(GC_thread_key);
+ tiny_fl = tsd->finalized_freelists;
+ my_fl = tiny_fl + lg;
+ my_entry = *my_fl;
+ while (EXPECT((word)my_entry
+ <= DIRECT_GRANULES + GC_TINY_FREELISTS + 1, FALSE)) {
+ if ((word)my_entry - 1 < DIRECT_GRANULES) {
+ *my_fl = (ptr_t)my_entry + lg + 1;
+ return GC_core_finalized_malloc(client_lb, fclos);
+ } else {
+ GC_generic_malloc_many(GC_RAW_BYTES_FROM_INDEX(lg),
+ GC_finalized_kind, my_fl);
+ my_entry = *my_fl;
+ if (my_entry == 0) {
+ return (*GC_get_oom_fn())(lb);
+ }
+ }
+ }
+
+ next = obj_link(my_entry);
+ result = (void *)my_entry;
+ *my_fl = next;
+ obj_link(result) = 0;
+ ((const void **)result)[GRANULES_TO_WORDS(lg) - 1] = fclos;
+ PREFETCH_FOR_WRITE(next);
+ return result;
+ }
+#endif /* THREAD_LOCAL_ALLOC */
+
+#endif /* ENABLE_DISCLAIM */
diff --git a/boehm-gc/gc.mak b/boehm-gc/gc.mak
index 5f0b5462427..9f92d381dd4 100644
--- a/boehm-gc/gc.mak
+++ b/boehm-gc/gc.mak
@@ -8,7 +8,7 @@
!IF "$(CFG)" == ""
CFG=gctest - Win32 Release
!MESSAGE No configuration specified. Defaulting to cord - Win32 Debug.
-!ENDIF
+!ENDIF
!IF "$(CFG)" != "gc - Win32 Release" && "$(CFG)" != "gc - Win32 Debug" &&\
"$(CFG)" != "gctest - Win32 Release" && "$(CFG)" != "gctest - Win32 Debug" &&\
@@ -16,26 +16,26 @@ CFG=gctest - Win32 Release
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE on this makefile
!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
+!MESSAGE
!MESSAGE NMAKE /f "gc.mak" CFG="cord - Win32 Debug"
-!MESSAGE
+!MESSAGE
!MESSAGE Possible choices for configuration are:
-!MESSAGE
+!MESSAGE
!MESSAGE "gc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "gc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "gctest - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "gctest - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE "cord - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "cord - Win32 Debug" (based on "Win32 (x86) Application")
-!MESSAGE
+!MESSAGE
!ERROR An invalid configuration is specified.
-!ENDIF
+!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
-!ELSE
+!ELSE
NULL=nul
-!ENDIF
+!ENDIF
################################################################################
# Begin Project
# PROP Target_Last_Scanned "gctest - Win32 Debug"
@@ -57,7 +57,7 @@ INTDIR=.\Release
ALL : ".\Release\gc.dll" ".\Release\gc.bsc"
-CLEAN :
+CLEAN :
-@erase ".\Release\allchblk.obj"
-@erase ".\Release\allchblk.sbr"
-@erase ".\Release\alloc.obj"
@@ -72,6 +72,8 @@ CLEAN :
-@erase ".\Release\dyn_load.sbr"
-@erase ".\Release\finalize.obj"
-@erase ".\Release\finalize.sbr"
+ -@erase ".\Release\fnlz_mlc.obj"
+ -@erase ".\Release\fnlz_mlc.sbr"
-@erase ".\Release\gc.bsc"
-@erase ".\Release\gc_cpp.obj"
-@erase ".\Release\gc_cpp.sbr"
@@ -108,48 +110,51 @@ CLEAN :
-@erase ".\Release\typd_mlc.sbr"
-@erase ".\Release\win32_threads.obj"
-@erase ".\Release\win32_threads.sbr"
+ -@erase ".\Release\msvc_dbg.obj"
+ -@erase ".\Release\msvc_dbg.sbr"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
CPP=cl.exe
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "SILENT" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
-CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "SILENT" /D "GC_BUILD" /D\
- "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D\
- "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/" /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /FR /YX /c
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D\
+ "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" \
+ /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" \
+ /I./libatomic_ops/src /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\Release/
CPP_SBRS=.\Release/
.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
MTL=mktyplib.exe
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /win32
-MTL_PROJ=/nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32
RSC=rc.exe
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
BSC32_SBRS= \
".\Release\allchblk.sbr" \
".\Release\alloc.sbr" \
@@ -158,6 +163,7 @@ BSC32_SBRS= \
".\Release\dbg_mlc.sbr" \
".\Release\dyn_load.sbr" \
".\Release\finalize.sbr" \
+ ".\Release\fnlz_mlc.sbr" \
".\Release\gc_cpp.sbr" \
".\Release\headers.sbr" \
".\Release\mach_dep.sbr" \
@@ -173,6 +179,7 @@ BSC32_SBRS= \
".\Release\reclaim.sbr" \
".\Release\stubborn.sbr" \
".\Release\typd_mlc.sbr" \
+ ".\Release\msvc_dbg.sbr" \
".\Release\win32_threads.sbr"
".\Release\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
@@ -187,7 +194,7 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
/pdb:"$(OUTDIR)/gc.pdb" /machine:I386 /out:"$(OUTDIR)/gc.dll"\
- /implib:"$(OUTDIR)/gc.lib"
+ /implib:"$(OUTDIR)/gc.lib"
LINK32_OBJS= \
".\Release\allchblk.obj" \
".\Release\alloc.obj" \
@@ -196,6 +203,7 @@ LINK32_OBJS= \
".\Release\dbg_mlc.obj" \
".\Release\dyn_load.obj" \
".\Release\finalize.obj" \
+ ".\Release\fnlz_mlc.obj" \
".\Release\gc_cpp.obj" \
".\Release\headers.obj" \
".\Release\mach_dep.obj" \
@@ -211,6 +219,7 @@ LINK32_OBJS= \
".\Release\reclaim.obj" \
".\Release\stubborn.obj" \
".\Release\typd_mlc.obj" \
+ ".\Release\msvc_dbg.obj" \
".\Release\win32_threads.obj"
".\Release\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -235,7 +244,7 @@ INTDIR=.\Debug
ALL : ".\Debug\gc.dll" ".\Debug\gc.bsc"
-CLEAN :
+CLEAN :
-@erase ".\Debug\allchblk.obj"
-@erase ".\Debug\allchblk.sbr"
-@erase ".\Debug\alloc.obj"
@@ -250,6 +259,8 @@ CLEAN :
-@erase ".\Debug\dyn_load.sbr"
-@erase ".\Debug\finalize.obj"
-@erase ".\Debug\finalize.sbr"
+ -@erase ".\Debug\fnlz_mlc.obj"
+ -@erase ".\Debug\fnlz_mlc.sbr"
-@erase ".\Debug\gc_cpp.obj"
-@erase ".\Debug\gc_cpp.sbr"
-@erase ".\Debug\gc.bsc"
@@ -290,49 +301,52 @@ CLEAN :
-@erase ".\Debug\vc40.pdb"
-@erase ".\Debug\win32_threads.obj"
-@erase ".\Debug\win32_threads.sbr"
+ -@erase ".\Debug\msvc_dbg.obj"
+ -@erase ".\Debug\msvc_dbg.sbr"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
CPP=cl.exe
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "SILENT" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
-CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "SILENT" /D "GC_BUILD"\
- /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D\
- "GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/"\
- /Fd"$(INTDIR)/" /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /FR /YX /c
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG"\
+ /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" \
+ /D "GC_ASSERTIONS" /D "GC_THREADS" \
+ /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/"\
+ /I./libatomic_ops/src /Fd"$(INTDIR)/" /c
CPP_OBJS=.\Debug/
CPP_SBRS=.\Debug/
.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
MTL=mktyplib.exe
# ADD BASE MTL /nologo /D "_DEBUG" /win32
# ADD MTL /nologo /D "_DEBUG" /win32
-MTL_PROJ=/nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32
RSC=rc.exe
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
BSC32_SBRS= \
".\Debug\allchblk.sbr" \
".\Debug\alloc.sbr" \
@@ -341,6 +355,7 @@ BSC32_SBRS= \
".\Debug\dbg_mlc.sbr" \
".\Debug\dyn_load.sbr" \
".\Debug\finalize.sbr" \
+ ".\Debug\fnlz_mlc.sbr" \
".\Debug\gc_cpp.sbr" \
".\Debug\headers.sbr" \
".\Debug\mach_dep.sbr" \
@@ -356,6 +371,7 @@ BSC32_SBRS= \
".\Debug\reclaim.sbr" \
".\Debug\stubborn.sbr" \
".\Debug\typd_mlc.sbr" \
+ ".\Debug\msvc_dbg.sbr" \
".\Debug\win32_threads.sbr"
".\Debug\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
@@ -370,7 +386,7 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
/pdb:"$(OUTDIR)/gc.pdb" /map:"$(INTDIR)/gc.map" /debug /machine:I386\
- /out:"$(OUTDIR)/gc.dll" /implib:"$(OUTDIR)/gc.lib"
+ /out:"$(OUTDIR)/gc.dll" /implib:"$(OUTDIR)/gc.lib"
LINK32_OBJS= \
".\Debug\allchblk.obj" \
".\Debug\alloc.obj" \
@@ -379,6 +395,7 @@ LINK32_OBJS= \
".\Debug\dbg_mlc.obj" \
".\Debug\dyn_load.obj" \
".\Debug\finalize.obj" \
+ ".\Debug\fnlz_mlc.obj" \
".\Debug\gc_cpp.obj" \
".\Debug\headers.obj" \
".\Debug\mach_dep.obj" \
@@ -394,6 +411,7 @@ LINK32_OBJS= \
".\Debug\reclaim.obj" \
".\Debug\stubborn.obj" \
".\Debug\typd_mlc.obj" \
+ ".\Debug\msvc_dbg.obj" \
".\Debug\win32_threads.obj"
".\Debug\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -418,7 +436,7 @@ INTDIR=.\gctest\Release
ALL : "gc - Win32 Release" ".\Release\gctest.exe"
-CLEAN :
+CLEAN :
-@erase ".\gctest\Release\test.obj"
-@erase ".\Release\gctest.exe"
@@ -430,51 +448,52 @@ test.c : tests\test.c
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /YX /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /YX /c
CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
- "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS"\
- /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /c
+ "ALL_INTERIOR_POINTERS" /D "GC_THREADS" \
+ /I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch" \
+ /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\gctest\Release/
CPP_SBRS=.\.
.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
MTL=mktyplib.exe
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /win32
-MTL_PROJ=/nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32
RSC=rc.exe
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
BSC32_SBRS= \
-
+
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/gctest.exe"
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:windows /incremental:no\
- /pdb:"$(OUTDIR)/gctest.pdb" /machine:I386 /out:"Release/gctest.exe"
+ /pdb:"$(OUTDIR)/gctest.pdb" /machine:I386 /out:"Release/gctest.exe"
LINK32_OBJS= \
".\gctest\Release\test.obj" \
".\Release\gc.lib"
@@ -501,7 +520,7 @@ INTDIR=.\gctest\Debug
ALL : "gc - Win32 Debug" ".\Debug\gctest.exe" ".\gctest\Debug\gctest.bsc"
-CLEAN :
+CLEAN :
-@erase ".\Debug\gctest.exe"
-@erase ".\gctest\Debug\gctest.bsc"
-@erase ".\gctest\Debug\gctest.map"
@@ -516,42 +535,42 @@ CLEAN :
CPP=cl.exe
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /FR /YX /c
CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
- /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR"$(INTDIR)/"\
- /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+ /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /FR"$(INTDIR)/"\
+ /I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\gctest\Debug/
CPP_SBRS=.\gctest\Debug/
.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
MTL=mktyplib.exe
# ADD BASE MTL /nologo /D "_DEBUG" /win32
# ADD MTL /nologo /D "_DEBUG" /win32
-MTL_PROJ=/nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32
RSC=rc.exe
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
BSC32_SBRS= \
".\gctest\Debug\test.sbr"
@@ -567,7 +586,7 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:windows /incremental:no\
/pdb:"$(OUTDIR)/gctest.pdb" /map:"$(INTDIR)/gctest.map" /debug /machine:I386\
- /out:"Debug/gctest.exe"
+ /out:"Debug/gctest.exe"
LINK32_OBJS= \
".\Debug\gc.lib" \
".\gctest\Debug\test.obj"
@@ -594,7 +613,7 @@ INTDIR=.\cord\Release
ALL : "gc - Win32 Release" ".\Release\de.exe"
-CLEAN :
+CLEAN :
-@erase ".\cord\Release\cordbscs.obj"
-@erase ".\cord\Release\cordxtra.obj"
-@erase ".\cord\Release\de.obj"
@@ -609,49 +628,49 @@ CPP=cl.exe
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "." /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
- "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c
+ /I./libatomic_ops/src "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c
CPP_OBJS=.\cord\Release/
CPP_SBRS=.\.
.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
MTL=mktyplib.exe
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /win32
-MTL_PROJ=/nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32
RSC=rc.exe
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
-RSC_PROJ=/l 0x809 /fo"$(INTDIR)/de_win.res" /d "NDEBUG"
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)/de_win.res" /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
BSC32_SBRS= \
-
+
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/de.exe"
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)/de.pdb"\
- /machine:I386 /out:"Release/de.exe"
+ /machine:I386 /out:"Release/de.exe"
LINK32_OBJS= \
".\cord\Release\cordbscs.obj" \
".\cord\Release\cordxtra.obj" \
@@ -682,7 +701,7 @@ INTDIR=.\cord\Debug
ALL : "gc - Win32 Debug" ".\Debug\de.exe"
-CLEAN :
+CLEAN :
-@erase ".\cord\Debug\cordbscs.obj"
-@erase ".\cord\Debug\cordxtra.obj"
-@erase ".\cord\Debug\de.obj"
@@ -702,49 +721,49 @@ CPP=cl.exe
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /I include /D "_DEBUG" /D "WIN32" /D\
"_WINDOWS" /D "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX\
- /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+ /I./libatomic_ops/src /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
CPP_OBJS=.\cord\Debug/
CPP_SBRS=.\.
.c{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_OBJS)}.obj:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.c{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cpp{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
.cxx{$(CPP_SBRS)}.sbr:
- $(CPP) $(CPP_PROJ) $<
+ $(CPP) $(CPP_PROJ) $<
MTL=mktyplib.exe
# ADD BASE MTL /nologo /D "_DEBUG" /win32
# ADD MTL /nologo /D "_DEBUG" /win32
-MTL_PROJ=/nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32
RSC=rc.exe
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
-RSC_PROJ=/l 0x809 /fo"$(INTDIR)/de_win.res" /d "_DEBUG"
+RSC_PROJ=/l 0x809 /fo"$(INTDIR)/de_win.res" /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
-BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
BSC32_SBRS= \
-
+
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/de.exe"
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib /nologo /subsystem:windows /incremental:yes\
- /pdb:"$(OUTDIR)/de.pdb" /debug /machine:I386 /out:"Debug/de.exe"
+ /pdb:"$(OUTDIR)/de.pdb" /debug /machine:I386 /out:"Debug/de.exe"
LINK32_OBJS= \
".\cord\Debug\cordbscs.obj" \
".\cord\Debug\cordxtra.obj" \
@@ -758,7 +777,7 @@ LINK32_OBJS= \
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
-!ENDIF
+!ENDIF
################################################################################
# Begin Target
@@ -770,7 +789,7 @@ LINK32_OBJS= \
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
-!ENDIF
+!ENDIF
################################################################################
# Begin Source File
@@ -786,12 +805,12 @@ DEP_CPP_RECLA=\
".\include\private\gc_priv.h"\
".\include\gc_cpp.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_RECLA=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\gc_cpp.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
@@ -807,19 +826,19 @@ DEP_CPP_RECLA=\
".\include\private\gc_priv.h"\
".\include\gc_cpp.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_RECLA=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\gc_cpp.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
".\Debug\gc_cpp.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -835,12 +854,12 @@ DEP_CPP_RECLA=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_RECLA=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\reclaim.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
@@ -855,19 +874,19 @@ DEP_CPP_RECLA=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_RECLA=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\reclaim.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
".\Debug\reclaim.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
@@ -885,7 +904,7 @@ DEP_CPP_OS_DE=\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\STAT.H"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_OS_DE=\
".\il\PCR_IL.h"\
".\mm\PCR_MM.h"\
@@ -893,7 +912,7 @@ NODEP_CPP_OS_DE=\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
".\vd\PCR_VD.h"\
-
+
".\Release\os_dep.obj" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
@@ -909,7 +928,7 @@ DEP_CPP_OS_DE=\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\STAT.H"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_OS_DE=\
".\il\PCR_IL.h"\
".\mm\PCR_MM.h"\
@@ -917,14 +936,14 @@ NODEP_CPP_OS_DE=\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
".\vd\PCR_VD.h"\
-
+
".\Debug\os_dep.obj" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
".\Debug\os_dep.sbr" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -940,13 +959,13 @@ DEP_CPP_MISC_=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MISC_=\
".\il\PCR_IL.h"\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\misc.obj" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
@@ -961,20 +980,20 @@ DEP_CPP_MISC_=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MISC_=\
".\il\PCR_IL.h"\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\misc.obj" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
".\Debug\misc.sbr" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -990,12 +1009,12 @@ DEP_CPP_MARK_=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MARK_=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\mark_rts.obj" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
@@ -1010,19 +1029,19 @@ DEP_CPP_MARK_=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MARK_=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\mark_rts.obj" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
".\Debug\mark_rts.sbr" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1038,12 +1057,12 @@ DEP_CPP_MACH_=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MACH_=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\mach_dep.obj" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
@@ -1058,19 +1077,19 @@ DEP_CPP_MACH_=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MACH_=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\mach_dep.obj" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
".\Debug\mach_dep.sbr" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1086,12 +1105,12 @@ DEP_CPP_HEADE=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_HEADE=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\headers.obj" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
@@ -1106,19 +1125,19 @@ DEP_CPP_HEADE=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_HEADE=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\headers.obj" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
".\Debug\headers.sbr" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1134,12 +1153,12 @@ DEP_CPP_ALLOC=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_ALLOC=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\alloc.obj" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
@@ -1154,19 +1173,19 @@ DEP_CPP_ALLOC=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_ALLOC=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\alloc.obj" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
".\Debug\alloc.sbr" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1182,12 +1201,12 @@ DEP_CPP_ALLCH=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_ALLCH=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\allchblk.obj" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
@@ -1202,19 +1221,19 @@ DEP_CPP_ALLCH=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_ALLCH=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\allchblk.obj" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
".\Debug\allchblk.sbr" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1230,12 +1249,12 @@ DEP_CPP_STUBB=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_STUBB=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\stubborn.obj" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
@@ -1250,19 +1269,19 @@ DEP_CPP_STUBB=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_STUBB=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\stubborn.obj" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
".\Debug\stubborn.sbr" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1278,12 +1297,12 @@ DEP_CPP_OBJ_M=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_OBJ_M=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\obj_map.obj" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
@@ -1298,19 +1317,19 @@ DEP_CPP_OBJ_M=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_OBJ_M=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\obj_map.obj" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
".\Debug\obj_map.sbr" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1326,12 +1345,12 @@ DEP_CPP_NEW_H=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_NEW_H=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\new_hblk.obj" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
@@ -1346,19 +1365,19 @@ DEP_CPP_NEW_H=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_NEW_H=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\new_hblk.obj" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
".\Debug\new_hblk.sbr" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1374,14 +1393,15 @@ DEP_CPP_MARK_C=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_pmark.h"\
".\include\gc_mark.h"\
+ ".\include\gc_disclaim.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MARK_C=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\mark.obj" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
@@ -1396,21 +1416,22 @@ DEP_CPP_MARK_C=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_pmark.h"\
".\include\gc_mark.h"\
+ ".\include\gc_disclaim.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MARK_C=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\mark.obj" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
".\Debug\mark.sbr" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1426,12 +1447,12 @@ DEP_CPP_MALLO=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MALLO=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\malloc.obj" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
@@ -1446,19 +1467,19 @@ DEP_CPP_MALLO=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MALLO=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\malloc.obj" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
".\Debug\malloc.sbr" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1474,12 +1495,12 @@ DEP_CPP_MALLX=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MALLX=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\mallocx.obj" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
@@ -1494,19 +1515,19 @@ DEP_CPP_MALLX=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_MALLX=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\mallocx.obj" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
".\Debug\mallocx.sbr" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1522,14 +1543,15 @@ DEP_CPP_FINAL=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_pmark.h"\
".\include\gc_mark.h"\
+ ".\include\gc_disclaim.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_FINAL=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\finalize.obj" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
@@ -1544,21 +1566,22 @@ DEP_CPP_FINAL=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_pmark.h"\
".\include\gc_mark.h"\
+ ".\include\gc_disclaim.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_FINAL=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\finalize.obj" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
".\Debug\finalize.sbr" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1574,12 +1597,12 @@ DEP_CPP_DBG_M=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_DBG_M=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\dbg_mlc.obj" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
@@ -1594,19 +1617,67 @@ DEP_CPP_DBG_M=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_DBG_M=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\dbg_mlc.obj" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
".\Debug\dbg_mlc.sbr" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
-!ENDIF
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\fnlz_mlc.c
+
+!IF "$(CFG)" == "gc - Win32 Release"
+
+DEP_CPP_DBG_M=\
+ ".\include\private\gcconfig.h"\
+ ".\include\gc.h"\
+ ".\include\private\gc_hdrs.h"\
+ ".\include\private\gc_priv.h"\
+ {$(INCLUDE)}"\sys\TYPES.H"\
+
+NODEP_CPP_DBG_M=\
+ ".\th\PCR_Th.h"\
+ ".\th\PCR_ThCrSec.h"\
+ ".\th\PCR_ThCtl.h"\
+
+
+".\Release\fnlz_mlc.obj" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
+
+".\Release\fnlz_mlc.sbr" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "gc - Win32 Debug"
+
+DEP_CPP_DBG_M=\
+ ".\include\private\gcconfig.h"\
+ ".\include\gc.h"\
+ ".\include\private\gc_hdrs.h"\
+ ".\include\private\gc_priv.h"\
+ {$(INCLUDE)}"\sys\TYPES.H"\
+
+NODEP_CPP_DBG_M=\
+ ".\th\PCR_Th.h"\
+ ".\th\PCR_ThCrSec.h"\
+ ".\th\PCR_ThCtl.h"\
+
+
+".\Debug\fnlz_mlc.obj" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
+
+".\Debug\fnlz_mlc.sbr" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
+
+
+!ENDIF
# End Source File
################################################################################
@@ -1622,12 +1693,12 @@ DEP_CPP_BLACK=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_BLACK=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\blacklst.obj" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
@@ -1642,19 +1713,19 @@ DEP_CPP_BLACK=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_BLACK=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\blacklst.obj" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
".\Debug\blacklst.sbr" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1670,15 +1741,16 @@ DEP_CPP_TYPD_=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_pmark.h"\
".\include\gc_mark.h"\
+ ".\include\gc_disclaim.h"\
".\include\private\gc_priv.h"\
".\include\gc_typed.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_TYPD_=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\typd_mlc.obj" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
@@ -1693,22 +1765,23 @@ DEP_CPP_TYPD_=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_pmark.h"\
".\include\gc_mark.h"\
+ ".\include\gc_disclaim.h"\
".\include\private\gc_priv.h"\
".\include\gc_typed.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_TYPD_=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\typd_mlc.obj" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
".\Debug\typd_mlc.sbr" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1724,14 +1797,15 @@ DEP_CPP_PTR_C=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_pmark.h"\
".\include\gc_mark.h"\
+ ".\include\gc_disclaim.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_PTR_C=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\ptr_chck.obj" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
@@ -1746,21 +1820,22 @@ DEP_CPP_PTR_C=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_pmark.h"\
".\include\gc_mark.h"\
+ ".\include\gc_disclaim.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_PTR_C=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\ptr_chck.obj" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
".\Debug\ptr_chck.sbr" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1777,14 +1852,14 @@ DEP_CPP_DYN_L=\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\STAT.H"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_DYN_L=\
".\il\PCR_IL.h"\
".\mm\PCR_MM.h"\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\dyn_load.obj" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
@@ -1800,21 +1875,21 @@ DEP_CPP_DYN_L=\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\STAT.H"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_DYN_L=\
".\il\PCR_IL.h"\
".\mm\PCR_MM.h"\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\dyn_load.obj" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
".\Debug\dyn_load.sbr" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -1830,12 +1905,12 @@ DEP_CPP_WIN32=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_WIN32=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\win32_threads.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
@@ -1850,19 +1925,69 @@ DEP_CPP_WIN32=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_WIN32=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\win32_threads.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
".\Debug\win32_threads.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
-!ENDIF
+!ENDIF
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\extra\msvc_dbg.c
+
+!IF "$(CFG)" == "gc - Win32 Release"
+
+DEP_CPP_WIN32=\
+ ".\include\private\gcconfig.h"\
+ ".\include\gc.h"\
+ ".\include\private\gc_hdrs.h"\
+ ".\include\private\gc_priv.h"\
+ ".\include\private\msvc_dbg.h"\
+ {$(INCLUDE)}"\sys\TYPES.H"\
+
+NODEP_CPP_WIN32=\
+ ".\th\PCR_Th.h"\
+ ".\th\PCR_ThCrSec.h"\
+ ".\th\PCR_ThCtl.h"\
+
+
+".\Release\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+".\Release\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "gc - Win32 Debug"
+
+DEP_CPP_WIN32=\
+ ".\include\private\gcconfig.h"\
+ ".\include\gc.h"\
+ ".\include\private\gc_hdrs.h"\
+ ".\include\private\gc_priv.h"\
+ ".\include\private\msvc_dbg.h"\
+ {$(INCLUDE)}"\sys\TYPES.H"\
+
+NODEP_CPP_WIN32=\
+ ".\th\PCR_Th.h"\
+ ".\th\PCR_ThCrSec.h"\
+ ".\th\PCR_ThCtl.h"\
+
+
+".\Debug\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+".\Debug\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
+
+
+!ENDIF
# End Source File
################################################################################
@@ -1878,12 +2003,12 @@ DEP_CPP_CHECK=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_CHECK=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Release\checksums.obj" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
@@ -1898,19 +2023,19 @@ DEP_CPP_CHECK=\
".\include\private\gc_hdrs.h"\
".\include\private\gc_priv.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_CHECK=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
".\Debug\checksums.obj" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
".\Debug\checksums.sbr" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
# End Target
@@ -1924,7 +2049,7 @@ NODEP_CPP_CHECK=\
!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
-!ENDIF
+!ENDIF
################################################################################
# Begin Project Dependency
@@ -1933,15 +2058,15 @@ NODEP_CPP_CHECK=\
!IF "$(CFG)" == "gctest - Win32 Release"
-"gc - Win32 Release" :
- $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Release"
+"gc - Win32 Release" :
+ $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Release"
!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
-"gc - Win32 Debug" :
- $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Debug"
+"gc - Win32 Debug" :
+ $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Debug"
-!ENDIF
+!ENDIF
# End Project Dependency
################################################################################
@@ -1955,12 +2080,12 @@ DEP_CPP_TEST_=\
".\include\private\gc_priv.h"\
".\include\gc_typed.h"\
{$(INCLUDE)}"\sys\TYPES.H"\
-
+
NODEP_CPP_TEST_=\
".\th\PCR_Th.h"\
".\th\PCR_ThCrSec.h"\
".\th\PCR_ThCtl.h"\
-
+
!IF "$(CFG)" == "gctest - Win32 Release"
@@ -1976,7 +2101,7 @@ NODEP_CPP_TEST_=\
".\gctest\Debug\test.sbr" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
-!ENDIF
+!ENDIF
# End Source File
# End Target
@@ -1990,7 +2115,7 @@ NODEP_CPP_TEST_=\
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-!ENDIF
+!ENDIF
################################################################################
# Begin Project Dependency
@@ -1999,30 +2124,30 @@ NODEP_CPP_TEST_=\
!IF "$(CFG)" == "cord - Win32 Release"
-"gc - Win32 Release" :
- $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Release"
+"gc - Win32 Release" :
+ $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Release"
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
-"gc - Win32 Debug" :
- $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Debug"
+"gc - Win32 Debug" :
+ $(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Debug"
-!ENDIF
+!ENDIF
# End Project Dependency
################################################################################
# Begin Source File
-SOURCE=.\cord\de_win.c
+SOURCE=.\cord\tests\de_win.c
DEP_CPP_DE_WI=\
".\include\cord.h"\
- ".\cord\de_cmds.h"\
- ".\cord\de_win.h"\
- ".\include\private\cord_pos.h"\
-
+ ".\cord\tests\de_cmds.h"\
+ ".\cord\tests\de_win.h"\
+ ".\include\cord_pos.h"\
+
NODEP_CPP_DE_WI=\
".\include\gc.h"\
-
+
!IF "$(CFG)" == "cord - Win32 Release"
@@ -2038,22 +2163,22 @@ NODEP_CPP_DE_WI=\
$(CPP) $(CPP_PROJ) $(SOURCE)
-!ENDIF
+!ENDIF
# End Source File
################################################################################
# Begin Source File
-SOURCE=.\cord\de.c
+SOURCE=.\cord\tests\de.c
DEP_CPP_DE_C2e=\
".\include\cord.h"\
- ".\cord\de_cmds.h"\
- ".\cord\de_win.h"\
- ".\include\private\cord_pos.h"\
-
+ ".\cord\tests\de_cmds.h"\
+ ".\cord\tests\de_win.h"\
+ ".\include\cord_pos.h"\
+
NODEP_CPP_DE_C2e=\
".\include\gc.h"\
-
+
!IF "$(CFG)" == "cord - Win32 Release"
@@ -2069,7 +2194,7 @@ NODEP_CPP_DE_C2e=\
$(CPP) $(CPP_PROJ) $(SOURCE)
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -2079,11 +2204,11 @@ SOURCE=.\cord\cordxtra.c
DEP_CPP_CORDX=\
".\include\cord.h"\
".\include\ec.h"\
- ".\include\private\cord_pos.h"\
-
+ ".\include\cord_pos.h"\
+
NODEP_CPP_CORDX=\
".\include\gc.h"\
-
+
!IF "$(CFG)" == "cord - Win32 Release"
@@ -2099,7 +2224,7 @@ NODEP_CPP_CORDX=\
$(CPP) $(CPP_PROJ) $(SOURCE)
-!ENDIF
+!ENDIF
# End Source File
################################################################################
@@ -2108,11 +2233,11 @@ NODEP_CPP_CORDX=\
SOURCE=.\cord\cordbscs.c
DEP_CPP_CORDB=\
".\include\cord.h"\
- ".\include\private\cord_pos.h"\
-
+ ".\include\cord_pos.h"\
+
NODEP_CPP_CORDB=\
".\include\gc.h"\
-
+
!IF "$(CFG)" == "cord - Win32 Release"
@@ -2128,13 +2253,13 @@ NODEP_CPP_CORDB=\
$(CPP) $(CPP_PROJ) $(SOURCE)
-!ENDIF
+!ENDIF
# End Source File
################################################################################
# Begin Source File
-SOURCE=.\cord\de_win.RC
+SOURCE=.\cord\tests\de_win.rc
!IF "$(CFG)" == "cord - Win32 Release"
@@ -2150,7 +2275,7 @@ SOURCE=.\cord\de_win.RC
$(RSC) /l 0x809 /fo"$(INTDIR)/de_win.res" /i "cord" /d "_DEBUG" $(SOURCE)
-!ENDIF
+!ENDIF
# End Source File
# End Target
diff --git a/boehm-gc/gc_cpp.cc b/boehm-gc/gc_cpp.cc
index f8b803a8baa..9f64b7481b6 100644
--- a/boehm-gc/gc_cpp.cc
+++ b/boehm-gc/gc_cpp.cc
@@ -1,15 +1,14 @@
-/*************************************************************************
-Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
-THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Last modified on Sat Nov 19 19:31:14 PST 1994 by ellis
- on Sat Jun 8 15:10:00 PST 1994 by boehm
-
-Permission is hereby granted to copy this code for any purpose,
-provided the above notices are retained on all copies.
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to copy this code for any purpose,
+ * provided the above notices are retained on all copies.
+ */
+/*************************************************************************
This implementation module for gc_c++.h provides an implementation of
the global operators "new" and "delete" that calls the Boehm
allocator. All objects allocated by this implementation will be
@@ -18,44 +17,72 @@ non-collectable but part of the root set of the collector.
You should ensure (using implementation-dependent techniques) that the
linker finds this module before the library that defines the default
built-in "new" and "delete".
+**************************************************************************/
-Authors: John R. Ellis and Jesse Hull
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
-**************************************************************************/
-/* Boehm, December 20, 1994 7:26 pm PST */
+#ifndef GC_BUILD
+# define GC_BUILD
+#endif
#include "gc_cpp.h"
-void* operator new( size_t size ) {
- return GC_MALLOC_UNCOLLECTABLE( size );}
-
-void operator delete( void* obj ) {
- GC_FREE( obj );}
-
-#ifdef GC_OPERATOR_NEW_ARRAY
+#if !defined(GC_NEW_DELETE_NEED_THROW) && defined(__GNUC__) \
+ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
+# define GC_NEW_DELETE_NEED_THROW
+#endif
+
+#ifdef GC_NEW_DELETE_NEED_THROW
+# include <new> /* for std::bad_alloc */
+# define GC_DECL_NEW_THROW throw(std::bad_alloc)
+# define GC_DECL_DELETE_THROW throw()
+#else
+# define GC_DECL_NEW_THROW /* empty */
+# define GC_DECL_DELETE_THROW /* empty */
+#endif /* !GC_NEW_DELETE_NEED_THROW */
+
+void* operator new( size_t size ) GC_DECL_NEW_THROW {
+ return GC_MALLOC_UNCOLLECTABLE(size);
+}
-void* operator new[]( size_t size ) {
- return GC_MALLOC_UNCOLLECTABLE( size );}
-
-void operator delete[]( void* obj ) {
- GC_FREE( obj );}
+#if !defined(__CYGWIN__)
+ void operator delete( void* obj ) GC_DECL_DELETE_THROW {
+ GC_FREE(obj);
+ }
+#endif /* !__CYGWIN__ */
+
+#ifdef GC_OPERATOR_NEW_ARRAY
+ void* operator new[]( size_t size ) GC_DECL_NEW_THROW {
+ return GC_MALLOC_UNCOLLECTABLE(size);
+ }
+ void operator delete[]( void* obj ) GC_DECL_DELETE_THROW {
+ GC_FREE(obj);
+ }
#endif /* GC_OPERATOR_NEW_ARRAY */
#ifdef _MSC_VER
-// This new operator is used by VC++ in case of Debug builds !
-void* operator new( size_t size,
- int ,//nBlockUse,
- const char * szFileName,
- int nLine )
-{
-#ifndef GC_DEBUG
- return GC_malloc_uncollectable( size );
-#else
- return GC_debug_malloc_uncollectable(size, szFileName, nLine);
-#endif
-}
+ // This new operator is used by VC++ in case of Debug builds!
+ void* operator new( size_t size, int /* nBlockUse */,
+ const char * szFileName, int nLine ) GC_DECL_NEW_THROW
+ {
+# ifndef GC_DEBUG
+ return GC_malloc_uncollectable(size);
+# else
+ return GC_debug_malloc_uncollectable(size, szFileName, nLine);
+# endif
+ }
-#endif /* _MSC_VER */
+# if _MSC_VER > 1020
+ // This new operator is used by VC++ 7.0 and later in Debug builds.
+ void* operator new[]( size_t size, int nBlockUse,
+ const char* szFileName, int nLine ) GC_DECL_NEW_THROW
+ {
+ return operator new(size, nBlockUse, szFileName, nLine);
+ }
+# endif
+#endif /* _MSC_VER */
diff --git a/boehm-gc/gc_dlopen.c b/boehm-gc/gc_dlopen.c
index 4c690edcfe4..0da82278600 100644
--- a/boehm-gc/gc_dlopen.c
+++ b/boehm-gc/gc_dlopen.c
@@ -11,81 +11,90 @@
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
- *
- * Original author: Bill Janssen
- * Heavily modified by Hans Boehm and others
- */
-
-/*
- * This used to be in dyn_load.c. It was extracted into a separate file
- * to avoid having to link against libdl.{a,so} if the client doesn't call
- * dlopen. Of course this fails if the collector is in a dynamic
- * library. -HB
*/
#include "private/gc_priv.h"
-# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) \
- || defined(GC_SOLARIS_THREADS)
+/* This used to be in dyn_load.c. It was extracted into a separate */
+/* file to avoid having to link against libdl.{a,so} if the client */
+/* doesn't call dlopen. Of course this fails if the collector is in */
+/* a dynamic library. -HB */
+#if defined(GC_PTHREADS) && !defined(GC_NO_DLOPEN)
-# if defined(dlopen) && !defined(GC_USE_LD_WRAP)
- /* To support various threads pkgs, gc.h interposes on dlopen by */
- /* defining "dlopen" to be "GC_dlopen", which is implemented below. */
- /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */
- /* real system dlopen() in their implementation. We first remove */
- /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
-# undef dlopen
-# endif
+#undef GC_MUST_RESTORE_REDEFINED_DLOPEN
+#if defined(dlopen) && !defined(GC_USE_LD_WRAP)
+ /* To support various threads pkgs, gc.h interposes on dlopen by */
+ /* defining "dlopen" to be "GC_dlopen", which is implemented below. */
+ /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */
+ /* real system dlopen() in their implementation. We first remove */
+ /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
+# undef dlopen
+# define GC_MUST_RESTORE_REDEFINED_DLOPEN
+#endif
- /* Make sure we're not in the middle of a collection, and make */
- /* sure we don't start any. Returns previous value of GC_dont_gc. */
- /* This is invoked prior to a dlopen call to avoid synchronization */
- /* issues. We can't just acquire the allocation lock, since startup */
- /* code in dlopen may try to allocate. */
- /* This solution risks heap growth in the presence of many dlopen */
- /* calls in either a multithreaded environment, or if the library */
- /* initialization code allocates substantial amounts of GC'ed memory. */
- /* But I don't know of a better solution. */
- static void disable_gc_for_dlopen()
+/* Make sure we're not in the middle of a collection, and make sure we */
+/* don't start any. This is invoked prior to a dlopen call to avoid */
+/* synchronization issues. We can't just acquire the allocation lock, */
+/* since startup code in dlopen may try to allocate. This solution */
+/* risks heap growth (or, even, heap overflow) in the presence of many */
+/* dlopen calls in either a multi-threaded environment, or if the */
+/* library initialization code allocates substantial amounts of GC'ed */
+/* memory. */
+#ifndef USE_PROC_FOR_LIBRARIES
+ static void disable_gc_for_dlopen(void)
{
+ DCL_LOCK_STATE;
LOCK();
while (GC_incremental && GC_collection_in_progress()) {
- GC_collect_a_little_inner(1000);
+ GC_collect_a_little_inner(1000);
}
++GC_dont_gc;
UNLOCK();
}
+#endif
- /* Redefine dlopen to guarantee mutual exclusion with */
- /* GC_register_dynamic_libraries. */
- /* Should probably happen for other operating systems, too. */
-
-#include <dlfcn.h>
+/* Redefine dlopen to guarantee mutual exclusion with */
+/* GC_register_dynamic_libraries. Should probably happen for */
+/* other operating systems, too. */
+/* This is similar to WRAP/REAL_FUNC() in pthread_support.c. */
#ifdef GC_USE_LD_WRAP
- void * __wrap_dlopen(const char *path, int mode)
+# define WRAP_DLFUNC(f) __wrap_##f
+# define REAL_DLFUNC(f) __real_##f
+ void * REAL_DLFUNC(dlopen)(const char *, int);
#else
- void * GC_dlopen(path, mode)
- GC_CONST char * path;
- int mode;
+# define WRAP_DLFUNC(f) GC_##f
+# define REAL_DLFUNC(f) f
#endif
+
+GC_API void * WRAP_DLFUNC(dlopen)(const char *path, int mode)
{
- void * result;
-
-# ifndef USE_PROC_FOR_LIBRARIES
- disable_gc_for_dlopen();
-# endif
-# ifdef GC_USE_LD_WRAP
- result = (void *)__real_dlopen(path, mode);
-# else
- result = dlopen(path, mode);
-# endif
-# ifndef USE_PROC_FOR_LIBRARIES
- GC_enable(); /* undoes disable_gc_for_dlopen */
-# endif
- return(result);
+ void * result;
+
+# ifndef USE_PROC_FOR_LIBRARIES
+ /* Disable collections. This solution risks heap growth (or, */
+ /* even, heap overflow) but there seems no better solutions. */
+ disable_gc_for_dlopen();
+# endif
+ result = REAL_DLFUNC(dlopen)(path, mode);
+# ifndef USE_PROC_FOR_LIBRARIES
+ GC_enable(); /* undoes disable_gc_for_dlopen */
+# endif
+ return(result);
}
-# endif /* GC_PTHREADS || GC_SOLARIS_THREADS ... */
+#ifdef GC_USE_LD_WRAP
+ /* Define GC_ function as an alias for the plain one, which will be */
+ /* intercepted. This allows files which include gc.h, and hence */
+ /* generate references to the GC_ symbol, to see the right symbol. */
+ GC_API void *GC_dlopen(const char *path, int mode)
+ {
+ return dlopen(path, mode);
+ }
+#endif /* GC_USE_LD_WRAP */
+#ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
+# define dlopen GC_dlopen
+#endif
+#endif /* GC_PTHREADS && !GC_NO_DLOPEN */
diff --git a/boehm-gc/gcc_support.c b/boehm-gc/gcc_support.c
deleted file mode 100644
index e8a7b8201db..00000000000
--- a/boehm-gc/gcc_support.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/***************************************************************************
-
-Interface between g++ and Boehm GC
-
- Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to copy this code for any purpose,
- provided the above notices are retained on all copies.
-
- Last modified on Sun Jul 16 23:21:14 PDT 1995 by ellis
-
-This module provides runtime support for implementing the
-Ellis/Detlefs GC proposal, "Safe, Efficient Garbage Collection for
-C++", within g++, using its -fgc-keyword extension. It defines
-versions of __builtin_new, __builtin_new_gc, __builtin_vec_new,
-__builtin_vec_new_gc, __builtin_delete, and __builtin_vec_delete that
-invoke the Bohem GC. It also implements the WeakPointer.h interface.
-
-This module assumes the following configuration options of the Boehm GC:
-
- -DALL_INTERIOR_POINTERS
- -DDONT_ADD_BYTE_AT_END
-
-This module adds its own required padding to the end of objects to
-support C/C++ "one-past-the-object" pointer semantics.
-
-****************************************************************************/
-
-#include <stddef.h>
-#include "gc.h"
-
-#if defined(__STDC__)
-# define PROTO( args ) args
-#else
-# define PROTO( args ) ()
-# endif
-
-#define BITSPERBYTE 8
- /* What's the portable way to do this? */
-
-
-typedef void (*vfp) PROTO(( void ));
-extern vfp __new_handler;
-extern void __default_new_handler PROTO(( void ));
-
-
-/* A destructor_proc is the compiler generated procedure representing a
-C++ destructor. The "flag" argument is a hidden argument following some
-compiler convention. */
-
-typedef (*destructor_proc) PROTO(( void* this, int flag ));
-
-
-/***************************************************************************
-
-A BI_header is the header the compiler adds to the front of
-new-allocated arrays of objects with destructors. The header is
-padded out to a double, because that's what the compiler does to
-ensure proper alignment of array elements on some architectures.
-
-int NUM_ARRAY_ELEMENTS (void* o)
- returns the number of array elements for array object o.
-
-char* FIRST_ELEMENT_P (void* o)
- returns the address of the first element of array object o.
-
-***************************************************************************/
-
-typedef struct BI_header {
- int nelts;
- char padding [sizeof( double ) - sizeof( int )];
- /* Better way to do this? */
-} BI_header;
-
-#define NUM_ARRAY_ELEMENTS( o ) \
- (((BI_header*) o)->nelts)
-
-#define FIRST_ELEMENT_P( o ) \
- ((char*) o + sizeof( BI_header ))
-
-
-/***************************************************************************
-
-The __builtin_new routines add a descriptor word to the end of each
-object. The descriptor serves two purposes.
-
-First, the descriptor acts as padding, implementing C/C++ pointer
-semantics. C and C++ allow a valid array pointer to be incremented
-one past the end of an object. The extra padding ensures that the
-collector will recognize that such a pointer points to the object and
-not the next object in memory.
-
-Second, the descriptor stores three extra pieces of information,
-whether an object has a registered finalizer (destructor), whether it
-may have any weak pointers referencing it, and for collectible arrays,
-the element size of the array. The element size is required for the
-array's finalizer to iterate through the elements of the array. (An
-alternative design would have the compiler generate a finalizer
-procedure for each different array type. But given the overhead of
-finalization, there isn't any efficiency to be gained by that.)
-
-The descriptor must be added to non-collectible as well as collectible
-objects, since the Ellis/Detlefs proposal allows "pointer to gc T" to
-be assigned to a "pointer to T", which could then be deleted. Thus,
-__builtin_delete must determine at runtime whether an object is
-collectible, whether it has weak pointers referencing it, and whether
-it may have a finalizer that needs unregistering. Though
-GC_REGISTER_FINALIZER doesn't care if you ask it to unregister a
-finalizer for an object that doesn't have one, it is a non-trivial
-procedure that does a hash look-up, etc. The descriptor trades a
-little extra space for a significant increase in time on the fast path
-through delete. (A similar argument applies to
-GC_UNREGISTER_DISAPPEARING_LINK).
-
-For non-array types, the space for the descriptor could be shrunk to a
-single byte for storing the "has finalizer" flag. But this would save
-space only on arrays of char (whose size is not a multiple of the word
-size) and structs whose largest member is less than a word in size
-(very infrequent). And it would require that programmers actually
-remember to call "delete[]" instead of "delete" (which they should,
-but there are probably lots of buggy programs out there). For the
-moment, the space savings seems not worthwhile, especially considering
-that the Boehm GC is already quite space competitive with other
-malloc's.
-
-
-Given a pointer o to the base of an object:
-
-Descriptor* DESCRIPTOR (void* o)
- returns a pointer to the descriptor for o.
-
-The implementation of descriptors relies on the fact that the GC
-implementation allocates objects in units of the machine's natural
-word size (e.g. 32 bits on a SPARC, 64 bits on an Alpha).
-
-**************************************************************************/
-
-typedef struct Descriptor {
- unsigned has_weak_pointers: 1;
- unsigned has_finalizer: 1;
- unsigned element_size: BITSPERBYTE * sizeof( unsigned ) - 2;
-} Descriptor;
-
-#define DESCRIPTOR( o ) \
- ((Descriptor*) ((char*)(o) + GC_size( o ) - sizeof( Descriptor )))
-
-
-/**************************************************************************
-
-Implementations of global operator new() and operator delete()
-
-***************************************************************************/
-
-
-void* __builtin_new( size )
- size_t size;
- /*
- For non-gc non-array types, the compiler generates calls to
- __builtin_new, which allocates non-collected storage via
- GC_MALLOC_UNCOLLECTABLE. This ensures that the non-collected
- storage will be part of the collector's root set, required by the
- Ellis/Detlefs semantics. */
-{
- vfp handler = __new_handler ? __new_handler : __default_new_handler;
-
- while (1) {
- void* o = GC_MALLOC_UNCOLLECTABLE( size + sizeof( Descriptor ) );
- if (o != 0) return o;
- (*handler) ();}}
-
-
-void* __builtin_vec_new( size )
- size_t size;
- /*
- For non-gc array types, the compiler generates calls to
- __builtin_vec_new. */
-{
- return __builtin_new( size );}
-
-
-void* __builtin_new_gc( size )
- size_t size;
- /*
- For gc non-array types, the compiler generates calls to
- __builtin_new_gc, which allocates collected storage via
- GC_MALLOC. */
-{
- vfp handler = __new_handler ? __new_handler : __default_new_handler;
-
- while (1) {
- void* o = GC_MALLOC( size + sizeof( Descriptor ) );
- if (o != 0) return o;
- (*handler) ();}}
-
-
-void* __builtin_new_gc_a( size )
- size_t size;
- /*
- For non-pointer-containing gc non-array types, the compiler
- generates calls to __builtin_new_gc_a, which allocates collected
- storage via GC_MALLOC_ATOMIC. */
-{
- vfp handler = __new_handler ? __new_handler : __default_new_handler;
-
- while (1) {
- void* o = GC_MALLOC_ATOMIC( size + sizeof( Descriptor ) );
- if (o != 0) return o;
- (*handler) ();}}
-
-
-void* __builtin_vec_new_gc( size )
- size_t size;
- /*
- For gc array types, the compiler generates calls to
- __builtin_vec_new_gc. */
-{
- return __builtin_new_gc( size );}
-
-
-void* __builtin_vec_new_gc_a( size )
- size_t size;
- /*
- For non-pointer-containing gc array types, the compiler generates
- calls to __builtin_vec_new_gc_a. */
-{
- return __builtin_new_gc_a( size );}
-
-
-static void call_destructor( o, data )
- void* o;
- void* data;
- /*
- call_destructor is the GC finalizer proc registered for non-array
- gc objects with destructors. Its client data is the destructor
- proc, which it calls with the magic integer 2, a special flag
- obeying the compiler convention for destructors. */
-{
- ((destructor_proc) data)( o, 2 );}
-
-
-void* __builtin_new_gc_dtor( o, d )
- void* o;
- destructor_proc d;
- /*
- The compiler generates a call to __builtin_new_gc_dtor to register
- the destructor "d" of a non-array gc object "o" as a GC finalizer.
- The destructor is registered via
- GC_REGISTER_FINALIZER_IGNORE_SELF, which causes the collector to
- ignore pointers from the object to itself when determining when
- the object can be finalized. This is necessary due to the self
- pointers used in the internal representation of multiply-inherited
- objects. */
-{
- Descriptor* desc = DESCRIPTOR( o );
-
- GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_destructor, d, 0, 0 );
- desc->has_finalizer = 1;}
-
-
-static void call_array_destructor( o, data )
- void* o;
- void* data;
- /*
- call_array_destructor is the GC finalizer proc registered for gc
- array objects whose elements have destructors. Its client data is
- the destructor proc. It iterates through the elements of the
- array in reverse order, calling the destructor on each. */
-{
- int num = NUM_ARRAY_ELEMENTS( o );
- Descriptor* desc = DESCRIPTOR( o );
- size_t size = desc->element_size;
- char* first_p = FIRST_ELEMENT_P( o );
- char* p = first_p + (num - 1) * size;
-
- if (num > 0) {
- while (1) {
- ((destructor_proc) data)( p, 2 );
- if (p == first_p) break;
- p -= size;}}}
-
-
-void* __builtin_vec_new_gc_dtor( first_elem, d, element_size )
- void* first_elem;
- destructor_proc d;
- size_t element_size;
- /*
- The compiler generates a call to __builtin_vec_new_gc_dtor to
- register the destructor "d" of a gc array object as a GC
- finalizer. "first_elem" points to the first element of the array,
- *not* the beginning of the object (this makes the generated call
- to this function smaller). The elements of the array are of size
- "element_size". The destructor is registered as in
- _builtin_new_gc_dtor. */
-{
- void* o = (char*) first_elem - sizeof( BI_header );
- Descriptor* desc = DESCRIPTOR( o );
-
- GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_array_destructor, d, 0, 0 );
- desc->element_size = element_size;
- desc->has_finalizer = 1;}
-
-
-void __builtin_delete( o )
- void* o;
- /*
- The compiler generates calls to __builtin_delete for operator
- delete(). The GC currently requires that any registered
- finalizers be unregistered before explicitly freeing an object.
- If the object has any weak pointers referencing it, we can't
- actually free it now. */
-{
- if (o != 0) {
- Descriptor* desc = DESCRIPTOR( o );
- if (desc->has_finalizer) GC_REGISTER_FINALIZER( o, 0, 0, 0, 0 );
- if (! desc->has_weak_pointers) GC_FREE( o );}}
-
-
-void __builtin_vec_delete( o )
- void* o;
- /*
- The compiler generates calls to __builitn_vec_delete for operator
- delete[](). */
-{
- __builtin_delete( o );}
-
-
-/**************************************************************************
-
-Implementations of the template class WeakPointer from WeakPointer.h
-
-***************************************************************************/
-
-typedef struct WeakPointer {
- void* pointer;
-} WeakPointer;
-
-
-void* _WeakPointer_New( t )
- void* t;
-{
- if (t == 0) {
- return 0;}
- else {
- void* base = GC_base( t );
- WeakPointer* wp =
- (WeakPointer*) GC_MALLOC_ATOMIC( sizeof( WeakPointer ) );
- Descriptor* desc = DESCRIPTOR( base );
-
- wp->pointer = t;
- desc->has_weak_pointers = 1;
- GC_general_register_disappearing_link( &wp->pointer, base );
- return wp;}}
-
-
-static void* PointerWithLock( wp )
- WeakPointer* wp;
-{
- if (wp == 0 || wp->pointer == 0) {
- return 0;}
- else {
- return (void*) wp->pointer;}}
-
-
-void* _WeakPointer_Pointer( wp )
- WeakPointer* wp;
-{
- return (void*) GC_call_with_alloc_lock( PointerWithLock, wp );}
-
-
-typedef struct EqualClosure {
- WeakPointer* wp1;
- WeakPointer* wp2;
-} EqualClosure;
-
-
-static void* EqualWithLock( ec )
- EqualClosure* ec;
-{
- if (ec->wp1 == 0 || ec->wp2 == 0) {
- return (void*) (ec->wp1 == ec->wp2);}
- else {
- return (void*) (ec->wp1->pointer == ec->wp2->pointer);}}
-
-
-int _WeakPointer_Equal( wp1, wp2 )
- WeakPointer* wp1;
- WeakPointer* wp2;
-{
- EqualClosure ec;
-
- ec.wp1 = wp1;
- ec.wp2 = wp2;
- return (int) GC_call_with_alloc_lock( EqualWithLock, &ec );}
-
-
-int _WeakPointer_Hash( wp )
- WeakPointer* wp;
-{
- return (int) _WeakPointer_Pointer( wp );}
-
-
-/**************************************************************************
-
-Implementations of the template class CleanUp from WeakPointer.h
-
-***************************************************************************/
-
-typedef struct Closure {
- void (*c) PROTO(( void* d, void* t ));
- ptrdiff_t t_offset;
- void* d;
-} Closure;
-
-
-static void _CleanUp_CallClosure( obj, data )
- void* obj;
- void* data;
-{
- Closure* closure = (Closure*) data;
- closure->c( closure->d, (char*) obj + closure->t_offset );}
-
-
-void _CleanUp_Set( t, c, d )
- void* t;
- void (*c) PROTO(( void* d, void* t ));
- void* d;
-{
- void* base = GC_base( t );
- Descriptor* desc = DESCRIPTOR( t );
-
- if (c == 0) {
- GC_REGISTER_FINALIZER_IGNORE_SELF( base, 0, 0, 0, 0 );
- desc->has_finalizer = 0;}
- else {
- Closure* closure = (Closure*) GC_MALLOC( sizeof( Closure ) );
- closure->c = c;
- closure->t_offset = (char*) t - (char*) base;
- closure->d = d;
- GC_REGISTER_FINALIZER_IGNORE_SELF( base, _CleanUp_CallClosure,
- closure, 0, 0 );
- desc->has_finalizer = 1;}}
-
-
-void _CleanUp_Call( t )
- void* t;
-{
- /* ? Aren't we supposed to deactivate weak pointers to t too?
- Why? */
- void* base = GC_base( t );
- void* d;
- GC_finalization_proc f;
-
- GC_REGISTER_FINALIZER( base, 0, 0, &f, &d );
- f( base, d );}
-
-
-typedef struct QueueElem {
- void* o;
- GC_finalization_proc f;
- void* d;
- struct QueueElem* next;
-} QueueElem;
-
-
-void* _CleanUp_Queue_NewHead()
-{
- return GC_MALLOC( sizeof( QueueElem ) );}
-
-
-static void _CleanUp_Queue_Enqueue( obj, data )
- void* obj;
- void* data;
-{
- QueueElem* q = (QueueElem*) data;
- QueueElem* head = q->next;
-
- q->o = obj;
- q->next = head->next;
- head->next = q;}
-
-
-void _CleanUp_Queue_Set( h, t )
- void* h;
- void* t;
-{
- QueueElem* head = (QueueElem*) h;
- void* base = GC_base( t );
- void* d;
- GC_finalization_proc f;
- QueueElem* q = (QueueElem*) GC_MALLOC( sizeof( QueueElem ) );
-
- GC_REGISTER_FINALIZER( base, _CleanUp_Queue_Enqueue, q, &f, &d );
- q->f = f;
- q->d = d;
- q->next = head;}
-
-
-int _CleanUp_Queue_Call( h )
- void* h;
-{
- QueueElem* head = (QueueElem*) h;
- QueueElem* q = head->next;
-
- if (q == 0) {
- return 0;}
- else {
- head->next = q->next;
- q->next = 0;
- if (q->f != 0) q->f( q->o, q->d );
- return 1;}}
-
-
-
diff --git a/boehm-gc/gcj_mlc.c b/boehm-gc/gcj_mlc.c
index 8b1da826c7a..78950e25f13 100644
--- a/boehm-gc/gcj_mlc.c
+++ b/boehm-gc/gcj_mlc.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
- * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -12,7 +12,8 @@
* modified is included with the above copyright notice.
*
*/
-/* Boehm, July 31, 1995 5:02 pm PDT */
+
+#include "private/gc_pmark.h" /* includes gc_priv.h */
#ifdef GC_GCJ_SUPPORT
@@ -31,291 +32,247 @@
* is to get better gcj performance.
*
* We assume:
- * 1) We have an ANSI conforming C compiler.
- * 2) Counting on explicit initialization of this interface is OK.
- * 3) FASTLOCK is not a significant win.
+ * 1) Counting on explicit initialization of this interface is OK;
+ * 2) FASTLOCK is not a significant win.
*/
-#include "private/gc_pmark.h"
#include "gc_gcj.h"
#include "private/dbg_mlc.h"
+#ifdef GC_ASSERTIONS
+ GC_INNER /* variable is also used in thread_local_alloc.c */
+#else
+ STATIC
+#endif
GC_bool GC_gcj_malloc_initialized = FALSE;
-int GC_gcj_kind; /* Object kind for objects with descriptors */
- /* in "vtable". */
-int GC_gcj_debug_kind; /* The kind of objects that is always marked */
- /* with a mark proc call. */
+int GC_gcj_kind = 0; /* Object kind for objects with descriptors */
+ /* in "vtable". */
+int GC_gcj_debug_kind = 0;
+ /* The kind of objects that is always marked */
+ /* with a mark proc call. */
-ptr_t * GC_gcjobjfreelist;
-ptr_t * GC_gcjdebugobjfreelist;
+GC_INNER ptr_t * GC_gcjobjfreelist = NULL;
+
+STATIC ptr_t * GC_gcjdebugobjfreelist = NULL;
+
+STATIC struct GC_ms_entry * GC_gcj_fake_mark_proc(word * addr GC_ATTR_UNUSED,
+ struct GC_ms_entry *mark_stack_ptr,
+ struct GC_ms_entry * mark_stack_limit GC_ATTR_UNUSED,
+ word env GC_ATTR_UNUSED)
+{
+ ABORT_RET("No client gcj mark proc is specified");
+ return mark_stack_ptr;
+}
/* Caller does not hold allocation lock. */
-void GC_init_gcj_malloc(int mp_index, void * /* really GC_mark_proc */mp)
+GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
+ void * /* really GC_mark_proc */mp)
{
- register int i;
GC_bool ignore_gcj_info;
DCL_LOCK_STATE;
- GC_init(); /* In case it's not already done. */
- DISABLE_SIGNALS();
+ if (mp == 0) /* In case GC_DS_PROC is unused. */
+ mp = (void *)(word)GC_gcj_fake_mark_proc;
+
+ GC_init(); /* In case it's not already done. */
LOCK();
if (GC_gcj_malloc_initialized) {
UNLOCK();
- ENABLE_SIGNALS();
return;
}
GC_gcj_malloc_initialized = TRUE;
- ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO"));
-# ifdef CONDPRINT
- if (GC_print_stats && ignore_gcj_info) {
- GC_printf0("Gcj-style type information is disabled!\n");
- }
+# ifdef GC_IGNORE_GCJ_INFO
+ /* This is useful for debugging on platforms with missing getenv(). */
+ ignore_gcj_info = 1;
+# else
+ ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO"));
# endif
+ if (ignore_gcj_info) {
+ GC_COND_LOG_PRINTF("Gcj-style type information is disabled!\n");
+ }
GC_ASSERT(GC_mark_procs[mp_index] == (GC_mark_proc)0); /* unused */
- GC_mark_procs[mp_index] = (GC_mark_proc)mp;
- if (mp_index >= GC_n_mark_procs) ABORT("GC_init_gcj_malloc: bad index");
+ GC_mark_procs[mp_index] = (GC_mark_proc)(word)mp;
+ if ((unsigned)mp_index >= GC_n_mark_procs)
+ ABORT("GC_init_gcj_malloc: bad index");
/* Set up object kind gcj-style indirect descriptor. */
GC_gcjobjfreelist = (ptr_t *)GC_new_free_list_inner();
if (ignore_gcj_info) {
- /* Use a simple length-based descriptor, thus forcing a fully */
- /* conservative scan. */
- GC_gcj_kind = GC_new_kind_inner((void **)GC_gcjobjfreelist,
- (0 | GC_DS_LENGTH),
- TRUE, TRUE);
+ /* Use a simple length-based descriptor, thus forcing a fully */
+ /* conservative scan. */
+ GC_gcj_kind = GC_new_kind_inner((void **)GC_gcjobjfreelist,
+ (0 | GC_DS_LENGTH),
+ TRUE, TRUE);
} else {
- GC_gcj_kind = GC_new_kind_inner(
- (void **)GC_gcjobjfreelist,
- (((word)(-MARK_DESCR_OFFSET - GC_INDIR_PER_OBJ_BIAS))
- | GC_DS_PER_OBJECT),
- FALSE, TRUE);
+ GC_gcj_kind = GC_new_kind_inner(
+ (void **)GC_gcjobjfreelist,
+ (((word)(-(signed_word)MARK_DESCR_OFFSET
+ - GC_INDIR_PER_OBJ_BIAS))
+ | GC_DS_PER_OBJECT),
+ FALSE, TRUE);
}
- /* Set up object kind for objects that require mark proc call. */
+ /* Set up object kind for objects that require mark proc call. */
if (ignore_gcj_info) {
- GC_gcj_debug_kind = GC_gcj_kind;
+ GC_gcj_debug_kind = GC_gcj_kind;
GC_gcjdebugobjfreelist = GC_gcjobjfreelist;
} else {
GC_gcjdebugobjfreelist = (ptr_t *)GC_new_free_list_inner();
- GC_gcj_debug_kind = GC_new_kind_inner(
- (void **)GC_gcjdebugobjfreelist,
- GC_MAKE_PROC(mp_index,
- 1 /* allocated with debug info */),
- FALSE, TRUE);
+ GC_gcj_debug_kind = GC_new_kind_inner(
+ (void **)GC_gcjdebugobjfreelist,
+ GC_MAKE_PROC(mp_index,
+ 1 /* allocated with debug info */),
+ FALSE, TRUE);
}
UNLOCK();
- ENABLE_SIGNALS();
}
-ptr_t GC_clear_stack();
+#define GENERAL_MALLOC_INNER(lb,k) \
+ GC_clear_stack(GC_generic_malloc_inner(lb, k))
-#define GENERAL_MALLOC(lb,k) \
- (GC_PTR)GC_clear_stack(GC_generic_malloc_inner((word)lb, k))
-
-#define GENERAL_MALLOC_IOP(lb,k) \
- (GC_PTR)GC_clear_stack(GC_generic_malloc_inner_ignore_off_page(lb, k))
+#define GENERAL_MALLOC_INNER_IOP(lb,k) \
+ GC_clear_stack(GC_generic_malloc_inner_ignore_off_page(lb, k))
-/* We need a mechanism to release the lock and invoke finalizers. */
-/* We don't really have an opportunity to do this on a rarely executed */
-/* path on which the lock is not held. Thus we check at a */
-/* rarely executed point at which it is safe to release the lock. */
-/* We do this even where we could just call GC_INVOKE_FINALIZERS, */
-/* since it's probably cheaper and certainly more uniform. */
-/* FIXME - Consider doing the same elsewhere? */
-static void maybe_finalize()
+/* We need a mechanism to release the lock and invoke finalizers. */
+/* We don't really have an opportunity to do this on a rarely executed */
+/* path on which the lock is not held. Thus we check at a */
+/* rarely executed point at which it is safe to release the lock. */
+/* We do this even where we could just call GC_INVOKE_FINALIZERS, */
+/* since it's probably cheaper and certainly more uniform. */
+/* FIXME - Consider doing the same elsewhere? */
+static void maybe_finalize(void)
{
- static int last_finalized_no = 0;
+ static word last_finalized_no = 0;
+ DCL_LOCK_STATE;
- if (GC_gc_no == last_finalized_no) return;
- if (!GC_is_initialized) return;
+ if (GC_gc_no == last_finalized_no ||
+ !EXPECT(GC_is_initialized, TRUE)) return;
UNLOCK();
GC_INVOKE_FINALIZERS();
- last_finalized_no = GC_gc_no;
LOCK();
+ last_finalized_no = GC_gc_no;
}
-/* Allocate an object, clear it, and store the pointer to the */
-/* type structure (vtable in gcj). */
+/* Allocate an object, clear it, and store the pointer to the */
+/* type structure (vtable in gcj). */
/* This adds a byte at the end of the object if GC_malloc would.*/
-void * GC_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr)
+#ifdef THREAD_LOCAL_ALLOC
+ GC_INNER void * GC_core_gcj_malloc(size_t lb,
+ void * ptr_to_struct_containing_descr)
+#else
+ GC_API void * GC_CALL GC_gcj_malloc(size_t lb,
+ void * ptr_to_struct_containing_descr)
+#endif
{
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-DCL_LOCK_STATE;
+ ptr_t op;
+ ptr_t * opp;
+ word lg;
+ DCL_LOCK_STATE;
- if( EXPECT(SMALL_OBJ(lb), 1) ) {
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_gcjobjfreelist[lw]);
- LOCK();
- op = *opp;
- if(EXPECT(op == 0, 0)) {
- maybe_finalize();
- op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind);
- if (0 == op) {
- UNLOCK();
- return(GC_oom_fn(lb));
- }
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb]; /* May have been uninitialized. */
-# endif
+ GC_DBG_COLLECT_AT_MALLOC(lb);
+ if(SMALL_OBJ(lb)) {
+ lg = GC_size_map[lb];
+ opp = &(GC_gcjobjfreelist[lg]);
+ LOCK();
+ op = *opp;
+ if(EXPECT(op == 0, FALSE)) {
+ maybe_finalize();
+ op = (ptr_t)GENERAL_MALLOC_INNER((word)lb, GC_gcj_kind);
+ if (0 == op) {
+ GC_oom_func oom_fn = GC_oom_fn;
+ UNLOCK();
+ return((*oom_fn)(lb));
+ }
} else {
*opp = obj_link(op);
- GC_words_allocd += lw;
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
}
- *(void **)op = ptr_to_struct_containing_descr;
- GC_ASSERT(((void **)op)[1] == 0);
- UNLOCK();
- } else {
- LOCK();
- maybe_finalize();
- op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind);
- if (0 == op) {
- UNLOCK();
- return(GC_oom_fn(lb));
- }
- *(void **)op = ptr_to_struct_containing_descr;
- UNLOCK();
- }
- return((GC_PTR) op);
-}
-
-/* Similar to GC_gcj_malloc, but add debug info. This is allocated */
-/* with GC_gcj_debug_kind. */
-GC_PTR GC_debug_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr,
- GC_EXTRA_PARAMS)
-{
- GC_PTR result;
-
- /* We're careful to avoid extra calls, which could */
- /* confuse the backtrace. */
- LOCK();
- maybe_finalize();
- result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
- if (result == 0) {
- UNLOCK();
- GC_err_printf2("GC_debug_gcj_malloc(%ld, 0x%lx) returning NIL (",
- (unsigned long) lb,
- (unsigned long) ptr_to_struct_containing_descr);
- GC_err_puts(s);
- GC_err_printf1(":%ld)\n", (unsigned long)i);
- return(GC_oom_fn(lb));
- }
- *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr;
- UNLOCK();
- if (!GC_debugging_started) {
- GC_start_debugging();
- }
- ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
-}
-
-/* Similar to GC_gcj_malloc, but the size is in words, and we don't */
-/* adjust it. The size is assumed to be such that it can be */
-/* allocated as a small object. */
-void * GC_gcj_fast_malloc(size_t lw, void * ptr_to_struct_containing_descr)
-{
-ptr_t op;
-ptr_t * opp;
-DCL_LOCK_STATE;
-
- opp = &(GC_gcjobjfreelist[lw]);
- LOCK();
- op = *opp;
- if( EXPECT(op == 0, 0) ) {
- maybe_finalize();
- op = (ptr_t)GC_clear_stack(
- GC_generic_malloc_words_small_inner(lw, GC_gcj_kind));
- if (0 == op) {
- UNLOCK();
- return GC_oom_fn(WORDS_TO_BYTES(lw));
- }
+ *(void **)op = ptr_to_struct_containing_descr;
+ GC_ASSERT(((void **)op)[1] == 0);
+ UNLOCK();
} else {
- *opp = obj_link(op);
- GC_words_allocd += lw;
+ LOCK();
+ maybe_finalize();
+ op = (ptr_t)GENERAL_MALLOC_INNER((word)lb, GC_gcj_kind);
+ if (0 == op) {
+ GC_oom_func oom_fn = GC_oom_fn;
+ UNLOCK();
+ return((*oom_fn)(lb));
+ }
+ *(void **)op = ptr_to_struct_containing_descr;
+ UNLOCK();
}
- *(void **)op = ptr_to_struct_containing_descr;
- UNLOCK();
- return((GC_PTR) op);
+ return((void *) op);
}
-/* And a debugging version of the above: */
-void * GC_debug_gcj_fast_malloc(size_t lw,
- void * ptr_to_struct_containing_descr,
- GC_EXTRA_PARAMS)
+/* Similar to GC_gcj_malloc, but add debug info. This is allocated */
+/* with GC_gcj_debug_kind. */
+GC_API void * GC_CALL GC_debug_gcj_malloc(size_t lb,
+ void * ptr_to_struct_containing_descr, GC_EXTRA_PARAMS)
{
- GC_PTR result;
- size_t lb = WORDS_TO_BYTES(lw);
+ void * result;
+ DCL_LOCK_STATE;
- /* We clone the code from GC_debug_gcj_malloc, so that we */
- /* dont end up with extra frames on the stack, which could */
- /* confuse the backtrace. */
+ /* We're careful to avoid extra calls, which could */
+ /* confuse the backtrace. */
LOCK();
maybe_finalize();
result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
if (result == 0) {
- UNLOCK();
- GC_err_printf2("GC_debug_gcj_fast_malloc(%ld, 0x%lx) returning NIL (",
- (unsigned long) lw,
- (unsigned long) ptr_to_struct_containing_descr);
- GC_err_puts(s);
- GC_err_printf1(":%ld)\n", (unsigned long)i);
- return GC_oom_fn(WORDS_TO_BYTES(lw));
+ GC_oom_func oom_fn = GC_oom_fn;
+ UNLOCK();
+ GC_err_printf("GC_debug_gcj_malloc(%lu, %p) returning NULL (%s:%d)\n",
+ (unsigned long)lb, ptr_to_struct_containing_descr, s, i);
+ return((*oom_fn)(lb));
}
*((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr;
UNLOCK();
if (!GC_debugging_started) {
- GC_start_debugging();
+ GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
- return (GC_store_debug_info(result, (word)lb, s, (word)i));
+ return (GC_store_debug_info(result, (word)lb, s, i));
}
-void * GC_gcj_malloc_ignore_off_page(size_t lb,
- void * ptr_to_struct_containing_descr)
+/* There is no THREAD_LOCAL_ALLOC for GC_gcj_malloc_ignore_off_page(). */
+GC_API void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
+ void * ptr_to_struct_containing_descr)
{
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-DCL_LOCK_STATE;
+ ptr_t op;
+ ptr_t * opp;
+ word lg;
+ DCL_LOCK_STATE;
- if( SMALL_OBJ(lb) ) {
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_gcjobjfreelist[lw]);
- LOCK();
- if( (op = *opp) == 0 ) {
- maybe_finalize();
- op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind);
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb]; /* May have been uninitialized. */
-# endif
+ GC_DBG_COLLECT_AT_MALLOC(lb);
+ if(SMALL_OBJ(lb)) {
+ lg = GC_size_map[lb];
+ opp = &(GC_gcjobjfreelist[lg]);
+ LOCK();
+ op = *opp;
+ if (EXPECT(0 == op, FALSE)) {
+ maybe_finalize();
+ op = (ptr_t)GENERAL_MALLOC_INNER_IOP(lb, GC_gcj_kind);
+ if (0 == op) {
+ GC_oom_func oom_fn = GC_oom_fn;
+ UNLOCK();
+ return((*oom_fn)(lb));
+ }
} else {
*opp = obj_link(op);
- GC_words_allocd += lw;
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
}
- *(void **)op = ptr_to_struct_containing_descr;
- UNLOCK();
} else {
- LOCK();
- maybe_finalize();
- op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind);
- if (0 != op) {
- *(void **)op = ptr_to_struct_containing_descr;
- }
- UNLOCK();
+ LOCK();
+ maybe_finalize();
+ op = (ptr_t)GENERAL_MALLOC_INNER_IOP(lb, GC_gcj_kind);
+ if (0 == op) {
+ GC_oom_func oom_fn = GC_oom_fn;
+ UNLOCK();
+ return((*oom_fn)(lb));
+ }
}
- return((GC_PTR) op);
+ *(void **)op = ptr_to_struct_containing_descr;
+ UNLOCK();
+ return((void *) op);
}
-#else
-
-char GC_no_gcj_support;
-
#endif /* GC_GCJ_SUPPORT */
diff --git a/boehm-gc/gcname.c b/boehm-gc/gcname.c
deleted file mode 100644
index e2119d79964..00000000000
--- a/boehm-gc/gcname.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <stdio.h>
-#include "version.h"
-
-int main()
-{
- if (GC_ALPHA_VERSION == GC_NOT_ALPHA) {
- printf("gc%d.%d", GC_VERSION_MAJOR, GC_VERSION_MINOR);
- } else {
- printf("gc%d.%dalpha%d", GC_VERSION_MAJOR,
- GC_VERSION_MINOR, GC_ALPHA_VERSION);
- }
- return 0;
-}
diff --git a/boehm-gc/headers.c b/boehm-gc/headers.c
index b7be1d84930..d650fe7876d 100644
--- a/boehm-gc/headers.c
+++ b/boehm-gc/headers.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
@@ -12,7 +12,9 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-
+
+#include "private/gc_priv.h"
+
/*
* This implements:
* 1. allocation of heap block headers
@@ -21,81 +23,137 @@
* Access speed is crucial. We implement an index structure based on a 2
* level tree.
*/
-
-# include "private/gc_priv.h"
-bottom_index * GC_all_bottom_indices = 0;
- /* Pointer to first (lowest addr) */
- /* bottom_index. */
+STATIC bottom_index * GC_all_bottom_indices = 0;
+ /* Pointer to first (lowest addr) */
+ /* bottom_index. */
+
+STATIC bottom_index * GC_all_bottom_indices_end = 0;
+ /* Pointer to last (highest addr) */
+ /* bottom_index. */
-bottom_index * GC_all_bottom_indices_end = 0;
- /* Pointer to last (highest addr) */
- /* bottom_index. */
-
/* Non-macro version of header location routine */
-hdr * GC_find_header(h)
-ptr_t h;
+GC_INNER hdr * GC_find_header(ptr_t h)
{
# ifdef HASH_TL
- register hdr * result;
- GET_HDR(h, result);
- return(result);
+ hdr * result;
+ GET_HDR(h, result);
+ return(result);
# else
- return(HDR_INNER(h));
+ return(HDR_INNER(h));
# endif
}
-
+
+/* Handle a header cache miss. Returns a pointer to the */
+/* header corresponding to p, if p can possibly be a valid */
+/* object pointer, and 0 otherwise. */
+/* GUARANTEED to return 0 for a pointer past the first page */
+/* of an object unless both GC_all_interior_pointers is set */
+/* and p is in fact a valid object pointer. */
+/* Never returns a pointer to a free hblk. */
+GC_INNER hdr *
+#ifdef PRINT_BLACK_LIST
+ GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce, ptr_t source)
+#else
+ GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce)
+#endif
+{
+ hdr *hhdr;
+ HC_MISS();
+ GET_HDR(p, hhdr);
+ if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+ if (GC_all_interior_pointers) {
+ if (hhdr != 0) {
+ ptr_t current = p;
+
+ current = (ptr_t)HBLKPTR(current);
+ do {
+ current = current - HBLKSIZE*(word)hhdr;
+ hhdr = HDR(current);
+ } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
+ /* current points to near the start of the large object */
+ if (hhdr -> hb_flags & IGNORE_OFF_PAGE)
+ return 0;
+ if (HBLK_IS_FREE(hhdr)
+ || p - current >= (ptrdiff_t)(hhdr->hb_sz)) {
+ GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
+ /* Pointer past the end of the block */
+ return 0;
+ }
+ } else {
+ GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
+ /* And return zero: */
+ }
+ GC_ASSERT(hhdr == 0 || !HBLK_IS_FREE(hhdr));
+ return hhdr;
+ /* Pointers past the first page are probably too rare */
+ /* to add them to the cache. We don't. */
+ /* And correctness relies on the fact that we don't. */
+ } else {
+ if (hhdr == 0) {
+ GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
+ }
+ return 0;
+ }
+ } else {
+ if (HBLK_IS_FREE(hhdr)) {
+ GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
+ return 0;
+ } else {
+ hce -> block_addr = (word)(p) >> LOG_HBLKSIZE;
+ hce -> hce_hdr = hhdr;
+ return hhdr;
+ }
+ }
+}
+
/* Routines to dynamically allocate collector data structures that will */
-/* never be freed. */
-
+/* never be freed. */
+
static ptr_t scratch_free_ptr = 0;
-
+
/* GC_scratch_last_end_ptr is end point of last obtained scratch area. */
-/* GC_scratch_end_ptr is end point of current scratch area. */
-
-ptr_t GC_scratch_alloc(bytes)
-register word bytes;
+/* GC_scratch_end_ptr is end point of current scratch area. */
+
+GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
{
register ptr_t result = scratch_free_ptr;
-# ifdef ALIGN_DOUBLE
-# define GRANULARITY (2 * sizeof(word))
-# else
-# define GRANULARITY sizeof(word)
-# endif
- bytes += GRANULARITY-1;
- bytes &= ~(GRANULARITY-1);
+ bytes += GRANULE_BYTES-1;
+ bytes &= ~(GRANULE_BYTES-1);
scratch_free_ptr += bytes;
- if (scratch_free_ptr <= GC_scratch_end_ptr) {
+ if ((word)scratch_free_ptr <= (word)GC_scratch_end_ptr) {
return(result);
}
{
word bytes_to_get = MINHINCR * HBLKSIZE;
-
+
if (bytes_to_get <= bytes) {
/* Undo the damage, and get memory directly */
- bytes_to_get = bytes;
-# ifdef USE_MMAP
- bytes_to_get += GC_page_size - 1;
- bytes_to_get &= ~(GC_page_size - 1);
-# endif
- result = (ptr_t)GET_MEM(bytes_to_get);
+ bytes_to_get = bytes;
+# ifdef USE_MMAP
+ bytes_to_get += GC_page_size - 1;
+ 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;
+ 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) {
-# ifdef PRINTSTATS
- GC_printf0("Out of memory - trying to allocate less\n");
-# endif
+ GC_COND_LOG_PRINTF("Out of memory - trying to allocate less\n");
scratch_free_ptr -= bytes;
- bytes_to_get = bytes;
-# ifdef USE_MMAP
- bytes_to_get += GC_page_size - 1;
- bytes_to_get &= ~(GC_page_size - 1);
-# endif
- return((ptr_t)GET_MEM(bytes_to_get));
+ bytes_to_get = bytes;
+# ifdef USE_MMAP
+ bytes_to_get += GC_page_size - 1;
+ 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);
+ return result;
}
scratch_free_ptr = result;
GC_scratch_end_ptr = scratch_free_ptr + bytes_to_get;
@@ -107,10 +165,10 @@ register word bytes;
static hdr * hdr_free_list = 0;
/* Return an uninitialized header */
-static hdr * alloc_hdr()
+static hdr * alloc_hdr(void)
{
register hdr * result;
-
+
if (hdr_free_list == 0) {
result = (hdr *) GC_scratch_alloc((word)(sizeof(hdr)));
} else {
@@ -120,48 +178,47 @@ static hdr * alloc_hdr()
return(result);
}
-static void free_hdr(hhdr)
-hdr * hhdr;
+GC_INLINE void free_hdr(hdr * hhdr)
{
hhdr -> hb_next = (struct hblk *) hdr_free_list;
hdr_free_list = hhdr;
}
-hdr * GC_invalid_header;
-
-#ifdef USE_HDR_CACHE
+#ifdef COUNT_HDR_CACHE_HITS
+ /* Used for debugging/profiling (the symbols are externally visible). */
word GC_hdr_cache_hits = 0;
word GC_hdr_cache_misses = 0;
#endif
-
-void GC_init_headers()
+
+GC_INNER void GC_init_headers(void)
{
register unsigned i;
-
+
GC_all_nils = (bottom_index *)GC_scratch_alloc((word)sizeof(bottom_index));
+ if (GC_all_nils == NULL) {
+ GC_err_printf("Insufficient memory for GC_all_nils\n");
+ EXIT();
+ }
BZERO(GC_all_nils, sizeof(bottom_index));
for (i = 0; i < TOP_SZ; i++) {
GC_top_index[i] = GC_all_nils;
}
- GC_invalid_header = alloc_hdr();
- GC_invalidate_map(GC_invalid_header);
}
/* Make sure that there is a bottom level index block for address addr */
-/* Return FALSE on failure. */
-static GC_bool get_index(addr)
-word addr;
+/* Return FALSE on failure. */
+static GC_bool get_index(word addr)
{
word hi = (word)(addr) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
bottom_index * r;
bottom_index * p;
bottom_index ** prev;
bottom_index *pi;
-
+
# ifdef HASH_TL
- unsigned i = TL_HASH(hi);
+ word i = TL_HASH(hi);
bottom_index * old;
-
+
old = p = GC_top_index[i];
while(p != GC_all_nils) {
if (p -> key == hi) return(TRUE);
@@ -181,53 +238,52 @@ word addr;
# endif
r -> key = hi;
/* Add it to the list of bottom indices */
- prev = &GC_all_bottom_indices; /* pointer to p */
- pi = 0; /* bottom_index preceding p */
+ prev = &GC_all_bottom_indices; /* pointer to p */
+ pi = 0; /* bottom_index preceding p */
while ((p = *prev) != 0 && p -> key < hi) {
- pi = p;
- prev = &(p -> asc_link);
+ pi = p;
+ prev = &(p -> asc_link);
}
r -> desc_link = pi;
if (0 == p) {
- GC_all_bottom_indices_end = r;
+ GC_all_bottom_indices_end = r;
} else {
- p -> desc_link = r;
+ p -> desc_link = r;
}
r -> asc_link = p;
*prev = r;
return(TRUE);
}
-/* Install a header for block h. */
-/* The header is uninitialized. */
-/* Returns the header or 0 on failure. */
-struct hblkhdr * GC_install_header(h)
-register struct hblk * h;
+/* Install a header for block h. */
+/* The header is uninitialized. */
+/* Returns the header or 0 on failure. */
+GC_INNER struct hblkhdr * GC_install_header(struct hblk *h)
{
hdr * result;
-
+
if (!get_index((word) h)) return(0);
result = alloc_hdr();
- SET_HDR(h, result);
-# ifdef USE_MUNMAP
- result -> hb_last_reclaimed = GC_gc_no;
-# endif
+ if (result) {
+ SET_HDR(h, result);
+# ifdef USE_MUNMAP
+ result -> hb_last_reclaimed = (unsigned short)GC_gc_no;
+# endif
+ }
return(result);
}
/* Set up forwarding counts for block h of size sz */
-GC_bool GC_install_counts(h, sz)
-register struct hblk * h;
-register word sz; /* bytes */
+GC_INNER GC_bool GC_install_counts(struct hblk *h, size_t sz/* bytes */)
{
- register struct hblk * hbp;
- register int i;
-
- for (hbp = h; (char *)hbp < (char *)h + sz; hbp += BOTTOM_SZ) {
+ struct hblk * hbp;
+ word i;
+
+ for (hbp = h; (word)hbp < (word)h + sz; hbp += BOTTOM_SZ) {
if (!get_index((word) hbp)) return(FALSE);
}
if (!get_index((word)h + sz - 1)) return(FALSE);
- for (hbp = h + 1; (char *)hbp < (char *)h + sz; hbp += 1) {
+ for (hbp = h + 1; (word)hbp < (word)h + sz; hbp += 1) {
i = HBLK_PTR_DIFF(hbp, h);
SET_HDR(hbp, (hdr *)(i > MAX_JUMP? MAX_JUMP : i));
}
@@ -235,65 +291,58 @@ register word sz; /* bytes */
}
/* Remove the header for block h */
-void GC_remove_header(h)
-register struct hblk * h;
+GC_INNER void GC_remove_header(struct hblk *h)
{
- hdr ** ha;
-
+ hdr **ha;
GET_HDR_ADDR(h, ha);
free_hdr(*ha);
*ha = 0;
}
/* Remove forwarding counts for h */
-void GC_remove_counts(h, sz)
-register struct hblk * h;
-register word sz; /* bytes */
+GC_INNER void GC_remove_counts(struct hblk *h, size_t sz/* bytes */)
{
register struct hblk * hbp;
-
- for (hbp = h+1; (char *)hbp < (char *)h + sz; hbp += 1) {
+ for (hbp = h+1; (word)hbp < (word)h + sz; hbp += 1) {
SET_HDR(hbp, 0);
}
}
/* Apply fn to all allocated blocks */
/*VARARGS1*/
-void GC_apply_to_all_blocks(fn, client_data)
-void (*fn) GC_PROTO((struct hblk *h, word client_data));
-word client_data;
+void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data),
+ word client_data)
{
- register int j;
- register bottom_index * index_p;
-
+ signed_word j;
+ bottom_index * index_p;
+
for (index_p = GC_all_bottom_indices; index_p != 0;
index_p = index_p -> asc_link) {
for (j = BOTTOM_SZ-1; j >= 0;) {
if (!IS_FORWARDING_ADDR_OR_NIL(index_p->index[j])) {
- if (index_p->index[j]->hb_map != GC_invalid_map) {
+ if (!HBLK_IS_FREE(index_p->index[j])) {
(*fn)(((struct hblk *)
- (((index_p->key << LOG_BOTTOM_SZ) + (word)j)
- << LOG_HBLKSIZE)),
+ (((index_p->key << LOG_BOTTOM_SZ) + (word)j)
+ << LOG_HBLKSIZE)),
client_data);
}
j--;
} else if (index_p->index[j] == 0) {
j--;
} else {
- j -= (word)(index_p->index[j]);
+ j -= (signed_word)(index_p->index[j]);
}
}
}
}
-/* Get the next valid block whose address is at least h */
-/* Return 0 if there is none. */
-struct hblk * GC_next_used_block(h)
-struct hblk * h;
+/* Get the next valid block whose address is at least h */
+/* Return 0 if there is none. */
+GC_INNER struct hblk * GC_next_used_block(struct hblk *h)
{
register bottom_index * bi;
register word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
-
+
GET_BI(h, bi);
if (bi == GC_all_nils) {
register word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
@@ -303,14 +352,14 @@ struct hblk * h;
}
while(bi != 0) {
while (j < BOTTOM_SZ) {
- hdr * hhdr = bi -> index[j];
+ hdr * hhdr = bi -> index[j];
if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
j++;
} else {
- if (hhdr->hb_map != GC_invalid_map) {
+ if (!HBLK_IS_FREE(hhdr)) {
return((struct hblk *)
- (((bi -> key << LOG_BOTTOM_SZ) + j)
- << LOG_HBLKSIZE));
+ (((bi -> key << LOG_BOTTOM_SZ) + j)
+ << LOG_HBLKSIZE));
} else {
j += divHBLKSZ(hhdr -> hb_sz);
}
@@ -322,15 +371,14 @@ struct hblk * h;
return(0);
}
-/* Get the last (highest address) block whose address is */
-/* at most h. Return 0 if there is none. */
-/* Unlike the above, this may return a free block. */
-struct hblk * GC_prev_block(h)
-struct hblk * h;
+/* Get the last (highest address) block whose address is */
+/* at most h. Return 0 if there is none. */
+/* Unlike the above, this may return a free block. */
+GC_INNER struct hblk * GC_prev_block(struct hblk *h)
{
register bottom_index * bi;
register signed_word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
-
+
GET_BI(h, bi);
if (bi == GC_all_nils) {
register word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
@@ -340,15 +388,15 @@ struct hblk * h;
}
while(bi != 0) {
while (j >= 0) {
- hdr * hhdr = bi -> index[j];
- if (0 == hhdr) {
- --j;
+ hdr * hhdr = bi -> index[j];
+ if (0 == hhdr) {
+ --j;
} else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
j -= (signed_word)hhdr;
} else {
return((struct hblk *)
(((bi -> key << LOG_BOTTOM_SZ) + j)
- << LOG_HBLKSIZE));
+ << LOG_HBLKSIZE));
}
}
j = BOTTOM_SZ - 1;
diff --git a/boehm-gc/hpux_test_and_clear.s b/boehm-gc/hpux_test_and_clear.s
deleted file mode 100644
index f09b211404b..00000000000
--- a/boehm-gc/hpux_test_and_clear.s
+++ /dev/null
@@ -1,21 +0,0 @@
- .SPACE $PRIVATE$
- .SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31
- .SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82
- .SPACE $TEXT$
- .SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44
- .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY
- .IMPORT $global$,DATA
- .IMPORT $$dyncall,MILLICODE
- .SPACE $TEXT$
- .SUBSPA $CODE$
-
- .align 4
- .EXPORT GC_test_and_clear,ENTRY,PRIV_LEV=3,ARGW0=GR,RTNVAL=GR
-GC_test_and_clear
- .PROC
- .CALLINFO FRAME=0,NO_CALLS
- .ENTRY
- ldcw,co (%r26),%r28
- bv,n 0(%r2)
- .EXIT
- .PROCEND
diff --git a/boehm-gc/include/cord.h b/boehm-gc/include/cord.h
index 926089e86fb..05eb4c4c1ef 100644
--- a/boehm-gc/include/cord.h
+++ b/boehm-gc/include/cord.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -9,11 +9,8 @@
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
- *
- * Author: Hans-J. Boehm (boehm@parc.xerox.com)
*/
-/* Boehm, October 5, 1995 4:20 pm PDT */
-
+
/*
* Cords are immutable character strings. A number of operations
* on long cords are much more efficient than their strings.h counterpart.
@@ -28,7 +25,7 @@
* concatenating instructions onto a cord representing the output file.
* - A text editor that converts the input file to a cord, and then
* performs editing operations by producing a new cord representing
- * the file after echa character change (and keeping the old ones in an
+ * the file after each character change (and keeping the old ones in an
* edit history)
*
* For optimal performance, cords should be built by
@@ -36,7 +33,7 @@
* This interface is designed for maximum compatibility with C strings.
* ASCII NUL characters may be embedded in cords using CORD_from_fn.
* This is handled correctly, but CORD_to_char_star will produce a string
- * with embedded NULs when given such a cord.
+ * with embedded NULs when given such a cord.
*
* This interface is fairly big, largely for performance reasons.
* The most basic constants and functions:
@@ -55,273 +52,303 @@
* (Non-NULL C constant strings are cords.)
* CORD_printf (etc.) - cord version of printf. Use %r for cords.
*/
-# ifndef CORD_H
-
-# define CORD_H
-# include <stddef.h>
-# include <stdio.h>
-/* Cords have type const char *. This is cheating quite a bit, and not */
-/* 100% portable. But it means that nonempty character string */
-/* constants may be used as cords directly, provided the string is */
-/* never modified in place. The empty cord is represented by, and */
-/* can be written as, 0. */
+#ifndef CORD_H
+#define CORD_H
+
+#include <stddef.h>
+#include <stdio.h>
+
+#ifdef GC_DLL
+ /* Same as for GC_API in gc_config_macros.h. */
+# ifdef CORD_BUILD
+# if defined(__MINGW32__) || defined(__CEGCC__)
+# define CORD_API __declspec(dllexport)
+# elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
+ || defined(__CYGWIN__) || defined(__WATCOMC__)
+# define CORD_API extern __declspec(dllexport)
+# elif defined(__GNUC__) && (__GNUC__ >= 4 \
+ || defined(GC_VISIBILITY_HIDDEN_SET))
+ /* Only matters if used in conjunction with -fvisibility=hidden option. */
+# define CORD_API extern __attribute__((__visibility__("default")))
+# endif
+# else
+# if defined(__MINGW32__) || defined(__CEGCC__) || defined(_MSC_VER) \
+ || defined(__DMC__) || defined(__BORLANDC__) || defined(__CYGWIN__)
+# define CORD_API __declspec(dllimport)
+# elif defined(__WATCOMC__)
+# define CORD_API extern __declspec(dllimport)
+# endif
+# endif /* !CORD_BUILD */
+#endif /* GC_DLL */
+
+#ifndef CORD_API
+# define CORD_API extern
+#endif
+
+/* Cords have type const char *. This is cheating quite a bit, and not */
+/* 100% portable. But it means that nonempty character string */
+/* constants may be used as cords directly, provided the string is */
+/* never modified in place. The empty cord is represented by, and */
+/* can be written as, 0. */
typedef const char * CORD;
-/* An empty cord is always represented as nil */
-# define CORD_EMPTY 0
+/* An empty cord is always represented as nil */
+#define CORD_EMPTY 0
/* Is a nonempty cord represented as a C string? */
#define CORD_IS_STRING(s) (*(s) != '\0')
-/* Concatenate two cords. If the arguments are C strings, they may */
-/* not be subsequently altered. */
-CORD CORD_cat(CORD x, CORD y);
+/* Concatenate two cords. If the arguments are C strings, they may */
+/* not be subsequently altered. */
+CORD_API CORD CORD_cat(CORD x, CORD y);
-/* Concatenate a cord and a C string with known length. Except for the */
-/* empty string case, this is a special case of CORD_cat. Since the */
-/* length is known, it can be faster. */
-/* The string y is shared with the resulting CORD. Hence it should */
-/* not be altered by the caller. */
-CORD CORD_cat_char_star(CORD x, const char * y, size_t leny);
+/* Concatenate a cord and a C string with known length. Except for the */
+/* empty string case, this is a special case of CORD_cat. Since the */
+/* length is known, it can be faster. */
+/* The string y is shared with the resulting CORD. Hence it should */
+/* not be altered by the caller. */
+CORD_API CORD CORD_cat_char_star(CORD x, const char * y, size_t leny);
/* Compute the length of a cord */
-size_t CORD_len(CORD x);
+CORD_API size_t CORD_len(CORD x);
/* Cords may be represented by functions defining the ith character */
typedef char (* CORD_fn)(size_t i, void * client_data);
-/* Turn a functional description into a cord. */
-CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len);
-
-/* Return the substring (subcord really) of x with length at most n, */
-/* starting at position i. (The initial character has position 0.) */
-CORD CORD_substr(CORD x, size_t i, size_t n);
-
-/* Return the argument, but rebalanced to allow more efficient */
-/* character retrieval, substring operations, and comparisons. */
-/* This is useful only for cords that were built using repeated */
-/* concatenation. Guarantees log time access to the result, unless */
-/* x was obtained through a large number of repeated substring ops */
-/* or the embedded functional descriptions take longer to evaluate. */
-/* May reallocate significant parts of the cord. The argument is not */
-/* modified; only the result is balanced. */
-CORD CORD_balance(CORD x);
-
-/* The following traverse a cord by applying a function to each */
-/* character. This is occasionally appropriate, especially where */
-/* speed is crucial. But, since C doesn't have nested functions, */
-/* clients of this sort of traversal are clumsy to write. Consider */
-/* the functions that operate on cord positions instead. */
-
-/* Function to iteratively apply to individual characters in cord. */
+/* Turn a functional description into a cord. */
+CORD_API CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len);
+
+/* Return the substring (subcord really) of x with length at most n, */
+/* starting at position i. (The initial character has position 0.) */
+CORD_API CORD CORD_substr(CORD x, size_t i, size_t n);
+
+/* Return the argument, but rebalanced to allow more efficient */
+/* character retrieval, substring operations, and comparisons. */
+/* This is useful only for cords that were built using repeated */
+/* concatenation. Guarantees log time access to the result, unless */
+/* x was obtained through a large number of repeated substring ops */
+/* or the embedded functional descriptions take longer to evaluate. */
+/* May reallocate significant parts of the cord. The argument is not */
+/* modified; only the result is balanced. */
+CORD_API CORD CORD_balance(CORD x);
+
+/* The following traverse a cord by applying a function to each */
+/* character. This is occasionally appropriate, especially where */
+/* speed is crucial. But, since C doesn't have nested functions, */
+/* clients of this sort of traversal are clumsy to write. Consider */
+/* the functions that operate on cord positions instead. */
+
+/* Function to iteratively apply to individual characters in cord. */
typedef int (* CORD_iter_fn)(char c, void * client_data);
-/* Function to apply to substrings of a cord. Each substring is a */
-/* a C character string, not a general cord. */
+/* Function to apply to substrings of a cord. Each substring is a */
+/* a C character string, not a general cord. */
typedef int (* CORD_batched_iter_fn)(const char * s, void * client_data);
-# define CORD_NO_FN ((CORD_batched_iter_fn)0)
-
-/* Apply f1 to each character in the cord, in ascending order, */
-/* starting at position i. If */
-/* f2 is not CORD_NO_FN, then multiple calls to f1 may be replaced by */
-/* a single call to f2. The parameter f2 is provided only to allow */
-/* some optimization by the client. This terminates when the right */
-/* end of this string is reached, or when f1 or f2 return != 0. In the */
-/* latter case CORD_iter returns != 0. Otherwise it returns 0. */
-/* The specified value of i must be < CORD_len(x). */
-int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
- CORD_batched_iter_fn f2, void * client_data);
-
-/* A simpler version that starts at 0, and without f2: */
-int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data);
-# define CORD_iter(x, f1, cd) CORD_iter5(x, 0, f1, CORD_NO_FN, cd)
-
-/* Similar to CORD_iter5, but end-to-beginning. No provisions for */
-/* CORD_batched_iter_fn. */
-int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data);
-
-/* A simpler version that starts at the end: */
-int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
-
-/* Functions that operate on cord positions. The easy way to traverse */
-/* cords. A cord position is logically a pair consisting of a cord */
-/* and an index into that cord. But it is much faster to retrieve a */
-/* charcter based on a position than on an index. Unfortunately, */
-/* positions are big (order of a few 100 bytes), so allocate them with */
-/* caution. */
-/* Things in cord_pos.h should be treated as opaque, except as */
-/* described below. Also note that */
-/* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function */
+#define CORD_NO_FN ((CORD_batched_iter_fn)0)
+
+/* Apply f1 to each character in the cord, in ascending order, */
+/* starting at position i. If */
+/* f2 is not CORD_NO_FN, then multiple calls to f1 may be replaced by */
+/* a single call to f2. The parameter f2 is provided only to allow */
+/* some optimization by the client. This terminates when the right */
+/* end of this string is reached, or when f1 or f2 return != 0. In the */
+/* latter case CORD_iter returns != 0. Otherwise it returns 0. */
+/* The specified value of i must be < CORD_len(x). */
+CORD_API int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
+ CORD_batched_iter_fn f2, void * client_data);
+
+/* A simpler version that starts at 0, and without f2: */
+CORD_API int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data);
+#define CORD_iter(x, f1, cd) CORD_iter5(x, 0, f1, CORD_NO_FN, cd)
+
+/* Similar to CORD_iter5, but end-to-beginning. No provisions for */
+/* CORD_batched_iter_fn. */
+CORD_API int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data);
+
+/* A simpler version that starts at the end: */
+CORD_API int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
+
+/* Functions that operate on cord positions. The easy way to traverse */
+/* cords. A cord position is logically a pair consisting of a cord */
+/* and an index into that cord. But it is much faster to retrieve a */
+/* character based on a position than on an index. Unfortunately, */
+/* positions are big (order of a few 100 bytes), so allocate them with */
+/* caution. */
+/* Things in cord_pos.h should be treated as opaque, except as */
+/* described below. Also note that */
+/* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function */
/* definitions. The former may evaluate their argument more than once. */
-# include "private/cord_pos.h"
+#include "cord_pos.h"
/*
- Visible definitions from above:
-
- typedef <OPAQUE but fairly big> CORD_pos[1];
-
- * Extract the cord from a position:
- CORD CORD_pos_to_cord(CORD_pos p);
-
- * Extract the current index from a position:
- size_t CORD_pos_to_index(CORD_pos p);
-
- * Fetch the character located at the given position:
- char CORD_pos_fetch(CORD_pos p);
-
- * Initialize the position to refer to the given cord and index.
- * Note that this is the most expensive function on positions:
- void CORD_set_pos(CORD_pos p, CORD x, size_t i);
-
- * Advance the position to the next character.
- * P must be initialized and valid.
- * Invalidates p if past end:
- void CORD_next(CORD_pos p);
-
- * Move the position to the preceding character.
- * P must be initialized and valid.
- * Invalidates p if past beginning:
- void CORD_prev(CORD_pos p);
-
- * Is the position valid, i.e. inside the cord?
- int CORD_pos_valid(CORD_pos p);
+ Visible definitions from above:
+
+ typedef <OPAQUE but fairly big> CORD_pos[1];
+
+ * Extract the cord from a position:
+ CORD CORD_pos_to_cord(CORD_pos p);
+
+ * Extract the current index from a position:
+ size_t CORD_pos_to_index(CORD_pos p);
+
+ * Fetch the character located at the given position:
+ char CORD_pos_fetch(CORD_pos p);
+
+ * Initialize the position to refer to the given cord and index.
+ * Note that this is the most expensive function on positions:
+ void CORD_set_pos(CORD_pos p, CORD x, size_t i);
+
+ * Advance the position to the next character.
+ * P must be initialized and valid.
+ * Invalidates p if past end:
+ void CORD_next(CORD_pos p);
+
+ * Move the position to the preceding character.
+ * P must be initialized and valid.
+ * Invalidates p if past beginning:
+ void CORD_prev(CORD_pos p);
+
+ * Is the position valid, i.e. inside the cord?
+ int CORD_pos_valid(CORD_pos p);
*/
-# define CORD_FOR(pos, cord) \
+#define CORD_FOR(pos, cord) \
for (CORD_set_pos(pos, cord, 0); CORD_pos_valid(pos); CORD_next(pos))
-
-/* An out of memory handler to call. May be supplied by client. */
-/* Must not return. */
+
+/* An out of memory handler to call. May be supplied by client. */
+/* Must not return. */
extern void (* CORD_oom_fn)(void);
-/* Dump the representation of x to stdout in an implementation defined */
-/* manner. Intended for debugging only. */
-void CORD_dump(CORD x);
-
-/* The following could easily be implemented by the client. They are */
-/* provided in cordxtra.c for convenience. */
-
-/* Concatenate a character to the end of a cord. */
-CORD CORD_cat_char(CORD x, char c);
-
-/* Concatenate n cords. */
-CORD CORD_catn(int n, /* CORD */ ...);
-
-/* Return the character in CORD_substr(x, i, 1) */
-char CORD_fetch(CORD x, size_t i);
-
-/* Return < 0, 0, or > 0, depending on whether x < y, x = y, x > y */
-int CORD_cmp(CORD x, CORD y);
-
-/* A generalization that takes both starting positions for the */
-/* comparison, and a limit on the number of characters to be compared. */
-int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len);
-
-/* Find the first occurrence of s in x at position start or later. */
-/* Return the position of the first character of s in x, or */
-/* CORD_NOT_FOUND if there is none. */
-size_t CORD_str(CORD x, size_t start, CORD s);
-
-/* Return a cord consisting of i copies of (possibly NUL) c. Dangerous */
-/* in conjunction with CORD_to_char_star. */
-/* The resulting representation takes constant space, independent of i. */
-CORD CORD_chars(char c, size_t i);
-# define CORD_nul(i) CORD_chars('\0', (i))
-
-/* Turn a file into cord. The file must be seekable. Its contents */
-/* must remain constant. The file may be accessed as an immediate */
-/* result of this call and/or as a result of subsequent accesses to */
-/* the cord. Short files are likely to be immediately read, but */
-/* long files are likely to be read on demand, possibly relying on */
-/* stdio for buffering. */
-/* We must have exclusive access to the descriptor f, i.e. we may */
-/* read it at any time, and expect the file pointer to be */
-/* where we left it. Normally this should be invoked as */
-/* CORD_from_file(fopen(...)) */
-/* CORD_from_file arranges to close the file descriptor when it is no */
-/* longer needed (e.g. when the result becomes inaccessible). */
-/* The file f must be such that ftell reflects the actual character */
-/* position in the file, i.e. the number of characters that can be */
-/* or were read with fread. On UNIX systems this is always true. On */
-/* MS Windows systems, f must be opened in binary mode. */
-CORD CORD_from_file(FILE * f);
-
-/* Equivalent to the above, except that the entire file will be read */
-/* and the file pointer will be closed immediately. */
-/* The binary mode restriction from above does not apply. */
-CORD CORD_from_file_eager(FILE * f);
+/* Dump the representation of x to stdout in an implementation defined */
+/* manner. Intended for debugging only. */
+CORD_API void CORD_dump(CORD x);
+
+/* The following could easily be implemented by the client. They are */
+/* provided in cordxtra.c for convenience. */
+
+/* Concatenate a character to the end of a cord. */
+CORD_API CORD CORD_cat_char(CORD x, char c);
+
+/* Concatenate n cords. */
+CORD_API CORD CORD_catn(int n, /* CORD */ ...);
+
+/* Return the character in CORD_substr(x, i, 1) */
+CORD_API char CORD_fetch(CORD x, size_t i);
+
+/* Return < 0, 0, or > 0, depending on whether x < y, x = y, x > y */
+CORD_API int CORD_cmp(CORD x, CORD y);
+
+/* A generalization that takes both starting positions for the */
+/* comparison, and a limit on the number of characters to be compared. */
+CORD_API int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start,
+ size_t len);
+
+/* Find the first occurrence of s in x at position start or later. */
+/* Return the position of the first character of s in x, or */
+/* CORD_NOT_FOUND if there is none. */
+CORD_API size_t CORD_str(CORD x, size_t start, CORD s);
+
+/* Return a cord consisting of i copies of (possibly NUL) c. Dangerous */
+/* in conjunction with CORD_to_char_star. */
+/* The resulting representation takes constant space, independent of i. */
+CORD_API CORD CORD_chars(char c, size_t i);
+#define CORD_nul(i) CORD_chars('\0', (i))
+
+/* Turn a file into cord. The file must be seekable. Its contents */
+/* must remain constant. The file may be accessed as an immediate */
+/* result of this call and/or as a result of subsequent accesses to */
+/* the cord. Short files are likely to be immediately read, but */
+/* long files are likely to be read on demand, possibly relying on */
+/* stdio for buffering. */
+/* We must have exclusive access to the descriptor f, i.e. we may */
+/* read it at any time, and expect the file pointer to be */
+/* where we left it. Normally this should be invoked as */
+/* CORD_from_file(fopen(...)) */
+/* CORD_from_file arranges to close the file descriptor when it is no */
+/* longer needed (e.g. when the result becomes inaccessible). */
+/* The file f must be such that ftell reflects the actual character */
+/* position in the file, i.e. the number of characters that can be */
+/* or were read with fread. On UNIX systems this is always true. On */
+/* MS Windows systems, f must be opened in binary mode. */
+CORD_API CORD CORD_from_file(FILE * f);
+
+/* Equivalent to the above, except that the entire file will be read */
+/* and the file pointer will be closed immediately. */
+/* The binary mode restriction from above does not apply. */
+CORD_API CORD CORD_from_file_eager(FILE * f);
/* Equivalent to the above, except that the file will be read on demand.*/
-/* The binary mode restriction applies. */
-CORD CORD_from_file_lazy(FILE * f);
-
-/* Turn a cord into a C string. The result shares no structure with */
-/* x, and is thus modifiable. */
-char * CORD_to_char_star(CORD x);
-
-/* Turn a C string into a CORD. The C string is copied, and so may */
-/* subsequently be modified. */
-CORD CORD_from_char_star(const char *s);
-
-/* Identical to the above, but the result may share structure with */
-/* the argument and is thus not modifiable. */
-const char * CORD_to_const_char_star(CORD x);
-
-/* Write a cord to a file, starting at the current position. No */
-/* trailing NULs are newlines are added. */
-/* Returns EOF if a write error occurs, 1 otherwise. */
-int CORD_put(CORD x, FILE * f);
-
-/* "Not found" result for the following two functions. */
-# define CORD_NOT_FOUND ((size_t)(-1))
-
-/* A vague analog of strchr. Returns the position (an integer, not */
-/* a pointer) of the first occurrence of (char) c inside x at position */
-/* i or later. The value i must be < CORD_len(x). */
-size_t CORD_chr(CORD x, size_t i, int c);
-
-/* A vague analog of strrchr. Returns index of the last occurrence */
-/* of (char) c inside x at position i or earlier. The value i */
-/* must be < CORD_len(x). */
-size_t CORD_rchr(CORD x, size_t i, int c);
-
-
-/* The following are also not primitive, but are implemented in */
-/* cordprnt.c. They provide functionality similar to the ANSI C */
-/* functions with corresponding names, but with the following */
-/* additions and changes: */
-/* 1. A %r conversion specification specifies a CORD argument. Field */
-/* width, precision, etc. have the same semantics as for %s. */
-/* (Note that %c,%C, and %S were already taken.) */
-/* 2. The format string is represented as a CORD. */
-/* 3. CORD_sprintf and CORD_vsprintf assign the result through the 1st */ /* argument. Unlike their ANSI C versions, there is no need to guess */
-/* the correct buffer size. */
-/* 4. Most of the conversions are implement through the native */
-/* vsprintf. Hence they are usually no faster, and */
-/* idiosyncracies of the native printf are preserved. However, */
-/* CORD arguments to CORD_sprintf and CORD_vsprintf are NOT copied; */
-/* the result shares the original structure. This may make them */
-/* very efficient in some unusual applications. */
-/* The format string is copied. */
-/* All functions return the number of characters generated or -1 on */
-/* error. This complies with the ANSI standard, but is inconsistent */
-/* with some older implementations of sprintf. */
-
-/* The implementation of these is probably less portable than the rest */
-/* of this package. */
+/* The binary mode restriction applies. */
+CORD_API CORD CORD_from_file_lazy(FILE * f);
+
+/* Turn a cord into a C string. The result shares no structure with */
+/* x, and is thus modifiable. */
+CORD_API char * CORD_to_char_star(CORD x);
+
+/* Turn a C string into a CORD. The C string is copied, and so may */
+/* subsequently be modified. */
+CORD_API CORD CORD_from_char_star(const char *s);
+
+/* Identical to the above, but the result may share structure with */
+/* the argument and is thus not modifiable. */
+CORD_API const char * CORD_to_const_char_star(CORD x);
+
+/* Write a cord to a file, starting at the current position. No */
+/* trailing NULs are newlines are added. */
+/* Returns EOF if a write error occurs, 1 otherwise. */
+CORD_API int CORD_put(CORD x, FILE * f);
+
+/* "Not found" result for the following two functions. */
+#define CORD_NOT_FOUND ((size_t)(-1))
+
+/* A vague analog of strchr. Returns the position (an integer, not */
+/* a pointer) of the first occurrence of (char) c inside x at position */
+/* i or later. The value i must be < CORD_len(x). */
+CORD_API size_t CORD_chr(CORD x, size_t i, int c);
+
+/* A vague analog of strrchr. Returns index of the last occurrence */
+/* of (char) c inside x at position i or earlier. The value i */
+/* must be < CORD_len(x). */
+CORD_API size_t CORD_rchr(CORD x, size_t i, int c);
+
+
+/* The following are also not primitive, but are implemented in */
+/* cordprnt.c. They provide functionality similar to the ANSI C */
+/* functions with corresponding names, but with the following */
+/* additions and changes: */
+/* 1. A %r conversion specification specifies a CORD argument. Field */
+/* width, precision, etc. have the same semantics as for %s. */
+/* (Note that %c, %C, and %S were already taken.) */
+/* 2. The format string is represented as a CORD. */
+/* 3. CORD_sprintf and CORD_vsprintf assign the result through the 1st */
+/* argument. Unlike their ANSI C versions, there is no need to guess */
+/* the correct buffer size. */
+/* 4. Most of the conversions are implement through the native */
+/* vsprintf. Hence they are usually no faster, and */
+/* idiosyncracies of the native printf are preserved. However, */
+/* CORD arguments to CORD_sprintf and CORD_vsprintf are NOT copied; */
+/* the result shares the original structure. This may make them */
+/* very efficient in some unusual applications. */
+/* The format string is copied. */
+/* All functions return the number of characters generated or -1 on */
+/* error. This complies with the ANSI standard, but is inconsistent */
+/* with some older implementations of sprintf. */
+
+/* The implementation of these is probably less portable than the rest */
+/* of this package. */
#ifndef CORD_NO_IO
#include <stdarg.h>
-int CORD_sprintf(CORD * out, CORD format, ...);
-int CORD_vsprintf(CORD * out, CORD format, va_list args);
-int CORD_fprintf(FILE * f, CORD format, ...);
-int CORD_vfprintf(FILE * f, CORD format, va_list args);
-int CORD_printf(CORD format, ...);
-int CORD_vprintf(CORD format, va_list args);
+CORD_API int CORD_sprintf(CORD * out, CORD format, ...);
+CORD_API int CORD_vsprintf(CORD * out, CORD format, va_list args);
+CORD_API int CORD_fprintf(FILE * f, CORD format, ...);
+CORD_API int CORD_vfprintf(FILE * f, CORD format, va_list args);
+CORD_API int CORD_printf(CORD format, ...);
+CORD_API int CORD_vprintf(CORD format, va_list args);
#endif /* CORD_NO_IO */
-# endif /* CORD_H */
+#endif /* CORD_H */
diff --git a/boehm-gc/include/cord_pos.h b/boehm-gc/include/cord_pos.h
new file mode 100644
index 00000000000..beaa2368e3c
--- /dev/null
+++ b/boehm-gc/include/cord_pos.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* This should never be included directly; included only from cord.h. */
+#if !defined(CORD_POSITION_H) && defined(CORD_H)
+#define CORD_POSITION_H
+
+/* The representation of CORD_position. This is private to the */
+/* implementation, but the size is known to clients. Also */
+/* the implementation of some exported macros relies on it. */
+/* Don't use anything defined here and not in cord.h. */
+
+# define MAX_DEPTH 48
+ /* The maximum depth of a balanced cord + 1. */
+ /* We don't let cords get deeper than MAX_DEPTH. */
+
+struct CORD_pe {
+ CORD pe_cord;
+ size_t pe_start_pos;
+};
+
+/* A structure describing an entry on the path from the root */
+/* to current position. */
+typedef struct CORD_Pos {
+ size_t cur_pos;
+ int path_len;
+# define CORD_POS_INVALID (0x55555555)
+ /* path_len == INVALID <==> position invalid */
+ const char *cur_leaf; /* Current leaf, if it is a string. */
+ /* If the current leaf is a function, */
+ /* then this may point to function_buf */
+ /* containing the next few characters. */
+ /* Always points to a valid string */
+ /* containing the current character */
+ /* unless cur_end is 0. */
+ size_t cur_start; /* Start position of cur_leaf */
+ size_t cur_end; /* Ending position of cur_leaf */
+ /* 0 if cur_leaf is invalid. */
+ struct CORD_pe path[MAX_DEPTH + 1];
+ /* path[path_len] is the leaf corresponding to cur_pos */
+ /* path[0].pe_cord is the cord we point to. */
+# define FUNCTION_BUF_SZ 8
+ char function_buf[FUNCTION_BUF_SZ]; /* Space for next few chars */
+ /* from function node. */
+} CORD_pos[1];
+
+/* Extract the cord from a position: */
+CORD_API CORD CORD_pos_to_cord(CORD_pos p);
+
+/* Extract the current index from a position: */
+CORD_API size_t CORD_pos_to_index(CORD_pos p);
+
+/* Fetch the character located at the given position: */
+CORD_API char CORD_pos_fetch(CORD_pos p);
+
+/* Initialize the position to refer to the give cord and index. */
+/* Note that this is the most expensive function on positions: */
+CORD_API void CORD_set_pos(CORD_pos p, CORD x, size_t i);
+
+/* Advance the position to the next character. */
+/* P must be initialized and valid. */
+/* Invalidates p if past end: */
+CORD_API void CORD_next(CORD_pos p);
+
+/* Move the position to the preceding character. */
+/* P must be initialized and valid. */
+/* Invalidates p if past beginning: */
+CORD_API void CORD_prev(CORD_pos p);
+
+/* Is the position valid, i.e. inside the cord? */
+CORD_API int CORD_pos_valid(CORD_pos p);
+
+CORD_API char CORD__pos_fetch(CORD_pos);
+CORD_API void CORD__next(CORD_pos);
+CORD_API void CORD__prev(CORD_pos);
+
+#define CORD_pos_fetch(p) \
+ (((p)[0].cur_end != 0)? \
+ (p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \
+ : CORD__pos_fetch(p))
+
+#define CORD_next(p) \
+ (((p)[0].cur_pos + 1 < (p)[0].cur_end)? \
+ (p)[0].cur_pos++ \
+ : (CORD__next(p), 0))
+
+#define CORD_prev(p) \
+ (((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start)? \
+ (p)[0].cur_pos-- \
+ : (CORD__prev(p), 0))
+
+#define CORD_pos_to_index(p) ((p)[0].cur_pos)
+
+#define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord)
+
+#define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID)
+
+/* Some grubby stuff for performance-critical friends: */
+#define CORD_pos_chars_left(p) ((long)((p)[0].cur_end) - (long)((p)[0].cur_pos))
+ /* Number of characters in cache. <= 0 ==> none */
+
+#define CORD_pos_advance(p,n) ((p)[0].cur_pos += (n) - 1, CORD_next(p))
+ /* Advance position by n characters */
+ /* 0 < n < CORD_pos_chars_left(p) */
+
+#define CORD_pos_cur_char_addr(p) \
+ (p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start)
+ /* address of current character in cache. */
+
+#endif
diff --git a/boehm-gc/include/ec.h b/boehm-gc/include/ec.h
index c829b83ad11..b88e70356df 100644
--- a/boehm-gc/include/ec.h
+++ b/boehm-gc/include/ec.h
@@ -5,26 +5,26 @@
# include "cord.h"
# endif
-/* Extensible cords are strings that may be destructively appended to. */
-/* They allow fast construction of cords from characters that are */
-/* being read from a stream. */
+/* Extensible cords are strings that may be destructively appended to. */
+/* They allow fast construction of cords from characters that are */
+/* being read from a stream. */
/*
* A client might look like:
*
- * {
- * CORD_ec x;
- * CORD result;
- * char c;
- * FILE *f;
+ * {
+ * CORD_ec x;
+ * CORD result;
+ * char c;
+ * FILE *f;
*
- * ...
- * CORD_ec_init(x);
- * while(...) {
- * c = getc(f);
- * ...
- * CORD_ec_append(x, c);
- * }
- * result = CORD_balance(CORD_ec_to_cord(x));
+ * ...
+ * CORD_ec_init(x);
+ * while(...) {
+ * c = getc(f);
+ * ...
+ * CORD_ec_append(x, c);
+ * }
+ * result = CORD_balance(CORD_ec_to_cord(x));
*
* If a C string is desired as the final result, the call to CORD_balance
* may be replaced by a call to CORD_to_char_star.
@@ -40,31 +40,31 @@ typedef struct CORD_ec_struct {
char ec_buf[CORD_BUFSZ+1];
} CORD_ec[1];
-/* This structure represents the concatenation of ec_cord with */
-/* ec_buf[0 ... (ec_bufptr-ec_buf-1)] */
+/* This structure represents the concatenation of ec_cord with */
+/* ec_buf[0 ... (ec_bufptr-ec_buf-1)] */
-/* Flush the buffer part of the extended chord into ec_cord. */
-/* Note that this is almost the only real function, and it is */
-/* implemented in 6 lines in cordxtra.c */
+/* Flush the buffer part of the extended chord into ec_cord. */
+/* Note that this is almost the only real function, and it is */
+/* implemented in 6 lines in cordxtra.c */
void CORD_ec_flush_buf(CORD_ec x);
-
+
/* Convert an extensible cord to a cord. */
# define CORD_ec_to_cord(x) (CORD_ec_flush_buf(x), (x)[0].ec_cord)
/* Initialize an extensible cord. */
# define CORD_ec_init(x) ((x)[0].ec_cord = 0, (x)[0].ec_bufptr = (x)[0].ec_buf)
-/* Append a character to an extensible cord. */
+/* Append a character to an extensible cord. */
# define CORD_ec_append(x, c) \
{ \
- if ((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ) { \
- CORD_ec_flush_buf(x); \
- } \
- *((x)[0].ec_bufptr)++ = (c); \
+ if ((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ) { \
+ CORD_ec_flush_buf(x); \
+ } \
+ *((x)[0].ec_bufptr)++ = (c); \
}
-/* Append a cord to an extensible cord. Structure remains shared with */
-/* original. */
+/* Append a cord to an extensible cord. Structure remains shared with */
+/* original. */
void CORD_ec_append_cord(CORD_ec x, CORD s);
# endif /* EC_H */
diff --git a/boehm-gc/include/extra/gc.h b/boehm-gc/include/extra/gc.h
new file mode 100644
index 00000000000..55ae4c6c14b
--- /dev/null
+++ b/boehm-gc/include/extra/gc.h
@@ -0,0 +1,2 @@
+/* This file is installed for backward compatibility. */
+#include <gc/gc.h>
diff --git a/boehm-gc/include/extra/gc_cpp.h b/boehm-gc/include/extra/gc_cpp.h
new file mode 100644
index 00000000000..36669f9c8d5
--- /dev/null
+++ b/boehm-gc/include/extra/gc_cpp.h
@@ -0,0 +1,2 @@
+/* This file is installed for backward compatibility. */
+#include <gc/gc_cpp.h>
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index 2a8900913df..4063e7945fd 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -1,8 +1,10 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
* Copyright 1996-1999 by Silicon Graphics. All rights reserved.
* Copyright 1999 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (C) 2007 Free Software Foundation, Inc
+ * Copyright (c) 2000-2011 by Hewlett-Packard Development Company.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -25,955 +27,1707 @@
* Everything else is best ignored unless you encounter performance
* problems.
*/
-
-#ifndef _GC_H
-
-# define _GC_H
-# include "gc_config_macros.h"
+#ifndef GC_H
+#define GC_H
-# if defined(__STDC__) || defined(__cplusplus)
-# define GC_PROTO(args) args
- typedef void * GC_PTR;
-# define GC_CONST const
-# else
-# define GC_PROTO(args) ()
- typedef char * GC_PTR;
-# define GC_CONST
-# endif
+#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. GC_get_version() can be used to obtain */
+ /* the latter. */
-# ifdef __cplusplus
- extern "C" {
-# endif
+#include "gc_config_macros.h"
+#ifdef __cplusplus
+ extern "C" {
+#endif
-/* Define word and signed_word to be unsigned and signed types of the */
-/* size as char * or void *. There seems to be no way to do this */
-/* even semi-portably. The following is probably no better/worse */
-/* than almost anything else. */
-/* The ANSI standard suggests that size_t and ptr_diff_t might be */
-/* better choices. But those had incorrect definitions on some older */
-/* systems. Notably "typedef int size_t" is WRONG. */
-#ifndef _WIN64
+typedef void * GC_PTR; /* preserved only for backward compatibility */
+
+/* Define word and signed_word to be unsigned and signed types of the */
+/* size as char * or void *. There seems to be no way to do this */
+/* even semi-portably. The following is probably no better/worse */
+/* than almost anything else. */
+/* The ANSI standard suggests that size_t and ptrdiff_t might be */
+/* better choices. But those had incorrect definitions on some older */
+/* systems. Notably "typedef int size_t" is WRONG. */
+#ifdef _WIN64
+# ifdef __int64
+ typedef unsigned __int64 GC_word;
+ typedef __int64 GC_signed_word;
+# else
+ typedef unsigned long long GC_word;
+ typedef long long GC_signed_word;
+# endif
+#else
typedef unsigned long GC_word;
typedef long GC_signed_word;
-#else
- /* Win64 isn't really supported yet, but this is the first step. And */
- /* it might cause error messages to show up in more plausible places. */
- /* This needs basetsd.h, which is included by windows.h. */
- typedef ULONG_PTR GC_word;
- typedef LONG_PTR GC_word;
#endif
-/* Public read-only variables */
+/* Get the GC library version. The returned value is a constant in the */
+/* form: ((version_major<<16) | (version_minor<<8) | alpha_version). */
+GC_API unsigned GC_CALL GC_get_version(void);
-GC_API GC_word GC_gc_no;/* Counter incremented per collection. */
- /* Includes empty GCs at startup. */
+/* Public read-only variables */
+/* The supplied getter functions are preferred for new code. */
+
+GC_API GC_ATTR_DEPRECATED GC_word GC_gc_no;
+ /* Counter incremented per collection. */
+ /* Includes empty GCs at startup. */
+GC_API GC_word GC_CALL GC_get_gc_no(void);
+ /* GC_get_gc_no() is unsynchronized, so */
+ /* it requires GC_call_with_alloc_lock() to */
+ /* avoid data races on multiprocessors. */
+
+#ifdef GC_THREADS
+ GC_API GC_ATTR_DEPRECATED int GC_parallel;
+ /* GC is parallelized for performance on */
+ /* multiprocessors. Currently set only */
+ /* implicitly if collector is built with */
+ /* PARALLEL_MARK defined and if either: */
+ /* Env variable GC_NPROC is set to > 1, or */
+ /* GC_NPROC is not set and this is an MP. */
+ /* If GC_parallel is on (non-zero), incremental */
+ /* collection is only partially functional, */
+ /* and may not be desirable. The getter does */
+ /* not use or need synchronization (i.e. */
+ /* acquiring the GC lock). Starting from */
+ /* GC v7.3, GC_parallel value is equal to the */
+ /* number of marker threads minus one (i.e. */
+ /* number of existing parallel marker threads */
+ /* excluding the initiating one). */
+ GC_API int GC_CALL GC_get_parallel(void);
+#endif
-GC_API int GC_parallel; /* GC is parallelized for performance on */
- /* multiprocessors. Currently set only */
- /* implicitly if collector is built with */
- /* -DPARALLEL_MARK and if either: */
- /* Env variable GC_NPROC is set to > 1, or */
- /* GC_NPROC is not set and this is an MP. */
- /* If GC_parallel is set, incremental */
- /* collection is only partially functional, */
- /* and may not be desirable. */
-
/* Public R/W variables */
-
-GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
- /* When there is insufficient memory to satisfy */
- /* an allocation request, we return */
- /* (*GC_oom_fn)(). By default this just */
- /* returns 0. */
- /* If it returns, it must return 0 or a valid */
- /* pointer to a previously allocated heap */
- /* object. */
-
-GC_API int GC_find_leak;
- /* Do not actually garbage collect, but simply */
- /* report inaccessible memory that was not */
- /* deallocated with GC_free. Initial value */
- /* is determined by FIND_LEAK macro. */
-
-GC_API int GC_all_interior_pointers;
- /* Arrange for pointers to object interiors to */
- /* be recognized as valid. May not be changed */
- /* after GC initialization. */
- /* Initial value is determined by */
- /* -DALL_INTERIOR_POINTERS. */
- /* Unless DONT_ADD_BYTE_AT_END is defined, this */
- /* also affects whether sizes are increased by */
- /* at least a byte to allow "off the end" */
- /* pointer recognition. */
- /* MUST BE 0 or 1. */
-
-GC_API int GC_quiet; /* Disable statistics output. Only matters if */
- /* collector has been compiled with statistics */
- /* enabled. This involves a performance cost, */
- /* and is thus not the default. */
-
-GC_API int GC_finalize_on_demand;
- /* If nonzero, finalizers will only be run in */
- /* response to an explicit GC_invoke_finalizers */
- /* call. The default is determined by whether */
- /* the FINALIZE_ON_DEMAND macro is defined */
- /* when the collector is built. */
-
-GC_API int GC_java_finalization;
- /* Mark objects reachable from finalizable */
- /* objects in a separate postpass. This makes */
- /* it a bit safer to use non-topologically- */
- /* ordered finalization. Default value is */
- /* determined by JAVA_FINALIZATION macro. */
-
-GC_API void (* GC_finalizer_notifier)();
- /* Invoked by the collector when there are */
- /* objects to be finalized. Invoked at most */
- /* once per GC cycle. Never invoked unless */
- /* GC_finalize_on_demand is set. */
- /* Typically this will notify a finalization */
- /* thread, which will call GC_invoke_finalizers */
- /* in response. */
-
-GC_API int GC_dont_gc; /* != 0 ==> Dont collect. In versions 6.2a1+, */
- /* this overrides explicit GC_gcollect() calls. */
- /* Used as a counter, so that nested enabling */
- /* and disabling work correctly. Should */
- /* normally be updated with GC_enable() and */
- /* GC_disable() calls. */
- /* Direct assignment to GC_dont_gc is */
- /* deprecated. */
-
-GC_API int GC_dont_expand;
- /* Dont expand heap unless explicitly requested */
- /* or forced to. */
-
-GC_API int GC_use_entire_heap;
- /* Causes the nonincremental collector to use the */
- /* entire heap before collecting. This was the only */
- /* option for GC versions < 5.0. This sometimes */
- /* results in more large block fragmentation, since */
- /* very larg blocks will tend to get broken up */
- /* during each GC cycle. It is likely to result in a */
- /* larger working set, but lower collection */
- /* frequencies, and hence fewer instructions executed */
- /* in the collector. */
-
-GC_API int GC_full_freq; /* Number of partial collections between */
- /* full collections. Matters only if */
- /* GC_incremental is set. */
- /* Full collections are also triggered if */
- /* the collector detects a substantial */
- /* increase in the number of in-use heap */
- /* blocks. Values in the tens are now */
- /* perfectly reasonable, unlike for */
- /* earlier GC versions. */
-
-GC_API GC_word GC_non_gc_bytes;
- /* Bytes not considered candidates for collection. */
- /* Used only to control scheduling of collections. */
- /* Updated by GC_malloc_uncollectable and GC_free. */
- /* Wizards only. */
-
-GC_API int GC_no_dls;
- /* Don't register dynamic library data segments. */
- /* Wizards only. Should be used only if the */
- /* application explicitly registers all roots. */
- /* In Microsoft Windows environments, this will */
- /* usually also prevent registration of the */
- /* main data segment as part of the root set. */
-
-GC_API GC_word GC_free_space_divisor;
- /* We try to make sure that we allocate at */
- /* least N/GC_free_space_divisor bytes between */
- /* collections, where N is the heap size plus */
- /* a rough estimate of the root set size. */
- /* Initially, GC_free_space_divisor = 4. */
- /* Increasing its value will use less space */
- /* but more collection time. Decreasing it */
- /* will appreciably decrease collection time */
- /* at the expense of space. */
- /* GC_free_space_divisor = 1 will effectively */
- /* disable collections. */
-
-GC_API GC_word GC_max_retries;
- /* The maximum number of GCs attempted before */
- /* reporting out of memory after heap */
- /* expansion fails. Initially 0. */
-
-
-GC_API char *GC_stackbottom; /* Cool end of user stack. */
- /* May be set in the client prior to */
- /* calling any GC_ routines. This */
- /* avoids some overhead, and */
- /* potentially some signals that can */
- /* confuse debuggers. Otherwise the */
- /* collector attempts to set it */
- /* automatically. */
- /* For multithreaded code, this is the */
- /* cold end of the stack for the */
- /* primordial thread. */
-
-GC_API int GC_dont_precollect; /* Don't collect as part of */
- /* initialization. Should be set only */
- /* if the client wants a chance to */
- /* manually initialize the root set */
- /* before the first collection. */
- /* Interferes with blacklisting. */
- /* Wizards only. */
-
-GC_API unsigned long GC_time_limit;
- /* If incremental collection is enabled, */
- /* We try to terminate collections */
- /* after this many milliseconds. Not a */
- /* hard time bound. Setting this to */
- /* GC_TIME_UNLIMITED will essentially */
- /* disable incremental collection while */
- /* leaving generational collection */
- /* enabled. */
-# define GC_TIME_UNLIMITED 999999
- /* Setting GC_time_limit to this value */
- /* will disable the "pause time exceeded"*/
- /* tests. */
+/* The supplied setter and getter functions are preferred for new code. */
+
+typedef void * (GC_CALLBACK * GC_oom_func)(size_t /* bytes_requested */);
+GC_API GC_ATTR_DEPRECATED GC_oom_func GC_oom_fn;
+ /* When there is insufficient memory to satisfy */
+ /* an allocation request, we return */
+ /* (*GC_oom_fn)(size). By default this just */
+ /* returns NULL. */
+ /* If it returns, it must return 0 or a valid */
+ /* pointer to a previously allocated heap */
+ /* object. GC_oom_fn must not be 0. */
+ /* Both the supplied setter and the getter */
+ /* acquire the GC lock (to avoid data races). */
+GC_API void GC_CALL GC_set_oom_fn(GC_oom_func) GC_ATTR_NONNULL(1);
+GC_API GC_oom_func GC_CALL GC_get_oom_fn(void);
+
+typedef void (GC_CALLBACK * GC_on_heap_resize_proc)(GC_word /* new_size */);
+GC_API GC_ATTR_DEPRECATED GC_on_heap_resize_proc GC_on_heap_resize;
+ /* Invoked when the heap grows or shrinks. */
+ /* Called with the world stopped (and the */
+ /* allocation lock held). May be 0. */
+GC_API void GC_CALL GC_set_on_heap_resize(GC_on_heap_resize_proc);
+GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void);
+ /* Both the supplied setter and the getter */
+ /* acquire the GC lock (to avoid data races). */
+
+GC_API GC_ATTR_DEPRECATED int GC_find_leak;
+ /* Do not actually garbage collect, but simply */
+ /* report inaccessible memory that was not */
+ /* deallocated with GC_free. Initial value */
+ /* is determined by FIND_LEAK macro. */
+ /* The value should not typically be modified */
+ /* after GC initialization (and, thus, it does */
+ /* not use or need synchronization). */
+GC_API void GC_CALL GC_set_find_leak(int);
+GC_API int GC_CALL GC_get_find_leak(void);
+
+GC_API GC_ATTR_DEPRECATED int GC_all_interior_pointers;
+ /* Arrange for pointers to object interiors to */
+ /* be recognized as valid. Typically should */
+ /* not be changed after GC initialization (in */
+ /* case of calling it after the GC is */
+ /* initialized, the setter acquires the GC lock */
+ /* (to avoid data races). The initial value */
+ /* depends on whether the GC is built with */
+ /* ALL_INTERIOR_POINTERS macro defined or not. */
+ /* Unless DONT_ADD_BYTE_AT_END is defined, this */
+ /* also affects whether sizes are increased by */
+ /* at least a byte to allow "off the end" */
+ /* pointer recognition. Must be only 0 or 1. */
+GC_API void GC_CALL GC_set_all_interior_pointers(int);
+GC_API int GC_CALL GC_get_all_interior_pointers(void);
+
+GC_API GC_ATTR_DEPRECATED int GC_finalize_on_demand;
+ /* If nonzero, finalizers will only be run in */
+ /* response to an explicit GC_invoke_finalizers */
+ /* call. The default is determined by whether */
+ /* the FINALIZE_ON_DEMAND macro is defined */
+ /* when the collector is built. */
+ /* The setter and getter are unsynchronized. */
+GC_API void GC_CALL GC_set_finalize_on_demand(int);
+GC_API int GC_CALL GC_get_finalize_on_demand(void);
+
+GC_API GC_ATTR_DEPRECATED int GC_java_finalization;
+ /* Mark objects reachable from finalizable */
+ /* objects in a separate post-pass. This makes */
+ /* it a bit safer to use non-topologically- */
+ /* ordered finalization. Default value is */
+ /* determined by JAVA_FINALIZATION macro. */
+ /* Enables register_finalizer_unreachable to */
+ /* work correctly. */
+ /* The setter and getter are unsynchronized. */
+GC_API void GC_CALL GC_set_java_finalization(int);
+GC_API int GC_CALL GC_get_java_finalization(void);
+
+typedef void (GC_CALLBACK * GC_finalizer_notifier_proc)(void);
+GC_API GC_ATTR_DEPRECATED GC_finalizer_notifier_proc GC_finalizer_notifier;
+ /* Invoked by the collector when there are */
+ /* objects to be finalized. Invoked at most */
+ /* once per GC cycle. Never invoked unless */
+ /* GC_finalize_on_demand is set. */
+ /* Typically this will notify a finalization */
+ /* thread, which will call GC_invoke_finalizers */
+ /* in response. May be 0 (means no notifier). */
+ /* Both the supplied setter and the getter */
+ /* acquire the GC lock (to avoid data races). */
+GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc);
+GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void);
+
+GC_API GC_ATTR_DEPRECATED int GC_dont_gc;
+ /* != 0 ==> Don't collect. In versions 6.2a1+, */
+ /* this overrides explicit GC_gcollect() calls. */
+ /* Used as a counter, so that nested enabling */
+ /* and disabling work correctly. Should */
+ /* normally be updated with GC_enable() and */
+ /* GC_disable() calls. Direct assignment to */
+ /* GC_dont_gc is deprecated. To check whether */
+ /* GC is disabled, GC_is_disabled() is */
+ /* preferred for new code. */
+
+GC_API GC_ATTR_DEPRECATED int GC_dont_expand;
+ /* Do not expand the heap unless explicitly */
+ /* requested or forced to. The setter and */
+ /* getter are unsynchronized. */
+GC_API void GC_CALL GC_set_dont_expand(int);
+GC_API int GC_CALL GC_get_dont_expand(void);
+
+GC_API GC_ATTR_DEPRECATED int GC_use_entire_heap;
+ /* Causes the non-incremental collector to use the */
+ /* entire heap before collecting. This was the only */
+ /* option for GC versions < 5.0. This sometimes */
+ /* results in more large block fragmentation, since */
+ /* very large blocks will tend to get broken up */
+ /* during each GC cycle. It is likely to result in a */
+ /* larger working set, but lower collection */
+ /* frequencies, and hence fewer instructions executed */
+ /* in the collector. */
+
+GC_API GC_ATTR_DEPRECATED int GC_full_freq;
+ /* Number of partial collections between */
+ /* full collections. Matters only if */
+ /* GC_incremental is set. */
+ /* Full collections are also triggered if */
+ /* the collector detects a substantial */
+ /* increase in the number of in-use heap */
+ /* blocks. Values in the tens are now */
+ /* perfectly reasonable, unlike for */
+ /* earlier GC versions. */
+ /* The setter and getter are unsynchronized, so */
+ /* GC_call_with_alloc_lock() is required to */
+ /* avoid data races (if the value is modified */
+ /* after the GC is put to multi-threaded mode). */
+GC_API void GC_CALL GC_set_full_freq(int);
+GC_API int GC_CALL GC_get_full_freq(void);
+
+GC_API GC_ATTR_DEPRECATED GC_word GC_non_gc_bytes;
+ /* Bytes not considered candidates for */
+ /* collection. Used only to control scheduling */
+ /* of collections. Updated by */
+ /* GC_malloc_uncollectable and GC_free. */
+ /* Wizards only. */
+ /* The setter and getter are unsynchronized, so */
+ /* GC_call_with_alloc_lock() is required to */
+ /* avoid data races (if the value is modified */
+ /* after the GC is put to multi-threaded mode). */
+GC_API void GC_CALL GC_set_non_gc_bytes(GC_word);
+GC_API GC_word GC_CALL GC_get_non_gc_bytes(void);
+
+GC_API GC_ATTR_DEPRECATED int GC_no_dls;
+ /* Don't register dynamic library data segments. */
+ /* Wizards only. Should be used only if the */
+ /* application explicitly registers all roots. */
+ /* (In some environments like Microsoft Windows */
+ /* and Apple's Darwin, this may also prevent */
+ /* registration of the main data segment as part */
+ /* of the root set.) */
+ /* The setter and getter are unsynchronized. */
+GC_API void GC_CALL GC_set_no_dls(int);
+GC_API int GC_CALL GC_get_no_dls(void);
+
+GC_API GC_ATTR_DEPRECATED GC_word GC_free_space_divisor;
+ /* We try to make sure that we allocate at */
+ /* least N/GC_free_space_divisor bytes between */
+ /* collections, where N is twice the number */
+ /* of traced bytes, plus the number of untraced */
+ /* bytes (bytes in "atomic" objects), plus */
+ /* a rough estimate of the root set size. */
+ /* N approximates GC tracing work per GC. */
+ /* Initially, GC_free_space_divisor = 3. */
+ /* Increasing its value will use less space */
+ /* but more collection time. Decreasing it */
+ /* will appreciably decrease collection time */
+ /* at the expense of space. */
+ /* The setter and getter are unsynchronized, so */
+ /* GC_call_with_alloc_lock() is required to */
+ /* avoid data races (if the value is modified */
+ /* after the GC is put to multi-threaded mode). */
+GC_API void GC_CALL GC_set_free_space_divisor(GC_word);
+GC_API GC_word GC_CALL GC_get_free_space_divisor(void);
+
+GC_API GC_ATTR_DEPRECATED GC_word GC_max_retries;
+ /* The maximum number of GCs attempted before */
+ /* reporting out of memory after heap */
+ /* expansion fails. Initially 0. */
+ /* The setter and getter are unsynchronized, so */
+ /* GC_call_with_alloc_lock() is required to */
+ /* avoid data races (if the value is modified */
+ /* after the GC is put to multi-threaded mode). */
+GC_API void GC_CALL GC_set_max_retries(GC_word);
+GC_API GC_word GC_CALL GC_get_max_retries(void);
+
+
+GC_API GC_ATTR_DEPRECATED char *GC_stackbottom;
+ /* Cool end of user stack. */
+ /* May be set in the client prior to */
+ /* calling any GC_ routines. This */
+ /* avoids some overhead, and */
+ /* potentially some signals that can */
+ /* confuse debuggers. Otherwise the */
+ /* collector attempts to set it */
+ /* automatically. */
+ /* For multi-threaded code, this is the */
+ /* cold end of the stack for the */
+ /* primordial thread. Portable clients */
+ /* should use GC_get_stack_base(), */
+ /* GC_call_with_gc_active() and */
+ /* GC_register_my_thread() instead. */
+
+GC_API GC_ATTR_DEPRECATED int GC_dont_precollect;
+ /* Do not collect as part of GC */
+ /* initialization. Should be set only */
+ /* if the client wants a chance to */
+ /* manually initialize the root set */
+ /* before the first collection. */
+ /* Interferes with blacklisting. */
+ /* Wizards only. The setter and getter */
+ /* are unsynchronized (and no external */
+ /* locking is needed since the value is */
+ /* accessed at GC initialization only). */
+GC_API void GC_CALL GC_set_dont_precollect(int);
+GC_API int GC_CALL GC_get_dont_precollect(void);
+
+GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit;
+ /* If incremental collection is enabled, */
+ /* We try to terminate collections */
+ /* after this many milliseconds. Not a */
+ /* hard time bound. Setting this to */
+ /* GC_TIME_UNLIMITED will essentially */
+ /* disable incremental collection while */
+ /* leaving generational collection */
+ /* enabled. */
+#define GC_TIME_UNLIMITED 999999
+ /* Setting GC_time_limit to this value */
+ /* will disable the "pause time exceeded"*/
+ /* tests. */
+ /* The setter and getter are unsynchronized, so */
+ /* GC_call_with_alloc_lock() is required to */
+ /* avoid data races (if the value is modified */
+ /* after the GC is put to multi-threaded mode). */
+GC_API void GC_CALL GC_set_time_limit(unsigned long);
+GC_API unsigned long GC_CALL GC_get_time_limit(void);
/* 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.
- */
-GC_API void GC_init GC_PROTO((void));
-
-/*
- * general purpose allocation routines, with roughly malloc calling conv.
- * The atomic versions promise that no relevant pointers are contained
- * in the object. The nonatomic versions guarantee that the new object
- * is cleared. GC_malloc_stubborn promises that no changes to the object
- * will occur after GC_end_stubborn_change has been called on the
- * result of GC_malloc_stubborn. GC_malloc_uncollectable allocates an object
- * that is scanned for pointers to collectable objects, but is not itself
- * collectable. The object is scanned even if it does not appear to
- * be reachable. GC_malloc_uncollectable and GC_free called on the resulting
- * object implicitly update GC_non_gc_bytes appropriately.
- *
- * Note that the GC_malloc_stubborn support is stubbed out by default
- * starting in 6.0. GC_malloc_stubborn is an alias for GC_malloc unless
- * the collector is built with STUBBORN_ALLOC defined.
- */
-GC_API GC_PTR GC_malloc GC_PROTO((size_t size_in_bytes));
-GC_API GC_PTR GC_malloc_atomic GC_PROTO((size_t size_in_bytes));
-GC_API GC_PTR GC_malloc_uncollectable GC_PROTO((size_t size_in_bytes));
-GC_API GC_PTR GC_malloc_stubborn GC_PROTO((size_t size_in_bytes));
-
-/* The following is only defined if the library has been suitably */
-/* compiled: */
-GC_API GC_PTR GC_malloc_atomic_uncollectable GC_PROTO((size_t size_in_bytes));
+/* Set whether the GC will allocate executable memory pages or not. */
+/* A non-zero argument instructs the collector to allocate memory with */
+/* the executable flag on. Must be called before the collector is */
+/* initialized. May have no effect on some platforms. The default */
+/* value is controlled by NO_EXECUTE_PERMISSION macro (if present then */
+/* the flag is off). Portable clients should have */
+/* GC_set_pages_executable(1) call (before GC_INIT) provided they are */
+/* going to execute code on any of the GC-allocated memory objects. */
+GC_API void GC_CALL GC_set_pages_executable(int);
+
+/* Returns non-zero value if the GC is set to the allocate-executable */
+/* mode. The mode could be changed by GC_set_pages_executable (before */
+/* GC_INIT) unless the former has no effect on the platform. Does not */
+/* use or need synchronization (i.e. acquiring the allocator lock). */
+GC_API int GC_CALL GC_get_pages_executable(void);
+
+/* Overrides the default handle-fork mode. Non-zero value means GC */
+/* should install proper pthread_atfork handlers. Has effect only if */
+/* called before GC_INIT. Clients should invoke GC_set_handle_fork */
+/* with non-zero argument if going to use fork with GC functions called */
+/* in the forked child. (Note that such client and atfork handlers */
+/* activities are not fully POSIX-compliant.) GC_set_handle_fork */
+/* instructs GC_init to setup GC fork handlers using pthread_atfork, */
+/* the latter might fail (or, even, absent on some targets) causing */
+/* abort at GC initialization. Starting from 7.3alpha3, problems with */
+/* missing (or failed) pthread_atfork() could be avoided by invocation */
+/* of GC_set_handle_fork(-1) at application start-up and surrounding */
+/* each fork() with the relevant GC_atfork_prepare/parent/child calls. */
+GC_API void GC_CALL GC_set_handle_fork(int);
+
+/* Routines to handle POSIX fork() manually (no-op if handled */
+/* automatically). GC_atfork_prepare should be called immediately */
+/* before fork(); GC_atfork_parent should be invoked just after fork in */
+/* the branch that corresponds to parent process (i.e., fork result is */
+/* non-zero); GC_atfork_child is to be called immediately in the child */
+/* branch (i.e., fork result is 0). Note that GC_atfork_child() call */
+/* should, of course, precede GC_start_mark_threads call (if any). */
+GC_API void GC_CALL GC_atfork_prepare(void);
+GC_API void GC_CALL GC_atfork_parent(void);
+GC_API void GC_CALL GC_atfork_child(void);
+
+/* Initialize the collector. Portable clients should call GC_INIT() */
+/* from the main program instead. */
+GC_API void GC_CALL GC_init(void);
+
+/* General purpose allocation routines, with roughly malloc calling */
+/* conv. The atomic versions promise that no relevant pointers are */
+/* contained in the object. The non-atomic versions guarantee that the */
+/* new object is cleared. GC_malloc_stubborn promises that no changes */
+/* to the object will occur after GC_end_stubborn_change has been */
+/* called on the result of GC_malloc_stubborn. GC_malloc_uncollectable */
+/* allocates an object that is scanned for pointers to collectable */
+/* objects, but is not itself collectable. The object is scanned even */
+/* if it does not appear to be reachable. GC_malloc_uncollectable and */
+/* GC_free called on the resulting object implicitly update */
+/* GC_non_gc_bytes appropriately. */
+/* Note that the GC_malloc_stubborn support doesn't really exist */
+/* anymore. MANUAL_VDB provides comparable functionality. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_malloc(size_t /* size_in_bytes */);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_malloc_atomic(size_t /* size_in_bytes */);
+GC_API GC_ATTR_MALLOC char * GC_CALL GC_strdup(const char *);
+GC_API GC_ATTR_MALLOC char * GC_CALL
+ GC_strndup(const char *, size_t) GC_ATTR_NONNULL(1);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_malloc_uncollectable(size_t /* size_in_bytes */);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_malloc_stubborn(size_t /* size_in_bytes */);
+
+/* GC_memalign() is not well tested. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(2) void * GC_CALL
+ GC_memalign(size_t /* align */, size_t /* lb */);
+GC_API int GC_CALL GC_posix_memalign(void ** /* memptr */, size_t /* align */,
+ size_t /* lb */) GC_ATTR_NONNULL(1);
/* Explicitly deallocate an object. Dangerous if used incorrectly. */
-/* Requires a pointer to the base of an object. */
+/* Requires a pointer to the base of an object. */
/* If the argument is stubborn, it should not be changeable when freed. */
-/* An object should not be enable for finalization when it is */
-/* explicitly deallocated. */
-/* GC_free(0) is a no-op, as required by ANSI C for free. */
-GC_API void GC_free GC_PROTO((GC_PTR object_addr));
-
-/*
- * Stubborn objects may be changed only if the collector is explicitly informed.
- * The collector is implicitly informed of coming change when such
- * an object is first allocated. The following routines inform the
- * collector that an object will no longer be changed, or that it will
- * once again be changed. Only nonNIL pointer stores into the object
- * are considered to be changes. The argument to GC_end_stubborn_change
- * must be exacly the value returned by GC_malloc_stubborn or passed to
- * GC_change_stubborn. (In the second case it may be an interior pointer
- * within 512 bytes of the beginning of the objects.)
- * There is a performance penalty for allowing more than
- * one stubborn object to be changed at once, but it is acceptable to
- * do so. The same applies to dropping stubborn objects that are still
- * changeable.
- */
-GC_API void GC_change_stubborn GC_PROTO((GC_PTR));
-GC_API void GC_end_stubborn_change GC_PROTO((GC_PTR));
-
-/* Return a pointer to the base (lowest address) of an object given */
-/* a pointer to a location within the object. */
-/* I.e. map an interior pointer to the corresponding bas pointer. */
-/* Note that with debugging allocation, this returns a pointer to the */
-/* actual base of the object, i.e. the debug information, not to */
-/* the base of the user object. */
-/* Return 0 if displaced_pointer doesn't point to within a valid */
-/* object. */
-GC_API GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
-
-/* Given a pointer to the base of an object, return its size in bytes. */
-/* The returned size may be slightly larger than what was originally */
-/* requested. */
-GC_API size_t GC_size GC_PROTO((GC_PTR object_addr));
-
-/* For compatibility with C library. This is occasionally faster than */
-/* a malloc followed by a bcopy. But if you rely on that, either here */
-/* or with the standard C library, your code is broken. In my */
-/* opinion, it shouldn't have been invented, but now we're stuck. -HB */
-/* The resulting object has the same kind as the original. */
-/* If the argument is stubborn, the result will have changes enabled. */
-/* It is an error to have changes enabled for the original object. */
-/* Follows ANSI comventions for NULL old_object. */
-GC_API GC_PTR GC_realloc
- GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes));
-
-/* Explicitly increase the heap size. */
+/* An object should not be enabled for finalization when it is */
+/* explicitly deallocated. */
+/* GC_free(0) is a no-op, as required by ANSI C for free. */
+GC_API void GC_CALL GC_free(void *);
+
+/* Stubborn objects may be changed only if the collector is explicitly */
+/* informed. The collector is implicitly informed of coming change */
+/* when such an object is first allocated. The following routines */
+/* inform the collector that an object will no longer be changed, or */
+/* that it will once again be changed. Only non-NULL pointer stores */
+/* into the object are considered to be changes. The argument to */
+/* GC_end_stubborn_change must be exactly the value returned by */
+/* GC_malloc_stubborn or passed to GC_change_stubborn. (In the second */
+/* case, it may be an interior pointer within 512 bytes of the */
+/* beginning of the objects.) There is a performance penalty for */
+/* allowing more than one stubborn object to be changed at once, but it */
+/* is acceptable to do so. The same applies to dropping stubborn */
+/* objects that are still changeable. */
+GC_API void GC_CALL GC_change_stubborn(const void *) GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_end_stubborn_change(const void *) GC_ATTR_NONNULL(1);
+
+/* Return a pointer to the base (lowest address) of an object given */
+/* a pointer to a location within the object. */
+/* I.e., map an interior pointer to the corresponding base pointer. */
+/* Note that with debugging allocation, this returns a pointer to the */
+/* actual base of the object, i.e. the debug information, not to */
+/* the base of the user object. */
+/* Return 0 if displaced_pointer doesn't point to within a valid */
+/* object. */
+/* Note that a deallocated object in the garbage collected heap */
+/* may be considered valid, even if it has been deallocated with */
+/* GC_free. */
+GC_API void * GC_CALL GC_base(void * /* displaced_pointer */);
+
+/* Return TRUE if and only if the argument points to somewhere in GC */
+/* heap. Primary use is as a fast alternative to GC_base to check */
+/* whether the pointed object is allocated by GC or not. It is assumed */
+/* that the collector is already initialized. */
+GC_API int GC_CALL GC_is_heap_ptr(const void *);
+
+/* Given a pointer to the base of an object, return its size in bytes. */
+/* The returned size may be slightly larger than what was originally */
+/* requested. */
+GC_API size_t GC_CALL GC_size(const void * /* obj_addr */) GC_ATTR_NONNULL(1);
+
+/* For compatibility with C library. This is occasionally faster than */
+/* a malloc followed by a bcopy. But if you rely on that, either here */
+/* or with the standard C library, your code is broken. In my */
+/* opinion, it shouldn't have been invented, but now we're stuck. -HB */
+/* The resulting object has the same kind as the original. */
+/* If the argument is stubborn, the result will have changes enabled. */
+/* It is an error to have changes enabled for the original object. */
+/* Follows ANSI conventions for NULL old_object. */
+GC_API void * GC_CALL GC_realloc(void * /* old_object */,
+ size_t /* new_size_in_bytes */)
+ /* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2);
+
+/* Explicitly increase the heap size. */
/* Returns 0 on failure, 1 on success. */
-GC_API int GC_expand_hp GC_PROTO((size_t number_of_bytes));
+GC_API int GC_CALL GC_expand_hp(size_t /* number_of_bytes */);
-/* Limit the heap size to n bytes. Useful when you're debugging, */
-/* especially on systems that don't handle running out of memory well. */
-/* n == 0 ==> unbounded. This is the default. */
-GC_API void GC_set_max_heap_size GC_PROTO((GC_word n));
+/* Limit the heap size to n bytes. Useful when you're debugging, */
+/* especially on systems that don't handle running out of memory well. */
+/* n == 0 ==> unbounded. This is the default. This setter function is */
+/* unsynchronized (so it might require GC_call_with_alloc_lock to avoid */
+/* data races). */
+GC_API void GC_CALL GC_set_max_heap_size(GC_word /* n */);
-/* Inform the collector that a certain section of statically allocated */
-/* memory contains no pointers to garbage collected memory. Thus it */
+/* Inform the collector that a certain section of statically allocated */
+/* memory contains no pointers to garbage collected memory. Thus it */
/* need not be scanned. This is sometimes important if the application */
-/* maps large read/write files into the address space, which could be */
-/* mistaken for dynamic library data segments on some systems. */
-GC_API void GC_exclude_static_roots GC_PROTO((GC_PTR start, GC_PTR finish));
-
-/* Clear the set of root segments. Wizards only. */
-GC_API void GC_clear_roots GC_PROTO((void));
-
-/* Add a root segment. Wizards only. */
-GC_API void GC_add_roots GC_PROTO((char * low_address,
- char * high_address_plus_1));
-
-/* Remove a root segment. Wizards only. */
-GC_API void GC_remove_roots GC_PROTO((char * low_address,
- char * high_address_plus_1));
-
-/* Add a displacement to the set of those considered valid by the */
+/* maps large read/write files into the address space, which could be */
+/* mistaken for dynamic library data segments on some systems. */
+/* Both section start and end are not needed to be pointer-aligned. */
+GC_API void GC_CALL GC_exclude_static_roots(void * /* low_address */,
+ void * /* high_address_plus_1 */);
+
+/* Clear the set of root segments. Wizards only. */
+GC_API void GC_CALL GC_clear_roots(void);
+
+/* Add a root segment. Wizards only. */
+/* Both segment start and end are not needed to be pointer-aligned. */
+/* low_address must not be greater than high_address_plus_1. */
+GC_API void GC_CALL GC_add_roots(void * /* low_address */,
+ void * /* high_address_plus_1 */);
+
+/* Remove a root segment. Wizards only. */
+/* May be unimplemented on some platforms. */
+GC_API void GC_CALL GC_remove_roots(void * /* low_address */,
+ void * /* high_address_plus_1 */);
+
+/* Add a displacement to the set of those considered valid by the */
/* collector. GC_register_displacement(n) means that if p was returned */
-/* by GC_malloc, then (char *)p + n will be considered to be a valid */
-/* pointer to p. N must be small and less than the size of p. */
-/* (All pointers to the interior of objects from the stack are */
-/* considered valid in any case. This applies to heap objects and */
-/* static data.) */
-/* Preferably, this should be called before any other GC procedures. */
-/* Calling it later adds to the probability of excess memory */
-/* retention. */
-/* This is a no-op if the collector has recognition of */
-/* arbitrary interior pointers enabled, which is now the default. */
-GC_API void GC_register_displacement GC_PROTO((GC_word n));
-
-/* The following version should be used if any debugging allocation is */
-/* being done. */
-GC_API void GC_debug_register_displacement GC_PROTO((GC_word n));
-
-/* Explicitly trigger a full, world-stop collection. */
-GC_API void GC_gcollect GC_PROTO((void));
-
-/* Trigger a full world-stopped collection. Abort the collection if */
-/* and when stop_func returns a nonzero value. Stop_func will be */
-/* called frequently, and should be reasonably fast. This works even */
-/* if virtual dirty bits, and hence incremental collection is not */
-/* available for this architecture. Collections can be aborted faster */
-/* than normal pause times for incremental collection. However, */
-/* aborted collections do no useful work; the next collection needs */
-/* to start from the beginning. */
-/* Return 0 if the collection was aborted, 1 if it succeeded. */
-typedef int (* GC_stop_func) GC_PROTO((void));
-GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
-
-/* Return the number of bytes in the heap. Excludes collector private */
-/* data structures. Includes empty blocks and fragmentation loss. */
-/* Includes some pages that were allocated but never written. */
-GC_API size_t GC_get_heap_size GC_PROTO((void));
-
-/* Return a lower bound on the number of free bytes in the heap. */
-GC_API size_t GC_get_free_bytes GC_PROTO((void));
-
-/* Return the number of bytes allocated since the last collection. */
-GC_API size_t GC_get_bytes_since_gc GC_PROTO((void));
-
-/* Return the total number of bytes allocated in this process. */
-/* Never decreases, except due to wrapping. */
-GC_API size_t GC_get_total_bytes GC_PROTO((void));
-
-/* Disable garbage collection. Even GC_gcollect calls will be */
-/* ineffective. */
-GC_API void GC_disable GC_PROTO((void));
-
-/* Reenable garbage collection. GC_disable() and GC_enable() calls */
-/* nest. Garbage collection is enabled if the number of calls to both */
-/* both functions is equal. */
-GC_API void GC_enable GC_PROTO((void));
-
-/* Enable incremental/generational collection. */
-/* Not advisable unless dirty bits are */
-/* available or most heap objects are */
-/* pointerfree(atomic) or immutable. */
-/* Don't use in leak finding mode. */
-/* Ignored if GC_dont_gc is true. */
-/* Only the generational piece of this is */
-/* functional if GC_parallel is TRUE */
-/* or if GC_time_limit is GC_TIME_UNLIMITED. */
-/* Causes GC_local_gcj_malloc() to revert to */
-/* locked allocation. Must be called */
-/* before any GC_local_gcj_malloc() calls. */
-GC_API void GC_enable_incremental GC_PROTO((void));
-
-/* Does incremental mode write-protect pages? Returns zero or */
-/* more of the following, or'ed together: */
-#define GC_PROTECTS_POINTER_HEAP 1 /* May protect non-atomic objs. */
+/* by GC_malloc, then (char *)p + n will be considered to be a valid */
+/* pointer to p. N must be small and less than the size of p. */
+/* (All pointers to the interior of objects from the stack are */
+/* considered valid in any case. This applies to heap objects and */
+/* static data.) */
+/* Preferably, this should be called before any other GC procedures. */
+/* Calling it later adds to the probability of excess memory */
+/* retention. */
+/* This is a no-op if the collector has recognition of */
+/* arbitrary interior pointers enabled, which is now the default. */
+GC_API void GC_CALL GC_register_displacement(size_t /* n */);
+
+/* The following version should be used if any debugging allocation is */
+/* being done. */
+GC_API void GC_CALL GC_debug_register_displacement(size_t /* n */);
+
+/* Explicitly trigger a full, world-stop collection. */
+GC_API void GC_CALL GC_gcollect(void);
+
+/* Same as above but ignores the default stop_func setting and tries to */
+/* unmap as much memory as possible (regardless of the corresponding */
+/* switch setting). The recommended usage: on receiving a system */
+/* low-memory event; before retrying a system call failed because of */
+/* the system is running out of resources. */
+GC_API void GC_CALL GC_gcollect_and_unmap(void);
+
+/* Trigger a full world-stopped collection. Abort the collection if */
+/* and when stop_func returns a nonzero value. Stop_func will be */
+/* called frequently, and should be reasonably fast. (stop_func is */
+/* called with the allocation lock held and the world might be stopped; */
+/* it's not allowed for stop_func to manipulate pointers to the garbage */
+/* collected heap or call most of GC functions.) This works even */
+/* if virtual dirty bits, and hence incremental collection is not */
+/* available for this architecture. Collections can be aborted faster */
+/* than normal pause times for incremental collection. However, */
+/* aborted collections do no useful work; the next collection needs */
+/* to start from the beginning. stop_func must not be 0. */
+/* GC_try_to_collect() returns 0 if the collection was aborted (or the */
+/* collections are disabled), 1 if it succeeded. */
+typedef int (GC_CALLBACK * GC_stop_func)(void);
+GC_API int GC_CALL GC_try_to_collect(GC_stop_func /* stop_func */)
+ GC_ATTR_NONNULL(1);
+
+/* Set and get the default stop_func. The default stop_func is used by */
+/* GC_gcollect() and by implicitly trigged collections (except for the */
+/* case when handling out of memory). Must not be 0. */
+/* Both the setter and getter acquire the GC lock to avoid data races. */
+GC_API void GC_CALL GC_set_stop_func(GC_stop_func /* stop_func */)
+ GC_ATTR_NONNULL(1);
+GC_API GC_stop_func GC_CALL GC_get_stop_func(void);
+
+/* Return the number of bytes in the heap. Excludes collector private */
+/* data structures. Excludes the unmapped memory (returned to the OS). */
+/* Includes empty blocks and fragmentation loss. Includes some pages */
+/* that were allocated but never written. */
+/* This is an unsynchronized getter, so it should be called typically */
+/* with the GC lock held to avoid data races on multiprocessors (the */
+/* alternative is to use GC_get_heap_usage_safe or GC_get_prof_stats */
+/* API calls instead). */
+/* This getter remains lock-free (unsynchronized) for compatibility */
+/* reason since some existing clients call it from a GC callback */
+/* holding the allocator lock. (This API function and the following */
+/* four ones bellow were made thread-safe in GC v7.2alpha1 and */
+/* reverted back in v7.2alpha7 for the reason described.) */
+GC_API size_t GC_CALL GC_get_heap_size(void);
+
+/* Return a lower bound on the number of free bytes in the heap */
+/* (excluding the unmapped memory space). This is an unsynchronized */
+/* getter (see GC_get_heap_size comment regarding thread-safety). */
+GC_API size_t GC_CALL GC_get_free_bytes(void);
+
+/* Return the size (in bytes) of the unmapped memory (which is returned */
+/* to the OS but could be remapped back by the collector later unless */
+/* the OS runs out of system/virtual memory). This is an unsynchronized */
+/* getter (see GC_get_heap_size comment regarding thread-safety). */
+GC_API size_t GC_CALL GC_get_unmapped_bytes(void);
+
+/* Return the number of bytes allocated since the last collection. */
+/* This is an unsynchronized getter (see GC_get_heap_size comment */
+/* regarding thread-safety). */
+GC_API size_t GC_CALL GC_get_bytes_since_gc(void);
+
+/* Return the total number of bytes allocated in this process. */
+/* Never decreases, except due to wrapping. This is an unsynchronized */
+/* getter (see GC_get_heap_size comment regarding thread-safety). */
+GC_API size_t GC_CALL GC_get_total_bytes(void);
+
+/* Return the heap usage information. This is a thread-safe (atomic) */
+/* alternative for the five above getters. (This function acquires */
+/* the allocator lock thus preventing data racing and returning the */
+/* consistent result.) Passing NULL pointer is allowed for any */
+/* argument. Returned (filled in) values are of word type. */
+/* (This API function was introduced in GC v7.2alpha7 at the same time */
+/* when GC_get_heap_size and the friends were made lock-free again.) */
+GC_API void GC_CALL GC_get_heap_usage_safe(GC_word * /* pheap_size */,
+ GC_word * /* pfree_bytes */,
+ GC_word * /* punmapped_bytes */,
+ GC_word * /* pbytes_since_gc */,
+ GC_word * /* ptotal_bytes */);
+
+/* Structure used to query GC statistics (profiling information). */
+/* More fields could be added in the future. To preserve compatibility */
+/* new fields should be added only to the end, and no deprecated fields */
+/* should be removed from. */
+struct GC_prof_stats_s {
+ GC_word heapsize_full;
+ /* Heap size in bytes (including the area unmapped to OS). */
+ /* Same as GC_get_heap_size() + GC_get_unmapped_bytes(). */
+ GC_word free_bytes_full;
+ /* Total bytes contained in free and unmapped blocks. */
+ /* Same as GC_get_free_bytes() + GC_get_unmapped_bytes(). */
+ GC_word unmapped_bytes;
+ /* Amount of memory unmapped to OS. Same as the value */
+ /* returned by GC_get_unmapped_bytes(). */
+ GC_word bytes_allocd_since_gc;
+ /* Number of bytes allocated since the recent collection. */
+ /* Same as returned by GC_get_bytes_since_gc(). */
+ GC_word allocd_bytes_before_gc;
+ /* Number of bytes allocated before the recent garbage */
+ /* collection. The value may wrap. Same as the result of */
+ /* GC_get_total_bytes() - GC_get_bytes_since_gc(). */
+ GC_word non_gc_bytes;
+ /* Number of bytes not considered candidates for garbage */
+ /* collection. Same as returned by GC_get_non_gc_bytes(). */
+ GC_word gc_no;
+ /* Garbage collection cycle number. The value may wrap */
+ /* (and could be -1). Same as returned by GC_get_gc_no(). */
+ GC_word markers_m1;
+ /* Number of marker threads (excluding the initiating one). */
+ /* Same as returned by GC_get_parallel (or 0 if the */
+ /* collector is single-threaded). */
+ GC_word bytes_reclaimed_since_gc;
+ /* Approximate number of reclaimed bytes after recent GC. */
+ GC_word reclaimed_bytes_before_gc;
+ /* Approximate number of bytes reclaimed before the recent */
+ /* garbage collection. The value may wrap. */
+};
+
+/* Atomically get GC statistics (various global counters). Clients */
+/* should pass the size of the buffer (of GC_prof_stats_s type) to fill */
+/* in the values - this is for interoperability between different GC */
+/* versions, an old client could have fewer fields, and vice versa, */
+/* client could use newer gc.h (with more entires declared in the */
+/* structure) than that of the linked libgc binary; in the latter case, */
+/* unsupported (unknown) fields are filled in with -1. Return the size */
+/* (in bytes) of the filled in part of the structure (excluding all */
+/* unknown fields, if any). */
+GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s *,
+ size_t /* stats_sz */);
+#ifdef GC_THREADS
+ /* Same as above but unsynchronized (i.e., not holding the allocation */
+ /* lock). Clients should call it using GC_call_with_alloc_lock to */
+ /* avoid data races on multiprocessors. */
+ GC_API size_t GC_CALL GC_get_prof_stats_unsafe(struct GC_prof_stats_s *,
+ size_t /* stats_sz */);
+#endif
+
+/* Disable garbage collection. Even GC_gcollect calls will be */
+/* ineffective. */
+GC_API void GC_CALL GC_disable(void);
+
+/* Return non-zero (TRUE) if and only if garbage collection is disabled */
+/* (i.e., GC_dont_gc value is non-zero). Does not acquire the lock. */
+GC_API int GC_CALL GC_is_disabled(void);
+
+/* Re-enable garbage collection. GC_disable() and GC_enable() calls */
+/* nest. Garbage collection is enabled if the number of calls to both */
+/* both functions is equal. */
+GC_API void GC_CALL GC_enable(void);
+
+/* Enable incremental/generational collection. Not advisable unless */
+/* dirty bits are available or most heap objects are pointer-free */
+/* (atomic) or immutable. Don't use in leak finding mode. Ignored if */
+/* GC_dont_gc is non-zero. Only the generational piece of this is */
+/* functional if GC_parallel is non-zero or if GC_time_limit is */
+/* GC_TIME_UNLIMITED. Causes thread-local variant of GC_gcj_malloc() */
+/* to revert to locked allocation. Must be called before any such */
+/* GC_gcj_malloc() calls. For best performance, should be called as */
+/* early as possible. On some platforms, calling it later may have */
+/* adverse effects. */
+/* Safe to call before GC_INIT(). Includes a GC_init() call. */
+GC_API void GC_CALL GC_enable_incremental(void);
+
+/* Does incremental mode write-protect pages? Returns zero or */
+/* more of the following, or'ed together: */
+#define GC_PROTECTS_POINTER_HEAP 1 /* May protect non-atomic objs. */
#define GC_PROTECTS_PTRFREE_HEAP 2
-#define GC_PROTECTS_STATIC_DATA 4 /* Curently never. */
-#define GC_PROTECTS_STACK 8 /* Probably impractical. */
+#define GC_PROTECTS_STATIC_DATA 4 /* Currently never. */
+#define GC_PROTECTS_STACK 8 /* Probably impractical. */
#define GC_PROTECTS_NONE 0
-GC_API int GC_incremental_protection_needs GC_PROTO((void));
-
-/* Perform some garbage collection work, if appropriate. */
-/* Return 0 if there is no more work to be done. */
-/* Typically performs an amount of work corresponding roughly */
-/* to marking from one page. May do more work if further */
-/* progress requires it, e.g. if incremental collection is */
-/* disabled. It is reasonable to call this in a wait loop */
-/* until it returns 0. */
-GC_API int GC_collect_a_little GC_PROTO((void));
-
-/* Allocate an object of size lb bytes. The client guarantees that */
-/* as long as the object is live, it will be referenced by a pointer */
-/* that points to somewhere within the first 256 bytes of the object. */
-/* (This should normally be declared volatile to prevent the compiler */
-/* from invalidating this assertion.) This routine is only useful */
-/* if a large array is being allocated. It reduces the chance of */
-/* accidentally retaining such an array as a result of scanning an */
-/* integer that happens to be an address inside the array. (Actually, */
-/* it reduces the chance of the allocator not finding space for such */
-/* an array, since it will try hard to avoid introducing such a false */
+/* The collector is assumed to be initialized before this call. */
+GC_API int GC_CALL GC_incremental_protection_needs(void);
+
+/* Perform some garbage collection work, if appropriate. */
+/* Return 0 if there is no more work to be done. */
+/* Typically performs an amount of work corresponding roughly */
+/* to marking from one page. May do more work if further */
+/* progress requires it, e.g. if incremental collection is */
+/* disabled. It is reasonable to call this in a wait loop */
+/* until it returns 0. */
+GC_API int GC_CALL GC_collect_a_little(void);
+
+/* Allocate an object of size lb bytes. The client guarantees that */
+/* as long as the object is live, it will be referenced by a pointer */
+/* that points to somewhere within the first 256 bytes of the object. */
+/* (This should normally be declared volatile to prevent the compiler */
+/* from invalidating this assertion.) This routine is only useful */
+/* if a large array is being allocated. It reduces the chance of */
+/* accidentally retaining such an array as a result of scanning an */
+/* integer that happens to be an address inside the array. (Actually, */
+/* it reduces the chance of the allocator not finding space for such */
+/* an array, since it will try hard to avoid introducing such a false */
/* reference.) On a SunOS 4.X or MS Windows system this is recommended */
-/* for arrays likely to be larger than 100K or so. For other systems, */
-/* or if the collector is not configured to recognize all interior */
-/* pointers, the threshold is normally much higher. */
-GC_API GC_PTR GC_malloc_ignore_off_page GC_PROTO((size_t lb));
-GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
-
-#if defined(__sgi) && !defined(__GNUC__) && _COMPILER_VERSION >= 720
-# define GC_ADD_CALLER
-# define GC_RETURN_ADDR (GC_word)__return_address
+/* for arrays likely to be larger than 100K or so. For other systems, */
+/* or if the collector is not configured to recognize all interior */
+/* pointers, the threshold is normally much higher. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_malloc_ignore_off_page(size_t /* lb */);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_malloc_atomic_ignore_off_page(size_t /* lb */);
+
+#ifdef GC_ADD_CALLER
+# define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
+# define GC_EXTRA_PARAMS GC_word ra, const char * s, int i
+#else
+# define GC_EXTRAS __FILE__, __LINE__
+# define GC_EXTRA_PARAMS const char * s, int i
#endif
-#ifdef __linux__
-# include <features.h>
-# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
- && !defined(__ia64__)
-# ifndef GC_HAVE_BUILTIN_BACKTRACE
-# define GC_HAVE_BUILTIN_BACKTRACE
-# endif
-# endif
-# if defined(__i386__) || defined(__x86_64__)
-# define GC_CAN_SAVE_CALL_STACKS
+/* The following is only defined if the library has been suitably */
+/* compiled: */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_malloc_atomic_uncollectable(size_t /* size_in_bytes */);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_malloc_atomic_uncollectable(size_t, GC_EXTRA_PARAMS);
+
+/* Debugging (annotated) allocation. GC_gcollect will check */
+/* objects allocated in this way for overwrites, etc. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_malloc(size_t /* size_in_bytes */, GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_malloc_atomic(size_t /* size_in_bytes */, GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC char * GC_CALL
+ GC_debug_strdup(const char *, GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC char * GC_CALL
+ GC_debug_strndup(const char *, size_t, GC_EXTRA_PARAMS)
+ GC_ATTR_NONNULL(1);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_malloc_uncollectable(size_t /* size_in_bytes */,
+ GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_malloc_stubborn(size_t /* size_in_bytes */, GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_malloc_ignore_off_page(size_t /* size_in_bytes */,
+ GC_EXTRA_PARAMS);
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_malloc_atomic_ignore_off_page(size_t /* size_in_bytes */,
+ GC_EXTRA_PARAMS);
+GC_API void GC_CALL GC_debug_free(void *);
+GC_API void * GC_CALL GC_debug_realloc(void * /* old_object */,
+ size_t /* new_size_in_bytes */, GC_EXTRA_PARAMS)
+ /* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2);
+GC_API void GC_CALL GC_debug_change_stubborn(const void *) GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_debug_end_stubborn_change(const void *)
+ GC_ATTR_NONNULL(1);
+
+/* Routines that allocate objects with debug information (like the */
+/* above), but just fill in dummy file and line number information. */
+/* Thus they can serve as drop-in malloc/realloc replacements. This */
+/* can be useful for two reasons: */
+/* 1) It allows the collector to be built with DBG_HDRS_ALL defined */
+/* even if some allocation calls come from 3rd party libraries */
+/* that can't be recompiled. */
+/* 2) On some platforms, the file and line information is redundant, */
+/* since it can be reconstructed from a stack trace. On such */
+/* platforms it may be more convenient not to recompile, e.g. for */
+/* leak detection. This can be accomplished by instructing the */
+/* linker to replace malloc/realloc with these. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_malloc_replacement(size_t /* size_in_bytes */);
+GC_API /* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2) void * GC_CALL
+ GC_debug_realloc_replacement(void * /* object_addr */,
+ size_t /* size_in_bytes */);
+
+#ifdef GC_DEBUG_REPLACEMENT
+# define GC_MALLOC(sz) GC_debug_malloc_replacement(sz)
+# define GC_REALLOC(old, sz) GC_debug_realloc_replacement(old, sz)
+#elif defined(GC_DEBUG)
+# define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
+# define GC_REALLOC(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
+#else
+# define GC_MALLOC(sz) GC_malloc(sz)
+# define GC_REALLOC(old, sz) GC_realloc(old, sz)
+#endif /* !GC_DEBUG_REPLACEMENT && !GC_DEBUG */
+
+#ifdef GC_DEBUG
+# define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
+# define GC_STRDUP(s) GC_debug_strdup(s, GC_EXTRAS)
+# define GC_STRNDUP(s, sz) GC_debug_strndup(s, sz, GC_EXTRAS)
+# define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz) \
+ GC_debug_malloc_atomic_uncollectable(sz, GC_EXTRAS)
+# define GC_MALLOC_UNCOLLECTABLE(sz) \
+ GC_debug_malloc_uncollectable(sz, GC_EXTRAS)
+# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
+ GC_debug_malloc_ignore_off_page(sz, GC_EXTRAS)
+# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
+ GC_debug_malloc_atomic_ignore_off_page(sz, GC_EXTRAS)
+# define GC_FREE(p) GC_debug_free(p)
+# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+ GC_debug_register_finalizer(p, f, d, of, od)
+# define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+ GC_debug_register_finalizer_ignore_self(p, f, d, of, od)
+# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
+ GC_debug_register_finalizer_no_order(p, f, d, of, od)
+# define GC_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
+ GC_debug_register_finalizer_unreachable(p, f, d, of, od)
+# define GC_MALLOC_STUBBORN(sz) GC_debug_malloc_stubborn(sz, GC_EXTRAS)
+# define GC_CHANGE_STUBBORN(p) GC_debug_change_stubborn(p)
+# define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p)
+# define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+ GC_general_register_disappearing_link(link, \
+ GC_base((/* no const */ void *)(obj)))
+# define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n)
+#else
+# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
+# define GC_STRDUP(s) GC_strdup(s)
+# define GC_STRNDUP(s, sz) GC_strndup(s, sz)
+# define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz) GC_malloc_atomic_uncollectable(sz)
+# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
+# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
+ GC_malloc_ignore_off_page(sz)
+# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
+ GC_malloc_atomic_ignore_off_page(sz)
+# define GC_FREE(p) GC_free(p)
+# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+ GC_register_finalizer(p, f, d, of, od)
+# define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+ GC_register_finalizer_ignore_self(p, f, d, of, od)
+# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
+ GC_register_finalizer_no_order(p, f, d, of, od)
+# define GC_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
+ GC_register_finalizer_unreachable(p, f, d, of, od)
+# define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
+# define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
+# define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
+# define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+ GC_general_register_disappearing_link(link, obj)
+# define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n)
+#endif /* !GC_DEBUG */
+
+/* The following are included because they are often convenient, and */
+/* reduce the chance for a misspecified size argument. But calls may */
+/* expand to something syntactically incorrect if t is a complicated */
+/* type expression. Note that, unlike C++ new operator, these ones */
+/* may return NULL (if out of memory). */
+#define GC_NEW(t) ((t*)GC_MALLOC(sizeof(t)))
+#define GC_NEW_ATOMIC(t) ((t*)GC_MALLOC_ATOMIC(sizeof(t)))
+#define GC_NEW_STUBBORN(t) ((t*)GC_MALLOC_STUBBORN(sizeof(t)))
+#define GC_NEW_UNCOLLECTABLE(t) ((t*)GC_MALLOC_UNCOLLECTABLE(sizeof(t)))
+
+#ifdef GC_REQUIRE_WCSDUP
+ /* This might be unavailable on some targets (or not needed). */
+ /* wchar_t should be defined in stddef.h */
+ GC_API GC_ATTR_MALLOC wchar_t * GC_CALL
+ GC_wcsdup(const wchar_t *) GC_ATTR_NONNULL(1);
+ GC_API GC_ATTR_MALLOC wchar_t * GC_CALL
+ GC_debug_wcsdup(const wchar_t *, GC_EXTRA_PARAMS) GC_ATTR_NONNULL(1);
+# ifdef GC_DEBUG
+# define GC_WCSDUP(s) GC_debug_wcsdup(s, GC_EXTRAS)
+# else
+# define GC_WCSDUP(s) GC_wcsdup(s)
# endif
-#endif
+#endif /* GC_REQUIRE_WCSDUP */
+
+/* Finalization. Some of these primitives are grossly unsafe. */
+/* The idea is to make them both cheap, and sufficient to build */
+/* a safer layer, closer to Modula-3, Java, or PCedar finalization. */
+/* The interface represents my conclusions from a long discussion */
+/* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes, */
+/* Christian Jacobi, and Russ Atkinson. It's not perfect, and */
+/* probably nobody else agrees with it. Hans-J. Boehm 3/13/92 */
+typedef void (GC_CALLBACK * GC_finalization_proc)(void * /* obj */,
+ void * /* client_data */);
+
+GC_API void GC_CALL GC_register_finalizer(void * /* obj */,
+ GC_finalization_proc /* fn */, void * /* cd */,
+ GC_finalization_proc * /* ofn */, void ** /* ocd */)
+ GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_debug_register_finalizer(void * /* obj */,
+ GC_finalization_proc /* fn */, void * /* cd */,
+ GC_finalization_proc * /* ofn */, void ** /* ocd */)
+ GC_ATTR_NONNULL(1);
+ /* When obj is no longer accessible, invoke */
+ /* (*fn)(obj, cd). If a and b are inaccessible, and */
+ /* a points to b (after disappearing links have been */
+ /* made to disappear), then only a will be */
+ /* finalized. (If this does not create any new */
+ /* pointers to b, then b will be finalized after the */
+ /* next collection.) Any finalizable object that */
+ /* is reachable from itself by following one or more */
+ /* pointers will not be finalized (or collected). */
+ /* Thus cycles involving finalizable objects should */
+ /* be avoided, or broken by disappearing links. */
+ /* All but the last finalizer registered for an object */
+ /* is ignored. */
+ /* Finalization may be removed by passing 0 as fn. */
+ /* Finalizers are implicitly unregistered when they are */
+ /* enqueued for finalization (i.e. become ready to be */
+ /* finalized). */
+ /* The old finalizer and client data are stored in */
+ /* *ofn and *ocd. (ofn and/or ocd may be NULL. */
+ /* The allocation lock is held while *ofn and *ocd are */
+ /* updated. In case of error (no memory to register */
+ /* new finalizer), *ofn and *ocd remain unchanged.) */
+ /* Fn is never invoked on an accessible object, */
+ /* provided hidden pointers are converted to real */
+ /* pointers only if the allocation lock is held, and */
+ /* such conversions are not performed by finalization */
+ /* routines. */
+ /* If GC_register_finalizer is aborted as a result of */
+ /* a signal, the object may be left with no */
+ /* finalization, even if neither the old nor new */
+ /* finalizer were NULL. */
+ /* Obj should be the starting address of an object */
+ /* allocated by GC_malloc or friends. Obj may also be */
+ /* NULL or point to something outside GC heap (in this */
+ /* case, fn is ignored, *ofn and *ocd are set to NULL). */
+ /* Note that any garbage collectable object referenced */
+ /* by cd will be considered accessible until the */
+ /* finalizer is invoked. */
+
+/* Another versions of the above follow. It ignores */
+/* self-cycles, i.e. pointers from a finalizable object to */
+/* itself. There is a stylistic argument that this is wrong, */
+/* but it's unavoidable for C++, since the compiler may */
+/* silently introduce these. It's also benign in that specific */
+/* case. And it helps if finalizable objects are split to */
+/* avoid cycles. */
+/* Note that cd will still be viewed as accessible, even if it */
+/* refers to the object itself. */
+GC_API void GC_CALL GC_register_finalizer_ignore_self(void * /* obj */,
+ GC_finalization_proc /* fn */, void * /* cd */,
+ GC_finalization_proc * /* ofn */, void ** /* ocd */)
+ GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_debug_register_finalizer_ignore_self(void * /* obj */,
+ GC_finalization_proc /* fn */, void * /* cd */,
+ GC_finalization_proc * /* ofn */, void ** /* ocd */)
+ GC_ATTR_NONNULL(1);
-#if defined(GC_HAVE_BUILTIN_BACKTRACE) && !defined(GC_CAN_SAVE_CALL_STACKS)
-# define GC_CAN_SAVE_CALL_STACKS
+/* Another version of the above. It ignores all cycles. */
+/* It should probably only be used by Java implementations. */
+/* Note that cd will still be viewed as accessible, even if it */
+/* refers to the object itself. */
+GC_API void GC_CALL GC_register_finalizer_no_order(void * /* obj */,
+ GC_finalization_proc /* fn */, void * /* cd */,
+ GC_finalization_proc * /* ofn */, void ** /* ocd */)
+ GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_debug_register_finalizer_no_order(void * /* obj */,
+ GC_finalization_proc /* fn */, void * /* cd */,
+ GC_finalization_proc * /* ofn */, void ** /* ocd */)
+ GC_ATTR_NONNULL(1);
+
+/* This is a special finalizer that is useful when an object's */
+/* finalizer must be run when the object is known to be no */
+/* longer reachable, not even from other finalizable objects. */
+/* It behaves like "normal" finalization, except that the */
+/* finalizer is not run while the object is reachable from */
+/* other objects specifying unordered finalization. */
+/* Effectively it allows an object referenced, possibly */
+/* indirectly, from an unordered finalizable object to override */
+/* the unordered finalization request. */
+/* This can be used in combination with finalizer_no_order so */
+/* as to release resources that must not be released while an */
+/* object can still be brought back to life by other */
+/* finalizers. */
+/* Only works if GC_java_finalization is set. Probably only */
+/* of interest when implementing a language that requires */
+/* unordered finalization (e.g. Java, C#). */
+GC_API void GC_CALL GC_register_finalizer_unreachable(void * /* obj */,
+ GC_finalization_proc /* fn */, void * /* cd */,
+ GC_finalization_proc * /* ofn */, void ** /* ocd */)
+ GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_debug_register_finalizer_unreachable(void * /* obj */,
+ GC_finalization_proc /* fn */, void * /* cd */,
+ GC_finalization_proc * /* ofn */, void ** /* ocd */)
+ GC_ATTR_NONNULL(1);
+
+#define GC_NO_MEMORY 2 /* Failure due to lack of memory. */
+
+/* The following routine may be used to break cycles between */
+/* finalizable objects, thus causing cyclic finalizable */
+/* objects to be finalized in the correct order. Standard */
+/* use involves calling GC_register_disappearing_link(&p), */
+/* where p is a pointer that is not followed by finalization */
+/* code, and should not be considered in determining */
+/* finalization order. */
+GC_API int GC_CALL GC_register_disappearing_link(void ** /* link */)
+ GC_ATTR_NONNULL(1);
+ /* Link should point to a field of a heap allocated */
+ /* object obj. *link will be cleared when obj is */
+ /* found to be inaccessible. This happens BEFORE any */
+ /* finalization code is invoked, and BEFORE any */
+ /* decisions about finalization order are made. */
+ /* This is useful in telling the finalizer that */
+ /* some pointers are not essential for proper */
+ /* finalization. This may avoid finalization cycles. */
+ /* Note that obj may be resurrected by another */
+ /* finalizer, and thus the clearing of *link may */
+ /* be visible to non-finalization code. */
+ /* There's an argument that an arbitrary action should */
+ /* be allowed here, instead of just clearing a pointer. */
+ /* But this causes problems if that action alters, or */
+ /* examines connectivity. Returns GC_DUPLICATE if link */
+ /* was already registered, GC_SUCCESS if registration */
+ /* succeeded, GC_NO_MEMORY 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_CALL GC_general_register_disappearing_link(void ** /* link */,
+ const void * /* obj */)
+ GC_ATTR_NONNULL(1) GC_ATTR_NONNULL(2);
+ /* A slight generalization of the above. *link is */
+ /* cleared when obj first becomes inaccessible. This */
+ /* can be used to implement weak pointers easily and */
+ /* safely. Typically link will point to a location */
+ /* holding a disguised pointer to obj. (A pointer */
+ /* inside an "atomic" object is effectively disguised.) */
+ /* In this way, weak pointers are broken before any */
+ /* object reachable from them gets finalized. */
+ /* Each link may be registered only with one obj value, */
+ /* i.e. all objects but the last one (link registered */
+ /* with) are ignored. This was added after a long */
+ /* email discussion with John Ellis. */
+ /* link must be non-NULL (and be properly aligned). */
+ /* obj must be a pointer to the first word of an object */
+ /* allocated by GC_malloc or friends. It is unsafe to */
+ /* explicitly deallocate the object containing link. */
+ /* Explicit deallocation of obj may or may not cause */
+ /* link to eventually be cleared. */
+ /* This function can be used to implement certain types */
+ /* of weak pointers. Note, however, this generally */
+ /* requires that the allocation lock is held (see */
+ /* GC_call_with_alloc_lock() below) when the disguised */
+ /* pointer is accessed. Otherwise a strong pointer */
+ /* could be recreated between the time the collector */
+ /* decides to reclaim the object and the link is */
+ /* cleared. Returns GC_SUCCESS if registration */
+ /* succeeded (a new link is registered), GC_DUPLICATE */
+ /* if link was already registered (with some object), */
+ /* GC_NO_MEMORY if registration failed for lack of */
+ /* memory (and GC_oom_fn did not handle the problem). */
+
+GC_API int GC_CALL GC_move_disappearing_link(void ** /* link */,
+ void ** /* new_link */)
+ GC_ATTR_NONNULL(2);
+ /* Moves a link previously registered via */
+ /* GC_general_register_disappearing_link (or */
+ /* GC_register_disappearing_link). Does not change the */
+ /* target object of the weak reference. Does not */
+ /* change (*new_link) content. May be called with */
+ /* new_link equal to link (to check whether link has */
+ /* been registered). Returns GC_SUCCESS on success, */
+ /* GC_DUPLICATE if there is already another */
+ /* disappearing link at the new location (never */
+ /* returned if new_link is equal to link), GC_NOT_FOUND */
+ /* if no link is registered at the original location. */
+
+GC_API int GC_CALL GC_unregister_disappearing_link(void ** /* link */);
+ /* Undoes a registration by either of the above two */
+ /* routines. Returns 0 if link was not actually */
+ /* registered (otherwise returns 1). */
+
+/* Returns !=0 if GC_invoke_finalizers has something to do. */
+GC_API int GC_CALL GC_should_invoke_finalizers(void);
+
+GC_API int GC_CALL GC_invoke_finalizers(void);
+ /* Run finalizers for all objects that are ready to */
+ /* be finalized. Return the number of finalizers */
+ /* that were run. Normally this is also called */
+ /* implicitly during some allocations. If */
+ /* GC_finalize_on_demand is nonzero, it must be called */
+ /* explicitly. */
+
+/* Explicitly tell the collector that an object is reachable */
+/* at a particular program point. This prevents the argument */
+/* pointer from being optimized away, even it is otherwise no */
+/* longer needed. It should have no visible effect in the */
+/* absence of finalizers or disappearing links. But it may be */
+/* needed to prevent finalizers from running while the */
+/* associated external resource is still in use. */
+/* The function is sometimes called keep_alive in other */
+/* settings. */
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+# define GC_reachable_here(ptr) \
+ __asm__ __volatile__(" " : : "X"(ptr) : "memory")
+#else
+ GC_API void GC_CALL GC_noop1(GC_word);
+# define GC_reachable_here(ptr) GC_noop1((GC_word)(ptr))
#endif
-#if defined(__sparc__)
-# define GC_CAN_SAVE_CALL_STACKS
+/* GC_set_warn_proc can be used to redirect or filter warning messages. */
+/* p may not be a NULL pointer. msg is printf format string (arg must */
+/* match the format). Both the setter and the getter acquire the GC */
+/* lock (to avoid data races). */
+typedef void (GC_CALLBACK * GC_warn_proc)(char * /* msg */,
+ GC_word /* arg */);
+GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc /* p */) GC_ATTR_NONNULL(1);
+/* GC_get_warn_proc returns the current warn_proc. */
+GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void);
+
+/* GC_ignore_warn_proc may be used as an argument for GC_set_warn_proc */
+/* to suppress all warnings (unless statistics printing is turned on). */
+GC_API void GC_CALLBACK GC_ignore_warn_proc(char *, GC_word);
+
+/* abort_func is invoked on GC fatal aborts (just before OS-dependent */
+/* abort or exit(1) is called). Must be non-NULL. The default one */
+/* outputs msg to stderr provided msg is non-NULL. msg is NULL if */
+/* invoked before exit(1) otherwise msg is non-NULL (i.e., if invoked */
+/* before abort). Both the setter and getter acquire the GC lock. */
+/* Both the setter and getter are defined only if the library has been */
+/* compiled without SMALL_CONFIG. */
+typedef void (GC_CALLBACK * GC_abort_func)(const char * /* msg */);
+GC_API void GC_CALL GC_set_abort_func(GC_abort_func) GC_ATTR_NONNULL(1);
+GC_API GC_abort_func GC_CALL GC_get_abort_func(void);
+
+/* The following is intended to be used by a higher level */
+/* (e.g. Java-like) finalization facility. It is expected */
+/* that finalization code will arrange for hidden pointers to */
+/* disappear. Otherwise objects can be accessed after they */
+/* have been collected. */
+/* Note that putting pointers in atomic objects or in */
+/* non-pointer slots of "typed" objects is equivalent to */
+/* disguising them in this way, and may have other advantages. */
+typedef GC_word GC_hidden_pointer;
+#define GC_HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
+/* Converting a hidden pointer to a real pointer requires verifying */
+/* that the object still exists. This involves acquiring the */
+/* allocator lock to avoid a race with the collector. */
+#define GC_REVEAL_POINTER(p) ((void *)GC_HIDE_POINTER(p))
+
+#if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
+ /* This exists only for compatibility (the GC-prefixed symbols are */
+ /* preferred for new code). */
+# define HIDE_POINTER(p) GC_HIDE_POINTER(p)
+# define REVEAL_POINTER(p) GC_REVEAL_POINTER(p)
#endif
-/* If we're on an a platform on which we can't save call stacks, but */
-/* gcc is normally used, we go ahead and define GC_ADD_CALLER. */
-/* We make this decision independent of whether gcc is actually being */
-/* used, in order to keep the interface consistent, and allow mixing */
-/* of compilers. */
-/* This may also be desirable if it is possible but expensive to */
-/* retrieve the call chain. */
-#if (defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) \
- || defined(__FreeBSD__)) & !defined(GC_CAN_SAVE_CALL_STACKS)
-# define GC_ADD_CALLER
-# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
- /* gcc knows how to retrieve return address, but we don't know */
- /* how to generate call stacks. */
-# define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
-# else
- /* Just pass 0 for gcc compatibility. */
-# define GC_RETURN_ADDR 0
+typedef void * (GC_CALLBACK * GC_fn_type)(void * /* client_data */);
+GC_API void * GC_CALL GC_call_with_alloc_lock(GC_fn_type /* fn */,
+ void * /* client_data */) GC_ATTR_NONNULL(1);
+
+/* These routines are intended to explicitly notify the collector */
+/* of new threads. Often this is unnecessary because thread creation */
+/* is implicitly intercepted by the collector, using header-file */
+/* defines, or linker-based interception. In the long run the intent */
+/* is to always make redundant registration safe. In the short run, */
+/* this is being implemented a platform at a time. */
+/* The interface is complicated by the fact that we probably will not */
+/* ever be able to automatically determine the stack base for thread */
+/* stacks on all platforms. */
+
+/* Structure representing the base of a thread stack. On most */
+/* platforms this contains just a single address. */
+struct GC_stack_base {
+ void * mem_base; /* Base of memory stack. */
+# if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+ void * reg_base; /* Base of separate register stack. */
# endif
+};
+
+typedef void * (GC_CALLBACK * GC_stack_base_func)(
+ struct GC_stack_base * /* sb */, void * /* arg */);
+
+/* Call a function with a stack base structure corresponding to */
+/* somewhere in the GC_call_with_stack_base frame. This often can */
+/* be used to provide a sufficiently accurate stack base. And we */
+/* implement it everywhere. */
+GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
+ void * /* arg */) GC_ATTR_NONNULL(1);
+
+#define GC_SUCCESS 0
+#define GC_DUPLICATE 1 /* Was already registered. */
+#define GC_NO_THREADS 2 /* No thread support in GC. */
+ /* GC_NO_THREADS is not returned by any GC function anymore. */
+#define GC_UNIMPLEMENTED 3 /* Not yet implemented on this platform. */
+#define GC_NOT_FOUND 4 /* Requested link not found (returned */
+ /* by GC_move_disappearing_link). */
+
+#if defined(GC_DARWIN_THREADS) || defined(GC_WIN32_THREADS)
+ /* Use implicit thread registration and processing (via Win32 DllMain */
+ /* or Darwin task_threads). Deprecated. Must be called before */
+ /* GC_INIT() and other GC routines. Should be avoided if */
+ /* GC_pthread_create, GC_beginthreadex (or GC_CreateThread) could be */
+ /* called instead. Disables parallelized GC on Win32. */
+ GC_API void GC_CALL GC_use_threads_discovery(void);
#endif
-#ifdef GC_ADD_CALLER
-# define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
-# define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * s, int i
+#ifdef GC_THREADS
+ /* Suggest the GC to use the specific signal to suspend threads. */
+ /* Has no effect after GC_init and on non-POSIX systems. */
+ GC_API void GC_CALL GC_set_suspend_signal(int);
+
+ /* Suggest the GC to use the specific signal to resume threads. */
+ /* Has no effect after GC_init and on non-POSIX systems. */
+ GC_API void GC_CALL GC_set_thr_restart_signal(int);
+
+ /* Return the signal number (constant after initialization) used by */
+ /* the GC to suspend threads on POSIX systems. Return -1 otherwise. */
+ GC_API int GC_CALL GC_get_suspend_signal(void);
+
+ /* Return the signal number (constant after initialization) used by */
+ /* the garbage collector to restart (resume) threads on POSIX */
+ /* systems. Return -1 otherwise. */
+ GC_API int GC_CALL GC_get_thr_restart_signal(void);
+
+ /* Restart marker threads after POSIX fork in child. Meaningless in */
+ /* other situations. Should not be called if fork followed by exec. */
+ GC_API void GC_CALL GC_start_mark_threads(void);
+
+ /* Explicitly enable GC_register_my_thread() invocation. */
+ /* Done implicitly if a GC thread-creation function is called (or */
+ /* implicit thread registration is activated). Otherwise, it must */
+ /* be called from the main (or any previously registered) thread */
+ /* between the collector initialization and the first explicit */
+ /* registering of a thread (it should be called as late as possible). */
+ GC_API void GC_CALL GC_allow_register_threads(void);
+
+ /* Register the current thread, with the indicated stack base, as */
+ /* a new thread whose stack(s) should be traced by the GC. If it */
+ /* is not implicitly called by the GC, this must be called before a */
+ /* thread can allocate garbage collected memory, or assign pointers */
+ /* to the garbage collected heap. Once registered, a thread will be */
+ /* stopped during garbage collections. */
+ /* This call must be previously enabled (see above). */
+ /* This should never be called from the main thread, where it is */
+ /* always done implicitly. This is normally done implicitly if GC_ */
+ /* functions are called to create the thread, e.g. by including gc.h */
+ /* (which redefines some system functions) before calling the system */
+ /* thread creation function. Nonetheless, thread cleanup routines */
+ /* (eg., pthread key destructor) typically require manual thread */
+ /* registering (and unregistering) if pointers to GC-allocated */
+ /* objects are manipulated inside. */
+ /* It is also always done implicitly on some platforms if */
+ /* GC_use_threads_discovery() is called at start-up. Except for the */
+ /* latter case, the explicit call is normally required for threads */
+ /* created by third-party libraries. */
+ /* A manually registered thread requires manual unregistering. */
+ GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *)
+ GC_ATTR_NONNULL(1);
+
+ /* Return TRUE if and only if the calling thread is registered with */
+ /* the garbage collector. */
+ GC_API int GC_CALL GC_thread_is_registered(void);
+
+ /* Unregister the current thread. Only an explicitly registered */
+ /* thread (i.e. for which GC_register_my_thread() returns GC_SUCCESS) */
+ /* is allowed (and required) to call this function. (As a special */
+ /* exception, it is also allowed to once unregister the main thread.) */
+ /* The thread may no longer allocate garbage collected memory or */
+ /* manipulate pointers to the garbage collected heap after making */
+ /* this call. Specifically, if it wants to return or otherwise */
+ /* communicate a pointer to the garbage-collected heap to another */
+ /* thread, it must do this before calling GC_unregister_my_thread, */
+ /* most probably by saving it in a global data structure. Must not */
+ /* be called inside a GC callback function (except for */
+ /* GC_call_with_stack_base() one). */
+ GC_API int GC_CALL GC_unregister_my_thread(void);
+#endif /* GC_THREADS */
+
+/* Wrapper for functions that are likely to block (or, at least, do not */
+/* allocate garbage collected memory and/or manipulate pointers to the */
+/* garbage collected heap) for an appreciable length of time. While fn */
+/* is running, the collector is said to be in the "inactive" state for */
+/* the current thread (this means that the thread is not suspended and */
+/* the thread's stack frames "belonging" to the functions in the */
+/* "inactive" state are not scanned during garbage collections). It is */
+/* allowed for fn to call GC_call_with_gc_active() (even recursively), */
+/* thus temporarily toggling the collector's state back to "active". */
+GC_API void * GC_CALL GC_do_blocking(GC_fn_type /* fn */,
+ void * /* client_data */) GC_ATTR_NONNULL(1);
+
+/* Call a function switching to the "active" state of the collector for */
+/* the current thread (i.e. the user function is allowed to call any */
+/* GC function and/or manipulate pointers to the garbage collected */
+/* heap). GC_call_with_gc_active() has the functionality opposite to */
+/* GC_do_blocking() one. It is assumed that the collector is already */
+/* initialized and the current thread is registered. fn may toggle */
+/* the collector thread's state temporarily to "inactive" one by using */
+/* GC_do_blocking. GC_call_with_gc_active() often can be used to */
+/* provide a sufficiently accurate stack base. */
+GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type /* fn */,
+ void * /* client_data */) GC_ATTR_NONNULL(1);
+
+/* Attempt to fill in the GC_stack_base structure with the stack base */
+/* for this thread. This appears to be required to implement anything */
+/* like the JNI AttachCurrentThread in an environment in which new */
+/* threads are not automatically registered with the collector. */
+/* It is also unfortunately hard to implement well on many platforms. */
+/* Returns GC_SUCCESS or GC_UNIMPLEMENTED. This function acquires the */
+/* GC lock on some platforms. */
+GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *)
+ GC_ATTR_NONNULL(1);
+
+/* The following routines are primarily intended for use with a */
+/* preprocessor which inserts calls to check C pointer arithmetic. */
+/* They indicate failure by invoking the corresponding _print_proc. */
+
+/* Check that p and q point to the same object. */
+/* Fail conspicuously if they don't. */
+/* Returns the first argument. */
+/* Succeeds if neither p nor q points to the heap. */
+/* May succeed if both p and q point to between heap objects. */
+GC_API void * GC_CALL GC_same_obj(void * /* p */, void * /* q */);
+
+/* Checked pointer pre- and post- increment operations. Note that */
+/* the second argument is in units of bytes, not multiples of the */
+/* object size. This should either be invoked from a macro, or the */
+/* call should be automatically generated. */
+GC_API void * GC_CALL GC_pre_incr(void **, ptrdiff_t /* how_much */)
+ GC_ATTR_NONNULL(1);
+GC_API void * GC_CALL GC_post_incr(void **, ptrdiff_t /* how_much */)
+ GC_ATTR_NONNULL(1);
+
+/* Check that p is visible */
+/* to the collector as a possibly pointer containing location. */
+/* If it isn't fail conspicuously. */
+/* Returns the argument in all cases. May erroneously succeed */
+/* in hard cases. (This is intended for debugging use with */
+/* untyped allocations. The idea is that it should be possible, though */
+/* slow, to add such a call to all indirect pointer stores.) */
+/* Currently useless for multi-threaded worlds. */
+GC_API void * GC_CALL GC_is_visible(void * /* p */);
+
+/* Check that if p is a pointer to a heap page, then it points to */
+/* a valid displacement within a heap object. */
+/* Fail conspicuously if this property does not hold. */
+/* Uninteresting with GC_all_interior_pointers. */
+/* Always returns its argument. */
+GC_API void * GC_CALL GC_is_valid_displacement(void * /* p */);
+
+/* Explicitly dump the GC state. This is most often called from the */
+/* debugger, or by setting the GC_DUMP_REGULARLY environment variable, */
+/* but it may be useful to call it from client code during debugging. */
+/* Defined only if the library has been compiled without NO_DEBUGGING. */
+GC_API void GC_CALL GC_dump(void);
+
+/* Safer, but slow, pointer addition. Probably useful mainly with */
+/* a preprocessor. Useful only for heap pointers. */
+/* Only the macros without trailing digits are meant to be used */
+/* by clients. These are designed to model the available C pointer */
+/* arithmetic expressions. */
+/* Even then, these are probably more useful as */
+/* documentation than as part of the API. */
+/* Note that GC_PTR_ADD evaluates the first argument more than once. */
+#if defined(GC_DEBUG) && defined(__GNUC__)
+# define GC_PTR_ADD3(x, n, type_of_result) \
+ ((type_of_result)GC_same_obj((x)+(n), (x)))
+# define GC_PRE_INCR3(x, n, type_of_result) \
+ ((type_of_result)GC_pre_incr((void **)(&(x)), (n)*sizeof(*x)))
+# define GC_POST_INCR3(x, n, type_of_result) \
+ ((type_of_result)GC_post_incr((void **)(&(x)), (n)*sizeof(*x)))
+# define GC_PTR_ADD(x, n) GC_PTR_ADD3(x, n, typeof(x))
+# define GC_PRE_INCR(x, n) GC_PRE_INCR3(x, n, typeof(x))
+# define GC_POST_INCR(x) GC_POST_INCR3(x, 1, typeof(x))
+# define GC_POST_DECR(x) GC_POST_INCR3(x, -1, typeof(x))
+#else /* !GC_DEBUG || !__GNUC__ */
+ /* We can't do this right without typeof, which ANSI decided was not */
+ /* sufficiently useful. Without it we resort to the non-debug version. */
+ /* FIXME: This should eventually support C++0x decltype. */
+# define GC_PTR_ADD(x, n) ((x)+(n))
+# define GC_PRE_INCR(x, n) ((x) += (n))
+# define GC_POST_INCR(x) ((x)++)
+# define GC_POST_DECR(x) ((x)--)
+#endif /* !GC_DEBUG || !__GNUC__ */
+
+/* Safer assignment of a pointer to a non-stack location. */
+#ifdef GC_DEBUG
+# define GC_PTR_STORE(p, q) \
+ (*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
#else
-# define GC_EXTRAS __FILE__, __LINE__
-# define GC_EXTRA_PARAMS GC_CONST char * s, int i
+# define GC_PTR_STORE(p, q) (*(p) = (q))
#endif
-/* Debugging (annotated) allocation. GC_gcollect will check */
-/* objects allocated in this way for overwrites, etc. */
-GC_API GC_PTR GC_debug_malloc
- GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_atomic
- GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_uncollectable
- GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_stubborn
- GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_ignore_off_page
- GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API GC_PTR GC_debug_malloc_atomic_ignore_off_page
- GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
-GC_API void GC_debug_free GC_PROTO((GC_PTR object_addr));
-GC_API GC_PTR GC_debug_realloc
- GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
- GC_EXTRA_PARAMS));
-GC_API void GC_debug_change_stubborn GC_PROTO((GC_PTR));
-GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
-
-/* Routines that allocate objects with debug information (like the */
-/* above), but just fill in dummy file and line number information. */
-/* Thus they can serve as drop-in malloc/realloc replacements. This */
-/* can be useful for two reasons: */
-/* 1) It allows the collector to be built with DBG_HDRS_ALL defined */
-/* even if some allocation calls come from 3rd party libraries */
-/* that can't be recompiled. */
-/* 2) On some platforms, the file and line information is redundant, */
-/* since it can be reconstructed from a stack trace. On such */
-/* platforms it may be more convenient not to recompile, e.g. for */
-/* leak detection. This can be accomplished by instructing the */
-/* linker to replace malloc/realloc with these. */
-GC_API GC_PTR GC_debug_malloc_replacement GC_PROTO((size_t size_in_bytes));
-GC_API GC_PTR GC_debug_realloc_replacement
- GC_PROTO((GC_PTR object_addr, size_t size_in_bytes));
-
-# ifdef GC_DEBUG
-# define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
-# define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
-# define GC_MALLOC_UNCOLLECTABLE(sz) \
- GC_debug_malloc_uncollectable(sz, GC_EXTRAS)
-# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
- GC_debug_malloc_ignore_off_page(sz, GC_EXTRAS)
-# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
- GC_debug_malloc_atomic_ignore_off_page(sz, GC_EXTRAS)
-# define GC_REALLOC(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
-# define GC_FREE(p) GC_debug_free(p)
-# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
- GC_debug_register_finalizer(p, f, d, of, od)
-# define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
- GC_debug_register_finalizer_ignore_self(p, f, d, of, od)
-# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
- GC_debug_register_finalizer_no_order(p, f, d, of, od)
-# define GC_MALLOC_STUBBORN(sz) GC_debug_malloc_stubborn(sz, GC_EXTRAS);
-# define GC_CHANGE_STUBBORN(p) GC_debug_change_stubborn(p)
-# define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p)
-# define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
- GC_general_register_disappearing_link(link, GC_base(obj))
-# define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n)
-# else
-# define GC_MALLOC(sz) GC_malloc(sz)
-# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
-# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
-# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
- GC_malloc_ignore_off_page(sz)
-# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
- GC_malloc_atomic_ignore_off_page(sz)
-# define GC_REALLOC(old, sz) GC_realloc(old, sz)
-# define GC_FREE(p) GC_free(p)
-# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
- GC_register_finalizer(p, f, d, of, od)
-# define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
- GC_register_finalizer_ignore_self(p, f, d, of, od)
-# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
- GC_register_finalizer_no_order(p, f, d, of, od)
-# define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
-# define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
-# define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
-# define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
- GC_general_register_disappearing_link(link, obj)
-# define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n)
-# endif
-/* The following are included because they are often convenient, and */
-/* reduce the chance for a misspecifed size argument. But calls may */
-/* expand to something syntactically incorrect if t is a complicated */
-/* type expression. */
-# define GC_NEW(t) (t *)GC_MALLOC(sizeof (t))
-# define GC_NEW_ATOMIC(t) (t *)GC_MALLOC_ATOMIC(sizeof (t))
-# define GC_NEW_STUBBORN(t) (t *)GC_MALLOC_STUBBORN(sizeof (t))
-# define GC_NEW_UNCOLLECTABLE(t) (t *)GC_MALLOC_UNCOLLECTABLE(sizeof (t))
-
-/* Finalization. Some of these primitives are grossly unsafe. */
-/* The idea is to make them both cheap, and sufficient to build */
-/* a safer layer, closer to Modula-3, Java, or PCedar finalization. */
-/* The interface represents my conclusions from a long discussion */
-/* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes, */
-/* Christian Jacobi, and Russ Atkinson. It's not perfect, and */
-/* probably nobody else agrees with it. Hans-J. Boehm 3/13/92 */
-typedef void (*GC_finalization_proc)
- GC_PROTO((GC_PTR obj, GC_PTR client_data));
-
-GC_API void GC_register_finalizer
- GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
- GC_finalization_proc *ofn, GC_PTR *ocd));
-GC_API void GC_debug_register_finalizer
- GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
- GC_finalization_proc *ofn, GC_PTR *ocd));
- /* When obj is no longer accessible, invoke */
- /* (*fn)(obj, cd). If a and b are inaccessible, and */
- /* a points to b (after disappearing links have been */
- /* made to disappear), then only a will be */
- /* finalized. (If this does not create any new */
- /* pointers to b, then b will be finalized after the */
- /* next collection.) Any finalizable object that */
- /* is reachable from itself by following one or more */
- /* pointers will not be finalized (or collected). */
- /* Thus cycles involving finalizable objects should */
- /* be avoided, or broken by disappearing links. */
- /* All but the last finalizer registered for an object */
- /* is ignored. */
- /* Finalization may be removed by passing 0 as fn. */
- /* Finalizers are implicitly unregistered just before */
- /* they are invoked. */
- /* The old finalizer and client data are stored in */
- /* *ofn and *ocd. */
- /* Fn is never invoked on an accessible object, */
- /* provided hidden pointers are converted to real */
- /* pointers only if the allocation lock is held, and */
- /* such conversions are not performed by finalization */
- /* routines. */
- /* If GC_register_finalizer is aborted as a result of */
- /* a signal, the object may be left with no */
- /* finalization, even if neither the old nor new */
- /* finalizer were NULL. */
- /* Obj should be the nonNULL starting address of an */
- /* object allocated by GC_malloc or friends. */
- /* Note that any garbage collectable object referenced */
- /* by cd will be considered accessible until the */
- /* finalizer is invoked. */
-
-/* Another versions of the above follow. It ignores */
-/* self-cycles, i.e. pointers from a finalizable object to */
-/* itself. There is a stylistic argument that this is wrong, */
-/* but it's unavoidable for C++, since the compiler may */
-/* silently introduce these. It's also benign in that specific */
-/* case. And it helps if finalizable objects are split to */
-/* avoid cycles. */
-/* Note that cd will still be viewed as accessible, even if it */
-/* refers to the object itself. */
-GC_API void GC_register_finalizer_ignore_self
- GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
- GC_finalization_proc *ofn, GC_PTR *ocd));
-GC_API void GC_debug_register_finalizer_ignore_self
- GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
- GC_finalization_proc *ofn, GC_PTR *ocd));
+/* Functions called to report pointer checking errors */
+GC_API void (GC_CALLBACK * GC_same_obj_print_proc)(void * /* p */,
+ void * /* q */);
+GC_API void (GC_CALLBACK * GC_is_valid_displacement_print_proc)(void *);
+GC_API void (GC_CALLBACK * GC_is_visible_print_proc)(void *);
+
+#ifdef GC_PTHREADS
+ /* For pthread support, we generally need to intercept a number of */
+ /* thread library calls. We do that here by macro defining them. */
+# include "gc_pthread_redirects.h"
+#endif
-/* Another version of the above. It ignores all cycles. */
-/* It should probably only be used by Java implementations. */
-/* Note that cd will still be viewed as accessible, even if it */
-/* refers to the object itself. */
-GC_API void GC_register_finalizer_no_order
- GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
- GC_finalization_proc *ofn, GC_PTR *ocd));
-GC_API void GC_debug_register_finalizer_no_order
- GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
- GC_finalization_proc *ofn, GC_PTR *ocd));
-
-
-/* The following routine may be used to break cycles between */
-/* finalizable objects, thus causing cyclic finalizable */
-/* objects to be finalized in the correct order. Standard */
-/* use involves calling GC_register_disappearing_link(&p), */
-/* where p is a pointer that is not followed by finalization */
-/* code, and should not be considered in determining */
-/* finalization order. */
-GC_API int GC_register_disappearing_link GC_PROTO((GC_PTR * /* link */));
- /* Link should point to a field of a heap allocated */
- /* object obj. *link will be cleared when obj is */
- /* found to be inaccessible. This happens BEFORE any */
- /* finalization code is invoked, and BEFORE any */
- /* decisions about finalization order are made. */
- /* This is useful in telling the finalizer that */
- /* some pointers are not essential for proper */
- /* finalization. This may avoid finalization cycles. */
- /* Note that obj may be resurrected by another */
- /* finalizer, and thus the clearing of *link may */
- /* be visible to non-finalization code. */
- /* There's an argument that an arbitrary action should */
- /* 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. */
- /* Only exists for backward compatibility. See below: */
-
-GC_API int GC_general_register_disappearing_link
- GC_PROTO((GC_PTR * /* link */, GC_PTR obj));
- /* A slight generalization of the above. *link is */
- /* cleared when obj first becomes inaccessible. This */
- /* can be used to implement weak pointers easily and */
- /* safely. Typically link will point to a location */
- /* holding a disguised pointer to obj. (A pointer */
- /* inside an "atomic" object is effectively */
- /* disguised.) In this way soft */
- /* pointers are broken before any object */
- /* reachable from them are finalized. Each link */
- /* May be registered only once, i.e. with one obj */
- /* value. This was added after a long email discussion */
- /* with John Ellis. */
- /* Obj must be a pointer to the first word of an object */
- /* we allocated. It is unsafe to explicitly deallocate */
- /* the object containing link. Explicitly deallocating */
- /* obj may or may not cause link to eventually be */
- /* cleared. */
-GC_API int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
- /* Returns 0 if link was not actually registered. */
- /* Undoes a registration by either of the above two */
- /* routines. */
-
-/* Returns !=0 if GC_invoke_finalizers has something to do. */
-GC_API int GC_should_invoke_finalizers GC_PROTO((void));
-
-GC_API int GC_invoke_finalizers GC_PROTO((void));
- /* Run finalizers for all objects that are ready to */
- /* be finalized. Return the number of finalizers */
- /* that were run. Normally this is also called */
- /* implicitly during some allocations. If */
- /* GC-finalize_on_demand is nonzero, it must be called */
- /* explicitly. */
-
-/* GC_set_warn_proc can be used to redirect or filter warning messages. */
-/* p may not be a NULL pointer. */
-typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
-GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
- /* Returns old warning procedure. */
-
-GC_API GC_word GC_set_free_space_divisor GC_PROTO((GC_word value));
- /* Set free_space_divisor. See above for definition. */
- /* Returns old value. */
-
-/* The following is intended to be used by a higher level */
-/* (e.g. Java-like) finalization facility. It is expected */
-/* that finalization code will arrange for hidden pointers to */
-/* disappear. Otherwise objects can be accessed after they */
-/* have been collected. */
-/* Note that putting pointers in atomic objects or in */
-/* nonpointer slots of "typed" objects is equivalent to */
-/* disguising them in this way, and may have other advantages. */
-# if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
- typedef GC_word GC_hidden_pointer;
-# define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
-# define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p)))
- /* Converting a hidden pointer to a real pointer requires verifying */
- /* that the object still exists. This involves acquiring the */
- /* allocator lock to avoid a race with the collector. */
-# endif /* I_HIDE_POINTERS */
-
-typedef GC_PTR (*GC_fn_type) GC_PROTO((GC_PTR client_data));
-GC_API GC_PTR GC_call_with_alloc_lock
- GC_PROTO((GC_fn_type fn, GC_PTR client_data));
-
-/* The following routines are primarily intended for use with a */
-/* preprocessor which inserts calls to check C pointer arithmetic. */
-/* They indicate failure by invoking the corresponding _print_proc. */
-
-/* Check that p and q point to the same object. */
-/* Fail conspicuously if they don't. */
-/* Returns the first argument. */
-/* Succeeds if neither p nor q points to the heap. */
-/* May succeed if both p and q point to between heap objects. */
-GC_API GC_PTR GC_same_obj GC_PROTO((GC_PTR p, GC_PTR q));
-
-/* Checked pointer pre- and post- increment operations. Note that */
-/* the second argument is in units of bytes, not multiples of the */
-/* object size. This should either be invoked from a macro, or the */
-/* call should be automatically generated. */
-GC_API GC_PTR GC_pre_incr GC_PROTO((GC_PTR *p, size_t how_much));
-GC_API GC_PTR GC_post_incr GC_PROTO((GC_PTR *p, size_t how_much));
-
-/* Check that p is visible */
-/* to the collector as a possibly pointer containing location. */
-/* If it isn't fail conspicuously. */
-/* Returns the argument in all cases. May erroneously succeed */
-/* in hard cases. (This is intended for debugging use with */
-/* untyped allocations. The idea is that it should be possible, though */
-/* slow, to add such a call to all indirect pointer stores.) */
-/* Currently useless for multithreaded worlds. */
-GC_API GC_PTR GC_is_visible GC_PROTO((GC_PTR p));
-
-/* Check that if p is a pointer to a heap page, then it points to */
-/* a valid displacement within a heap object. */
-/* Fail conspicuously if this property does not hold. */
-/* Uninteresting with GC_all_interior_pointers. */
-/* Always returns its argument. */
-GC_API GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR p));
-
-/* Safer, but slow, pointer addition. Probably useful mainly with */
-/* a preprocessor. Useful only for heap pointers. */
-#ifdef GC_DEBUG
-# define GC_PTR_ADD3(x, n, type_of_result) \
- ((type_of_result)GC_same_obj((x)+(n), (x)))
-# define GC_PRE_INCR3(x, n, type_of_result) \
- ((type_of_result)GC_pre_incr(&(x), (n)*sizeof(*x))
-# define GC_POST_INCR2(x, type_of_result) \
- ((type_of_result)GC_post_incr(&(x), sizeof(*x))
-# ifdef __GNUC__
-# define GC_PTR_ADD(x, n) \
- GC_PTR_ADD3(x, n, typeof(x))
-# define GC_PRE_INCR(x, n) \
- GC_PRE_INCR3(x, n, typeof(x))
-# define GC_POST_INCR(x, n) \
- GC_POST_INCR3(x, typeof(x))
+/* This returns a list of objects, linked through their first word. */
+/* Its use can greatly reduce lock contention problems, since the */
+/* allocation lock can be acquired and released many fewer times. */
+GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_many(size_t /* lb */);
+#define GC_NEXT(p) (*(void * *)(p)) /* Retrieve the next element */
+ /* in returned list. */
+
+/* A filter function to control the scanning of dynamic libraries. */
+/* If implemented, called by GC before registering a dynamic library */
+/* (discovered by GC) section as a static data root (called only as */
+/* a last reason not to register). The filename of the library, the */
+/* address and the length of the memory region (section) are passed. */
+/* This routine should return nonzero if that region should be scanned. */
+/* Always called with the allocation lock held. Depending on the */
+/* platform, might be called with the "world" stopped. */
+typedef int (GC_CALLBACK * GC_has_static_roots_func)(
+ const char * /* dlpi_name */,
+ void * /* section_start */,
+ size_t /* section_size */);
+
+/* Register a new callback (a user-supplied filter) to control the */
+/* scanning of dynamic libraries. Replaces any previously registered */
+/* callback. May be 0 (means no filtering). May be unused on some */
+/* platforms (if the filtering is unimplemented or inappropriate). */
+GC_API void GC_CALL GC_register_has_static_roots_callback(
+ GC_has_static_roots_func);
+
+#if defined(GC_WIN32_THREADS) \
+ && (!defined(GC_PTHREADS) || defined(GC_BUILD) || defined(WINAPI))
+ /* Note: for Cygwin and win32-pthread, this is skipped */
+ /* unless windows.h is included before gc.h. */
+
+# if !defined(GC_NO_THREAD_DECLS) || defined(GC_BUILD)
+
+# ifdef __cplusplus
+ } /* Including windows.h in an extern "C" context no longer works. */
+# endif
+
+# if !defined(_WIN32_WCE) && !defined(__CEGCC__)
+# include <process.h> /* For _beginthreadex, _endthreadex */
+# endif
+
+# include <windows.h>
+
+# ifdef __cplusplus
+ extern "C" {
+# endif
+
+# ifdef GC_UNDERSCORE_STDCALL
+ /* Explicitly prefix exported/imported WINAPI (__stdcall) symbols */
+ /* with '_' (underscore). Might be useful if MinGW/x86 is used. */
+# define GC_CreateThread _GC_CreateThread
+# define GC_ExitThread _GC_ExitThread
+# endif
+
+# ifdef GC_INSIDE_DLL
+ /* Export GC DllMain to be invoked from client DllMain. */
+# ifdef GC_UNDERSCORE_STDCALL
+# define GC_DllMain _GC_DllMain
+# endif
+ GC_API BOOL WINAPI GC_DllMain(HINSTANCE /* inst */, ULONG /* reason */,
+ LPVOID /* reserved */);
+# endif /* GC_INSIDE_DLL */
+
+# if !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) \
+ && !defined(UINTPTR_MAX)
+ typedef GC_word GC_uintptr_t;
# else
- /* We can't do this right without typeof, which ANSI */
- /* decided was not sufficiently useful. Repeatedly */
- /* mentioning the arguments seems too dangerous to be */
- /* useful. So does not casting the result. */
-# define GC_PTR_ADD(x, n) ((x)+(n))
+ typedef uintptr_t GC_uintptr_t;
+# endif
+# define GC_WIN32_SIZE_T GC_uintptr_t
+
+ /* All threads must be created using GC_CreateThread or */
+ /* GC_beginthreadex, or must explicitly call GC_register_my_thread */
+ /* (and call GC_unregister_my_thread before thread termination), so */
+ /* that they will be recorded in the thread table. For backward */
+ /* compatibility, it is possible to build the GC with GC_DLL */
+ /* defined, and to call GC_use_threads_discovery. This implicitly */
+ /* registers all created threads, but appears to be less robust. */
+ /* Currently the collector expects all threads to fall through and */
+ /* terminate normally, or call GC_endthreadex() or GC_ExitThread, */
+ /* so that the thread is properly unregistered. */
+ GC_API HANDLE WINAPI GC_CreateThread(
+ LPSECURITY_ATTRIBUTES /* lpThreadAttributes */,
+ GC_WIN32_SIZE_T /* dwStackSize */,
+ LPTHREAD_START_ROUTINE /* lpStartAddress */,
+ LPVOID /* lpParameter */, DWORD /* dwCreationFlags */,
+ LPDWORD /* lpThreadId */);
+
+# ifndef DECLSPEC_NORETURN
+ /* Typically defined in winnt.h. */
+# define DECLSPEC_NORETURN /* empty */
# endif
-#else /* !GC_DEBUG */
-# define GC_PTR_ADD3(x, n, type_of_result) ((x)+(n))
-# define GC_PTR_ADD(x, n) ((x)+(n))
-# define GC_PRE_INCR3(x, n, type_of_result) ((x) += (n))
-# define GC_PRE_INCR(x, n) ((x) += (n))
-# define GC_POST_INCR2(x, n, type_of_result) ((x)++)
-# define GC_POST_INCR(x, n) ((x)++)
-#endif
-/* Safer assignment of a pointer to a nonstack location. */
-#ifdef GC_DEBUG
-# ifdef __STDC__
-# define GC_PTR_STORE(p, q) \
- (*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
-# else
-# define GC_PTR_STORE(p, q) \
- (*(char **)GC_is_visible(p) = GC_is_valid_displacement(q))
+ GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(
+ DWORD /* dwExitCode */);
+
+# if !defined(_WIN32_WCE) && !defined(__CEGCC__)
+ GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
+ void * /* security */, unsigned /* stack_size */,
+ unsigned (__stdcall *)(void *),
+ void * /* arglist */, unsigned /* initflag */,
+ unsigned * /* thrdaddr */);
+
+ /* Note: _endthreadex() is not currently marked as no-return in */
+ /* VC++ and MinGW headers, so we don't mark it neither. */
+ GC_API void GC_CALL GC_endthreadex(unsigned /* retval */);
+# endif /* !_WIN32_WCE */
+
+# endif /* !GC_NO_THREAD_DECLS */
+
+# ifdef GC_WINMAIN_REDIRECT
+ /* win32_threads.c implements the real WinMain(), which will start */
+ /* a new thread to call GC_WinMain() after initializing the garbage */
+ /* collector. */
+# define WinMain GC_WinMain
# endif
-#else /* !GC_DEBUG */
-# define GC_PTR_STORE(p, q) *((p) = (q))
+
+ /* For compatibility only. */
+# define GC_use_DllMain GC_use_threads_discovery
+
+# ifndef GC_NO_THREAD_REDIRECTS
+# define CreateThread GC_CreateThread
+# define ExitThread GC_ExitThread
+# undef _beginthreadex
+# define _beginthreadex GC_beginthreadex
+# undef _endthreadex
+# define _endthreadex GC_endthreadex
+/* #define _beginthread { > "Please use _beginthreadex instead of _beginthread" < } */
+# endif /* !GC_NO_THREAD_REDIRECTS */
+
+#endif /* GC_WIN32_THREADS */
+
+/* Public setter and getter for switching "unmap as much as possible" */
+/* mode on(1) and off(0). Has no effect unless unmapping is turned on. */
+/* Has no effect on implicitly-initiated garbage collections. Initial */
+/* value is controlled by GC_FORCE_UNMAP_ON_GCOLLECT. The setter and */
+/* getter are unsynchronized. */
+GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int);
+GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
+
+/* Fully portable code should call GC_INIT() from the main program */
+/* before making any other GC_ calls. On most platforms this is a */
+/* no-op and the collector self-initializes. But a number of */
+/* platforms make that too hard. */
+/* A GC_INIT call is required if the collector is built with */
+/* THREAD_LOCAL_ALLOC defined and the initial allocation call is not */
+/* to GC_malloc() or GC_malloc_atomic(). */
+
+#ifdef __CYGWIN32__
+ /* Similarly gnu-win32 DLLs need explicit initialization from the */
+ /* main program, as does AIX. */
+ extern int _data_start__[], _data_end__[], _bss_start__[], _bss_end__[];
+# define GC_DATASTART ((GC_word)_data_start__ < (GC_word)_bss_start__ ? \
+ (void *)_data_start__ : (void *)_bss_start__)
+# define GC_DATAEND ((GC_word)_data_end__ > (GC_word)_bss_end__ ? \
+ (void *)_data_end__ : (void *)_bss_end__)
+# define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND); \
+ GC_gcollect() /* For blacklisting. */
+ /* Required at least if GC is in a DLL. And doesn't hurt. */
+#elif defined(_AIX)
+ extern int _data[], _end[];
+# define GC_DATASTART ((void *)((ulong)_data))
+# define GC_DATAEND ((void *)((ulong)_end))
+# define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND)
+#elif (defined(PLATFORM_ANDROID) || defined(__ANDROID__)) \
+ && !defined(GC_NOT_DLL)
+ /* Required if GC is built as shared library. */
+ extern int __data_start[], _end[];
+# define GC_INIT_CONF_ROOTS GC_add_roots(__data_start, _end)
+#else
+# define GC_INIT_CONF_ROOTS /* empty */
#endif
-/* Functions called to report pointer checking errors */
-GC_API void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR p, GC_PTR q));
+#ifdef GC_DONT_EXPAND
+ /* Set GC_dont_expand to TRUE at start-up */
+# define GC_INIT_CONF_DONT_EXPAND GC_set_dont_expand(1)
+#else
+# define GC_INIT_CONF_DONT_EXPAND /* empty */
+#endif
-GC_API void (*GC_is_valid_displacement_print_proc)
- GC_PROTO((GC_PTR p));
+#ifdef GC_FORCE_UNMAP_ON_GCOLLECT
+ /* Turn on "unmap as much as possible on explicit GC" mode at start-up */
+# define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT \
+ GC_set_force_unmap_on_gcollect(1)
+#else
+# define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT /* empty */
+#endif
-GC_API void (*GC_is_visible_print_proc)
- GC_PROTO((GC_PTR p));
+#ifdef GC_DONT_GC
+ /* This is for debugging only (useful if environment variables are */
+ /* unsupported); cannot call GC_disable as goes before GC_init. */
+# define GC_INIT_CONF_MAX_RETRIES (void)(GC_dont_gc = 1)
+#elif defined(GC_MAX_RETRIES)
+ /* Set GC_max_retries to the desired value at start-up */
+# define GC_INIT_CONF_MAX_RETRIES GC_set_max_retries(GC_MAX_RETRIES)
+#else
+# define GC_INIT_CONF_MAX_RETRIES /* empty */
+#endif
+#ifdef GC_FREE_SPACE_DIVISOR
+ /* Set GC_free_space_divisor to the desired value at start-up */
+# define GC_INIT_CONF_FREE_SPACE_DIVISOR \
+ GC_set_free_space_divisor(GC_FREE_SPACE_DIVISOR)
+#else
+# define GC_INIT_CONF_FREE_SPACE_DIVISOR /* empty */
+#endif
-/* For pthread support, we generally need to intercept a number of */
-/* thread library calls. We do that here by macro defining them. */
+#ifdef GC_FULL_FREQ
+ /* Set GC_full_freq to the desired value at start-up */
+# define GC_INIT_CONF_FULL_FREQ GC_set_full_freq(GC_FULL_FREQ)
+#else
+# define GC_INIT_CONF_FULL_FREQ /* empty */
+#endif
-#if !defined(GC_USE_LD_WRAP) && \
- (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS))
-# include "gc_pthread_redirects.h"
+#ifdef GC_TIME_LIMIT
+ /* Set GC_time_limit to the desired value at start-up */
+# define GC_INIT_CONF_TIME_LIMIT GC_set_time_limit(GC_TIME_LIMIT)
+#else
+# define GC_INIT_CONF_TIME_LIMIT /* empty */
#endif
-# if defined(PCR) || defined(GC_SOLARIS_THREADS) || \
- defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
- /* Any flavor of threads except SRC_M3. */
-/* This returns a list of objects, linked through their first */
-/* word. Its use can greatly reduce lock contention problems, since */
-/* the allocation lock can be acquired and released many fewer times. */
-/* lb must be large enough to hold the pointer field. */
-/* It is used internally by gc_local_alloc.h, which provides a simpler */
-/* programming interface on Linux. */
-GC_PTR GC_malloc_many(size_t lb);
-#define GC_NEXT(p) (*(GC_PTR *)(p)) /* Retrieve the next element */
- /* in returned list. */
-extern void GC_thr_init(); /* Needed for Solaris/X86 */
-
-#endif /* THREADS && !SRC_M3 */
-
-#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
-# include <windows.h>
-
- /*
- * All threads must be created using GC_CreateThread, so that they will be
- * recorded in the thread table. For backwards compatibility, this is not
- * technically true if the GC is built as a dynamic library, since it can
- * and does then use DllMain to keep track of thread creations. But new code
- * should be built to call GC_CreateThread.
- */
- GC_API HANDLE WINAPI GC_CreateThread(
- LPSECURITY_ATTRIBUTES lpThreadAttributes,
- DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
- LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
-
-# if defined(_WIN32_WCE)
- /*
- * win32_threads.c implements the real WinMain, which will start a new thread
- * to call GC_WinMain after initializing the garbage collector.
- */
- int WINAPI GC_WinMain(
- HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPWSTR lpCmdLine,
- int nCmdShow );
-
-# ifndef GC_BUILD
-# define WinMain GC_WinMain
-# define CreateThread GC_CreateThread
-# endif
-# endif /* defined(_WIN32_WCE) */
-
-#endif /* defined(GC_WIN32_THREADS) && !cygwin */
-
- /*
- * Fully portable code should call GC_INIT() from the main program
- * before making any other GC_ calls. On most platforms this is a
- * no-op and the collector self-initializes. But a number of platforms
- * make that too hard.
- */
-#if (defined(sparc) || defined(__sparc)) && defined(sun)
- /*
- * If you are planning on putting
- * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
- * from the statically loaded program section.
- * This circumvents a Solaris 2.X (X<=4) linker bug.
- */
-# define GC_INIT() { extern end, etext; \
- GC_noop(&end, &etext); }
+#if defined(GC_SIG_SUSPEND) && defined(GC_THREADS)
+# define GC_INIT_CONF_SUSPEND_SIGNAL GC_set_suspend_signal(GC_SIG_SUSPEND)
#else
-# if defined(__CYGWIN32__) && defined(GC_DLL) || defined (_AIX)
- /*
- * Similarly gnu-win32 DLLs need explicit initialization from
- * the main program, as does AIX.
- */
-# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
-# else
-# if defined(__APPLE__) && defined(__MACH__) || defined(GC_WIN32_THREADS)
-# define GC_INIT() { GC_init(); }
-# else
-# define GC_INIT()
-# endif /* !__MACH && !GC_WIN32_THREADS */
-# endif /* !AIX && !cygwin */
-#endif /* !sparc */
-
-#if !defined(_WIN32_WCE) \
- && ((defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
- || defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__))
- /* win32S may not free all resources on process exit. */
- /* This explicitly deallocates the heap. */
- GC_API void GC_win32_free_heap ();
+# define GC_INIT_CONF_SUSPEND_SIGNAL /* empty */
+#endif
+
+#if defined(GC_SIG_THR_RESTART) && defined(GC_THREADS)
+# define GC_INIT_CONF_THR_RESTART_SIGNAL \
+ GC_set_thr_restart_signal(GC_SIG_THR_RESTART)
+#else
+# define GC_INIT_CONF_THR_RESTART_SIGNAL /* empty */
+#endif
+
+#ifdef GC_MAXIMUM_HEAP_SIZE
+ /* Limit the heap size to the desired value (useful for debugging). */
+ /* The limit could be overridden either at the program start-up by */
+ /* the similar environment variable or anytime later by the */
+ /* corresponding API function call. */
+# define GC_INIT_CONF_MAXIMUM_HEAP_SIZE \
+ GC_set_max_heap_size(GC_MAXIMUM_HEAP_SIZE)
+#else
+# define GC_INIT_CONF_MAXIMUM_HEAP_SIZE /* empty */
+#endif
+
+#ifdef GC_IGNORE_WARN
+ /* Turn off all warnings at start-up (after GC initialization) */
+# define GC_INIT_CONF_IGNORE_WARN GC_set_warn_proc(GC_ignore_warn_proc)
+#else
+# define GC_INIT_CONF_IGNORE_WARN /* empty */
#endif
-#if ( defined(_AMIGA) && !defined(GC_AMIGA_MAKINGLIB) )
- /* Allocation really goes through GC_amiga_allocwrapper_do */
-# include "gc_amiga_redirects.h"
+#ifdef GC_INITIAL_HEAP_SIZE
+ /* Set heap size to the desired value at start-up */
+# define GC_INIT_CONF_INITIAL_HEAP_SIZE \
+ { size_t heap_size = GC_get_heap_size(); \
+ if (heap_size < (GC_INITIAL_HEAP_SIZE)) \
+ (void)GC_expand_hp((GC_INITIAL_HEAP_SIZE) - heap_size); }
+#else
+# define GC_INIT_CONF_INITIAL_HEAP_SIZE /* empty */
#endif
-#if defined(GC_REDIRECT_TO_LOCAL) && !defined(GC_LOCAL_ALLOC_H)
-# include "gc_local_alloc.h"
+/* Portable clients should call this at the program start-up. More */
+/* over, some platforms require this call to be done strictly from the */
+/* primordial thread. */
+#define GC_INIT() { GC_INIT_CONF_DONT_EXPAND; /* pre-init */ \
+ GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT; \
+ GC_INIT_CONF_MAX_RETRIES; \
+ GC_INIT_CONF_FREE_SPACE_DIVISOR; \
+ GC_INIT_CONF_FULL_FREQ; \
+ GC_INIT_CONF_TIME_LIMIT; \
+ GC_INIT_CONF_SUSPEND_SIGNAL; \
+ GC_INIT_CONF_THR_RESTART_SIGNAL; \
+ GC_INIT_CONF_MAXIMUM_HEAP_SIZE; \
+ GC_init(); /* real GC initialization */ \
+ GC_INIT_CONF_ROOTS; /* post-init */ \
+ GC_INIT_CONF_IGNORE_WARN; \
+ GC_INIT_CONF_INITIAL_HEAP_SIZE; }
+
+/* win32S may not free all resources on process exit. */
+/* This explicitly deallocates the heap. */
+GC_API void GC_CALL GC_win32_free_heap(void);
+
+#if defined(__SYMBIAN32__)
+ void GC_init_global_static_roots(void);
#endif
+#if defined(_AMIGA) && !defined(GC_AMIGA_MAKINGLIB)
+ /* Allocation really goes through GC_amiga_allocwrapper_do. */
+ void *GC_amiga_realloc(void *, size_t);
+# define GC_realloc(a,b) GC_amiga_realloc(a,b)
+ void GC_amiga_set_toany(void (*)(void));
+ extern int GC_amiga_free_space_divisor_inc;
+ extern void *(*GC_amiga_allocwrapper_do)(size_t, void *(GC_CALL *)(size_t));
+# define GC_malloc(a) \
+ (*GC_amiga_allocwrapper_do)(a,GC_malloc)
+# define GC_malloc_atomic(a) \
+ (*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic)
+# define GC_malloc_uncollectable(a) \
+ (*GC_amiga_allocwrapper_do)(a,GC_malloc_uncollectable)
+# define GC_malloc_stubborn(a) \
+ (*GC_amiga_allocwrapper_do)(a,GC_malloc_stubborn)
+# define GC_malloc_atomic_uncollectable(a) \
+ (*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic_uncollectable)
+# define GC_malloc_ignore_off_page(a) \
+ (*GC_amiga_allocwrapper_do)(a,GC_malloc_ignore_off_page)
+# define GC_malloc_atomic_ignore_off_page(a) \
+ (*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic_ignore_off_page)
+#endif /* _AMIGA && !GC_AMIGA_MAKINGLIB */
+
#ifdef __cplusplus
- } /* end of extern "C" */
+ } /* end of extern "C" */
#endif
-#endif /* _GC_H */
+#endif /* GC_H */
diff --git a/boehm-gc/include/gc_alloc.h b/boehm-gc/include/gc_alloc.h
deleted file mode 100644
index c50a7589646..00000000000
--- a/boehm-gc/include/gc_alloc.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Copyright (c) 1996-1998 by Silicon Graphics. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-
-//
-// This is a C++ header file that is intended to replace the SGI STL
-// alloc.h. This assumes SGI STL version < 3.0.
-//
-// This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE
-// and -DALL_INTERIOR_POINTERS. We also recommend
-// -DREDIRECT_MALLOC=GC_uncollectable_malloc.
-//
-// Some of this could be faster in the explicit deallocation case. In particular,
-// we spend too much time clearing objects on the free lists. That could be avoided.
-//
-// This uses template classes with static members, and hence does not work
-// with g++ 2.7.2 and earlier.
-//
-// This code assumes that the collector itself has been compiled with a
-// compiler that defines __STDC__ .
-//
-
-#include "gc.h"
-
-#ifndef GC_ALLOC_H
-
-#define GC_ALLOC_H
-#define __ALLOC_H // Prevent inclusion of the default version. Ugly.
-#define __SGI_STL_ALLOC_H
-#define __SGI_STL_INTERNAL_ALLOC_H
-
-#ifndef __ALLOC
-# define __ALLOC alloc
-#endif
-
-#include <stddef.h>
-#include <string.h>
-
-// The following is just replicated from the conventional SGI alloc.h:
-
-template<class T, class alloc>
-class simple_alloc {
-
-public:
- static T *allocate(size_t n)
- { return 0 == n? 0 : (T*) alloc::allocate(n * sizeof (T)); }
- static T *allocate(void)
- { return (T*) alloc::allocate(sizeof (T)); }
- static void deallocate(T *p, size_t n)
- { if (0 != n) alloc::deallocate(p, n * sizeof (T)); }
- static void deallocate(T *p)
- { alloc::deallocate(p, sizeof (T)); }
-};
-
-#include "gc.h"
-
-// The following need to match collector data structures.
-// We can't include gc_priv.h, since that pulls in way too much stuff.
-// This should eventually be factored out into another include file.
-
-extern "C" {
- extern void ** const GC_objfreelist_ptr;
- extern void ** const GC_aobjfreelist_ptr;
- extern void ** const GC_uobjfreelist_ptr;
- extern void ** const GC_auobjfreelist_ptr;
-
- extern void GC_incr_words_allocd(size_t words);
- extern void GC_incr_mem_freed(size_t words);
-
- extern char * GC_generic_malloc_words_small(size_t word, int kind);
-}
-
-// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
-// AUNCOLLECTABLE in gc_priv.h.
-
-enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
- GC_AUNCOLLECTABLE = 3 };
-
-enum { GC_max_fast_bytes = 255 };
-
-enum { GC_bytes_per_word = sizeof(char *) };
-
-enum { GC_byte_alignment = 8 };
-
-enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
-
-inline void * &GC_obj_link(void * p)
-{ return *(void **)p; }
-
-// Compute a number of words >= n+1 bytes.
-// The +1 allows for pointers one past the end.
-inline size_t GC_round_up(size_t n)
-{
- return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
-}
-
-// The same but don't allow for extra byte.
-inline size_t GC_round_up_uncollectable(size_t n)
-{
- return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
-}
-
-template <int dummy>
-class GC_aux_template {
-public:
- // File local count of allocated words. Occasionally this is
- // added into the global count. A separate count is necessary since the
- // real one must be updated with a procedure call.
- static size_t GC_words_recently_allocd;
-
- // Same for uncollectable mmory. Not yet reflected in either
- // GC_words_recently_allocd or GC_non_gc_bytes.
- static size_t GC_uncollectable_words_recently_allocd;
-
- // Similar counter for explicitly deallocated memory.
- static size_t GC_mem_recently_freed;
-
- // Again for uncollectable memory.
- static size_t GC_uncollectable_mem_recently_freed;
-
- static void * GC_out_of_line_malloc(size_t nwords, int kind);
-};
-
-template <int dummy>
-size_t GC_aux_template<dummy>::GC_words_recently_allocd = 0;
-
-template <int dummy>
-size_t GC_aux_template<dummy>::GC_uncollectable_words_recently_allocd = 0;
-
-template <int dummy>
-size_t GC_aux_template<dummy>::GC_mem_recently_freed = 0;
-
-template <int dummy>
-size_t GC_aux_template<dummy>::GC_uncollectable_mem_recently_freed = 0;
-
-template <int dummy>
-void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
-{
- GC_words_recently_allocd += GC_uncollectable_words_recently_allocd;
- GC_non_gc_bytes +=
- GC_bytes_per_word * GC_uncollectable_words_recently_allocd;
- GC_uncollectable_words_recently_allocd = 0;
-
- GC_mem_recently_freed += GC_uncollectable_mem_recently_freed;
- GC_non_gc_bytes -=
- GC_bytes_per_word * GC_uncollectable_mem_recently_freed;
- GC_uncollectable_mem_recently_freed = 0;
-
- GC_incr_words_allocd(GC_words_recently_allocd);
- GC_words_recently_allocd = 0;
-
- GC_incr_mem_freed(GC_mem_recently_freed);
- GC_mem_recently_freed = 0;
-
- return GC_generic_malloc_words_small(nwords, kind);
-}
-
-typedef GC_aux_template<0> GC_aux;
-
-// A fast, single-threaded, garbage-collected allocator
-// We assume the first word will be immediately overwritten.
-// In this version, deallocation is not a noop, and explicit
-// deallocation is likely to help performance.
-template <int dummy>
-class single_client_gc_alloc_template {
- public:
- static void * allocate(size_t n)
- {
- size_t nwords = GC_round_up(n);
- void ** flh;
- void * op;
-
- if (n > GC_max_fast_bytes) return GC_malloc(n);
- flh = GC_objfreelist_ptr + nwords;
- if (0 == (op = *flh)) {
- return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
- }
- *flh = GC_obj_link(op);
- GC_aux::GC_words_recently_allocd += nwords;
- return op;
- }
- static void * ptr_free_allocate(size_t n)
- {
- size_t nwords = GC_round_up(n);
- void ** flh;
- void * op;
-
- if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
- flh = GC_aobjfreelist_ptr + nwords;
- if (0 == (op = *flh)) {
- return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
- }
- *flh = GC_obj_link(op);
- GC_aux::GC_words_recently_allocd += nwords;
- return op;
- }
- static void deallocate(void *p, size_t n)
- {
- size_t nwords = GC_round_up(n);
- void ** flh;
-
- if (n > GC_max_fast_bytes) {
- GC_free(p);
- } else {
- flh = GC_objfreelist_ptr + nwords;
- GC_obj_link(p) = *flh;
- memset((char *)p + GC_bytes_per_word, 0,
- GC_bytes_per_word * (nwords - 1));
- *flh = p;
- GC_aux::GC_mem_recently_freed += nwords;
- }
- }
- static void ptr_free_deallocate(void *p, size_t n)
- {
- size_t nwords = GC_round_up(n);
- void ** flh;
-
- if (n > GC_max_fast_bytes) {
- GC_free(p);
- } else {
- flh = GC_aobjfreelist_ptr + nwords;
- GC_obj_link(p) = *flh;
- *flh = p;
- GC_aux::GC_mem_recently_freed += nwords;
- }
- }
-};
-
-typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
-
-// Once more, for uncollectable objects.
-template <int dummy>
-class single_client_alloc_template {
- public:
- static void * allocate(size_t n)
- {
- size_t nwords = GC_round_up_uncollectable(n);
- void ** flh;
- void * op;
-
- if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
- flh = GC_uobjfreelist_ptr + nwords;
- if (0 == (op = *flh)) {
- return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
- }
- *flh = GC_obj_link(op);
- GC_aux::GC_uncollectable_words_recently_allocd += nwords;
- return op;
- }
- static void * ptr_free_allocate(size_t n)
- {
- size_t nwords = GC_round_up_uncollectable(n);
- void ** flh;
- void * op;
-
- if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
- flh = GC_auobjfreelist_ptr + nwords;
- if (0 == (op = *flh)) {
- return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
- }
- *flh = GC_obj_link(op);
- GC_aux::GC_uncollectable_words_recently_allocd += nwords;
- return op;
- }
- static void deallocate(void *p, size_t n)
- {
- size_t nwords = GC_round_up_uncollectable(n);
- void ** flh;
-
- if (n > GC_max_fast_bytes) {
- GC_free(p);
- } else {
- flh = GC_uobjfreelist_ptr + nwords;
- GC_obj_link(p) = *flh;
- *flh = p;
- GC_aux::GC_uncollectable_mem_recently_freed += nwords;
- }
- }
- static void ptr_free_deallocate(void *p, size_t n)
- {
- size_t nwords = GC_round_up_uncollectable(n);
- void ** flh;
-
- if (n > GC_max_fast_bytes) {
- GC_free(p);
- } else {
- flh = GC_auobjfreelist_ptr + nwords;
- GC_obj_link(p) = *flh;
- *flh = p;
- GC_aux::GC_uncollectable_mem_recently_freed += nwords;
- }
- }
-};
-
-typedef single_client_alloc_template<0> single_client_alloc;
-
-template < int dummy >
-class gc_alloc_template {
- public:
- static void * allocate(size_t n) { return GC_malloc(n); }
- static void * ptr_free_allocate(size_t n)
- { return GC_malloc_atomic(n); }
- static void deallocate(void *, size_t) { }
- static void ptr_free_deallocate(void *, size_t) { }
-};
-
-typedef gc_alloc_template < 0 > gc_alloc;
-
-template < int dummy >
-class alloc_template {
- public:
- static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
- static void * ptr_free_allocate(size_t n)
- { return GC_malloc_atomic_uncollectable(n); }
- static void deallocate(void *p, size_t) { GC_free(p); }
- static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
-};
-
-typedef alloc_template < 0 > alloc;
-
-#ifdef _SGI_SOURCE
-
-// We want to specialize simple_alloc so that it does the right thing
-// for all pointerfree types. At the moment there is no portable way to
-// even approximate that. The following approximation should work for
-// SGI compilers, and perhaps some others.
-
-# define __GC_SPECIALIZE(T,alloc) \
-class simple_alloc<T, alloc> { \
-public: \
- static T *allocate(size_t n) \
- { return 0 == n? 0 : \
- (T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
- static T *allocate(void) \
- { return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
- static void deallocate(T *p, size_t n) \
- { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
- static void deallocate(T *p) \
- { alloc::ptr_free_deallocate(p, sizeof (T)); } \
-};
-
-__GC_SPECIALIZE(char, gc_alloc)
-__GC_SPECIALIZE(int, gc_alloc)
-__GC_SPECIALIZE(unsigned, gc_alloc)
-__GC_SPECIALIZE(float, gc_alloc)
-__GC_SPECIALIZE(double, gc_alloc)
-
-__GC_SPECIALIZE(char, alloc)
-__GC_SPECIALIZE(int, alloc)
-__GC_SPECIALIZE(unsigned, alloc)
-__GC_SPECIALIZE(float, alloc)
-__GC_SPECIALIZE(double, alloc)
-
-__GC_SPECIALIZE(char, single_client_gc_alloc)
-__GC_SPECIALIZE(int, single_client_gc_alloc)
-__GC_SPECIALIZE(unsigned, single_client_gc_alloc)
-__GC_SPECIALIZE(float, single_client_gc_alloc)
-__GC_SPECIALIZE(double, single_client_gc_alloc)
-
-__GC_SPECIALIZE(char, single_client_alloc)
-__GC_SPECIALIZE(int, single_client_alloc)
-__GC_SPECIALIZE(unsigned, single_client_alloc)
-__GC_SPECIALIZE(float, single_client_alloc)
-__GC_SPECIALIZE(double, single_client_alloc)
-
-#ifdef __STL_USE_STD_ALLOCATORS
-
-???copy stuff from stl_alloc.h or remove it to a different file ???
-
-#endif /* __STL_USE_STD_ALLOCATORS */
-
-#endif /* _SGI_SOURCE */
-
-#endif /* GC_ALLOC_H */
diff --git a/boehm-gc/include/gc_allocator.h b/boehm-gc/include/gc_allocator.h
new file mode 100644
index 00000000000..086fac4b3db
--- /dev/null
+++ b/boehm-gc/include/gc_allocator.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 1996-1997
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * Copyright (c) 2002
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ */
+
+/*
+ * This implements standard-conforming allocators that interact with
+ * the garbage collector. Gc_alloctor<T> allocates garbage-collectable
+ * objects of type T. Traceable_allocator<T> allocates objects that
+ * are not themselves garbage collected, but are scanned by the
+ * collector for pointers to collectable objects. Traceable_alloc
+ * should be used for explicitly managed STL containers that may
+ * point to collectable objects.
+ *
+ * This code was derived from an earlier version of the GNU C++ standard
+ * library, which itself was derived from the SGI STL implementation.
+ *
+ * Ignore-off-page allocator: George T. Talbot
+ */
+
+#ifndef GC_ALLOCATOR_H
+
+#define GC_ALLOCATOR_H
+
+#include "gc.h"
+#include <new> // for placement new
+
+#if defined(__GNUC__)
+# define GC_ATTR_UNUSED __attribute__((__unused__))
+#else
+# define GC_ATTR_UNUSED
+#endif
+
+/* First some helpers to allow us to dispatch on whether or not a type
+ * is known to be pointer-free.
+ * These are private, except that the client may invoke the
+ * GC_DECLARE_PTRFREE macro.
+ */
+
+struct GC_true_type {};
+struct GC_false_type {};
+
+template <class GC_tp>
+struct GC_type_traits {
+ GC_false_type GC_is_ptr_free;
+};
+
+# define GC_DECLARE_PTRFREE(T) \
+template<> struct GC_type_traits<T> { GC_true_type GC_is_ptr_free; }
+
+GC_DECLARE_PTRFREE(char);
+GC_DECLARE_PTRFREE(signed char);
+GC_DECLARE_PTRFREE(unsigned char);
+GC_DECLARE_PTRFREE(signed short);
+GC_DECLARE_PTRFREE(unsigned short);
+GC_DECLARE_PTRFREE(signed int);
+GC_DECLARE_PTRFREE(unsigned int);
+GC_DECLARE_PTRFREE(signed long);
+GC_DECLARE_PTRFREE(unsigned long);
+GC_DECLARE_PTRFREE(float);
+GC_DECLARE_PTRFREE(double);
+GC_DECLARE_PTRFREE(long double);
+/* The client may want to add others. */
+
+// In the following GC_Tp is GC_true_type if we are allocating a
+// pointer-free object.
+template <class GC_Tp>
+inline void * GC_selective_alloc(size_t n, GC_Tp, bool ignore_off_page) {
+ return ignore_off_page?GC_MALLOC_IGNORE_OFF_PAGE(n):GC_MALLOC(n);
+}
+
+template <>
+inline void * GC_selective_alloc<GC_true_type>(size_t n, GC_true_type,
+ bool ignore_off_page) {
+ return ignore_off_page? GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(n)
+ : GC_MALLOC_ATOMIC(n);
+}
+
+/* Now the public gc_allocator<T> class:
+ */
+template <class GC_Tp>
+class gc_allocator {
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef GC_Tp* pointer;
+ typedef const GC_Tp* const_pointer;
+ typedef GC_Tp& reference;
+ typedef const GC_Tp& const_reference;
+ typedef GC_Tp value_type;
+
+ template <class GC_Tp1> struct rebind {
+ typedef gc_allocator<GC_Tp1> other;
+ };
+
+ gc_allocator() {}
+ gc_allocator(const gc_allocator&) throw() {}
+# if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
+ // MSVC++ 6.0 do not support member templates
+ template <class GC_Tp1> gc_allocator(const gc_allocator<GC_Tp1>&) throw() {}
+# endif
+ ~gc_allocator() throw() {}
+
+ pointer address(reference GC_x) const { return &GC_x; }
+ const_pointer address(const_reference GC_x) const { return &GC_x; }
+
+ // GC_n is permitted to be 0. The C++ standard says nothing about what
+ // the return value is when GC_n == 0.
+ GC_Tp* allocate(size_type GC_n, const void* = 0) {
+ GC_type_traits<GC_Tp> traits;
+ return static_cast<GC_Tp *>
+ (GC_selective_alloc(GC_n * sizeof(GC_Tp),
+ traits.GC_is_ptr_free, false));
+ }
+
+ // __p is not permitted to be a null pointer.
+ void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
+ { GC_FREE(__p); }
+
+ size_type max_size() const throw()
+ { return size_t(-1) / sizeof(GC_Tp); }
+
+ void construct(pointer __p, const GC_Tp& __val) { new(__p) GC_Tp(__val); }
+ void destroy(pointer __p) { __p->~GC_Tp(); }
+};
+
+template<>
+class gc_allocator<void> {
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef void* pointer;
+ typedef const void* const_pointer;
+ typedef void value_type;
+
+ template <class GC_Tp1> struct rebind {
+ typedef gc_allocator<GC_Tp1> other;
+ };
+};
+
+
+template <class GC_T1, class GC_T2>
+inline bool operator==(const gc_allocator<GC_T1>&, const gc_allocator<GC_T2>&)
+{
+ return true;
+}
+
+template <class GC_T1, class GC_T2>
+inline bool operator!=(const gc_allocator<GC_T1>&, const gc_allocator<GC_T2>&)
+{
+ return false;
+}
+
+
+/* Now the public gc_allocator_ignore_off_page<T> class:
+ */
+template <class GC_Tp>
+class gc_allocator_ignore_off_page {
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef GC_Tp* pointer;
+ typedef const GC_Tp* const_pointer;
+ typedef GC_Tp& reference;
+ typedef const GC_Tp& const_reference;
+ typedef GC_Tp value_type;
+
+ template <class GC_Tp1> struct rebind {
+ typedef gc_allocator_ignore_off_page<GC_Tp1> other;
+ };
+
+ gc_allocator_ignore_off_page() {}
+ gc_allocator_ignore_off_page(const gc_allocator_ignore_off_page&) throw() {}
+# if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
+ // MSVC++ 6.0 do not support member templates
+ template <class GC_Tp1>
+ gc_allocator_ignore_off_page(const gc_allocator_ignore_off_page<GC_Tp1>&)
+ throw() {}
+# endif
+ ~gc_allocator_ignore_off_page() throw() {}
+
+ pointer address(reference GC_x) const { return &GC_x; }
+ const_pointer address(const_reference GC_x) const { return &GC_x; }
+
+ // GC_n is permitted to be 0. The C++ standard says nothing about what
+ // the return value is when GC_n == 0.
+ GC_Tp* allocate(size_type GC_n, const void* = 0) {
+ GC_type_traits<GC_Tp> traits;
+ return static_cast<GC_Tp *>
+ (GC_selective_alloc(GC_n * sizeof(GC_Tp),
+ traits.GC_is_ptr_free, true));
+ }
+
+ // __p is not permitted to be a null pointer.
+ void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
+ { GC_FREE(__p); }
+
+ size_type max_size() const throw()
+ { return size_t(-1) / sizeof(GC_Tp); }
+
+ void construct(pointer __p, const GC_Tp& __val) { new(__p) GC_Tp(__val); }
+ void destroy(pointer __p) { __p->~GC_Tp(); }
+};
+
+template<>
+class gc_allocator_ignore_off_page<void> {
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef void* pointer;
+ typedef const void* const_pointer;
+ typedef void value_type;
+
+ template <class GC_Tp1> struct rebind {
+ typedef gc_allocator_ignore_off_page<GC_Tp1> other;
+ };
+};
+
+template <class GC_T1, class GC_T2>
+inline bool operator==(const gc_allocator_ignore_off_page<GC_T1>&, const gc_allocator_ignore_off_page<GC_T2>&)
+{
+ return true;
+}
+
+template <class GC_T1, class GC_T2>
+inline bool operator!=(const gc_allocator_ignore_off_page<GC_T1>&, const gc_allocator_ignore_off_page<GC_T2>&)
+{
+ return false;
+}
+
+/*
+ * And the public traceable_allocator class.
+ */
+
+// Note that we currently don't specialize the pointer-free case, since a
+// pointer-free traceable container doesn't make that much sense,
+// though it could become an issue due to abstraction boundaries.
+template <class GC_Tp>
+class traceable_allocator {
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef GC_Tp* pointer;
+ typedef const GC_Tp* const_pointer;
+ typedef GC_Tp& reference;
+ typedef const GC_Tp& const_reference;
+ typedef GC_Tp value_type;
+
+ template <class GC_Tp1> struct rebind {
+ typedef traceable_allocator<GC_Tp1> other;
+ };
+
+ traceable_allocator() throw() {}
+ traceable_allocator(const traceable_allocator&) throw() {}
+# if !(GC_NO_MEMBER_TEMPLATES || 0 < _MSC_VER && _MSC_VER <= 1200)
+ // MSVC++ 6.0 do not support member templates
+ template <class GC_Tp1> traceable_allocator
+ (const traceable_allocator<GC_Tp1>&) throw() {}
+# endif
+ ~traceable_allocator() throw() {}
+
+ pointer address(reference GC_x) const { return &GC_x; }
+ const_pointer address(const_reference GC_x) const { return &GC_x; }
+
+ // GC_n is permitted to be 0. The C++ standard says nothing about what
+ // the return value is when GC_n == 0.
+ GC_Tp* allocate(size_type GC_n, const void* = 0) {
+ return static_cast<GC_Tp*>(GC_MALLOC_UNCOLLECTABLE(GC_n * sizeof(GC_Tp)));
+ }
+
+ // __p is not permitted to be a null pointer.
+ void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
+ { GC_FREE(__p); }
+
+ size_type max_size() const throw()
+ { return size_t(-1) / sizeof(GC_Tp); }
+
+ void construct(pointer __p, const GC_Tp& __val) { new(__p) GC_Tp(__val); }
+ void destroy(pointer __p) { __p->~GC_Tp(); }
+};
+
+template<>
+class traceable_allocator<void> {
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef void* pointer;
+ typedef const void* const_pointer;
+ typedef void value_type;
+
+ template <class GC_Tp1> struct rebind {
+ typedef traceable_allocator<GC_Tp1> other;
+ };
+};
+
+
+template <class GC_T1, class GC_T2>
+inline bool operator==(const traceable_allocator<GC_T1>&, const traceable_allocator<GC_T2>&)
+{
+ return true;
+}
+
+template <class GC_T1, class GC_T2>
+inline bool operator!=(const traceable_allocator<GC_T1>&, const traceable_allocator<GC_T2>&)
+{
+ return false;
+}
+
+#endif /* GC_ALLOCATOR_H */
diff --git a/boehm-gc/include/gc_amiga_redirects.h b/boehm-gc/include/gc_amiga_redirects.h
deleted file mode 100644
index 9e975c8c832..00000000000
--- a/boehm-gc/include/gc_amiga_redirects.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef GC_AMIGA_REDIRECTS_H
-
-# define GC_AMIGA_REDIRECTS_H
-
-# if ( defined(_AMIGA) && !defined(GC_AMIGA_MAKINGLIB) )
- extern void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes);
-# define GC_realloc(a,b) GC_amiga_realloc(a,b)
- extern void GC_amiga_set_toany(void (*func)(void));
- extern int GC_amiga_free_space_divisor_inc;
- extern void *(*GC_amiga_allocwrapper_do) \
- (size_t size,void *(*AllocFunction)(size_t size2));
-# define GC_malloc(a) \
- (*GC_amiga_allocwrapper_do)(a,GC_malloc)
-# define GC_malloc_atomic(a) \
- (*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic)
-# define GC_malloc_uncollectable(a) \
- (*GC_amiga_allocwrapper_do)(a,GC_malloc_uncollectable)
-# define GC_malloc_stubborn(a) \
- (*GC_amiga_allocwrapper_do)(a,GC_malloc_stubborn)
-# define GC_malloc_atomic_uncollectable(a) \
- (*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic_uncollectable)
-# define GC_malloc_ignore_off_page(a) \
- (*GC_amiga_allocwrapper_do)(a,GC_malloc_ignore_off_page)
-# define GC_malloc_atomic_ignore_off_page(a) \
- (*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic_ignore_off_page)
-# endif /* _AMIGA && !GC_AMIGA_MAKINGLIB */
-
-#endif /* GC_AMIGA_REDIRECTS_H */
-
-
diff --git a/boehm-gc/include/gc_backptr.h b/boehm-gc/include/gc_backptr.h
index 5899496e0fe..c7e29d285a9 100644
--- a/boehm-gc/include/gc_backptr.h
+++ b/boehm-gc/include/gc_backptr.h
@@ -1,4 +1,21 @@
/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/*
* This is a simple API to implement pointer back tracing, i.e.
* to answer questions such as "who is pointing to this" or
* "why is this object being retained by the collector"
@@ -22,44 +39,60 @@
#ifndef GC_BACKPTR_H
#define GC_BACKPTR_H
+
+#ifndef GC_H
+# include "gc.h"
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
/* Store information about the object referencing dest in *base_p */
/* and *offset_p. */
-/* If multiple objects or roots point to dest, the one reported */
+/* If multiple objects or roots point to dest, the one reported */
/* will be the last on used by the garbage collector to trace the */
-/* object. */
-/* source is root ==> *base_p = address, *offset_p = 0 */
+/* object. */
+/* source is root ==> *base_p = address, *offset_p = 0 */
/* source is heap object ==> *base_p != 0, *offset_p = offset */
/* Returns 1 on success, 0 if source couldn't be determined. */
/* Dest can be any address within a heap object. */
-typedef enum { GC_UNREFERENCED, /* No reference info available. */
- GC_NO_SPACE, /* Dest not allocated with debug alloc */
- GC_REFD_FROM_ROOT, /* Referenced directly by root *base_p */
- GC_REFD_FROM_REG, /* Referenced from a register, i.e. */
- /* a root without an address. */
- GC_REFD_FROM_HEAP, /* Referenced from another heap obj. */
- GC_FINALIZER_REFD /* Finalizable and hence accessible. */
+typedef enum {
+ GC_UNREFERENCED, /* No reference info available. */
+ GC_NO_SPACE, /* Dest not allocated with debug alloc. */
+ GC_REFD_FROM_ROOT, /* Referenced directly by root *base_p. */
+ GC_REFD_FROM_REG, /* Referenced from a register, i.e. */
+ /* a root without an address. */
+ GC_REFD_FROM_HEAP, /* Referenced from another heap obj. */
+ GC_FINALIZER_REFD /* Finalizable and hence accessible. */
} GC_ref_kind;
-GC_ref_kind GC_get_back_ptr_info(void *dest, void **base_p, size_t *offset_p);
+GC_API GC_ref_kind GC_CALL GC_get_back_ptr_info(void * /* dest */,
+ void ** /* base_p */, size_t * /* offset_p */)
+ GC_ATTR_NONNULL(1);
/* Generate a random heap address. */
/* The resulting address is in the heap, but */
/* not necessarily inside a valid object. */
-void * GC_generate_random_heap_address(void);
+GC_API void * GC_CALL GC_generate_random_heap_address(void);
/* Generate a random address inside a valid marked heap object. */
-void * GC_generate_random_valid_address(void);
+GC_API void * GC_CALL GC_generate_random_valid_address(void);
+
+/* Force a garbage collection and generate a backtrace from a */
+/* random heap address. */
+/* This uses the GC logging mechanism (GC_printf) to produce */
+/* output. It can often be called from a debugger. The */
+/* source in dbg_mlc.c also serves as a sample client. */
+GC_API void GC_CALL GC_generate_random_backtrace(void);
-/* Force a garbage collection and generate a backtrace from a */
-/* random heap address. */
-/* This uses the GC logging mechanism (GC_printf) to produce */
-/* output. It can often be called from a debugger. The */
-/* source in dbg_mlc.c also serves as a sample client. */
-void GC_generate_random_backtrace(void);
+/* Print a backtrace from a specific address. Used by the */
+/* above. The client should call GC_gcollect() immediately */
+/* before invocation. */
+GC_API void GC_CALL GC_print_backtrace(void *) GC_ATTR_NONNULL(1);
-/* Print a backtrace from a specific address. Used by the */
-/* above. The client should call GC_gcollect() immediately */
-/* before invocation. */
-void GC_print_backtrace(void *);
+#ifdef __cplusplus
+ } /* end of extern "C" */
+#endif
#endif /* GC_BACKPTR_H */
diff --git a/boehm-gc/include/gc_config_macros.h b/boehm-gc/include/gc_config_macros.h
new file mode 100644
index 00000000000..9d5890077c3
--- /dev/null
+++ b/boehm-gc/include/gc_config_macros.h
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* This should never be included directly; it is included only from gc.h. */
+/* We separate it only to make gc.h more suitable as documentation. */
+#if defined(GC_H)
+
+/* Some tests for old macros. These violate our namespace rules and */
+/* will disappear shortly. Use the GC_ names. */
+#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS) \
+ || defined(_SOLARIS_PTHREADS) || defined(GC_SOLARIS_PTHREADS)
+ /* We no longer support old style Solaris threads. */
+ /* GC_SOLARIS_THREADS now means pthreads. */
+# ifndef GC_SOLARIS_THREADS
+# define GC_SOLARIS_THREADS
+# endif
+#endif
+#if defined(IRIX_THREADS)
+# define GC_IRIX_THREADS
+#endif
+#if defined(DGUX_THREADS) && !defined(GC_DGUX386_THREADS)
+# define GC_DGUX386_THREADS
+#endif
+#if defined(AIX_THREADS)
+# define GC_AIX_THREADS
+#endif
+#if defined(HPUX_THREADS)
+# define GC_HPUX_THREADS
+#endif
+#if defined(OSF1_THREADS)
+# define GC_OSF1_THREADS
+#endif
+#if defined(LINUX_THREADS)
+# define GC_LINUX_THREADS
+#endif
+#if defined(WIN32_THREADS)
+# define GC_WIN32_THREADS
+#endif
+#if defined(RTEMS_THREADS)
+# define GC_RTEMS_PTHREADS
+#endif
+#if defined(USE_LD_WRAP)
+# define GC_USE_LD_WRAP
+#endif
+
+#if defined(GC_WIN32_PTHREADS) && !defined(GC_WIN32_THREADS)
+ /* Using pthreads-w32 library. */
+# define GC_WIN32_THREADS
+#endif
+
+#if defined(GC_AIX_THREADS) || defined(GC_DARWIN_THREADS) \
+ || defined(GC_DGUX386_THREADS) || defined(GC_FREEBSD_THREADS) \
+ || defined(GC_GNU_THREADS) || defined(GC_HPUX_THREADS) \
+ || defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) \
+ || defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS) \
+ || defined(GC_OSF1_THREADS) || defined(GC_SOLARIS_THREADS) \
+ || defined(GC_WIN32_THREADS) || defined(GC_RTEMS_PTHREADS)
+# ifndef GC_THREADS
+# define GC_THREADS
+# endif
+#elif defined(GC_THREADS)
+# if defined(__linux__)
+# define GC_LINUX_THREADS
+# endif
+# if !defined(__linux__) && (defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
+ || defined(hppa) || defined(__HPPA)) \
+ || (defined(__ia64) && defined(_HPUX_SOURCE))
+# define GC_HPUX_THREADS
+# endif
+# if !defined(__linux__) && (defined(__alpha) || defined(__alpha__))
+# define GC_OSF1_THREADS
+# endif
+# if defined(__mips) && !defined(__linux__)
+# define GC_IRIX_THREADS
+# endif
+# if defined(__sparc) && !defined(__linux__) \
+ || defined(sun) && (defined(i386) || defined(__i386__) \
+ || defined(__amd64__))
+# define GC_SOLARIS_THREADS
+# elif defined(__APPLE__) && defined(__MACH__)
+# define GC_DARWIN_THREADS
+# elif defined(__OpenBSD__)
+# define GC_OPENBSD_THREADS
+# elif !defined(GC_LINUX_THREADS) && !defined(GC_HPUX_THREADS) \
+ && !defined(GC_OSF1_THREADS) && !defined(GC_IRIX_THREADS)
+ /* FIXME: Should we really need for FreeBSD and NetBSD to check */
+ /* that no other GC_xxx_THREADS macro is set? */
+# if defined(__FreeBSD__) || defined(__DragonFly__)
+# define GC_FREEBSD_THREADS
+# elif defined(__NetBSD__)
+# define GC_NETBSD_THREADS
+# endif
+# endif
+# if defined(DGUX) && (defined(i386) || defined(__i386__))
+# define GC_DGUX386_THREADS
+# endif
+# if defined(_AIX)
+# define GC_AIX_THREADS
+# endif
+# if (defined(_WIN32) || defined(_MSC_VER) || defined(__BORLANDC__) \
+ || defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__CEGCC__) \
+ || defined(_WIN32_WCE) || defined(__MINGW32__)) \
+ && !defined(GC_WIN32_THREADS)
+ /* Either posix or native Win32 threads. */
+# define GC_WIN32_THREADS
+# endif
+# if defined(__rtems__) && (defined(i386) || defined(__i386__))
+# define GC_RTEMS_PTHREADS
+# endif
+#endif /* GC_THREADS */
+
+#undef GC_PTHREADS
+#if (!defined(GC_WIN32_THREADS) || defined(GC_WIN32_PTHREADS) \
+ || defined(__CYGWIN32__) || defined(__CYGWIN__)) && defined(GC_THREADS)
+ /* Posix threads. */
+# define GC_PTHREADS
+#endif
+
+#if !defined(_PTHREADS) && defined(GC_NETBSD_THREADS)
+# define _PTHREADS
+#endif
+
+#if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
+# define _POSIX4A_DRAFT10_SOURCE 1
+#endif
+
+#if !defined(_REENTRANT) && defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
+ /* Better late than never. This fails if system headers that depend */
+ /* on this were previously included. */
+# define _REENTRANT
+#endif
+
+#define __GC
+#if !defined(_WIN32_WCE) || defined(__GNUC__)
+# include <stddef.h>
+# if defined(__MINGW32__) && !defined(_WIN32_WCE)
+# include <stdint.h>
+ /* We mention uintptr_t. */
+ /* Perhaps this should be included in pure msft environments */
+ /* as well? */
+# endif
+#else /* _WIN32_WCE */
+ /* Yet more kludges for WinCE. */
+# include <stdlib.h> /* size_t is defined here */
+# ifndef _PTRDIFF_T_DEFINED
+ /* ptrdiff_t is not defined */
+# define _PTRDIFF_T_DEFINED
+ typedef long ptrdiff_t;
+# endif
+#endif /* _WIN32_WCE */
+
+#if !defined(GC_NOT_DLL) && !defined(GC_DLL) \
+ && ((defined(_DLL) && !defined(__GNUC__)) \
+ || (defined(DLL_EXPORT) && defined(GC_BUILD)))
+# define GC_DLL
+#endif
+
+#if defined(GC_DLL) && !defined(GC_API)
+
+# if defined(__MINGW32__) || defined(__CEGCC__)
+# ifdef GC_BUILD
+# define GC_API __declspec(dllexport)
+# else
+# define GC_API __declspec(dllimport)
+# endif
+
+# elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
+ || defined(__CYGWIN__)
+# ifdef GC_BUILD
+# define GC_API extern __declspec(dllexport)
+# else
+# define GC_API __declspec(dllimport)
+# endif
+
+# elif defined(__WATCOMC__)
+# ifdef GC_BUILD
+# define GC_API extern __declspec(dllexport)
+# else
+# define GC_API extern __declspec(dllimport)
+# endif
+
+# elif defined(__SYMBIAN32__)
+# ifdef GC_BUILD
+# define GC_API extern EXPORT_C
+# else
+# define GC_API extern IMPORT_C
+# endif
+
+# elif defined(__GNUC__)
+ /* Only matters if used in conjunction with -fvisibility=hidden option. */
+# if defined(GC_BUILD) && (__GNUC__ >= 4 \
+ || defined(GC_VISIBILITY_HIDDEN_SET))
+# define GC_API extern __attribute__((__visibility__("default")))
+# endif
+# endif
+#endif /* GC_DLL */
+
+#ifndef GC_API
+# define GC_API extern
+#endif
+
+#ifndef GC_CALL
+# define GC_CALL
+#endif
+
+#ifndef GC_CALLBACK
+# define GC_CALLBACK GC_CALL
+#endif
+
+#ifndef GC_ATTR_MALLOC
+ /* 'malloc' attribute should be used for all malloc-like functions */
+ /* (to tell the compiler that a function may be treated as if any */
+ /* non-NULL pointer it returns cannot alias any other pointer valid */
+ /* when the function returns). If the client code violates this rule */
+ /* by using custom GC_oom_func then define GC_OOM_FUNC_RETURNS_ALIAS. */
+# ifdef GC_OOM_FUNC_RETURNS_ALIAS
+# define GC_ATTR_MALLOC /* empty */
+# elif defined(__GNUC__) && (__GNUC__ > 3 \
+ || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+# define GC_ATTR_MALLOC __attribute__((__malloc__))
+# elif defined(_MSC_VER) && _MSC_VER >= 14
+# define GC_ATTR_MALLOC __declspec(noalias) __declspec(restrict)
+# else
+# define GC_ATTR_MALLOC
+# endif
+#endif
+
+#ifndef GC_ATTR_ALLOC_SIZE
+ /* 'alloc_size' attribute improves __builtin_object_size correctness. */
+ /* Only single-argument form of 'alloc_size' attribute is used. */
+# if defined(__GNUC__) && (__GNUC__ > 4 \
+ || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 && !defined(__ICC)))
+# define GC_ATTR_ALLOC_SIZE(argnum) __attribute__((__alloc_size__(argnum)))
+# else
+# define GC_ATTR_ALLOC_SIZE(argnum)
+# endif
+#endif
+
+#ifndef GC_ATTR_NONNULL
+# if defined(__GNUC__) && __GNUC__ >= 4
+# define GC_ATTR_NONNULL(argnum) __attribute__((__nonnull__(argnum)))
+# else
+# define GC_ATTR_NONNULL(argnum) /* empty */
+# endif
+#endif
+
+#ifndef GC_ATTR_DEPRECATED
+# ifdef GC_BUILD
+# undef GC_ATTR_DEPRECATED
+# define GC_ATTR_DEPRECATED /* empty */
+# elif defined(__GNUC__) && __GNUC__ >= 4
+# define GC_ATTR_DEPRECATED __attribute__((__deprecated__))
+# elif defined(_MSC_VER) && _MSC_VER >= 12
+# define GC_ATTR_DEPRECATED __declspec(deprecated)
+# else
+# define GC_ATTR_DEPRECATED /* empty */
+# endif
+#endif
+
+#if defined(__sgi) && !defined(__GNUC__) && _COMPILER_VERSION >= 720
+# define GC_ADD_CALLER
+# define GC_RETURN_ADDR (GC_word)__return_address
+#endif
+
+#if defined(__linux__) || defined(__GLIBC__)
+# if !defined(__native_client__)
+# include <features.h>
+# endif
+# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
+ && !defined(__ia64__) && !defined(__UCLIBC__) \
+ && !defined(GC_HAVE_BUILTIN_BACKTRACE)
+# define GC_HAVE_BUILTIN_BACKTRACE
+# endif
+# if defined(__i386__) || defined(__x86_64__)
+# define GC_CAN_SAVE_CALL_STACKS
+# endif
+#endif /* GLIBC */
+
+#if defined(_MSC_VER) && _MSC_VER >= 1200 /* version 12.0+ (MSVC 6.0+) */ \
+ && !defined(_AMD64_) && !defined(_M_X64) && !defined(_WIN32_WCE) \
+ && !defined(GC_HAVE_NO_BUILTIN_BACKTRACE) \
+ && !defined(GC_HAVE_BUILTIN_BACKTRACE)
+# define GC_HAVE_BUILTIN_BACKTRACE
+#endif
+
+#if defined(GC_HAVE_BUILTIN_BACKTRACE) && !defined(GC_CAN_SAVE_CALL_STACKS)
+# define GC_CAN_SAVE_CALL_STACKS
+#endif
+
+#if defined(__sparc__)
+# define GC_CAN_SAVE_CALL_STACKS
+#endif
+
+/* If we're on an a platform on which we can't save call stacks, but */
+/* gcc is normally used, we go ahead and define GC_ADD_CALLER. */
+/* We make this decision independent of whether gcc is actually being */
+/* used, in order to keep the interface consistent, and allow mixing */
+/* of compilers. */
+/* This may also be desirable if it is possible but expensive to */
+/* retrieve the call chain. */
+#if (defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(__FreeBSD__) || defined(__DragonFly__) \
+ || defined(PLATFORM_ANDROID) || defined(__ANDROID__)) \
+ && !defined(GC_CAN_SAVE_CALL_STACKS)
+# define GC_ADD_CALLER
+# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+ /* gcc knows how to retrieve return address, but we don't know */
+ /* how to generate call stacks. */
+# define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
+# else
+ /* Just pass 0 for gcc compatibility. */
+# define GC_RETURN_ADDR 0
+# endif
+#endif /* !GC_CAN_SAVE_CALL_STACKS */
+
+#ifdef GC_PTHREADS
+
+# if (defined(GC_DARWIN_THREADS) || defined(GC_WIN32_PTHREADS) \
+ || defined(__native_client__) || defined(GC_RTEMS_PTHREADS)) \
+ && !defined(GC_NO_DLOPEN)
+ /* Either there is no dlopen() or we do not need to intercept it. */
+# define GC_NO_DLOPEN
+# endif
+
+# if (defined(GC_DARWIN_THREADS) || defined(GC_WIN32_PTHREADS) \
+ || defined(GC_OPENBSD_THREADS) || defined(__native_client__)) \
+ && !defined(GC_NO_PTHREAD_SIGMASK)
+ /* Either there is no pthread_sigmask() or no need to intercept it. */
+# define GC_NO_PTHREAD_SIGMASK
+# endif
+
+# if defined(__native_client__)
+ /* At present, NaCl pthread_create() prototype does not have */
+ /* "const" for its "attr" argument; also, NaCl pthread_exit() one */
+ /* does not have "noreturn" attribute. */
+# ifndef GC_PTHREAD_CREATE_CONST
+# define GC_PTHREAD_CREATE_CONST /* empty */
+# endif
+# ifndef GC_PTHREAD_EXIT_ATTRIBUTE
+# define GC_PTHREAD_EXIT_ATTRIBUTE /* empty */
+# endif
+# endif
+
+# if !defined(GC_PTHREAD_EXIT_ATTRIBUTE) \
+ && !defined(PLATFORM_ANDROID) && !defined(__ANDROID__) \
+ && (defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS))
+ /* Intercept pthread_exit on Linux and Solaris. */
+# if defined(__GNUC__) /* since GCC v2.7 */
+# define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__))
+# elif defined(__NORETURN) /* used in Solaris */
+# define GC_PTHREAD_EXIT_ATTRIBUTE __NORETURN
+# else
+# define GC_PTHREAD_EXIT_ATTRIBUTE /* empty */
+# endif
+# endif
+
+# if (!defined(GC_PTHREAD_EXIT_ATTRIBUTE) || defined(__native_client__)) \
+ && !defined(GC_NO_PTHREAD_CANCEL)
+ /* Either there is no pthread_cancel() or no need to intercept it. */
+# define GC_NO_PTHREAD_CANCEL
+# endif
+
+#endif /* GC_PTHREADS */
+
+#endif
diff --git a/boehm-gc/include/gc_cpp.h b/boehm-gc/include/gc_cpp.h
index c4d8b50e6b9..6882786b0a5 100644
--- a/boehm-gc/include/gc_cpp.h
+++ b/boehm-gc/include/gc_cpp.h
@@ -1,21 +1,23 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program for any
+ * purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is
+ * granted, provided the above notices are retained, and a notice that
+ * the code was modified is included with the above copyright notice.
+ */
+
#ifndef GC_CPP_H
#define GC_CPP_H
-/****************************************************************************
-Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
-THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
-Permission is hereby granted to use or copy this program for any
-purpose, provided the above notices are retained on all copies.
-Permission to modify the code and to distribute modified code is
-granted, provided the above notices are retained, and a notice that
-the code was modified is included with the above copyright notice.
-****************************************************************************
+/****************************************************************************
C++ Interface to the Boehm Collector
- John R. Ellis and Jesse Hull
+ John R. Ellis and Jesse Hull
This interface provides access to the Boehm collector. It provides
basic facilities similar to those described in "Safe, Efficient
@@ -34,7 +36,7 @@ Objects allocated with the built-in "::operator new" are uncollectable.
Objects derived from class "gc" are collectable. For example:
class A: public gc {...};
- A* a = new A; // a is collectable.
+ A* a = new A; // a is collectable.
Collectable instances of non-class types can be allocated using the GC
(or UseGC) placement:
@@ -48,6 +50,12 @@ using the NoGC placement:
class A: public gc {...};
A* a = new (NoGC) A; // a is uncollectable.
+The new(PointerFreeGC) syntax allows the allocation of collectable
+objects that are not scanned by the collector. This useful if you
+are allocating compressed data, bitmaps, or network packets. (In
+the latter case, it may remove danger of unfriendly network packets
+intentionally containing values that cause spurious memory retention.)
+
Both uncollectable and collectable objects can be explicitly deleted
with "delete", which invokes an object's destructors and frees its
storage immediately.
@@ -74,13 +82,14 @@ cycle, then that's considered a storage leak, and neither will be
collectable. See the interface gc.h for low-level facilities for
handling such cycles of objects with clean-up.
-The collector cannot guarrantee that it will find all inaccessible
+The collector cannot guarantee that it will find all inaccessible
objects. In practice, it finds almost all of them.
Cautions:
-1. Be sure the collector has been augmented with "make c++".
+1. Be sure the collector has been augmented with "make c++" or
+"--enable-cplusplus".
2. If your compiler supports the new "operator new[]" syntax, then
add -DGC_OPERATOR_NEW_ARRAY to the Makefile.
@@ -111,7 +120,7 @@ clean-up function:
that preserves the correct exception semantics requires a language
extension, e.g. the "gc" keyword.)
-4. Compiler bugs:
+4. Compiler bugs (now hopefully history):
* Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
destructors of classes derived from gc_cleanup won't be invoked.
@@ -133,8 +142,14 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
#include "gc.h"
+#ifdef GC_NAMESPACE
+# define GC_NS_QUALIFY(T) boehmgc::T
+#else
+# define GC_NS_QUALIFY(T) T
+#endif
+
#ifndef THINK_CPLUS
-# define GC_cdecl
+# define GC_cdecl GC_CALLBACK
#else
# define GC_cdecl _cdecl
#endif
@@ -142,9 +157,10 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
#if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \
&& !defined(_ENABLE_ARRAYNEW) /* Digimars */ \
&& (defined(__BORLANDC__) && (__BORLANDC__ < 0x450) \
- || (defined(__GNUC__) && \
- (__GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 6)) \
- || (defined(__WATCOMC__) && __WATCOMC__ < 1050))
+ || (defined(__GNUC__) && \
+ (__GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 6)) \
+ || (defined(_MSC_VER) && _MSC_VER <= 1020) \
+ || (defined(__WATCOMC__) && __WATCOMC__ < 1050))
# define GC_NO_OPERATOR_NEW_ARRAY
#endif
@@ -152,25 +168,37 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
# define GC_OPERATOR_NEW_ARRAY
#endif
-#if ! defined ( __BORLANDC__ ) /* Confuses the Borland compiler. */ \
- && ! defined ( __sgi )
+#if (!defined(__BORLANDC__) || __BORLANDC__ > 0x0620) \
+ && ! defined ( __sgi ) && ! defined( __WATCOMC__ ) \
+ && (!defined(_MSC_VER) || _MSC_VER > 1020)
# define GC_PLACEMENT_DELETE
#endif
-enum GCPlacement {UseGC,
-#ifndef GC_NAME_CONFLICT
- GC=UseGC,
+#ifdef GC_NAMESPACE
+namespace boehmgc
+{
#endif
- NoGC, PointerFreeGC};
-class gc {public:
+enum GCPlacement {
+ UseGC,
+# ifndef GC_NAME_CONFLICT
+ GC=UseGC,
+# endif
+ NoGC,
+ PointerFreeGC
+};
+
+class gc {
+ public:
inline void* operator new( size_t size );
inline void* operator new( size_t size, GCPlacement gcp );
inline void* operator new( size_t size, void *p );
- /* Must be redefined here, since the other overloadings */
- /* hide the global definition. */
+ /* 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
@@ -180,20 +208,23 @@ class gc {public:
inline void* operator new[]( size_t size, void *p );
inline void operator delete[]( void* obj );
# ifdef GC_PLACEMENT_DELETE
- inline void gc::operator delete[]( void*, void* );
+ inline void operator delete[]( void*, GCPlacement );
+ inline void operator delete[]( void*, void* );
# endif
#endif /* GC_OPERATOR_NEW_ARRAY */
- };
+};
/*
- Instances of classes derived from "gc" will be allocated in the
+ Instances of classes derived from "gc" will be allocated in the
collected heap by default, unless an explicit NoGC placement is
specified. */
-class gc_cleanup: virtual public gc {public:
+class gc_cleanup: virtual public gc {
+ public:
inline gc_cleanup();
inline virtual ~gc_cleanup();
private:
- inline static void GC_cdecl cleanup( void* obj, void* clientData );};
+ inline static void GC_cdecl cleanup( void* obj, void* clientData );
+};
/*
Instances of classes derived from "gc_cleanup" will be allocated
in the collected heap by default. When the collector discovers an
@@ -201,7 +232,13 @@ private:
member derived from "gc_cleanup", its destructors will be
invoked. */
-extern "C" {typedef void (*GCCleanUpFunc)( void* obj, void* clientData );}
+extern "C" {
+ typedef void (GC_CALLBACK * GCCleanUpFunc)( void* obj, void* clientData );
+}
+
+#ifdef GC_NAMESPACE
+}
+#endif
#ifdef _MSC_VER
// Disable warning that "no matching operator delete found; memory will
@@ -209,11 +246,9 @@ extern "C" {typedef void (*GCCleanUpFunc)( void* obj, void* clientData );}
# pragma warning(disable:4291)
#endif
-inline void* operator new(
- size_t size,
- GCPlacement gcp,
- GCCleanUpFunc cleanup = 0,
- void* clientData = 0 );
+inline void* operator new( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
+ GC_NS_QUALIFY(GCCleanUpFunc) cleanup = 0,
+ void* clientData = 0 );
/*
Allocates a collectable or uncollected object, according to the
value of "gcp".
@@ -228,40 +263,36 @@ 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*, GC_NS_QUALIFY(GCPlacement),
+ GC_NS_QUALIFY(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
- * including this everywhere.
+ * There seems to be no way to redirect new in this environment without
+ * including this everywhere.
*/
- void *operator new[]( size_t size );
-
- void operator delete[](void* obj);
+# if _MSC_VER > 1020
+ void *operator new[]( size_t size );
+ void operator delete[]( void* obj );
+# endif
- void* operator new( size_t size);
+ void* operator new( size_t size );
+ void operator delete( void* obj );
- void operator delete(void* obj);
-
- // This new operator is used by VC++ in case of Debug builds !
- void* operator new( size_t size,
- int ,//nBlockUse,
- const char * szFileName,
- int nLine );
+ // This new operator is used by VC++ in case of Debug builds !
+ void* operator new( size_t size, int /* nBlockUse */,
+ const char * szFileName, int nLine );
#endif /* _MSC_VER */
-
#ifdef GC_OPERATOR_NEW_ARRAY
-
-inline void* operator new[](
- size_t size,
- GCPlacement gcp,
- GCCleanUpFunc cleanup = 0,
- void* clientData = 0 );
- /*
- The operator new for arrays, identical to the above. */
-
+ inline void* operator new[]( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
+ GC_NS_QUALIFY(GCCleanUpFunc) cleanup = 0,
+ void* clientData = 0 );
+ /* The operator new for arrays, identical to the above. */
#endif /* GC_OPERATOR_NEW_ARRAY */
/****************************************************************************
@@ -270,53 +301,73 @@ Inline implementation
****************************************************************************/
+#ifdef GC_NAMESPACE
+namespace boehmgc
+{
+#endif
+
inline void* gc::operator new( size_t size ) {
- return GC_MALLOC( size );}
-
+ return GC_MALLOC( size );
+}
+
inline void* gc::operator new( size_t size, GCPlacement gcp ) {
- if (gcp == UseGC)
+ if (gcp == UseGC)
return GC_MALLOC( size );
else if (gcp == PointerFreeGC)
- return GC_MALLOC_ATOMIC( size );
+ return GC_MALLOC_ATOMIC( size );
else
- return GC_MALLOC_UNCOLLECTABLE( size );}
+ return GC_MALLOC_UNCOLLECTABLE( size );
+}
-inline void* gc::operator new( size_t size, void *p ) {
- return p;}
+inline void* gc::operator new( size_t /* size */, void *p ) {
+ return p;
+}
inline void gc::operator delete( void* obj ) {
- GC_FREE( obj );}
-
+ GC_FREE( 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
+ inline void* gc::operator new[]( size_t size ) {
+ return gc::operator new( size );
+ }
-inline void* gc::operator new[]( size_t size ) {
- return gc::operator new( size );}
-
-inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
- return gc::operator new( size, gcp );}
+ inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
+ return gc::operator new( size, gcp );
+ }
-inline void* gc::operator new[]( size_t size, void *p ) {
- return p;}
+ inline void* gc::operator new[]( size_t /* size */, void *p ) {
+ return p;
+ }
-inline void gc::operator delete[]( void* obj ) {
- gc::operator delete( obj );}
+ inline void gc::operator delete[]( void* obj ) {
+ gc::operator delete( obj );
+ }
-#ifdef GC_PLACEMENT_DELETE
- inline void gc::operator delete[]( void*, void* ) {}
-#endif
-
-#endif /* GC_OPERATOR_NEW_ARRAY */
+# 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 */
inline gc_cleanup::~gc_cleanup() {
- GC_register_finalizer_ignore_self( GC_base(this), 0, 0, 0, 0 );}
+ GC_register_finalizer_ignore_self( GC_base(this), 0, 0, 0, 0 );
+}
-inline void gc_cleanup::cleanup( void* obj, void* displ ) {
- ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
+inline void GC_CALLBACK gc_cleanup::cleanup( void* obj, void* displ ) {
+ ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();
+}
inline gc_cleanup::gc_cleanup() {
GC_finalization_proc oldProc;
@@ -324,44 +375,62 @@ inline gc_cleanup::gc_cleanup() {
void* base = GC_base( (void *) this );
if (0 != base) {
// Don't call the debug version, since this is a real base address.
- GC_register_finalizer_ignore_self(
- base, (GC_finalization_proc)cleanup, (void*) ((char*) this - (char*) base),
- &oldProc, &oldData );
+ GC_register_finalizer_ignore_self( base, (GC_finalization_proc)cleanup,
+ (void*)((char*)this - (char*)base),
+ &oldProc, &oldData );
if (0 != oldProc) {
- GC_register_finalizer_ignore_self( base, oldProc, oldData, 0, 0 );}}}
+ GC_register_finalizer_ignore_self( base, oldProc, oldData, 0, 0 );
+ }
+ }
+}
-inline void* operator new(
- size_t size,
- GCPlacement gcp,
- GCCleanUpFunc cleanup,
- void* clientData )
+#ifdef GC_NAMESPACE
+}
+#endif
+
+inline void* operator new( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
+ GC_NS_QUALIFY(GCCleanUpFunc) cleanup,
+ void* clientData )
{
void* obj;
- if (gcp == UseGC) {
+ if (gcp == GC_NS_QUALIFY(UseGC)) {
obj = GC_MALLOC( size );
- if (cleanup != 0)
- GC_REGISTER_FINALIZER_IGNORE_SELF(
- obj, cleanup, clientData, 0, 0 );}
- else if (gcp == PointerFreeGC) {
- obj = GC_MALLOC_ATOMIC( size );}
- else {
- obj = GC_MALLOC_UNCOLLECTABLE( size );};
- return obj;}
-
+ if (cleanup != 0)
+ GC_REGISTER_FINALIZER_IGNORE_SELF( obj, cleanup, clientData,
+ 0, 0 );
+ } else if (gcp == GC_NS_QUALIFY(PointerFreeGC)) {
+ obj = GC_MALLOC_ATOMIC( size );
+ } else {
+ obj = GC_MALLOC_UNCOLLECTABLE( size );
+ };
+ return obj;
+}
-#ifdef GC_OPERATOR_NEW_ARRAY
-
-inline void* operator new[](
- size_t size,
- GCPlacement gcp,
- GCCleanUpFunc cleanup,
- void* clientData )
-{
- return ::operator new( size, gcp, cleanup, clientData );}
+#ifdef GC_PLACEMENT_DELETE
+ inline void operator delete( void *p, GC_NS_QUALIFY(GCPlacement) /* gcp */,
+ GC_NS_QUALIFY(GCCleanUpFunc) /* cleanup */,
+ void* /* clientData */ )
+ {
+ GC_FREE(p);
+ }
+#endif /* GC_PLACEMENT_DELETE */
+#ifdef GC_OPERATOR_NEW_ARRAY
+ inline void* operator new[]( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
+ GC_NS_QUALIFY(GCCleanUpFunc) cleanup,
+ void* clientData )
+ {
+ return ::operator new( size, gcp, cleanup, clientData );
+ }
#endif /* GC_OPERATOR_NEW_ARRAY */
+#if defined(__CYGWIN__)
+# include <new> // for delete throw()
+ inline void operator delete(void *p)
+ {
+ GC_FREE(p);
+ }
+#endif
#endif /* GC_CPP_H */
-
diff --git a/boehm-gc/include/gc_disclaim.h b/boehm-gc/include/gc_disclaim.h
new file mode 100644
index 00000000000..3631e6e89e0
--- /dev/null
+++ b/boehm-gc/include/gc_disclaim.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2007-2011 by Hewlett-Packard Company. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+#ifndef GC_DISCLAIM_H
+#define GC_DISCLAIM_H
+
+#include "gc.h"
+
+/* This API is defined only if the library has been suitably compiled */
+/* (i.e. with ENABLE_DISCLAIM defined). */
+
+/* Prepare the object kind used by GC_finalized_malloc. Call it from */
+/* your initialization code or, at least, at some point before using */
+/* finalized allocations. The function is thread-safe. */
+GC_API void GC_CALL GC_init_finalized_malloc(void);
+
+/* Type of a disclaim call-back. */
+typedef int (GC_CALLBACK * GC_disclaim_proc)(void * /*obj*/);
+
+/* Register "proc" to be called on each object of "kind" ready to be */
+/* reclaimed. If "proc" returns non-zero, the collector will not */
+/* reclaim the object on this GC cycle. Objects reachable from "proc" */
+/* will be protected from collection if "mark_from_all" is non-zero, */
+/* but at the expense that long chains of objects will take many cycles */
+/* to reclaim. */
+GC_API void GC_CALL GC_register_disclaim_proc(int /*kind*/,
+ GC_disclaim_proc /*proc*/,
+ int /*mark_from_all*/);
+
+/* The finalizer closure used by GC_finalized_malloc. */
+struct GC_finalizer_closure {
+ GC_finalization_proc proc;
+ void *cd;
+};
+
+/* Allocate "size" bytes which is finalized by "fc". This uses a */
+/* dedicated object kind with a disclaim procedure, and is more */
+/* efficient than GC_register_finalizer and friends. */
+/* GC_init_finalized_malloc must be called before using this. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_finalized_malloc(size_t /*size*/,
+ const struct GC_finalizer_closure * /*fc*/);
+
+#endif
diff --git a/boehm-gc/include/gc_gcj.h b/boehm-gc/include/gc_gcj.h
index 5e79e27b821..eba714c64ea 100644
--- a/boehm-gc/include/gc_gcj.h
+++ b/boehm-gc/include/gc_gcj.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
* Copyright 1996-1999 by Silicon Graphics. All rights reserved.
@@ -14,8 +14,7 @@
* modified is included with the above copyright notice.
*/
-/* This file assumes the collector has been compiled with GC_GCJ_SUPPORT */
-/* and that an ANSI C compiler is available. */
+/* This file assumes the collector has been compiled with GC_GCJ_SUPPORT. */
/*
* We allocate objects whose first word contains a pointer to a struct
@@ -25,89 +24,87 @@
*/
#ifndef GC_GCJ_H
-
#define GC_GCJ_H
-#ifndef MARK_DESCR_OFFSET
-# define MARK_DESCR_OFFSET sizeof(word)
+ /* Gcj keeps GC descriptor as second word of vtable. This */
+ /* probably needs to be adjusted for other clients. */
+ /* We currently assume that this offset is such that: */
+ /* - all objects of this kind are large enough to have */
+ /* a value at that offset, and */
+ /* - it is not zero. */
+ /* These assumptions allow objects on the free list to be */
+ /* marked normally. */
+
+#ifndef GC_H
+# include "gc.h"
#endif
- /* Gcj keeps GC descriptor as second word of vtable. This */
- /* probably needs to be adjusted for other clients. */
- /* We currently assume that this offset is such that: */
- /* - all objects of this kind are large enough to have */
- /* a value at that offset, and */
- /* - it is not zero. */
- /* These assumptions allow objects on the free list to be */
- /* marked normally. */
-
-#ifndef _GC_H
-# include "gc.h"
+
+#ifdef __cplusplus
+ extern "C" {
#endif
-/* The following allocators signal an out of memory condition with */
-/* return GC_oom_fn(bytes); */
+/* The following allocators signal an out of memory condition with */
+/* return GC_oom_fn(bytes); */
-/* The following function must be called before the gcj allocators */
-/* can be invoked. */
-/* mp_index and mp are the index and mark_proc (see gc_mark.h) */
-/* respectively for the allocated objects. Mark_proc will be */
-/* used to build the descriptor for objects allocated through the */
-/* debugging interface. The mark_proc will be invoked on all such */
-/* objects with an "environment" value of 1. The client may choose */
+/* The following function must be called before the gcj allocators */
+/* can be invoked. */
+/* mp_index and mp are the index and mark_proc (see gc_mark.h) */
+/* respectively for the allocated objects. Mark_proc will be */
+/* used to build the descriptor for objects allocated through the */
+/* debugging interface. The mark_proc will be invoked on all such */
+/* objects with an "environment" value of 1. The client may choose */
/* to use the same mark_proc for some of its generated mark descriptors.*/
-/* In that case, it should use a different "environment" value to */
-/* detect the presence or absence of the debug header. */
-/* Mp is really of type mark_proc, as defined in gc_mark.h. We don't */
-/* want to include that here for namespace pollution reasons. */
-extern void GC_init_gcj_malloc(int mp_index, void * /* really mark_proc */mp);
-
-/* Allocate an object, clear it, and store the pointer to the */
-/* type structure (vtable in gcj). */
+/* In that case, it should use a different "environment" value to */
+/* detect the presence or absence of the debug header. */
+/* Mp is really of type mark_proc, as defined in gc_mark.h. We don't */
+/* want to include that here for namespace pollution reasons. */
+/* Passing in mp_index here instead of having GC_init_gcj_malloc() */
+/* internally call GC_new_proc() is quite ugly, but in typical usage */
+/* scenarios a compiler also has to know about mp_index, so */
+/* generating it dynamically is not acceptable. Mp_index will */
+/* typically be an integer < RESERVED_MARK_PROCS, so that it doesn't */
+/* collide with GC_new_proc allocated indices. If the application */
+/* needs no other reserved indices, zero */
+/* (GC_GCJ_RESERVED_MARK_PROC_INDEX in gc_mark.h) is an obvious choice. */
+GC_API void GC_CALL GC_init_gcj_malloc(int /* mp_index */,
+ void * /* really mark_proc */ /* mp */);
+
+/* Allocate an object, clear it, and store the pointer to the */
+/* type structure (vtable in gcj). */
/* This adds a byte at the end of the object if GC_malloc would.*/
-extern void * GC_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr);
-/* The debug versions allocate such that the specified mark_proc */
-/* is always invoked. */
-extern void * GC_debug_gcj_malloc(size_t lb,
- void * ptr_to_struct_containing_descr,
- GC_EXTRA_PARAMS);
-
-/* Similar to the above, but the size is in words, and we don't */
-/* adjust it. The size is assumed to be such that it can be */
-/* allocated as a small object. */
-/* Unless it is known that the collector is not configured */
-/* with USE_MARK_BYTES and unless it is known that the object */
-/* has weak alignment requirements, lw must be even. */
-extern void * GC_gcj_fast_malloc(size_t lw,
- void * ptr_to_struct_containing_descr);
-extern void * GC_debug_gcj_fast_malloc(size_t lw,
- void * ptr_to_struct_containing_descr,
- GC_EXTRA_PARAMS);
-
-/* Similar to GC_gcj_malloc, but assumes that a pointer to near the */
-/* beginning of the resulting object is always maintained. */
-extern void * GC_gcj_malloc_ignore_off_page(size_t lb,
- void * ptr_to_struct_containing_descr);
-
-/* The kind numbers of normal and debug gcj objects. */
-/* Useful only for debug support, we hope. */
-extern int GC_gcj_kind;
-
-extern int GC_gcj_debug_kind;
-
-# if defined(GC_LOCAL_ALLOC_H) && defined(GC_REDIRECT_TO_LOCAL)
- --> gc_local_alloc.h should be included after this. Otherwise
- --> we undo the redirection.
-# endif
-
-# ifdef GC_DEBUG
-# define GC_GCJ_MALLOC(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
-# define GC_GCJ_FAST_MALLOC(s,d) GC_debug_gcj_fast_malloc(s,d,GC_EXTRAS)
-# define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
-# else
-# define GC_GCJ_MALLOC(s,d) GC_gcj_malloc(s,d)
-# define GC_GCJ_FAST_MALLOC(s,d) GC_gcj_fast_malloc(s,d)
-# define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) \
- GC_gcj_malloc_ignore_off_page(s,d)
-# endif
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_gcj_malloc(size_t /* lb */,
+ void * /* ptr_to_struct_containing_descr */);
+
+/* The debug versions allocate such that the specified mark_proc */
+/* is always invoked. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_debug_gcj_malloc(size_t /* lb */,
+ void * /* ptr_to_struct_containing_descr */,
+ GC_EXTRA_PARAMS);
+
+/* Similar to GC_gcj_malloc, but assumes that a pointer to near the */
+/* beginning of the resulting object is always maintained. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_gcj_malloc_ignore_off_page(size_t /* lb */,
+ void * /* ptr_to_struct_containing_descr */);
+
+/* The kind numbers of normal and debug gcj objects. */
+/* Useful only for debug support, we hope. */
+GC_API int GC_gcj_kind;
+
+GC_API int GC_gcj_debug_kind;
+
+#ifdef GC_DEBUG
+# define GC_GCJ_MALLOC(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
+# define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
+#else
+# define GC_GCJ_MALLOC(s,d) GC_gcj_malloc(s,d)
+# define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) GC_gcj_malloc_ignore_off_page(s,d)
+#endif
+
+#ifdef __cplusplus
+ } /* end of extern "C" */
+#endif
#endif /* GC_GCJ_H */
diff --git a/boehm-gc/include/gc_inl.h b/boehm-gc/include/gc_inl.h
deleted file mode 100644
index c535cfd73fc..00000000000
--- a/boehm-gc/include/gc_inl.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
- * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/* Boehm, October 3, 1995 2:07 pm PDT */
-
-# ifndef GC_PRIVATE_H
-# include "private/gc_priv.h"
-# endif
-
-/* USE OF THIS FILE IS NOT RECOMMENDED unless GC_all_interior_pointers */
-/* is always set, or the collector has been built with */
-/* -DDONT_ADD_BYTE_AT_END, or the specified size includes a pointerfree */
-/* word at the end. In the standard collector configuration, */
-/* the final word of each object may not be scanned. */
-/* This iinterface is most useful for compilers that generate C. */
-/* Manual use is hereby discouraged. */
-
-/* Allocate n words (NOT BYTES). X is made to point to the result. */
-/* It is assumed that n < MAXOBJSZ, and */
-/* that n > 0. On machines requiring double word alignment of some */
-/* data, we also assume that n is 1 or even. */
-/* If the collector is built with -DUSE_MARK_BYTES or -DPARALLEL_MARK, */
-/* the n = 1 case is also disallowed. */
-/* Effectively this means that portable code should make sure n is even.*/
-/* This bypasses the */
-/* MERGE_SIZES mechanism. In order to minimize the number of distinct */
-/* free lists that are maintained, the caller should ensure that a */
-/* small number of distinct values of n are used. (The MERGE_SIZES */
-/* mechanism normally does this by ensuring that only the leading three */
-/* bits of n may be nonzero. See misc.c for details.) We really */
-/* recommend this only in cases in which n is a constant, and no */
-/* locking is required. */
-/* In that case it may allow the compiler to perform substantial */
-/* additional optimizations. */
-# define GC_MALLOC_WORDS(result,n) \
-{ \
- register ptr_t op; \
- register ptr_t *opp; \
- DCL_LOCK_STATE; \
- \
- opp = &(GC_objfreelist[n]); \
- FASTLOCK(); \
- if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) { \
- FASTUNLOCK(); \
- (result) = GC_generic_malloc_words_small((n), NORMAL); \
- } else { \
- *opp = obj_link(op); \
- obj_link(op) = 0; \
- GC_words_allocd += (n); \
- FASTUNLOCK(); \
- (result) = (GC_PTR) op; \
- } \
-}
-
-
-/* The same for atomic objects: */
-# define GC_MALLOC_ATOMIC_WORDS(result,n) \
-{ \
- register ptr_t op; \
- register ptr_t *opp; \
- DCL_LOCK_STATE; \
- \
- opp = &(GC_aobjfreelist[n]); \
- FASTLOCK(); \
- if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) { \
- FASTUNLOCK(); \
- (result) = GC_generic_malloc_words_small((n), PTRFREE); \
- } else { \
- *opp = obj_link(op); \
- obj_link(op) = 0; \
- GC_words_allocd += (n); \
- FASTUNLOCK(); \
- (result) = (GC_PTR) op; \
- } \
-}
-
-/* And once more for two word initialized objects: */
-# define GC_CONS(result, first, second) \
-{ \
- register ptr_t op; \
- register ptr_t *opp; \
- DCL_LOCK_STATE; \
- \
- opp = &(GC_objfreelist[2]); \
- FASTLOCK(); \
- if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) { \
- FASTUNLOCK(); \
- op = GC_generic_malloc_words_small(2, NORMAL); \
- } else { \
- *opp = obj_link(op); \
- GC_words_allocd += 2; \
- FASTUNLOCK(); \
- } \
- ((word *)op)[0] = (word)(first); \
- ((word *)op)[1] = (word)(second); \
- (result) = (GC_PTR) op; \
-}
diff --git a/boehm-gc/include/gc_inline.h b/boehm-gc/include/gc_inline.h
index db62d1d58a8..cc49da22864 100644
--- a/boehm-gc/include/gc_inline.h
+++ b/boehm-gc/include/gc_inline.h
@@ -1 +1,146 @@
-# include "gc_inl.h"
+/*
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef GC_INLINE_H
+#define GC_INLINE_H
+
+/* WARNING: */
+/* Note that for these routines, it is the clients responsibility to */
+/* add the extra byte at the end to deal with one-past-the-end pointers.*/
+/* In the standard collector configuration, the collector assumes that */
+/* such a byte has been added, and hence does not trace the last word */
+/* in the resulting object. */
+/* This is not an issue if the collector is compiled with */
+/* DONT_ADD_BYTE_AT_END, or if GC_all_interior_pointers is not set. */
+/* This interface is most useful for compilers that generate C. */
+/* It is also used internally for thread-local allocation. */
+/* Manual use is hereby discouraged. */
+
+#include "gc.h"
+#include "gc_tiny_fl.h"
+
+#if __GNUC__ >= 3
+# define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome)
+ /* Equivalent to (expr), but predict that usually (expr)==outcome. */
+#else
+# define GC_EXPECT(expr, outcome) (expr)
+#endif /* __GNUC__ */
+
+#ifndef GC_ASSERT
+# define GC_ASSERT(expr) /* empty */
+#endif
+
+/* Store a pointer to a list of newly allocated objects of kind k and */
+/* size lb in *result. The caller must make sure that *result is */
+/* traced even if objects are ptrfree. */
+GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
+ void ** /* result */);
+
+/* The ultimately general inline allocation macro. Allocate an object */
+/* 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. */
+/* If num_direct is nonzero, and the individual free list pointers */
+/* are initialized to (void *)1, then we allocate numdirect granules */
+/* directly using gmalloc before putting multiple objects into the */
+/* tiny_fl entry. If num_direct is zero, then the free lists may also */
+/* be initialized to (void *)0. */
+/* Note that we use the zeroth free list to hold objects 1 granule in */
+/* size that are used to satisfy size 0 allocation requests. */
+/* We rely on much of this hopefully getting optimized away in the */
+/* num_direct = 0 case. */
+/* 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) \
+{ \
+ if (GC_EXPECT((granules) >= GC_TINY_FREELISTS,0)) { \
+ result = (default_expr); \
+ } else { \
+ void **my_fl = (tiny_fl) + (granules); \
+ void *my_entry=*my_fl; \
+ void *next; \
+ \
+ while (GC_EXPECT((GC_word)my_entry \
+ <= (num_direct) + GC_TINY_FREELISTS + 1, 0)) { \
+ /* Entry contains counter or NULL */ \
+ if ((GC_word)my_entry - 1 < (num_direct)) { \
+ /* Small counter value, not NULL */ \
+ *my_fl = (char *)my_entry + (granules) + 1; \
+ result = (default_expr); \
+ goto out; \
+ } else { \
+ /* Large counter or NULL */ \
+ GC_generic_malloc_many(((granules) == 0? GC_GRANULE_BYTES : \
+ GC_RAW_BYTES_FROM_INDEX(granules)), \
+ kind, my_fl); \
+ my_entry = *my_fl; \
+ if (my_entry == 0) { \
+ result = (*GC_get_oom_fn())((granules)*GC_GRANULE_BYTES); \
+ goto out; \
+ } \
+ } \
+ } \
+ next = *(void **)(my_entry); \
+ result = (void *)my_entry; \
+ *my_fl = next; \
+ init; \
+ PREFETCH_FOR_WRITE(next); \
+ GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
+ GC_ASSERT((kind) == PTRFREE || ((GC_word *)result)[1] == 0); \
+ out: ; \
+ } \
+}
+
+# define GC_WORDS_TO_WHOLE_GRANULES(n) \
+ GC_WORDS_TO_GRANULES((n) + GC_GRANULE_WORDS - 1)
+
+/* Allocate n words (NOT BYTES). X is made to point to the result. */
+/* This should really only be used if GC_all_interior_pointers is */
+/* not set, or DONT_ADD_BYTE_AT_END is set. See above. */
+/* The semantics changed in version 7.0; we no longer lock, and */
+/* the caller is responsible for supplying a cleared tiny_fl */
+/* free list array. For single-threaded applications, this may be */
+/* a global array. */
+# define GC_MALLOC_WORDS(result,n,tiny_fl) \
+{ \
+ size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
+ GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
+ NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
+ *(void **)(result) = 0); \
+}
+
+# define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
+{ \
+ size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
+ GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
+ PTRFREE, GC_malloc_atomic(grans*GC_GRANULE_BYTES), \
+ (void)0 /* no initialization */); \
+}
+
+/* And once more for two word initialized objects: */
+# define GC_CONS(result, first, second, tiny_fl) \
+{ \
+ size_t grans = GC_WORDS_TO_WHOLE_GRANULES(2); \
+ GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, \
+ NORMAL, GC_malloc(grans*GC_GRANULE_BYTES), \
+ *(void **)(result) = (void *)(first)); \
+ ((void **)(result))[1] = (void *)(second); \
+}
+
+#endif /* !GC_INLINE_H */
diff --git a/boehm-gc/include/gc_local_alloc.h b/boehm-gc/include/gc_local_alloc.h
deleted file mode 100644
index 1874c7b6d20..00000000000
--- a/boehm-gc/include/gc_local_alloc.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2000 by Hewlett-Packard Company. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-
-/*
- * Interface for thread local allocation. Memory obtained
- * this way can be used by all threads, as though it were obtained
- * from an allocator like GC_malloc. The difference is that GC_local_malloc
- * counts the number of allocations of a given size from the current thread,
- * and uses GC_malloc_many to perform the allocations once a threashold
- * is exceeded. Thus far less synchronization may be needed.
- * Allocation of known large objects should not use this interface.
- * This interface is designed primarily for fast allocation of small
- * objects on multiprocessors, e.g. for a JVM running on an MP server.
- *
- * If this file is included with GC_GCJ_SUPPORT defined, GCJ-style
- * bitmap allocation primitives will also be included.
- *
- * If this file is included with GC_REDIRECT_TO_LOCAL defined, then
- * GC_MALLOC, GC_MALLOC_ATOMIC, and possibly GC_GCJ_MALLOC will
- * be redefined to use the thread local allocatoor.
- *
- * The interface is available only if the collector is built with
- * -DTHREAD_LOCAL_ALLOC, which is currently supported only on Linux.
- *
- * The debugging allocators use standard, not thread-local allocation.
- *
- * These routines normally require an explicit call to GC_init(), though
- * that may be done from a constructor function.
- */
-
-#ifndef GC_LOCAL_ALLOC_H
-#define GC_LOCAL_ALLOC_H
-
-#ifndef _GC_H
-# include "gc.h"
-#endif
-
-#if defined(GC_GCJ_SUPPORT) && !defined(GC_GCJ_H)
-# include "gc_gcj.h"
-#endif
-
-/* We assume ANSI C for this interface. */
-
-GC_PTR GC_local_malloc(size_t bytes);
-
-GC_PTR GC_local_malloc_atomic(size_t bytes);
-
-#if defined(GC_GCJ_SUPPORT)
- GC_PTR GC_local_gcj_malloc(size_t bytes,
- void * ptr_to_struct_containing_descr);
-#endif
-
-# ifdef GC_DEBUG
- /* We don't really use local allocation in this case. */
-# define GC_LOCAL_MALLOC(s) GC_debug_malloc(s,GC_EXTRAS)
-# define GC_LOCAL_MALLOC_ATOMIC(s) GC_debug_malloc_atomic(s,GC_EXTRAS)
-# ifdef GC_GCJ_SUPPORT
-# define GC_LOCAL_GCJ_MALLOC(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
-# endif
-# else
-# define GC_LOCAL_MALLOC(s) GC_local_malloc(s)
-# define GC_LOCAL_MALLOC_ATOMIC(s) GC_local_malloc_atomic(s)
-# ifdef GC_GCJ_SUPPORT
-# define GC_LOCAL_GCJ_MALLOC(s,d) GC_local_gcj_malloc(s,d)
-# endif
-# endif
-
-# ifdef GC_REDIRECT_TO_LOCAL
-# undef GC_MALLOC
-# define GC_MALLOC(s) GC_LOCAL_MALLOC(s)
-# undef GC_MALLOC_ATOMIC
-# define GC_MALLOC_ATOMIC(s) GC_LOCAL_MALLOC_ATOMIC(s)
-# ifdef GC_GCJ_SUPPORT
-# undef GC_GCJ_MALLOC
-# define GC_GCJ_MALLOC(s,d) GC_LOCAL_GCJ_MALLOC(s,d)
-# endif
-# endif
-
-#endif /* GC_LOCAL_ALLOC_H */
diff --git a/boehm-gc/include/gc_mark.h b/boehm-gc/include/gc_mark.h
index 953bb74dc08..508fb2cc3b0 100644
--- a/boehm-gc/include/gc_mark.h
+++ b/boehm-gc/include/gc_mark.h
@@ -18,186 +18,241 @@
* clients that provide detailed heap layout information to the collector.
* This interface should not be used by normal C or C++ clients.
* It will be useful to runtimes for other languages.
- *
+ *
* This is an experts-only interface! There are many ways to break the
* collector in subtle ways by using this functionality.
*/
#ifndef GC_MARK_H
-# define GC_MARK_H
-
-# ifndef GC_H
-# include "gc.h"
-# endif
-
-/* A client supplied mark procedure. Returns new mark stack pointer. */
-/* Primary effect should be to push new entries on the mark stack. */
-/* Mark stack pointer values are passed and returned explicitly. */
-/* Global variables decribing mark stack are not necessarily valid. */
-/* (This usually saves a few cycles by keeping things in registers.) */
-/* Assumed to scan about GC_PROC_BYTES on average. If it needs to do */
-/* much more work than that, it should do it in smaller pieces by */
-/* pushing itself back on the mark stack. */
-/* Note that it should always do some work (defined as marking some */
-/* objects) before pushing more than one entry on the mark stack. */
-/* This is required to ensure termination in the event of mark stack */
-/* overflows. */
+#define GC_MARK_H
+
+#ifndef GC_H
+# include "gc.h"
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* A client supplied mark procedure. Returns new mark stack pointer. */
+/* Primary effect should be to push new entries on the mark stack. */
+/* Mark stack pointer values are passed and returned explicitly. */
+/* Global variables describing mark stack are not necessarily valid. */
+/* (This usually saves a few cycles by keeping things in registers.) */
+/* Assumed to scan about GC_PROC_BYTES on average. If it needs to do */
+/* much more work than that, it should do it in smaller pieces by */
+/* pushing itself back on the mark stack. */
+/* Note that it should always do some work (defined as marking some */
+/* objects) before pushing more than one entry on the mark stack. */
+/* This is required to ensure termination in the event of mark stack */
+/* overflows. */
/* This procedure is always called with at least one empty entry on the */
-/* mark stack. */
-/* Currently we require that mark procedures look for pointers in a */
-/* subset of the places the conservative marker would. It must be safe */
-/* to invoke the normal mark procedure instead. */
+/* mark stack. */
+/* Currently we require that mark procedures look for pointers in a */
+/* subset of the places the conservative marker would. It must be safe */
+/* to invoke the normal mark procedure instead. */
/* WARNING: Such a mark procedure may be invoked on an unused object */
-/* residing on a free list. Such objects are cleared, except for a */
-/* free list link field in the first word. Thus mark procedures may */
-/* not count on the presence of a type descriptor, and must handle this */
-/* case correctly somehow. */
-# define GC_PROC_BYTES 100
-struct GC_ms_entry;
-typedef struct GC_ms_entry * (*GC_mark_proc) GC_PROTO((
- GC_word * addr, struct GC_ms_entry * mark_stack_ptr,
- struct GC_ms_entry * mark_stack_limit, GC_word env));
-
-# define GC_LOG_MAX_MARK_PROCS 6
-# define GC_MAX_MARK_PROCS (1 << GC_LOG_MAX_MARK_PROCS)
-
-/* In a few cases it's necessary to assign statically known indices to */
-/* certain mark procs. Thus we reserve a few for well known clients. */
-/* (This is necessary if mark descriptors are compiler generated.) */
+/* residing on a free list. Such objects are cleared, except for a */
+/* free list link field in the first word. Thus mark procedures may */
+/* not count on the presence of a type descriptor, and must handle this */
+/* case correctly somehow. */
+#define GC_PROC_BYTES 100
+
+#ifdef GC_BUILD
+ struct GC_ms_entry;
+#else
+ struct GC_ms_entry { void *opaque; };
+#endif
+typedef struct GC_ms_entry * (*GC_mark_proc)(GC_word * /* addr */,
+ struct GC_ms_entry * /* mark_stack_ptr */,
+ struct GC_ms_entry * /* mark_stack_limit */,
+ GC_word /* env */);
+
+#define GC_LOG_MAX_MARK_PROCS 6
+#define GC_MAX_MARK_PROCS (1 << GC_LOG_MAX_MARK_PROCS)
+
+/* In a few cases it's necessary to assign statically known indices to */
+/* certain mark procs. Thus we reserve a few for well known clients. */
+/* (This is necessary if mark descriptors are compiler generated.) */
#define GC_RESERVED_MARK_PROCS 8
-# define GC_GCJ_RESERVED_MARK_PROC_INDEX 0
+#define GC_GCJ_RESERVED_MARK_PROC_INDEX 0
-/* Object descriptors on mark stack or in objects. Low order two */
-/* bits are tags distinguishing among the following 4 possibilities */
-/* for the high order 30 bits. */
+/* Object descriptors on mark stack or in objects. Low order two */
+/* bits are tags distinguishing among the following 4 possibilities */
+/* for the high order 30 bits. */
#define GC_DS_TAG_BITS 2
#define GC_DS_TAGS ((1 << GC_DS_TAG_BITS) - 1)
-#define GC_DS_LENGTH 0 /* The entire word is a length in bytes that */
- /* must be a multiple of 4. */
-#define GC_DS_BITMAP 1 /* 30 (62) bits are a bitmap describing pointer */
- /* fields. The msb is 1 iff the first word */
- /* is a pointer. */
- /* (This unconventional ordering sometimes */
- /* makes the marker slightly faster.) */
- /* Zeroes indicate definite nonpointers. Ones */
- /* indicate possible pointers. */
- /* Only usable if pointers are word aligned. */
+#define GC_DS_LENGTH 0 /* The entire word is a length in bytes that */
+ /* must be a multiple of 4. */
+#define GC_DS_BITMAP 1 /* 30 (62) bits are a bitmap describing pointer */
+ /* fields. The msb is 1 if the first word */
+ /* is a pointer. */
+ /* (This unconventional ordering sometimes */
+ /* makes the marker slightly faster.) */
+ /* Zeroes indicate definite nonpointers. Ones */
+ /* indicate possible pointers. */
+ /* Only usable if pointers are word aligned. */
#define GC_DS_PROC 2
- /* The objects referenced by this object can be */
- /* pushed on the mark stack by invoking */
- /* PROC(descr). ENV(descr) is passed as the */
- /* last argument. */
-# define GC_MAKE_PROC(proc_index, env) \
- (((((env) << GC_LOG_MAX_MARK_PROCS) \
- | (proc_index)) << GC_DS_TAG_BITS) | GC_DS_PROC)
-#define GC_DS_PER_OBJECT 3 /* The real descriptor is at the */
- /* byte displacement from the beginning of the */
- /* object given by descr & ~DS_TAGS */
- /* If the descriptor is negative, the real */
- /* descriptor is at (*<object_start>) - */
- /* (descr & ~DS_TAGS) - GC_INDIR_PER_OBJ_BIAS */
- /* The latter alternative can be used if each */
- /* object contains a type descriptor in the */
- /* first word. */
- /* Note that in multithreaded environments */
- /* per object descriptors maust be located in */
- /* either the first two or last two words of */
- /* the object, since only those are guaranteed */
- /* to be cleared while the allocation lock is */
- /* held. */
+ /* The objects referenced by this object can be */
+ /* pushed on the mark stack by invoking */
+ /* PROC(descr). ENV(descr) is passed as the */
+ /* last argument. */
+#define GC_MAKE_PROC(proc_index, env) \
+ (((((env) << GC_LOG_MAX_MARK_PROCS) \
+ | (proc_index)) << GC_DS_TAG_BITS) | GC_DS_PROC)
+#define GC_DS_PER_OBJECT 3 /* The real descriptor is at the */
+ /* byte displacement from the beginning of the */
+ /* object given by descr & ~DS_TAGS */
+ /* If the descriptor is negative, the real */
+ /* descriptor is at (*<object_start>) - */
+ /* (descr & ~DS_TAGS) - GC_INDIR_PER_OBJ_BIAS */
+ /* The latter alternative can be used if each */
+ /* object contains a type descriptor in the */
+ /* first word. */
+ /* Note that in multithreaded environments */
+ /* per object descriptors must be located in */
+ /* either the first two or last two words of */
+ /* the object, since only those are guaranteed */
+ /* to be cleared while the allocation lock is */
+ /* held. */
#define GC_INDIR_PER_OBJ_BIAS 0x10
-
-extern GC_PTR GC_least_plausible_heap_addr;
-extern GC_PTR GC_greatest_plausible_heap_addr;
- /* Bounds on the heap. Guaranteed valid */
- /* Likely to include future heap expansion. */
-
-/* Handle nested references in a custom mark procedure. */
-/* Check if obj is a valid object. If so, ensure that it is marked. */
-/* If it was not previously marked, push its contents onto the mark */
-/* stack for future scanning. The object will then be scanned using */
-/* its mark descriptor. */
-/* Returns the new mark stack pointer. */
-/* Handles mark stack overflows correctly. */
-/* Since this marks first, it makes progress even if there are mark */
-/* stack overflows. */
-/* Src is the address of the pointer to obj, which is used only */
-/* for back pointer-based heap debugging. */
-/* It is strongly recommended that most objects be handled without mark */
-/* procedures, e.g. with bitmap descriptors, and that mark procedures */
-/* be reserved for exceptional cases. That will ensure that */
-/* performance of this call is not extremely performance critical. */
-/* (Otherwise we would need to inline GC_mark_and_push completely, */
-/* which would tie the client code to a fixed collector version.) */
-/* Note that mark procedures should explicitly call FIXUP_POINTER() */
-/* if required. */
-struct GC_ms_entry *GC_mark_and_push
- GC_PROTO((GC_PTR obj,
- struct GC_ms_entry * mark_stack_ptr,
- struct GC_ms_entry * mark_stack_limit, GC_PTR *src));
+
+GC_API void * GC_least_plausible_heap_addr;
+GC_API void * GC_greatest_plausible_heap_addr;
+ /* Bounds on the heap. Guaranteed valid */
+ /* Likely to include future heap expansion. */
+ /* Hence usually includes not-yet-mapped */
+ /* memory. */
+
+/* Handle nested references in a custom mark procedure. */
+/* Check if obj is a valid object. If so, ensure that it is marked. */
+/* If it was not previously marked, push its contents onto the mark */
+/* stack for future scanning. The object will then be scanned using */
+/* its mark descriptor. */
+/* Returns the new mark stack pointer. */
+/* Handles mark stack overflows correctly. */
+/* Since this marks first, it makes progress even if there are mark */
+/* stack overflows. */
+/* Src is the address of the pointer to obj, which is used only */
+/* for back pointer-based heap debugging. */
+/* It is strongly recommended that most objects be handled without mark */
+/* procedures, e.g. with bitmap descriptors, and that mark procedures */
+/* be reserved for exceptional cases. That will ensure that */
+/* performance of this call is not extremely performance critical. */
+/* (Otherwise we would need to inline GC_mark_and_push completely, */
+/* which would tie the client code to a fixed collector version.) */
+/* Note that mark procedures should explicitly call FIXUP_POINTER() */
+/* if required. */
+GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void * /* obj */,
+ struct GC_ms_entry * /* mark_stack_ptr */,
+ struct GC_ms_entry * /* mark_stack_limit */,
+ void ** /* src */);
#define GC_MARK_AND_PUSH(obj, msp, lim, src) \
- (((GC_word)obj >= (GC_word)GC_least_plausible_heap_addr && \
- (GC_word)obj <= (GC_word)GC_greatest_plausible_heap_addr)? \
- GC_mark_and_push(obj, msp, lim, src) : \
- msp)
+ ((GC_word)(obj) >= (GC_word)GC_least_plausible_heap_addr && \
+ (GC_word)(obj) <= (GC_word)GC_greatest_plausible_heap_addr ? \
+ GC_mark_and_push(obj, msp, lim, src) : (msp))
-extern size_t GC_debug_header_size;
+GC_API size_t GC_debug_header_size;
/* The size of the header added to objects allocated through */
/* the GC_debug routines. */
/* Defined as a variable so that client mark procedures don't */
/* need to be recompiled for collector version changes. */
-#define GC_USR_PTR_FROM_BASE(p) ((GC_PTR)((char *)(p) + GC_debug_header_size))
+#define GC_USR_PTR_FROM_BASE(p) ((void *)((char *)(p) + GC_debug_header_size))
-/* And some routines to support creation of new "kinds", e.g. with */
-/* custom mark procedures, by language runtimes. */
-/* The _inner versions assume the caller holds the allocation lock. */
+/* And some routines to support creation of new "kinds", e.g. with */
+/* custom mark procedures, by language runtimes. */
+/* The _inner versions assume the caller holds the allocation lock. */
-/* Return a new free list array. */
-void ** GC_new_free_list GC_PROTO((void));
-void ** GC_new_free_list_inner GC_PROTO((void));
+/* Return a new free list array. */
+GC_API void ** GC_CALL GC_new_free_list(void);
+GC_API void ** GC_CALL GC_new_free_list_inner(void);
/* Return a new kind, as specified. */
-int GC_new_kind GC_PROTO((void **free_list, GC_word mark_descriptor_template,
- int add_size_to_descriptor, int clear_new_objects));
- /* The last two parameters must be zero or one. */
-int GC_new_kind_inner GC_PROTO((void **free_list,
- GC_word mark_descriptor_template,
- int add_size_to_descriptor,
- int clear_new_objects));
-
-/* Return a new mark procedure identifier, suitable for use as */
-/* the first argument in GC_MAKE_PROC. */
-int GC_new_proc GC_PROTO((GC_mark_proc));
-int GC_new_proc_inner GC_PROTO((GC_mark_proc));
-
-/* Allocate an object of a given kind. Note that in multithreaded */
-/* contexts, this is usually unsafe for kinds that have the descriptor */
-/* in the object itself, since there is otherwise a window in which */
-/* the descriptor is not correct. Even in the single-threaded case, */
-/* we need to be sure that cleared objects on a free list don't */
-/* cause a GC crash if they are accidentally traced. */
-/* ptr_t */char * GC_generic_malloc GC_PROTO((GC_word lb, int k));
-
-/* FIXME - Should return void *, but that requires other changes. */
-
-typedef void (*GC_describe_type_fn) GC_PROTO((void *p, char *out_buf));
- /* A procedure which */
- /* produces a human-readable */
- /* description of the "type" of object */
- /* p into the buffer out_buf of length */
- /* GC_TYPE_DESCR_LEN. This is used by */
- /* the debug support when printing */
- /* objects. */
- /* These functions should be as robust */
- /* as possible, though we do avoid */
- /* invoking them on objects on the */
- /* global free list. */
-# define GC_TYPE_DESCR_LEN 40
-
-void GC_register_describe_type_fn GC_PROTO((int kind, GC_describe_type_fn knd));
- /* Register a describe_type function */
- /* to be used when printing objects */
- /* of a particular kind. */
-
-#endif /* GC_MARK_H */
+GC_API unsigned GC_CALL GC_new_kind(void ** /* free_list */,
+ GC_word /* mark_descriptor_template */,
+ int /* add_size_to_descriptor */,
+ int /* clear_new_objects */) GC_ATTR_NONNULL(1);
+ /* The last two parameters must be zero or one. */
+GC_API unsigned GC_CALL GC_new_kind_inner(void ** /* free_list */,
+ GC_word /* mark_descriptor_template */,
+ int /* add_size_to_descriptor */,
+ int /* clear_new_objects */) GC_ATTR_NONNULL(1);
+
+/* Return a new mark procedure identifier, suitable for use as */
+/* the first argument in GC_MAKE_PROC. */
+GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc);
+GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc);
+
+/* Allocate an object of a given kind. Note that in multithreaded */
+/* contexts, this is usually unsafe for kinds that have the descriptor */
+/* in the object itself, since there is otherwise a window in which */
+/* the descriptor is not correct. Even in the single-threaded case, */
+/* we need to be sure that cleared objects on a free list don't */
+/* cause a GC crash if they are accidentally traced. */
+GC_API GC_ATTR_MALLOC void * GC_CALL
+ GC_generic_malloc(size_t /* lb */, int /* k */);
+
+typedef void (GC_CALLBACK * GC_describe_type_fn)(void * /* p */,
+ char * /* out_buf */);
+ /* A procedure which */
+ /* produces a human-readable */
+ /* description of the "type" of object */
+ /* p into the buffer out_buf of length */
+ /* GC_TYPE_DESCR_LEN. This is used by */
+ /* the debug support when printing */
+ /* objects. */
+ /* These functions should be as robust */
+ /* as possible, though we do avoid */
+ /* invoking them on objects on the */
+ /* global free list. */
+#define GC_TYPE_DESCR_LEN 40
+
+GC_API void GC_CALL GC_register_describe_type_fn(int /* kind */,
+ GC_describe_type_fn);
+ /* Register a describe_type function */
+ /* to be used when printing objects */
+ /* of a particular kind. */
+
+/* Clear some of the inaccessible part of the stack. Returns its */
+/* argument, so it can be used in a tail call position, hence clearing */
+/* another frame. Argument may be NULL. */
+GC_API void * GC_CALL GC_clear_stack(void *);
+
+/* Set and get the client notifier on collections. The client function */
+/* is called at the start of every full GC (called with the allocation */
+/* lock held). May be 0. This is a really tricky interface to use */
+/* correctly. Unless you really understand the collector internals, */
+/* the callback should not, directly or indirectly, make any GC_ or */
+/* potentially blocking calls. In particular, it is not safe to */
+/* allocate memory using the garbage collector from within the callback */
+/* function. Both the setter and getter acquire the GC lock. */
+typedef void (GC_CALLBACK * GC_start_callback_proc)(void);
+GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc);
+GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void);
+
+/* Slow/general mark bit manipulation. The caller must hold the */
+/* allocation lock. GC_is_marked returns 1 (TRUE) or 0. */
+GC_API int GC_CALL GC_is_marked(const void *) GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_clear_mark_bit(const void *) GC_ATTR_NONNULL(1);
+GC_API void GC_CALL GC_set_mark_bit(const void *) GC_ATTR_NONNULL(1);
+
+/* Push everything in the given range onto the mark stack. */
+/* (GC_push_conditional pushes either all or only dirty pages depending */
+/* on the third argument.) */
+GC_API void GC_CALL GC_push_all(char * /* bottom */, char * /* top */);
+GC_API void GC_CALL GC_push_conditional(char * /* bottom */, char * /* top */,
+ int /* bool all */);
+
+/* Set and get the client push-other-roots procedure. A client */
+/* supplied procedure should also call the original procedure. */
+/* Note that both the setter and getter require some external */
+/* synchronization to avoid data race. */
+typedef void (GC_CALLBACK * GC_push_other_roots_proc)(void);
+GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc);
+GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void);
+
+#ifdef __cplusplus
+ } /* end of extern "C" */
+#endif
+#endif /* GC_MARK_H */
diff --git a/boehm-gc/include/gc_pthread_redirects.h b/boehm-gc/include/gc_pthread_redirects.h
index 842518cfcc4..37cb249ac04 100644
--- a/boehm-gc/include/gc_pthread_redirects.h
+++ b/boehm-gc/include/gc_pthread_redirects.h
@@ -1,82 +1,95 @@
-/* Our pthread support normally needs to intercept a number of thread */
-/* calls. We arrange to do that here, if appropriate. */
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2010 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
-#ifndef GC_PTHREAD_REDIRECTS_H
+/* Our pthread support normally needs to intercept a number of thread */
+/* calls. We arrange to do that here, if appropriate. */
-#define GC_PTHREAD_REDIRECTS_H
+/* Included from gc.h only. Included only if GC_PTHREADS. */
+#if defined(GC_H) && defined(GC_PTHREADS)
-#if defined(GC_SOLARIS_THREADS)
-/* We need to intercept calls to many of the threads primitives, so */
-/* that we can locate thread stacks and stop the world. */
-/* Note also that the collector cannot see thread specific data. */
-/* Thread specific data should generally consist of pointers to */
-/* uncollectable objects (allocated with GC_malloc_uncollectable, */
-/* not the system malloc), which are deallocated using the destructor */
-/* facility in thr_keycreate. Alternatively, keep a redundant pointer */
-/* to thread specific data on the thread stack. */
-# include <thread.h>
- int GC_thr_create(void *stack_base, size_t stack_size,
- void *(*start_routine)(void *), void *arg, long flags,
- thread_t *new_thread);
- int GC_thr_join(thread_t wait_for, thread_t *departed, void **status);
- int GC_thr_suspend(thread_t target_thread);
- int GC_thr_continue(thread_t target_thread);
- void * GC_dlopen(const char *path, int mode);
-# define thr_create GC_thr_create
-# define thr_join GC_thr_join
-# define thr_suspend GC_thr_suspend
-# define thr_continue GC_thr_continue
-#endif /* GC_SOLARIS_THREADS */
+/* We need to intercept calls to many of the threads primitives, so */
+/* that we can locate thread stacks and stop the world. */
+/* Note also that the collector cannot always see thread specific data. */
+/* Thread specific data should generally consist of pointers to */
+/* uncollectable objects (allocated with GC_malloc_uncollectable, */
+/* not the system malloc), which are deallocated using the destructor */
+/* facility in thr_keycreate. Alternatively, keep a redundant pointer */
+/* to thread specific data on the thread stack. */
-#if defined(GC_SOLARIS_PTHREADS)
-# include <pthread.h>
+#include <pthread.h>
+
+#ifndef GC_NO_DLOPEN
+# include <dlfcn.h>
+ GC_API void *GC_dlopen(const char * /* path */, int /* mode */);
+#endif /* !GC_NO_DLOPEN */
+
+#ifndef GC_NO_PTHREAD_SIGMASK
# include <signal.h>
- extern int GC_pthread_create(pthread_t *new_thread,
- const pthread_attr_t *attr,
- void * (*thread_execp)(void *), void *arg);
- extern int GC_pthread_join(pthread_t wait_for, void **status);
-# define pthread_join GC_pthread_join
-# define pthread_create GC_pthread_create
-#endif
+ GC_API int GC_pthread_sigmask(int /* how */, const sigset_t *,
+ sigset_t * /* oset */);
+#endif /* !GC_NO_PTHREAD_SIGMASK */
-#if defined(GC_SOLARIS_PTHREADS) || defined(GC_SOLARIS_THREADS)
-# define dlopen GC_dlopen
-#endif /* SOLARIS_THREADS || SOLARIS_PTHREADS */
+#ifndef GC_PTHREAD_CREATE_CONST
+ /* This is used for pthread_create() only. */
+# define GC_PTHREAD_CREATE_CONST const
+#endif
+GC_API int GC_pthread_create(pthread_t *,
+ GC_PTHREAD_CREATE_CONST pthread_attr_t *,
+ void *(*)(void *), void * /* arg */);
+GC_API int GC_pthread_join(pthread_t, void ** /* retval */);
+GC_API int GC_pthread_detach(pthread_t);
-#if !defined(GC_USE_LD_WRAP) && defined(GC_PTHREADS) && !defined(GC_SOLARIS_PTHREADS)
-/* We treat these similarly. */
-# include <pthread.h>
-# include <signal.h>
+#ifndef GC_NO_PTHREAD_CANCEL
+ GC_API int GC_pthread_cancel(pthread_t);
+#endif
- int GC_pthread_create(pthread_t *new_thread,
- const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg);
-#ifndef GC_DARWIN_THREADS
- int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
+#if defined(GC_PTHREAD_EXIT_ATTRIBUTE) && !defined(GC_PTHREAD_EXIT_DECLARED)
+# define GC_PTHREAD_EXIT_DECLARED
+ GC_API void GC_pthread_exit(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
#endif
- int GC_pthread_join(pthread_t thread, void **retval);
- int GC_pthread_detach(pthread_t thread);
-#if defined(GC_OSF1_THREADS) \
- && defined(_PTHREAD_USE_MANGLED_NAMES_) && !defined(_PTHREAD_USE_PTDNAM_)
-/* Unless the compiler supports #pragma extern_prefix, the Tru64 UNIX
- <pthread.h> redefines some POSIX thread functions to use mangled names.
- If so, undef them before redefining. */
+#if !defined(GC_NO_THREAD_REDIRECTS) && !defined(GC_USE_LD_WRAP)
+ /* Unless the compiler supports #pragma extern_prefix, the Tru64 */
+ /* UNIX <pthread.h> redefines some POSIX thread functions to use */
+ /* mangled names. Anyway, it's safe to undef them before redefining. */
# undef pthread_create
# undef pthread_join
# undef pthread_detach
-#endif
-
# define pthread_create GC_pthread_create
# define pthread_join GC_pthread_join
# define pthread_detach GC_pthread_detach
-#ifndef GC_DARWIN_THREADS
-# define pthread_sigmask GC_pthread_sigmask
-# define dlopen GC_dlopen
-#endif
-
-#endif /* GC_xxxxx_THREADS */
+# ifndef GC_NO_PTHREAD_SIGMASK
+# undef pthread_sigmask
+# define pthread_sigmask GC_pthread_sigmask
+# endif
+# ifndef GC_NO_DLOPEN
+# undef dlopen
+# define dlopen GC_dlopen
+# endif
+# ifndef GC_NO_PTHREAD_CANCEL
+# undef pthread_cancel
+# define pthread_cancel GC_pthread_cancel
+# endif
+# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+# undef pthread_exit
+# define pthread_exit GC_pthread_exit
+# endif
+#endif /* !GC_NO_THREAD_REDIRECTS */
-#endif /* GC_PTHREAD_REDIRECTS_H */
+#endif /* GC_PTHREADS */
diff --git a/boehm-gc/include/gc_tiny_fl.h b/boehm-gc/include/gc_tiny_fl.h
new file mode 100644
index 00000000000..0382b4179d7
--- /dev/null
+++ b/boehm-gc/include/gc_tiny_fl.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1999-2005 Hewlett-Packard Development Company, L.P.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef GC_TINY_FL_H
+#define GC_TINY_FL_H
+/*
+ * Constants and data structures for "tiny" free lists.
+ * These are used for thread-local allocation or in-lined allocators.
+ * Each global free list also essentially starts with one of these.
+ * However, global free lists are known to the GC. "Tiny" free lists
+ * are basically private to the client. Their contents are viewed as
+ * "in use" and marked accordingly by the core of the GC.
+ *
+ * Note that inlined code might know about the layout of these and the constants
+ * involved. Thus any change here may invalidate clients, and such changes should
+ * be avoided. Hence we keep this as simple as possible.
+ */
+
+/*
+ * We always set 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
+ * and space usage for mark bits (usually mark bytes).
+ * On many 64-bit architectures some memory references require 16-byte
+ * alignment, making this necessary anyway.
+ * For a few 32-bit architecture (e.g. x86), we may also need 16-byte alignment
+ * for certain memory references. But currently that does not seem to be the
+ * default for all conventional malloc implementations, so we ignore that
+ * problem.
+ * It would always be safe, and often useful, to be able to allocate very
+ * small objects with smaller alignment. But that would cost us mark bit
+ * space, so we no longer do so.
+ */
+#ifndef GC_GRANULE_BYTES
+ /* GC_GRANULE_BYTES should not be overridden in any instances of the GC */
+ /* library that may be shared between applications, since it affects */
+ /* the binary interface to the library. */
+# if defined(__LP64__) || defined (_LP64) || defined(_WIN64) \
+ || defined(__s390x__) \
+ || (defined(__x86_64__) && !defined(__ILP32__)) \
+ || defined(__alpha__) || defined(__powerpc64__) \
+ || defined(__arch64__)
+# define GC_GRANULE_BYTES 16
+# define GC_GRANULE_WORDS 2
+# else
+# define GC_GRANULE_BYTES 8
+# define GC_GRANULE_WORDS 2
+# endif
+#endif /* !GC_GRANULE_BYTES */
+
+#if GC_GRANULE_WORDS == 2
+# define GC_WORDS_TO_GRANULES(n) ((n)>>1)
+#else
+# define GC_WORDS_TO_GRANULES(n) ((n)*sizeof(void *)/GC_GRANULE_BYTES)
+#endif
+
+/* A "tiny" free list header contains TINY_FREELISTS pointers to */
+/* singly linked lists of objects of different sizes, the ith one */
+/* containing objects i granules in size. Note that there is a list */
+/* of size zero objects. */
+#ifndef GC_TINY_FREELISTS
+# if GC_GRANULE_BYTES == 16
+# define GC_TINY_FREELISTS 25
+# else
+# define GC_TINY_FREELISTS 33 /* Up to and including 256 bytes */
+# endif
+#endif /* !GC_TINY_FREELISTS */
+
+/* The ith free list corresponds to size i*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. */
+
+/* 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 GC_RAW_BYTES_FROM_INDEX(i) ((i) * GC_GRANULE_BYTES)
+
+#endif /* GC_TINY_FL_H */
diff --git a/boehm-gc/include/gc_typed.h b/boehm-gc/include/gc_typed.h
index 905734b8da0..8261cd7b1c8 100644
--- a/boehm-gc/include/gc_typed.h
+++ b/boehm-gc/include/gc_typed.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright 1996 Silicon Graphics. All rights reserved.
@@ -12,6 +12,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
+
/*
* Some simple primitives for allocation with explicit type information.
* Facilities for dynamic type inference may be added later.
@@ -21,93 +22,96 @@
* of the collector, and is not linked in unless referenced.
* This does not currently support GC_DEBUG in any interesting way.
*/
-/* Boehm, May 19, 1994 2:13 pm PDT */
-#ifndef _GC_TYPED_H
-# define _GC_TYPED_H
-# ifndef _GC_H
-# include "gc.h"
-# endif
+#ifndef GC_TYPED_H
+#define GC_TYPED_H
+
+#ifndef GC_H
+# include "gc.h"
+#endif
#ifdef __cplusplus
extern "C" {
#endif
+
typedef GC_word * GC_bitmap;
- /* The least significant bit of the first word is one if */
- /* the first word in the object may be a pointer. */
-
-# define GC_WORDSZ (8*sizeof(GC_word))
-# define GC_get_bit(bm, index) \
- (((bm)[index/GC_WORDSZ] >> (index%GC_WORDSZ)) & 1)
-# define GC_set_bit(bm, index) \
- (bm)[index/GC_WORDSZ] |= ((GC_word)1 << (index%GC_WORDSZ))
-# define GC_WORD_OFFSET(t, f) (offsetof(t,f)/sizeof(GC_word))
-# define GC_WORD_LEN(t) (sizeof(t)/ sizeof(GC_word))
-# define GC_BITMAP_SIZE(t) ((GC_WORD_LEN(t) + GC_WORDSZ-1)/GC_WORDSZ)
+ /* The least significant bit of the first word is one if */
+ /* the first word in the object may be a pointer. */
+
+#define GC_WORDSZ (8 * sizeof(GC_word))
+#define GC_get_bit(bm, index) \
+ (((bm)[(index) / GC_WORDSZ] >> ((index) % GC_WORDSZ)) & 1)
+#define GC_set_bit(bm, index) \
+ ((bm)[(index) / GC_WORDSZ] |= (GC_word)1 << ((index) % GC_WORDSZ))
+#define GC_WORD_OFFSET(t, f) (offsetof(t,f) / sizeof(GC_word))
+#define GC_WORD_LEN(t) (sizeof(t) / sizeof(GC_word))
+#define GC_BITMAP_SIZE(t) ((GC_WORD_LEN(t) + GC_WORDSZ - 1) / GC_WORDSZ)
typedef GC_word GC_descr;
-GC_API GC_descr GC_make_descriptor GC_PROTO((GC_bitmap bm, size_t len));
- /* Return a type descriptor for the object whose layout */
- /* is described by the argument. */
- /* The least significant bit of the first word is one */
- /* if the first word in the object may be a pointer. */
- /* The second argument specifies the number of */
- /* meaningful bits in the bitmap. The actual object */
- /* may be larger (but not smaller). Any additional */
- /* words in the object are assumed not to contain */
- /* pointers. */
- /* Returns a conservative approximation in the */
- /* (unlikely) case of insufficient memory to build */
- /* the descriptor. Calls to GC_make_descriptor */
- /* may consume some amount of a finite resource. This */
- /* is intended to be called once per type, not once */
- /* per allocation. */
+GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * /* GC_bitmap bm */,
+ size_t /* len */);
+ /* Return a type descriptor for the object whose layout */
+ /* is described by the argument. */
+ /* The least significant bit of the first word is one */
+ /* if the first word in the object may be a pointer. */
+ /* The second argument specifies the number of */
+ /* meaningful bits in the bitmap. The actual object */
+ /* may be larger (but not smaller). Any additional */
+ /* words in the object are assumed not to contain */
+ /* pointers. */
+ /* Returns a conservative approximation in the */
+ /* (unlikely) case of insufficient memory to build */
+ /* the descriptor. Calls to GC_make_descriptor */
+ /* may consume some amount of a finite resource. This */
+ /* is intended to be called once per type, not once */
+ /* per allocation. */
-/* It is possible to generate a descriptor for a C type T with */
-/* word aligned pointer fields f1, f2, ... as follows: */
-/* */
+/* It is possible to generate a descriptor for a C type T with */
+/* word aligned pointer fields f1, f2, ... as follows: */
+/* */
/* GC_descr T_descr; */
-/* GC_word T_bitmap[GC_BITMAP_SIZE(T)] = {0}; */
-/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f1)); */
-/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f2)); */
-/* ... */
-/* T_descr = GC_make_descriptor(T_bitmap, GC_WORD_LEN(T)); */
+/* GC_word T_bitmap[GC_BITMAP_SIZE(T)] = {0}; */
+/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f1)); */
+/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f2)); */
+/* ... */
+/* T_descr = GC_make_descriptor(T_bitmap, GC_WORD_LEN(T)); */
+
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_malloc_explicitly_typed(size_t /* size_in_bytes */,
+ GC_descr /* d */);
+ /* Allocate an object whose layout is described by d. */
+ /* The resulting object MAY NOT BE PASSED TO REALLOC. */
+ /* The returned object is cleared. */
-GC_API GC_PTR GC_malloc_explicitly_typed
- GC_PROTO((size_t size_in_bytes, GC_descr d));
- /* Allocate an object whose layout is described by d. */
- /* The resulting object MAY NOT BE PASSED TO REALLOC. */
- /* The returned object is cleared. */
+GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
+ GC_malloc_explicitly_typed_ignore_off_page(size_t /* size_in_bytes */,
+ GC_descr /* d */);
-GC_API GC_PTR GC_malloc_explicitly_typed_ignore_off_page
- GC_PROTO((size_t size_in_bytes, GC_descr d));
-
-GC_API GC_PTR GC_calloc_explicitly_typed
- GC_PROTO((size_t nelements,
- size_t element_size_in_bytes,
- GC_descr d));
- /* Allocate an array of nelements elements, each of the */
- /* given size, and with the given descriptor. */
- /* The elemnt size must be a multiple of the byte */
- /* alignment required for pointers. E.g. on a 32-bit */
- /* machine with 16-bit aligned pointers, size_in_bytes */
- /* must be a multiple of 2. */
- /* Returned object is cleared. */
+GC_API GC_ATTR_MALLOC void * GC_CALL
+ GC_calloc_explicitly_typed(size_t /* nelements */,
+ size_t /* element_size_in_bytes */,
+ GC_descr /* d */);
+ /* Allocate an array of nelements elements, each of the */
+ /* given size, and with the given descriptor. */
+ /* The element size must be a multiple of the byte */
+ /* alignment required for pointers. E.g. on a 32-bit */
+ /* machine with 16-bit aligned pointers, size_in_bytes */
+ /* must be a multiple of 2. */
+ /* Returned object is cleared. */
#ifdef GC_DEBUG
-# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) GC_MALLOC(bytes)
-# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC(n*bytes)
+# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) GC_MALLOC(bytes)
+# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC((n) * (bytes))
#else
-# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \
- GC_malloc_explicitly_typed(bytes, d)
-# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \
- GC_calloc_explicitly_typed(n, bytes, d)
-#endif /* !GC_DEBUG */
+# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \
+ GC_malloc_explicitly_typed(bytes, d)
+# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \
+ GC_calloc_explicitly_typed(n, bytes, d)
+#endif
#ifdef __cplusplus
} /* matches extern "C" */
#endif
-#endif /* _GC_TYPED_H */
-
+#endif /* GC_TYPED_H */
diff --git a/boehm-gc/include/gc_version.h b/boehm-gc/include/gc_version.h
new file mode 100644
index 00000000000..38afc0f3eee
--- /dev/null
+++ b/boehm-gc/include/gc_version.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* This should never be included directly; it is included only from gc.h. */
+#if defined(GC_H)
+
+/* The version here should match that in configure/configure.ac */
+/* Eventually this one may become unnecessary. For now we need */
+/* it to keep the old-style build process working. */
+#define GC_TMP_VERSION_MAJOR 7
+#define GC_TMP_VERSION_MINOR 3
+#define GC_TMP_ALPHA_VERSION 3 /* 7.3alpha3 */
+
+#ifndef GC_NOT_ALPHA
+# define GC_NOT_ALPHA 0xff
+#endif
+
+#ifdef GC_VERSION_MAJOR
+# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR \
+ || GC_TMP_VERSION_MINOR != GC_VERSION_MINOR \
+ || defined(GC_ALPHA_VERSION) != (GC_TMP_ALPHA_VERSION != GC_NOT_ALPHA) \
+ || (defined(GC_ALPHA_VERSION) && GC_TMP_ALPHA_VERSION != GC_ALPHA_VERSION)
+# error Inconsistent version info. Check README, include/gc_version.h and configure.ac.
+# endif
+#else
+# define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
+# define GC_VERSION_MINOR GC_TMP_VERSION_MINOR
+# define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
+#endif /* !GC_VERSION_MAJOR */
+
+#endif
diff --git a/boehm-gc/include/include.am b/boehm-gc/include/include.am
new file mode 100644
index 00000000000..1b2a557b0e8
--- /dev/null
+++ b/boehm-gc/include/include.am
@@ -0,0 +1,54 @@
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program
+# for any purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+
+## Process this file with automake to produce part of Makefile.in.
+
+# installed headers
+#
+pkginclude_HEADERS += \
+ include/gc.h \
+ include/gc_allocator.h \
+ include/gc_backptr.h \
+ include/gc_config_macros.h \
+ include/gc_disclaim.h \
+ include/gc_gcj.h \
+ include/gc_inline.h \
+ include/gc_mark.h \
+ include/gc_pthread_redirects.h \
+ include/gc_tiny_fl.h \
+ include/gc_typed.h \
+ include/gc_version.h \
+ include/javaxfc.h \
+ include/leak_detector.h \
+ include/weakpointer.h
+
+# headers which are not installed
+#
+dist_noinst_HEADERS += \
+ include/cord.h \
+ include/cord_pos.h \
+ include/ec.h \
+ include/new_gc_alloc.h \
+ include/private/darwin_semaphore.h \
+ include/private/darwin_stop_world.h \
+ include/private/dbg_mlc.h \
+ include/private/gc_hdrs.h \
+ include/private/gc_locks.h \
+ include/private/gc_pmark.h \
+ include/private/gc_priv.h \
+ include/private/gcconfig.h \
+ include/private/pthread_stop_world.h \
+ include/private/pthread_support.h \
+ include/private/specific.h \
+ include/private/thread_local_alloc.h
+
+# unprefixed header
+include_HEADERS += \
+ include/extra/gc.h
diff --git a/boehm-gc/include/javaxfc.h b/boehm-gc/include/javaxfc.h
index 23e01005afe..99eaf9ad871 100644
--- a/boehm-gc/include/javaxfc.h
+++ b/boehm-gc/include/javaxfc.h
@@ -1,13 +1,35 @@
-# ifndef GC_H
-# include "gc.h"
-# endif
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef GC_H
+# include "gc.h"
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
/*
- * Invoke all remaining finalizers that haven't yet been run.
- * This is needed for strict compliance with the Java standard,
+ * Invoke all remaining finalizers that haven't yet been run. (Since the
+ * notifier is not called, this should be called from a separate thread.)
+ * This function is needed for strict compliance with the Java standard,
* which can make the runtime guarantee that all finalizers are run.
* This is problematic for several reasons:
- * 1) It means that finalizers, and all methods calle by them,
+ * 1) It means that finalizers, and all methods called by them,
* must be prepared to deal with objects that have been finalized in
* spite of the fact that they are still referenced by statically
* allocated pointer variables.
@@ -16,6 +38,8 @@
* probably unlikely.
* Thus this is not recommended for general use.
*/
-void GC_finalize_all();
-
+GC_API void GC_CALL GC_finalize_all(void);
+#ifdef __cplusplus
+ } /* end of extern "C" */
+#endif
diff --git a/boehm-gc/include/leak_detector.h b/boehm-gc/include/leak_detector.h
index 0674ab4d09f..5540c227a18 100644
--- a/boehm-gc/include/leak_detector.h
+++ b/boehm-gc/include/leak_detector.h
@@ -1,7 +1,68 @@
-#define GC_DEBUG
+/*
+ * Copyright (c) 2000-2011 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef GC_LEAK_DETECTOR_H
+#define GC_LEAK_DETECTOR_H
+
+/* Include leak_detector.h (eg., via GCC --include directive) */
+/* to turn BoehmGC into a Leak Detector. */
+
+#ifndef GC_DEBUG
+# define GC_DEBUG
+#endif
#include "gc.h"
+
+#ifndef GC_DONT_INCLUDE_STDLIB
+ /* We ensure stdlib.h and string.h are included before */
+ /* redirecting malloc() and the accompanying functions. */
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#undef malloc
#define malloc(n) GC_MALLOC(n)
+#undef calloc
#define calloc(m,n) GC_MALLOC((m)*(n))
+#undef free
#define free(p) GC_FREE(p)
-#define realloc(p,n) GC_REALLOC((p),(n))
-#define CHECK_LEAKS() GC_gcollect()
+#undef realloc
+#define realloc(p,n) GC_REALLOC(p,n)
+
+#undef strdup
+#define strdup(s) GC_STRDUP(s)
+#undef strndup
+#define strndup(s,n) GC_STRNDUP(s,n)
+
+#ifdef GC_REQUIRE_WCSDUP
+ /* The collector should be built with GC_REQUIRE_WCSDUP */
+ /* defined as well to redirect wcsdup(). */
+# include <wchar.h>
+# undef wcsdup
+# define wcsdup(s) GC_WCSDUP(s)
+#endif
+
+#undef memalign
+#define memalign(a,n) GC_memalign(a,n)
+#undef posix_memalign
+#define posix_memalign(p,a,n) GC_posix_memalign(p,a,n)
+
+#ifndef CHECK_LEAKS
+# define CHECK_LEAKS() GC_gcollect()
+ /* Note 1: CHECK_LEAKS does not have GC prefix (preserved for */
+ /* backward compatibility). */
+ /* Note 2: GC_gcollect() is also called automatically in the */
+ /* leak-finding mode at program exit. */
+#endif
+
+#endif /* GC_LEAK_DETECTOR_H */
diff --git a/boehm-gc/include/new_gc_alloc.h b/boehm-gc/include/new_gc_alloc.h
index f2219b7732d..bf09780ebd6 100644
--- a/boehm-gc/include/new_gc_alloc.h
+++ b/boehm-gc/include/new_gc_alloc.h
@@ -32,10 +32,10 @@
// with g++ 2.7.2 and earlier.
//
// Unlike its predecessor, this one simply defines
-// gc_alloc
-// single_client_gc_alloc
-// traceable_alloc
-// single_client_traceable_alloc
+// gc_alloc
+// single_client_gc_alloc
+// traceable_alloc
+// single_client_traceable_alloc
//
// It does not redefine alloc. Nor does it change the default allocator,
// though the user may wish to do so. (The argument against changing
@@ -43,9 +43,6 @@
// problems. The argument for changing it is that the usual default
// allocator is usually a very bad choice for a garbage collected environment.)
//
-// This code assumes that the collector itself has been compiled with a
-// compiler that defines __STDC__ .
-//
#ifndef GC_ALLOC_H
@@ -64,15 +61,13 @@
#endif
#endif
-/* A hack to deal with gcc 3.1. If you are using gcc3.1 and later, */
-/* you should probably really use gc_allocator.h instead. */
+/* A hack to deal with gcc 3.1. If you are using gcc3.1 and later, */
+/* you should probably really use gc_allocator.h instead. */
#if defined (__GNUC__) && \
- (__GNUC > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
+ (__GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
# define simple_alloc __simple_alloc
#endif
-
-
#define GC_ALLOC_H
#include <stddef.h>
@@ -83,15 +78,16 @@
// This should eventually be factored out into another include file.
extern "C" {
- extern void ** const GC_objfreelist_ptr;
- extern void ** const GC_aobjfreelist_ptr;
- extern void ** const GC_uobjfreelist_ptr;
- extern void ** const GC_auobjfreelist_ptr;
+ GC_API void ** const GC_objfreelist_ptr;
+ GC_API void ** const GC_aobjfreelist_ptr;
+ GC_API void ** const GC_uobjfreelist_ptr;
+ GC_API void ** const GC_auobjfreelist_ptr;
- extern void GC_incr_words_allocd(size_t words);
- extern void GC_incr_mem_freed(size_t words);
+ GC_API void GC_CALL GC_incr_bytes_allocd(size_t bytes);
+ GC_API void GC_CALL GC_incr_bytes_freed(size_t bytes);
- extern char * GC_generic_malloc_words_small(size_t word, int kind);
+ GC_API char * GC_CALL GC_generic_malloc_words_small(size_t word, int kind);
+ /* FIXME: Doesn't exist anymore. */
}
// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
@@ -109,7 +105,7 @@ enum { GC_byte_alignment = 8 };
enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
inline void * &GC_obj_link(void * p)
-{ return *(void **)p; }
+{ return *reinterpret_cast<void **>(p); }
// Compute a number of words >= n+1 bytes.
// The +1 allows for pointers one past the end.
@@ -130,51 +126,50 @@ public:
// File local count of allocated words. Occasionally this is
// added into the global count. A separate count is necessary since the
// real one must be updated with a procedure call.
- static size_t GC_words_recently_allocd;
+ static size_t GC_bytes_recently_allocd;
- // Same for uncollectable mmory. Not yet reflected in either
- // GC_words_recently_allocd or GC_non_gc_bytes.
- static size_t GC_uncollectable_words_recently_allocd;
+ // Same for uncollectable memory. Not yet reflected in either
+ // GC_bytes_recently_allocd or GC_non_gc_bytes.
+ static size_t GC_uncollectable_bytes_recently_allocd;
// Similar counter for explicitly deallocated memory.
- static size_t GC_mem_recently_freed;
+ static size_t GC_bytes_recently_freed;
// Again for uncollectable memory.
- static size_t GC_uncollectable_mem_recently_freed;
+ static size_t GC_uncollectable_bytes_recently_freed;
static void * GC_out_of_line_malloc(size_t nwords, int kind);
};
template <int dummy>
-size_t GC_aux_template<dummy>::GC_words_recently_allocd = 0;
+size_t GC_aux_template<dummy>::GC_bytes_recently_allocd = 0;
template <int dummy>
-size_t GC_aux_template<dummy>::GC_uncollectable_words_recently_allocd = 0;
+size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_allocd = 0;
template <int dummy>
-size_t GC_aux_template<dummy>::GC_mem_recently_freed = 0;
+size_t GC_aux_template<dummy>::GC_bytes_recently_freed = 0;
template <int dummy>
-size_t GC_aux_template<dummy>::GC_uncollectable_mem_recently_freed = 0;
+size_t GC_aux_template<dummy>::GC_uncollectable_bytes_recently_freed = 0;
template <int dummy>
void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
{
- GC_words_recently_allocd += GC_uncollectable_words_recently_allocd;
+ GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd;
GC_non_gc_bytes +=
- GC_bytes_per_word * GC_uncollectable_words_recently_allocd;
- GC_uncollectable_words_recently_allocd = 0;
+ GC_uncollectable_bytes_recently_allocd;
+ GC_uncollectable_bytes_recently_allocd = 0;
- GC_mem_recently_freed += GC_uncollectable_mem_recently_freed;
- GC_non_gc_bytes -=
- GC_bytes_per_word * GC_uncollectable_mem_recently_freed;
- GC_uncollectable_mem_recently_freed = 0;
+ GC_bytes_recently_freed += GC_uncollectable_bytes_recently_freed;
+ GC_non_gc_bytes -= GC_uncollectable_bytes_recently_freed;
+ GC_uncollectable_bytes_recently_freed = 0;
- GC_incr_words_allocd(GC_words_recently_allocd);
- GC_words_recently_allocd = 0;
+ GC_incr_bytes_allocd(GC_bytes_recently_allocd);
+ GC_bytes_recently_allocd = 0;
- GC_incr_mem_freed(GC_mem_recently_freed);
- GC_mem_recently_freed = 0;
+ GC_incr_bytes_freed(GC_bytes_recently_freed);
+ GC_bytes_recently_freed = 0;
return GC_generic_malloc_words_small(nwords, kind);
}
@@ -183,71 +178,71 @@ typedef GC_aux_template<0> GC_aux;
// A fast, single-threaded, garbage-collected allocator
// We assume the first word will be immediately overwritten.
-// In this version, deallocation is not a noop, and explicit
+// In this version, deallocation is not a no-op, and explicit
// deallocation is likely to help performance.
template <int dummy>
class single_client_gc_alloc_template {
public:
- static void * allocate(size_t n)
+ static void * allocate(size_t n)
{
- size_t nwords = GC_round_up(n);
- void ** flh;
- void * op;
-
- if (n > GC_max_fast_bytes) return GC_malloc(n);
- flh = GC_objfreelist_ptr + nwords;
- if (0 == (op = *flh)) {
- return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
- }
- *flh = GC_obj_link(op);
- GC_aux::GC_words_recently_allocd += nwords;
- return op;
+ size_t nwords = GC_round_up(n);
+ void ** flh;
+ void * op;
+
+ if (n > GC_max_fast_bytes) return GC_malloc(n);
+ flh = GC_objfreelist_ptr + nwords;
+ if (0 == (op = *flh)) {
+ return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
+ }
+ *flh = GC_obj_link(op);
+ GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
+ return op;
}
- static void * ptr_free_allocate(size_t n)
+ static void * ptr_free_allocate(size_t n)
{
- size_t nwords = GC_round_up(n);
- void ** flh;
- void * op;
-
- if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
- flh = GC_aobjfreelist_ptr + nwords;
- if (0 == (op = *flh)) {
- return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
- }
- *flh = GC_obj_link(op);
- GC_aux::GC_words_recently_allocd += nwords;
- return op;
+ size_t nwords = GC_round_up(n);
+ void ** flh;
+ void * op;
+
+ if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
+ flh = GC_aobjfreelist_ptr + nwords;
+ if (0 == (op = *flh)) {
+ return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
+ }
+ *flh = GC_obj_link(op);
+ GC_aux::GC_bytes_recently_allocd += nwords * GC_bytes_per_word;
+ return op;
}
- static void deallocate(void *p, size_t n)
- {
+ static void deallocate(void *p, size_t n)
+ {
size_t nwords = GC_round_up(n);
void ** flh;
-
- if (n > GC_max_fast_bytes) {
- GC_free(p);
- } else {
- flh = GC_objfreelist_ptr + nwords;
- GC_obj_link(p) = *flh;
- memset((char *)p + GC_bytes_per_word, 0,
- GC_bytes_per_word * (nwords - 1));
- *flh = p;
- GC_aux::GC_mem_recently_freed += nwords;
- }
- }
- static void ptr_free_deallocate(void *p, size_t n)
- {
+
+ if (n > GC_max_fast_bytes) {
+ GC_free(p);
+ } else {
+ flh = GC_objfreelist_ptr + nwords;
+ GC_obj_link(p) = *flh;
+ memset(reinterpret_cast<char *>(p) + GC_bytes_per_word, 0,
+ GC_bytes_per_word * (nwords - 1));
+ *flh = p;
+ GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
+ }
+ }
+ static void ptr_free_deallocate(void *p, size_t n)
+ {
size_t nwords = GC_round_up(n);
void ** flh;
-
- if (n > GC_max_fast_bytes) {
- GC_free(p);
- } else {
- flh = GC_aobjfreelist_ptr + nwords;
- GC_obj_link(p) = *flh;
- *flh = p;
- GC_aux::GC_mem_recently_freed += nwords;
- }
- }
+
+ if (n > GC_max_fast_bytes) {
+ GC_free(p);
+ } else {
+ flh = GC_aobjfreelist_ptr + nwords;
+ GC_obj_link(p) = *flh;
+ *flh = p;
+ GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
+ }
+ }
};
typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
@@ -256,64 +251,68 @@ typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
template <int dummy>
class single_client_traceable_alloc_template {
public:
- static void * allocate(size_t n)
+ static void * allocate(size_t n)
{
- size_t nwords = GC_round_up_uncollectable(n);
- void ** flh;
- void * op;
-
- if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
- flh = GC_uobjfreelist_ptr + nwords;
- if (0 == (op = *flh)) {
- return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
- }
- *flh = GC_obj_link(op);
- GC_aux::GC_uncollectable_words_recently_allocd += nwords;
- return op;
+ size_t nwords = GC_round_up_uncollectable(n);
+ void ** flh;
+ void * op;
+
+ if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
+ flh = GC_uobjfreelist_ptr + nwords;
+ if (0 == (op = *flh)) {
+ return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
+ }
+ *flh = GC_obj_link(op);
+ GC_aux::GC_uncollectable_bytes_recently_allocd +=
+ nwords * GC_bytes_per_word;
+ return op;
}
- static void * ptr_free_allocate(size_t n)
+ static void * ptr_free_allocate(size_t n)
{
- size_t nwords = GC_round_up_uncollectable(n);
- void ** flh;
- void * op;
-
- if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
- flh = GC_auobjfreelist_ptr + nwords;
- if (0 == (op = *flh)) {
- return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
- }
- *flh = GC_obj_link(op);
- GC_aux::GC_uncollectable_words_recently_allocd += nwords;
- return op;
+ size_t nwords = GC_round_up_uncollectable(n);
+ void ** flh;
+ void * op;
+
+ if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
+ flh = GC_auobjfreelist_ptr + nwords;
+ if (0 == (op = *flh)) {
+ return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
+ }
+ *flh = GC_obj_link(op);
+ GC_aux::GC_uncollectable_bytes_recently_allocd +=
+ nwords * GC_bytes_per_word;
+ return op;
}
- static void deallocate(void *p, size_t n)
- {
+ static void deallocate(void *p, size_t n)
+ {
size_t nwords = GC_round_up_uncollectable(n);
void ** flh;
-
- if (n > GC_max_fast_bytes) {
- GC_free(p);
- } else {
- flh = GC_uobjfreelist_ptr + nwords;
- GC_obj_link(p) = *flh;
- *flh = p;
- GC_aux::GC_uncollectable_mem_recently_freed += nwords;
- }
- }
- static void ptr_free_deallocate(void *p, size_t n)
- {
+
+ if (n > GC_max_fast_bytes) {
+ GC_free(p);
+ } else {
+ flh = GC_uobjfreelist_ptr + nwords;
+ GC_obj_link(p) = *flh;
+ *flh = p;
+ GC_aux::GC_uncollectable_bytes_recently_freed +=
+ nwords * GC_bytes_per_word;
+ }
+ }
+ static void ptr_free_deallocate(void *p, size_t n)
+ {
size_t nwords = GC_round_up_uncollectable(n);
void ** flh;
-
- if (n > GC_max_fast_bytes) {
- GC_free(p);
- } else {
- flh = GC_auobjfreelist_ptr + nwords;
- GC_obj_link(p) = *flh;
- *flh = p;
- GC_aux::GC_uncollectable_mem_recently_freed += nwords;
- }
- }
+
+ if (n > GC_max_fast_bytes) {
+ GC_free(p);
+ } else {
+ flh = GC_auobjfreelist_ptr + nwords;
+ GC_obj_link(p) = *flh;
+ *flh = p;
+ GC_aux::GC_uncollectable_bytes_recently_freed +=
+ nwords * GC_bytes_per_word;
+ }
+ }
};
typedef single_client_traceable_alloc_template<0> single_client_traceable_alloc;
@@ -321,11 +320,11 @@ typedef single_client_traceable_alloc_template<0> single_client_traceable_alloc;
template < int dummy >
class gc_alloc_template {
public:
- static void * allocate(size_t n) { return GC_malloc(n); }
- static void * ptr_free_allocate(size_t n)
- { return GC_malloc_atomic(n); }
- static void deallocate(void *, size_t) { }
- static void ptr_free_deallocate(void *, size_t) { }
+ static void * allocate(size_t n) { return GC_malloc(n); }
+ static void * ptr_free_allocate(size_t n)
+ { return GC_malloc_atomic(n); }
+ static void deallocate(void *, size_t) { }
+ static void ptr_free_deallocate(void *, size_t) { }
};
typedef gc_alloc_template < 0 > gc_alloc;
@@ -333,59 +332,60 @@ typedef gc_alloc_template < 0 > gc_alloc;
template < int dummy >
class traceable_alloc_template {
public:
- static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
- static void * ptr_free_allocate(size_t n)
- { return GC_malloc_atomic_uncollectable(n); }
- static void deallocate(void *p, size_t) { GC_free(p); }
- static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
+ static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
+ static void * ptr_free_allocate(size_t n)
+ { return GC_malloc_atomic_uncollectable(n); }
+ static void deallocate(void *p, size_t) { GC_free(p); }
+ static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
};
typedef traceable_alloc_template < 0 > traceable_alloc;
// We want to specialize simple_alloc so that it does the right thing
-// for all pointerfree types. At the moment there is no portable way to
+// for all pointer-free types. At the moment there is no portable way to
// even approximate that. The following approximation should work for
// SGI compilers, and recent versions of g++.
-# define __GC_SPECIALIZE(T,alloc) \
-class simple_alloc<T, alloc> { \
-public: \
+// GC_SPECIALIZE() is used internally.
+#define GC_SPECIALIZE(T,alloc) \
+ class simple_alloc<T, alloc> { \
+ public: \
static T *allocate(size_t n) \
- { return 0 == n? 0 : \
- (T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
+ { return 0 == n? 0 : \
+ reinterpret_cast<T*>(alloc::ptr_free_allocate(n * sizeof(T))); } \
static T *allocate(void) \
- { return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
+ { return reinterpret_cast<T*>(alloc::ptr_free_allocate(sizeof(T))); } \
static void deallocate(T *p, size_t n) \
- { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
+ { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof(T)); } \
static void deallocate(T *p) \
- { alloc::ptr_free_deallocate(p, sizeof (T)); } \
-};
+ { alloc::ptr_free_deallocate(p, sizeof(T)); } \
+ };
__STL_BEGIN_NAMESPACE
-__GC_SPECIALIZE(char, gc_alloc)
-__GC_SPECIALIZE(int, gc_alloc)
-__GC_SPECIALIZE(unsigned, gc_alloc)
-__GC_SPECIALIZE(float, gc_alloc)
-__GC_SPECIALIZE(double, gc_alloc)
-
-__GC_SPECIALIZE(char, traceable_alloc)
-__GC_SPECIALIZE(int, traceable_alloc)
-__GC_SPECIALIZE(unsigned, traceable_alloc)
-__GC_SPECIALIZE(float, traceable_alloc)
-__GC_SPECIALIZE(double, traceable_alloc)
-
-__GC_SPECIALIZE(char, single_client_gc_alloc)
-__GC_SPECIALIZE(int, single_client_gc_alloc)
-__GC_SPECIALIZE(unsigned, single_client_gc_alloc)
-__GC_SPECIALIZE(float, single_client_gc_alloc)
-__GC_SPECIALIZE(double, single_client_gc_alloc)
-
-__GC_SPECIALIZE(char, single_client_traceable_alloc)
-__GC_SPECIALIZE(int, single_client_traceable_alloc)
-__GC_SPECIALIZE(unsigned, single_client_traceable_alloc)
-__GC_SPECIALIZE(float, single_client_traceable_alloc)
-__GC_SPECIALIZE(double, single_client_traceable_alloc)
+GC_SPECIALIZE(char, gc_alloc)
+GC_SPECIALIZE(int, gc_alloc)
+GC_SPECIALIZE(unsigned, gc_alloc)
+GC_SPECIALIZE(float, gc_alloc)
+GC_SPECIALIZE(double, gc_alloc)
+
+GC_SPECIALIZE(char, traceable_alloc)
+GC_SPECIALIZE(int, traceable_alloc)
+GC_SPECIALIZE(unsigned, traceable_alloc)
+GC_SPECIALIZE(float, traceable_alloc)
+GC_SPECIALIZE(double, traceable_alloc)
+
+GC_SPECIALIZE(char, single_client_gc_alloc)
+GC_SPECIALIZE(int, single_client_gc_alloc)
+GC_SPECIALIZE(unsigned, single_client_gc_alloc)
+GC_SPECIALIZE(float, single_client_gc_alloc)
+GC_SPECIALIZE(double, single_client_gc_alloc)
+
+GC_SPECIALIZE(char, single_client_traceable_alloc)
+GC_SPECIALIZE(int, single_client_traceable_alloc)
+GC_SPECIALIZE(unsigned, single_client_traceable_alloc)
+GC_SPECIALIZE(float, single_client_traceable_alloc)
+GC_SPECIALIZE(double, single_client_traceable_alloc)
__STL_END_NAMESPACE
diff --git a/boehm-gc/include/private/cord_pos.h b/boehm-gc/include/private/cord_pos.h
deleted file mode 100644
index d2b24bb8ab6..00000000000
--- a/boehm-gc/include/private/cord_pos.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/* Boehm, May 19, 1994 2:23 pm PDT */
-# ifndef CORD_POSITION_H
-
-/* The representation of CORD_position. This is private to the */
-/* implementation, but the size is known to clients. Also */
-/* the implementation of some exported macros relies on it. */
-/* Don't use anything defined here and not in cord.h. */
-
-# define MAX_DEPTH 48
- /* The maximum depth of a balanced cord + 1. */
- /* We don't let cords get deeper than MAX_DEPTH. */
-
-struct CORD_pe {
- CORD pe_cord;
- size_t pe_start_pos;
-};
-
-/* A structure describing an entry on the path from the root */
-/* to current position. */
-typedef struct CORD_Pos {
- size_t cur_pos;
- int path_len;
-# define CORD_POS_INVALID (0x55555555)
- /* path_len == INVALID <==> position invalid */
- const char *cur_leaf; /* Current leaf, if it is a string. */
- /* If the current leaf is a function, */
- /* then this may point to function_buf */
- /* containing the next few characters. */
- /* Always points to a valid string */
- /* containing the current character */
- /* unless cur_end is 0. */
- size_t cur_start; /* Start position of cur_leaf */
- size_t cur_end; /* Ending position of cur_leaf */
- /* 0 if cur_leaf is invalid. */
- struct CORD_pe path[MAX_DEPTH + 1];
- /* path[path_len] is the leaf corresponding to cur_pos */
- /* path[0].pe_cord is the cord we point to. */
-# define FUNCTION_BUF_SZ 8
- char function_buf[FUNCTION_BUF_SZ]; /* Space for next few chars */
- /* from function node. */
-} CORD_pos[1];
-
-/* Extract the cord from a position: */
-CORD CORD_pos_to_cord(CORD_pos p);
-
-/* Extract the current index from a position: */
-size_t CORD_pos_to_index(CORD_pos p);
-
-/* Fetch the character located at the given position: */
-char CORD_pos_fetch(CORD_pos p);
-
-/* Initialize the position to refer to the give cord and index. */
-/* Note that this is the most expensive function on positions: */
-void CORD_set_pos(CORD_pos p, CORD x, size_t i);
-
-/* Advance the position to the next character. */
-/* P must be initialized and valid. */
-/* Invalidates p if past end: */
-void CORD_next(CORD_pos p);
-
-/* Move the position to the preceding character. */
-/* P must be initialized and valid. */
-/* Invalidates p if past beginning: */
-void CORD_prev(CORD_pos p);
-
-/* Is the position valid, i.e. inside the cord? */
-int CORD_pos_valid(CORD_pos p);
-
-char CORD__pos_fetch(CORD_pos);
-void CORD__next(CORD_pos);
-void CORD__prev(CORD_pos);
-
-#define CORD_pos_fetch(p) \
- (((p)[0].cur_end != 0)? \
- (p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \
- : CORD__pos_fetch(p))
-
-#define CORD_next(p) \
- (((p)[0].cur_pos + 1 < (p)[0].cur_end)? \
- (p)[0].cur_pos++ \
- : (CORD__next(p), 0))
-
-#define CORD_prev(p) \
- (((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start)? \
- (p)[0].cur_pos-- \
- : (CORD__prev(p), 0))
-
-#define CORD_pos_to_index(p) ((p)[0].cur_pos)
-
-#define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord)
-
-#define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID)
-
-/* Some grubby stuff for performance-critical friends: */
-#define CORD_pos_chars_left(p) ((long)((p)[0].cur_end) - (long)((p)[0].cur_pos))
- /* Number of characters in cache. <= 0 ==> none */
-
-#define CORD_pos_advance(p,n) ((p)[0].cur_pos += (n) - 1, CORD_next(p))
- /* Advance position by n characters */
- /* 0 < n < CORD_pos_chars_left(p) */
-
-#define CORD_pos_cur_char_addr(p) \
- (p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start)
- /* address of current character in cache. */
-
-#endif
diff --git a/boehm-gc/include/private/darwin_semaphore.h b/boehm-gc/include/private/darwin_semaphore.h
new file mode 100644
index 00000000000..379a7f7112d
--- /dev/null
+++ b/boehm-gc/include/private/darwin_semaphore.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef GC_DARWIN_SEMAPHORE_H
+#define GC_DARWIN_SEMAPHORE_H
+
+#if !defined(GC_DARWIN_THREADS)
+#error darwin_semaphore.h included with GC_DARWIN_THREADS not defined
+#endif
+
+/*
+ This is a very simple semaphore implementation for darwin. It
+ is implemented in terms of pthreads calls so it isn't async signal
+ safe. This isn't a problem because signals aren't used to
+ suspend threads on darwin.
+*/
+
+typedef struct {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int value;
+} sem_t;
+
+static int sem_init(sem_t *sem, int pshared, int value) {
+ int ret;
+ if(pshared)
+ ABORT("sem_init with pshared set");
+ sem->value = value;
+
+ ret = pthread_mutex_init(&sem->mutex,NULL);
+ if(ret < 0) return -1;
+ ret = pthread_cond_init(&sem->cond,NULL);
+ if(ret < 0) return -1;
+ return 0;
+}
+
+static int sem_post(sem_t *sem) {
+ if(pthread_mutex_lock(&sem->mutex) < 0)
+ return -1;
+ sem->value++;
+ if(pthread_cond_signal(&sem->cond) < 0) {
+ pthread_mutex_unlock(&sem->mutex);
+ return -1;
+ }
+ if(pthread_mutex_unlock(&sem->mutex) < 0)
+ return -1;
+ return 0;
+}
+
+static int sem_wait(sem_t *sem) {
+ if(pthread_mutex_lock(&sem->mutex) < 0)
+ return -1;
+ while(sem->value == 0) {
+ pthread_cond_wait(&sem->cond,&sem->mutex);
+ }
+ sem->value--;
+ if(pthread_mutex_unlock(&sem->mutex) < 0)
+ return -1;
+ return 0;
+}
+
+static int sem_destroy(sem_t *sem) {
+ int ret;
+ ret = pthread_cond_destroy(&sem->cond);
+ if(ret < 0) return -1;
+ ret = pthread_mutex_destroy(&sem->mutex);
+ if(ret < 0) return -1;
+ return 0;
+}
+
+#endif
diff --git a/boehm-gc/include/private/darwin_stop_world.h b/boehm-gc/include/private/darwin_stop_world.h
new file mode 100644
index 00000000000..399304ead07
--- /dev/null
+++ b/boehm-gc/include/private/darwin_stop_world.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef GC_DARWIN_STOP_WORLD_H
+#define GC_DARWIN_STOP_WORLD_H
+
+#if !defined(GC_DARWIN_THREADS)
+# error darwin_stop_world.h included without GC_DARWIN_THREADS defined
+#endif
+
+#include <mach/mach.h>
+#include <mach/thread_act.h>
+
+struct thread_stop_info {
+ mach_port_t mach_thread;
+ ptr_t stack_ptr; /* Valid only when thread is in a "blocked" state. */
+};
+
+#ifndef DARWIN_DONT_PARSE_STACK
+ GC_INNER ptr_t GC_FindTopOfStack(unsigned long);
+#endif
+
+#ifdef MPROTECT_VDB
+ GC_INNER void GC_mprotect_stop(void);
+ GC_INNER void GC_mprotect_resume(void);
+#endif
+
+#if defined(PARALLEL_MARK) && !defined(GC_NO_THREADS_DISCOVERY)
+ GC_INNER GC_bool GC_is_mach_marker(thread_act_t);
+#endif
+
+#endif
diff --git a/boehm-gc/include/private/dbg_mlc.h b/boehm-gc/include/private/dbg_mlc.h
index e0a994de5e2..7b2969d2676 100644
--- a/boehm-gc/include/private/dbg_mlc.h
+++ b/boehm-gc/include/private/dbg_mlc.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
* Copyright (c) 1997 by Silicon Graphics. All rights reserved.
@@ -23,153 +23,144 @@
*/
#ifndef _DBG_MLC_H
-
#define _DBG_MLC_H
-# define I_HIDE_POINTERS
-# include "gc_priv.h"
-# ifdef KEEP_BACK_PTRS
-# include "gc_backptr.h"
-# endif
-
-#ifndef HIDE_POINTER
- /* Gc.h was previously included, and hence the I_HIDE_POINTERS */
- /* definition had no effect. Repeat the gc.h definitions here to */
- /* get them anyway. */
- typedef GC_word GC_hidden_pointer;
-# define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
-# define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p)))
-#endif /* HIDE_POINTER */
-
-# define START_FLAG ((word)0xfedcedcb)
-# define END_FLAG ((word)0xbcdecdef)
- /* Stored both one past the end of user object, and one before */
- /* the end of the object as seen by the allocator. */
+#include "gc_priv.h"
+#ifdef KEEP_BACK_PTRS
+# include "gc_backptr.h"
+#endif
-# if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST) \
- || defined(MAKE_BACK_GRAPH)
- /* Pointer "source"s that aren't real locations. */
- /* Used in oh_back_ptr fields and as "source" */
- /* argument to some marking functions. */
-# define NOT_MARKED (ptr_t)(0)
-# define MARKED_FOR_FINALIZATION (ptr_t)(2)
- /* Object was marked because it is finalizable. */
-# define MARKED_FROM_REGISTER (ptr_t)(4)
- /* Object was marked from a rgister. Hence the */
- /* source of the reference doesn't have an address. */
-# endif /* KEEP_BACK_PTRS || PRINT_BLACK_LIST */
+#if CPP_WORDSZ == 32
+# define START_FLAG (word)0xfedcedcb
+# define END_FLAG (word)0xbcdecdef
+#else
+# define START_FLAG GC_WORD_C(0xFEDCEDCBfedcedcb)
+# define END_FLAG GC_WORD_C(0xBCDECDEFbcdecdef)
+#endif
+ /* Stored both one past the end of user object, and one before */
+ /* the end of the object as seen by the allocator. */
+
+#if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST) \
+ || defined(MAKE_BACK_GRAPH)
+ /* Pointer "source"s that aren't real locations. */
+ /* Used in oh_back_ptr fields and as "source" */
+ /* argument to some marking functions. */
+# define NOT_MARKED (ptr_t)0
+# define MARKED_FOR_FINALIZATION ((ptr_t)(word)2)
+ /* Object was marked because it is finalizable. */
+# define MARKED_FROM_REGISTER ((ptr_t)(word)4)
+ /* Object was marked from a register. Hence the */
+ /* source of the reference doesn't have an address. */
+#endif /* KEEP_BACK_PTRS || PRINT_BLACK_LIST */
/* Object header */
typedef struct {
-# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
- /* We potentially keep two different kinds of back */
- /* pointers. KEEP_BACK_PTRS stores a single back */
- /* pointer in each reachable object to allow reporting */
- /* of why an object was retained. MAKE_BACK_GRAPH */
- /* builds a graph containing the inverse of all */
- /* "points-to" edges including those involving */
- /* objects that have just become unreachable. This */
- /* allows detection of growing chains of unreachable */
- /* objects. It may be possible to eventually combine */
- /* both, but for now we keep them separate. Both */
- /* kinds of back pointers are hidden using the */
- /* following macros. In both cases, the plain version */
- /* is constrained to have an least significant bit of 1,*/
- /* to allow it to be distinguished from a free list */
- /* link. This means the plain version must have an */
- /* lsb of 0. */
- /* Note that blocks dropped by black-listing will */
- /* also have the lsb clear once debugging has */
- /* started. */
- /* We're careful never to overwrite a value with lsb 0. */
-# if ALIGNMENT == 1
- /* Fudge back pointer to be even. */
-# define HIDE_BACK_PTR(p) HIDE_POINTER(~1 & (GC_word)(p))
-# else
-# define HIDE_BACK_PTR(p) HIDE_POINTER(p)
-# endif
-
-# ifdef KEEP_BACK_PTRS
- GC_hidden_pointer oh_back_ptr;
-# endif
-# ifdef MAKE_BACK_GRAPH
- GC_hidden_pointer oh_bg_ptr;
-# endif
-# if defined(ALIGN_DOUBLE) && \
- (defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH))
- word oh_dummy;
-# endif
+# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
+ /* We potentially keep two different kinds of back */
+ /* pointers. KEEP_BACK_PTRS stores a single back */
+ /* pointer in each reachable object to allow reporting */
+ /* of why an object was retained. MAKE_BACK_GRAPH */
+ /* builds a graph containing the inverse of all */
+ /* "points-to" edges including those involving */
+ /* objects that have just become unreachable. This */
+ /* allows detection of growing chains of unreachable */
+ /* objects. It may be possible to eventually combine */
+ /* both, but for now we keep them separate. Both */
+ /* kinds of back pointers are hidden using the */
+ /* following macros. In both cases, the plain version */
+ /* is constrained to have an least significant bit of 1, */
+ /* to allow it to be distinguished from a free list */
+ /* link. This means the plain version must have an */
+ /* lsb of 0. */
+ /* Note that blocks dropped by black-listing will */
+ /* also have the lsb clear once debugging has */
+ /* started. */
+ /* We're careful never to overwrite a value with lsb 0. */
+# if ALIGNMENT == 1
+ /* Fudge back pointer to be even. */
+# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(~1 & (GC_word)(p))
+# else
+# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(p)
+# endif
+# ifdef KEEP_BACK_PTRS
+ GC_hidden_pointer oh_back_ptr;
# endif
- GC_CONST char * oh_string; /* object descriptor string */
- word oh_int; /* object descriptor integers */
-# ifdef NEED_CALLINFO
- struct callinfo oh_ci[NFRAMES];
+# ifdef MAKE_BACK_GRAPH
+ GC_hidden_pointer oh_bg_ptr;
# endif
-# ifndef SHORT_DBG_HDRS
- word oh_sz; /* Original malloc arg. */
- word oh_sf; /* start flag */
-# endif /* SHORT_DBG_HDRS */
+# if defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH)
+ /* Keep double-pointer-sized alignment. */
+ word oh_dummy;
+# endif
+# endif
+ const char * oh_string; /* object descriptor string */
+ word oh_int; /* object descriptor integers */
+# ifdef NEED_CALLINFO
+ struct callinfo oh_ci[NFRAMES];
+# endif
+# ifndef SHORT_DBG_HDRS
+ word oh_sz; /* Original malloc arg. */
+ word oh_sf; /* start flag */
+# endif /* SHORT_DBG_HDRS */
} oh;
-/* The size of the above structure is assumed not to dealign things, */
-/* and to be a multiple of the word length. */
+/* The size of the above structure is assumed not to de-align things, */
+/* and to be a multiple of the word length. */
#ifdef SHORT_DBG_HDRS
-# define DEBUG_BYTES (sizeof (oh))
-# define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
+# define DEBUG_BYTES (sizeof (oh))
+# define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
#else
- /* Add space for END_FLAG, but use any extra space that was already */
- /* added to catch off-the-end pointers. */
- /* For uncollectable objects, the extra byte is not added. */
-# define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word))
-# define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
+ /* Add space for END_FLAG, but use any extra space that was already */
+ /* added to catch off-the-end pointers. */
+ /* For uncollectable objects, the extra byte is not added. */
+# define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word))
+# define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
#endif
-/* Round bytes to words without adding extra byte at end. */
+/* Round bytes to words without adding extra byte at end. */
#define SIMPLE_ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
-/* ADD_CALL_CHAIN stores a (partial) call chain into an object */
-/* header. It may be called with or without the allocation */
-/* lock. */
-/* PRINT_CALL_CHAIN prints the call chain stored in an object */
-/* to stderr. It requires that we do not hold the lock. */
-#ifdef SAVE_CALL_CHAIN
-# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
-# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
+/* ADD_CALL_CHAIN stores a (partial) call chain into an object */
+/* header. It may be called with or without the allocation */
+/* lock. */
+/* PRINT_CALL_CHAIN prints the call chain stored in an object */
+/* to stderr. It requires that we do not hold the lock. */
+#if defined(SAVE_CALL_CHAIN)
+ struct callinfo;
+ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]);
+ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
+# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
+# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
+#elif defined(GC_ADD_CALLER)
+ struct callinfo;
+ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
+# define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra)
+# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
#else
-# ifdef GC_ADD_CALLER
-# define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra)
-# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
-# else
-# define ADD_CALL_CHAIN(base, ra)
-# define PRINT_CALL_CHAIN(base)
-# endif
+# define ADD_CALL_CHAIN(base, ra)
+# define PRINT_CALL_CHAIN(base)
#endif
-# ifdef GC_ADD_CALLER
-# define OPT_RA ra,
-# else
-# define OPT_RA
-# endif
-
+#ifdef GC_ADD_CALLER
+# define OPT_RA ra,
+#else
+# define OPT_RA
+#endif
-/* Check whether object with base pointer p has debugging info */
-/* p is assumed to point to a legitimate object in our part */
-/* of the heap. */
+/* Check whether object with base pointer p has debugging info */
+/* p is assumed to point to a legitimate object in our part */
+/* of the heap. */
#ifdef SHORT_DBG_HDRS
-# define GC_has_other_debug_info(p) TRUE
+# define GC_has_other_debug_info(p) 1
#else
- GC_bool GC_has_other_debug_info(/* p */);
+ GC_INNER int GC_has_other_debug_info(ptr_t p);
#endif
#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
# define GC_HAS_DEBUG_INFO(p) \
- ((*((word *)p) & 1) && GC_has_other_debug_info(p))
+ ((*((word *)p) & 1) && GC_has_other_debug_info(p) > 0)
#else
-# define GC_HAS_DEBUG_INFO(p) GC_has_other_debug_info(p)
+# define GC_HAS_DEBUG_INFO(p) (GC_has_other_debug_info(p) > 0)
#endif
-/* Store debugging info into p. Return displaced pointer. */
-/* Assumes we don't hold allocation lock. */
-ptr_t GC_store_debug_info(/* p, sz, string, integer */);
-
#endif /* _DBG_MLC_H */
diff --git a/boehm-gc/include/private/gc_hdrs.h b/boehm-gc/include/private/gc_hdrs.h
index 96749ab1bf0..ad46de0cd13 100644
--- a/boehm-gc/include/private/gc_hdrs.h
+++ b/boehm-gc/include/private/gc_hdrs.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
*
@@ -11,14 +11,15 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, July 11, 1995 11:54 am PDT */
-# ifndef GC_HEADERS_H
-# define GC_HEADERS_H
+
+#ifndef GC_HEADERS_H
+#define GC_HEADERS_H
+
typedef struct hblkhdr hdr;
-# if CPP_WORDSZ != 32 && CPP_WORDSZ < 36
- --> Get a real machine.
-# endif
+#if CPP_WORDSZ != 32 && CPP_WORDSZ < 36
+ --> Get a real machine.
+#endif
/*
* The 2 level tree data structure that is used to find block headers.
@@ -28,206 +29,176 @@ typedef struct hblkhdr hdr;
* This defines HDR, GET_HDR, and SET_HDR, the main macros used to
* retrieve and set object headers.
*
- * Since 5.0 alpha 5, we can also take advantage of a header lookup
+ * We take advantage of a header lookup
* cache. This is a locally declared direct mapped cache, used inside
* the marker. The HC_GET_HDR macro uses and maintains this
* cache. Assuming we get reasonable hit rates, this shaves a few
* memory references from each pointer validation.
*/
-# if CPP_WORDSZ > 32
-# define HASH_TL
-# endif
+#if CPP_WORDSZ > 32
+# define HASH_TL
+#endif
-/* Define appropriate out-degrees for each of the two tree levels */
-# ifdef SMALL_CONFIG
-# define LOG_BOTTOM_SZ 11
- /* Keep top index size reasonable with smaller blocks. */
-# else
-# define LOG_BOTTOM_SZ 10
-# endif
-# ifndef HASH_TL
-# define LOG_TOP_SZ (WORDSZ - LOG_BOTTOM_SZ - LOG_HBLKSIZE)
-# else
-# define LOG_TOP_SZ 11
-# endif
-# define TOP_SZ (1 << LOG_TOP_SZ)
-# define BOTTOM_SZ (1 << LOG_BOTTOM_SZ)
+/* Define appropriate out-degrees for each of the two tree levels */
+#if defined(LARGE_CONFIG) || !defined(SMALL_CONFIG)
+# define LOG_BOTTOM_SZ 10
+#else
+# define LOG_BOTTOM_SZ 11
+ /* Keep top index size reasonable with smaller blocks. */
+#endif
+#define BOTTOM_SZ (1 << LOG_BOTTOM_SZ)
-#ifndef SMALL_CONFIG
-# define USE_HDR_CACHE
+#ifndef HASH_TL
+# define LOG_TOP_SZ (WORDSZ - LOG_BOTTOM_SZ - LOG_HBLKSIZE)
+#else
+# define LOG_TOP_SZ 11
#endif
+#define TOP_SZ (1 << LOG_TOP_SZ)
/* #define COUNT_HDR_CACHE_HITS */
-extern hdr * GC_invalid_header; /* header for an imaginary block */
- /* containing no objects. */
+#ifdef COUNT_HDR_CACHE_HITS
+ extern word GC_hdr_cache_hits; /* used for debugging/profiling */
+ extern word GC_hdr_cache_misses;
+# define HC_HIT() ++GC_hdr_cache_hits
+# define HC_MISS() ++GC_hdr_cache_misses
+#else
+# define HC_HIT()
+# define HC_MISS()
+#endif
+typedef struct hce {
+ word block_addr; /* right shifted by LOG_HBLKSIZE */
+ hdr * hce_hdr;
+} hdr_cache_entry;
-/* Check whether p and corresponding hhdr point to long or invalid */
-/* object. If so, advance hhdr to */
-/* beginning of block, or set hhdr to GC_invalid_header. */
-#define ADVANCE(p, hhdr, source) \
- { \
- hdr * new_hdr = GC_invalid_header; \
- p = GC_find_start(p, hhdr, &new_hdr); \
- hhdr = new_hdr; \
- }
+#define HDR_CACHE_SIZE 8 /* power of 2 */
-#ifdef USE_HDR_CACHE
+#define DECLARE_HDR_CACHE \
+ hdr_cache_entry hdr_cache[HDR_CACHE_SIZE]
-# ifdef COUNT_HDR_CACHE_HITS
- extern word GC_hdr_cache_hits;
- extern word GC_hdr_cache_misses;
-# define HC_HIT() ++GC_hdr_cache_hits
-# define HC_MISS() ++GC_hdr_cache_misses
-# else
-# define HC_HIT()
-# define HC_MISS()
-# endif
+#define INIT_HDR_CACHE BZERO(hdr_cache, sizeof(hdr_cache))
+
+#define HCE(h) hdr_cache + (((word)(h) >> LOG_HBLKSIZE) & (HDR_CACHE_SIZE-1))
+
+#define HCE_VALID_FOR(hce,h) ((hce) -> block_addr == \
+ ((word)(h) >> LOG_HBLKSIZE))
+
+#define HCE_HDR(h) ((hce) -> hce_hdr)
- typedef struct hce {
- word block_addr; /* right shifted by LOG_HBLKSIZE */
- hdr * hce_hdr;
- } hdr_cache_entry;
-
-# define HDR_CACHE_SIZE 8 /* power of 2 */
-
-# define DECLARE_HDR_CACHE \
- hdr_cache_entry hdr_cache[HDR_CACHE_SIZE]
-
-# define INIT_HDR_CACHE BZERO(hdr_cache, sizeof(hdr_cache));
-
-# define HCE(h) hdr_cache + (((word)(h) >> LOG_HBLKSIZE) & (HDR_CACHE_SIZE-1))
-
-# define HCE_VALID_FOR(hce,h) ((hce) -> block_addr == \
- ((word)(h) >> LOG_HBLKSIZE))
-
-# define HCE_HDR(h) ((hce) -> hce_hdr)
-
-
-/* Analogous to GET_HDR, except that in the case of large objects, it */
-/* Returns the header for the object beginning, and updates p. */
-/* Returns &GC_bad_header instead of 0. All of this saves a branch */
-/* in the fast path. */
-# define HC_GET_HDR(p, hhdr, source) \
- { \
- hdr_cache_entry * hce = HCE(p); \
- if (HCE_VALID_FOR(hce, p)) { \
- HC_HIT(); \
- hhdr = hce -> hce_hdr; \
- } else { \
- HC_MISS(); \
- GET_HDR(p, hhdr); \
- if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \
- ADVANCE(p, hhdr, source); \
- } else { \
- hce -> block_addr = (word)(p) >> LOG_HBLKSIZE; \
- hce -> hce_hdr = hhdr; \
- } \
- } \
- }
-
-#else /* !USE_HDR_CACHE */
-
-# define DECLARE_HDR_CACHE
-
-# define INIT_HDR_CACHE
-
-# define HC_GET_HDR(p, hhdr, source) \
- { \
- GET_HDR(p, hhdr); \
- if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \
- ADVANCE(p, hhdr, source); \
- } \
- }
+#ifdef PRINT_BLACK_LIST
+ GC_INNER hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce,
+ ptr_t source);
+# define HEADER_CACHE_MISS(p, hce, source) \
+ GC_header_cache_miss(p, hce, source)
+#else
+ GC_INNER hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce);
+# define HEADER_CACHE_MISS(p, hce, source) GC_header_cache_miss(p, hce)
#endif
+/* Set hhdr to the header for p. Analogous to GET_HDR below, */
+/* except that in the case of large objects, it */
+/* gets the header for the object beginning, if GC_all_interior_ptrs */
+/* is set. */
+/* Returns zero if p points to somewhere other than the first page */
+/* of an object, and it is not a valid pointer to the object. */
+#define HC_GET_HDR(p, hhdr, source, exit_label) \
+ { \
+ hdr_cache_entry * hce = HCE(p); \
+ if (EXPECT(HCE_VALID_FOR(hce, p), TRUE)) { \
+ HC_HIT(); \
+ hhdr = hce -> hce_hdr; \
+ } else { \
+ hhdr = HEADER_CACHE_MISS(p, hce, source); \
+ if (0 == hhdr) goto exit_label; \
+ } \
+ }
+
typedef struct bi {
hdr * index[BOTTOM_SZ];
- /*
- * The bottom level index contains one of three kinds of values:
- * 0 means we're not responsible for this block,
- * or this is a block other than the first one in a free block.
- * 1 < (long)X <= MAX_JUMP means the block starts at least
- * X * HBLKSIZE bytes before the current address.
- * A valid pointer points to a hdr structure. (The above can't be
- * valid pointers due to the GET_MEM return convention.)
- */
- struct bi * asc_link; /* All indices are linked in */
- /* ascending order... */
- struct bi * desc_link; /* ... and in descending order. */
- word key; /* high order address bits. */
+ /*
+ * The bottom level index contains one of three kinds of values:
+ * 0 means we're not responsible for this block,
+ * or this is a block other than the first one in a free block.
+ * 1 < (long)X <= MAX_JUMP means the block starts at least
+ * X * HBLKSIZE bytes before the current address.
+ * A valid pointer points to a hdr structure. (The above can't be
+ * valid pointers due to the GET_MEM return convention.)
+ */
+ struct bi * asc_link; /* All indices are linked in */
+ /* ascending order... */
+ struct bi * desc_link; /* ... and in descending order. */
+ word key; /* high order address bits. */
# ifdef HASH_TL
- struct bi * hash_link; /* Hash chain link. */
+ struct bi * hash_link; /* Hash chain link. */
# endif
} bottom_index;
-/* extern bottom_index GC_all_nils; - really part of GC_arrays */
+/* bottom_index GC_all_nils; - really part of GC_arrays */
/* extern bottom_index * GC_top_index []; - really part of GC_arrays */
- /* Each entry points to a bottom_index. */
- /* On a 32 bit machine, it points to */
- /* the index for a set of high order */
- /* bits equal to the index. For longer */
- /* addresses, we hash the high order */
- /* bits to compute the index in */
- /* GC_top_index, and each entry points */
- /* to a hash chain. */
- /* The last entry in each chain is */
- /* GC_all_nils. */
-
-
-# define MAX_JUMP (HBLKSIZE - 1)
-
-# define HDR_FROM_BI(bi, p) \
- ((bi)->index[((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)])
-# ifndef HASH_TL
-# define BI(p) (GC_top_index \
- [(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE)])
-# define HDR_INNER(p) HDR_FROM_BI(BI(p),p)
-# ifdef SMALL_CONFIG
-# define HDR(p) GC_find_header((ptr_t)(p))
-# else
-# define HDR(p) HDR_INNER(p)
-# endif
-# define GET_BI(p, bottom_indx) (bottom_indx) = BI(p)
-# define GET_HDR(p, hhdr) (hhdr) = HDR(p)
-# define SET_HDR(p, hhdr) HDR_INNER(p) = (hhdr)
-# define GET_HDR_ADDR(p, ha) (ha) = &(HDR_INNER(p))
-# else /* hash */
-/* Hash function for tree top level */
-# define TL_HASH(hi) ((hi) & (TOP_SZ - 1))
-/* Set bottom_indx to point to the bottom index for address p */
-# define GET_BI(p, bottom_indx) \
- { \
- register word hi = \
- (word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
- register bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \
- \
- while (_bi -> key != hi && _bi != GC_all_nils) \
- _bi = _bi -> hash_link; \
- (bottom_indx) = _bi; \
- }
-# define GET_HDR_ADDR(p, ha) \
- { \
- register bottom_index * bi; \
- \
- GET_BI(p, bi); \
- (ha) = &(HDR_FROM_BI(bi, p)); \
- }
-# define GET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
- (hhdr) = *_ha; }
-# define SET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
- *_ha = (hhdr); }
-# define HDR(p) GC_find_header((ptr_t)(p))
+ /* Each entry points to a bottom_index. */
+ /* On a 32 bit machine, it points to */
+ /* the index for a set of high order */
+ /* bits equal to the index. For longer */
+ /* addresses, we hash the high order */
+ /* bits to compute the index in */
+ /* GC_top_index, and each entry points */
+ /* to a hash chain. */
+ /* The last entry in each chain is */
+ /* GC_all_nils. */
+
+
+#define MAX_JUMP (HBLKSIZE - 1)
+
+#define HDR_FROM_BI(bi, p) \
+ ((bi)->index[((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)])
+#ifndef HASH_TL
+# define BI(p) (GC_top_index \
+ [(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE)])
+# define HDR_INNER(p) HDR_FROM_BI(BI(p),p)
+# ifdef SMALL_CONFIG
+# define HDR(p) GC_find_header((ptr_t)(p))
+# else
+# define HDR(p) HDR_INNER(p)
# endif
-
-/* Is the result a forwarding address to someplace closer to the */
-/* beginning of the block or NIL? */
-# define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((unsigned long) (hhdr) <= MAX_JUMP)
+# define GET_BI(p, bottom_indx) (bottom_indx) = BI(p)
+# define GET_HDR(p, hhdr) (hhdr) = HDR(p)
+# define SET_HDR(p, hhdr) HDR_INNER(p) = (hhdr)
+# define GET_HDR_ADDR(p, ha) (ha) = &(HDR_INNER(p))
+#else /* hash */
+ /* Hash function for tree top level */
+# define TL_HASH(hi) ((hi) & (TOP_SZ - 1))
+ /* Set bottom_indx to point to the bottom index for address p */
+# define GET_BI(p, bottom_indx) \
+ { \
+ register word hi = \
+ (word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
+ register bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \
+ while (_bi -> key != hi && _bi != GC_all_nils) \
+ _bi = _bi -> hash_link; \
+ (bottom_indx) = _bi; \
+ }
+# define GET_HDR_ADDR(p, ha) \
+ { \
+ register bottom_index * bi; \
+ GET_BI(p, bi); \
+ (ha) = &(HDR_FROM_BI(bi, p)); \
+ }
+# define GET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
+ (hhdr) = *_ha; }
+# define SET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
+ *_ha = (hhdr); }
+# define HDR(p) GC_find_header((ptr_t)(p))
+#endif
+
+/* Is the result a forwarding address to someplace closer to the */
+/* beginning of the block or NULL? */
+#define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((size_t) (hhdr) <= MAX_JUMP)
/* Get an HBLKSIZE aligned address closer to the beginning of the block */
-/* h. Assumes hhdr == HDR(h) and IS_FORWARDING_ADDR(hhdr). */
-# define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (unsigned long)(hhdr))
-# endif /* GC_HEADERS_H */
+/* h. Assumes hhdr == HDR(h) and IS_FORWARDING_ADDR(hhdr). */
+#define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (size_t)(hhdr))
+
+#endif /* GC_HEADERS_H */
diff --git a/boehm-gc/include/private/gc_locks.h b/boehm-gc/include/private/gc_locks.h
index df8043b64be..7c3e9c8983a 100644
--- a/boehm-gc/include/private/gc_locks.h
+++ b/boehm-gc/include/private/gc_locks.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
@@ -21,636 +21,190 @@
/*
* Mutual exclusion between allocator/collector routines.
* Needed if there is more than one allocator thread.
- * FASTLOCK() is assumed to try to acquire the lock in a cheap and
- * dirty way that is acceptable for a few instructions, e.g. by
- * inhibiting preemption. This is assumed to have succeeded only
- * if a subsequent call to FASTLOCK_SUCCEEDED() returns TRUE.
- * FASTUNLOCK() is called whether or not FASTLOCK_SUCCEEDED().
- * If signals cannot be tolerated with the FASTLOCK held, then
- * FASTLOCK should disable signals. The code executed under
- * FASTLOCK is otherwise immune to interruption, provided it is
- * not restarted.
- * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK
- * and/or DISABLE_SIGNALS and ENABLE_SIGNALS and/or FASTLOCK.
- * (There is currently no equivalent for FASTLOCK.)
+ * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK.
*
- * In the PARALLEL_MARK case, we also need to define a number of
- * other inline finctions here:
- * GC_bool GC_compare_and_exchange( volatile GC_word *addr,
- * GC_word old, GC_word new )
- * GC_word GC_atomic_add( volatile GC_word *addr, GC_word how_much )
- * void GC_memory_barrier( )
- *
- */
+ * Note that I_HOLD_LOCK and I_DONT_HOLD_LOCK are used only positively
+ * in assertions, and may return TRUE in the "don't know" case.
+ */
# ifdef THREADS
- void GC_noop1 GC_PROTO((word));
-# ifdef PCR_OBSOLETE /* Faster, but broken with multiple lwp's */
-# include "th/PCR_Th.h"
-# include "th/PCR_ThCrSec.h"
- extern struct PCR_Th_MLRep GC_allocate_ml;
-# define DCL_LOCK_STATE PCR_sigset_t GC_old_sig_mask
-# define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
-# define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
-# define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
-# define FASTLOCK() PCR_ThCrSec_EnterSys()
- /* Here we cheat (a lot): */
-# define FASTLOCK_SUCCEEDED() (*(int *)(&GC_allocate_ml) == 0)
- /* TRUE if nobody currently holds the lock */
-# define FASTUNLOCK() PCR_ThCrSec_ExitSys()
+
+# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
+# include "atomic_ops.h"
# endif
+
# ifdef PCR
# include <base/PCR_Base.h>
# include <th/PCR_Th.h>
- extern PCR_Th_ML GC_allocate_ml;
+ GC_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 FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml))
-# define FASTLOCK_SUCCEEDED() (GC_fastLockRes == PCR_ERes_okay)
-# define FASTUNLOCK() {\
- if( FASTLOCK_SUCCEEDED() ) PCR_Th_ML_Release(&GC_allocate_ml); }
-# endif
-# ifdef SRC_M3
- extern GC_word RT0u__inCritical;
-# define LOCK() RT0u__inCritical++
-# define UNLOCK() RT0u__inCritical--
-# endif
-# ifdef GC_SOLARIS_THREADS
-# include <thread.h>
-# include <signal.h>
- extern mutex_t GC_allocate_ml;
-# define LOCK() mutex_lock(&GC_allocate_ml);
-# define UNLOCK() mutex_unlock(&GC_allocate_ml);
+ PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
+# define UNCOND_LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
+# define UNCOND_UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
# endif
-/* Try to define GC_TEST_AND_SET and a matching GC_CLEAR for spin lock */
-/* acquisition and release. We need this for correct operation of the */
-/* incremental GC. */
-# ifdef __GNUC__
-# if defined(I386)
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- int oldval;
- /* Note: the "xchg" instruction does not need a "lock" prefix */
- __asm__ __volatile__("xchgl %0, %1"
- : "=r"(oldval), "=m"(*(addr))
- : "0"(1), "m"(*(addr)) : "memory");
- return oldval;
- }
-# define GC_TEST_AND_SET_DEFINED
-# endif
-# if defined(IA64)
-# if defined(__INTEL_COMPILER)
-# include <ia64intrin.h>
-# endif
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- long oldval, n = 1;
-# ifndef __INTEL_COMPILER
- __asm__ __volatile__("xchg4 %0=%1,%2"
- : "=r"(oldval), "=m"(*addr)
- : "r"(n), "1"(*addr) : "memory");
-# else
- oldval = _InterlockedExchange(addr, n);
-# endif
- return oldval;
- }
-# define GC_TEST_AND_SET_DEFINED
- /* Should this handle post-increment addressing?? */
- inline static void GC_clear(volatile unsigned int *addr) {
-# ifndef __INTEL_COMPILER
- __asm__ __volatile__("st4.rel %0=r0" : "=m" (*addr) : : "memory");
-# else
- // there is no st4 but I can use xchg I hope
- _InterlockedExchange(addr, 0);
-# endif
- }
-# define GC_CLEAR_DEFINED
-# endif
-# ifdef SPARC
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- int oldval;
-
- __asm__ __volatile__("ldstub %1,%0"
- : "=r"(oldval), "=m"(*addr)
- : "m"(*addr) : "memory");
- return oldval;
- }
-# define GC_TEST_AND_SET_DEFINED
-# endif
-# ifdef M68K
- /* Contributed by Tony Mantler. I'm not sure how well it was */
- /* tested. */
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- char oldval; /* this must be no longer than 8 bits */
-
- /* The return value is semi-phony. */
- /* 'tas' sets bit 7 while the return */
- /* value pretends bit 0 was set */
- __asm__ __volatile__(
- "tas %1@; sne %0; negb %0"
- : "=d" (oldval)
- : "a" (addr) : "memory");
- return oldval;
- }
-# define GC_TEST_AND_SET_DEFINED
-# endif
-# if defined(POWERPC)
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- int oldval;
- int temp = 1; /* locked value */
-
- __asm__ __volatile__(
- "1:\tlwarx %0,0,%3\n" /* load and reserve */
- "\tcmpwi %0, 0\n" /* if load is */
- "\tbne 2f\n" /* non-zero, return already set */
- "\tstwcx. %2,0,%1\n" /* else store conditional */
- "\tbne- 1b\n" /* retry if lost reservation */
- "\tsync\n" /* import barrier */
- "2:\t\n" /* oldval is zero if we set */
- : "=&r"(oldval), "=p"(addr)
- : "r"(temp), "1"(addr)
- : "cr0","memory");
- return oldval;
- }
-# define GC_TEST_AND_SET_DEFINED
- inline static void GC_clear(volatile unsigned int *addr) {
- __asm__ __volatile__("eieio" : : : "memory");
- *(addr) = 0;
- }
-# define GC_CLEAR_DEFINED
-# endif
-# if defined(ALPHA)
- inline static int GC_test_and_set(volatile unsigned int * addr)
- {
- unsigned long oldvalue;
- unsigned long temp;
-
- __asm__ __volatile__(
- "1: ldl_l %0,%1\n"
- " and %0,%3,%2\n"
- " bne %2,2f\n"
- " xor %0,%3,%0\n"
- " stl_c %0,%1\n"
-# ifdef __ELF__
- " beq %0,3f\n"
-# else
- " beq %0,1b\n"
-# endif
- " mb\n"
- "2:\n"
-# ifdef __ELF__
- ".section .text2,\"ax\"\n"
- "3: br 1b\n"
- ".previous"
-# endif
- :"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
- :"Ir" (1), "m" (*addr)
- :"memory");
+# if (!defined(AO_HAVE_test_and_set_acquire) || defined(GC_RTEMS_PTHREADS) \
+ || defined(SN_TARGET_PS3) || defined(GC_WIN32_THREADS) \
+ || defined(LINT2)) && defined(GC_PTHREADS)
+# define USE_PTHREAD_LOCKS
+# endif
- return oldvalue;
- }
-# define GC_TEST_AND_SET_DEFINED
- inline static void GC_clear(volatile unsigned int *addr) {
- __asm__ __volatile__("mb" : : : "memory");
- *(addr) = 0;
- }
-# define GC_CLEAR_DEFINED
-# endif /* ALPHA */
-# ifdef ARM32
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- int oldval;
- /* SWP on ARM is very similar to XCHG on x86. Doesn't lock the
- * bus because there are no SMP ARM machines. If/when there are,
- * this code will likely need to be updated. */
- /* See linuxthreads/sysdeps/arm/pt-machine.h in glibc-2.1 */
- __asm__ __volatile__("swp %0, %1, [%2]"
- : "=r"(oldval)
- : "r"(1), "r"(addr)
- : "memory");
- return oldval;
- }
-# define GC_TEST_AND_SET_DEFINED
-# endif /* ARM32 */
-# ifdef S390
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- int ret;
- __asm__ __volatile__ (
- " l %0,0(%2)\n"
- "0: cs %0,%1,0(%2)\n"
- " jl 0b"
- : "=&d" (ret)
- : "d" (1), "a" (addr)
- : "cc", "memory");
- return ret;
- }
-# endif
-# endif /* __GNUC__ */
-# if (defined(ALPHA) && !defined(__GNUC__))
-# ifndef OSF1
- --> We currently assume that if gcc is not used, we are
- --> running under Tru64.
+# if defined(GC_WIN32_THREADS) && !defined(USE_PTHREAD_LOCKS)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
# endif
-# include <machine/builtins.h>
-# include <c_asm.h>
-# define GC_test_and_set(addr) __ATOMIC_EXCH_LONG(addr, 1)
-# define GC_TEST_AND_SET_DEFINED
-# define GC_clear(addr) { asm("mb"); *(volatile unsigned *)addr = 0; }
-# define GC_CLEAR_DEFINED
-# endif
-# if defined(MSWIN32)
-# define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
-# define GC_TEST_AND_SET_DEFINED
-# endif
-# ifdef MIPS
-# ifdef LINUX
-# include <sys/tas.h>
-# define GC_test_and_set(addr) _test_and_set((int *) addr,1)
-# define GC_TEST_AND_SET_DEFINED
-# elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
- || !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
-# ifdef __GNUC__
-# define GC_test_and_set(addr) _test_and_set((void *)addr,1)
-# else
-# define GC_test_and_set(addr) test_and_set((void *)addr,1)
-# endif
+# define NOSERVICE
+# include <windows.h>
+# define NO_THREAD (DWORD)(-1)
+ GC_EXTERN DWORD GC_lock_holder;
+ GC_EXTERN CRITICAL_SECTION GC_allocate_ml;
+# ifdef GC_ASSERTIONS
+# define UNCOND_LOCK() \
+ { EnterCriticalSection(&GC_allocate_ml); \
+ SET_LOCK_HOLDER(); }
+# define UNCOND_UNLOCK() \
+ { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
+ LeaveCriticalSection(&GC_allocate_ml); }
# else
-# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
-# define GC_clear(addr) __lock_release(addr);
-# define GC_CLEAR_DEFINED
-# endif
-# define GC_TEST_AND_SET_DEFINED
-# endif /* MIPS */
-# if defined(_AIX)
-# include <sys/atomic_op.h>
-# if (defined(_POWER) || defined(_POWERPC))
-# if defined(__GNUC__)
- inline static void GC_memsync() {
- __asm__ __volatile__ ("sync" : : : "memory");
- }
-# else
-# ifndef inline
-# define inline __inline
-# endif
-# pragma mc_func GC_memsync { \
- "7c0004ac" /* sync (same opcode used for dcs)*/ \
- }
-# endif
-# else
-# error dont know how to memsync
-# endif
- inline static int GC_test_and_set(volatile unsigned int * addr) {
- int oldvalue = 0;
- if (compare_and_swap((void *)addr, &oldvalue, 1)) {
- GC_memsync();
- return 0;
- } else return 1;
- }
-# define GC_TEST_AND_SET_DEFINED
- inline static void GC_clear(volatile unsigned int *addr) {
- GC_memsync();
- *(addr) = 0;
- }
-# define GC_CLEAR_DEFINED
-
-# endif
-# if 0 /* defined(HP_PA) */
- /* The official recommendation seems to be to not use ldcw from */
- /* user mode. Since multithreaded incremental collection doesn't */
- /* work anyway on HP_PA, this shouldn't be a major loss. */
+# define UNCOND_LOCK() EnterCriticalSection(&GC_allocate_ml)
+# define UNCOND_UNLOCK() LeaveCriticalSection(&GC_allocate_ml)
+# endif /* !GC_ASSERTIONS */
+# define SET_LOCK_HOLDER() GC_lock_holder = GetCurrentThreadId()
+# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
+# define I_HOLD_LOCK() (!GC_need_to_lock \
+ || GC_lock_holder == GetCurrentThreadId())
+# define I_DONT_HOLD_LOCK() (!GC_need_to_lock \
+ || GC_lock_holder != GetCurrentThreadId())
+# elif defined(GC_PTHREADS)
+# include <pthread.h>
- /* "set" means 0 and "clear" means 1 here. */
-# define GC_test_and_set(addr) !GC_test_and_clear(addr);
-# define GC_TEST_AND_SET_DEFINED
-# define GC_clear(addr) GC_noop1((word)(addr)); *(volatile unsigned int *)addr = 1;
- /* The above needs a memory barrier! */
-# define GC_CLEAR_DEFINED
-# endif
-# if defined(GC_TEST_AND_SET_DEFINED) && !defined(GC_CLEAR_DEFINED)
-# ifdef __GNUC__
- inline static void GC_clear(volatile unsigned int *addr) {
- /* Try to discourage gcc from moving anything past this. */
- __asm__ __volatile__(" " : : : "memory");
- *(addr) = 0;
- }
+ /* Posix allows pthread_t to be a struct, though it rarely is. */
+ /* Unfortunately, we need to use a pthread_t to index a data */
+ /* structure. It also helps if comparisons don't involve a */
+ /* function call. Hence we introduce platform-dependent macros */
+ /* to compare pthread_t ids and to map them to integers. */
+ /* the mapping to integers does not need to result in different */
+ /* integers for each thread, though that should be true as much */
+ /* as possible. */
+ /* Refine to exclude platforms on which pthread_t is struct */
+# if !defined(GC_WIN32_PTHREADS)
+# define NUMERIC_THREAD_ID(id) ((unsigned long)(id))
+# define THREAD_EQUAL(id1, id2) ((id1) == (id2))
+# define NUMERIC_THREAD_ID_UNIQUE
# else
- /* The function call in the following should prevent the */
- /* compiler from moving assignments to below the UNLOCK. */
-# define GC_clear(addr) GC_noop1((word)(addr)); \
- *((volatile unsigned int *)(addr)) = 0;
+# define NUMERIC_THREAD_ID(id) ((unsigned long)(id.p))
+ /* Using documented internal details of win32-pthread library. */
+ /* Faster than pthread_equal(). Should not change with */
+ /* future versions of win32-pthread library. */
+# define THREAD_EQUAL(id1, id2) ((id1.p == id2.p) && (id1.x == id2.x))
+# undef NUMERIC_THREAD_ID_UNIQUE
+ /* Generic definitions based on pthread_equal() always work but */
+ /* will result in poor performance (as NUMERIC_THREAD_ID is */
+ /* defined to just a constant) and weak assertion checking. */
# endif
-# define GC_CLEAR_DEFINED
-# endif /* !GC_CLEAR_DEFINED */
-
-# if !defined(GC_TEST_AND_SET_DEFINED)
-# define USE_PTHREAD_LOCKS
-# endif
-
-# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
- && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
-# define NO_THREAD (pthread_t)(-1)
-# include <pthread.h>
-# if defined(PARALLEL_MARK)
- /* We need compare-and-swap to update mark bits, where it's */
- /* performance critical. If USE_MARK_BYTES is defined, it is */
- /* no longer needed for this purpose. However we use it in */
- /* either case to implement atomic fetch-and-add, though that's */
- /* less performance critical, and could perhaps be done with */
- /* a lock. */
-# if defined(GENERIC_COMPARE_AND_SWAP)
- /* Probably not useful, except for debugging. */
- /* We do use GENERIC_COMPARE_AND_SWAP on PA_RISC, but we */
- /* minimize its use. */
- extern pthread_mutex_t GC_compare_and_swap_lock;
-
- /* Note that if GC_word updates are not atomic, a concurrent */
- /* reader should acquire GC_compare_and_swap_lock. On */
- /* currently supported platforms, such updates are atomic. */
- extern GC_bool GC_compare_and_exchange(volatile GC_word *addr,
- GC_word old, GC_word new_val);
-# endif /* GENERIC_COMPARE_AND_SWAP */
-# if defined(I386)
-# if !defined(GENERIC_COMPARE_AND_SWAP)
- /* Returns TRUE if the comparison succeeded. */
- inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
- GC_word old,
- GC_word new_val)
- {
- char result;
- __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
- : "+m"(*(addr)), "=r"(result)
- : "r" (new_val), "a"(old) : "memory");
- return (GC_bool) result;
- }
-# endif /* !GENERIC_COMPARE_AND_SWAP */
- inline static void GC_memory_barrier()
- {
- /* We believe the processor ensures at least processor */
- /* consistent ordering. Thus a compiler barrier */
- /* should suffice. */
- __asm__ __volatile__("" : : : "memory");
- }
-# endif /* I386 */
-
-# if defined(POWERPC)
-# if !defined(GENERIC_COMPARE_AND_SWAP)
- /* Returns TRUE if the comparison succeeded. */
- inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
- GC_word old, GC_word new_val)
- {
- int result, dummy;
- __asm__ __volatile__(
- "1:\tlwarx %0,0,%5\n"
- "\tcmpw %0,%4\n"
- "\tbne 2f\n"
- "\tstwcx. %3,0,%2\n"
- "\tbne- 1b\n"
- "\tsync\n"
- "\tli %1, 1\n"
- "\tb 3f\n"
- "2:\tli %1, 0\n"
- "3:\t\n"
- : "=&r" (dummy), "=r" (result), "=p" (addr)
- : "r" (new_val), "r" (old), "2"(addr)
- : "cr0","memory");
- return (GC_bool) result;
- }
-# endif /* !GENERIC_COMPARE_AND_SWAP */
- inline static void GC_memory_barrier()
- {
- __asm__ __volatile__("sync" : : : "memory");
- }
-# endif /* POWERPC */
-
-# if defined(IA64)
-# if !defined(GENERIC_COMPARE_AND_SWAP)
- inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
- GC_word old, GC_word new_val)
- {
- unsigned long oldval;
- __asm__ __volatile__("mov ar.ccv=%4 ;; cmpxchg8.rel %0=%1,%2,ar.ccv"
- : "=r"(oldval), "=m"(*addr)
- : "r"(new_val), "1"(*addr), "r"(old) : "memory");
- return (oldval == old);
- }
-# endif /* !GENERIC_COMPARE_AND_SWAP */
-# if 0
- /* Shouldn't be needed; we use volatile stores instead. */
- inline static void GC_memory_barrier()
- {
- __asm__ __volatile__("mf" : : : "memory");
- }
-# endif /* 0 */
-# endif /* IA64 */
-# if defined(ALPHA)
-# if !defined(GENERIC_COMPARE_AND_SWAP)
-# if defined(__GNUC__)
- inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
- GC_word old, GC_word new_val)
- {
- unsigned long was_equal;
- unsigned long temp;
-
- __asm__ __volatile__(
- "1: ldq_l %0,%1\n"
- " cmpeq %0,%4,%2\n"
- " mov %3,%0\n"
- " beq %2,2f\n"
- " stq_c %0,%1\n"
- " beq %0,1b\n"
- "2:\n"
- " mb\n"
- :"=&r" (temp), "=m" (*addr), "=&r" (was_equal)
- : "r" (new_val), "Ir" (old)
- :"memory");
- return was_equal;
- }
-# else /* !__GNUC__ */
- inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
- GC_word old, GC_word new_val)
- {
- return __CMP_STORE_QUAD(addr, old, new_val, addr);
- }
-# endif /* !__GNUC__ */
-# endif /* !GENERIC_COMPARE_AND_SWAP */
-# ifdef __GNUC__
- inline static void GC_memory_barrier()
- {
- __asm__ __volatile__("mb" : : : "memory");
- }
-# else
-# define GC_memory_barrier() asm("mb")
-# endif /* !__GNUC__ */
-# endif /* ALPHA */
-# if defined(S390)
-# if !defined(GENERIC_COMPARE_AND_SWAP)
- inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
- GC_word old, GC_word new_val)
- {
- int retval;
- __asm__ __volatile__ (
-# ifndef __s390x__
- " cs %1,%2,0(%3)\n"
-# else
- " csg %1,%2,0(%3)\n"
-# endif
- " ipm %0\n"
- " srl %0,28\n"
- : "=&d" (retval), "+d" (old)
- : "d" (new_val), "a" (addr)
- : "cc", "memory");
- return retval == 0;
- }
-# endif
-# endif
-# if !defined(GENERIC_COMPARE_AND_SWAP)
- /* Returns the original value of *addr. */
- inline static GC_word GC_atomic_add(volatile GC_word *addr,
- GC_word how_much)
- {
- GC_word old;
- do {
- old = *addr;
- } while (!GC_compare_and_exchange(addr, old, old+how_much));
- return old;
- }
-# else /* GENERIC_COMPARE_AND_SWAP */
- /* So long as a GC_word can be atomically updated, it should */
- /* be OK to read *addr without a lock. */
- extern GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much);
-# endif /* GENERIC_COMPARE_AND_SWAP */
-
-# endif /* PARALLEL_MARK */
+# define NO_THREAD ((unsigned long)(-1l))
+ /* != NUMERIC_THREAD_ID(pthread_self()) for any thread */
# if !defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_LOCKS)
- /* In the THREAD_LOCAL_ALLOC case, the allocation lock tends to */
- /* be held for long periods, if it is held at all. Thus spinning */
- /* and sleeping for fixed periods are likely to result in */
+ /* In the THREAD_LOCAL_ALLOC case, the allocation lock tends to */
+ /* be held for long periods, if it is held at all. Thus spinning */
+ /* and sleeping for fixed periods are likely to result in */
/* significant wasted time. We thus rely mostly on queued locks. */
# define USE_SPIN_LOCK
- extern volatile unsigned int GC_allocate_lock;
- extern void GC_lock(void);
- /* Allocation lock holder. Only set if acquired by client through */
- /* GC_call_with_alloc_lock. */
+ GC_EXTERN volatile AO_TS_t GC_allocate_lock;
+ GC_INNER void GC_lock(void);
+ /* Allocation lock holder. Only set if acquired by client through */
+ /* GC_call_with_alloc_lock. */
# ifdef GC_ASSERTIONS
-# define LOCK() \
- { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); \
- SET_LOCK_HOLDER(); }
-# define UNLOCK() \
- { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
- GC_clear(&GC_allocate_lock); }
+# define UNCOND_LOCK() \
+ { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
+ GC_lock(); \
+ SET_LOCK_HOLDER(); }
+# define UNCOND_UNLOCK() \
+ { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
+ AO_CLEAR(&GC_allocate_lock); }
# else
-# define LOCK() \
- { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
-# define UNLOCK() \
- GC_clear(&GC_allocate_lock)
+# define UNCOND_LOCK() \
+ { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
+ GC_lock(); }
+# define UNCOND_UNLOCK() AO_CLEAR(&GC_allocate_lock)
# endif /* !GC_ASSERTIONS */
-# if 0
- /* Another alternative for OSF1 might be: */
-# include <sys/mman.h>
- extern msemaphore GC_allocate_semaphore;
-# define LOCK() { if (msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) \
- != 0) GC_lock(); else GC_allocate_lock = 1; }
- /* The following is INCORRECT, since the memory model is too weak. */
- /* Is this true? Presumably msem_unlock has the right semantics? */
- /* - HB */
-# define UNLOCK() { GC_allocate_lock = 0; \
- msem_unlock(&GC_allocate_semaphore, 0); }
-# endif /* 0 */
-# else /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */
+# else /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */
# ifndef USE_PTHREAD_LOCKS
# define USE_PTHREAD_LOCKS
# endif
-# endif /* THREAD_LOCAL_ALLOC */
-# ifdef USE_PTHREAD_LOCKS
+# endif /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */
+# ifdef USE_PTHREAD_LOCKS
# include <pthread.h>
- extern pthread_mutex_t GC_allocate_ml;
+ GC_EXTERN pthread_mutex_t GC_allocate_ml;
# ifdef GC_ASSERTIONS
-# define LOCK() \
- { GC_lock(); \
- SET_LOCK_HOLDER(); }
-# define UNLOCK() \
- { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
- pthread_mutex_unlock(&GC_allocate_ml); }
+# define UNCOND_LOCK() { GC_lock(); SET_LOCK_HOLDER(); }
+# define UNCOND_UNLOCK() \
+ { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
+ pthread_mutex_unlock(&GC_allocate_ml); }
# else /* !GC_ASSERTIONS */
# if defined(NO_PTHREAD_TRYLOCK)
-# define LOCK() GC_lock();
-# else /* !defined(NO_PTHREAD_TRYLOCK) */
-# define LOCK() \
- { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
+# ifdef USE_SPIN_LOCK
+# define UNCOND_LOCK() GC_lock()
+# else
+# define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml)
+# endif
+# else
+# define UNCOND_LOCK() \
+ { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) \
+ GC_lock(); }
# endif
-# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
+# define UNCOND_UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
# endif /* !GC_ASSERTIONS */
-# endif /* USE_PTHREAD_LOCKS */
-# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
-# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
-# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
- extern VOLATILE GC_bool GC_collecting;
-# define ENTER_GC() GC_collecting = 1;
-# define EXIT_GC() GC_collecting = 0;
- extern void GC_lock(void);
- extern pthread_t GC_lock_holder;
-# ifdef GC_ASSERTIONS
- extern pthread_t GC_mark_lock_holder;
-# endif
-# endif /* GC_PTHREADS with linux_threads.c implementation */
-# if defined(GC_IRIX_THREADS)
-# include <pthread.h>
- /* This probably should never be included, but I can't test */
- /* on Irix anymore. */
-# include <mutex.h>
-
- extern volatile unsigned int GC_allocate_lock;
- /* This is not a mutex because mutexes that obey the (optional) */
- /* POSIX scheduling rules are subject to convoys in high contention */
- /* applications. This is basically a spin lock. */
- extern pthread_t GC_lock_holder;
- extern void GC_lock(void);
- /* Allocation lock holder. Only set if acquired by client through */
- /* GC_call_with_alloc_lock. */
-# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
-# define NO_THREAD (pthread_t)(-1)
+# endif /* USE_PTHREAD_LOCKS */
+# define SET_LOCK_HOLDER() \
+ GC_lock_holder = NUMERIC_THREAD_ID(pthread_self())
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
-# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
-# define LOCK() { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
-# define UNLOCK() GC_clear(&GC_allocate_lock);
- extern VOLATILE GC_bool GC_collecting;
-# define ENTER_GC() \
- { \
- GC_collecting = 1; \
- }
-# define EXIT_GC() GC_collecting = 0;
-# endif /* GC_IRIX_THREADS */
-# if defined(GC_WIN32_THREADS)
-# if defined(GC_PTHREADS)
-# include <pthread.h>
- extern pthread_mutex_t GC_allocate_ml;
-# define LOCK() pthread_mutex_lock(&GC_allocate_ml)
-# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
+# define I_HOLD_LOCK() \
+ (!GC_need_to_lock || \
+ GC_lock_holder == NUMERIC_THREAD_ID(pthread_self()))
+# ifndef NUMERIC_THREAD_ID_UNIQUE
+# define I_DONT_HOLD_LOCK() 1 /* Conservatively say yes */
# else
-# include <windows.h>
- GC_API CRITICAL_SECTION GC_allocate_ml;
-# define LOCK() EnterCriticalSection(&GC_allocate_ml);
-# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
+# define I_DONT_HOLD_LOCK() \
+ (!GC_need_to_lock \
+ || GC_lock_holder != NUMERIC_THREAD_ID(pthread_self()))
# endif
-# endif
-# ifndef SET_LOCK_HOLDER
-# define SET_LOCK_HOLDER()
-# define UNSET_LOCK_HOLDER()
-# define I_HOLD_LOCK() FALSE
- /* Used on platforms were locks can be reacquired, */
- /* so it doesn't matter if we lie. */
-# endif
+ GC_EXTERN volatile GC_bool GC_collecting;
+# define ENTER_GC() GC_collecting = 1;
+# define EXIT_GC() GC_collecting = 0;
+ GC_INNER void GC_lock(void);
+ GC_EXTERN unsigned long GC_lock_holder;
+# if defined(GC_ASSERTIONS) && defined(PARALLEL_MARK)
+ GC_EXTERN unsigned long GC_mark_lock_holder;
+# endif
+# endif /* GC_PTHREADS with linux_threads.c implementation */
+ GC_EXTERN GC_bool GC_need_to_lock;
+
# else /* !THREADS */
-# define LOCK()
-# define UNLOCK()
-# endif /* !THREADS */
-# ifndef SET_LOCK_HOLDER
+# define LOCK()
+# define UNLOCK()
# define SET_LOCK_HOLDER()
# define UNSET_LOCK_HOLDER()
-# define I_HOLD_LOCK() FALSE
- /* Used on platforms were locks can be reacquired, */
- /* so it doesn't matter if we lie. */
+# define I_HOLD_LOCK() TRUE
+# define I_DONT_HOLD_LOCK() TRUE
+ /* Used only in positive assertions or to test whether */
+ /* we still need to acquire the lock. TRUE works in */
+ /* either case. */
+# endif /* !THREADS */
+
+#if defined(UNCOND_LOCK) && !defined(LOCK)
+# ifdef LINT2
+ /* Instruct code analysis tools not to care about GC_need_to_lock */
+ /* influence to LOCK/UNLOCK semantic. */
+# define LOCK() UNCOND_LOCK()
+# define UNLOCK() UNCOND_UNLOCK()
+# else
+ /* At least two thread running; need to lock. */
+# define LOCK() { if (GC_need_to_lock) UNCOND_LOCK(); }
+# define UNLOCK() { if (GC_need_to_lock) UNCOND_UNLOCK(); }
# endif
+#endif
+
# ifndef ENTER_GC
# define ENTER_GC()
# define EXIT_GC()
@@ -659,10 +213,5 @@
# ifndef DCL_LOCK_STATE
# define DCL_LOCK_STATE
# endif
-# ifndef FASTLOCK
-# define FASTLOCK() LOCK()
-# define FASTLOCK_SUCCEEDED() TRUE
-# define FASTUNLOCK() UNLOCK()
-# endif
#endif /* GC_LOCKS_H */
diff --git a/boehm-gc/include/private/gc_pmark.h b/boehm-gc/include/private/gc_pmark.h
index 51981914dc5..def4a91799d 100644
--- a/boehm-gc/include/private/gc_pmark.h
+++ b/boehm-gc/include/private/gc_pmark.h
@@ -18,65 +18,76 @@
/*
* Declarations of mark stack. Needed by marker and client supplied mark
* routines. Transitively include gc_priv.h.
- * (Note that gc_priv.h should not be included before this, since this
- * includes dbg_mlc.h, which wants to include gc_priv.h AFTER defining
- * I_HIDE_POINTERS.)
*/
#ifndef GC_PMARK_H
-# define GC_PMARK_H
-
-# if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST)
-# include "dbg_mlc.h"
-# endif
-# ifndef GC_MARK_H
-# include "../gc_mark.h"
-# endif
-# ifndef GC_PRIVATE_H
-# include "gc_priv.h"
-# endif
-
-/* The real declarations of the following is in gc_priv.h, so that */
-/* we can avoid scanning the following table. */
+#define GC_PMARK_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef GC_BUILD
+# define GC_BUILD
+#endif
+
+#if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST)
+# include "dbg_mlc.h"
+#endif
+
+#ifndef GC_MARK_H
+# include "../gc_mark.h"
+#endif
+
+#ifndef GC_PRIVATE_H
+# include "gc_priv.h"
+#endif
+
+/* The real declarations of the following is in gc_priv.h, so that */
+/* we can avoid scanning the following table. */
/*
-extern mark_proc GC_mark_procs[MAX_MARK_PROCS];
+mark_proc GC_mark_procs[MAX_MARK_PROCS];
*/
+#ifndef MARK_DESCR_OFFSET
+# define MARK_DESCR_OFFSET sizeof(word)
+#endif
+
/*
* Mark descriptor stuff that should remain private for now, mostly
* because it's hard to export WORDSZ without including gcconfig.h.
*/
-# define BITMAP_BITS (WORDSZ - GC_DS_TAG_BITS)
-# define PROC(descr) \
- (GC_mark_procs[((descr) >> GC_DS_TAG_BITS) & (GC_MAX_MARK_PROCS-1)])
-# define ENV(descr) \
- ((descr) >> (GC_DS_TAG_BITS + GC_LOG_MAX_MARK_PROCS))
-# define MAX_ENV \
- (((word)1 << (WORDSZ - GC_DS_TAG_BITS - GC_LOG_MAX_MARK_PROCS)) - 1)
-
+#define BITMAP_BITS (WORDSZ - GC_DS_TAG_BITS)
+#define PROC(descr) \
+ (GC_mark_procs[((descr) >> GC_DS_TAG_BITS) & (GC_MAX_MARK_PROCS-1)])
+#define ENV(descr) \
+ ((descr) >> (GC_DS_TAG_BITS + GC_LOG_MAX_MARK_PROCS))
+#define MAX_ENV \
+ (((word)1 << (WORDSZ - GC_DS_TAG_BITS - GC_LOG_MAX_MARK_PROCS)) - 1)
-extern word GC_n_mark_procs;
+GC_EXTERN unsigned GC_n_mark_procs;
-/* Number of mark stack entries to discard on overflow. */
+/* Number of mark stack entries to discard on overflow. */
#define GC_MARK_STACK_DISCARDS (INITIAL_MARK_STACK_SIZE/8)
typedef struct GC_ms_entry {
- GC_word * mse_start; /* First word of object */
- GC_word mse_descr; /* Descriptor; low order two bits are tags, */
- /* identifying the upper 30 bits as one of the */
- /* following: */
+ ptr_t mse_start; /* First word of object, word aligned. */
+ union word_ptr_ao_u mse_descr;
+ /* Descriptor; low order two bits are tags, */
+ /* as described in gc_mark.h. */
} mse;
-extern word GC_mark_stack_size;
+GC_EXTERN size_t GC_mark_stack_size;
-extern mse * GC_mark_stack_limit;
+GC_EXTERN mse * GC_mark_stack_limit;
#ifdef PARALLEL_MARK
- extern mse * VOLATILE GC_mark_stack_top;
+ GC_EXTERN mse * volatile GC_mark_stack_top;
+ /* FIXME: Use union to avoid casts to AO_t */
#else
- extern mse * GC_mark_stack_top;
+ GC_EXTERN mse * GC_mark_stack_top;
#endif
-extern mse * GC_mark_stack;
+GC_EXTERN mse * GC_mark_stack;
#ifdef PARALLEL_MARK
/*
@@ -84,19 +95,19 @@ extern mse * GC_mark_stack;
* This works roughly as follows:
* The main mark stack never shrinks, but it can grow.
*
- * The initiating threads holds the GC lock, and sets GC_help_wanted.
- *
+ * The initiating threads holds the GC lock, and sets GC_help_wanted.
+ *
* Other threads:
* 1) update helper_count (while holding mark_lock.)
- * 2) allocate a local mark stack
+ * 2) allocate a local mark stack
* repeatedly:
- * 3) Steal a global mark stack entry by atomically replacing
- * its descriptor with 0.
- * 4) Copy it to the local stack.
- * 5) Mark on the local stack until it is empty, or
- * it may be profitable to copy it back.
- * 6) If necessary, copy local stack to global one,
- * holding mark lock.
+ * 3) Steal a global mark stack entry by atomically replacing
+ * its descriptor with 0.
+ * 4) Copy it to the local stack.
+ * 5) Mark on the local stack until it is empty, or
+ * it may be profitable to copy it back.
+ * 6) If necessary, copy local stack to global one,
+ * holding mark lock.
* 7) Stop when the global mark stack is empty.
* 8) decrement helper_count (holding mark_lock).
*
@@ -104,24 +115,9 @@ extern mse * GC_mark_stack;
* of the University of Tokyo SGC in a less intrusive, though probably
* also less performant, way.
*/
- void GC_do_parallel_mark();
- /* inititate parallel marking. */
-
- extern GC_bool GC_help_wanted; /* Protected by mark lock */
- extern unsigned GC_helper_count; /* Number of running helpers. */
- /* Protected by mark lock */
- extern unsigned GC_active_count; /* Number of active helpers. */
- /* Protected by mark lock */
- /* May increase and decrease */
- /* within each mark cycle. But */
- /* once it returns to 0, it */
- /* stays zero for the cycle. */
- /* GC_mark_stack_top is also protected by mark lock. */
- extern mse * VOLATILE GC_first_nonempty;
- /* Lowest entry on mark stack */
- /* that may be nonempty. */
- /* Updated only by initiating */
- /* thread. */
+
+ /* GC_mark_stack_top is protected by mark lock. */
+
/*
* GC_notify_all_marker() is used when GC_help_wanted is first set,
* when the last helper becomes inactive,
@@ -132,146 +128,242 @@ extern mse * GC_mark_stack;
*/
#endif /* PARALLEL_MARK */
-/* Return a pointer to within 1st page of object. */
-/* Set *new_hdr_p to corr. hdr. */
-#ifdef __STDC__
- ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
-#else
- ptr_t GC_find_start();
-#endif
-
-mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp));
-
-# ifdef GATHERSTATS
-# define ADD_TO_ATOMIC(sz) GC_atomic_in_use += (sz)
-# define ADD_TO_COMPOSITE(sz) GC_composite_in_use += (sz)
-# else
-# define ADD_TO_ATOMIC(sz)
-# define ADD_TO_COMPOSITE(sz)
-# endif
+GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
-/* Push the object obj with corresponding heap block header hhdr onto */
-/* the mark stack. */
-# define PUSH_OBJ(obj, hhdr, mark_stack_top, mark_stack_limit) \
+/* Push the object obj with corresponding heap block header hhdr onto */
+/* the mark stack. */
+#define PUSH_OBJ(obj, hhdr, mark_stack_top, mark_stack_limit) \
{ \
register word _descr = (hhdr) -> hb_descr; \
- \
- if (_descr == 0) { \
- ADD_TO_ATOMIC((hhdr) -> hb_sz); \
- } else { \
- ADD_TO_COMPOSITE((hhdr) -> hb_sz); \
+ GC_ASSERT(!HBLK_IS_FREE(hhdr)); \
+ if (_descr != 0) { \
mark_stack_top++; \
- if (mark_stack_top >= mark_stack_limit) { \
+ if ((word)mark_stack_top >= (word)(mark_stack_limit)) { \
mark_stack_top = GC_signal_mark_stack_overflow(mark_stack_top); \
} \
mark_stack_top -> mse_start = (obj); \
- mark_stack_top -> mse_descr = _descr; \
+ mark_stack_top -> mse_descr.w = _descr; \
} \
}
-/* Push the contents of current onto the mark stack if it is a valid */
-/* ptr to a currently unmarked object. Mark it. */
-/* If we assumed a standard-conforming compiler, we could probably */
-/* generate the exit_label transparently. */
-# define PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, \
- source, exit_label) \
+/* Push the contents of current onto the mark stack if it is a valid */
+/* ptr to a currently unmarked object. Mark it. */
+/* If we assumed a standard-conforming compiler, we could probably */
+/* generate the exit_label transparently. */
+#define PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, \
+ source, exit_label) \
{ \
hdr * my_hhdr; \
- ptr_t my_current = current; \
- \
- GET_HDR(my_current, my_hhdr); \
- if (IS_FORWARDING_ADDR_OR_NIL(my_hhdr)) { \
- hdr * new_hdr = GC_invalid_header; \
- my_current = GC_find_start(my_current, my_hhdr, &new_hdr); \
- my_hhdr = new_hdr; \
- } \
- PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \
- source, exit_label, my_hhdr); \
+ HC_GET_HDR(current, my_hhdr, source, exit_label); \
+ PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
+ source, exit_label, my_hhdr, TRUE); \
exit_label: ; \
}
-/* As above, but use header cache for header lookup. */
-# define HC_PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, \
- source, exit_label) \
-{ \
- hdr * my_hhdr; \
- ptr_t my_current = current; \
- \
- HC_GET_HDR(my_current, my_hhdr, source); \
- PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \
- source, exit_label, my_hhdr); \
-exit_label: ; \
-}
-
-/* Set mark bit, exit if it was already set. */
-
-# ifdef USE_MARK_BYTES
- /* Unlike the mark bit case, there is a race here, and we may set */
- /* the bit twice in the concurrent case. This can result in the */
- /* object being pushed twice. But that's only a performance issue. */
-# define SET_MARK_BIT_EXIT_IF_SET(hhdr,displ,exit_label) \
+/* Set mark bit, exit if it was already set. */
+#ifdef USE_MARK_BYTES
+ /* There is a race here, and we may set */
+ /* the bit twice in the concurrent case. This can result in the */
+ /* object being pushed twice. But that's only a performance issue. */
+# define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
{ \
- register VOLATILE char * mark_byte_addr = \
- hhdr -> hb_marks + ((displ) >> 1); \
- register char mark_byte = *mark_byte_addr; \
- \
- if (mark_byte) goto exit_label; \
- *mark_byte_addr = 1; \
- }
+ char * mark_byte_addr = (char *)hhdr -> hb_marks + (bit_no); \
+ if (*mark_byte_addr) goto exit_label; \
+ *mark_byte_addr = 1; \
+ }
+#else
+# ifdef PARALLEL_MARK
+ /* This is used only if we explicitly set USE_MARK_BITS. */
+ /* The following may fail to exit even if the bit was already set. */
+ /* For our uses, that's benign: */
+# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
+ { \
+ if (!(*(addr) & (bits))) { \
+ AO_or((volatile AO_t *)(addr), (AO_t)(bits)); \
+ } else { \
+ goto exit_label; \
+ } \
+ }
# else
-# define SET_MARK_BIT_EXIT_IF_SET(hhdr,displ,exit_label) \
+# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
+ { \
+ word old = *(addr); \
+ word my_bits = (bits); \
+ if (old & my_bits) goto exit_label; \
+ *(addr) = (old | my_bits); \
+ }
+# endif /* !PARALLEL_MARK */
+# define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
{ \
- register word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(displ); \
- \
- OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(displ), \
- exit_label); \
- }
-# endif /* USE_MARK_BYTES */
-
-/* If the mark bit corresponding to current is not set, set it, and */
-/* push the contents of the object on the mark stack. For a small */
-/* object we assume that current is the (possibly interior) pointer */
-/* to the object. For large objects we assume that current points */
-/* to somewhere inside the first page of the object. If */
-/* GC_all_interior_pointers is set, it may have been previously */
-/* adjusted to make that true. */
+ word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(bit_no); \
+ OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(bit_no), \
+ exit_label); \
+ }
+#endif /* !USE_MARK_BYTES */
+
+#ifdef PARALLEL_MARK
+# define INCR_MARKS(hhdr) \
+ AO_store(&hhdr->hb_n_marks, AO_load(&hhdr->hb_n_marks) + 1)
+#else
+# define INCR_MARKS(hhdr) (void)(++hhdr->hb_n_marks)
+#endif
+
+#ifdef ENABLE_TRACE
+# define TRACE(source, cmd) \
+ if (GC_trace_addr != 0 && (ptr_t)(source) == GC_trace_addr) cmd
+# define TRACE_TARGET(target, cmd) \
+ if (GC_trace_addr != 0 && (target) == *(ptr_t *)GC_trace_addr) cmd
+#else
+# define TRACE(source, cmd)
+# define TRACE_TARGET(source, cmd)
+#endif
+
+#if defined(I386) && defined(__GNUC__)
+# define LONG_MULT(hprod, lprod, x, y) { \
+ __asm__ __volatile__("mull %2" : "=a"(lprod), "=d"(hprod) \
+ : "g"(y), "0"(x)); \
+ }
+#else
+# define LONG_MULT(hprod, lprod, x, y) { \
+ unsigned long long prod = (unsigned long long)(x) \
+ * (unsigned long long)(y); \
+ hprod = prod >> 32; \
+ lprod = (unsigned32)prod; \
+ }
+#endif /* !I386 */
+
+/* If the mark bit corresponding to current is not set, set it, and */
+/* push the contents of the object on the mark stack. Current points */
+/* to the beginning of the object. We rely on the fact that the */
+/* preceding header calculation will succeed for a pointer past the */
+/* 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 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, \
+ source, exit_label, hhdr, do_offset_check) \
+{ \
+ size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
+ /* displ is always within range. If current doesn't point to */ \
+ /* first block, then we are in the all_interior_pointers case, and */ \
+ /* it is safe to use any displacement value. */ \
+ size_t gran_displ = BYTES_TO_GRANULES(displ); \
+ size_t gran_offset = hhdr -> hb_map[gran_displ]; \
+ size_t byte_offset = displ & (GRANULE_BYTES - 1); \
+ ptr_t base = current; \
+ /* The following always fails for large block references. */ \
+ if (EXPECT((gran_offset | byte_offset) != 0, FALSE)) { \
+ if (hhdr -> hb_large_block) { \
+ /* gran_offset is bogus. */ \
+ size_t obj_displ; \
+ base = (ptr_t)(hhdr -> hb_block); \
+ obj_displ = (ptr_t)(current) - base; \
+ if (obj_displ != displ) { \
+ GC_ASSERT(obj_displ < hhdr -> hb_sz); \
+ /* Must be in all_interior_pointer case, not first block */ \
+ /* already did validity check on cache miss. */ \
+ } else { \
+ if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
+ GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
+ goto exit_label; \
+ } \
+ } \
+ gran_displ = 0; \
+ GC_ASSERT(hhdr -> hb_sz > HBLKSIZE || \
+ hhdr -> hb_block == HBLKPTR(current)); \
+ GC_ASSERT((word)hhdr->hb_block <= (word)(current)); \
+ } else { \
+ size_t obj_displ = GRANULES_TO_BYTES(gran_offset) \
+ + byte_offset; \
+ if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
+ GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
+ goto exit_label; \
+ } \
+ gran_displ -= gran_offset; \
+ base -= obj_displ; \
+ } \
+ } \
+ GC_ASSERT(hhdr == GC_find_header(base)); \
+ GC_ASSERT(gran_displ % BYTES_TO_GRANULES(hhdr -> hb_sz) == 0); \
+ TRACE(source, GC_log_printf("GC:%u: passed validity tests\n", \
+ (unsigned)GC_gc_no)); \
+ SET_MARK_BIT_EXIT_IF_SET(hhdr, gran_displ, exit_label); \
+ TRACE(source, GC_log_printf("GC:%u: previously unmarked\n", \
+ (unsigned)GC_gc_no)); \
+ TRACE_TARGET(base, \
+ GC_log_printf("GC:%u: marking %p from %p instead\n", \
+ (unsigned)GC_gc_no, base, source)); \
+ INCR_MARKS(hhdr); \
+ GC_STORE_BACK_PTR((ptr_t)source, base); \
+ PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
+}
+#endif /* MARK_BIT_PER_GRANULE */
+
+#ifdef MARK_BIT_PER_OBJ
# define PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
- source, exit_label, hhdr) \
+ source, exit_label, hhdr, do_offset_check) \
{ \
- int displ; /* Displacement in block; first bytes, then words */ \
- int map_entry; \
- \
- displ = HBLKDISPL(current); \
- map_entry = MAP_ENTRY((hhdr -> hb_map), displ); \
- displ = BYTES_TO_WORDS(displ); \
- if (map_entry > CPP_MAX_OFFSET) { \
- if (map_entry == OFFSET_TOO_BIG) { \
- map_entry = displ % (hhdr -> hb_sz); \
- displ -= map_entry; \
- if (displ + (hhdr -> hb_sz) > BYTES_TO_WORDS(HBLKSIZE)) { \
- GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); \
- goto exit_label; \
- } \
- } else { \
- GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); goto exit_label; \
- } \
- } else { \
- displ -= map_entry; \
+ size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
+ unsigned32 low_prod, high_prod; \
+ unsigned32 inv_sz = hhdr -> hb_inv_sz; \
+ ptr_t base = current; \
+ LONG_MULT(high_prod, low_prod, displ, inv_sz); \
+ /* product is > and within sz_in_bytes of displ * sz_in_bytes * 2**32 */ \
+ if (EXPECT(low_prod >> 16 != 0, FALSE)) { \
+ FIXME: fails if offset is a multiple of HBLKSIZE which becomes 0 \
+ if (inv_sz == LARGE_INV_SZ) { \
+ size_t obj_displ; \
+ base = (ptr_t)(hhdr -> hb_block); \
+ obj_displ = (ptr_t)(current) - base; \
+ if (obj_displ != displ) { \
+ GC_ASSERT(obj_displ < hhdr -> hb_sz); \
+ /* Must be in all_interior_pointer case, not first block */ \
+ /* already did validity check on cache miss. */ \
+ } else { \
+ if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
+ GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
+ goto exit_label; \
+ } \
+ } \
+ GC_ASSERT(hhdr -> hb_sz > HBLKSIZE || \
+ hhdr -> hb_block == HBLKPTR(current)); \
+ GC_ASSERT((word)hhdr->hb_block < (word)(current)); \
+ } else { \
+ /* Accurate enough if HBLKSIZE <= 2**15. */ \
+ GC_STATIC_ASSERT(HBLKSIZE <= (1 << 15)); \
+ size_t obj_displ = (((low_prod >> 16) + 1) * (hhdr->hb_sz)) >> 16; \
+ if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
+ GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
+ goto exit_label; \
+ } \
+ base -= obj_displ; \
+ } \
} \
- GC_ASSERT(displ >= 0 && displ < MARK_BITS_PER_HBLK); \
- SET_MARK_BIT_EXIT_IF_SET(hhdr, displ, exit_label); \
- GC_STORE_BACK_PTR((ptr_t)source, (ptr_t)HBLKPTR(current) \
- + WORDS_TO_BYTES(displ)); \
- PUSH_OBJ(((word *)(HBLKPTR(current)) + displ), hhdr, \
- mark_stack_top, mark_stack_limit) \
+ /* May get here for pointer to start of block not at */ \
+ /* beginning of object. If so, it's valid, and we're fine. */ \
+ GC_ASSERT(high_prod >= 0 && high_prod <= HBLK_OBJS(hhdr -> hb_sz)); \
+ TRACE(source, GC_log_printf("GC:%u: passed validity tests\n", \
+ (unsigned)GC_gc_no)); \
+ SET_MARK_BIT_EXIT_IF_SET(hhdr, high_prod, exit_label); \
+ TRACE(source, GC_log_printf("GC:%u: previously unmarked\n", \
+ (unsigned)GC_gc_no)); \
+ TRACE_TARGET(base, \
+ GC_log_printf("GC:%u: marking %p from %p instead\n", \
+ (unsigned)GC_gc_no, base, source)); \
+ INCR_MARKS(hhdr); \
+ GC_STORE_BACK_PTR((ptr_t)source, base); \
+ PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
}
+#endif /* MARK_BIT_PER_OBJ */
#if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
-# define PUSH_ONE_CHECKED_STACK(p, source) \
- GC_mark_and_push_stack(p, (ptr_t)(source))
+# define PUSH_ONE_CHECKED_STACK(p, source) \
+ GC_mark_and_push_stack((ptr_t)(p), (ptr_t)(source))
#else
-# define PUSH_ONE_CHECKED_STACK(p, source) \
- GC_mark_and_push_stack(p)
+# define PUSH_ONE_CHECKED_STACK(p, source) \
+ GC_mark_and_push_stack((ptr_t)(p))
#endif
/*
@@ -282,57 +374,59 @@ exit_label: ; \
* if the mark stack overflows.
*/
-# if NEED_FIXUP_POINTER
- /* Try both the raw version and the fixed up one. */
-# define GC_PUSH_ONE_STACK(p, source) \
- if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
- && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
- PUSH_ONE_CHECKED_STACK(p, source); \
+#if NEED_FIXUP_POINTER
+ /* Try both the raw version and the fixed up one. */
+# define GC_PUSH_ONE_STACK(p, source) \
+ if ((word)(p) >= (word)GC_least_plausible_heap_addr \
+ && (word)(p) < (word)GC_greatest_plausible_heap_addr) { \
+ PUSH_ONE_CHECKED_STACK(p, source); \
} \
FIXUP_POINTER(p); \
- if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
- && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
- PUSH_ONE_CHECKED_STACK(p, source); \
+ if ((word)(p) >= (word)GC_least_plausible_heap_addr \
+ && (word)(p) < (word)GC_greatest_plausible_heap_addr) { \
+ PUSH_ONE_CHECKED_STACK(p, source); \
}
-# else /* !NEED_FIXUP_POINTER */
-# define GC_PUSH_ONE_STACK(p, source) \
- if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
- && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
- PUSH_ONE_CHECKED_STACK(p, source); \
+#else /* !NEED_FIXUP_POINTER */
+# define GC_PUSH_ONE_STACK(p, source) \
+ if ((word)(p) >= (word)GC_least_plausible_heap_addr \
+ && (word)(p) < (word)GC_greatest_plausible_heap_addr) { \
+ PUSH_ONE_CHECKED_STACK(p, source); \
}
-# endif
-
+#endif
-/*
- * As above, but interior pointer recognition as for
- * normal for heap pointers.
- */
-# define GC_PUSH_ONE_HEAP(p,source) \
- FIXUP_POINTER(p); \
- if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
- && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
- GC_mark_stack_top = GC_mark_and_push( \
- (GC_PTR)(p), GC_mark_stack_top, \
- GC_mark_stack_limit, (GC_PTR *)(source)); \
+/* As above, but interior pointer recognition as for normal heap pointers. */
+#define GC_PUSH_ONE_HEAP(p,source,mark_stack_top) \
+ { \
+ FIXUP_POINTER(p); \
+ if ((word)(p) >= (word)GC_least_plausible_heap_addr \
+ && (word)(p) < (word)GC_greatest_plausible_heap_addr) \
+ mark_stack_top = GC_mark_and_push((void *)(p), mark_stack_top, \
+ GC_mark_stack_limit, (void * *)(source)); \
}
-/* Mark starting at mark stack entry top (incl.) down to */
-/* mark stack entry bottom (incl.). Stop after performing */
-/* about one page worth of work. Return the new mark stack */
-/* top entry. */
-mse * GC_mark_from GC_PROTO((mse * top, mse * bottom, mse *limit));
+/* Mark starting at mark stack entry top (incl.) down to */
+/* mark stack entry bottom (incl.). Stop after performing */
+/* about one page worth of work. Return the new mark stack */
+/* top entry. */
+GC_INNER mse * GC_mark_from(mse * top, mse * bottom, mse *limit);
#define MARK_FROM_MARK_STACK() \
- GC_mark_stack_top = GC_mark_from(GC_mark_stack_top, \
- GC_mark_stack, \
- GC_mark_stack + GC_mark_stack_size);
+ GC_mark_stack_top = GC_mark_from(GC_mark_stack_top, \
+ GC_mark_stack, \
+ GC_mark_stack + GC_mark_stack_size);
+
+#define GC_mark_stack_empty() ((word)GC_mark_stack_top < (word)GC_mark_stack)
/*
* Mark from one finalizable object using the specified
- * mark proc. May not mark the object pointed to by
- * real_ptr. That is the job of the caller, if appropriate
+ * mark proc. May not mark the object pointed to by
+ * real_ptr. That is the job of the caller, if appropriate.
+ * Note that this is called with the mutator running, but
+ * with us holding the allocation lock. This is safe only if the
+ * mutator needs the allocation lock to reveal hidden pointers.
+ * FIXME: Why do we need the GC_mark_state test below?
*/
-# define GC_MARK_FO(real_ptr, mark_proc) \
+#define GC_MARK_FO(real_ptr, mark_proc) \
{ \
(*(mark_proc))(real_ptr); \
while (!GC_mark_stack_empty()) MARK_FROM_MARK_STACK(); \
@@ -342,51 +436,49 @@ mse * GC_mark_from GC_PROTO((mse * top, mse * bottom, mse *limit));
} \
}
-extern GC_bool GC_mark_stack_too_small;
- /* We need a larger mark stack. May be */
- /* set by client supplied mark routines.*/
+GC_EXTERN GC_bool GC_mark_stack_too_small;
+ /* We need a larger mark stack. May be */
+ /* set by client supplied mark routines.*/
-typedef int mark_state_t; /* Current state of marking, as follows:*/
- /* Used to remember where we are during */
- /* concurrent marking. */
+typedef int mark_state_t; /* Current state of marking, as follows:*/
+ /* Used to remember where we are during */
+ /* concurrent marking. */
- /* We say something is dirty if it was */
- /* written since the last time we */
- /* retrieved dirty bits. We say it's */
- /* grungy if it was marked dirty in the */
- /* last set of bits we retrieved. */
-
- /* Invariant I: all roots and marked */
- /* objects p are either dirty, or point */
- /* to objects q that are either marked */
- /* or a pointer to q appears in a range */
- /* on the mark stack. */
+ /* We say something is dirty if it was */
+ /* written since the last time we */
+ /* retrieved dirty bits. We say it's */
+ /* grungy if it was marked dirty in the */
+ /* last set of bits we retrieved. */
-# define MS_NONE 0 /* No marking in progress. I holds. */
- /* Mark stack is empty. */
+ /* Invariant I: all roots and marked */
+ /* objects p are either dirty, or point */
+ /* to objects q that are either marked */
+ /* or a pointer to q appears in a range */
+ /* on the mark stack. */
-# define MS_PUSH_RESCUERS 1 /* Rescuing objects are currently */
- /* being pushed. I holds, except */
- /* that grungy roots may point to */
- /* unmarked objects, as may marked */
- /* grungy objects above scan_ptr. */
+#define MS_NONE 0 /* No marking in progress. I holds. */
+ /* Mark stack is empty. */
-# define MS_PUSH_UNCOLLECTABLE 2
- /* I holds, except that marked */
- /* uncollectable objects above scan_ptr */
- /* may point to unmarked objects. */
- /* Roots may point to unmarked objects */
+#define MS_PUSH_RESCUERS 1 /* Rescuing objects are currently */
+ /* being pushed. I holds, except */
+ /* that grungy roots may point to */
+ /* unmarked objects, as may marked */
+ /* grungy objects above scan_ptr. */
-# define MS_ROOTS_PUSHED 3 /* I holds, mark stack may be nonempty */
+#define MS_PUSH_UNCOLLECTABLE 2 /* I holds, except that marked */
+ /* uncollectable objects above scan_ptr */
+ /* may point to unmarked objects. */
+ /* Roots may point to unmarked objects */
-# define MS_PARTIALLY_INVALID 4 /* I may not hold, e.g. because of M.S. */
- /* overflow. However marked heap */
- /* objects below scan_ptr point to */
- /* marked or stacked objects. */
+#define MS_ROOTS_PUSHED 3 /* I holds, mark stack may be nonempty */
-# define MS_INVALID 5 /* I may not hold. */
+#define MS_PARTIALLY_INVALID 4 /* I may not hold, e.g. because of M.S. */
+ /* overflow. However marked heap */
+ /* objects below scan_ptr point to */
+ /* marked or stacked objects. */
-extern mark_state_t GC_mark_state;
+#define MS_INVALID 5 /* I may not hold. */
-#endif /* GC_PMARK_H */
+GC_EXTERN mark_state_t GC_mark_state;
+#endif /* GC_PMARK_H */
diff --git a/boehm-gc/include/private/gc_priv.h b/boehm-gc/include/private/gc_priv.h
index 08dd8ea247b..fb0d9644c15 100644
--- a/boehm-gc/include/private/gc_priv.h
+++ b/boehm-gc/include/private/gc_priv.h
@@ -1,8 +1,8 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
- * Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
*
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -14,96 +14,184 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-
-# ifndef GC_PRIVATE_H
-# define GC_PRIVATE_H
+#ifndef GC_PRIVATE_H
+#define GC_PRIVATE_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef GC_BUILD
+# define GC_BUILD
+#endif
+
+#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \
+ && !defined(_GNU_SOURCE)
+ /* Can't test LINUX, since this must be defined before other includes. */
+# define _GNU_SOURCE 1
+#endif
+
+#if (defined(DGUX) && defined(GC_THREADS) || defined(DGUX386_THREADS) \
+ || defined(GC_DGUX386_THREADS)) && !defined(_USING_POSIX4A_DRAFT10)
+# define _USING_POSIX4A_DRAFT10 1
+#endif
+
+# if defined(NO_DEBUGGING) && !defined(GC_ASSERTIONS) && !defined(NDEBUG)
+ /* To turn off assertion checking (in atomic_ops.h). */
+# define NDEBUG 1
+# endif
-#if defined(mips) && defined(SYSTYPE_BSD) && defined(sony_news)
- /* sony RISC NEWS, NEWSOS 4 */
-# define BSD_TIME
-/* typedef long ptrdiff_t; -- necessary on some really old systems */
+#ifndef GC_H
+# include "../gc.h"
#endif
-#if defined(mips) && defined(SYSTYPE_BSD43)
- /* MIPS RISCOS 4 */
-# define BSD_TIME
+#include <stdlib.h>
+#if !defined(sony_news)
+# include <stddef.h>
#endif
#ifdef DGUX
-# include <sys/types.h>
-# include <sys/time.h>
-# include <sys/resource.h>
+# include <sys/types.h>
+# include <sys/time.h>
+# include <sys/resource.h>
#endif /* DGUX */
#ifdef BSD_TIME
-# include <sys/types.h>
-# include <sys/time.h>
-# include <sys/resource.h>
+# include <sys/types.h>
+# include <sys/time.h>
+# include <sys/resource.h>
#endif /* BSD_TIME */
-# ifndef _GC_H
-# include "../gc.h"
+#ifdef PARALLEL_MARK
+# define AO_REQUIRE_CAS
+# if !defined(__GNUC__) && !defined(AO_ASSUME_WINDOWS98)
+# define AO_ASSUME_WINDOWS98
# endif
+#endif
-# ifndef GC_MARK_H
-# include "../gc_mark.h"
-# endif
+#ifndef GC_TINY_FL_H
+# include "../gc_tiny_fl.h"
+#endif
+
+#ifndef GC_MARK_H
+# include "../gc_mark.h"
+#endif
typedef GC_word word;
typedef GC_signed_word signed_word;
+typedef unsigned int unsigned32;
typedef int GC_bool;
-# define TRUE 1
-# define FALSE 0
+#define TRUE 1
+#define FALSE 0
-typedef char * ptr_t; /* A generic pointer to which we can add */
- /* byte displacements. */
- /* Preferably identical to caddr_t, if it */
- /* exists. */
-
-# ifndef GCCONFIG_H
-# include "gcconfig.h"
-# endif
+typedef char * ptr_t; /* A generic pointer to which we can add */
+ /* byte displacements and which can be used */
+ /* for address comparisons. */
-# ifndef HEADERS_H
-# include "gc_hdrs.h"
-# endif
+#ifndef GCCONFIG_H
+# include "gcconfig.h"
+#endif
-#if defined(__STDC__)
-# include <stdlib.h>
-# if !(defined( sony_news ) )
-# include <stddef.h>
-# endif
-# define VOLATILE volatile
-#else
-# ifdef MSWIN32
-# include <stdlib.h>
+#ifndef GC_INNER
+ /* This tagging macro must be used at the start of every variable */
+ /* definition which is declared with GC_EXTERN. Should be also used */
+ /* for the GC-scope function definitions and prototypes. Must not be */
+ /* used in gcconfig.h. Shouldn't be used for the debugging-only */
+ /* functions. Currently, not used for the functions declared in or */
+ /* called from the "dated" source files (pcr_interface.c and files */
+ /* located in the "extra" folder). */
+# if defined(GC_DLL) && defined(__GNUC__) && !defined(MSWIN32) \
+ && !defined(MSWINCE) && !defined(CYGWIN32)
+# if __GNUC__ >= 4
+ /* See the corresponding GC_API definition. */
+# define GC_INNER __attribute__((__visibility__("hidden")))
+# else
+ /* The attribute is unsupported. */
+# define GC_INNER /* empty */
# endif
-# define VOLATILE
+# else
+# define GC_INNER /* empty */
+# endif
+
+# define GC_EXTERN extern GC_INNER
+ /* Used only for the GC-scope variables (prefixed with "GC_") */
+ /* declared in the header files. Must not be used for thread-local */
+ /* variables. Must not be used in gcconfig.h. Shouldn't be used for */
+ /* the debugging-only or profiling-only variables. Currently, not */
+ /* used for the variables accessed from the "dated" source files */
+ /* (pcr_interface.c, specific.c/h, and in the "extra" folder). */
+ /* The corresponding variable definition must start with GC_INNER. */
+#endif /* !GC_INNER */
+
+#ifndef HEADERS_H
+# include "gc_hdrs.h"
#endif
-#if 0 /* defined(__GNUC__) doesn't work yet */
+#ifndef GC_ATTR_UNUSED
+# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# define GC_ATTR_UNUSED __attribute__((__unused__))
+# else
+# define GC_ATTR_UNUSED /* empty */
+# endif
+#endif /* !GC_ATTR_UNUSED */
+
+#if __GNUC__ >= 3 && !defined(LINT2)
# define EXPECT(expr, outcome) __builtin_expect(expr,outcome)
/* Equivalent to (expr), but predict that usually (expr)==outcome. */
#else
# define EXPECT(expr, outcome) (expr)
#endif /* __GNUC__ */
-# ifndef GC_LOCKS_H
-# include "gc_locks.h"
+#ifdef HAVE_CONFIG_H
+ /* The `inline' keyword as determined by Autoconf's `AC_C_INLINE'. */
+# define GC_INLINE static inline
+#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) || defined(__DMC__) \
+ || defined(__WATCOMC__)
+# define GC_INLINE static __inline
+#elif (__GNUC__ >= 3) || defined(__sun)
+# define GC_INLINE static inline
+#else
+# define GC_INLINE static
+#endif
+
+#ifndef GC_API_OSCALL
+ /* This is used to identify GC routines called by name from OS. */
+# if defined(__GNUC__)
+# if __GNUC__ >= 4
+ /* Same as GC_API if GC_DLL. */
+# define GC_API_OSCALL extern __attribute__((__visibility__("default")))
+# else
+ /* The attribute is unsupported. */
+# define GC_API_OSCALL extern
+# endif
+# else
+# define GC_API_OSCALL GC_API
# endif
+#endif
+
+#ifndef GC_API_PRIV
+# define GC_API_PRIV GC_API
+#endif
+
+#ifndef GC_LOCKS_H
+# include "gc_locks.h"
+#endif
+
+#define ONES ((word)(signed_word)(-1))
# ifdef STACK_GROWS_DOWN
# define COOLER_THAN >
# define HOTTER_THAN <
-# define MAKE_COOLER(x,y) if ((word)(x)+(y) > (word)(x)) {(x) += (y);} \
- else {(x) = (word)ONES;}
+# define MAKE_COOLER(x,y) if ((word)((x) + (y)) > (word)(x)) {(x) += (y);} \
+ else {(x) = (ptr_t)ONES;}
# define MAKE_HOTTER(x,y) (x) -= (y)
# else
# define COOLER_THAN <
# define HOTTER_THAN >
-# define MAKE_COOLER(x,y) if ((word)(x)-(y) < (word)(x)) {(x) -= (y);} else {(x) = 0;}
+# define MAKE_COOLER(x,y) if ((word)((x) - (y)) < (word)(x)) {(x) -= (y);} \
+ else {(x) = 0;}
# define MAKE_HOTTER(x,y) (x) += (y)
# endif
@@ -128,214 +216,179 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/*********************************/
/* #define STUBBORN_ALLOC */
- /* Enable stubborm allocation, and thus a limited */
- /* form of incremental collection w/o dirty bits. */
+ /* Enable stubborn allocation, and thus a limited */
+ /* form of incremental collection w/o dirty bits. */
/* #define ALL_INTERIOR_POINTERS */
- /* Forces all pointers into the interior of an */
- /* object to be considered valid. Also causes the */
- /* sizes of all objects to be inflated by at least */
- /* one byte. This should suffice to guarantee */
- /* that in the presence of a compiler that does */
- /* not perform garbage-collector-unsafe */
- /* optimizations, all portable, strictly ANSI */
- /* conforming C programs should be safely usable */
- /* with malloc replaced by GC_malloc and free */
- /* calls removed. There are several disadvantages: */
- /* 1. There are probably no interesting, portable, */
- /* strictly ANSI conforming C programs. */
- /* 2. This option makes it hard for the collector */
- /* to allocate space that is not ``pointed to'' */
- /* by integers, etc. Under SunOS 4.X with a */
- /* statically linked libc, we empiricaly */
- /* observed that it would be difficult to */
- /* allocate individual objects larger than 100K. */
- /* Even if only smaller objects are allocated, */
- /* more swap space is likely to be needed. */
- /* Fortunately, much of this will never be */
- /* touched. */
- /* If you can easily avoid using this option, do. */
- /* If not, try to keep individual objects small. */
- /* This is now really controlled at startup, */
- /* through GC_all_interior_pointers. */
-
-#define PRINTSTATS /* Print garbage collection statistics */
- /* For less verbose output, undefine in reclaim.c */
-
-#define PRINTTIMES /* Print the amount of time consumed by each garbage */
- /* collection. */
-
-#define PRINTBLOCKS /* Print object sizes associated with heap blocks, */
- /* whether the objects are atomic or composite, and */
- /* whether or not the block was found to be empty */
- /* during the reclaim phase. Typically generates */
- /* about one screenful per garbage collection. */
-#undef PRINTBLOCKS
-
-#ifdef SILENT
-# ifdef PRINTSTATS
-# undef PRINTSTATS
+ /* Forces all pointers into the interior of an */
+ /* object to be considered valid. Also causes the */
+ /* sizes of all objects to be inflated by at least */
+ /* one byte. This should suffice to guarantee */
+ /* that in the presence of a compiler that does */
+ /* not perform garbage-collector-unsafe */
+ /* optimizations, all portable, strictly ANSI */
+ /* conforming C programs should be safely usable */
+ /* with malloc replaced by GC_malloc and free */
+ /* calls removed. There are several disadvantages: */
+ /* 1. There are probably no interesting, portable, */
+ /* strictly ANSI conforming C programs. */
+ /* 2. This option makes it hard for the collector */
+ /* to allocate space that is not ``pointed to'' */
+ /* by integers, etc. Under SunOS 4.X with a */
+ /* statically linked libc, we empirically */
+ /* observed that it would be difficult to */
+ /* allocate individual objects larger than 100K. */
+ /* Even if only smaller objects are allocated, */
+ /* more swap space is likely to be needed. */
+ /* Fortunately, much of this will never be */
+ /* touched. */
+ /* If you can easily avoid using this option, do. */
+ /* If not, try to keep individual objects small. */
+ /* This is now really controlled at startup, */
+ /* through GC_all_interior_pointers. */
+
+
+#ifndef GC_NO_FINALIZATION
+# define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
+ GC_INNER void GC_notify_or_invoke_finalizers(void);
+ /* If GC_finalize_on_demand is not set, invoke */
+ /* eligible finalizers. Otherwise: */
+ /* Call *GC_finalizer_notifier if there are */
+ /* finalizers to be run, and we haven't called */
+ /* this procedure yet this GC cycle. */
+
+ GC_INNER void GC_push_finalizer_structures(void);
+ GC_INNER void GC_finalize(void);
+ /* Perform all indicated finalization actions */
+ /* on unmarked objects. */
+ /* Unreachable finalizable objects are enqueued */
+ /* for processing by GC_invoke_finalizers. */
+ /* Invoked with lock. */
+
+# ifndef SMALL_CONFIG
+ GC_INNER void GC_print_finalization_stats(void);
# endif
-# ifdef PRINTTIMES
-# undef PRINTTIMES
-# endif
-# ifdef PRINTNBLOCKS
-# undef PRINTNBLOCKS
-# endif
-#endif
-
-#if defined(PRINTSTATS) && !defined(GATHERSTATS)
-# define GATHERSTATS
-#endif
-
-#if defined(PRINTSTATS) || !defined(SMALL_CONFIG)
-# define CONDPRINT /* Print some things if GC_print_stats is set */
-#endif
-
-#define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
-
-#define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */
- /* free lists are actually maintained. This applies */
- /* only to the top level routines in misc.c, not to */
- /* user generated code that calls GC_allocobj and */
- /* GC_allocaobj directly. */
- /* Slows down average programs slightly. May however */
- /* substantially reduce fragmentation if allocation */
- /* request sizes are widely scattered. */
- /* May save significant amounts of space for obj_map */
- /* entries. */
-
-#if defined(USE_MARK_BYTES) && !defined(ALIGN_DOUBLE)
-# define ALIGN_DOUBLE
- /* We use one byte for every 2 words, which doesn't allow for */
- /* odd numbered words to have mark bits. */
-#endif
-
-#if defined(GC_GCJ_SUPPORT) && ALIGNMENT < 8 && !defined(ALIGN_DOUBLE)
- /* GCJ's Hashtable synchronization code requires 64-bit alignment. */
-# define ALIGN_DOUBLE
-#endif
-
-/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
-# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
-# define MERGE_SIZES
-# endif
+#else
+# define GC_INVOKE_FINALIZERS() (void)0
+#endif /* GC_NO_FINALIZATION */
#if !defined(DONT_ADD_BYTE_AT_END)
-# define EXTRA_BYTES GC_all_interior_pointers
+# ifdef LINT2
+ /* Explicitly instruct the code analysis tool that */
+ /* GC_all_interior_pointers is assumed to have only 0 or 1 value. */
+# define EXTRA_BYTES (GC_all_interior_pointers? 1 : 0)
+# else
+# define EXTRA_BYTES GC_all_interior_pointers
+# endif
+# define MAX_EXTRA_BYTES 1
#else
# define EXTRA_BYTES 0
+# define MAX_EXTRA_BYTES 0
#endif
# ifndef LARGE_CONFIG
-# define MINHINCR 16 /* Minimum heap increment, in blocks of HBLKSIZE */
- /* Must be multiple of largest page size. */
+# define MINHINCR 16 /* Minimum heap increment, in blocks of HBLKSIZE */
+ /* Must be multiple of largest page size. */
# define MAXHINCR 2048 /* Maximum heap increment, in blocks */
# else
# define MINHINCR 64
# define MAXHINCR 4096
# endif
-# define TIME_LIMIT 50 /* We try to keep pause times from exceeding */
- /* this by much. In milliseconds. */
-
# define BL_LIMIT GC_black_list_spacing
- /* If we need a block of N bytes, and we have */
- /* a block of N + BL_LIMIT bytes available, */
- /* and N > BL_LIMIT, */
- /* but all possible positions in it are */
- /* blacklisted, we just use it anyway (and */
- /* print a warning, if warnings are enabled). */
- /* This risks subsequently leaking the block */
- /* due to a false reference. But not using */
- /* the block risks unreasonable immediate */
- /* heap growth. */
+ /* If we need a block of N bytes, and we have */
+ /* a block of N + BL_LIMIT bytes available, */
+ /* and N > BL_LIMIT, */
+ /* but all possible positions in it are */
+ /* blacklisted, we just use it anyway (and */
+ /* print a warning, if warnings are enabled). */
+ /* This risks subsequently leaking the block */
+ /* due to a false reference. But not using */
+ /* the block risks unreasonable immediate */
+ /* heap growth. */
/*********************************/
/* */
-/* Stack saving for debugging */
+/* Stack saving for debugging */
/* */
/*********************************/
-#ifdef SAVE_CALL_CHAIN
-
-/* Fill in the pc and argument information for up to NFRAMES of my */
-/* callers. Ignore my frame and my callers frame. */
-struct callinfo;
-void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES]));
-
-void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
-
-#endif
-
#ifdef NEED_CALLINFO
struct callinfo {
- word ci_pc; /* Caller, not callee, pc */
-# if NARGS > 0
- word ci_arg[NARGS]; /* bit-wise complement to avoid retention */
-# endif
-# if defined(ALIGN_DOUBLE) && (NFRAMES * (NARGS + 1)) % 2 == 1
- /* Likely alignment problem. */
- word ci_dummy;
-# endif
+ word ci_pc; /* Caller, not callee, pc */
+# if NARGS > 0
+ word ci_arg[NARGS]; /* bit-wise complement to avoid retention */
+# endif
+# if (NFRAMES * (NARGS + 1)) % 2 == 1
+ /* Likely alignment problem. */
+ word ci_dummy;
+# endif
};
#endif
+#ifdef SAVE_CALL_CHAIN
+ /* Fill in the pc and argument information for up to NFRAMES of my */
+ /* callers. Ignore my frame and my callers frame. */
+ GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]);
+ GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
+#endif
+
/*********************************/
/* */
-/* OS interface routines */
+/* OS interface routines */
/* */
/*********************************/
#ifdef BSD_TIME
-# undef CLOCK_TYPE
-# undef GET_TIME
-# undef MS_TIME_DIFF
-# define CLOCK_TYPE struct timeval
-# define GET_TIME(x) { struct rusage rusage; \
- getrusage (RUSAGE_SELF, &rusage); \
- x = rusage.ru_utime; }
-# define MS_TIME_DIFF(a,b) ((double) (a.tv_sec - b.tv_sec) * 1000.0 \
- + (double) (a.tv_usec - b.tv_usec) / 1000.0)
-#else /* !BSD_TIME */
-# if defined(MSWIN32) || defined(MSWINCE)
-# include <windows.h>
-# include <winbase.h>
-# define CLOCK_TYPE DWORD
-# define GET_TIME(x) x = GetTickCount()
-# define MS_TIME_DIFF(a,b) ((long)((a)-(b)))
-# else /* !MSWIN32, !MSWINCE, !BSD_TIME */
-# include <time.h>
-# if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4)
- clock_t clock(); /* Not in time.h, where it belongs */
-# endif
-# if defined(FREEBSD) && !defined(CLOCKS_PER_SEC)
-# include <machine/limits.h>
-# define CLOCKS_PER_SEC CLK_TCK
-# endif
-# if !defined(CLOCKS_PER_SEC)
-# define CLOCKS_PER_SEC 1000000
-/*
- * This is technically a bug in the implementation. ANSI requires that
- * CLOCKS_PER_SEC be defined. But at least under SunOS4.1.1, it isn't.
- * Also note that the combination of ANSI C and POSIX is incredibly gross
- * here. The type clock_t is used by both clock() and times(). But on
- * some machines these use different notions of a clock tick, CLOCKS_PER_SEC
- * seems to apply only to clock. Hence we use it here. On many machines,
- * including SunOS, clock actually uses units of microseconds (which are
- * not really clock ticks).
- */
-# endif
-# define CLOCK_TYPE clock_t
-# define GET_TIME(x) x = clock()
-# define MS_TIME_DIFF(a,b) ((unsigned long) \
- (1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC))
-# endif /* !MSWIN32 */
-#endif /* !BSD_TIME */
-
-/* We use bzero and bcopy internally. They may not be available. */
+# undef CLOCK_TYPE
+# undef GET_TIME
+# undef MS_TIME_DIFF
+# define CLOCK_TYPE struct timeval
+# define GET_TIME(x) { struct rusage rusage; \
+ getrusage (RUSAGE_SELF, &rusage); \
+ x = rusage.ru_utime; }
+# define MS_TIME_DIFF(a,b) ((unsigned long)(a.tv_sec - b.tv_sec) * 1000 \
+ + (unsigned long)(a.tv_usec - b.tv_usec) / 1000)
+#elif defined(MSWIN32) || defined(MSWINCE)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# define NOSERVICE
+# include <windows.h>
+# include <winbase.h>
+# define CLOCK_TYPE DWORD
+# define GET_TIME(x) x = GetTickCount()
+# define MS_TIME_DIFF(a,b) ((long)((a)-(b)))
+#else /* !MSWIN32, !MSWINCE, !BSD_TIME */
+# include <time.h>
+# if defined(FREEBSD) && !defined(CLOCKS_PER_SEC)
+# include <machine/limits.h>
+# define CLOCKS_PER_SEC CLK_TCK
+# endif
+# if !defined(CLOCKS_PER_SEC)
+# define CLOCKS_PER_SEC 1000000
+ /* This is technically a bug in the implementation. */
+ /* ANSI requires that CLOCKS_PER_SEC be defined. But at least */
+ /* under SunOS 4.1.1, it isn't. Also note that the combination of */
+ /* ANSI C and POSIX is incredibly gross here. The type clock_t */
+ /* is used by both clock() and times(). But on some machines */
+ /* these use different notions of a clock tick, CLOCKS_PER_SEC */
+ /* seems to apply only to clock. Hence we use it here. On many */
+ /* machines, including SunOS, clock actually uses units of */
+ /* microseconds (which are not really clock ticks). */
+# endif
+# define CLOCK_TYPE clock_t
+# define GET_TIME(x) x = clock()
+# define MS_TIME_DIFF(a,b) (CLOCKS_PER_SEC % 1000 == 0 ? \
+ (unsigned long)((a) - (b)) / (unsigned long)(CLOCKS_PER_SEC / 1000) \
+ : ((unsigned long)((a) - (b)) * 1000) / (unsigned long)CLOCKS_PER_SEC)
+ /* Avoid using double type since some targets (like ARM) might */
+ /* require -lm option for double-to-long conversion. */
+#endif /* !BSD_TIME && !MSWIN32 */
+
+/* We use bzero and bcopy internally. They may not be available. */
# if defined(SPARC) && defined(SUNOS4)
# define BCOPY_EXISTS
# endif
@@ -356,45 +409,20 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
# include <string.h>
# define BCOPY_EXISTS
# endif
+# if defined(MACOS) && defined(POWERPC)
+# include <MacMemory.h>
+# define bcopy(x,y,n) BlockMoveData(x, y, n)
+# define bzero(x,n) BlockZero(x, n)
+# define BCOPY_EXISTS
+# endif
# ifndef BCOPY_EXISTS
# include <string.h>
# define BCOPY(x,y,n) memcpy(y, x, (size_t)(n))
# define BZERO(x,n) memset(x, 0, (size_t)(n))
# else
-# define BCOPY(x,y,n) bcopy((char *)(x),(char *)(y),(int)(n))
-# define BZERO(x,n) bzero((char *)(x),(int)(n))
-# endif
-
-/* Delay any interrupts or signals that may abort this thread. Data */
-/* structures are in a consistent state outside this pair of calls. */
-/* ANSI C allows both to be empty (though the standard isn't very */
-/* clear on that point). Standard malloc implementations are usually */
-/* neither interruptable nor thread-safe, and thus correspond to */
-/* empty definitions. */
-/* It probably doesn't make any sense to declare these to be nonempty */
-/* if the code is being optimized, since signal safety relies on some */
-/* ordering constraints that are typically not obeyed by optimizing */
-/* compilers. */
-# ifdef PCR
-# define DISABLE_SIGNALS() \
- PCR_Th_SetSigMask(PCR_allSigsBlocked,&GC_old_sig_mask)
-# define ENABLE_SIGNALS() \
- PCR_Th_SetSigMask(&GC_old_sig_mask, NIL)
-# else
-# if defined(THREADS) || defined(AMIGA) \
- || defined(MSWIN32) || defined(MSWINCE) || defined(MACOS) \
- || defined(DJGPP) || defined(NO_SIGNALS)
- /* Also useful for debugging. */
- /* Should probably use thr_sigsetmask for GC_SOLARIS_THREADS. */
-# define DISABLE_SIGNALS()
-# define ENABLE_SIGNALS()
-# else
-# define DISABLE_SIGNALS() GC_disable_signals()
- void GC_disable_signals();
-# define ENABLE_SIGNALS() GC_enable_signals()
- void GC_enable_signals();
-# endif
+# define BCOPY(x,y,n) bcopy((void *)(x),(void *)(y),(size_t)(n))
+# define BZERO(x,n) bzero((void *)(x),(size_t)(n))
# endif
/*
@@ -403,22 +431,22 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
# ifdef PCR
# include "th/PCR_ThCtl.h"
# define STOP_WORLD() \
- PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_stopNormal, \
- PCR_allSigsBlocked, \
- PCR_waitForever)
+ PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_stopNormal, \
+ PCR_allSigsBlocked, \
+ PCR_waitForever)
# define START_WORLD() \
- PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_null, \
- PCR_allSigsBlocked, \
- PCR_waitForever);
+ PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_null, \
+ PCR_allSigsBlocked, \
+ PCR_waitForever)
# else
-# if defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) \
- || defined(GC_PTHREADS)
- void GC_stop_world();
- void GC_start_world();
+# if defined(GC_WIN32_THREADS) || defined(GC_PTHREADS)
+ GC_INNER void GC_stop_world(void);
+ GC_INNER void GC_start_world(void);
# define STOP_WORLD() GC_stop_world()
# define START_WORLD() GC_start_world()
# else
-# define STOP_WORLD()
+ /* Just do a sanity check: we are not inside GC_do_blocking(). */
+# define STOP_WORLD() GC_ASSERT(GC_blocked_sp == NULL)
# define START_WORLD()
# endif
# endif
@@ -427,44 +455,153 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
# ifdef PCR
# define ABORT(s) PCR_Base_Panic(s)
# else
+# if defined(MSWINCE) && !defined(DebugBreak) \
+ && (!defined(UNDER_CE) || (defined(__MINGW32CE__) && !defined(ARM32)))
+ /* This simplifies linking for WinCE (and, probably, doesn't */
+ /* hurt debugging much); use -DDebugBreak=DebugBreak to override */
+ /* this behavior if really needed. This is also a workaround for */
+ /* x86mingw32ce toolchain (if it is still declaring DebugBreak() */
+ /* instead of defining it as a macro). */
+# define DebugBreak() _exit(-1) /* there is no abort() in WinCE */
+# endif
# ifdef SMALL_CONFIG
-# define ABORT(msg) abort();
+# define GC_on_abort(msg) (void)0 /* be silent on abort */
# else
- GC_API void GC_abort GC_PROTO((GC_CONST char * msg));
-# define ABORT(msg) GC_abort(msg);
-# endif
-# endif
+ GC_API_PRIV GC_abort_func GC_on_abort;
+# endif /* !SMALL_CONFIG */
+# if defined(MSWIN32) && (defined(NO_DEBUGGING) || defined(LINT2))
+ /* A more user-friendly abort after showing fatal message. */
+# define ABORT(msg) (GC_on_abort(msg), _exit(-1))
+ /* Exit on error without running "at-exit" callbacks. */
+# elif defined(MSWINCE) && defined(NO_DEBUGGING)
+# define ABORT(msg) (GC_on_abort(msg), ExitProcess(-1))
+# elif defined(MSWIN32) || defined(MSWINCE)
+# define ABORT(msg) { GC_on_abort(msg); DebugBreak(); }
+ /* Note that: on a WinCE box, this could be silently */
+ /* ignored (i.e., the program is not aborted); */
+ /* DebugBreak is a statement in some toolchains. */
+# else
+# define ABORT(msg) (GC_on_abort(msg), abort())
+# endif /* !MSWIN32 */
+# endif /* !PCR */
+
+/* Same as ABORT but does not have 'no-return' attribute. */
+/* ABORT on dummy condition (which is always true). */
+#define ABORT_RET(msg) { if ((signed_word)GC_current_warn_proc != -1) \
+ ABORT(msg); }
/* Exit abnormally, but without making a mess (e.g. out of memory) */
# ifdef PCR
# define EXIT() PCR_Base_Exit(1,PCR_waitForever)
# else
-# define EXIT() (void)exit(1)
-# endif
-
-/* Print warning message, e.g. almost out of memory. */
-# define WARN(msg,arg) (*GC_current_warn_proc)("GC Warning: " msg, (GC_word)(arg))
-extern GC_warn_proc GC_current_warn_proc;
+# define EXIT() (GC_on_abort(NULL), exit(1 /* EXIT_FAILURE */))
+# endif
+
+/* Print warning message, e.g. almost out of memory. */
+/* The argument (if any) format specifier should be: */
+/* "%s", "%p" or "%"WARN_PRIdPTR. */
+#define WARN(msg, arg) (*GC_current_warn_proc)("GC Warning: " msg, \
+ (GC_word)(arg))
+GC_EXTERN GC_warn_proc GC_current_warn_proc;
+
+/* Print format type macro for decimal signed_word value passed WARN(). */
+/* This could be redefined for Win64 or LLP64, but typically should */
+/* not be done as the WARN format string is, possibly, processed on the */
+/* client side, so non-standard print type modifiers (like MS "I64d") */
+/* should be avoided here if possible. */
+#ifndef WARN_PRIdPTR
+ /* Assume sizeof(void *) == sizeof(long) (or a little-endian machine) */
+# define WARN_PRIdPTR "ld"
+#endif
/* Get environment entry */
-#if !defined(NO_GETENV)
-# if defined(EMPTY_GETENV_RESULTS)
- /* Workaround for a reputed Wine bug. */
- static inline char * fixed_getenv(const char *name)
- {
- char * tmp = getenv(name);
- if (tmp == 0 || strlen(tmp) == 0)
- return 0;
- return tmp;
- }
-# define GETENV(name) fixed_getenv(name)
-# else
-# define GETENV(name) getenv(name)
-# endif
+#ifdef GC_READ_ENV_FILE
+ GC_INNER char * GC_envfile_getenv(const char *name);
+# define GETENV(name) GC_envfile_getenv(name)
+#elif defined(NO_GETENV)
+# define GETENV(name) NULL
+#elif defined(EMPTY_GETENV_RESULTS)
+ /* Workaround for a reputed Wine bug. */
+ GC_INLINE char * fixed_getenv(const char *name)
+ {
+ char *value = getenv(name);
+ return value != NULL && *value != '\0' ? value : NULL;
+ }
+# define GETENV(name) fixed_getenv(name)
#else
-# define GETENV(name) 0
+# define GETENV(name) getenv(name)
#endif
+#if defined(DARWIN)
+# ifndef MAC_OS_X_VERSION_MAX_ALLOWED
+# include <AvailabilityMacros.h>
+ /* Include this header just to import the above macro. */
+# endif
+# if defined(POWERPC)
+# if CPP_WORDSZ == 32
+# define GC_THREAD_STATE_T ppc_thread_state_t
+# define GC_MACH_THREAD_STATE PPC_THREAD_STATE
+# define GC_MACH_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
+# 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
+# endif
+# elif defined(I386) || defined(X86_64)
+# if CPP_WORDSZ == 32
+# if defined(i386_THREAD_STATE_COUNT) && !defined(x86_THREAD_STATE32_COUNT)
+ /* Use old naming convention for 32-bit x86. */
+# define GC_THREAD_STATE_T i386_thread_state_t
+# define GC_MACH_THREAD_STATE i386_THREAD_STATE
+# define GC_MACH_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
+# else
+# define GC_THREAD_STATE_T x86_thread_state32_t
+# define GC_MACH_THREAD_STATE x86_THREAD_STATE32
+# define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
+# endif
+# 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
+# endif
+# else
+# if defined(ARM32)
+# define GC_THREAD_STATE_T arm_thread_state_t
+# ifdef ARM_MACHINE_THREAD_STATE_COUNT
+# define GC_MACH_THREAD_STATE ARM_MACHINE_THREAD_STATE
+# define GC_MACH_THREAD_STATE_COUNT ARM_MACHINE_THREAD_STATE_COUNT
+# endif
+# else
+# error define GC_THREAD_STATE_T
+# endif
+# endif
+# ifndef GC_MACH_THREAD_STATE
+# define GC_MACH_THREAD_STATE MACHINE_THREAD_STATE
+# define GC_MACH_THREAD_STATE_COUNT MACHINE_THREAD_STATE_COUNT
+# endif
+
+# if CPP_WORDSZ == 32
+# define GC_MACH_HEADER mach_header
+# define GC_MACH_SECTION section
+# define GC_GETSECTBYNAME getsectbynamefromheader
+# else
+# define GC_MACH_HEADER mach_header_64
+# define GC_MACH_SECTION section_64
+# define GC_GETSECTBYNAME getsectbynamefromheader_64
+# endif
+
+ /* Try to work out the right way to access thread state structure */
+ /* members. The structure has changed its definition in different */
+ /* Darwin versions. This now defaults to the (older) names */
+ /* without __, thus hopefully, not breaking any existing */
+ /* Makefile.direct builds. */
+# if __DARWIN_UNIX03
+# define THREAD_FLD(x) __ ## x
+# else
+# define THREAD_FLD(x) x
+# endif
+#endif /* DARWIN */
+
/*********************************/
/* */
/* Word-size-dependent defines */
@@ -472,30 +609,62 @@ extern GC_warn_proc GC_current_warn_proc;
/*********************************/
#if CPP_WORDSZ == 32
-# define WORDS_TO_BYTES(x) ((x)<<2)
-# define BYTES_TO_WORDS(x) ((x)>>2)
-# define LOGWL ((word)5) /* log[2] of CPP_WORDSZ */
-# define modWORDSZ(n) ((n) & 0x1f) /* n mod size of word */
-# if ALIGNMENT != 4
-# define UNALIGNED
-# endif
+# define WORDS_TO_BYTES(x) ((x)<<2)
+# define BYTES_TO_WORDS(x) ((x)>>2)
+# define LOGWL ((word)5) /* log[2] of CPP_WORDSZ */
+# define modWORDSZ(n) ((n) & 0x1f) /* n mod size of word */
+# if ALIGNMENT != 4
+# define UNALIGNED_PTRS
+# endif
#endif
#if CPP_WORDSZ == 64
# define WORDS_TO_BYTES(x) ((x)<<3)
# define BYTES_TO_WORDS(x) ((x)>>3)
# define LOGWL ((word)6) /* log[2] of CPP_WORDSZ */
-# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */
+# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */
# if ALIGNMENT != 8
-# define UNALIGNED
+# define UNALIGNED_PTRS
# endif
#endif
+/* The first TINY_FREELISTS free lists correspond to the first */
+/* TINY_FREELISTS multiples of GRANULE_BYTES, i.e. we keep */
+/* separate free lists for each multiple of GRANULE_BYTES */
+/* up to (TINY_FREELISTS-1) * GRANULE_BYTES. After that they */
+/* may be spread out further. */
+#include "../gc_tiny_fl.h"
+#define GRANULE_BYTES GC_GRANULE_BYTES
+#define TINY_FREELISTS GC_TINY_FREELISTS
+
#define WORDSZ ((word)CPP_WORDSZ)
#define SIGNB ((word)1 << (WORDSZ-1))
#define BYTES_PER_WORD ((word)(sizeof (word)))
-#define ONES ((word)(signed_word)(-1))
-#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */
+#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */
+
+#if GRANULE_BYTES == 8
+# define BYTES_TO_GRANULES(n) ((n)>>3)
+# define GRANULES_TO_BYTES(n) ((n)<<3)
+# if CPP_WORDSZ == 64
+# define GRANULES_TO_WORDS(n) (n)
+# elif CPP_WORDSZ == 32
+# define GRANULES_TO_WORDS(n) ((n)<<1)
+# else
+# define GRANULES_TO_WORDS(n) BYTES_TO_WORDS(GRANULES_TO_BYTES(n))
+# endif
+#elif GRANULE_BYTES == 16
+# define BYTES_TO_GRANULES(n) ((n)>>4)
+# define GRANULES_TO_BYTES(n) ((n)<<4)
+# if CPP_WORDSZ == 64
+# define GRANULES_TO_WORDS(n) ((n)<<1)
+# elif CPP_WORDSZ == 32
+# define GRANULES_TO_WORDS(n) ((n)<<2)
+# else
+# define GRANULES_TO_WORDS(n) BYTES_TO_WORDS(GRANULES_TO_BYTES(n))
+# endif
+#else
+# error Bad GRANULE_BYTES value
+#endif
/*********************/
/* */
@@ -503,123 +672,124 @@ 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(LARGE_CONFIG) || !defined(SMALL_CONFIG)
+# ifdef ALPHA
# define CPP_LOG_HBLKSIZE 13
+# else
+# define CPP_LOG_HBLKSIZE 12
# endif
+# else
+# define CPP_LOG_HBLKSIZE 10
# endif
#else
# if HBLKSIZE == 512
# define CPP_LOG_HBLKSIZE 9
-# endif
-# if HBLKSIZE == 1024
+# elif HBLKSIZE == 1024
# define CPP_LOG_HBLKSIZE 10
-# endif
-# if HBLKSIZE == 2048
+# elif HBLKSIZE == 2048
# define CPP_LOG_HBLKSIZE 11
-# endif
-# if HBLKSIZE == 4096
+# elif HBLKSIZE == 4096
# define CPP_LOG_HBLKSIZE 12
-# endif
-# if HBLKSIZE == 8192
+# elif HBLKSIZE == 8192
# define CPP_LOG_HBLKSIZE 13
-# endif
-# if HBLKSIZE == 16384
+# elif HBLKSIZE == 16384
# define CPP_LOG_HBLKSIZE 14
-# endif
-# ifndef CPP_LOG_HBLKSIZE
+# else
--> fix HBLKSIZE
# endif
# undef HBLKSIZE
#endif
+
# define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
-# define LOG_HBLKSIZE ((word)CPP_LOG_HBLKSIZE)
-# define HBLKSIZE ((word)CPP_HBLKSIZE)
+# define LOG_HBLKSIZE ((size_t)CPP_LOG_HBLKSIZE)
+# define HBLKSIZE ((size_t)CPP_HBLKSIZE)
-/* max size objects supported by freelist (larger objects may be */
-/* allocated, but less efficiently) */
+/* max size objects supported by freelist (larger objects are */
+/* allocated directly with allchblk(), by rounding to the next */
+/* multiple of HBLKSIZE. */
#define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2)
-#define MAXOBJBYTES ((word)CPP_MAXOBJBYTES)
-#define CPP_MAXOBJSZ BYTES_TO_WORDS(CPP_MAXOBJBYTES)
-#define MAXOBJSZ ((word)CPP_MAXOBJSZ)
-
+#define MAXOBJBYTES ((size_t)CPP_MAXOBJBYTES)
+#define CPP_MAXOBJWORDS BYTES_TO_WORDS(CPP_MAXOBJBYTES)
+#define MAXOBJWORDS ((size_t)CPP_MAXOBJWORDS)
+#define CPP_MAXOBJGRANULES BYTES_TO_GRANULES(CPP_MAXOBJBYTES)
+#define MAXOBJGRANULES ((size_t)CPP_MAXOBJGRANULES)
+
# define divHBLKSZ(n) ((n) >> LOG_HBLKSIZE)
# define HBLK_PTR_DIFF(p,q) divHBLKSZ((ptr_t)p - (ptr_t)q)
- /* Equivalent to subtracting 2 hblk pointers. */
- /* We do it this way because a compiler should */
- /* find it hard to use an integer division */
- /* instead of a shift. The bundled SunOS 4.1 */
- /* o.w. sometimes pessimizes the subtraction to */
- /* involve a call to .div. */
-
+ /* Equivalent to subtracting 2 hblk pointers. */
+ /* We do it this way because a compiler should */
+ /* find it hard to use an integer division */
+ /* instead of a shift. The bundled SunOS 4.1 */
+ /* o.w. sometimes pessimizes the subtraction to */
+ /* involve a call to .div. */
+
# define modHBLKSZ(n) ((n) & (HBLKSIZE-1))
-
+
# define HBLKPTR(objptr) ((struct hblk *)(((word) (objptr)) & ~(HBLKSIZE-1)))
-# define HBLKDISPL(objptr) (((word) (objptr)) & (HBLKSIZE-1))
+# define HBLKDISPL(objptr) (((size_t) (objptr)) & (HBLKSIZE-1))
/* Round up byte allocation requests to integral number of words, etc. */
-# define ROUNDED_UP_WORDS(n) \
- BYTES_TO_WORDS((n) + (WORDS_TO_BYTES(1) - 1 + EXTRA_BYTES))
-# ifdef ALIGN_DOUBLE
-# define ALIGNED_WORDS(n) \
- (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1 + EXTRA_BYTES) & ~1)
+# define ROUNDED_UP_GRANULES(n) \
+ BYTES_TO_GRANULES((n) + (GRANULE_BYTES - 1 + EXTRA_BYTES))
+# if MAX_EXTRA_BYTES == 0
+# define SMALL_OBJ(bytes) EXPECT((bytes) <= (MAXOBJBYTES), TRUE)
# else
-# define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n)
+# define SMALL_OBJ(bytes) \
+ (EXPECT((bytes) <= (MAXOBJBYTES - MAX_EXTRA_BYTES), TRUE) \
+ || (bytes) <= MAXOBJBYTES - EXTRA_BYTES)
+ /* This really just tests bytes <= MAXOBJBYTES - EXTRA_BYTES. */
+ /* But we try to avoid looking up EXTRA_BYTES. */
# endif
-# define SMALL_OBJ(bytes) ((bytes) <= (MAXOBJBYTES - EXTRA_BYTES))
# define ADD_SLOP(bytes) ((bytes) + EXTRA_BYTES)
# ifndef MIN_WORDS
- /* MIN_WORDS is the size of the smallest allocated object. */
- /* 1 and 2 are the only valid values. */
- /* 2 must be used if: */
- /* - GC_gcj_malloc can be used for objects of requested */
- /* size smaller than 2 words, or */
- /* - USE_MARK_BYTES is defined. */
-# if defined(USE_MARK_BYTES) || defined(GC_GCJ_SUPPORT)
-# define MIN_WORDS 2 /* Smallest allocated object. */
-# else
-# define MIN_WORDS 1
-# endif
+# define MIN_WORDS 2 /* FIXME: obsolete */
# endif
-
/*
- * Hash table representation of sets of pages. This assumes it is
- * OK to add spurious entries to sets.
+ * Hash table representation of sets of pages.
+ * Implements a map from aligned HBLKSIZE chunks of the address space to one
+ * bit each.
+ * This assumes it is OK to spuriously set bits, e.g. because multiple
+ * addresses are represented by a single location.
* Used by black-listing code, and perhaps by dirty bit maintenance code.
*/
-
+
# ifdef LARGE_CONFIG
-# 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
-# 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. */
-# 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. */
- /* Even for somewhat smaller heaps, */
- /* say half that, collisions may be an */
- /* issue because we blacklist */
- /* addresses outside the heap. */
+# 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
+# elif !defined(SMALL_CONFIG)
+# 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 */
+ /* addresses outside the heap. */
+# else
+# define LOG_PHT_ENTRIES 15 /* Collisions are likely if heap grows */
+ /* to more than 32K hblks = 128MB. */
+ /* Each hash table occupies 4K bytes. */
# endif
# define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES)
# define PHT_SIZE (PHT_ENTRIES >> LOGWL)
@@ -628,16 +798,15 @@ typedef word page_hash_table[PHT_SIZE];
# define PHT_HASH(addr) ((((word)(addr)) >> LOG_HBLKSIZE) & (PHT_ENTRIES - 1))
# define get_pht_entry_from_index(bl, index) \
- (((bl)[divWORDSZ(index)] >> modWORDSZ(index)) & 1)
+ (((bl)[divWORDSZ(index)] >> modWORDSZ(index)) & 1)
# define set_pht_entry_from_index(bl, index) \
- (bl)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index)
+ (bl)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index)
# define clear_pht_entry_from_index(bl, index) \
- (bl)[divWORDSZ(index)] &= ~((word)1 << modWORDSZ(index))
-/* And a dumb but thread-safe version of set_pht_entry_from_index. */
-/* This sets (many) extra bits. */
+ (bl)[divWORDSZ(index)] &= ~((word)1 << modWORDSZ(index))
+/* And a dumb but thread-safe version of set_pht_entry_from_index. */
+/* This sets (many) extra bits. */
# define set_pht_entry_from_index_safe(bl, index) \
- (bl)[divWORDSZ(index)] = ONES
-
+ (bl)[divWORDSZ(index)] = ONES
/********************************************/
@@ -649,128 +818,179 @@ typedef word page_hash_table[PHT_SIZE];
/* heap block header */
#define HBLKMASK (HBLKSIZE-1)
-#define BITS_PER_HBLK (CPP_HBLKSIZE * 8)
+#define MARK_BITS_PER_HBLK (HBLKSIZE/GRANULE_BYTES)
+ /* upper bound */
+ /* We allocate 1 bit per allocation granule. */
+ /* If MARK_BIT_PER_GRANULE is defined, we use */
+ /* every nth bit, where n is the number of */
+ /* allocation granules per object. If */
+ /* MARK_BIT_PER_OBJ is defined, we only use the */
+ /* initial group of mark bits, and it is safe */
+ /* to allocate smaller header for large objects. */
-#define MARK_BITS_PER_HBLK (BITS_PER_HBLK/CPP_WORDSZ)
- /* upper bound */
- /* We allocate 1 bit/word, unless USE_MARK_BYTES */
- /* is defined. Only the first word */
- /* in each object is actually marked. */
+#ifdef PARALLEL_MARK
+# include "atomic_ops.h"
+# define counter_t volatile AO_t
+#else
+ typedef size_t counter_t;
+# if defined(THREADS) && (defined(MPROTECT_VDB) \
+ || (defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)))
+# include "atomic_ops.h"
+# endif
+#endif /* !PARALLEL_MARK */
-# ifdef USE_MARK_BYTES
-# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/2)
- /* Unlike the other case, this is in units of bytes. */
- /* We actually allocate only every second mark bit, since we */
- /* force all objects to be doubleword aligned. */
- /* However, each mark bit is allocated as a byte. */
-# else
-# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ)
+union word_ptr_ao_u {
+ word w;
+ signed_word sw;
+ void *vp;
+# ifdef AO_HAVE_load
+ volatile AO_t ao;
# endif
+};
/* We maintain layout maps for heap blocks containing objects of a given */
-/* size. Each entry in this map describes a byte offset and has the */
-/* following type. */
-typedef unsigned char map_entry_type;
-
+/* size. Each entry in this map describes a byte offset and has the */
+/* following type. */
struct hblkhdr {
- word hb_sz; /* If in use, size in words, of objects in the block. */
- /* if free, the size in bytes of the whole block */
- struct hblk * hb_next; /* Link field for hblk free list */
- /* and for lists of chunks waiting to be */
- /* reclaimed. */
- struct hblk * hb_prev; /* Backwards link for free list. */
- word hb_descr; /* object descriptor for marking. See */
- /* mark.h. */
- map_entry_type * hb_map;
- /* A pointer to a pointer validity map of the block. */
- /* See GC_obj_map. */
- /* Valid for all blocks with headers. */
- /* Free blocks point to GC_invalid_map. */
+ struct hblk * hb_next; /* Link field for hblk free list */
+ /* and for lists of chunks waiting to be */
+ /* reclaimed. */
+ struct hblk * hb_prev; /* Backwards link for free list. */
+ struct hblk * hb_block; /* The corresponding block. */
unsigned char hb_obj_kind;
- /* Kind of objects in the block. Each kind */
- /* identifies a mark procedure and a set of */
- /* list headers. Sometimes called regions. */
+ /* Kind of objects in the block. Each kind */
+ /* identifies a mark procedure and a set of */
+ /* list headers. Sometimes called regions. */
unsigned char hb_flags;
-# define IGNORE_OFF_PAGE 1 /* Ignore pointers that do not */
- /* point to the first page of */
- /* this object. */
-# define WAS_UNMAPPED 2 /* This is a free block, which has */
- /* been unmapped from the address */
- /* space. */
- /* GC_remap must be invoked on it */
- /* before it can be reallocated. */
- /* Only set with USE_MUNMAP. */
+# define IGNORE_OFF_PAGE 1 /* Ignore pointers that do not */
+ /* point to the first page of */
+ /* this object. */
+# define WAS_UNMAPPED 2 /* This is a free block, which has */
+ /* been unmapped from the address */
+ /* space. */
+ /* GC_remap must be invoked on it */
+ /* before it can be reallocated. */
+ /* Only set with USE_MUNMAP. */
+# define FREE_BLK 4 /* Block is free, i.e. not in use. */
+# ifdef ENABLE_DISCLAIM
+# define HAS_DISCLAIM 8
+ /* This kind has a callback on reclaim. */
+# define MARK_UNCONDITIONALLY 0x10
+ /* Mark from all objects, marked or */
+ /* not. Used to mark objects needed by */
+ /* reclaim notifier. */
+# endif
unsigned short hb_last_reclaimed;
- /* Value of GC_gc_no when block was */
- /* last allocated or swept. May wrap. */
- /* For a free block, this is maintained */
- /* only for USE_MUNMAP, and indicates */
- /* when the header was allocated, or */
- /* when the size of the block last */
- /* changed. */
+ /* Value of GC_gc_no when block was */
+ /* last allocated or swept. May wrap. */
+ /* For a free block, this is maintained */
+ /* only for USE_MUNMAP, and indicates */
+ /* when the header was allocated, or */
+ /* when the size of the block last */
+ /* changed. */
+ size_t hb_sz; /* If in use, size in bytes, of objects in the block. */
+ /* if free, the size in bytes of the whole block */
+ /* 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
+ unsigned32 hb_inv_sz; /* A good upper bound for 2**32/hb_sz. */
+ /* For large objects, we use */
+ /* LARGE_INV_SZ. */
+# define LARGE_INV_SZ (1 << 16)
+# else
+ unsigned char hb_large_block;
+ short * hb_map; /* Essentially a table of remainders */
+ /* mod BYTES_TO_GRANULES(hb_sz), except */
+ /* for large blocks. See GC_obj_map. */
+# endif
+ counter_t hb_n_marks; /* Number of set mark bits, excluding */
+ /* the one always set at the end. */
+ /* Currently it is concurrently */
+ /* updated and hence only approximate. */
+ /* But a zero value does guarantee that */
+ /* the block contains no marked */
+ /* objects. */
+ /* Ensuring this property means that we */
+ /* never decrement it to zero during a */
+ /* collection, and hence the count may */
+ /* be one too high. Due to concurrent */
+ /* updates, an arbitrary number of */
+ /* increments, but not all of them (!) */
+ /* may be lost, hence it may in theory */
+ /* be much too low. */
+ /* The count may also be too high if */
+ /* multiple mark threads mark the */
+ /* same object due to a race. */
+ /* Without parallel marking, the count */
+ /* is accurate. */
# ifdef USE_MARK_BYTES
+# define MARK_BITS_SZ (MARK_BITS_PER_HBLK + 1)
+ /* Unlike the other case, this is in units of bytes. */
+ /* Since we force double-word alignment, we need at most one */
+ /* mark bit per 2 words. But we do allocate and set one */
+ /* extra mark bit to avoid an explicit check for the */
+ /* partial object at the end of each block. */
union {
char _hb_marks[MARK_BITS_SZ];
- /* The i'th byte is 1 if the object */
- /* starting at word 2i is marked, 0 o.w. */
- word dummy; /* Force word alignment of mark bytes. */
+ /* The i'th byte is 1 if the object */
+ /* starting at granule i or object i is */
+ /* marked, 0 o.w. */
+ /* The mark bit for the "one past the */
+ /* end" object is always set to avoid a */
+ /* special case test in the marker. */
+ word dummy; /* Force word alignment of mark bytes. */
} _mark_byte_union;
# define hb_marks _mark_byte_union._hb_marks
# else
+# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ + 1)
word hb_marks[MARK_BITS_SZ];
- /* Bit i in the array refers to the */
- /* object starting at the ith word (header */
- /* INCLUDED) in the heap block. */
- /* The lsb of word 0 is numbered 0. */
- /* Unused bits are invalid, and are */
- /* occasionally set, e.g for uncollectable */
- /* objects. */
# endif /* !USE_MARK_BYTES */
};
+# define ANY_INDEX 23 /* "Random" mark bit index for assertions */
+
/* heap block body */
-# define BODY_SZ (HBLKSIZE/sizeof(word))
+# define HBLK_WORDS (HBLKSIZE/sizeof(word))
+# define HBLK_GRANULES (HBLKSIZE/GRANULE_BYTES)
+
+/* The number of objects in a block dedicated to a certain size. */
+/* may erroneously yield zero (instead of one) for large objects. */
+# define HBLK_OBJS(sz_in_bytes) (HBLKSIZE/(sz_in_bytes))
struct hblk {
- word hb_body[BODY_SZ];
+ char hb_body[HBLKSIZE];
};
-# define HBLK_IS_FREE(hdr) ((hdr) -> hb_map == GC_invalid_map)
+# define HBLK_IS_FREE(hdr) (((hdr) -> hb_flags & FREE_BLK) != 0)
-# define OBJ_SZ_TO_BLOCKS(sz) \
- divHBLKSZ(WORDS_TO_BYTES(sz) + HBLKSIZE-1)
- /* Size of block (in units of HBLKSIZE) needed to hold objects of */
- /* given sz (in words). */
+# define OBJ_SZ_TO_BLOCKS(sz) divHBLKSZ((sz) + HBLKSIZE-1)
+ /* Size of block (in units of HBLKSIZE) needed to hold objects of */
+ /* given sz (in bytes). */
/* Object free list link */
-# define obj_link(p) (*(ptr_t *)(p))
+# define obj_link(p) (*(void **)(p))
# define LOG_MAX_MARK_PROCS 6
# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS)
-/* Root sets. Logically private to mark_rts.c. But we don't want the */
-/* tables scanned, so we put them here. */
-/* MAX_ROOT_SETS is the maximum number of ranges that can be */
-/* registered as static roots. */
+/* Root sets. Logically private to mark_rts.c. But we don't want the */
+/* tables scanned, so we put them here. */
+/* 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
+# elif !defined(SMALL_CONFIG)
+# define MAX_ROOT_SETS 2048
# else
-# ifdef PCR
-# define MAX_ROOT_SETS 1024
-# else
-# if defined(MSWIN32) || defined(MSWINCE)
-# define MAX_ROOT_SETS 1024
- /* Under NT, we add only written pages, which can result */
- /* in many small root sets. */
-# else
-# define MAX_ROOT_SETS 256
-# endif
-# endif
+# define MAX_ROOT_SETS 512
# endif
# define MAX_EXCLUSIONS (MAX_ROOT_SETS/4)
-/* Maximum number of segments that can be excluded from root sets. */
+/* Maximum number of segments that can be excluded from root sets. */
/*
* Data structure for excluded static roots.
@@ -780,1179 +1000,1462 @@ struct exclusion {
ptr_t e_end;
};
-/* Data structure for list of root sets. */
-/* We keep a hash table, so that we can filter out duplicate additions. */
-/* Under Win32, we need to do a better job of filtering overlaps, so */
-/* we resort to sequential search, and pay the price. */
+/* Data structure for list of root sets. */
+/* We keep a hash table, so that we can filter out duplicate additions. */
+/* Under Win32, we need to do a better job of filtering overlaps, so */
+/* we resort to sequential search, and pay the price. */
struct roots {
- ptr_t r_start;
- ptr_t r_end;
-# if !defined(MSWIN32) && !defined(MSWINCE)
- struct roots * r_next;
-# endif
- GC_bool r_tmp;
- /* Delete before registering new dynamic libraries */
+ ptr_t r_start;/* multiple of word size */
+ ptr_t r_end; /* multiple of word size and greater than r_start */
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ struct roots * r_next;
+# endif
+ GC_bool r_tmp;
+ /* Delete before registering new dynamic libraries */
};
-#if !defined(MSWIN32) && !defined(MSWINCE)
- /* Size of hash table index to roots. */
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ /* Size of hash table index to roots. */
# define LOG_RT_SIZE 6
# define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */
#endif
-/* Lists of all heap blocks and free lists */
-/* as well as other random data structures */
-/* that should not be scanned by the */
-/* collector. */
-/* These are grouped together in a struct */
-/* so that they can be easily skipped by the */
-/* GC_mark routine. */
-/* The ordering is weird to make GC_malloc */
-/* faster by keeping the important fields */
-/* sufficiently close together that a */
-/* single load of a base register will do. */
-/* Scalars that could easily appear to */
-/* be pointers are also put here. */
-/* The main fields should precede any */
-/* conditionally included fields, so that */
-/* gc_inl.h will work even if a different set */
-/* of macros is defined when the client is */
-/* compiled. */
+#ifndef MAX_HEAP_SECTS
+# ifdef LARGE_CONFIG
+# if CPP_WORDSZ > 32
+# define MAX_HEAP_SECTS 8192 /* overflows at roughly 128 GB */
+# else
+# define MAX_HEAP_SECTS 768 /* Separately added heap sections. */
+# endif
+# elif defined(SMALL_CONFIG) && !defined(USE_PROC_FOR_LIBRARIES)
+# if defined(PARALLEL_MARK) && (defined(MSWIN32) || defined(CYGWIN32))
+# define MAX_HEAP_SECTS 384
+# else
+# define MAX_HEAP_SECTS 128 /* Roughly 256MB (128*2048*1K) */
+# endif
+# elif CPP_WORDSZ > 32
+# define MAX_HEAP_SECTS 1024 /* Roughly 8GB */
+# else
+# define MAX_HEAP_SECTS 512 /* Roughly 4GB */
+# endif
+#endif /* !MAX_HEAP_SECTS */
+
+/* Lists of all heap blocks and free lists */
+/* as well as other random data structures */
+/* that should not be scanned by the */
+/* collector. */
+/* These are grouped together in a struct */
+/* so that they can be easily skipped by the */
+/* GC_mark routine. */
+/* The ordering is weird to make GC_malloc */
+/* faster by keeping the important fields */
+/* sufficiently close together that a */
+/* single load of a base register will do. */
+/* Scalars that could easily appear to */
+/* be pointers are also put here. */
+/* The main fields should precede any */
+/* conditionally included fields, so that */
+/* gc_inl.h will work even if a different set */
+/* of macros is defined when the client is */
+/* compiled. */
struct _GC_arrays {
- word _heapsize;
- word _max_heapsize;
- word _requested_heapsize; /* Heap size due to explicit expansion */
+ word _heapsize; /* Heap size in bytes. */
+ word _requested_heapsize; /* Heap size due to explicit expansion. */
ptr_t _last_heap_addr;
ptr_t _prev_heap_addr;
word _large_free_bytes;
- /* Total bytes contained in blocks on large object free */
- /* list. */
+ /* Total bytes contained in blocks on large object free */
+ /* list. */
word _large_allocd_bytes;
- /* Total number of bytes in allocated large objects blocks. */
- /* For the purposes of this counter and the next one only, a */
- /* large object is one that occupies a block of at least */
- /* 2*HBLKSIZE. */
+ /* Total number of bytes in allocated large objects blocks. */
+ /* For the purposes of this counter and the next one only, a */
+ /* large object is one that occupies a block of at least */
+ /* 2*HBLKSIZE. */
word _max_large_allocd_bytes;
- /* Maximum number of bytes that were ever allocated in */
- /* large object blocks. This is used to help decide when it */
- /* is safe to split up a large block. */
- word _words_allocd_before_gc;
- /* Number of words allocated before this */
- /* collection cycle. */
+ /* Maximum number of bytes that were ever allocated in */
+ /* large object blocks. This is used to help decide when it */
+ /* is safe to split up a large block. */
+ word _bytes_allocd_before_gc;
+ /* Number of bytes allocated before this */
+ /* collection cycle. */
# ifndef SEPARATE_GLOBALS
- word _words_allocd;
- /* Number of words allocated during this collection cycle */
-# endif
- word _words_wasted;
- /* Number of words wasted due to internal fragmentation */
- /* in large objects, or due to dropping blacklisted */
- /* blocks, since last gc. Approximate. */
- word _words_finalized;
- /* Approximate number of words in objects (and headers) */
- /* That became ready for finalization in the last */
- /* collection. */
- word _non_gc_bytes_at_gc;
- /* Number of explicitly managed bytes of storage */
- /* at last collection. */
- word _mem_freed;
- /* Number of explicitly deallocated words of memory */
- /* since last collection. */
- word _finalizer_mem_freed;
- /* Words of memory explicitly deallocated while */
- /* finalizers were running. Used to approximate mem. */
- /* explicitly deallocated by finalizers. */
+# define GC_bytes_allocd GC_arrays._bytes_allocd
+ word _bytes_allocd;
+ /* Number of bytes 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 */
+ /* collection. */
+ word _bytes_freed;
+ /* Number of explicitly deallocated bytes of memory */
+ /* since last collection. */
+ word _finalizer_bytes_freed;
+ /* Bytes of memory explicitly deallocated while */
+ /* finalizers were running. Used to approximate mem. */
+ /* explicitly deallocated by finalizers. */
ptr_t _scratch_end_ptr;
ptr_t _scratch_last_end_ptr;
- /* Used by headers.c, and can easily appear to point to */
- /* heap. */
+ /* Used by headers.c, and can easily appear to point to */
+ /* heap. */
GC_mark_proc _mark_procs[MAX_MARK_PROCS];
- /* Table of user-defined mark procedures. There is */
- /* a small number of these, which can be referenced */
- /* by DS_PROC mark descriptors. See gc_mark.h. */
-
+ /* Table of user-defined mark procedures. There is */
+ /* a small number of these, which can be referenced */
+ /* by DS_PROC mark descriptors. See gc_mark.h. */
# ifndef SEPARATE_GLOBALS
- ptr_t _objfreelist[MAXOBJSZ+1];
- /* free list for objects */
- ptr_t _aobjfreelist[MAXOBJSZ+1];
- /* free list for atomic objs */
-# endif
-
- ptr_t _uobjfreelist[MAXOBJSZ+1];
- /* uncollectable but traced objs */
- /* objects on this and auobjfreelist */
- /* are always marked, except during */
- /* garbage collections. */
+# define GC_objfreelist GC_arrays._objfreelist
+ void *_objfreelist[MAXOBJGRANULES+1];
+ /* free list for objects */
+# define GC_aobjfreelist GC_arrays._aobjfreelist
+ void *_aobjfreelist[MAXOBJGRANULES+1];
+ /* free list for atomic objs */
+# endif
+ void *_uobjfreelist[MAXOBJGRANULES+1];
+ /* Uncollectable but traced objs */
+ /* objects on this and auobjfreelist */
+ /* are always marked, except during */
+ /* garbage collections. */
# ifdef ATOMIC_UNCOLLECTABLE
- ptr_t _auobjfreelist[MAXOBJSZ+1];
-# endif
- /* uncollectable but traced objs */
-
-# ifdef GATHERSTATS
- word _composite_in_use;
- /* Number of words in accessible composite */
- /* objects. */
- word _atomic_in_use;
- /* Number of words in accessible atomic */
- /* objects. */
+# define GC_auobjfreelist GC_arrays._auobjfreelist
+ void *_auobjfreelist[MAXOBJGRANULES+1];
+ /* Atomic uncollectable but traced objs */
# endif
+ word _composite_in_use; /* Number of bytes in the accessible */
+ /* composite objects. */
+ word _atomic_in_use; /* Number of bytes in the accessible */
+ /* atomic objects. */
# ifdef USE_MUNMAP
+# define GC_unmapped_bytes GC_arrays._unmapped_bytes
word _unmapped_bytes;
+# else
+# define GC_unmapped_bytes 0
# endif
-# ifdef MERGE_SIZES
- unsigned _size_map[WORDS_TO_BYTES(MAXOBJSZ+1)];
- /* Number of words to allocate for a given allocation request in */
- /* bytes. */
-# endif
+ size_t _size_map[MAXOBJBYTES+1];
+ /* Number of granules to allocate when asked for a certain */
+ /* number of bytes. */
# ifdef STUBBORN_ALLOC
- ptr_t _sobjfreelist[MAXOBJSZ+1];
-# endif
- /* free list for immutable objects */
- map_entry_type * _obj_map[MAXOBJSZ+1];
- /* If not NIL, then a pointer to a map of valid */
- /* object addresses. _obj_map[sz][i] is j if the */
- /* address block_start+i is a valid pointer */
- /* to an object at block_start + */
- /* WORDS_TO_BYTES(BYTES_TO_WORDS(i) - j) */
- /* I.e. j is a word displacement from the */
- /* object beginning. */
- /* The entry is OBJ_INVALID if the corresponding */
- /* address is not a valid pointer. It is */
- /* OFFSET_TOO_BIG if the value j would be too */
- /* large to fit in the entry. (Note that the */
- /* size of these entries matters, both for */
- /* space consumption and for cache utilization.) */
-# define OFFSET_TOO_BIG 0xfe
-# define OBJ_INVALID 0xff
-# define MAP_ENTRY(map, bytes) (map)[bytes]
-# define MAP_ENTRIES HBLKSIZE
-# define MAP_SIZE MAP_ENTRIES
-# define CPP_MAX_OFFSET (OFFSET_TOO_BIG - 1)
-# define MAX_OFFSET ((word)CPP_MAX_OFFSET)
- /* The following are used only if GC_all_interior_ptrs != 0 */
-# define VALID_OFFSET_SZ \
- (CPP_MAX_OFFSET > WORDS_TO_BYTES(CPP_MAXOBJSZ)? \
- CPP_MAX_OFFSET+1 \
- : WORDS_TO_BYTES(CPP_MAXOBJSZ)+1)
- char _valid_offsets[VALID_OFFSET_SZ];
- /* GC_valid_offsets[i] == TRUE ==> i */
- /* is registered as a displacement. */
- char _modws_valid_offsets[sizeof(word)];
- /* GC_valid_offsets[i] ==> */
- /* GC_modws_valid_offsets[i%sizeof(word)] */
-# define OFFSET_VALID(displ) \
- (GC_all_interior_pointers || GC_valid_offsets[displ])
+# define GC_sobjfreelist GC_arrays._sobjfreelist
+ ptr_t _sobjfreelist[MAXOBJGRANULES+1];
+# endif
+ /* free list for immutable objects */
+# ifdef MARK_BIT_PER_GRANULE
+# define GC_obj_map GC_arrays._obj_map
+ short * _obj_map[MAXOBJGRANULES+1];
+ /* If not NULL, then a pointer to a map of valid */
+ /* object addresses. */
+ /* _obj_map[sz_in_granules][i] is */
+ /* i % sz_in_granules. */
+ /* This is now used purely to replace a */
+ /* division in the marker by a table lookup. */
+ /* _obj_map[0] is used for large objects and */
+ /* contains all nonzero entries. This gets us */
+ /* out of the marker fast path without an extra */
+ /* test. */
+# define MAP_LEN BYTES_TO_GRANULES(HBLKSIZE)
+# endif
+# define VALID_OFFSET_SZ HBLKSIZE
+ char _valid_offsets[VALID_OFFSET_SZ];
+ /* GC_valid_offsets[i] == TRUE ==> i */
+ /* is registered as a displacement. */
+ char _modws_valid_offsets[sizeof(word)];
+ /* GC_valid_offsets[i] ==> */
+ /* GC_modws_valid_offsets[i%sizeof(word)] */
# ifdef STUBBORN_ALLOC
+# define GC_changed_pages GC_arrays._changed_pages
page_hash_table _changed_pages;
- /* Stubborn object pages that were changes since last call to */
- /* GC_read_changed. */
+ /* Stubborn object pages that were changes since last call to */
+ /* GC_read_changed. */
+# define GC_prev_changed_pages GC_arrays._prev_changed_pages
page_hash_table _prev_changed_pages;
- /* Stubborn object pages that were changes before last call to */
- /* GC_read_changed. */
-# endif
-# if defined(PROC_VDB) || defined(MPROTECT_VDB)
- page_hash_table _grungy_pages; /* Pages that were dirty at last */
- /* GC_read_dirty. */
+ /* Stubborn object pages that were changes before last call to */
+ /* GC_read_changed. */
# endif
-# ifdef MPROTECT_VDB
- VOLATILE page_hash_table _dirty_pages;
- /* Pages dirtied since last GC_read_dirty. */
+# if defined(PROC_VDB) || defined(MPROTECT_VDB) \
+ || defined(GWW_VDB) || defined(MANUAL_VDB)
+# define GC_grungy_pages GC_arrays._grungy_pages
+ page_hash_table _grungy_pages; /* Pages that were dirty at last */
+ /* GC_read_dirty. */
# endif
-# ifdef PROC_VDB
- page_hash_table _written_pages; /* Pages ever dirtied */
+# if defined(MPROTECT_VDB) || defined(MANUAL_VDB)
+# define GC_dirty_pages GC_arrays._dirty_pages
+ volatile page_hash_table _dirty_pages;
+ /* Pages dirtied since last GC_read_dirty. */
# endif
-# ifdef LARGE_CONFIG
-# if CPP_WORDSZ > 32
-# define MAX_HEAP_SECTS 4096 /* overflows at roughly 64 GB */
-# else
-# define MAX_HEAP_SECTS 768 /* Separately added heap sections. */
-# endif
-# else
-# ifdef SMALL_CONFIG
-# define MAX_HEAP_SECTS 128 /* Roughly 256MB (128*2048*1K) */
-# else
-# define MAX_HEAP_SECTS 384 /* Roughly 3GB */
-# endif
+# if defined(PROC_VDB) || defined(GWW_VDB)
+# define GC_written_pages GC_arrays._written_pages
+ page_hash_table _written_pages; /* Pages ever dirtied */
# endif
+# define GC_heap_sects GC_arrays._heap_sects
struct HeapSect {
- ptr_t hs_start; word hs_bytes;
- } _heap_sects[MAX_HEAP_SECTS];
-# if defined(MSWIN32) || defined(MSWINCE)
+ ptr_t hs_start;
+ size_t hs_bytes;
+ } _heap_sects[MAX_HEAP_SECTS]; /* Heap segments potentially */
+ /* client objects. */
+# if defined(USE_PROC_FOR_LIBRARIES)
+# define GC_our_memory GC_arrays._our_memory
+ struct HeapSect _our_memory[MAX_HEAP_SECTS];
+ /* All GET_MEM allocated */
+ /* memory. Includes block */
+ /* headers and the like. */
+# endif
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+# define GC_heap_bases GC_arrays._heap_bases
ptr_t _heap_bases[MAX_HEAP_SECTS];
- /* Start address of memory regions obtained from kernel. */
+ /* Start address of memory regions obtained from kernel. */
# endif
# ifdef MSWINCE
+# define GC_heap_lengths GC_arrays._heap_lengths
word _heap_lengths[MAX_HEAP_SECTS];
- /* Commited lengths of memory regions obtained from kernel. */
+ /* Committed lengths of memory regions obtained from kernel. */
# endif
struct roots _static_roots[MAX_ROOT_SETS];
-# if !defined(MSWIN32) && !defined(MSWINCE)
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+# define GC_root_index GC_arrays._root_index
struct roots * _root_index[RT_SIZE];
# endif
struct exclusion _excl_table[MAX_EXCLUSIONS];
/* Block header index; see gc_headers.h */
bottom_index * _all_nils;
bottom_index * _top_index [TOP_SZ];
-#ifdef SAVE_CALL_CHAIN
- struct callinfo _last_stack[NFRAMES]; /* Stack at last garbage collection.*/
- /* Useful for debugging mysterious */
- /* object disappearances. */
- /* In the multithreaded case, we */
- /* currently only save the calling */
- /* stack. */
-#endif
-};
-
-GC_API GC_FAR struct _GC_arrays GC_arrays;
-
-# ifndef SEPARATE_GLOBALS
-# define GC_objfreelist GC_arrays._objfreelist
-# define GC_aobjfreelist GC_arrays._aobjfreelist
-# define GC_words_allocd GC_arrays._words_allocd
-# endif
-# define GC_uobjfreelist GC_arrays._uobjfreelist
-# ifdef ATOMIC_UNCOLLECTABLE
-# define GC_auobjfreelist GC_arrays._auobjfreelist
-# endif
-# define GC_sobjfreelist GC_arrays._sobjfreelist
-# define GC_valid_offsets GC_arrays._valid_offsets
-# define GC_modws_valid_offsets GC_arrays._modws_valid_offsets
-# ifdef STUBBORN_ALLOC
-# define GC_changed_pages GC_arrays._changed_pages
-# define GC_prev_changed_pages GC_arrays._prev_changed_pages
-# endif
-# define GC_obj_map GC_arrays._obj_map
-# define GC_last_heap_addr GC_arrays._last_heap_addr
-# define GC_prev_heap_addr GC_arrays._prev_heap_addr
-# define GC_words_wasted GC_arrays._words_wasted
-# define GC_large_free_bytes GC_arrays._large_free_bytes
-# define GC_large_allocd_bytes GC_arrays._large_allocd_bytes
-# define GC_max_large_allocd_bytes GC_arrays._max_large_allocd_bytes
-# define GC_words_finalized GC_arrays._words_finalized
-# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
-# define GC_mem_freed GC_arrays._mem_freed
-# define GC_finalizer_mem_freed GC_arrays._finalizer_mem_freed
-# define GC_scratch_end_ptr GC_arrays._scratch_end_ptr
-# define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
-# define GC_mark_procs GC_arrays._mark_procs
-# define GC_heapsize GC_arrays._heapsize
-# define GC_max_heapsize GC_arrays._max_heapsize
-# define GC_requested_heapsize GC_arrays._requested_heapsize
-# define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc
-# define GC_heap_sects GC_arrays._heap_sects
-# define GC_last_stack GC_arrays._last_stack
-# ifdef USE_MUNMAP
-# define GC_unmapped_bytes GC_arrays._unmapped_bytes
-# endif
-# if defined(MSWIN32) || defined(MSWINCE)
-# define GC_heap_bases GC_arrays._heap_bases
-# endif
-# ifdef MSWINCE
-# define GC_heap_lengths GC_arrays._heap_lengths
-# endif
-# define GC_static_roots GC_arrays._static_roots
-# define GC_root_index GC_arrays._root_index
-# define GC_excl_table GC_arrays._excl_table
-# define GC_all_nils GC_arrays._all_nils
-# define GC_top_index GC_arrays._top_index
-# if defined(PROC_VDB) || defined(MPROTECT_VDB)
-# define GC_grungy_pages GC_arrays._grungy_pages
+# ifdef ENABLE_TRACE
+# define GC_trace_addr GC_arrays._trace_addr
+ ptr_t _trace_addr;
+# endif
+# ifdef SAVE_CALL_CHAIN
+# define GC_last_stack GC_arrays._last_stack
+ struct callinfo _last_stack[NFRAMES];
+ /* Stack at last garbage collection. Useful for */
+ /* debugging mysterious object disappearances. In the */
+ /* multithreaded case, we currently only save the */
+ /* calling stack. */
# endif
-# ifdef MPROTECT_VDB
-# define GC_dirty_pages GC_arrays._dirty_pages
-# endif
-# ifdef PROC_VDB
-# define GC_written_pages GC_arrays._written_pages
-# endif
-# ifdef GATHERSTATS
-# define GC_composite_in_use GC_arrays._composite_in_use
-# define GC_atomic_in_use GC_arrays._atomic_in_use
-# endif
-# ifdef MERGE_SIZES
-# define GC_size_map GC_arrays._size_map
-# endif
-
-# define beginGC_arrays ((ptr_t)(&GC_arrays))
-# define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays))
+};
+GC_API_PRIV GC_FAR struct _GC_arrays GC_arrays;
+
+#define GC_all_nils GC_arrays._all_nils
+#define GC_atomic_in_use GC_arrays._atomic_in_use
+#define GC_bytes_allocd_before_gc GC_arrays._bytes_allocd_before_gc
+#define GC_bytes_dropped GC_arrays._bytes_dropped
+#define GC_bytes_finalized GC_arrays._bytes_finalized
+#define GC_bytes_freed GC_arrays._bytes_freed
+#define GC_composite_in_use GC_arrays._composite_in_use
+#define GC_excl_table GC_arrays._excl_table
+#define GC_finalizer_bytes_freed GC_arrays._finalizer_bytes_freed
+#define GC_heapsize GC_arrays._heapsize
+#define GC_large_allocd_bytes GC_arrays._large_allocd_bytes
+#define GC_large_free_bytes GC_arrays._large_free_bytes
+#define GC_last_heap_addr GC_arrays._last_heap_addr
+#define GC_mark_procs GC_arrays._mark_procs
+#define GC_max_large_allocd_bytes GC_arrays._max_large_allocd_bytes
+#define GC_modws_valid_offsets GC_arrays._modws_valid_offsets
+#define GC_prev_heap_addr GC_arrays._prev_heap_addr
+#define GC_requested_heapsize GC_arrays._requested_heapsize
+#define GC_scratch_end_ptr GC_arrays._scratch_end_ptr
+#define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
+#define GC_size_map GC_arrays._size_map
+#define GC_static_roots GC_arrays._static_roots
+#define GC_top_index GC_arrays._top_index
+#define GC_uobjfreelist GC_arrays._uobjfreelist
+#define GC_valid_offsets GC_arrays._valid_offsets
+
+#define beginGC_arrays ((ptr_t)(&GC_arrays))
+#define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays))
#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes)
/* Object kinds: */
-# define MAXOBJKINDS 16
+#define MAXOBJKINDS 16
-extern struct obj_kind {
- ptr_t *ok_freelist; /* Array of free listheaders for this kind of object */
- /* Point either to GC_arrays or to storage allocated */
- /* with GC_scratch_alloc. */
+GC_EXTERN struct obj_kind {
+ void **ok_freelist; /* Array of free listheaders for this kind of object */
+ /* Point either to GC_arrays or to storage allocated */
+ /* with GC_scratch_alloc. */
struct hblk **ok_reclaim_list;
- /* List headers for lists of blocks waiting to be */
- /* swept. */
- word ok_descriptor; /* Descriptor template for objects in this */
- /* block. */
+ /* List headers for lists of blocks waiting to be */
+ /* swept. */
+ /* Indexed by object size in granules. */
+ word ok_descriptor; /* Descriptor template for objects in this */
+ /* block. */
GC_bool ok_relocate_descr;
- /* Add object size in bytes to descriptor */
- /* template to obtain descriptor. Otherwise */
- /* template is used as is. */
+ /* Add object size in bytes to descriptor */
+ /* template to obtain descriptor. Otherwise */
+ /* template is used as is. */
GC_bool ok_init; /* Clear objects before putting them on the free list. */
+# ifdef ENABLE_DISCLAIM
+ GC_bool ok_mark_unconditionally;
+ /* Mark from all, including unmarked, objects */
+ /* in block. Used to protect objects reachable */
+ /* from reclaim notifiers. */
+ int (GC_CALLBACK *ok_disclaim_proc)(void * /*obj*/);
+ /* The disclaim procedure is called before obj */
+ /* is reclaimed, but must also tolerate being */
+ /* called with object from freelist. Non-zero */
+ /* exit prevents object from being reclaimed. */
+# define OK_DISCLAIM_INITZ /* comma */, FALSE, 0
+# else
+# define OK_DISCLAIM_INITZ /* empty */
+# endif /* !ENABLE_DISCLAIM */
} GC_obj_kinds[MAXOBJKINDS];
-# define beginGC_obj_kinds ((ptr_t)(&GC_obj_kinds))
-# define endGC_obj_kinds (beginGC_obj_kinds + (sizeof GC_obj_kinds))
+#define beginGC_obj_kinds ((ptr_t)(&GC_obj_kinds))
+#define endGC_obj_kinds (beginGC_obj_kinds + (sizeof GC_obj_kinds))
-/* Variables that used to be in GC_arrays, but need to be accessed by */
-/* inline allocation code. If they were in GC_arrays, the inlined */
-/* allocation code would include GC_arrays offsets (as it did), which */
-/* introduce maintenance problems. */
+/* Variables that used to be in GC_arrays, but need to be accessed by */
+/* inline allocation code. If they were in GC_arrays, the inlined */
+/* allocation code would include GC_arrays offsets (as it did), which */
+/* introduce maintenance problems. */
#ifdef SEPARATE_GLOBALS
- word GC_words_allocd;
- /* Number of words allocated during this collection cycle */
- ptr_t GC_objfreelist[MAXOBJSZ+1];
- /* free list for NORMAL objects */
+ extern word GC_bytes_allocd;
+ /* Number of bytes allocated during this collection cycle. */
+ extern ptr_t GC_objfreelist[MAXOBJGRANULES+1];
+ /* free list for NORMAL objects */
# define beginGC_objfreelist ((ptr_t)(&GC_objfreelist))
# define endGC_objfreelist (beginGC_objfreelist + sizeof(GC_objfreelist))
- ptr_t GC_aobjfreelist[MAXOBJSZ+1];
- /* free list for atomic (PTRFREE) objs */
+ extern ptr_t GC_aobjfreelist[MAXOBJGRANULES+1];
+ /* free list for atomic (PTRFREE) objs */
# define beginGC_aobjfreelist ((ptr_t)(&GC_aobjfreelist))
# define endGC_aobjfreelist (beginGC_aobjfreelist + sizeof(GC_aobjfreelist))
-#endif
+#endif /* SEPARATE_GLOBALS */
/* Predefined kinds: */
-# define PTRFREE 0
-# define NORMAL 1
-# define UNCOLLECTABLE 2
-# ifdef ATOMIC_UNCOLLECTABLE
-# define AUNCOLLECTABLE 3
-# define STUBBORN 4
-# define IS_UNCOLLECTABLE(k) (((k) & ~1) == UNCOLLECTABLE)
-# else
-# define STUBBORN 3
-# define IS_UNCOLLECTABLE(k) ((k) == UNCOLLECTABLE)
-# endif
+#define PTRFREE 0
+#define NORMAL 1
+#define UNCOLLECTABLE 2
+#ifdef ATOMIC_UNCOLLECTABLE
+# define AUNCOLLECTABLE 3
+# define STUBBORN 4
+# define IS_UNCOLLECTABLE(k) (((k) & ~1) == UNCOLLECTABLE)
+#else
+# define STUBBORN 3
+# define IS_UNCOLLECTABLE(k) ((k) == UNCOLLECTABLE)
+#endif
-extern int GC_n_kinds;
+GC_EXTERN unsigned GC_n_kinds;
-GC_API word GC_fo_entries;
+GC_EXTERN word GC_n_heap_sects; /* Number of separately added heap */
+ /* sections. */
-extern word GC_n_heap_sects; /* Number of separately added heap */
- /* sections. */
+#ifdef USE_PROC_FOR_LIBRARIES
+ GC_EXTERN word GC_n_memory; /* Number of GET_MEM allocated memory */
+ /* sections. */
+#endif
-extern word GC_page_size;
+GC_EXTERN word GC_page_size;
-# if defined(MSWIN32) || defined(MSWINCE)
+#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
struct _SYSTEM_INFO;
- extern struct _SYSTEM_INFO GC_sysinfo;
- extern word GC_n_heap_bases; /* See GC_heap_bases. */
-# endif
-
-extern word GC_total_stack_black_listed;
- /* Number of bytes on stack blacklist. */
-
-extern word GC_black_list_spacing;
- /* Average number of bytes between blacklisted */
- /* blocks. Approximate. */
- /* Counts only blocks that are */
- /* "stack-blacklisted", i.e. that are */
- /* problematic in the interior of an object. */
+ GC_EXTERN struct _SYSTEM_INFO GC_sysinfo;
+ GC_INNER GC_bool GC_is_heap_base(ptr_t p);
+#endif
-extern map_entry_type * GC_invalid_map;
- /* Pointer to the nowhere valid hblk map */
- /* Blocks pointing to this map are free. */
-extern struct hblk * GC_hblkfreelist[];
- /* List of completely empty heap blocks */
- /* Linked through hb_next field of */
- /* header structure associated with */
- /* block. */
+GC_EXTERN word GC_black_list_spacing;
+ /* Average number of bytes between blacklisted */
+ /* blocks. Approximate. */
+ /* Counts only blocks that are */
+ /* "stack-blacklisted", i.e. that are */
+ /* problematic in the interior of an object. */
-extern GC_bool GC_objects_are_marked; /* There are marked objects in */
- /* the heap. */
+#ifdef GC_GCJ_SUPPORT
+ extern struct hblk * GC_hblkfreelist[];
+ /* Remains visible to GNU GCJ. */
+#endif
-#ifndef SMALL_CONFIG
- extern GC_bool GC_incremental;
- /* Using incremental/generational collection. */
-# define TRUE_INCREMENTAL \
- (GC_incremental && GC_time_limit != GC_TIME_UNLIMITED)
- /* True incremental, not just generational, mode */
-#else
+#ifdef GC_DISABLE_INCREMENTAL
# define GC_incremental FALSE
- /* Hopefully allow optimizer to remove some code. */
+ /* Hopefully allow optimizer to remove some code. */
# define TRUE_INCREMENTAL FALSE
-#endif
-
-extern GC_bool GC_dirty_maintained;
- /* Dirty bits are being maintained, */
- /* either for incremental collection, */
- /* or to limit the root set. */
+#else
+ GC_EXTERN GC_bool GC_incremental;
+ /* Using incremental/generational collection. */
+# define TRUE_INCREMENTAL \
+ (GC_incremental && GC_time_limit != GC_TIME_UNLIMITED)
+ /* True incremental, not just generational, mode */
+#endif /* !GC_DISABLE_INCREMENTAL */
-extern word GC_root_size; /* Total size of registered root sections */
+GC_EXTERN word GC_root_size; /* Total size of registered root sections. */
-extern GC_bool GC_debugging_started; /* GC_debug_malloc has been called. */
+GC_EXTERN GC_bool GC_debugging_started;
+ /* GC_debug_malloc has been called. */
-extern long GC_large_alloc_warn_interval;
- /* Interval between unsuppressed warnings. */
+/* This is used by GC_do_blocking[_inner](). */
+struct blocking_data {
+ GC_fn_type fn;
+ void * client_data; /* and result */
+};
-extern long GC_large_alloc_warn_suppressed;
- /* Number of warnings suppressed so far. */
+/* This is used by GC_call_with_gc_active(), GC_push_all_stack_sections(). */
+struct GC_traced_stack_sect_s {
+ ptr_t saved_stack_ptr;
+# ifdef IA64
+ ptr_t saved_backing_store_ptr;
+ ptr_t backing_store_end;
+# endif
+ struct GC_traced_stack_sect_s *prev;
+};
#ifdef THREADS
- extern GC_bool GC_world_stopped;
-#endif
-
-/* Operations */
-# ifndef abs
-# define abs(x) ((x) < 0? (-(x)) : (x))
-# endif
+ /* Process all "traced stack sections" - scan entire stack except for */
+ /* frames belonging to the user functions invoked by GC_do_blocking. */
+ GC_INNER void GC_push_all_stack_sections(ptr_t lo, ptr_t hi,
+ struct GC_traced_stack_sect_s *traced_stack_sect);
+ GC_EXTERN word GC_total_stacksize; /* updated on every push_all_stacks */
+#else
+ GC_EXTERN ptr_t GC_blocked_sp;
+ GC_EXTERN struct GC_traced_stack_sect_s *GC_traced_stack_sect;
+ /* Points to the "frame" data held in stack by */
+ /* the innermost GC_call_with_gc_active(). */
+ /* NULL if no such "frame" active. */
+#endif /* !THREADS */
+#ifdef IA64
+ /* Similar to GC_push_all_stack_sections() but for IA-64 registers store. */
+ GC_INNER void GC_push_all_register_sections(ptr_t bs_lo, ptr_t bs_hi,
+ int eager, struct GC_traced_stack_sect_s *traced_stack_sect);
+#endif
/* Marks are in a reserved area in */
/* each heap block. Each word has one mark bit associated */
/* with it. Only those corresponding to the beginning of an */
/* object are used. */
-/* Set mark bit correctly, even if mark bits may be concurrently */
-/* accessed. */
-#ifdef PARALLEL_MARK
-# define OR_WORD(addr, bits) \
- { word old; \
- do { \
- old = *((volatile word *)addr); \
- } while (!GC_compare_and_exchange((addr), old, old | (bits))); \
- }
-# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
- { word old; \
- word my_bits = (bits); \
- do { \
- old = *((volatile word *)addr); \
- if (old & my_bits) goto exit_label; \
- } while (!GC_compare_and_exchange((addr), old, old | my_bits)); \
- }
-#else
-# define OR_WORD(addr, bits) *(addr) |= (bits)
-# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
- { \
- word old = *(addr); \
- word my_bits = (bits); \
- if (old & my_bits) goto exit_label; \
- *(addr) = (old | my_bits); \
- }
-#endif
-
/* Mark bit operations */
/*
- * Retrieve, set, clear the mark bit corresponding
- * to the nth word in a given heap block.
+ * Retrieve, set, clear the nth mark bit in a given heap block.
*
- * (Recall that bit n corresponds to object beginning at word n
+ * (Recall that bit n corresponds to nth object or allocation granule
* relative to the beginning of the block, including unused words)
*/
#ifdef USE_MARK_BYTES
-# define mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n) >> 1])
-# define set_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n)>>1]) = 1
-# define clear_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n)>>1]) = 0
-#else /* !USE_MARK_BYTES */
-# define mark_bit_from_hdr(hhdr,n) (((hhdr)->hb_marks[divWORDSZ(n)] \
- >> (modWORDSZ(n))) & (word)1)
+# define mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n])
+# define set_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n] = 1)
+# define clear_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n] = 0)
+#else
+/* Set mark bit correctly, even if mark bits may be concurrently */
+/* accessed. */
+# ifdef PARALLEL_MARK
+ /* This is used only if we explicitly set USE_MARK_BITS. */
+# define OR_WORD(addr, bits) AO_or((volatile AO_t *)(addr), (AO_t)(bits))
+# else
+# define OR_WORD(addr, bits) (void)(*(addr) |= (bits))
+# endif
+# define mark_bit_from_hdr(hhdr,n) \
+ (((hhdr)->hb_marks[divWORDSZ(n)] >> modWORDSZ(n)) & (word)1)
# define set_mark_bit_from_hdr(hhdr,n) \
- OR_WORD((hhdr)->hb_marks+divWORDSZ(n), \
- (word)1 << modWORDSZ(n))
-# define clear_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \
- &= ~((word)1 << modWORDSZ(n))
+ OR_WORD((hhdr)->hb_marks+divWORDSZ(n), (word)1 << modWORDSZ(n))
+# define clear_mark_bit_from_hdr(hhdr,n) \
+ ((hhdr)->hb_marks[divWORDSZ(n)] &= ~((word)1 << modWORDSZ(n)))
#endif /* !USE_MARK_BYTES */
+#ifdef MARK_BIT_PER_OBJ
+# define MARK_BIT_NO(offset, sz) (((unsigned)(offset))/(sz))
+ /* Get the mark bit index corresponding to the given byte */
+ /* offset and size (in bytes). */
+# define MARK_BIT_OFFSET(sz) 1
+ /* Spacing between useful mark bits. */
+# define IF_PER_OBJ(x) x
+# define FINAL_MARK_BIT(sz) ((sz) > MAXOBJBYTES? 1 : HBLK_OBJS(sz))
+ /* Position of final, always set, mark bit. */
+#else /* MARK_BIT_PER_GRANULE */
+# define MARK_BIT_NO(offset, sz) BYTES_TO_GRANULES((unsigned)(offset))
+# define MARK_BIT_OFFSET(sz) BYTES_TO_GRANULES(sz)
+# define IF_PER_OBJ(x)
+# define FINAL_MARK_BIT(sz) \
+ ((sz) > MAXOBJBYTES ? MARK_BITS_PER_HBLK \
+ : BYTES_TO_GRANULES((sz) * HBLK_OBJS(sz)))
+#endif
+
/* Important internal collector routines */
-ptr_t GC_approx_sp GC_PROTO((void));
-
-GC_bool GC_should_collect GC_PROTO((void));
-
-void GC_apply_to_all_blocks GC_PROTO(( \
- void (*fn) GC_PROTO((struct hblk *h, word client_data)), \
- word client_data));
- /* Invoke fn(hbp, client_data) for each */
- /* allocated heap block. */
-struct hblk * GC_next_used_block GC_PROTO((struct hblk * h));
- /* Return first in-use block >= h */
-struct hblk * GC_prev_block GC_PROTO((struct hblk * h));
- /* Return last block <= h. Returned block */
- /* is managed by GC, but may or may not be in */
- /* use. */
-void GC_mark_init GC_PROTO((void));
-void GC_clear_marks GC_PROTO((void)); /* Clear mark bits for all heap objects. */
-void GC_invalidate_mark_state GC_PROTO((void));
- /* Tell the marker that marked */
- /* objects may point to unmarked */
- /* ones, and roots may point to */
- /* unmarked objects. */
- /* Reset mark stack. */
-GC_bool GC_mark_stack_empty GC_PROTO((void));
-GC_bool GC_mark_some GC_PROTO((ptr_t cold_gc_frame));
- /* Perform about one pages worth of marking */
- /* work of whatever kind is needed. Returns */
- /* quickly if no collection is in progress. */
- /* Return TRUE if mark phase finished. */
-void GC_initiate_gc GC_PROTO((void));
- /* initiate collection. */
- /* If the mark state is invalid, this */
- /* becomes full colleection. Otherwise */
- /* it's partial. */
-void GC_push_all GC_PROTO((ptr_t bottom, ptr_t top));
- /* Push everything in a range */
- /* onto mark stack. */
-void GC_push_selected GC_PROTO(( \
- ptr_t bottom, \
- ptr_t top, \
- int (*dirty_fn) GC_PROTO((struct hblk *h)), \
- void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top)) ));
- /* Push all pages h in [b,t) s.t. */
- /* select_fn(h) != 0 onto mark stack. */
-#ifndef SMALL_CONFIG
- void GC_push_conditional GC_PROTO((ptr_t b, ptr_t t, GC_bool all));
+GC_INNER ptr_t GC_approx_sp(void);
+
+GC_INNER GC_bool GC_should_collect(void);
+
+void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data),
+ word client_data);
+ /* Invoke fn(hbp, client_data) for each */
+ /* allocated heap block. */
+GC_INNER struct hblk * GC_next_used_block(struct hblk * h);
+ /* Return first in-use block >= h */
+GC_INNER struct hblk * GC_prev_block(struct hblk * h);
+ /* Return last block <= h. Returned block */
+ /* is managed by GC, but may or may not be in */
+ /* use. */
+GC_INNER void GC_mark_init(void);
+GC_INNER void GC_clear_marks(void);
+ /* Clear mark bits for all heap objects. */
+GC_INNER void GC_invalidate_mark_state(void);
+ /* Tell the marker that marked */
+ /* objects may point to unmarked */
+ /* ones, and roots may point to */
+ /* unmarked objects. Reset mark stack. */
+GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame);
+ /* Perform about one pages worth of marking */
+ /* work of whatever kind is needed. Returns */
+ /* quickly if no collection is in progress. */
+ /* Return TRUE if mark phase finished. */
+GC_INNER void GC_initiate_gc(void);
+ /* initiate collection. */
+ /* If the mark state is invalid, this */
+ /* becomes full collection. Otherwise */
+ /* it's partial. */
+
+GC_INNER GC_bool GC_collection_in_progress(void);
+ /* Collection is in progress, or was abandoned. */
+
+#ifndef GC_DISABLE_INCREMENTAL
+# define GC_PUSH_CONDITIONAL(b, t, all) \
+ GC_push_conditional((ptr_t)(b), (ptr_t)(t), all)
+ /* Do either of GC_push_all or GC_push_selected */
+ /* depending on the third arg. */
#else
-# define GC_push_conditional(b, t, all) GC_push_all(b, t)
-#endif
- /* Do either of the above, depending */
- /* on the third arg. */
-void GC_push_all_stack GC_PROTO((ptr_t b, ptr_t t));
- /* As above, but consider */
- /* interior pointers as valid */
-void GC_push_all_eager GC_PROTO((ptr_t b, ptr_t t));
- /* Same as GC_push_all_stack, but */
- /* ensures that stack is scanned */
- /* immediately, not just scheduled */
- /* for scanning. */
-#ifndef THREADS
- void GC_push_all_stack_partially_eager GC_PROTO(( \
- ptr_t bottom, ptr_t top, ptr_t cold_gc_frame ));
- /* Similar to GC_push_all_eager, but only the */
- /* part hotter than cold_gc_frame is scanned */
- /* immediately. Needed to ensure that callee- */
- /* save registers are not missed. */
-#else
- /* In the threads case, we push part of the current thread stack */
+# define GC_PUSH_CONDITIONAL(b, t, all) GC_push_all((ptr_t)(b), (ptr_t)(t))
+#endif
+
+GC_INNER void GC_push_all_stack(ptr_t b, ptr_t t);
+ /* As GC_push_all but consider */
+ /* interior pointers as valid. */
+GC_INNER void GC_push_all_eager(ptr_t b, ptr_t t);
+ /* Same as GC_push_all_stack, but */
+ /* ensures that stack is scanned */
+ /* immediately, not just scheduled */
+ /* for scanning. */
+
+ /* In the threads case, we push part of the current thread stack */
/* with GC_push_all_eager when we push the registers. This gets the */
- /* callee-save registers that may disappear. The remainder of the */
- /* stacks are scheduled for scanning in *GC_push_other_roots, which */
- /* is thread-package-specific. */
-#endif
-void GC_push_current_stack GC_PROTO((ptr_t cold_gc_frame));
- /* Push enough of the current stack eagerly to */
- /* ensure that callee-save registers saved in */
- /* GC frames are scanned. */
- /* In the non-threads case, schedule entire */
- /* stack for scanning. */
-void GC_push_roots GC_PROTO((GC_bool all, ptr_t cold_gc_frame));
- /* Push all or dirty roots. */
-extern void (*GC_push_other_roots) GC_PROTO((void));
- /* Push system or application specific roots */
- /* onto the mark stack. In some environments */
- /* (e.g. threads environments) this is */
- /* predfined to be non-zero. A client supplied */
- /* replacement should also call the original */
- /* function. */
-extern void GC_push_gc_structures GC_PROTO((void));
- /* Push GC internal roots. These are normally */
- /* included in the static data segment, and */
- /* Thus implicitly pushed. But we must do this */
- /* explicitly if normal root processing is */
- /* disabled. Calls the following: */
- extern void GC_push_finalizer_structures GC_PROTO((void));
- extern void GC_push_stubborn_structures GC_PROTO((void));
-# ifdef THREADS
- extern void GC_push_thread_structures GC_PROTO((void));
-# endif
-extern void (*GC_start_call_back) GC_PROTO((void));
- /* Called at start of full collections. */
- /* Not called if 0. Called with allocation */
- /* lock held. */
- /* 0 by default. */
-# if defined(USE_GENERIC_PUSH_REGS)
- void GC_generic_push_regs GC_PROTO((ptr_t cold_gc_frame));
-# else
- void GC_push_regs GC_PROTO((void));
-# endif
-# if defined(SPARC) || defined(IA64)
- /* Cause all stacked registers to be saved in memory. Return a */
- /* pointer to the top of the corresponding memory stack. */
- word GC_save_regs_in_stack GC_PROTO((void));
-# endif
- /* Push register contents onto mark stack. */
- /* If NURSERY is defined, the default push */
- /* action can be overridden with GC_push_proc */
+ /* callee-save registers that may disappear. The remainder of the */
+ /* stacks are scheduled for scanning in *GC_push_other_roots, which */
+ /* is thread-package-specific. */
+
+GC_INNER void GC_push_roots(GC_bool all, ptr_t cold_gc_frame);
+ /* Push all or dirty roots. */
+
+GC_API_PRIV GC_push_other_roots_proc GC_push_other_roots;
+ /* Push system or application specific roots */
+ /* onto the mark stack. In some environments */
+ /* (e.g. threads environments) this is */
+ /* predefined to be non-zero. A client */
+ /* supplied replacement should also call the */
+ /* original function. Remains externally */
+ /* visible as used by some well-known 3rd-party */
+ /* software (e.g., ECL) currently. */
-# ifdef NURSERY
- extern void (*GC_push_proc)(ptr_t);
-# endif
-# if defined(MSWIN32) || defined(MSWINCE)
- void __cdecl GC_push_one GC_PROTO((word p));
-# else
- void GC_push_one GC_PROTO((word p));
- /* If p points to an object, mark it */
+#ifdef THREADS
+ void GC_push_thread_structures(void);
+#endif
+GC_EXTERN void (*GC_push_typed_structures)(void);
+ /* A pointer such that we can avoid linking in */
+ /* the typed allocation support if unused. */
+
+GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
+ ptr_t arg);
+
+#if defined(SPARC) || defined(IA64)
+ /* Cause all stacked registers to be saved in memory. Return a */
+ /* pointer to the top of the corresponding memory stack. */
+ ptr_t GC_save_regs_in_stack(void);
+#endif
+ /* Push register contents onto mark stack. */
+
+#if defined(MSWIN32) || defined(MSWINCE)
+ void __cdecl GC_push_one(word p);
+#else
+ void GC_push_one(word p);
+ /* If p points to an object, mark it */
/* and push contents on the mark stack */
- /* Pointer recognition test always */
- /* accepts interior pointers, i.e. this */
- /* is appropriate for pointers found on */
- /* stack. */
-# endif
-# if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
- void GC_mark_and_push_stack GC_PROTO((word p, ptr_t source));
- /* Ditto, omits plausibility test */
-# else
- void GC_mark_and_push_stack GC_PROTO((word p));
-# endif
-void GC_push_marked GC_PROTO((struct hblk * h, hdr * hhdr));
- /* Push contents of all marked objects in h onto */
- /* mark stack. */
-#ifdef SMALL_CONFIG
-# define GC_push_next_marked_dirty(h) GC_push_next_marked(h)
+ /* Pointer recognition test always */
+ /* accepts interior pointers, i.e. this */
+ /* is appropriate for pointers found on */
+ /* stack. */
+#endif
+
+#if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
+ GC_INNER void GC_mark_and_push_stack(ptr_t p, ptr_t source);
+ /* Ditto, omits plausibility test */
#else
- struct hblk * GC_push_next_marked_dirty GC_PROTO((struct hblk * h));
- /* Invoke GC_push_marked on next dirty block above h. */
- /* Return a pointer just past the end of this block. */
-#endif /* !SMALL_CONFIG */
-struct hblk * GC_push_next_marked GC_PROTO((struct hblk * h));
- /* Ditto, but also mark from clean pages. */
-struct hblk * GC_push_next_marked_uncollectable GC_PROTO((struct hblk * h));
- /* Ditto, but mark only from uncollectable pages. */
-GC_bool GC_stopped_mark GC_PROTO((GC_stop_func stop_func));
- /* Stop world and mark from all roots */
- /* and rescuers. */
-void GC_clear_hdr_marks GC_PROTO((hdr * hhdr));
- /* Clear the mark bits in a header */
-void GC_set_hdr_marks GC_PROTO((hdr * hhdr));
- /* Set the mark bits in a header */
-void GC_set_fl_marks GC_PROTO((ptr_t p));
- /* Set all mark bits associated with */
- /* a free list. */
-void GC_add_roots_inner GC_PROTO((char * b, char * e, GC_bool tmp));
-void GC_remove_roots_inner GC_PROTO((char * b, char * e));
-GC_bool GC_is_static_root GC_PROTO((ptr_t p));
- /* Is the address p in one of the registered static */
- /* root sections? */
-# if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
-GC_bool GC_is_tmp_root GC_PROTO((ptr_t p));
- /* Is the address p in one of the temporary static */
- /* root sections? */
-# endif
-void GC_register_dynamic_libraries GC_PROTO((void));
- /* Add dynamic library data sections to the root set. */
-
-GC_bool GC_register_main_static_data GC_PROTO((void));
- /* We need to register the main data segment. Returns */
- /* TRUE unless this is done implicitly as part of */
- /* dynamic library registration. */
-
+ GC_INNER void GC_mark_and_push_stack(ptr_t p);
+#endif
+
+GC_INNER void GC_clear_hdr_marks(hdr * hhdr);
+ /* Clear the mark bits in a header */
+GC_INNER void GC_set_hdr_marks(hdr * hhdr);
+ /* Set the mark bits in a header */
+GC_INNER void GC_set_fl_marks(ptr_t p);
+ /* Set all mark bits associated with */
+ /* a free list. */
+#if defined(GC_ASSERTIONS) && defined(THREADS) && defined(THREAD_LOCAL_ALLOC)
+ void GC_check_fl_marks(void **);
+ /* Check that all mark bits */
+ /* associated with a free list are */
+ /* set. Abort if not. */
+#endif
+void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp);
+GC_INNER void GC_exclude_static_roots_inner(void *start, void *finish);
+#if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
+ || defined(CYGWIN32) || defined(PCR)
+ GC_INNER void GC_register_dynamic_libraries(void);
+ /* Add dynamic library data sections to the root set. */
+#endif
+GC_INNER void GC_cond_register_dynamic_libraries(void);
+ /* Remove and reregister dynamic libraries if we're */
+ /* configured to do that at each GC. */
+
/* Machine dependent startup routines */
-ptr_t GC_get_stack_base GC_PROTO((void)); /* Cold end of stack */
+ptr_t GC_get_main_stack_base(void); /* Cold end of stack. */
#ifdef IA64
- ptr_t GC_get_register_stack_base GC_PROTO((void));
- /* Cold end of register stack. */
+ GC_INNER ptr_t GC_get_register_stack_base(void);
+ /* Cold end of register stack. */
#endif
-void GC_register_data_segments GC_PROTO((void));
-
+void GC_register_data_segments(void);
+
+#ifdef THREADS
+ GC_INNER void GC_thr_init(void);
+ GC_INNER void GC_init_parallel(void);
+#else
+ GC_INNER GC_bool GC_is_static_root(ptr_t p);
+ /* Is the address p in one of the registered static */
+ /* root sections? */
+#endif
+
/* Black listing: */
-void GC_bl_init GC_PROTO((void));
-# ifdef PRINT_BLACK_LIST
- void GC_add_to_black_list_normal GC_PROTO((word p, ptr_t source));
- /* Register bits as a possible future false */
- /* reference from the heap or static data */
-# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
- if (GC_all_interior_pointers) { \
- GC_add_to_black_list_stack(bits, (ptr_t)(source)); \
- } else { \
- GC_add_to_black_list_normal(bits, (ptr_t)(source)); \
- }
-# else
- void GC_add_to_black_list_normal GC_PROTO((word p));
-# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
- if (GC_all_interior_pointers) { \
- GC_add_to_black_list_stack(bits); \
- } else { \
- GC_add_to_black_list_normal(bits); \
- }
-# endif
+#ifdef PRINT_BLACK_LIST
+ GC_INNER void GC_add_to_black_list_normal(word p, ptr_t source);
+ /* Register bits as a possible future false */
+ /* reference from the heap or static data */
+# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
+ if (GC_all_interior_pointers) { \
+ GC_add_to_black_list_stack((word)(bits), (source)); \
+ } else { \
+ GC_add_to_black_list_normal((word)(bits), (source)); \
+ }
+ GC_INNER void GC_add_to_black_list_stack(word p, ptr_t source);
+# define GC_ADD_TO_BLACK_LIST_STACK(bits, source) \
+ GC_add_to_black_list_stack((word)(bits), (source))
+#else
+ GC_INNER void GC_add_to_black_list_normal(word p);
+# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
+ if (GC_all_interior_pointers) { \
+ GC_add_to_black_list_stack((word)(bits)); \
+ } else { \
+ GC_add_to_black_list_normal((word)(bits)); \
+ }
+ GC_INNER void GC_add_to_black_list_stack(word p);
+# define GC_ADD_TO_BLACK_LIST_STACK(bits, source) \
+ GC_add_to_black_list_stack((word)(bits))
+#endif /* PRINT_BLACK_LIST */
+
+struct hblk * GC_is_black_listed(struct hblk * h, word len);
+ /* If there are likely to be false references */
+ /* to a block starting at h of the indicated */
+ /* length, then return the next plausible */
+ /* starting location for h that might avoid */
+ /* these false references. Remains externally */
+ /* visible as used by GNU GCJ currently. */
+
+GC_INNER void GC_promote_black_lists(void);
+ /* Declare an end to a black listing phase. */
+GC_INNER void GC_unpromote_black_lists(void);
+ /* Approximately undo the effect of the above. */
+ /* This actually loses some information, but */
+ /* only in a reasonably safe way. */
+
+GC_INNER ptr_t GC_scratch_alloc(size_t bytes);
+ /* GC internal memory allocation for */
+ /* small objects. Deallocation is not */
+ /* possible. May return NULL. */
+
+/* Heap block layout maps: */
+GC_INNER GC_bool GC_add_map_entry(size_t sz);
+ /* Add a heap block map for objects of */
+ /* size sz to obj_map. */
+ /* Return FALSE on failure. */
+GC_INNER void GC_register_displacement_inner(size_t offset);
+ /* Version of GC_register_displacement */
+ /* that assumes lock is already held. */
+
+/* hblk allocation: */
+GC_INNER void GC_new_hblk(size_t size_in_granules, int kind);
+ /* Allocate a new heap block, and build */
+ /* a free list in it. */
+
+GC_INNER ptr_t GC_build_fl(struct hblk *h, size_t words, GC_bool clear,
+ ptr_t list);
+ /* Build a free list for objects of */
+ /* size sz in block h. Append list to */
+ /* end of the free lists. Possibly */
+ /* clear objects on the list. Normally */
+ /* called by GC_new_hblk, but also */
+ /* called explicitly without GC lock. */
+
+GC_INNER struct hblk * GC_allochblk(size_t size_in_bytes, int kind,
+ unsigned flags);
+ /* Allocate a heap block, inform */
+ /* the marker that block is valid */
+ /* for objects of indicated size. */
+
+GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags);
+ /* Allocate a large block of size lb bytes. */
+ /* The block is not cleared. */
+ /* Flags is 0 or IGNORE_OFF_PAGE. */
+ /* Calls GC_allchblk to do the actual */
+ /* allocation, but also triggers GC and/or */
+ /* heap expansion as appropriate. */
+ /* Does not update GC_bytes_allocd, but does */
+ /* other accounting. */
+
+GC_INNER void GC_freehblk(struct hblk * p);
+ /* Deallocate a heap block and mark it */
+ /* as invalid. */
-# ifdef PRINT_BLACK_LIST
- void GC_add_to_black_list_stack GC_PROTO((word p, ptr_t source));
-# else
- void GC_add_to_black_list_stack GC_PROTO((word p));
-# endif
-struct hblk * GC_is_black_listed GC_PROTO((struct hblk * h, word len));
- /* If there are likely to be false references */
- /* to a block starting at h of the indicated */
- /* length, then return the next plausible */
- /* starting location for h that might avoid */
- /* these false references. */
-void GC_promote_black_lists GC_PROTO((void));
- /* Declare an end to a black listing phase. */
-void GC_unpromote_black_lists GC_PROTO((void));
- /* Approximately undo the effect of the above. */
- /* This actually loses some information, but */
- /* only in a reasonably safe way. */
-word GC_number_stack_black_listed GC_PROTO(( \
- struct hblk *start, struct hblk *endp1));
- /* Return the number of (stack) blacklisted */
- /* blocks in the range for statistical */
- /* purposes. */
-
-ptr_t GC_scratch_alloc GC_PROTO((word bytes));
- /* GC internal memory allocation for */
- /* small objects. Deallocation is not */
- /* possible. */
-
-/* Heap block layout maps: */
-void GC_invalidate_map GC_PROTO((hdr * hhdr));
- /* Remove the object map associated */
- /* with the block. This identifies */
- /* the block as invalid to the mark */
- /* routines. */
-GC_bool GC_add_map_entry GC_PROTO((word sz));
- /* Add a heap block map for objects of */
- /* size sz to obj_map. */
- /* Return FALSE on failure. */
-void GC_register_displacement_inner GC_PROTO((word offset));
- /* Version of GC_register_displacement */
- /* that assumes lock is already held */
- /* and signals are already disabled. */
-
-/* hblk allocation: */
-void GC_new_hblk GC_PROTO((word size_in_words, int kind));
- /* Allocate a new heap block, and build */
- /* a free list in it. */
-
-ptr_t GC_build_fl GC_PROTO((struct hblk *h, word sz,
- GC_bool clear, ptr_t list));
- /* Build a free list for objects of */
- /* size sz in block h. Append list to */
- /* end of the free lists. Possibly */
- /* clear objects on the list. Normally */
- /* called by GC_new_hblk, but also */
- /* called explicitly without GC lock. */
-
-struct hblk * GC_allochblk GC_PROTO(( \
- word size_in_words, int kind, unsigned flags));
- /* Allocate a heap block, inform */
- /* the marker that block is valid */
- /* for objects of indicated size. */
-
-ptr_t GC_alloc_large GC_PROTO((word lw, int k, unsigned flags));
- /* Allocate a large block of size lw words. */
- /* The block is not cleared. */
- /* Flags is 0 or IGNORE_OFF_PAGE. */
- /* Calls GC_allchblk to do the actual */
- /* allocation, but also triggers GC and/or */
- /* heap expansion as appropriate. */
- /* Does not update GC_words_allocd, but does */
- /* other accounting. */
-
-ptr_t GC_alloc_large_and_clear GC_PROTO((word lw, int k, unsigned flags));
- /* As above, but clear block if appropriate */
- /* for kind k. */
-
-void GC_freehblk GC_PROTO((struct hblk * p));
- /* Deallocate a heap block and mark it */
- /* as invalid. */
-
/* Misc GC: */
-void GC_init_inner GC_PROTO((void));
-GC_bool GC_expand_hp_inner GC_PROTO((word n));
-void GC_start_reclaim GC_PROTO((int abort_if_found));
- /* Restore unmarked objects to free */
- /* lists, or (if abort_if_found is */
- /* TRUE) report them. */
- /* Sweeping of small object pages is */
- /* largely deferred. */
-void GC_continue_reclaim GC_PROTO((word sz, int kind));
- /* Sweep pages of the given size and */
- /* kind, as long as possible, and */
- /* as long as the corr. free list is */
- /* empty. */
-void GC_reclaim_or_delete_all GC_PROTO((void));
- /* Arrange for all reclaim lists to be */
- /* empty. Judiciously choose between */
- /* sweeping and discarding each page. */
-GC_bool GC_reclaim_all GC_PROTO((GC_stop_func stop_func, GC_bool ignore_old));
- /* Reclaim all blocks. Abort (in a */
- /* consistent state) if f returns TRUE. */
-GC_bool GC_block_empty GC_PROTO((hdr * hhdr));
- /* Block completely unmarked? */
-GC_bool GC_never_stop_func GC_PROTO((void));
- /* Returns FALSE. */
-GC_bool GC_try_to_collect_inner GC_PROTO((GC_stop_func f));
-
- /* Collect; caller must have acquired */
- /* lock and disabled signals. */
- /* Collection is aborted if f returns */
- /* TRUE. Returns TRUE if it completes */
- /* successfully. */
-# define GC_gcollect_inner() \
- (void) GC_try_to_collect_inner(GC_never_stop_func)
-void GC_finish_collection GC_PROTO((void));
- /* Finish collection. Mark bits are */
- /* consistent and lock is still held. */
-GC_bool GC_collect_or_expand GC_PROTO(( \
- word needed_blocks, GC_bool ignore_off_page));
- /* Collect or expand heap in an attempt */
- /* make the indicated number of free */
- /* blocks available. Should be called */
- /* until the blocks are available or */
- /* until it fails by returning FALSE. */
-
-extern GC_bool GC_is_initialized; /* GC_init() has been run. */
+GC_INNER GC_bool GC_expand_hp_inner(word n);
+GC_INNER void GC_start_reclaim(GC_bool abort_if_found);
+ /* Restore unmarked objects to free */
+ /* lists, or (if abort_if_found is */
+ /* TRUE) report them. */
+ /* Sweeping of small object pages is */
+ /* largely deferred. */
+GC_INNER void GC_continue_reclaim(size_t sz, int kind);
+ /* Sweep pages of the given size and */
+ /* kind, as long as possible, and */
+ /* as long as the corr. free list is */
+ /* empty. Sz is in granules. */
+
+GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old);
+ /* Reclaim all blocks. Abort (in a */
+ /* consistent state) if f returns TRUE. */
+GC_INNER ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
+ GC_bool init, ptr_t list,
+ signed_word *count);
+ /* Rebuild free list in hbp with */
+ /* header hhdr, with objects of size sz */
+ /* bytes. Add list to the end of the */
+ /* free list. Add the number of */
+ /* reclaimed bytes to *count. */
+GC_INNER GC_bool GC_block_empty(hdr * hhdr);
+ /* Block completely unmarked? */
+GC_INNER int GC_CALLBACK GC_never_stop_func(void);
+ /* Always returns 0 (FALSE). */
+GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func f);
+
+ /* Collect; caller must have acquired */
+ /* lock. Collection is aborted if f */
+ /* returns TRUE. Returns TRUE if it */
+ /* completes successfully. */
+#define GC_gcollect_inner() \
+ (void)GC_try_to_collect_inner(GC_never_stop_func)
+
+GC_EXTERN GC_bool GC_is_initialized; /* GC_init() has been run. */
#if defined(MSWIN32) || defined(MSWINCE)
- void GC_deinit GC_PROTO((void));
+ void GC_deinit(void);
/* Free any resources allocated by */
/* GC_init */
#endif
-void GC_collect_a_little_inner GC_PROTO((int n));
- /* Do n units worth of garbage */
- /* collection work, if appropriate. */
- /* A unit is an amount appropriate for */
- /* HBLKSIZE bytes of allocation. */
-/* ptr_t GC_generic_malloc GC_PROTO((word lb, int k)); */
- /* Allocate an object of the given */
- /* kind. By default, there are only */
- /* a few kinds: composite(pointerfree), */
- /* atomic, uncollectable, etc. */
- /* We claim it's possible for clever */
- /* client code that understands GC */
- /* internals to add more, e.g. to */
- /* communicate object layout info */
- /* to the collector. */
- /* The actual decl is in gc_mark.h. */
-ptr_t GC_generic_malloc_ignore_off_page GC_PROTO((size_t b, int k));
- /* As above, but pointers past the */
- /* first page of the resulting object */
- /* are ignored. */
-ptr_t GC_generic_malloc_inner GC_PROTO((word lb, int k));
- /* Ditto, but I already hold lock, etc. */
-ptr_t GC_generic_malloc_words_small GC_PROTO((size_t lw, int k));
- /* As above, but size in units of words */
- /* Bypasses MERGE_SIZES. Assumes */
- /* words <= MAXOBJSZ. */
-ptr_t GC_generic_malloc_inner_ignore_off_page GC_PROTO((size_t lb, int k));
- /* Allocate an object, where */
- /* the client guarantees that there */
- /* will always be a pointer to the */
- /* beginning of the object while the */
- /* object is live. */
-ptr_t GC_allocobj GC_PROTO((word sz, int kind));
- /* Make the indicated */
- /* free list nonempty, and return its */
- /* head. */
-
-void GC_free_inner(GC_PTR p);
-
-void GC_init_headers GC_PROTO((void));
-struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h));
- /* Install a header for block h. */
- /* Return 0 on failure, or the header */
- /* otherwise. */
-GC_bool GC_install_counts GC_PROTO((struct hblk * h, word sz));
- /* Set up forwarding counts for block */
- /* h of size sz. */
- /* Return FALSE on failure. */
-void GC_remove_header GC_PROTO((struct hblk * h));
- /* Remove the header for block h. */
-void GC_remove_counts GC_PROTO((struct hblk * h, word sz));
- /* Remove forwarding counts for h. */
-hdr * GC_find_header GC_PROTO((ptr_t h)); /* Debugging only. */
-
-void GC_finalize GC_PROTO((void));
- /* Perform all indicated finalization actions */
- /* on unmarked objects. */
- /* Unreachable finalizable objects are enqueued */
- /* for processing by GC_invoke_finalizers. */
- /* Invoked with lock. */
-
-void GC_notify_or_invoke_finalizers GC_PROTO((void));
- /* If GC_finalize_on_demand is not set, invoke */
- /* eligible finalizers. Otherwise: */
- /* Call *GC_finalizer_notifier if there are */
- /* finalizers to be run, and we haven't called */
- /* this procedure yet this GC cycle. */
-
-GC_API GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
-GC_API void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
- /* Auxiliary fns to make finalization work */
- /* correctly with displaced pointers introduced */
- /* by the debugging allocators. */
-
-void GC_add_to_heap GC_PROTO((struct hblk *p, word bytes));
- /* Add a HBLKSIZE aligned chunk to the heap. */
-
-void GC_print_obj GC_PROTO((ptr_t p));
- /* P points to somewhere inside an object with */
- /* debugging info. Print a human readable */
- /* description of the object to stderr. */
-extern void (*GC_check_heap) GC_PROTO((void));
- /* Check that all objects in the heap with */
- /* debugging info are intact. */
- /* Add any that are not to GC_smashed list. */
-extern void (*GC_print_all_smashed) GC_PROTO((void));
- /* Print GC_smashed if it's not empty. */
- /* Clear GC_smashed list. */
-extern void GC_print_all_errors GC_PROTO((void));
- /* Print smashed and leaked objects, if any. */
- /* Clear the lists of such objects. */
-extern void (*GC_print_heap_obj) GC_PROTO((ptr_t p));
- /* If possible print s followed by a more */
- /* detailed description of the object */
- /* referred to by p. */
+GC_INNER void GC_collect_a_little_inner(int n);
+ /* Do n units worth of garbage */
+ /* collection work, if appropriate. */
+ /* A unit is an amount appropriate for */
+ /* HBLKSIZE bytes of allocation. */
+/* void * GC_generic_malloc(size_t lb, int k); */
+ /* Allocate an object of the given */
+ /* kind. By default, there are only */
+ /* a few kinds: composite(pointerfree), */
+ /* atomic, uncollectable, etc. */
+ /* We claim it's possible for clever */
+ /* client code that understands GC */
+ /* internals to add more, e.g. to */
+ /* communicate object layout info */
+ /* to the collector. */
+ /* The actual decl is in gc_mark.h. */
+GC_INNER void * GC_generic_malloc_ignore_off_page(size_t b, int k);
+ /* As above, but pointers past the */
+ /* first page of the resulting object */
+ /* are ignored. */
+GC_INNER void * GC_generic_malloc_inner(size_t lb, int k);
+ /* Ditto, but I already hold lock, etc. */
+GC_INNER void * GC_generic_malloc_inner_ignore_off_page(size_t lb, int k);
+ /* Allocate an object, where */
+ /* the client guarantees that there */
+ /* will always be a pointer to the */
+ /* beginning of the object while the */
+ /* object is live. */
+
+GC_INNER ptr_t GC_allocobj(size_t sz, int kind);
+ /* Make the indicated */
+ /* free list nonempty, and return its */
+ /* head. Sz is in granules. */
+
+#ifdef GC_ADD_CALLER
+# define GC_DBG_RA GC_RETURN_ADDR,
+#else
+# define GC_DBG_RA /* empty */
+#endif
+
+/* We make the GC_clear_stack() call a tail one, hoping to get more of */
+/* the stack. */
+#define GENERAL_MALLOC(lb,k) \
+ GC_clear_stack(GC_generic_malloc(lb, k))
+#define GENERAL_MALLOC_IOP(lb,k) \
+ GC_clear_stack(GC_generic_malloc_ignore_off_page(lb, k))
+
+#ifdef GC_COLLECT_AT_MALLOC
+ extern size_t GC_dbg_collect_at_malloc_min_lb;
+ /* variable visible outside for debugging */
+# define GC_DBG_COLLECT_AT_MALLOC(lb) \
+ (void)((lb) >= GC_dbg_collect_at_malloc_min_lb ? \
+ (GC_gcollect(), 0) : 0)
+#else
+# define GC_DBG_COLLECT_AT_MALLOC(lb) (void)0
+#endif /* !GC_COLLECT_AT_MALLOC */
+
+/* Allocation routines that bypass the thread local cache. */
+#ifdef THREAD_LOCAL_ALLOC
+ GC_INNER void * GC_core_malloc(size_t);
+ GC_INNER void * GC_core_malloc_atomic(size_t);
+# ifdef GC_GCJ_SUPPORT
+ GC_INNER void * GC_core_gcj_malloc(size_t, void *);
+# endif
+#endif /* THREAD_LOCAL_ALLOC */
+
+GC_INNER void GC_init_headers(void);
+GC_INNER struct hblkhdr * GC_install_header(struct hblk *h);
+ /* Install a header for block h. */
+ /* Return 0 on failure, or the header */
+ /* otherwise. */
+GC_INNER GC_bool GC_install_counts(struct hblk * h, size_t sz);
+ /* Set up forwarding counts for block */
+ /* h of size sz. */
+ /* Return FALSE on failure. */
+GC_INNER void GC_remove_header(struct hblk * h);
+ /* Remove the header for block h. */
+GC_INNER void GC_remove_counts(struct hblk * h, size_t sz);
+ /* Remove forwarding counts for h. */
+GC_INNER hdr * GC_find_header(ptr_t h);
+
+GC_INNER void GC_add_to_heap(struct hblk *p, size_t bytes);
+ /* Add a HBLKSIZE aligned chunk to the heap. */
+
+#ifdef USE_PROC_FOR_LIBRARIES
+ GC_INNER 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
+
+GC_INNER void GC_print_all_errors(void);
+ /* Print smashed and leaked objects, if any. */
+ /* Clear the lists of such objects. */
+
+GC_EXTERN void (*GC_check_heap)(void);
+ /* Check that all objects in the heap with */
+ /* debugging info are intact. */
+ /* Add any that are not to GC_smashed list. */
+GC_EXTERN void (*GC_print_all_smashed)(void);
+ /* Print GC_smashed if it's not empty. */
+ /* Clear GC_smashed list. */
+GC_EXTERN void (*GC_print_heap_obj)(ptr_t p);
+ /* If possible print (using GC_err_printf) */
+ /* a more detailed description (terminated with */
+ /* "\n") of the object referred to by p. */
+
#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
- void GC_print_address_map GC_PROTO((void));
- /* Print an address map of the process. */
+ void GC_print_address_map(void);
+ /* Print an address map of the process. */
#endif
-extern GC_bool GC_have_errors; /* We saw a smashed or leaked object. */
- /* Call error printing routine */
- /* occasionally. */
-extern GC_bool GC_print_stats; /* Produce at least some logging output */
- /* Set from environment variable. */
+#ifndef SHORT_DBG_HDRS
+ GC_EXTERN GC_bool GC_findleak_delay_free;
+ /* Do not immediately deallocate object on */
+ /* free() in the leak-finding mode, just mark */
+ /* it as freed (and deallocate it after GC). */
+ GC_INNER GC_bool GC_check_leaked(ptr_t base); /* from dbg_mlc.c */
+#endif
-#ifndef NO_DEBUGGING
- extern GC_bool GC_dump_regularly; /* Generate regular debugging dumps. */
-# define COND_DUMP if (GC_dump_regularly) GC_dump();
-#else
-# define COND_DUMP
+GC_EXTERN GC_bool GC_have_errors; /* We saw a smashed or leaked object. */
+ /* Call error printing routine */
+ /* occasionally. It is ok to read it */
+ /* without acquiring the lock. */
+
+#define VERBOSE 2
+#ifndef SMALL_CONFIG
+ /* GC_print_stats should be visible to extra/MacOS.c. */
+# ifndef GC_ANDROID_LOG
+ extern int GC_print_stats; /* Nonzero generates basic GC log. */
+ /* VERBOSE generates add'l messages. */
+# define GC_real_print_stats GC_print_stats
+# else
+# ifndef GC_print_stats
+# define GC_print_stats VERBOSE
+# endif
+ extern int GC_real_print_stats;
+ /* Influences logging only if redirected to a file. */
+# endif
+#else /* SMALL_CONFIG */
+# define GC_print_stats 0
+ /* Will this remove the message character strings from the executable? */
+ /* With a particular level of optimizations, it should... */
#endif
#ifdef KEEP_BACK_PTRS
- extern long GC_backtraces;
+ GC_EXTERN long GC_backtraces;
+ GC_INNER void GC_generate_random_backtrace_no_gc(void);
#endif
-/* Macros used for collector internal allocation. */
-/* These assume the collector lock is held. */
+GC_EXTERN GC_bool GC_print_back_height;
+
+#ifdef MAKE_BACK_GRAPH
+ void GC_print_back_graph_stats(void);
+#endif
+
+#ifdef THREADS
+ GC_INNER void GC_free_inner(void * p);
+#endif
+
+/* Macros used for collector internal allocation. */
+/* These assume the collector lock is held. */
#ifdef DBG_HDRS_ALL
- extern GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k);
- extern GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
- int k);
-# define GC_INTERNAL_MALLOC GC_debug_generic_malloc_inner
-# define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \
- GC_debug_generic_malloc_inner_ignore_off_page
-# ifdef THREADS
-# define GC_INTERNAL_FREE GC_debug_free_inner
-# else
-# define GC_INTERNAL_FREE GC_debug_free
-# endif
+ GC_INNER void * GC_debug_generic_malloc_inner(size_t lb, int k);
+ GC_INNER void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
+ int k);
+# define GC_INTERNAL_MALLOC GC_debug_generic_malloc_inner
+# define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \
+ GC_debug_generic_malloc_inner_ignore_off_page
+# ifdef THREADS
+ GC_INNER void GC_debug_free_inner(void * p);
+# define GC_INTERNAL_FREE GC_debug_free_inner
+# else
+# define GC_INTERNAL_FREE GC_debug_free
+# endif
#else
-# define GC_INTERNAL_MALLOC GC_generic_malloc_inner
-# define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \
- GC_generic_malloc_inner_ignore_off_page
-# ifdef THREADS
-# define GC_INTERNAL_FREE GC_free_inner
-# else
-# define GC_INTERNAL_FREE GC_free
-# endif
-#endif
+# define GC_INTERNAL_MALLOC GC_generic_malloc_inner
+# define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \
+ GC_generic_malloc_inner_ignore_off_page
+# ifdef THREADS
+# define GC_INTERNAL_FREE GC_free_inner
+# else
+# define GC_INTERNAL_FREE GC_free
+# endif
+#endif /* !DBG_HDRS_ALL */
-/* Memory unmapping: */
#ifdef USE_MUNMAP
- void GC_unmap_old(void);
- void GC_merge_unmapped(void);
- void GC_unmap(ptr_t start, word bytes);
- void GC_remap(ptr_t start, word bytes);
- void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2);
-#endif
-
-/* Virtual dirty bit implementation: */
-/* Each implementation exports the following: */
-void GC_read_dirty GC_PROTO((void));
- /* Retrieve dirty bits. */
-GC_bool GC_page_was_dirty GC_PROTO((struct hblk *h));
- /* Read retrieved dirty bits. */
-GC_bool GC_page_was_ever_dirty GC_PROTO((struct hblk *h));
- /* Could the page contain valid heap pointers? */
-void GC_is_fresh GC_PROTO((struct hblk *h, word n));
- /* Assert the region currently contains no */
- /* valid pointers. */
-void GC_remove_protection GC_PROTO((struct hblk *h, word nblocks,
- GC_bool pointerfree));
- /* h is about to be writteni or allocated. Ensure */
- /* that it's not write protected by the virtual */
- /* dirty bit implementation. */
-
-void GC_dirty_init GC_PROTO((void));
-
-/* Slow/general mark bit manipulation: */
-GC_API GC_bool GC_is_marked GC_PROTO((ptr_t p));
-void GC_clear_mark_bit GC_PROTO((ptr_t p));
-void GC_set_mark_bit GC_PROTO((ptr_t p));
-
+ /* Memory unmapping: */
+ GC_INNER void GC_unmap_old(void);
+ GC_INNER void GC_merge_unmapped(void);
+ GC_INNER void GC_unmap(ptr_t start, size_t bytes);
+ GC_INNER void GC_remap(ptr_t start, size_t bytes);
+ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
+ size_t bytes2);
+#endif
+
+#ifdef CAN_HANDLE_FORK
+ GC_EXTERN int GC_handle_fork;
+ /* Fork-handling mode: */
+ /* 0 means no fork handling requested (but client could */
+ /* anyway call fork() provided it is surrounded with */
+ /* GC_atfork_prepare/parent/child calls); */
+ /* -1 means GC tries to use pthread_at_fork if it is */
+ /* available (if it succeeds then GC_handle_fork value */
+ /* is changed to 1), client should nonetheless surround */
+ /* fork() with GC_atfork_prepare/parent/child (for the */
+ /* case of pthread_at_fork failure or absence); */
+ /* 1 (or other values) means client fully relies on */
+ /* pthread_at_fork (so if it is missing or failed then */
+ /* abort occurs in GC_init), GC_atfork_prepare and the */
+ /* accompanying routines are no-op in such a case. */
+#endif
+
+#ifndef GC_DISABLE_INCREMENTAL
+ GC_EXTERN GC_bool GC_dirty_maintained;
+ /* Dirty bits are being maintained, */
+ /* either for incremental collection, */
+ /* or to limit the root set. */
+
+ /* Virtual dirty bit implementation: */
+ /* Each implementation exports the following: */
+ GC_INNER void GC_read_dirty(void);
+ /* Retrieve dirty bits. */
+ GC_INNER GC_bool GC_page_was_dirty(struct hblk *h);
+ /* Read retrieved dirty bits. */
+ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
+ GC_bool pointerfree);
+ /* h is about to be written or allocated. Ensure */
+ /* that it's not write protected by the virtual */
+ /* dirty bit implementation. */
+
+ GC_INNER void GC_dirty_init(void);
+#endif /* !GC_DISABLE_INCREMENTAL */
+
+/* Same as GC_base but excepts and returns a pointer to const object. */
+#define GC_base_C(p) ((const void *)GC_base((/* no const */ void *)(p)))
+
/* Stubborn objects: */
-void GC_read_changed GC_PROTO((void)); /* Analogous to GC_read_dirty */
-GC_bool GC_page_was_changed GC_PROTO((struct hblk * h));
- /* Analogous to GC_page_was_dirty */
-void GC_clean_changing_list GC_PROTO((void));
- /* Collect obsolete changing list entries */
-void GC_stubborn_init GC_PROTO((void));
-
+void GC_read_changed(void); /* Analogous to GC_read_dirty */
+GC_bool GC_page_was_changed(struct hblk * h);
+ /* Analogous to GC_page_was_dirty */
+void GC_clean_changing_list(void);
+ /* Collect obsolete changing list entries */
+void GC_stubborn_init(void);
+
/* Debugging print routines: */
-void GC_print_block_list GC_PROTO((void));
-void GC_print_hblkfreelist GC_PROTO((void));
-void GC_print_heap_sects GC_PROTO((void));
-void GC_print_static_roots GC_PROTO((void));
-void GC_print_finalization_stats GC_PROTO((void));
-void GC_dump GC_PROTO((void));
+void GC_print_block_list(void);
+void GC_print_hblkfreelist(void);
+void GC_print_heap_sects(void);
+void GC_print_static_roots(void);
+/* void GC_dump(void); - declared in gc.h */
+
+extern word GC_fo_entries; /* should be visible in extra/MacOS.c */
#ifdef KEEP_BACK_PTRS
- void GC_store_back_pointer(ptr_t source, ptr_t dest);
- void GC_marked_for_finalization(ptr_t dest);
+ GC_INNER void GC_store_back_pointer(ptr_t source, ptr_t dest);
+ GC_INNER void GC_marked_for_finalization(ptr_t dest);
# define GC_STORE_BACK_PTR(source, dest) GC_store_back_pointer(source, dest)
# define GC_MARKED_FOR_FINALIZATION(dest) GC_marked_for_finalization(dest)
#else
-# define GC_STORE_BACK_PTR(source, dest)
+# define GC_STORE_BACK_PTR(source, dest)
# define GC_MARKED_FOR_FINALIZATION(dest)
#endif
/* Make arguments appear live to compiler */
-# ifdef __WATCOMC__
- void GC_noop(void*, ...);
+void GC_noop6(word, word, word, word, word, word);
+
+GC_API void GC_CALL GC_noop1(word);
+
+#ifndef GC_ATTR_FORMAT_PRINTF
+# if defined(__GNUC__) && __GNUC__ >= 3
+# define GC_ATTR_FORMAT_PRINTF(spec_argnum, first_checked) \
+ __attribute__((__format__(__printf__, spec_argnum, first_checked)))
# else
-# ifdef __DMC__
- GC_API void GC_noop(...);
-# else
- GC_API void GC_noop();
-# endif
+# define GC_ATTR_FORMAT_PRINTF(spec_argnum, first_checked)
# endif
+#endif
+
+/* Logging and diagnostic output: */
+/* GC_printf is used typically on client explicit print requests. */
+/* For all GC_X_printf routines, it is recommended to put "\n" at */
+/* 'format' string end (for output atomicity). */
+GC_API_PRIV void GC_printf(const char * format, ...)
+ GC_ATTR_FORMAT_PRINTF(1, 2);
+ /* A version of printf that doesn't allocate, */
+ /* 1K total output length. */
+ /* (We use sprintf. Hopefully that doesn't */
+ /* allocate for long arguments.) */
+GC_API_PRIV void GC_err_printf(const char * format, ...)
+ GC_ATTR_FORMAT_PRINTF(1, 2);
+
+/* Basic logging routine. Typically, GC_log_printf is called directly */
+/* only inside various DEBUG_x blocks. */
+#if defined(__cplusplus) && defined(SYMBIAN)
+ extern "C" {
+#endif
+GC_API_PRIV void GC_log_printf(const char * format, ...)
+ GC_ATTR_FORMAT_PRINTF(1, 2);
+#if defined(__cplusplus) && defined(SYMBIAN)
+ }
+#endif
+
+#ifndef GC_ANDROID_LOG
+ /* GC_stats_log_printf should be called only if GC_print_stats. */
+# define GC_stats_log_printf GC_log_printf
+ /* GC_verbose_log_printf is called only if GC_print_stats is VERBOSE. */
+# define GC_verbose_log_printf GC_log_printf
+#else
+ GC_INNER void GC_stats_log_printf(const char *format, ...)
+ GC_ATTR_FORMAT_PRINTF(1, 2);
+ GC_INNER void GC_verbose_log_printf(const char *format, ...)
+ GC_ATTR_FORMAT_PRINTF(1, 2);
+#endif /* GC_ANDROID_LOG */
+
+/* Convenient macros for GC_stats/verbose_log_printf invocation. */
+#define GC_COND_LOG_PRINTF if (!GC_print_stats) {} else GC_stats_log_printf
+#define GC_VERBOSE_LOG_PRINTF \
+ if (GC_print_stats != VERBOSE) {} else GC_verbose_log_printf
+
+void GC_err_puts(const char *s);
+ /* Write s to stderr, don't buffer, don't add */
+ /* newlines, don't ... */
+
+GC_EXTERN unsigned GC_fail_count;
+ /* How many consecutive GC/expansion failures? */
+ /* Reset by GC_allochblk(); defined in alloc.c. */
+
+GC_EXTERN long GC_large_alloc_warn_interval; /* defined in misc.c */
+
+GC_EXTERN signed_word GC_bytes_found;
+ /* Number of reclaimed bytes after garbage collection; */
+ /* protected by GC lock; defined in reclaim.c. */
+
+#ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
+ GC_EXTERN word GC_reclaimed_bytes_before_gc;
+ /* Number of bytes reclaimed before this */
+ /* collection cycle; used for statistics only. */
+#endif
+
+#ifdef USE_MUNMAP
+ GC_EXTERN int GC_unmap_threshold; /* defined in allchblk.c */
+ GC_EXTERN GC_bool GC_force_unmap_on_gcollect; /* defined in misc.c */
+#endif
-void GC_noop1 GC_PROTO((word));
-
-/* Logging and diagnostic output: */
-GC_API void GC_printf GC_PROTO((GC_CONST char * format, long, long, long, long, long, long));
- /* A version of printf that doesn't allocate, */
- /* is restricted to long arguments, and */
- /* (unfortunately) doesn't use varargs for */
- /* portability. Restricted to 6 args and */
- /* 1K total output length. */
- /* (We use sprintf. Hopefully that doesn't */
- /* allocate for long arguments.) */
-# define GC_printf0(f) GC_printf(f, 0l, 0l, 0l, 0l, 0l, 0l)
-# define GC_printf1(f,a) GC_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l)
-# define GC_printf2(f,a,b) GC_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l)
-# define GC_printf3(f,a,b,c) GC_printf(f, (long)a, (long)b, (long)c, 0l, 0l, 0l)
-# define GC_printf4(f,a,b,c,d) GC_printf(f, (long)a, (long)b, (long)c, \
- (long)d, 0l, 0l)
-# define GC_printf5(f,a,b,c,d,e) GC_printf(f, (long)a, (long)b, (long)c, \
- (long)d, (long)e, 0l)
-# define GC_printf6(f,a,b,c,d,e,g) GC_printf(f, (long)a, (long)b, (long)c, \
- (long)d, (long)e, (long)g)
-
-GC_API void GC_err_printf GC_PROTO((GC_CONST char * format, long, long, long, long, long, long));
-# define GC_err_printf0(f) GC_err_puts(f)
-# define GC_err_printf1(f,a) GC_err_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l)
-# define GC_err_printf2(f,a,b) GC_err_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l)
-# define GC_err_printf3(f,a,b,c) GC_err_printf(f, (long)a, (long)b, (long)c, \
- 0l, 0l, 0l)
-# define GC_err_printf4(f,a,b,c,d) GC_err_printf(f, (long)a, (long)b, \
- (long)c, (long)d, 0l, 0l)
-# define GC_err_printf5(f,a,b,c,d,e) GC_err_printf(f, (long)a, (long)b, \
- (long)c, (long)d, \
- (long)e, 0l)
-# define GC_err_printf6(f,a,b,c,d,e,g) GC_err_printf(f, (long)a, (long)b, \
- (long)c, (long)d, \
- (long)e, (long)g)
- /* Ditto, writes to stderr. */
-
-void GC_err_puts GC_PROTO((GC_CONST char *s));
- /* Write s to stderr, don't buffer, don't add */
- /* newlines, don't ... */
-
-#if defined(LINUX) && !defined(SMALL_CONFIG)
- void GC_err_write GC_PROTO((GC_CONST char *buf, size_t len));
- /* Write buf to stderr, don't buffer, don't add */
- /* newlines, don't ... */
+#ifdef MSWIN32
+ GC_EXTERN GC_bool GC_no_win32_dlls; /* defined in os_dep.c */
+ GC_EXTERN GC_bool GC_wnt; /* Is Windows NT derivative; */
+ /* defined and set in os_dep.c. */
#endif
+#ifdef THREADS
+# if defined(MSWIN32) || defined(MSWINCE)
+ GC_EXTERN CRITICAL_SECTION GC_write_cs; /* defined in misc.c */
+# ifdef GC_ASSERTIONS
+ GC_EXTERN GC_bool GC_write_disabled;
+ /* defined in win32_threads.c; */
+ /* protected by GC_write_cs. */
+
+# endif
+# endif
+# ifdef MPROTECT_VDB
+ GC_EXTERN volatile AO_TS_t GC_fault_handler_lock;
+ /* defined in os_dep.c */
+# endif
+# ifdef MSWINCE
+ GC_EXTERN GC_bool GC_dont_query_stack_min;
+ /* Defined and set in os_dep.c. */
+# endif
+#elif defined(IA64)
+ GC_EXTERN ptr_t GC_save_regs_ret_val; /* defined in mach_dep.c. */
+ /* Previously set to backing store pointer. */
+#endif /* !THREADS */
+
+#ifdef THREAD_LOCAL_ALLOC
+ GC_EXTERN GC_bool GC_world_stopped; /* defined in alloc.c */
+ GC_INNER void GC_mark_thread_local_free_lists(void);
+#endif
+#ifdef GC_GCJ_SUPPORT
# ifdef GC_ASSERTIONS
-# define GC_ASSERT(expr) if(!(expr)) {\
- GC_err_printf2("Assertion failure: %s:%ld\n", \
- __FILE__, (unsigned long)__LINE__); \
- ABORT("assertion failure"); }
-# else
-# define GC_ASSERT(expr)
+ GC_EXTERN GC_bool GC_gcj_malloc_initialized; /* defined in gcj_mlc.c */
+# endif
+ GC_EXTERN ptr_t * GC_gcjobjfreelist;
+#endif
+
+#if defined(GWW_VDB) && defined(MPROTECT_VDB)
+ GC_INNER GC_bool GC_gww_dirty_init(void);
+ /* Defined in os_dep.c. Returns TRUE if GetWriteWatch is available. */
+ /* May be called repeatedly. */
+#endif
+
+#if defined(CHECKSUMS) || defined(PROC_VDB)
+ GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h);
+ /* Could the page contain valid heap pointers? */
+#endif
+
+GC_INNER void GC_default_print_heap_obj_proc(ptr_t p);
+
+GC_INNER void GC_extend_size_map(size_t); /* in misc.c */
+
+GC_INNER void GC_setpagesize(void);
+
+GC_INNER void GC_initialize_offsets(void); /* defined in obj_map.c */
+
+GC_INNER void GC_bl_init(void);
+GC_INNER void GC_bl_init_no_interiors(void); /* defined in blacklst.c */
+
+GC_INNER void GC_start_debugging(void); /* defined in dbg_mlc.c */
+
+/* Store debugging info into p. Return displaced pointer. */
+/* Assumes we don't hold allocation lock. */
+GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
+ int linenum);
+
+#ifdef REDIRECT_MALLOC
+# ifdef GC_LINUX_THREADS
+ GC_INNER GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp);
+ /* from os_dep.c */
+# endif
+#elif defined(USE_WINALLOC)
+ GC_INNER void GC_add_current_malloc_heap(void);
+#endif /* !REDIRECT_MALLOC */
+
+#ifdef MAKE_BACK_GRAPH
+ GC_INNER void GC_build_back_graph(void);
+ GC_INNER void GC_traverse_back_graph(void);
+#endif
+
+#ifdef MSWIN32
+ GC_INNER void GC_init_win32(void);
+#endif
+
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ GC_INNER void * GC_roots_present(ptr_t);
+ /* The type is a lie, since the real type doesn't make sense here, */
+ /* and we only test for NULL. */
+#endif
+
+#ifdef GC_WIN32_THREADS
+ GC_INNER void GC_get_next_stack(char *start, char * limit, char **lo,
+ char **hi);
+# ifdef MPROTECT_VDB
+ GC_INNER void GC_set_write_fault_handler(void);
+# endif
+#endif /* GC_WIN32_THREADS */
+
+#ifdef THREADS
+ GC_INNER void GC_reset_finalizer_nested(void);
+ GC_INNER unsigned char *GC_check_finalizer_nested(void);
+ GC_INNER void GC_do_blocking_inner(ptr_t data, void * context);
+ GC_INNER void GC_push_all_stacks(void);
+# ifdef USE_PROC_FOR_LIBRARIES
+ GC_INNER GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi);
+# endif
+# ifdef IA64
+ GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound);
+# endif
+#endif /* THREADS */
+
+#ifdef DYNAMIC_LOADING
+ GC_INNER GC_bool GC_register_main_static_data(void);
+# ifdef DARWIN
+ GC_INNER void GC_init_dyld(void);
# endif
+#endif /* DYNAMIC_LOADING */
-/* Check a compile time assertion at compile time. The error */
-/* message for failure is a bit baroque, but ... */
+#ifdef SEARCH_FOR_DATA_START
+ GC_INNER void GC_init_linux_data_start(void);
+#endif
+
+#if defined(NETBSD) && defined(__ELF__)
+ GC_INNER void GC_init_netbsd_elf(void);
+#endif
+
+#ifdef UNIX_LIKE
+ GC_INNER void GC_set_and_save_fault_handler(void (*handler)(int));
+#endif
+
+#ifdef NEED_PROC_MAPS
+# if defined(DYNAMIC_LOADING) && defined(USE_PROC_FOR_LIBRARIES)
+ GC_INNER char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
+ char **prot, unsigned int *maj_dev,
+ char **mapping_name);
+# endif
+ GC_INNER char *GC_get_maps(void); /* from os_dep.c */
+#endif /* NEED_PROC_MAPS */
+
+#ifdef GC_ASSERTIONS
+# define GC_ASSERT(expr) \
+ if (!(expr)) { \
+ GC_err_printf("Assertion failure: %s:%d\n", \
+ __FILE__, __LINE__); \
+ ABORT("assertion failure"); \
+ }
+ GC_INNER word GC_compute_large_free_bytes(void);
+ GC_INNER word GC_compute_root_size(void);
+#else
+# define GC_ASSERT(expr)
+#endif
+
+/* Check a compile time assertion at compile time. The error */
+/* message for failure is a bit baroque, but ... */
#if defined(mips) && !defined(__GNUC__)
-/* DOB: MIPSPro C gets an internal error taking the sizeof an array type.
+/* DOB: MIPSPro C gets an internal error taking the sizeof an array type.
This code works correctly (ugliness is to avoid "unused var" warnings) */
-# define GC_STATIC_ASSERT(expr) do { if (0) { char j[(expr)? 1 : -1]; j[0]='\0'; j[0]=j[0]; } } while(0)
+# define GC_STATIC_ASSERT(expr) \
+ do { if (0) { char j[(expr)? 1 : -1]; j[0]='\0'; j[0]=j[0]; } } while(0)
#else
-# define GC_STATIC_ASSERT(expr) sizeof(char[(expr)? 1 : -1])
-#endif
-
-# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
- /* We need additional synchronization facilities from the thread */
- /* support. We believe these are less performance critical */
- /* than the main garbage collector lock; standard pthreads-based */
- /* implementations should be sufficient. */
-
- /* The mark lock and condition variable. If the GC lock is also */
- /* acquired, the GC lock must be acquired first. The mark lock is */
- /* used to both protect some variables used by the parallel */
- /* marker, and to protect GC_fl_builder_count, below. */
- /* GC_notify_all_marker() is called when */
- /* the state of the parallel marker changes */
- /* in some significant way (see gc_mark.h for details). The */
- /* latter set of events includes incrementing GC_mark_no. */
- /* GC_notify_all_builder() is called when GC_fl_builder_count */
- /* reaches 0. */
-
- extern void GC_acquire_mark_lock();
- extern void GC_release_mark_lock();
- extern void GC_notify_all_builder();
- /* extern void GC_wait_builder(); */
- extern void GC_wait_for_reclaim();
-
- extern word GC_fl_builder_count; /* Protected by mark lock. */
-# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
-# ifdef PARALLEL_MARK
- extern void GC_notify_all_marker();
- extern void GC_wait_marker();
- extern word GC_mark_no; /* Protected by mark lock. */
-
- extern void GC_help_marker(word my_mark_no);
- /* Try to help out parallel marker for mark cycle */
- /* my_mark_no. Returns if the mark cycle finishes or */
- /* was already done, or there was nothing to do for */
- /* some other reason. */
-# endif /* PARALLEL_MARK */
-
-# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS)
- /* We define the thread suspension signal here, so that we can refer */
- /* to it in the dirty bit implementation, if necessary. Ideally we */
- /* would allocate a (real-time ?) signal using the standard mechanism.*/
- /* unfortunately, there is no standard mechanism. (There is one */
- /* in Linux glibc, but it's not exported.) Thus we continue to use */
- /* the same hard-coded signals we've always used. */
-# if !defined(SIG_SUSPEND)
-# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
-# if defined(SPARC) && !defined(SIGPWR)
- /* SPARC/Linux doesn't properly define SIGPWR in <signal.h>.
- * It is aliased to SIGLOST in asm/signal.h, though. */
-# define SIG_SUSPEND SIGLOST
-# else
- /* Linuxthreads itself uses SIGUSR1 and SIGUSR2. */
-# define SIG_SUSPEND SIGPWR
-# endif
-# else /* !GC_LINUX_THREADS */
-# if defined(_SIGRTMIN)
-# define SIG_SUSPEND _SIGRTMIN + 6
-# else
-# define SIG_SUSPEND SIGRTMIN + 6
-# endif
+# define GC_STATIC_ASSERT(expr) (void)sizeof(char[(expr)? 1 : -1])
+#endif
+
+#define COND_DUMP_CHECKS { \
+ GC_ASSERT(GC_compute_large_free_bytes() == GC_large_free_bytes); \
+ GC_ASSERT(GC_compute_root_size() == GC_root_size); }
+
+#ifndef NO_DEBUGGING
+ GC_EXTERN GC_bool GC_dump_regularly;
+ /* Generate regular debugging dumps. */
+# define COND_DUMP { if (EXPECT(GC_dump_regularly, FALSE)) GC_dump(); \
+ else COND_DUMP_CHECKS; }
+#else
+# define COND_DUMP COND_DUMP_CHECKS
+#endif
+
+#if defined(PARALLEL_MARK)
+ /* We need additional synchronization facilities from the thread */
+ /* support. We believe these are less performance critical */
+ /* than the main garbage collector lock; standard pthreads-based */
+ /* implementations should be sufficient. */
+
+# define GC_markers_m1 GC_parallel
+ /* Number of mark threads we would like to have */
+ /* excluding the initiating thread. */
+
+ /* The mark lock and condition variable. If the GC lock is also */
+ /* acquired, the GC lock must be acquired first. The mark lock is */
+ /* used to both protect some variables used by the parallel */
+ /* marker, and to protect GC_fl_builder_count, below. */
+ /* GC_notify_all_marker() is called when */
+ /* the state of the parallel marker changes */
+ /* in some significant way (see gc_mark.h for details). The */
+ /* latter set of events includes incrementing GC_mark_no. */
+ /* GC_notify_all_builder() is called when GC_fl_builder_count */
+ /* reaches 0. */
+
+ GC_INNER void GC_acquire_mark_lock(void);
+ GC_INNER void GC_release_mark_lock(void);
+ GC_INNER void GC_notify_all_builder(void);
+ GC_INNER void GC_wait_for_reclaim(void);
+
+ GC_EXTERN word GC_fl_builder_count; /* Protected by mark lock. */
+
+ GC_INNER void GC_notify_all_marker(void);
+ GC_INNER void GC_wait_marker(void);
+ GC_EXTERN word GC_mark_no; /* Protected by mark lock. */
+
+ GC_INNER void GC_help_marker(word my_mark_no);
+ /* Try to help out parallel marker for mark cycle */
+ /* my_mark_no. Returns if the mark cycle finishes or */
+ /* was already done, or there was nothing to do for */
+ /* some other reason. */
+#endif /* PARALLEL_MARK */
+
+#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && !defined(NACL) \
+ && !defined(SIG_SUSPEND)
+ /* We define the thread suspension signal here, so that we can refer */
+ /* to it in the dirty bit implementation, if necessary. Ideally we */
+ /* would allocate a (real-time?) signal using the standard mechanism. */
+ /* unfortunately, there is no standard mechanism. (There is one */
+ /* in Linux glibc, but it's not exported.) Thus we continue to use */
+ /* the same hard-coded signals we've always used. */
+# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
+# if defined(SPARC) && !defined(SIGPWR)
+ /* SPARC/Linux doesn't properly define SIGPWR in <signal.h>. */
+ /* It is aliased to SIGLOST in asm/signal.h, though. */
+# define SIG_SUSPEND SIGLOST
+# else
+ /* Linuxthreads itself uses SIGUSR1 and SIGUSR2. */
+# define SIG_SUSPEND SIGPWR
+# endif
+# elif !defined(GC_OPENBSD_THREADS) && !defined(GC_DARWIN_THREADS)
+# if defined(_SIGRTMIN)
+# define SIG_SUSPEND _SIGRTMIN + 6
+# else
+# define SIG_SUSPEND SIGRTMIN + 6
# endif
-# endif /* !SIG_SUSPEND */
-
# endif
+#endif /* GC_PTHREADS && !SIG_SUSPEND */
+
+#if defined(GC_PTHREADS) && !defined(GC_SEM_INIT_PSHARED)
+# define GC_SEM_INIT_PSHARED 0
+#endif
+
+#include <setjmp.h>
+
+/* Some macros for setjmp that works across signal handlers */
+/* were possible, and a couple of routines to facilitate */
+/* catching accesses to bad addresses when that's */
+/* possible/needed. */
+#if (defined(UNIX_LIKE) || (defined(NEED_FIND_LIMIT) && defined(CYGWIN32))) \
+ && !defined(GC_NO_SIGSETJMP)
+# if defined(SUNOS5SIGS) && !defined(FREEBSD) && !defined(LINUX)
+# include <sys/siginfo.h>
+# endif
+ /* Define SETJMP and friends to be the version that restores */
+ /* the signal mask. */
+# define SETJMP(env) sigsetjmp(env, 1)
+# define LONGJMP(env, val) siglongjmp(env, val)
+# define JMP_BUF sigjmp_buf
+#else
+# ifdef ECOS
+# define SETJMP(env) hal_setjmp(env)
+# else
+# define SETJMP(env) setjmp(env)
+# endif
+# define LONGJMP(env, val) longjmp(env, val)
+# define JMP_BUF jmp_buf
+#endif /* !UNIX_LIKE || GC_NO_SIGSETJMP */
-# endif /* GC_PRIVATE_H */
+/* Do we need the GC_find_limit machinery to find the end of a */
+/* data segment. */
+#if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)
+# define NEED_FIND_LIMIT
+#endif
+
+#if !defined(STACKBOTTOM) && defined(HEURISTIC2)
+# define NEED_FIND_LIMIT
+#endif
+
+#if (defined(SVR4) || defined(AUX) || defined(DGUX) \
+ || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
+# define NEED_FIND_LIMIT
+#endif
+
+#if defined(FREEBSD) && (defined(I386) || defined(X86_64) \
+ || defined(powerpc) || defined(__powerpc__))
+# include <machine/trap.h>
+# if !defined(PCR)
+# define NEED_FIND_LIMIT
+# endif
+#endif /* FREEBSD */
+
+#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \
+ && !defined(NEED_FIND_LIMIT)
+ /* Used by GC_init_netbsd_elf() in os_dep.c. */
+# define NEED_FIND_LIMIT
+#endif
+
+#if defined(IA64) && !defined(NEED_FIND_LIMIT)
+# define NEED_FIND_LIMIT
+ /* May be needed for register backing store base. */
+#endif
+
+#if defined(NEED_FIND_LIMIT) \
+ || (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))
+ JMP_BUF GC_jmp_buf;
+
+ /* Set up a handler for address faults which will longjmp to */
+ /* GC_jmp_buf; */
+ GC_INNER void GC_setup_temporary_fault_handler(void);
+ /* Undo the effect of GC_setup_temporary_fault_handler. */
+ GC_INNER void GC_reset_fault_handler(void);
+#endif /* NEED_FIND_LIMIT || USE_PROC_FOR_LIBRARIES */
+
+/* Some convenience macros for cancellation support. */
+#if defined(CANCEL_SAFE)
+# if defined(GC_ASSERTIONS) && (defined(USE_COMPILER_TLS) \
+ || (defined(LINUX) && !defined(ARM32) \
+ && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) \
+ || defined(HPUX) /* and probably others ... */))
+ extern __thread unsigned char GC_cancel_disable_count;
+# define NEED_CANCEL_DISABLE_COUNT
+# define INCR_CANCEL_DISABLE() ++GC_cancel_disable_count
+# define DECR_CANCEL_DISABLE() --GC_cancel_disable_count
+# define ASSERT_CANCEL_DISABLED() GC_ASSERT(GC_cancel_disable_count > 0)
+# else
+# define INCR_CANCEL_DISABLE()
+# define DECR_CANCEL_DISABLE()
+# define ASSERT_CANCEL_DISABLED()
+# endif /* GC_ASSERTIONS & ... */
+# define DISABLE_CANCEL(state) \
+ { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); \
+ INCR_CANCEL_DISABLE(); }
+# define RESTORE_CANCEL(state) \
+ { ASSERT_CANCEL_DISABLED(); \
+ pthread_setcancelstate(state, NULL); \
+ DECR_CANCEL_DISABLE(); }
+#else /* !CANCEL_SAFE */
+# define DISABLE_CANCEL(state)
+# define RESTORE_CANCEL(state)
+# define ASSERT_CANCEL_DISABLED()
+#endif /* !CANCEL_SAFE */
+
+#endif /* GC_PRIVATE_H */
diff --git a/boehm-gc/include/private/gcconfig.h b/boehm-gc/include/private/gcconfig.h
index 94b446b6796..c21c38ca32f 100644
--- a/boehm-gc/include/private/gcconfig.h
+++ b/boehm-gc/include/private/gcconfig.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
@@ -21,27 +21,38 @@
* case, a few declarations relying on types declared in gc_priv.h will be
* omitted.
*/
-
-#ifndef GCCONFIG_H
-# define GCCONFIG_H
+#ifndef GCCONFIG_H
+#define GCCONFIG_H
# ifndef GC_PRIVATE_H
- /* Fake ptr_t declaration, just to avoid compilation errors. */
- /* This avoids many instances if "ifndef GC_PRIVATE_H" below. */
+ /* Fake ptr_t declaration, just to avoid compilation errors. */
+ /* This avoids many instances if "ifndef GC_PRIVATE_H" below. */
typedef struct GC_undefined_struct * ptr_t;
+# include <stddef.h> /* For size_t etc. */
# endif
-/* Machine dependent parameters. Some tuning parameters can be found */
-/* near the top of gc_private.h. */
+/* Machine dependent parameters. Some tuning parameters can be found */
+/* near the top of gc_private.h. */
/* Machine specific parts contributed by various people. See README file. */
+#if defined(__ANDROID__) && !defined(PLATFORM_ANDROID)
+ /* __ANDROID__ macro is defined by Android NDK gcc. */
+# define PLATFORM_ANDROID 1
+#endif
+
+#if defined(__SYMBIAN32__) && !defined(SYMBIAN)
+# define SYMBIAN
+# ifdef __WINS__
+# pragma data_seg(".data2")
+# endif
+#endif
+
/* First a unified test for Linux: */
-# if defined(linux) || defined(__linux__)
-# ifndef LINUX
-# define LINUX
-# endif
+# if (defined(linux) || defined(__linux__) || defined(PLATFORM_ANDROID)) \
+ && !defined(LINUX) && !defined(__native_client__)
+# define LINUX
# endif
/* And one for NetBSD: */
@@ -55,29 +66,39 @@
# endif
/* And one for FreeBSD: */
-# if defined(__FreeBSD__)
+# if (defined(__FreeBSD__) || defined(__DragonFly__) \
+ || defined(__FreeBSD_kernel__)) && !defined(FREEBSD)
# define FREEBSD
# endif
+/* And one for Darwin: */
+# if defined(macosx) || (defined(__APPLE__) && defined(__MACH__))
+# define DARWIN
+# endif
+
/* Determine the machine type: */
-# if defined(__arm__) || defined(__thumb__)
+# if defined(__native_client__)
+# define NACL
+# define I386
+# define mach_type_known
+# endif
+# if defined(__arm) || defined(__arm__) || defined(__thumb__)
# define ARM32
-# if !defined(LINUX) && !defined(NETBSD)
+# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) \
+ && !defined(DARWIN) && !defined(_WIN32) && !defined(__CEGCC__) \
+ && !defined(SYMBIAN)
# define NOSYS
# define mach_type_known
# endif
# endif
# if defined(sun) && defined(mc68000)
-# define M68K
-# define SUNOS4
-# define mach_type_known
+# error SUNOS4 no longer supported
# endif
# if defined(hp9000s300)
-# define M68K
-# define HP
-# define mach_type_known
+# error M68K based HP machines no longer supported.
# endif
# if defined(OPENBSD) && defined(m68k)
+ /* FIXME: Should we remove this case? */
# define M68K
# define mach_type_known
# endif
@@ -85,6 +106,14 @@
# define SPARC
# define mach_type_known
# endif
+# if defined(OPENBSD) && defined(__arm__)
+# define ARM32
+# define mach_type_known
+# endif
+# if defined(OPENBSD) && defined(__sh__)
+# define SH
+# define mach_type_known
+# endif
# if defined(NETBSD) && (defined(m68k) || defined(__m68k__))
# define M68K
# define mach_type_known
@@ -97,12 +126,16 @@
# define ARM32
# define mach_type_known
# endif
-# if defined(vax)
+# if defined(NETBSD) && defined(__sh__)
+# define SH
+# define mach_type_known
+# endif
+# if defined(vax) || defined(__vax__)
# define VAX
# ifdef ultrix
-# define ULTRIX
+# define ULTRIX
# else
-# define BSD
+# define BSD
# endif
# define mach_type_known
# endif
@@ -115,16 +148,12 @@
# if defined(nec_ews) || defined(_nec_ews)
# define EWS4800
# endif
-# if !defined(LINUX) && !defined(EWS4800)
-# if defined(ultrix) || defined(__ultrix) || defined(__NetBSD__)
-# define ULTRIX
+# if !defined(LINUX) && !defined(EWS4800) && !defined(NETBSD) \
+ && !defined(OPENBSD)
+# if defined(ultrix) || defined(__ultrix)
+# define ULTRIX
# else
-# if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) \
- || defined(__SYSTYPE_SVR4__)
-# define IRIX5 /* or IRIX 6.X */
-# else
-# define RISCOS /* or IRIX 4.X */
-# endif
+# define IRIX5 /* or IRIX 6.X */
# endif
# endif /* !LINUX */
# if defined(__NetBSD__) && defined(__MIPSEL__)
@@ -146,7 +175,12 @@
# endif
# if defined(sun) && (defined(i386) || defined(__i386__))
# define I386
-# define SUNOS5
+# define SOLARIS
+# define mach_type_known
+# endif
+# if defined(sun) && defined(__amd64)
+# define X86_64
+# define SOLARIS
# define mach_type_known
# endif
# if (defined(__OS2__) || defined(__EMX__)) && defined(__32BIT__)
@@ -155,28 +189,25 @@
# define mach_type_known
# endif
# if defined(ibm032)
-# define RT
-# define mach_type_known
+# error IBM PC/RT no longer supported.
# endif
# if defined(sun) && (defined(sparc) || defined(__sparc))
# define SPARC
/* Test for SunOS 5.x */
# include <errno.h>
-# ifdef ECHRNG
-# define SUNOS5
-# else
-# define SUNOS4
-# endif
+# define SOLARIS
# define mach_type_known
# endif
# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
- && !defined(__OpenBSD__) && !(__NetBSD__)
+ && !defined(__OpenBSD__) && !defined(__NetBSD__) \
+ && !defined(__FreeBSD__) && !defined(__DragonFly__)
# define SPARC
# define DRSNX
# define mach_type_known
# endif
# if defined(_IBMR2)
-# define RS6000
+# define POWERPC
+# define AIX
# define mach_type_known
# endif
# if defined(__NetBSD__) && defined(__sparc__)
@@ -184,7 +215,7 @@
# define mach_type_known
# endif
# if defined(_M_XENIX) && defined(_M_SYSV) && defined(_M_I386)
- /* The above test may need refinement */
+ /* The above test may need refinement */
# define I386
# if defined(_SCO_ELF)
# define SCO_ELF
@@ -194,21 +225,21 @@
# define mach_type_known
# endif
# if defined(_AUX_SOURCE)
-# define M68K
-# define SYSV
-# define mach_type_known
+# error A/UX no longer supported
# endif
# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
|| defined(hppa) || defined(__hppa__)
# define HP_PA
-# ifndef LINUX
+# if !defined(LINUX) && !defined(HPUX) && !defined(OPENBSD)
# define HPUX
# endif
# define mach_type_known
# endif
-# if defined(__ia64) && defined(_HPUX_SOURCE)
+# if defined(__ia64) && (defined(_HPUX_SOURCE) || defined(__HP_aCC))
# define IA64
-# define HPUX
+# ifndef HPUX
+# define HPUX
+# endif
# define mach_type_known
# endif
# if defined(__BEOS__) && defined(_X86_)
@@ -216,6 +247,10 @@
# define BEOS
# define mach_type_known
# endif
+# if defined(OPENBSD) && defined(__amd64__)
+# define X86_64
+# define mach_type_known
+# endif
# if defined(LINUX) && (defined(i386) || defined(__i386__))
# define I386
# define mach_type_known
@@ -228,11 +263,18 @@
# define IA64
# define mach_type_known
# endif
-# if defined(LINUX) && defined(__arm__)
+# if defined(LINUX) && (defined(__arm) || defined(__arm__))
# define ARM32
# define mach_type_known
# endif
-# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || defined(powerpc64) || defined(__powerpc64__))
+# if defined(LINUX) && defined(__cris__)
+# ifndef CRIS
+# define CRIS
+# endif
+# define mach_type_known
+# endif
+# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) \
+ || defined(powerpc64) || defined(__powerpc64__))
# define POWERPC
# define mach_type_known
# endif
@@ -244,48 +286,74 @@
# define SPARC
# define mach_type_known
# endif
-# if defined(LINUX) && defined(__arm__)
-# define ARM32
-# define mach_type_known
-# endif
# if defined(LINUX) && defined(__sh__)
# define SH
# define mach_type_known
# endif
+# if defined(LINUX) && defined(__avr32__)
+# define AVR32
+# define mach_type_known
+# endif
+# if defined(LINUX) && defined(__m32r__)
+# define M32R
+# define mach_type_known
+# endif
+# if defined(FREEBSD) && (defined(powerpc) || defined(__powerpc__))
+# define POWERPC
+# define mach_type_known
+# endif
# if defined(__alpha) || defined(__alpha__)
# define ALPHA
-# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) && !defined(FREEBSD)
-# define OSF1 /* a.k.a Digital Unix */
+# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) \
+ && !defined(FREEBSD)
+# define OSF1 /* a.k.a Digital Unix */
# endif
# define mach_type_known
# endif
# if defined(_AMIGA) && !defined(AMIGA)
# define AMIGA
# endif
-# ifdef AMIGA
+# ifdef AMIGA
# define M68K
# define mach_type_known
# endif
-# if defined(THINK_C) || defined(__MWERKS__) && !defined(__powerc)
+# if defined(THINK_C) \
+ || (defined(__MWERKS__) && !defined(__powerc) && !defined(SYMBIAN))
# define M68K
# define MACOS
# define mach_type_known
# endif
-# if defined(__MWERKS__) && defined(__powerc) && !defined(__MACH__)
+# if defined(__MWERKS__) && defined(__powerc) && !defined(__MACH__) \
+ && !defined(SYMBIAN)
# define POWERPC
# define MACOS
# define mach_type_known
# endif
-# if defined(macosx) || \
- defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
-# define DARWIN
+# if defined(__OpenBSD__) && defined(__powerpc__)
+# define POWERPC
+# define OPENBSD
+# define mach_type_known
+# endif
+# if defined(DARWIN)
+# if defined(__ppc__) || defined(__ppc64__)
# define POWERPC
# define mach_type_known
-# endif
-# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
-# define DARWIN
+# elif defined(__x86_64__) || defined(__x86_64)
+# define X86_64
+# define mach_type_known
+# elif defined(__i386__)
# define I386
- --> Not really supported, but at least we recognize it.
+# define mach_type_known
+# elif defined(__arm__)
+# define ARM32
+# define mach_type_known
+# define DARWIN_DONT_PARSE_STACK
+# endif
+# endif
+# if defined(__rtems__) && (defined(i386) || defined(__i386__))
+# define I386
+# define RTEMS
+# define mach_type_known
# endif
# if defined(NeXT) && defined(mc68000)
# define M68K
@@ -306,6 +374,10 @@
# define I386
# define mach_type_known
# endif
+# if defined(FREEBSD) && defined(__x86_64__)
+# define X86_64
+# define mach_type_known
+# endif
# if defined(__NetBSD__) && (defined(i386) || defined(__i386__))
# define I386
# define mach_type_known
@@ -314,6 +386,10 @@
# define X86_64
# define mach_type_known
# endif
+# if defined(FREEBSD) && defined(__sparc__)
+# define SPARC
+# define mach_type_known
+# endif
# if defined(bsdi) && (defined(i386) || defined(__i386__))
# define I386
# define BSDI
@@ -334,30 +410,35 @@
/* DGUX defined */
# define mach_type_known
# endif
-# if defined(_WIN32_WCE)
+# if defined(_WIN32_WCE) || defined(__CEGCC__) || defined(__MINGW32CE__)
/* SH3, SH4, MIPS already defined for corresponding architectures */
# if defined(SH3) || defined(SH4)
# define SH
# endif
-# if defined(x86)
+# if defined(x86) || defined(__i386__)
# define I386
# endif
-# if defined(ARM)
+# if defined(_M_ARM) || defined(ARM) || defined(_ARM_)
# define ARM32
# endif
# define MSWINCE
# define mach_type_known
# else
-# if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
- || defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
-# define I386
-# define MSWIN32 /* or Win32s */
+# if ((defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300)) \
+ || (defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) \
+ && !defined(SYMBIAN))
+# if defined(__LP64__) || defined(_WIN64)
+# define X86_64
+# else
+# define I386
+# endif
+# define MSWIN32 /* or Win64 */
# define mach_type_known
# endif
# if defined(_MSC_VER) && defined(_M_IA64)
# define IA64
-# define MSWIN32 /* Really win64, but we don't treat 64-bit */
- /* variants as a differnt platform. */
+# define MSWIN32 /* Really win64, but we don't treat 64-bit */
+ /* variants as a different platform. */
# endif
# endif
# if defined(__DJGPP__)
@@ -372,7 +453,7 @@
# define CYGWIN32
# define mach_type_known
# endif
-# if defined(__MINGW32__)
+# if defined(__MINGW32__) && !defined(mach_type_known)
# define I386
# define MSWIN32
# define mach_type_known
@@ -388,15 +469,16 @@
# define mach_type_known
# endif
# if defined(__pj__)
-# define PJ
-# define mach_type_known
+# error PicoJava no longer supported
+ /* The implementation had problems, and I haven't heard of users */
+ /* in ages. If you want it resurrected, let me know. */
# endif
# if defined(__embedded__) && defined(PPC)
# define POWERPC
# define NOSYS
# define mach_type_known
# endif
-/* Ivan Demakov */
+
# if defined(__WATCOMC__) && defined(__386__)
# define I386
# if !defined(OS2) && !defined(MSWIN32) && !defined(DOS4GW)
@@ -418,73 +500,89 @@
# endif
# if defined(__GNU__)
# if defined(__i386__)
-/* The Debian Hurd running on generic PC */
+/* The Debian Hurd running on generic PC */
# define HURD
# define I386
# define mach_type_known
-# endif
+# endif
+# endif
+# if defined(__TANDEM)
+ /* Nonstop S-series */
+ /* FIXME: Should recognize Integrity series? */
+# define MIPS
+# define NONSTOP
+# define mach_type_known
+# endif
+# if defined(__hexagon__) && defined(LINUX)
+# define HEXAGON
+# define mach_type_known
+# endif
+
+# if defined(SYMBIAN)
+# define mach_type_known
# endif
/* Feel free to add more clauses here */
-/* Or manually define the machine type here. A machine type is */
-/* characterized by the architecture. Some */
-/* machine types are further subdivided by OS. */
-/* the macros ULTRIX, RISCOS, and BSD to distinguish. */
-/* Note that SGI IRIX is treated identically to RISCOS. */
-/* SYSV on an M68K actually means A/UX. */
+/* Or manually define the machine type here. A machine type is */
+/* characterized by the architecture. Some */
+/* machine types are further subdivided by OS. */
+/* Macros such as LINUX, FREEBSD, etc. distinguish them. */
+/* SYSV on an M68K actually means A/UX. */
/* The distinction in these cases is usually the stack starting address */
# ifndef mach_type_known
- --> unknown machine type
-# endif
- /* Mapping is: M68K ==> Motorola 680X0 */
- /* (SUNOS4,HP,NEXT, and SYSV (A/UX), */
- /* MACOS and AMIGA variants) */
- /* I386 ==> Intel 386 */
- /* (SEQUENT, OS2, SCO, LINUX, NETBSD, */
- /* FREEBSD, THREE86BSD, MSWIN32, */
- /* BSDI,SUNOS5, NEXT, other variants) */
- /* NS32K ==> Encore Multimax */
- /* MIPS ==> R2000 or R3000 */
- /* (RISCOS, ULTRIX variants) */
- /* VAX ==> DEC VAX */
- /* (BSD, ULTRIX variants) */
- /* RS6000 ==> IBM RS/6000 AIX3.X */
- /* RT ==> IBM PC/RT */
- /* HP_PA ==> HP9000/700 & /800 */
- /* HP/UX, LINUX */
- /* SPARC ==> SPARC v7/v8/v9 */
- /* (SUNOS4, SUNOS5, LINUX, */
- /* DRSNX variants) */
- /* ALPHA ==> DEC Alpha */
- /* (OSF1 and LINUX variants) */
- /* M88K ==> Motorola 88XX0 */
- /* (CX_UX and DGUX) */
- /* S370 ==> 370-like machine */
- /* running Amdahl UTS4 */
+# error "The collector has not been ported to this machine/OS combination."
+# endif
+ /* Mapping is: M68K ==> Motorola 680X0 */
+ /* (NEXT, and SYSV (A/UX), */
+ /* MACOS and AMIGA variants) */
+ /* I386 ==> Intel 386 */
+ /* (SEQUENT, OS2, SCO, LINUX, NETBSD, */
+ /* FREEBSD, THREE86BSD, MSWIN32, */
+ /* BSDI,SOLARIS, NEXT, other variants) */
+ /* NS32K ==> Encore Multimax */
+ /* MIPS ==> R2000 through R14K */
+ /* (many variants) */
+ /* VAX ==> DEC VAX */
+ /* (BSD, ULTRIX variants) */
+ /* HP_PA ==> HP9000/700 & /800 */
+ /* HP/UX, LINUX */
+ /* SPARC ==> SPARC v7/v8/v9 */
+ /* (SOLARIS, LINUX, DRSNX variants) */
+ /* ALPHA ==> DEC Alpha */
+ /* (OSF1 and LINUX variants) */
+ /* M88K ==> Motorola 88XX0 */
+ /* (CX_UX and DGUX) */
+ /* S370 ==> 370-like machine */
+ /* running Amdahl UTS4 */
/* S390 ==> 390-like machine */
- /* running LINUX */
- /* ARM32 ==> Intel StrongARM */
- /* IA64 ==> Intel IPF */
- /* (e.g. Itanium) */
- /* (LINUX and HPUX) */
- /* SH ==> Hitachi SuperH */
- /* (LINUX & MSWINCE) */
- /* X86_64 ==> AMD x86-64 */
- /* POWERPC ==> IBM/Apple PowerPC */
- /* (MACOS(<=9),DARWIN(incl.MACOSX),*/
- /* LINUX, NETBSD, NOSYS variants) */
+ /* running LINUX */
+ /* ARM32 ==> Intel StrongARM */
+ /* IA64 ==> Intel IPF */
+ /* (e.g. Itanium) */
+ /* (LINUX and HPUX) */
+ /* SH ==> Hitachi SuperH */
+ /* (LINUX & MSWINCE) */
+ /* X86_64 ==> AMD x86-64 */
+ /* POWERPC ==> IBM/Apple PowerPC */
+ /* (MACOS(<=9),DARWIN(incl.MACOSX),*/
+ /* LINUX, NETBSD, AIX, NOSYS */
+ /* variants) */
+ /* Handles 32 and 64-bit variants. */
+ /* CRIS ==> Axis Etrax */
+ /* M32R ==> Renesas M32R */
+ /* HEXAGON ==> Qualcomm Hexagon */
/*
* For each architecture and OS, the following need to be defined:
*
- * CPP_WORD_SZ is a simple integer constant representing the word size.
- * in bits. We assume byte addressibility, where a byte has 8 bits.
- * We also assume CPP_WORD_SZ is either 32 or 64.
+ * CPP_WORDSZ is a simple integer constant representing the word size.
+ * in bits. We assume byte addressability, where a byte has 8 bits.
+ * We also assume CPP_WORDSZ is either 32 or 64.
* (We care about the length of pointers, not hardware
* bus widths. Thus a 64 bit processor with a C compiler that uses
- * 32 bit pointers should use CPP_WORD_SZ of 32, not 64. Default is 32.)
+ * 32 bit pointers should use CPP_WORDSZ of 32, not 64. Default is 32.)
*
* MACH_TYPE is a string representation of the machine type.
* OS_TYPE is analogous for the OS.
@@ -505,9 +603,9 @@
* DATAEND, if not `end' where `end' is defined as ``extern int end[];''.
* RTH suggests gaining access to linker script synth'd values with
* this idiom instead of `&end' where `end' is defined as ``extern int end;'' .
- *
- * ALIGN_DOUBLE of GC_malloc should return blocks aligned to twice
- * the pointer size.
+ * Otherwise, ``GCC will assume these are in .sdata/.sbss'' and it will, e.g.,
+ * cause failures on alpha*-*-* with ``-msmall-data or -fpic'' or mips-*-*
+ * without any special options.
*
* STACKBOTTOM is the cool end of the stack, which is usually the
* highest address in the stack.
@@ -515,24 +613,26 @@
* For each machine, the following should:
* 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and
* 2) define exactly one of
- * STACKBOTTOM (should be defined to be an expression)
- * LINUX_STACKBOTTOM
- * HEURISTIC1
- * HEURISTIC2
+ * STACKBOTTOM (should be defined to be an expression)
+ * LINUX_STACKBOTTOM
+ * HEURISTIC1
+ * HEURISTIC2
* 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 if 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
- * the next multiple of STACK_GRAN.
+ * the next multiple of STACK_GRAN.
* HEURISTIC2: Take an address inside GC_init's frame, increment it repeatedly
- * in small steps (decrement if STACK_GROWS_UP), and read the value
- * at each location. Remember the value when the first
- * Segmentation violation or Bus error is signalled. Round that
- * to the nearest plausible page boundary, and use that instead
- * of STACKBOTTOM.
+ * in small steps (decrement if STACK_GROWS_UP), and read the value
+ * at each location. Remember the value when the first
+ * Segmentation violation or Bus error is signaled. Round that
+ * to the nearest plausible page boundary, and use that instead
+ * of STACKBOTTOM.
*
* Gustavo Rodriguez-Rivera points out that on most (all?) Unix machines,
* the value of environ is a pointer that can serve as STACKBOTTOM.
@@ -556,27 +656,31 @@
* easily accomplished by introducing a new main program, setting
* GC_stackbottom to the address of a local variable, and then calling
* the original main program. The new main program would read something
- * like:
+ * like (provided real_main() is not inlined by the compiler):
*
- * # include "gc_private.h"
+ * # include "gc_private.h"
*
- * main(argc, argv, envp)
- * int argc;
- * char **argv, **envp;
- * {
- * int dummy;
+ * main(argc, argv, envp)
+ * int argc;
+ * char **argv, **envp;
+ * {
+ * volatile int dummy;
*
- * GC_stackbottom = (ptr_t)(&dummy);
- * return(real_main(argc, argv, envp));
- * }
+ * GC_stackbottom = (ptr_t)(&dummy);
+ * return(real_main(argc, argv, envp));
+ * }
*
*
* Each architecture may also define the style of virtual dirty bit
* implementation to be used:
* MPROTECT_VDB: Write protect the heap and catch faults.
+ * GWW_VDB: Use win32 GetWriteWatch primitive.
* PROC_VDB: Use the SVR4 /proc primitives to read dirty bits.
*
- * An architecture may define DYNAMIC_LOADING if dynamic_load.c
+ * The first and second one may be combined, in which case a runtime
+ * selection will be made, based on GetWriteWatch availability.
+ *
+ * An architecture may define DYNAMIC_LOADING if dyn_load.c
* defined GC_register_dynamic_libraries() for the architecture.
*
* An architecture may define PREFETCH(x) to preload the cache with *x.
@@ -592,56 +696,68 @@
* allocation.
*/
-/* If we are using a recent version of gcc, we can use __builtin_unwind_init()
- * to push the relevant registers onto the stack. This generally makes
- * USE_GENERIC_PUSH_REGS the preferred approach for marking from registers.
- */
-# if defined(__GNUC__) && ((__GNUC__ >= 3) || \
- (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
- && !defined(__INTEL_COMPILER)
+/* If we are using a recent version of gcc, we can use */
+/* __builtin_unwind_init() to push the relevant registers onto the stack. */
+# if defined(__GNUC__) && ((__GNUC__ >= 3) \
+ || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
+ && !defined(__INTEL_COMPILER) && !defined(__PATHCC__) \
+ && !(defined(POWERPC) && defined(DARWIN)) /* for MacOS X 10.3.9 */ \
+ && !defined(RTEMS) \
+ && !defined(__clang__) /* since no-op in clang (3.0) */
# define HAVE_BUILTIN_UNWIND_INIT
# endif
+# ifdef SYMBIAN
+# define MACH_TYPE "SYMBIAN"
+# define OS_TYPE "SYMBIAN"
+# define CPP_WORDSZ 32
+# define ALIGNMENT 4
+# define DATASTART NULL
+# define DATAEND NULL
+# endif
+
# define STACK_GRAN 0x1000000
# ifdef M68K
# define MACH_TYPE "M68K"
# define ALIGNMENT 2
# ifdef OPENBSD
-# define OS_TYPE "OPENBSD"
-# define HEURISTIC2
-# ifdef __ELF__
-# define DATASTART GC_data_start
-# define DYNAMIC_LOADING
-# else
- extern char etext[];
-# define DATASTART ((ptr_t)(etext))
+ /* FIXME: Should we remove this case? */
+# define OS_TYPE "OPENBSD"
+# define HEURISTIC2
+# ifdef __ELF__
+ extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
+# else
+ extern char etext[];
+# define DATASTART ((ptr_t)(etext))
# endif
-# define USE_GENERIC_PUSH_REGS
# endif
# ifdef NETBSD
-# define OS_TYPE "NETBSD"
-# define HEURISTIC2
-# ifdef __ELF__
-# define DATASTART GC_data_start
-# define DYNAMIC_LOADING
-# else
- extern char etext[];
-# define DATASTART ((ptr_t)(etext))
+# define OS_TYPE "NETBSD"
+# define HEURISTIC2
+# ifdef __ELF__
+ extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
+# else
+ extern char etext[];
+# define DATASTART ((ptr_t)(etext))
# endif
-# define USE_GENERIC_PUSH_REGS
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
-# define STACKBOTTOM ((ptr_t)0xf0000000)
-# define USE_GENERIC_PUSH_REGS
- /* We never got around to the assembly version. */
-/* # define MPROTECT_VDB - Reported to not work 9/17/01 */
+# define LINUX_STACKBOTTOM
+# define MPROTECT_VDB
# ifdef __ELF__
# define DYNAMIC_LOADING
-# include <features.h>
-# if defined(__GLIBC__)&& __GLIBC__>=2
+# include <features.h>
+# if defined(__GLIBC__) && __GLIBC__ >= 2
# define SEARCH_FOR_DATA_START
-# else /* !GLIBC2 */
+# else /* !GLIBC2 */
+# ifdef PLATFORM_ANDROID
+# define __environ environ
+# endif
extern char **__environ;
# define DATASTART ((ptr_t)(&__environ))
/* hideous kludge: __environ is the first */
@@ -652,148 +768,211 @@
/* would include .rodata, which may */
/* contain large read-only data tables */
/* that we'd rather not scan. */
-# endif /* !GLIBC2 */
+# endif /* !GLIBC2 */
extern int _end[];
-# define DATAEND (_end)
+# define DATAEND (ptr_t)(_end)
# else
extern int etext[];
# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
# endif
# endif
-# ifdef SUNOS4
-# define OS_TYPE "SUNOS4"
- extern char etext[];
-# define DATASTART ((ptr_t)((((word) (etext)) + 0x1ffff) & ~0x1ffff))
-# define HEURISTIC1 /* differs */
-# define DYNAMIC_LOADING
-# endif
-# ifdef HP
-# define OS_TYPE "HP"
- extern char etext[];
-# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
-# define STACKBOTTOM ((ptr_t) 0xffeffffc)
- /* empirically determined. seems to work. */
-# include <unistd.h>
-# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE)
-# endif
-# ifdef SYSV
-# define OS_TYPE "SYSV"
- extern etext[];
-# define DATASTART ((ptr_t)((((word) (etext)) + 0x3fffff) \
- & ~0x3fffff) \
- +((word)etext & 0x1fff))
- /* This only works for shared-text binaries with magic number 0413.
- The other sorts of SysV binaries put the data at the end of the text,
- in which case the default of etext would work. Unfortunately,
- handling both would require having the magic-number available.
- -- Parag
- */
-# define STACKBOTTOM ((ptr_t)0xFFFFFFFE)
- /* The stack starts at the top of memory, but */
- /* 0x0 cannot be used as setjump_test complains */
- /* that the stack direction is incorrect. Two */
- /* bytes down from 0x0 should be safe enough. */
- /* --Parag */
-# include <sys/mmu.h>
-# define GETPAGESIZE() PAGESIZE /* Is this still right? */
-# endif
# ifdef AMIGA
-# define OS_TYPE "AMIGA"
- /* STACKBOTTOM and DATASTART handled specially */
- /* in os_dep.c */
-# define DATAEND /* not needed */
-# define GETPAGESIZE() 4096
+# define OS_TYPE "AMIGA"
+ /* STACKBOTTOM and DATASTART handled specially */
+ /* in os_dep.c */
+# define DATAEND /* not needed */
+# define GETPAGESIZE() 4096
# endif
# ifdef MACOS
# ifndef __LOWMEM__
# include <LowMem.h>
# endif
# define OS_TYPE "MACOS"
- /* see os_dep.c for details of global data segments. */
+ /* see os_dep.c for details of global data segments. */
# define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
-# define DATAEND /* not needed */
+# define DATAEND /* not needed */
# define GETPAGESIZE() 4096
# endif
# ifdef NEXT
-# define OS_TYPE "NEXT"
-# define DATASTART ((ptr_t) get_etext())
-# define STACKBOTTOM ((ptr_t) 0x4000000)
-# define DATAEND /* not needed */
+# define OS_TYPE "NEXT"
+# define DATASTART ((ptr_t) get_etext())
+# define DATASTART_IS_FUNC
+# define STACKBOTTOM ((ptr_t) 0x4000000)
+# define DATAEND /* not needed */
# endif
# endif
-# ifdef POWERPC
+# if defined(POWERPC)
# define MACH_TYPE "POWERPC"
# ifdef MACOS
-# define ALIGNMENT 2 /* Still necessary? Could it be 4? */
+# define ALIGNMENT 2 /* Still necessary? Could it be 4? */
# ifndef __LOWMEM__
# include <LowMem.h>
# endif
# define OS_TYPE "MACOS"
- /* see os_dep.c for details of global data segments. */
+ /* see os_dep.c for details of global data segments. */
# define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
# define DATAEND /* not needed */
# endif
# ifdef LINUX
-# if (defined (powerpc64) || defined(__powerpc64__))
+# if defined(__powerpc64__)
# define ALIGNMENT 8
# define CPP_WORDSZ 64
+# ifndef HBLKSIZE
+# define HBLKSIZE 4096
+# endif
# else
-# define ALIGNMENT 4 /* Guess. Can someone verify? */
- /* This was 2, but that didn't sound right. */
+# define ALIGNMENT 4
# endif
# define OS_TYPE "LINUX"
- /* HEURISTIC1 has been reliably reported to fail for a 32-bit */
- /* executable on a 64 bit kernel. */
+ /* HEURISTIC1 has been reliably reported to fail for a 32-bit */
+ /* executable on a 64 bit kernel. */
# define LINUX_STACKBOTTOM
# define DYNAMIC_LOADING
# define SEARCH_FOR_DATA_START
extern int _end[];
-# define DATAEND (_end)
+# define DATAEND (ptr_t)(_end)
# endif
# ifdef DARWIN
-# define ALIGNMENT 4
# define OS_TYPE "DARWIN"
# define DYNAMIC_LOADING
- /* XXX: see get_end(3), get_etext() and get_end() should not be used.
- These aren't used when dyld support is enabled (it is by default) */
+# if defined(__ppc64__)
+# define ALIGNMENT 8
+# define CPP_WORDSZ 64
+# define STACKBOTTOM ((ptr_t) 0x7fff5fc00000)
+# define CACHE_LINE_SIZE 64
+# ifndef HBLKSIZE
+# define HBLKSIZE 4096
+# endif
+# else
+# define ALIGNMENT 4
+# define STACKBOTTOM ((ptr_t) 0xc0000000)
+# endif
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used. */
+ /* These aren't used when dyld support is enabled (it is by default). */
# define DATASTART ((ptr_t) get_etext())
-# define DATAEND ((ptr_t) get_end())
-# define STACKBOTTOM ((ptr_t) 0xc0000000)
-# define USE_MMAP
+# define DATAEND ((ptr_t) get_end())
+# ifndef USE_MMAP
+# define USE_MMAP
+# endif
# define USE_MMAP_ANON
-# define USE_ASM_PUSH_REGS
- /* This is potentially buggy. It needs more testing. See the comments in
- os_dep.c */
# define MPROTECT_VDB
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
# if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
- /* The performance impact of prefetches is untested */
-# define PREFETCH(x) \
- __asm__ __volatile__ ("dcbt 0,%0" : : "r" ((const void *) (x)))
-# define PREFETCH_FOR_WRITE(x) \
- __asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
+ /* The performance impact of prefetches is untested */
+# define PREFETCH(x) \
+ __asm__ __volatile__ ("dcbt 0,%0" : : "r" ((const void *) (x)))
+# define PREFETCH_FOR_WRITE(x) \
+ __asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
# endif
- /* There seems to be some issues with trylock hanging on darwin. This
- should be looked into some more */
+ /* There seems to be some issues with trylock hanging on darwin. */
+ /* This should be looked into some more. */
# define NO_PTHREAD_TRYLOCK
# endif
+# ifdef OPENBSD
+# define OS_TYPE "OPENBSD"
+# define ALIGNMENT 4
+# ifdef GC_OPENBSD_THREADS
+# define UTHREAD_SP_OFFSET 268
+# else
+# include <sys/param.h>
+# include <uvm/uvm_extern.h>
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# endif
+ extern int __data_start[];
+# define DATASTART ((ptr_t)__data_start)
+ extern char _end[];
+# define DATAEND ((ptr_t)(&_end))
+# define DYNAMIC_LOADING
+# endif
+# ifdef FREEBSD
+# if defined(__powerpc64__)
+# define ALIGNMENT 8
+# define CPP_WORDSZ 64
+# ifndef HBLKSIZE
+# define HBLKSIZE 4096
+# endif
+# else
+# define ALIGNMENT 4
+# endif
+# define OS_TYPE "FREEBSD"
+# ifndef GC_FREEBSD_THREADS
+# define MPROTECT_VDB
+# endif
+# define SIG_SUSPEND SIGUSR1
+# define SIG_THR_RESTART SIGUSR2
+# define FREEBSD_STACKBOTTOM
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+# endif
+ extern char etext[];
+ ptr_t GC_FreeBSDGetDataStart(size_t, ptr_t);
+# define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
+# define DATASTART_IS_FUNC
+# endif
# ifdef NETBSD
# define ALIGNMENT 4
# define OS_TYPE "NETBSD"
# define HEURISTIC2
- extern char etext[];
+ extern ptr_t GC_data_start;
# define DATASTART GC_data_start
# define DYNAMIC_LOADING
# endif
+# ifdef SN_TARGET_PS3
+# define NO_GETENV
+# define CPP_WORDSZ 32
+# define ALIGNMENT 4
+ extern int _end [];
+ extern int __bss_start;
+# define DATAEND (ptr_t)(_end)
+# define DATASTART (ptr_t)(__bss_start)
+# define STACKBOTTOM ((ptr_t)ps3_get_stack_bottom())
+# define NO_PTHREAD_TRYLOCK
+ /* Current GC LOCK() implementation for PS3 explicitly */
+ /* use pthread_mutex_lock for some reason. */
+# endif
+# ifdef AIX
+# define OS_TYPE "AIX"
+# undef ALIGNMENT /* in case it's defined */
+# undef IA64
+ /* DOB: some AIX installs stupidly define IA64 in */
+ /* /usr/include/sys/systemcfg.h */
+# ifdef __64BIT__
+# define ALIGNMENT 8
+# define CPP_WORDSZ 64
+# define STACKBOTTOM ((ptr_t)0x1000000000000000)
+# else
+# define ALIGNMENT 4
+# define CPP_WORDSZ 32
+# define STACKBOTTOM ((ptr_t)((ulong)&errno))
+# endif
+# ifndef USE_MMAP
+# define USE_MMAP
+# endif
+# define USE_MMAP_ANON
+ /* From AIX linker man page:
+ _text Specifies the first location of the program.
+ _etext Specifies the first location after the program.
+ _data Specifies the first location of the data.
+ _edata Specifies the first location after the initialized data
+ _end or end Specifies the first location after all data.
+ */
+ extern int _data[], _end[];
+# define DATASTART ((ptr_t)((ulong)_data))
+# define DATAEND ((ptr_t)((ulong)_end))
+ extern int errno;
+# define DYNAMIC_LOADING
+ /* For really old versions of AIX, this may have to be removed. */
+# endif
+
# ifdef NOSYS
# define ALIGNMENT 4
# define OS_TYPE "NOSYS"
extern void __end[], __dso_handle[];
# define DATASTART (__dso_handle) /* OK, that's ugly. */
-# define DATAEND (__end)
- /* Stack starts at 0xE0000000 for the simulator. */
+# define DATAEND (ptr_t)(__end)
+ /* Stack starts at 0xE0000000 for the simulator. */
# undef STACK_GRAN
# define STACK_GRAN 0x10000000
# define HEURISTIC1
@@ -802,27 +981,20 @@
# ifdef VAX
# define MACH_TYPE "VAX"
-# define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */
+# define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */
extern char etext[];
# define DATASTART ((ptr_t)(etext))
# ifdef BSD
-# define OS_TYPE "BSD"
-# define HEURISTIC1
- /* HEURISTIC2 may be OK, but it's hard to test. */
+# define OS_TYPE "BSD"
+# define HEURISTIC1
+ /* HEURISTIC2 may be OK, but it's hard to test. */
# endif
# ifdef ULTRIX
-# define OS_TYPE "ULTRIX"
-# define STACKBOTTOM ((ptr_t) 0x7fffc800)
+# define OS_TYPE "ULTRIX"
+# define STACKBOTTOM ((ptr_t) 0x7fffc800)
# endif
# endif
-# ifdef RT
-# define MACH_TYPE "RT"
-# define ALIGNMENT 4
-# define DATASTART ((ptr_t) 0x10000000)
-# define STACKBOTTOM ((ptr_t) 0x1fffd800)
-# endif
-
# ifdef SPARC
# define MACH_TYPE "SPARC"
# if defined(__arch64__) || defined(__sparcv9)
@@ -830,75 +1002,59 @@
# define CPP_WORDSZ 64
# define ELF_CLASS ELFCLASS64
# else
-# define ALIGNMENT 4 /* Required by hardware */
+# define ALIGNMENT 4 /* Required by hardware */
# define CPP_WORDSZ 32
# endif
-# define ALIGN_DOUBLE
-# ifdef SUNOS5
-# define OS_TYPE "SUNOS5"
- extern int _etext[];
- extern int _end[];
- extern ptr_t GC_SysVGetDataStart();
-# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
-# define DATAEND (_end)
-# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
-# define USE_MMAP
- /* Otherwise we now use calloc. Mmap may result in the */
- /* heap interleaved with thread stacks, which can result in */
- /* excessive blacklisting. Sbrk is unusable since it */
- /* doesn't interact correctly with the system malloc. */
-# endif
+ /* Don't define USE_ASM_PUSH_REGS. We do use an asm helper, but */
+ /* not to push the registers on the mark stack. */
+# ifdef SOLARIS
+# define OS_TYPE "SOLARIS"
+ extern int _etext[];
+ extern int _end[];
+ ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+# define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext)
+# define DATASTART_IS_FUNC
+# define DATAEND (ptr_t)(_end)
+# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
+# define USE_MMAP
+ /* Otherwise we now use calloc. Mmap may result in the */
+ /* heap interleaved with thread stacks, which can result in */
+ /* excessive blacklisting. Sbrk is unusable since it */
+ /* doesn't interact correctly with the system malloc. */
+# endif
# ifdef USE_MMAP
# define HEAP_START (ptr_t)0x40000000
# else
-# define HEAP_START DATAEND
+# define HEAP_START DATAEND
# endif
-# define PROC_VDB
-/* HEURISTIC1 reportedly no longer works under 2.7. */
-/* HEURISTIC2 probably works, but this appears to be preferable. */
-/* Apparently USRSTACK is defined to be USERLIMIT, but in some */
-/* installations that's undefined. We work around this with a */
-/* gross hack: */
+# define PROC_VDB
+/* HEURISTIC1 reportedly no longer works under 2.7. */
+/* HEURISTIC2 probably works, but this appears to be preferable. */
+/* Apparently USRSTACK is defined to be USERLIMIT, but in some */
+/* installations that's undefined. We work around this with a */
+/* gross hack: */
# include <sys/vmparam.h>
-# ifdef USERLIMIT
- /* This should work everywhere, but doesn't. */
-# define STACKBOTTOM USRSTACK
+# ifdef USERLIMIT
+ /* This should work everywhere, but doesn't. */
+# define STACKBOTTOM ((ptr_t) USRSTACK)
# else
-# define HEURISTIC2
+# define HEURISTIC2
# endif
-# include <unistd.h>
+# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
- /* getpagesize() appeared to be missing from at least one */
- /* Solaris 5.4 installation. Weird. */
-# define DYNAMIC_LOADING
-# endif
-# ifdef SUNOS4
-# define OS_TYPE "SUNOS4"
- /* [If you have a weak stomach, don't read this.] */
- /* We would like to use: */
-/* # define DATASTART ((ptr_t)((((word) (etext)) + 0x1fff) & ~0x1fff)) */
- /* This fails occasionally, due to an ancient, but very */
- /* persistent ld bug. etext is set 32 bytes too high. */
- /* We instead read the text segment size from the a.out */
- /* header, which happens to be mapped into our address space */
- /* at the start of the text segment. The detective work here */
- /* was done by Robert Ehrlich, Manuel Serrano, and Bernard */
- /* Serpette of INRIA. */
- /* This assumes ZMAGIC, i.e. demand-loadable executables. */
-# define TEXTSTART 0x2000
-# define DATASTART ((ptr_t)(*(int *)(TEXTSTART+0x4)+TEXTSTART))
-# define MPROTECT_VDB
-# define HEURISTIC1
-# define DYNAMIC_LOADING
+ /* getpagesize() appeared to be missing from at least one */
+ /* Solaris 5.4 installation. Weird. */
+# define DYNAMIC_LOADING
# endif
# ifdef DRSNX
-# define OS_TYPE "DRSNX"
- extern ptr_t GC_SysVGetDataStart();
- extern int etext[];
-# define DATASTART GC_SysVGetDataStart(0x10000, etext)
-# define MPROTECT_VDB
+# define OS_TYPE "DRSNX"
+ ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+ extern int etext[];
+# define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)etext)
+# define DATASTART_IS_FUNC
+# define MPROTECT_VDB
# define STACKBOTTOM ((ptr_t) 0xdfff0000)
-# define DYNAMIC_LOADING
+# define DYNAMIC_LOADING
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
@@ -909,62 +1065,81 @@
# endif
extern int _end[];
extern int _etext[];
-# define DATAEND (_end)
+# define DATAEND (ptr_t)(_end)
# define SVR4
- extern ptr_t GC_SysVGetDataStart();
+ ptr_t GC_SysVGetDataStart(size_t, ptr_t);
# ifdef __arch64__
-# define DATASTART GC_SysVGetDataStart(0x100000, _etext)
- /* libc_stack_end is not set reliably for sparc64 */
-# define STACKBOTTOM ((ptr_t) 0x80000000000ULL)
+# define DATASTART GC_SysVGetDataStart(0x100000, (ptr_t)_etext)
# else
-# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
-# define LINUX_STACKBOTTOM
+# define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext)
# endif
+# define DATASTART_IS_FUNC
+# define LINUX_STACKBOTTOM
# endif
# ifdef OPENBSD
# define OS_TYPE "OPENBSD"
-# define STACKBOTTOM ((ptr_t) 0xf8000000)
- extern int etext[];
-# define DATASTART ((ptr_t)(etext))
+# ifdef GC_OPENBSD_THREADS
+# define UTHREAD_SP_OFFSET 232
+# else
+# include <sys/param.h>
+# include <uvm/uvm_extern.h>
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# endif
+ extern int __data_start[];
+# define DATASTART ((ptr_t)__data_start)
+ extern char _end[];
+# define DATAEND ((ptr_t)(&_end))
+# define DYNAMIC_LOADING
# endif
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
# ifdef __ELF__
-# define DATASTART GC_data_start
-# define DYNAMIC_LOADING
+ extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
# else
- extern char etext[];
-# define DATASTART ((ptr_t)(etext))
+ extern char etext[];
+# define DATASTART ((ptr_t)(etext))
# endif
# endif
+# ifdef FREEBSD
+# define OS_TYPE "FREEBSD"
+# define SIG_SUSPEND SIGUSR1
+# define SIG_THR_RESTART SIGUSR2
+# define FREEBSD_STACKBOTTOM
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+# endif
+ extern char etext[];
+ extern char edata[];
+ extern char end[];
+# define NEED_FIND_LIMIT
+# define DATASTART ((ptr_t)(&etext))
+ ptr_t GC_find_limit(ptr_t, GC_bool);
+# define DATAEND (GC_find_limit (DATASTART, TRUE))
+# define DATAEND_IS_FUNC
+# define DATASTART2 ((ptr_t)(&edata))
+# define DATAEND2 ((ptr_t)(&end))
+# endif
# endif
# ifdef I386
# define MACH_TYPE "I386"
# if defined(__LP64__) || defined(_WIN64)
-# define CPP_WORDSZ 64
-# define ALIGNMENT 8
+# error This should be handled as X86_64
# else
# define CPP_WORDSZ 32
# define ALIGNMENT 4
- /* Appears to hold for all "32 bit" compilers */
- /* except Borland. The -a4 option fixes */
- /* Borland. */
- /* Ivan Demakov: For Watcom the option is -zp4. */
-# endif
-# ifndef SMALL_CONFIG
-# define ALIGN_DOUBLE /* Not strictly necessary, but may give speed */
- /* improvement on Pentiums. */
-# endif
-# ifdef HAVE_BUILTIN_UNWIND_INIT
-# define USE_GENERIC_PUSH_REGS
+ /* Appears to hold for all "32 bit" compilers */
+ /* except Borland. The -a4 option fixes */
+ /* Borland. For Watcom the option is -zp4. */
# endif
# ifdef SEQUENT
-# define OS_TYPE "SEQUENT"
- extern int etext[];
+# define OS_TYPE "SEQUENT"
+ extern int etext[];
# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
-# define STACKBOTTOM ((ptr_t) 0x3ffff000)
+# define STACKBOTTOM ((ptr_t) 0x3ffff000)
# endif
# ifdef BEOS
# define OS_TYPE "BEOS"
@@ -973,45 +1148,49 @@
extern int etext[];
# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
# endif
-# ifdef SUNOS5
-# define OS_TYPE "SUNOS5"
+# ifdef SOLARIS
+# define OS_TYPE "SOLARIS"
extern int _etext[], _end[];
- extern ptr_t GC_SysVGetDataStart();
-# define DATASTART GC_SysVGetDataStart(0x1000, _etext)
-# define DATAEND (_end)
-/* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7, */
-/* but reportedly breaks under 2.8. It appears that the stack */
-/* base is a property of the executable, so this should not break */
-/* old executables. */
-/* HEURISTIC2 probably works, but this appears to be preferable. */
+ ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+# define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext)
+# define DATASTART_IS_FUNC
+# define DATAEND (ptr_t)(_end)
+/* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7, */
+/* but reportedly breaks under 2.8. It appears that the stack */
+/* base is a property of the executable, so this should not break */
+/* old executables. */
+/* HEURISTIC2 probably works, but this appears to be preferable. */
# include <sys/vm.h>
-# define STACKBOTTOM USRSTACK
+# define STACKBOTTOM ((ptr_t) USRSTACK)
/* At least in Solaris 2.5, PROC_VDB gives wrong values for dirty bits. */
-/* It appears to be fixed in 2.8 and 2.9. */
-# ifdef SOLARIS25_PROC_VDB_BUG_FIXED
-# define PROC_VDB
-# endif
-# define DYNAMIC_LOADING
-# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
-# define USE_MMAP
- /* Otherwise we now use calloc. Mmap may result in the */
- /* heap interleaved with thread stacks, which can result in */
- /* excessive blacklisting. Sbrk is unusable since it */
- /* doesn't interact correctly with the system malloc. */
-# endif
+/* It appears to be fixed in 2.8 and 2.9. */
+# ifdef SOLARIS25_PROC_VDB_BUG_FIXED
+# define PROC_VDB
+# endif
+# ifndef GC_THREADS
+# define MPROTECT_VDB
+# endif
+# define DYNAMIC_LOADING
+# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
+# define USE_MMAP
+ /* Otherwise we now use calloc. Mmap may result in the */
+ /* heap interleaved with thread stacks, which can result in */
+ /* excessive blacklisting. Sbrk is unusable since it */
+ /* doesn't interact correctly with the system malloc. */
+# endif
# ifdef USE_MMAP
# define HEAP_START (ptr_t)0x40000000
# else
-# define HEAP_START DATAEND
+# define HEAP_START DATAEND
# endif
# endif
# ifdef SCO
-# define OS_TYPE "SCO"
- extern int etext[];
-# define DATASTART ((ptr_t)((((word) (etext)) + 0x3fffff) \
- & ~0x3fffff) \
- +((word)etext & 0xfff))
-# define STACKBOTTOM ((ptr_t) 0x7ffffffc)
+# define OS_TYPE "SCO"
+ extern int etext[];
+# define DATASTART ((ptr_t)((((word) (etext)) + 0x3fffff) \
+ & ~0x3fffff) \
+ +((word)etext & 0xfff))
+# define STACKBOTTOM ((ptr_t) 0x7ffffffc)
# endif
# ifdef SCO_ELF
# define OS_TYPE "SCO_ELF"
@@ -1019,151 +1198,153 @@
# define DATASTART ((ptr_t)(etext))
# define STACKBOTTOM ((ptr_t) 0x08048000)
# define DYNAMIC_LOADING
-# define ELF_CLASS ELFCLASS32
+# define ELF_CLASS ELFCLASS32
# endif
# ifdef DGUX
-# define OS_TYPE "DGUX"
- extern int _etext, _end;
- extern ptr_t GC_SysVGetDataStart();
-# define DATASTART GC_SysVGetDataStart(0x1000, &_etext)
-# define DATAEND (&_end)
-# define STACK_GROWS_DOWN
-# define HEURISTIC2
-# include <unistd.h>
-# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
-# define DYNAMIC_LOADING
-# ifndef USE_MMAP
-# define USE_MMAP
-# endif /* USE_MMAP */
-# define MAP_FAILED (void *) -1
-# ifdef USE_MMAP
-# define HEAP_START (ptr_t)0x40000000
-# else /* USE_MMAP */
-# define HEAP_START DATAEND
-# endif /* USE_MMAP */
+# define OS_TYPE "DGUX"
+ extern int _etext, _end;
+ ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+# define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)(&_etext))
+# define DATASTART_IS_FUNC
+# define DATAEND (ptr_t)(&_end)
+# define STACK_GROWS_DOWN
+# define HEURISTIC2
+# include <unistd.h>
+# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
+# define DYNAMIC_LOADING
+# ifndef USE_MMAP
+# define USE_MMAP
+# endif
+# define MAP_FAILED (void *) ((word)-1)
+# ifdef USE_MMAP
+# define HEAP_START (ptr_t)0x40000000
+# else
+# define HEAP_START DATAEND
+# endif
# endif /* DGUX */
+# ifdef NACL
+# define OS_TYPE "NACL"
+ extern int etext[];
+/* #define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) */
+# define DATASTART ((ptr_t)0x10000000)
+ extern int _end[];
+# define DATAEND (_end)
+# undef STACK_GRAN
+# define STACK_GRAN 0x10000
+# define HEURISTIC1
+# define GETPAGESIZE() 65536
+# ifndef MAX_NACL_GC_THREADS
+# define MAX_NACL_GC_THREADS 1024
+# endif
+# endif /* NACL */
+
# ifdef LINUX
-# ifndef __GNUC__
- /* The Intel compiler doesn't like inline assembly */
-# define USE_GENERIC_PUSH_REGS
-# endif
-# define OS_TYPE "LINUX"
+# define OS_TYPE "LINUX"
# define LINUX_STACKBOTTOM
-# if 0
-# define HEURISTIC1
+# if 0
+# define HEURISTIC1
# undef STACK_GRAN
# define STACK_GRAN 0x10000000
- /* STACKBOTTOM is usually 0xc0000000, but this changes with */
- /* different kernel configurations. In particular, systems */
- /* with 2GB physical memory will usually move the user */
- /* address space limit, and hence initial SP to 0x80000000. */
+ /* STACKBOTTOM is usually 0xc0000000, but this changes with */
+ /* different kernel configurations. In particular, systems */
+ /* with 2GB physical memory will usually move the user */
+ /* address space limit, and hence initial SP to 0x80000000. */
# endif
# if !defined(GC_LINUX_THREADS) || !defined(REDIRECT_MALLOC)
-# define MPROTECT_VDB
-# else
- /* We seem to get random errors in incremental mode, */
- /* possibly because Linux threads is itself a malloc client */
- /* and can't deal with the signals. */
-# endif
-# define HEAP_START (ptr_t)0x1000
- /* This encourages mmap to give us low addresses, */
- /* thus allowing the heap to grow to ~3GB */
+# define MPROTECT_VDB
+# else
+ /* We seem to get random errors in incremental mode, */
+ /* possibly because Linux threads is itself a malloc client */
+ /* and can't deal with the signals. */
+# endif
+# define HEAP_START (ptr_t)0x1000
+ /* This encourages mmap to give us low addresses, */
+ /* thus allowing the heap to grow to ~3GB */
# ifdef __ELF__
# define DYNAMIC_LOADING
-# ifdef UNDEFINED /* includes ro data */
- extern int _etext[];
+# ifdef UNDEFINED /* includes ro data */
+ extern int _etext[];
# define DATASTART ((ptr_t)((((word) (_etext)) + 0xfff) & ~0xfff))
-# endif
-# include <features.h>
-# if defined(__GLIBC__) && __GLIBC__ >= 2
-# define SEARCH_FOR_DATA_START
-# else
- extern char **__environ;
+# endif
+# include <features.h>
+# if defined(__GLIBC__) && __GLIBC__ >= 2 \
+ || defined(PLATFORM_ANDROID)
+# define SEARCH_FOR_DATA_START
+# else
+ extern char **__environ;
# define DATASTART ((ptr_t)(&__environ))
- /* hideous kludge: __environ is the first */
- /* word in crt0.o, and delimits the start */
- /* of the data segment, no matter which */
- /* ld options were passed through. */
- /* We could use _etext instead, but that */
- /* would include .rodata, which may */
- /* contain large read-only data tables */
- /* that we'd rather not scan. */
-# endif
- extern int _end[];
-# define DATAEND (_end)
-# else
- extern int etext[];
+ /* hideous kludge: __environ is the first */
+ /* word in crt0.o, and delimits the start */
+ /* of the data segment, no matter which */
+ /* ld options were passed through. */
+ /* We could use _etext instead, but that */
+ /* would include .rodata, which may */
+ /* contain large read-only data tables */
+ /* that we'd rather not scan. */
+# endif
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
+# if defined(PLATFORM_ANDROID) && !defined(GC_NO_SIGSETJMP)
+ /* As of Android NDK r8b, _sigsetjmp is still missing */
+ /* for x86 (setjmp is used instead to find data_start). */
+# define GC_NO_SIGSETJMP
+# endif
+# else
+ extern int etext[];
# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
# endif
-# ifdef USE_I686_PREFETCH
- /* FIXME: Thus should use __builtin_prefetch, but we'll leave that */
- /* for the next rtelease. */
-# define PREFETCH(x) \
- __asm__ __volatile__ (" prefetchnta %0": : "m"(*(char *)(x)))
- /* Empirically prefetcht0 is much more effective at reducing */
- /* cache miss stalls for the targetted load instructions. But it */
- /* seems to interfere enough with other cache traffic that the net */
- /* result is worse than prefetchnta. */
-# if 0
- /* Using prefetches for write seems to have a slight negative */
- /* impact on performance, at least for a PIII/500. */
-# define PREFETCH_FOR_WRITE(x) \
- __asm__ __volatile__ (" prefetcht0 %0": : "m"(*(char *)(x)))
-# endif
-# endif
-# ifdef USE_3DNOW_PREFETCH
-# define PREFETCH(x) \
- __asm__ __volatile__ (" prefetch %0": : "m"(*(char *)(x)))
-# define PREFETCH_FOR_WRITE(x) \
- __asm__ __volatile__ (" prefetchw %0": : "m"(*(char *)(x)))
-# endif
+# ifdef USE_I686_PREFETCH
+ /* FIXME: Thus should use __builtin_prefetch, but we'll leave that */
+ /* for the next rtelease. */
+# define PREFETCH(x) \
+ __asm__ __volatile__ ("prefetchnta %0" : : "m"(*(char *)(x)))
+ /* Empirically prefetcht0 is much more effective at reducing */
+ /* cache miss stalls for the targeted load instructions. But it */
+ /* seems to interfere enough with other cache traffic that the */
+ /* net result is worse than prefetchnta. */
+# ifdef FORCE_WRITE_PREFETCH
+ /* Using prefetches for write seems to have a slight negative */
+ /* impact on performance, at least for a PIII/500. */
+# define PREFETCH_FOR_WRITE(x) \
+ __asm__ __volatile__ ("prefetcht0 %0" : : "m"(*(char *)(x)))
+# endif
+# endif
+# ifdef USE_3DNOW_PREFETCH
+# define PREFETCH(x) \
+ __asm__ __volatile__ ("prefetch %0" : : "m"(*(char *)(x)))
+# define PREFETCH_FOR_WRITE(x) \
+ __asm__ __volatile__ ("prefetchw %0" : : "m"(*(char *)(x)))
+# endif
# endif
# ifdef CYGWIN32
# define OS_TYPE "CYGWIN32"
- extern int _data_start__[];
- extern int _data_end__[];
- extern int _bss_start__[];
- extern int _bss_end__[];
- /* For binutils 2.9.1, we have */
- /* DATASTART = _data_start__ */
- /* DATAEND = _bss_end__ */
- /* whereas for some earlier versions it was */
- /* DATASTART = _bss_start__ */
- /* DATAEND = _data_end__ */
- /* To get it right for both, we take the */
- /* minumum/maximum of the two. */
-# ifndef MAX
-# define MAX(x,y) ((x) > (y) ? (x) : (y))
-# endif
-# ifndef MIN
-# define MIN(x,y) ((x) < (y) ? (x) : (y))
-# endif
-# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__))
-# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__))
-# undef STACK_GRAN
+# define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */
+# define DATAEND ((ptr_t)GC_DATAEND)
+# undef STACK_GRAN
# define STACK_GRAN 0x10000
-# define HEURISTIC1
+# ifdef USE_MMAP
+# define NEED_FIND_LIMIT
+# define USE_MMAP_ANON
+# endif
# endif
# ifdef OS2
-# define OS_TYPE "OS2"
- /* STACKBOTTOM and DATASTART are handled specially in */
- /* os_dep.c. OS2 actually has the right */
- /* system call! */
-# define DATAEND /* not needed */
-# define USE_GENERIC_PUSH_REGS
+# define OS_TYPE "OS2"
+ /* STACKBOTTOM and DATASTART are handled specially in */
+ /* os_dep.c. OS2 actually has the right */
+ /* system call! */
+# define DATAEND /* not needed */
# endif
# ifdef MSWIN32
-# define OS_TYPE "MSWIN32"
- /* STACKBOTTOM and DATASTART are handled specially in */
- /* os_dep.c. */
-# ifndef __WATCOMC__
-# define MPROTECT_VDB
-# endif
+# define OS_TYPE "MSWIN32"
+ /* STACKBOTTOM and DATASTART are handled specially in */
+ /* os_dep.c. */
+# define MPROTECT_VDB
+# define GWW_VDB
# define DATAEND /* not needed */
# endif
# ifdef MSWINCE
-# define OS_TYPE "MSWINCE"
+# define OS_TYPE "MSWINCE"
# define DATAEND /* not needed */
# endif
# ifdef DJGPP
@@ -1173,61 +1354,94 @@
extern int _stklen;
extern int __djgpp_stack_limit;
# define DATASTART ((ptr_t)((((word) (etext)) + 0x1ff) & ~0x1ff))
-/* # define STACKBOTTOM ((ptr_t)((word) _stubinfo + _stubinfo->size \
- + _stklen)) */
+/* #define STACKBOTTOM ((ptr_t)((word)_stubinfo+_stubinfo->size+_stklen)) */
# define STACKBOTTOM ((ptr_t)((word) __djgpp_stack_limit + _stklen))
- /* This may not be right. */
+ /* This may not be right. */
# endif
# ifdef OPENBSD
-# define OS_TYPE "OPENBSD"
+# define OS_TYPE "OPENBSD"
+# ifdef GC_OPENBSD_THREADS
+# define UTHREAD_SP_OFFSET 176
+# else
+# include <sys/param.h>
+# include <uvm/uvm_extern.h>
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# endif
+ extern int __data_start[];
+# define DATASTART ((ptr_t)__data_start)
+ extern char _end[];
+# define DATAEND ((ptr_t)(&_end))
+# define DYNAMIC_LOADING
# endif
# ifdef FREEBSD
-# define OS_TYPE "FREEBSD"
-# ifndef GC_FREEBSD_THREADS
-# define MPROTECT_VDB
-# endif
-# define SIG_SUSPEND SIGUSR1
-# define SIG_THR_RESTART SIGUSR2
-# define FREEBSD_STACKBOTTOM
-# ifdef __ELF__
-# define DYNAMIC_LOADING
-# endif
- extern char etext[];
- extern char * GC_FreeBSDGetDataStart();
-# define DATASTART GC_FreeBSDGetDataStart(0x1000, &etext)
+# define OS_TYPE "FREEBSD"
+# ifndef GC_FREEBSD_THREADS
+# define MPROTECT_VDB
+# endif
+# ifdef __GLIBC__
+# define SIG_SUSPEND (32+6)
+# define SIG_THR_RESTART (32+5)
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
+# else
+# define SIG_SUSPEND SIGUSR1
+# define SIG_THR_RESTART SIGUSR2
+ /* SIGTSTP and SIGCONT could be used alternatively. */
+# endif
+# define FREEBSD_STACKBOTTOM
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+# endif
+ extern char etext[];
+ char * GC_FreeBSDGetDataStart(size_t, ptr_t);
+# define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
+# define DATASTART_IS_FUNC
# endif
# ifdef NETBSD
-# define OS_TYPE "NETBSD"
-# ifdef __ELF__
-# define DYNAMIC_LOADING
-# endif
+# define OS_TYPE "NETBSD"
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+# endif
# endif
# ifdef THREE86BSD
-# define OS_TYPE "THREE86BSD"
+# define OS_TYPE "THREE86BSD"
# endif
# ifdef BSDI
-# define OS_TYPE "BSDI"
+# define OS_TYPE "BSDI"
# endif
-# if defined(OPENBSD) || defined(NETBSD) \
- || defined(THREE86BSD) || defined(BSDI)
-# define HEURISTIC2
- extern char etext[];
-# define DATASTART ((ptr_t)(etext))
+# if defined(NETBSD) || defined(THREE86BSD) || defined(BSDI)
+# define HEURISTIC2
+ extern char etext[];
+# define DATASTART ((ptr_t)(etext))
# endif
# ifdef NEXT
-# define OS_TYPE "NEXT"
-# define DATASTART ((ptr_t) get_etext())
-# define STACKBOTTOM ((ptr_t)0xc0000000)
-# define DATAEND /* not needed */
+# define OS_TYPE "NEXT"
+# define DATASTART ((ptr_t) get_etext())
+# define DATASTART_IS_FUNC
+# define STACKBOTTOM ((ptr_t)0xc0000000)
+# define DATAEND /* not needed */
+# endif
+# ifdef RTEMS
+# define OS_TYPE "RTEMS"
+# include <sys/unistd.h>
+ extern int etext[];
+ extern int end[];
+ void *rtems_get_stack_bottom(void);
+# define InitStackBottom rtems_get_stack_bottom()
+# define DATASTART ((ptr_t)etext)
+# define DATAEND ((ptr_t)end)
+# define STACKBOTTOM ((ptr_t)InitStackBottom)
+# define SIG_SUSPEND SIGUSR1
+# define SIG_THR_RESTART SIGUSR2
# endif
# ifdef DOS4GW
# define OS_TYPE "DOS4GW"
extern long __nullarea;
extern char _end;
extern char *_STACKTOP;
- /* Depending on calling conventions Watcom C either precedes
- or does not precedes with undescore names of C-variables.
- Make sure startup code variables always have the same names. */
+ /* Depending on calling conventions Watcom C either precedes */
+ /* or does not precedes with underscore names of C-variables. */
+ /* Make sure startup code variables always have the same names. */
#pragma aux __nullarea "*";
#pragma aux _end "*";
# define STACKBOTTOM ((ptr_t) _STACKTOP)
@@ -1239,13 +1453,34 @@
# define OS_TYPE "HURD"
# define STACK_GROWS_DOWN
# define HEURISTIC2
- extern int __data_start[];
-# define DATASTART ( (ptr_t) (__data_start))
- extern int _end[];
-# define DATAEND ( (ptr_t) (_end))
+# define SIG_SUSPEND SIGUSR1
+# define SIG_THR_RESTART SIGUSR2
+# define SEARCH_FOR_DATA_START
+ extern int _end[];
+# define DATAEND ((ptr_t) (_end))
/* # define MPROTECT_VDB Not quite working yet? */
# define DYNAMIC_LOADING
# endif
+# ifdef DARWIN
+# define OS_TYPE "DARWIN"
+# define DARWIN_DONT_PARSE_STACK
+# define DYNAMIC_LOADING
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used. */
+ /* These aren't used when dyld support is enabled (it is by default). */
+# define DATASTART ((ptr_t) get_etext())
+# define DATAEND ((ptr_t) get_end())
+# define STACKBOTTOM ((ptr_t) 0xc0000000)
+# ifndef USE_MMAP
+# define USE_MMAP
+# endif
+# define USE_MMAP_ANON
+# define MPROTECT_VDB
+# include <unistd.h>
+# define GETPAGESIZE() getpagesize()
+ /* There seems to be some issues with trylock hanging on darwin. */
+ /* This should be looked into some more. */
+# define NO_PTHREAD_TRYLOCK
+# endif /* DARWIN */
# endif
# ifdef NS32K
@@ -1253,30 +1488,36 @@
# define ALIGNMENT 4
extern char **environ;
# define DATASTART ((ptr_t)(&environ))
- /* hideous kludge: environ is the first */
- /* word in crt0.o, and delimits the start */
- /* of the data segment, no matter which */
- /* ld options were passed through. */
+ /* hideous kludge: environ is the first */
+ /* word in crt0.o, and delimits the start */
+ /* of the data segment, no matter which */
+ /* ld options were passed through. */
# define STACKBOTTOM ((ptr_t) 0xfffff000) /* for Encore */
# endif
# ifdef MIPS
# define MACH_TYPE "MIPS"
# ifdef LINUX
- /* This was developed for a linuxce style platform. Probably */
- /* needs to be tweaked for workstation class machines. */
# define OS_TYPE "LINUX"
# define DYNAMIC_LOADING
extern int _end[];
-# define DATAEND (_end)
+# define DATAEND (ptr_t)(_end)
+# pragma weak __data_start
extern int __data_start[];
# define DATASTART ((ptr_t)(__data_start))
-# define ALIGNMENT 4
-# define USE_GENERIC_PUSH_REGS
+# ifdef _MIPS_SZPTR
+# define CPP_WORDSZ _MIPS_SZPTR
+# define ALIGNMENT (_MIPS_SZPTR/8)
+# else
+# define ALIGNMENT 4
+# endif
+# ifndef HBLKSIZE
+# define HBLKSIZE 4096
+# endif
# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2
-# define LINUX_STACKBOTTOM
+# define LINUX_STACKBOTTOM
# else
-# define STACKBOTTOM 0x80000000
+# define STACKBOTTOM ((ptr_t)0x7fff8000)
# endif
# endif /* Linux */
# ifdef EWS4800
@@ -1292,58 +1533,47 @@
extern int _DYNAMIC_LINKING[], _gp[];
# define DATASTART ((ptr_t)((((word)etext + 0x3ffff) & ~0x3ffff) \
+ ((word)etext & 0xffff)))
-# define DATAEND (edata)
+# define DATAEND (ptr_t)(edata)
# define DATASTART2 (_DYNAMIC_LINKING \
? (ptr_t)(((word)_gp + 0x8000 + 0x3ffff) & ~0x3ffff) \
: (ptr_t)edata)
-# define DATAEND2 (end)
+# define DATAEND2 (ptr_t)(end)
# define ALIGNMENT 4
# endif
# define OS_TYPE "EWS4800"
-# define USE_GENERIC_PUSH_REGS 1
# endif
# ifdef ULTRIX
-# define HEURISTIC2
+# define HEURISTIC2
# define DATASTART (ptr_t)0x10000000
- /* Could probably be slightly higher since */
- /* startup code allocates lots of stuff. */
-# define OS_TYPE "ULTRIX"
+ /* Could probably be slightly higher since */
+ /* startup code allocates lots of stuff. */
+# define OS_TYPE "ULTRIX"
# define ALIGNMENT 4
# endif
-# ifdef RISCOS
-# define HEURISTIC2
-# define DATASTART (ptr_t)0x10000000
-# define OS_TYPE "RISCOS"
-# define ALIGNMENT 4 /* Required by hardware */
-# endif
# ifdef IRIX5
-# define HEURISTIC2
+# define HEURISTIC2
extern int _fdata[];
# define DATASTART ((ptr_t)(_fdata))
# ifdef USE_MMAP
# define HEAP_START (ptr_t)0x30000000
# else
-# define HEAP_START DATASTART
+# define HEAP_START DATASTART
# endif
- /* Lowest plausible heap address. */
- /* In the MMAP case, we map there. */
- /* In either case it is used to identify */
- /* heap sections so they're not */
- /* considered as roots. */
-# define OS_TYPE "IRIX5"
+ /* Lowest plausible heap address. */
+ /* In the MMAP case, we map there. */
+ /* In either case it is used to identify */
+ /* heap sections so they're not */
+ /* considered as roots. */
+# define OS_TYPE "IRIX5"
/*# define MPROTECT_VDB DOB: this should work, but there is evidence */
-/* of recent breakage. */
+/* of recent breakage. */
# ifdef _MIPS_SZPTR
-# define CPP_WORDSZ _MIPS_SZPTR
-# define ALIGNMENT (_MIPS_SZPTR/8)
-# if CPP_WORDSZ != 64
-# define ALIGN_DOUBLE
-# endif
-# else
+# define CPP_WORDSZ _MIPS_SZPTR
+# define ALIGNMENT (_MIPS_SZPTR/8)
+# else
# define ALIGNMENT 4
-# define ALIGN_DOUBLE
-# endif
-# define DYNAMIC_LOADING
+# endif
+# define DYNAMIC_LOADING
# endif
# ifdef MSWINCE
# define OS_TYPE "MSWINCE"
@@ -1351,14 +1581,11 @@
# define DATAEND /* not needed */
# endif
# if defined(NETBSD)
- /* This also checked for __MIPSEL__ . Why? NETBSD recognition */
- /* should be handled at the top of the file. */
-# define ALIGNMENT 4
# define OS_TYPE "NETBSD"
+# define ALIGNMENT 4
# define HEURISTIC2
-# define USE_GENERIC_PUSH_REGS
# ifdef __ELF__
- extern int etext[];
+ extern ptr_t GC_data_start;
# define DATASTART GC_data_start
# define NEED_FIND_LIMIT
# define DYNAMIC_LOADING
@@ -1367,39 +1594,31 @@
# define STACKBOTTOM ((ptr_t) 0x7ffff000)
# endif /* _ELF_ */
# endif
-# endif
-
-# ifdef RS6000
-# define MACH_TYPE "RS6000"
-# ifdef ALIGNMENT
-# undef ALIGNMENT
-# endif
-# ifdef IA64
-# undef IA64 /* DOB: some AIX installs stupidly define IA64 in /usr/include/sys/systemcfg.h */
+# ifdef OPENBSD
+# define OS_TYPE "OPENBSD"
+# define ALIGNMENT 4
+# ifdef GC_OPENBSD_THREADS
+# define UTHREAD_SP_OFFSET 808
+# else
+# include <sys/param.h>
+# include <uvm/uvm_extern.h>
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# endif
+ extern int _fdata[];
+# define DATASTART ((ptr_t)_fdata)
+ extern char _end[];
+# define DATAEND ((ptr_t)(&_end))
+# define DYNAMIC_LOADING
+# endif
+# if defined(NONSTOP)
+# define CPP_WORDSZ 32
+# define OS_TYPE "NONSTOP"
+# define ALIGNMENT 4
+# define DATASTART ((ptr_t) 0x08000000)
+ extern char **environ;
+# define DATAEND ((ptr_t)(environ - 0x10))
+# define STACKBOTTOM ((ptr_t) 0x4fffffff)
# endif
-# ifdef __64BIT__
-# define ALIGNMENT 8
-# define CPP_WORDSZ 64
-# define STACKBOTTOM ((ptr_t)0x1000000000000000)
-# else
-# define ALIGNMENT 4
-# define CPP_WORDSZ 32
-# define STACKBOTTOM ((ptr_t)((ulong)&errno))
-# endif
- /* From AIX linker man page:
- _text Specifies the first location of the program.
- _etext Specifies the first location after the program.
- _data Specifies the first location of the data.
- _edata Specifies the first location after the initialized data
- _end or end Specifies the first location after all data.
- */
- extern int _data[], _end[];
-# define DATASTART ((ptr_t)((ulong)_data))
-# define DATAEND ((ptr_t)((ulong)_end))
- extern int errno;
-# define USE_GENERIC_PUSH_REGS
-# define DYNAMIC_LOADING
- /* For really old versions of AIX, this may have to be removed. */
# endif
# ifdef HP_PA
@@ -1410,40 +1629,30 @@
# else
# define CPP_WORDSZ 32
# define ALIGNMENT 4
-# define ALIGN_DOUBLE
# endif
-# if !defined(GC_HPUX_THREADS) && !defined(GC_LINUX_THREADS)
-# ifndef LINUX /* For now. */
-# define MPROTECT_VDB
-# endif
-# else
-# define GENERIC_COMPARE_AND_SWAP
- /* No compare-and-swap instruction. Use pthread mutexes */
- /* when we absolutely have to. */
-# ifdef PARALLEL_MARK
-# define USE_MARK_BYTES
- /* Minimize compare-and-swap usage. */
-# endif
+# if !defined(GC_HPUX_THREADS) && !defined(GC_LINUX_THREADS) \
+ && !defined(OPENBSD) && !defined(LINUX) /* For now. */
+# define MPROTECT_VDB
# endif
# define STACK_GROWS_UP
# ifdef HPUX
# define OS_TYPE "HPUX"
extern int __data_start[];
# define DATASTART ((ptr_t)(__data_start))
-# if 0
- /* The following appears to work for 7xx systems running HP/UX */
- /* 9.xx Furthermore, it might result in much faster */
- /* collections than HEURISTIC2, which may involve scanning */
- /* segments that directly precede the stack. It is not the */
- /* default, since it may not work on older machine/OS */
- /* combinations. (Thanks to Raymond X.T. Nijssen for uncovering */
- /* this.) */
+# ifdef USE_HPUX_FIXED_STACKBOTTOM
+ /* The following appears to work for 7xx systems running HP/UX */
+ /* 9.xx. Furthermore, it might result in much faster */
+ /* collections than HEURISTIC2, which may involve scanning */
+ /* segments that directly precede the stack. It is not the */
+ /* default, since it may not work on older machine/OS */
+ /* combinations. (Thanks to Raymond X.T. Nijssen for uncovering */
+ /* this.) */
# define STACKBOTTOM ((ptr_t) 0x7b033000) /* from /etc/conf/h/param.h */
# else
- /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */
- /* to this. Note that the GC must be initialized before the */
- /* first putenv call. */
- extern char ** environ;
+ /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */
+ /* to this. Note that the GC must be initialized before the */
+ /* first putenv call. */
+ extern char ** environ;
# define STACKBOTTOM ((ptr_t)environ)
# endif
# define DYNAMIC_LOADING
@@ -1462,207 +1671,211 @@
# define DYNAMIC_LOADING
# define SEARCH_FOR_DATA_START
extern int _end[];
-# define DATAEND (&_end)
+# define DATAEND (ptr_t)(&_end)
# endif /* LINUX */
+# ifdef OPENBSD
+# define OS_TYPE "OPENBSD"
+# ifdef GC_OPENBSD_THREADS
+# define UTHREAD_SP_OFFSET 520
+# else
+# include <sys/param.h>
+# include <uvm/uvm_extern.h>
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# endif
+ extern int __data_start[];
+# define DATASTART ((ptr_t)__data_start)
+ extern char _end[];
+# define DATAEND ((ptr_t)(&_end))
+# define DYNAMIC_LOADING
+# endif
# endif /* HP_PA */
# ifdef ALPHA
# define MACH_TYPE "ALPHA"
# define ALIGNMENT 8
# define CPP_WORDSZ 64
-# ifndef LINUX
-# define USE_GENERIC_PUSH_REGS
- /* Gcc and probably the DEC/Compaq compiler spill pointers to preserved */
- /* fp registers in some cases when the target is a 21264. The assembly */
- /* code doesn't handle that yet, and version dependencies make that a */
- /* bit tricky. Do the easy thing for now. */
-# endif
# ifdef NETBSD
-# define OS_TYPE "NETBSD"
-# define HEURISTIC2
-# define DATASTART GC_data_start
-# define ELFCLASS32 32
-# define ELFCLASS64 64
-# define ELF_CLASS ELFCLASS64
+# define OS_TYPE "NETBSD"
+# define HEURISTIC2
+ extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
+# define ELFCLASS32 32
+# define ELFCLASS64 64
+# define ELF_CLASS ELFCLASS64
# define DYNAMIC_LOADING
# endif
# ifdef OPENBSD
-# define OS_TYPE "OPENBSD"
-# define HEURISTIC2
-# ifdef __ELF__ /* since OpenBSD/Alpha 2.9 */
-# define DATASTART GC_data_start
-# define ELFCLASS32 32
-# define ELFCLASS64 64
-# define ELF_CLASS ELFCLASS64
-# else /* ECOFF, until OpenBSD/Alpha 2.7 */
-# define DATASTART ((ptr_t) 0x140000000)
-# endif
+# define OS_TYPE "OPENBSD"
+# define ELF_CLASS ELFCLASS64
+# ifdef GC_OPENBSD_THREADS
+# define UTHREAD_SP_OFFSET 816
+# else
+# include <sys/param.h>
+# include <uvm/uvm_extern.h>
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# endif
+ extern int __data_start[];
+# define DATASTART ((ptr_t)__data_start)
+ extern char _end[];
+# define DATAEND ((ptr_t)(&_end))
+# define DYNAMIC_LOADING
# endif
# ifdef FREEBSD
-# define OS_TYPE "FREEBSD"
+# define OS_TYPE "FREEBSD"
/* MPROTECT_VDB is not yet supported at all on FreeBSD/alpha. */
-# define SIG_SUSPEND SIGUSR1
-# define SIG_THR_RESTART SIGUSR2
-# define FREEBSD_STACKBOTTOM
-# ifdef __ELF__
-# define DYNAMIC_LOADING
-# endif
+# define SIG_SUSPEND SIGUSR1
+# define SIG_THR_RESTART SIGUSR2
+ /* SIGTSTP and SIGCONT could be used alternatively. */
+# define FREEBSD_STACKBOTTOM
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+# endif
/* Handle unmapped hole alpha*-*-freebsd[45]* puts between etext and edata. */
- extern char etext[];
- extern char edata[];
- extern char end[];
-# define NEED_FIND_LIMIT
-# define DATASTART ((ptr_t)(&etext))
-# define DATAEND (GC_find_limit (DATASTART, TRUE))
-# define DATASTART2 ((ptr_t)(&edata))
-# define DATAEND2 ((ptr_t)(&end))
+ extern char etext[];
+ extern char edata[];
+ extern char end[];
+# define NEED_FIND_LIMIT
+# define DATASTART ((ptr_t)(&etext))
+ ptr_t GC_find_limit(ptr_t, GC_bool);
+# define DATAEND (GC_find_limit (DATASTART, TRUE))
+# define DATAEND_IS_FUNC
+# define DATASTART2 ((ptr_t)(&edata))
+# define DATAEND2 ((ptr_t)(&end))
# endif
# ifdef OSF1
-# define OS_TYPE "OSF1"
-# define DATASTART ((ptr_t) 0x140000000)
- extern int _end[];
-# define DATAEND ((ptr_t) &_end)
- extern char ** environ;
- /* round up from the value of environ to the nearest page boundary */
- /* Probably breaks if putenv is called before collector */
- /* initialization. */
-# define STACKBOTTOM ((ptr_t)(((word)(environ) | (getpagesize()-1))+1))
-/* # define HEURISTIC2 */
- /* Normally HEURISTIC2 is too conervative, since */
- /* the text segment immediately follows the stack. */
- /* Hence we give an upper pound. */
- /* This is currently unused, since we disabled HEURISTIC2 */
- extern int __start[];
-# define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1)))
-# ifndef GC_OSF1_THREADS
- /* Unresolved signal issues with threads. */
-# define MPROTECT_VDB
+# define OS_TYPE "OSF1"
+# define DATASTART ((ptr_t) 0x140000000)
+ extern int _end[];
+# define DATAEND ((ptr_t) &_end)
+ extern char ** environ;
+ /* round up from the value of environ to the nearest page boundary */
+ /* Probably breaks if putenv is called before collector */
+ /* initialization. */
+# define STACKBOTTOM ((ptr_t)(((word)(environ) | (getpagesize()-1))+1))
+/* # define HEURISTIC2 */
+ /* Normally HEURISTIC2 is too conservative, since */
+ /* the text segment immediately follows the stack. */
+ /* Hence we give an upper pound. */
+ /* This is currently unused, since we disabled HEURISTIC2 */
+ extern int __start[];
+# define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1)))
+# ifndef GC_OSF1_THREADS
+ /* Unresolved signal issues with threads. */
+# define MPROTECT_VDB
# endif
-# define DYNAMIC_LOADING
+# define DYNAMIC_LOADING
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
-# define STACKBOTTOM ((ptr_t) 0x120000000)
+# define LINUX_STACKBOTTOM
# ifdef __ELF__
-# define SEARCH_FOR_DATA_START
+# define SEARCH_FOR_DATA_START
# define DYNAMIC_LOADING
# else
# define DATASTART ((ptr_t) 0x140000000)
# endif
- extern int _end[];
-# define DATAEND (_end)
-# define MPROTECT_VDB
- /* Has only been superficially tested. May not */
- /* work on all versions. */
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
+# define MPROTECT_VDB
+ /* Has only been superficially tested. May not */
+ /* work on all versions. */
# endif
# endif
# ifdef IA64
# define MACH_TYPE "IA64"
-# define USE_GENERIC_PUSH_REGS
- /* We need to get preserved registers in addition to register */
- /* windows. That's easiest to do with setjmp. */
-# ifdef PARALLEL_MARK
-# define USE_MARK_BYTES
- /* Compare-and-exchange is too expensive to use for */
- /* setting mark bits. */
-# endif
# ifdef HPUX
-# ifdef _ILP32
-# define CPP_WORDSZ 32
-# define ALIGN_DOUBLE
- /* Requires 8 byte alignment for malloc */
-# define ALIGNMENT 4
+# ifdef _ILP32
+# define CPP_WORDSZ 32
+ /* Requires 8 byte alignment for malloc */
+# define ALIGNMENT 4
# else
-# ifndef _LP64
- ---> unknown ABI
+# ifndef _LP64
+# error --> unknown ABI
# endif
-# define CPP_WORDSZ 64
-# define ALIGN_DOUBLE
- /* Requires 16 byte alignment for malloc */
+# define CPP_WORDSZ 64
+ /* Requires 16 byte alignment for malloc */
# define ALIGNMENT 8
# endif
-# define OS_TYPE "HPUX"
+# define OS_TYPE "HPUX"
extern int __data_start[];
# define DATASTART ((ptr_t)(__data_start))
- /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */
- /* to this. Note that the GC must be initialized before the */
- /* first putenv call. */
- extern char ** environ;
+ /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */
+ /* to this. Note that the GC must be initialized before the */
+ /* first putenv call. */
+ extern char ** environ;
# define STACKBOTTOM ((ptr_t)environ)
# define HPUX_STACKBOTTOM
# define DYNAMIC_LOADING
# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE)
- /* The following was empirically determined, and is probably */
- /* not very robust. */
- /* Note that the backing store base seems to be at a nice */
- /* address minus one page. */
-# define BACKING_STORE_DISPLACEMENT 0x1000000
-# define BACKING_STORE_ALIGNMENT 0x1000
- extern ptr_t GC_register_stackbottom;
-# define BACKING_STORE_BASE GC_register_stackbottom
- /* Known to be wrong for recent HP/UX versions!!! */
+ /* The following was empirically determined, and is probably */
+ /* not very robust. */
+ /* Note that the backing store base seems to be at a nice */
+ /* address minus one page. */
+# define BACKING_STORE_DISPLACEMENT 0x1000000
+# define BACKING_STORE_ALIGNMENT 0x1000
+ extern ptr_t GC_register_stackbottom;
+# define BACKING_STORE_BASE GC_register_stackbottom
+ /* Known to be wrong for recent HP/UX versions!!! */
# endif
# ifdef LINUX
-# define CPP_WORDSZ 64
-# define ALIGN_DOUBLE
- /* Requires 16 byte alignment for malloc */
-# define ALIGNMENT 8
+# define CPP_WORDSZ 64
+# define ALIGNMENT 8
# define OS_TYPE "LINUX"
- /* The following works on NUE and older kernels: */
-/* # define STACKBOTTOM ((ptr_t) 0xa000000000000000l) */
- /* This does not work on NUE: */
+ /* The following works on NUE and older kernels: */
+/* # define STACKBOTTOM ((ptr_t) 0xa000000000000000l) */
+ /* This does not work on NUE: */
# define LINUX_STACKBOTTOM
- /* We also need the base address of the register stack */
- /* backing store. This is computed in */
- /* GC_linux_register_stack_base based on the following */
- /* constants: */
+ /* We also need the base address of the register stack */
+ /* backing store. This is computed in */
+ /* GC_linux_register_stack_base based on the following */
+ /* constants: */
# define BACKING_STORE_ALIGNMENT 0x100000
# define BACKING_STORE_DISPLACEMENT 0x80000000
- extern ptr_t GC_register_stackbottom;
-# define BACKING_STORE_BASE GC_register_stackbottom
-# define SEARCH_FOR_DATA_START
-# ifdef __GNUC__
+ extern ptr_t GC_register_stackbottom;
+# define BACKING_STORE_BASE GC_register_stackbottom
+# define SEARCH_FOR_DATA_START
+# ifdef __GNUC__
# define DYNAMIC_LOADING
-# else
- /* In the Intel compiler environment, we seem to end up with */
- /* statically linked executables and an undefined reference */
- /* to _DYNAMIC */
-# endif
-# define MPROTECT_VDB
- /* Requires Linux 2.3.47 or later. */
- extern int _end[];
-# define DATAEND (_end)
+# else
+ /* In the Intel compiler environment, we seem to end up with */
+ /* statically linked executables and an undefined reference */
+ /* to _DYNAMIC */
+# endif
+# define MPROTECT_VDB
+ /* Requires Linux 2.3.47 or later. */
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
# ifdef __GNUC__
-# ifndef __INTEL_COMPILER
-# define PREFETCH(x) \
- __asm__ (" lfetch [%0]": : "r"(x))
-# define PREFETCH_FOR_WRITE(x) \
- __asm__ (" lfetch.excl [%0]": : "r"(x))
-# define CLEAR_DOUBLE(x) \
- __asm__ (" stf.spill [%0]=f0": : "r"((void *)(x)))
-# else
+# ifndef __INTEL_COMPILER
+# define PREFETCH(x) \
+ __asm__ (" lfetch [%0]": : "r"(x))
+# define PREFETCH_FOR_WRITE(x) \
+ __asm__ (" lfetch.excl [%0]": : "r"(x))
+# define CLEAR_DOUBLE(x) \
+ __asm__ (" stf.spill [%0]=f0": : "r"((void *)(x)))
+# else
# include <ia64intrin.h>
-# define PREFETCH(x) \
- __lfetch(__lfhint_none, (x))
-# define PREFETCH_FOR_WRITE(x) \
- __lfetch(__lfhint_nta, (x))
-# define CLEAR_DOUBLE(x) \
- __stf_spill((void *)(x), 0)
-# endif // __INTEL_COMPILER
+# define PREFETCH(x) \
+ __lfetch(__lfhint_none, (x))
+# define PREFETCH_FOR_WRITE(x) \
+ __lfetch(__lfhint_nta, (x))
+# define CLEAR_DOUBLE(x) \
+ __stf_spill((void *)(x), 0)
+# endif /* __INTEL_COMPILER */
# endif
# endif
# ifdef MSWIN32
- /* FIXME: This is a very partial guess. There is no port, yet. */
+ /* FIXME: This is a very partial guess. There is no port, yet. */
# define OS_TYPE "MSWIN32"
- /* STACKBOTTOM and DATASTART are handled specially in */
- /* os_dep.c. */
+ /* STACKBOTTOM and DATASTART are handled specially in */
+ /* os_dep.c. */
# define DATAEND /* not needed */
# if defined(_WIN64)
# define CPP_WORDSZ 64
# else
-# define CPP_WORDSZ 32 /* Is this possible? */
+# define CPP_WORDSZ 32 /* Is this possible? */
# endif
# define ALIGNMENT 8
# endif
@@ -1671,48 +1884,49 @@
# ifdef M88K
# define MACH_TYPE "M88K"
# define ALIGNMENT 4
-# define ALIGN_DOUBLE
extern int etext[];
# ifdef CX_UX
-# define OS_TYPE "CX_UX"
+# define OS_TYPE "CX_UX"
# define DATASTART ((((word)etext + 0x3fffff) & ~0x3fffff) + 0x10000)
# endif
# ifdef DGUX
-# define OS_TYPE "DGUX"
- extern ptr_t GC_SysVGetDataStart();
-# define DATASTART GC_SysVGetDataStart(0x10000, etext)
+# define OS_TYPE "DGUX"
+ ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+# define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)etext)
+# define DATASTART_IS_FUNC
# endif
# define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */
# endif
# ifdef S370
- /* If this still works, and if anyone cares, this should probably */
- /* be moved to the S390 category. */
+ /* If this still works, and if anyone cares, this should probably */
+ /* be moved to the S390 category. */
# define MACH_TYPE "S370"
-# define ALIGNMENT 4 /* Required by hardware */
-# define USE_GENERIC_PUSH_REGS
+# define ALIGNMENT 4 /* Required by hardware */
# ifdef UTS4
# define OS_TYPE "UTS4"
extern int etext[];
- extern int _etext[];
- extern int _end[];
- extern ptr_t GC_SysVGetDataStart();
-# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
-# define DATAEND (_end)
-# define HEURISTIC2
+ extern int _etext[];
+ extern int _end[];
+ ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+# define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext)
+# define DATASTART_IS_FUNC
+# define DATAEND (ptr_t)(_end)
+# define HEURISTIC2
# endif
# endif
# ifdef S390
# define MACH_TYPE "S390"
-# define USE_GENERIC_PUSH_REGS
# ifndef __s390x__
# define ALIGNMENT 4
# define CPP_WORDSZ 32
# else
# define ALIGNMENT 8
# define CPP_WORDSZ 64
-# define HBLKSIZE 4096
+# ifndef HBLKSIZE
+# define HBLKSIZE 4096
+# endif
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
@@ -1721,19 +1935,12 @@
extern int __data_start[];
# define DATASTART ((ptr_t)(__data_start))
extern int _end[];
-# define DATAEND (_end)
+# define DATAEND (ptr_t)(_end)
# define CACHE_LINE_SIZE 256
# define GETPAGESIZE() 4096
# endif
# endif
-# if defined(PJ)
-# define ALIGNMENT 4
- extern int _etext[];
-# define DATASTART ((ptr_t)(_etext))
-# define HEURISTIC1
-# endif
-
# ifdef ARM32
# define CPP_WORDSZ 32
# define MACH_TYPE "ARM32"
@@ -1741,42 +1948,42 @@
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
-# ifdef __ELF__
+# ifdef __ELF__
+ extern ptr_t GC_data_start;
# define DATASTART GC_data_start
-# define DYNAMIC_LOADING
-# else
+# define DYNAMIC_LOADING
+# else
extern char etext[];
# define DATASTART ((ptr_t)(etext))
-# endif
-# define USE_GENERIC_PUSH_REGS
+# endif
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
-# define HEURISTIC1
+# define LINUX_STACKBOTTOM
# undef STACK_GRAN
# define STACK_GRAN 0x10000000
-# define USE_GENERIC_PUSH_REGS
# ifdef __ELF__
# define DYNAMIC_LOADING
-# include <features.h>
-# if defined(__GLIBC__) && __GLIBC__ >= 2
-# define SEARCH_FOR_DATA_START
-# else
- extern char **__environ;
+# include <features.h>
+# if defined(__GLIBC__) && __GLIBC__ >= 2 \
+ || defined(PLATFORM_ANDROID)
+# define SEARCH_FOR_DATA_START
+# else
+ extern char **__environ;
# define DATASTART ((ptr_t)(&__environ))
- /* hideous kludge: __environ is the first */
- /* word in crt0.o, and delimits the start */
- /* of the data segment, no matter which */
- /* ld options were passed through. */
- /* We could use _etext instead, but that */
- /* would include .rodata, which may */
- /* contain large read-only data tables */
- /* that we'd rather not scan. */
-# endif
- extern int _end[];
-# define DATAEND (_end)
-# else
- extern int etext[];
+ /* hideous kludge: __environ is the first */
+ /* word in crt0.o, and delimits the start */
+ /* of the data segment, no matter which */
+ /* ld options were passed through. */
+ /* We could use _etext instead, but that */
+ /* would include .rodata, which may */
+ /* contain large read-only data tables */
+ /* that we'd rather not scan. */
+# endif
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
+# else
+ extern int etext[];
# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
# endif
# endif
@@ -1784,18 +1991,68 @@
# define OS_TYPE "MSWINCE"
# define DATAEND /* not needed */
# endif
+# ifdef DARWIN
+ /* iPhone */
+# define OS_TYPE "DARWIN"
+# ifndef GC_DONT_REGISTER_MAIN_STATIC_DATA
+# define DYNAMIC_LOADING
+# endif
+# define DATASTART ((ptr_t) get_etext())
+# define DATAEND ((ptr_t) get_end())
+# define STACKBOTTOM ((ptr_t) 0x30000000)
+# ifndef USE_MMAP
+# define USE_MMAP
+# endif
+# define USE_MMAP_ANON
+# define MPROTECT_VDB
+# include <unistd.h>
+# define GETPAGESIZE() getpagesize()
+ /* FIXME: There seems to be some issues with trylock hanging on */
+ /* darwin. This should be looked into some more. */
+# define NO_PTHREAD_TRYLOCK
+# ifndef NO_DYLD_BIND_FULLY_IMAGE
+# define NO_DYLD_BIND_FULLY_IMAGE
+# endif
+# endif
+# ifdef OPENBSD
+# define ALIGNMENT 4
+# define OS_TYPE "OPENBSD"
+# ifdef GC_OPENBSD_THREADS
+# define UTHREAD_SP_OFFSET 176
+# else
+# include <sys/param.h>
+# include <uvm/uvm_extern.h>
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# endif
+ extern int __data_start[];
+# define DATASTART ((ptr_t)__data_start)
+ extern char _end[];
+# define DATAEND ((ptr_t)(&_end))
+# define DYNAMIC_LOADING
+# endif
# ifdef NOSYS
/* __data_start is usually defined in the target linker script. */
extern int __data_start[];
# define DATASTART (ptr_t)(__data_start)
-# define USE_GENERIC_PUSH_REGS
/* __stack_base__ is set in newlib/libc/sys/arm/crt0.S */
extern void *__stack_base__;
# define STACKBOTTOM ((ptr_t) (__stack_base__))
# endif
#endif
-# ifdef SH
+# ifdef CRIS
+# define MACH_TYPE "CRIS"
+# define CPP_WORDSZ 32
+# define ALIGNMENT 1
+# define OS_TYPE "LINUX"
+# define DYNAMIC_LOADING
+# define LINUX_STACKBOTTOM
+# define SEARCH_FOR_DATA_START
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
+# endif
+
+# if defined(SH) && !defined(SH4)
# define MACH_TYPE "SH"
# define ALIGNMENT 4
# ifdef MSWINCE
@@ -1804,15 +2061,36 @@
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
-# define STACKBOTTOM ((ptr_t) 0x7c000000)
-# define USE_GENERIC_PUSH_REGS
+# define LINUX_STACKBOTTOM
# define DYNAMIC_LOADING
# define SEARCH_FOR_DATA_START
extern int _end[];
-# define DATAEND (_end)
+# define DATAEND (ptr_t)(_end)
+# endif
+# ifdef NETBSD
+# define OS_TYPE "NETBSD"
+# define HEURISTIC2
+ extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
+# endif
+# ifdef OPENBSD
+# define OS_TYPE "OPENBSD"
+# ifdef GC_OPENBSD_THREADS
+# define UTHREAD_SP_OFFSET 332
+# else
+# include <sys/param.h>
+# include <uvm/uvm_extern.h>
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# endif
+ extern int __data_start[];
+# define DATASTART ((ptr_t)__data_start)
+ extern char _end[];
+# define DATAEND ((ptr_t)(&_end))
+# define DYNAMIC_LOADING
# endif
# endif
-
+
# ifdef SH4
# define MACH_TYPE "SH4"
# define OS_TYPE "MSWINCE"
@@ -1820,384 +2098,772 @@
# define DATAEND /* not needed */
# endif
+# ifdef AVR32
+# define MACH_TYPE "AVR32"
+# define CPP_WORDSZ 32
+# define ALIGNMENT 4
+# define OS_TYPE "LINUX"
+# define DYNAMIC_LOADING
+# define LINUX_STACKBOTTOM
+# define SEARCH_FOR_DATA_START
+ extern int _end[];
+# define DATAEND (_end)
+# endif
+
+# ifdef M32R
+# define CPP_WORDSZ 32
+# define MACH_TYPE "M32R"
+# define ALIGNMENT 4
+# ifdef LINUX
+# define OS_TYPE "LINUX"
+# define LINUX_STACKBOTTOM
+# undef STACK_GRAN
+# define STACK_GRAN 0x10000000
+# define DYNAMIC_LOADING
+# define SEARCH_FOR_DATA_START
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
+# endif
+# endif
+
# ifdef X86_64
# define MACH_TYPE "X86_64"
-# define ALIGNMENT 8
-# define CPP_WORDSZ 64
+# ifdef __ILP32__
+# define ALIGNMENT 4
+# define CPP_WORDSZ 32
+# else
+# define ALIGNMENT 8
+# define CPP_WORDSZ 64
+# endif
# ifndef HBLKSIZE
# define HBLKSIZE 4096
# endif
# define CACHE_LINE_SIZE 64
-# define USE_GENERIC_PUSH_REGS
+# ifdef OPENBSD
+# define OS_TYPE "OPENBSD"
+# define ELF_CLASS ELFCLASS64
+# ifdef GC_OPENBSD_THREADS
+# define UTHREAD_SP_OFFSET 400
+# else
+# include <sys/param.h>
+# include <uvm/uvm_extern.h>
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# endif
+ extern int __data_start[];
+# define DATASTART ((ptr_t)__data_start)
+ extern char _end[];
+# define DATAEND ((ptr_t)(&_end))
+# define DYNAMIC_LOADING
+# endif
# ifdef LINUX
-# define OS_TYPE "LINUX"
+# define OS_TYPE "LINUX"
# define LINUX_STACKBOTTOM
# if !defined(GC_LINUX_THREADS) || !defined(REDIRECT_MALLOC)
-# define MPROTECT_VDB
-# else
- /* We seem to get random errors in incremental mode, */
- /* possibly because Linux threads is itself a malloc client */
- /* and can't deal with the signals. */
-# endif
+# define MPROTECT_VDB
+# else
+ /* We seem to get random errors in incremental mode, */
+ /* possibly because Linux threads is itself a malloc client */
+ /* and can't deal with the signals. */
+# endif
# ifdef __ELF__
# define DYNAMIC_LOADING
-# ifdef UNDEFINED /* includes ro data */
- extern int _etext[];
+# ifdef UNDEFINED /* includes ro data */
+ extern int _etext[];
# define DATASTART ((ptr_t)((((word) (_etext)) + 0xfff) & ~0xfff))
-# endif
-# include <features.h>
-# define SEARCH_FOR_DATA_START
- extern int _end[];
-# define DATAEND (_end)
-# else
- extern int etext[];
+# endif
+# include <features.h>
+# define SEARCH_FOR_DATA_START
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
+# else
+ extern int etext[];
# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff))
# endif
-# if defined(__GNUC__) && __GNUC >= 3
-# define PREFETCH(x) __builtin_prefetch((x), 0, 0)
-# define PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1)
-# endif
+# if defined(__GNUC__) && __GNUC__ >= 3
+# define PREFETCH(x) __builtin_prefetch((x), 0, 0)
+# define PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1)
+# endif
+# if defined(__GLIBC__)
+ /* At present, there's a bug in GLibc getcontext() on */
+ /* Linux/x64 (it clears FPU exception mask). We define this */
+ /* macro to workaround it. */
+ /* FIXME: This seems to be fixed in GLibc v2.14. */
+# define GETCONTEXT_FPU_EXCMASK_BUG
+# endif
+# endif
+# ifdef DARWIN
+# define OS_TYPE "DARWIN"
+# define DARWIN_DONT_PARSE_STACK
+# define DYNAMIC_LOADING
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used. */
+ /* These aren't used when dyld support is enabled (it is by default) */
+# define DATASTART ((ptr_t) get_etext())
+# define DATAEND ((ptr_t) get_end())
+# define STACKBOTTOM ((ptr_t) 0x7fff5fc00000)
+# ifndef USE_MMAP
+# define USE_MMAP
+# endif
+# define USE_MMAP_ANON
+# define MPROTECT_VDB
+# include <unistd.h>
+# define GETPAGESIZE() getpagesize()
+ /* There seems to be some issues with trylock hanging on darwin. */
+ /* This should be looked into some more. */
+# define NO_PTHREAD_TRYLOCK
+# endif
+# ifdef FREEBSD
+# define OS_TYPE "FREEBSD"
+# ifndef GC_FREEBSD_THREADS
+# define MPROTECT_VDB
+# endif
+# ifdef __GLIBC__
+# define SIG_SUSPEND (32+6)
+# define SIG_THR_RESTART (32+5)
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
+# else
+# define SIG_SUSPEND SIGUSR1
+# define SIG_THR_RESTART SIGUSR2
+ /* SIGTSTP and SIGCONT could be used alternatively. */
+# endif
+# define FREEBSD_STACKBOTTOM
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+# endif
+ extern char etext[];
+ ptr_t GC_FreeBSDGetDataStart(size_t, ptr_t);
+# define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
+# define DATASTART_IS_FUNC
# endif
# ifdef NETBSD
-# define OS_TYPE "NETBSD"
-# ifdef __ELF__
-# define DYNAMIC_LOADING
-# endif
-# define HEURISTIC2
- extern char etext[];
-# define SEARCH_FOR_DATA_START
+# define OS_TYPE "NETBSD"
+# define HEURISTIC2
+# ifdef __ELF__
+ extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
+# else
+# define SEARCH_FOR_DATA_START
+# endif
+# endif
+# ifdef SOLARIS
+# define OS_TYPE "SOLARIS"
+# define ELF_CLASS ELFCLASS64
+ extern int _etext[], _end[];
+ ptr_t GC_SysVGetDataStart(size_t, ptr_t);
+# define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext)
+# define DATASTART_IS_FUNC
+# define DATAEND (ptr_t)(_end)
+/* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7, */
+/* but reportedly breaks under 2.8. It appears that the stack */
+/* base is a property of the executable, so this should not break */
+/* old executables. */
+/* HEURISTIC2 probably works, but this appears to be preferable. */
+/* Apparently USRSTACK is defined to be USERLIMIT, but in some */
+/* installations that's undefined. We work around this with a */
+/* gross hack: */
+# include <sys/vmparam.h>
+# ifdef USERLIMIT
+ /* This should work everywhere, but doesn't. */
+# define STACKBOTTOM ((ptr_t) USRSTACK)
+# else
+# define HEURISTIC2
+# endif
+/* At least in Solaris 2.5, PROC_VDB gives wrong values for dirty bits. */
+/* It appears to be fixed in 2.8 and 2.9. */
+# ifdef SOLARIS25_PROC_VDB_BUG_FIXED
+# define PROC_VDB
+# endif
+# ifndef GC_THREADS
+# define MPROTECT_VDB
+# endif
+# define DYNAMIC_LOADING
+# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
+# define USE_MMAP
+ /* Otherwise we now use calloc. Mmap may result in the */
+ /* heap interleaved with thread stacks, which can result in */
+ /* excessive blacklisting. Sbrk is unusable since it */
+ /* doesn't interact correctly with the system malloc. */
+# endif
+# ifdef USE_MMAP
+# define HEAP_START (ptr_t)0x40000000
+# else
+# define HEAP_START DATAEND
+# endif
+# endif
+# ifdef MSWIN32
+# define OS_TYPE "MSWIN32"
+ /* STACKBOTTOM and DATASTART are handled specially in */
+ /* os_dep.c. */
+# if !defined(__GNUC__) || defined(__INTEL_COMPILER)
+ /* GCC does not currently support SetUnhandledExceptionFilter */
+ /* (does not generate SEH unwinding information) on x64. */
+# define MPROTECT_VDB
+# endif
+# define GWW_VDB
+# define DATAEND /* not needed */
+# endif
+# endif /* X86_64 */
+
+# ifdef HEXAGON
+# define CPP_WORDSZ 32
+# define MACH_TYPE "HEXAGON"
+# define ALIGNMENT 4
+# ifdef LINUX
+# define OS_TYPE "LINUX"
+# define LINUX_STACKBOTTOM
+# define MPROTECT_VDB
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+# include <features.h>
+# if defined(__GLIBC__) && __GLIBC__ >= 2
+# define SEARCH_FOR_DATA_START
+# else
+# error --> unknown Hexagon libc configuration
+# endif
+ extern int _end[];
+# define DATAEND (ptr_t)(_end)
+# else
+# error --> bad Hexagon Linux configuration
+# endif
+# else
+# error --> unknown Hexagon OS configuration
# 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. */
+ /* The kernel may do a somewhat better job merging mappings etc. */
+ /* with anonymous mappings. */
# define USE_MMAP_ANON
#endif
-#if defined(LINUX) && defined(REDIRECT_MALLOC)
- /* Rld appears to allocate some memory with its own allocator, and */
- /* some through malloc, which might be redirected. To make this */
- /* work with collectable memory, we have to scan memory allocated */
- /* by rld's internal malloc. */
+#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
+ && !defined(USE_PROC_FOR_LIBRARIES)
+ /* Nptl allocates thread stacks with mmap, which is fine. But it */
+ /* keeps a cache of thread stacks. Thread stacks contain the */
+ /* thread control blocks. These in turn contain a pointer to */
+ /* (sizeof (void *) from the beginning of) the dtv for thread-local */
+ /* storage, which is calloc allocated. If we don't scan the cached */
+ /* thread stacks, we appear to lose the dtv. This tends to */
+ /* result in something that looks like a bogus dtv count, which */
+ /* tends to result in a memset call on a block that is way too */
+ /* large. Sometimes we're lucky and the process just dies ... */
+ /* There seems to be a similar issue with some other memory */
+ /* allocated by the dynamic loader. */
+ /* This 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. */
+ /* In spite of the fact that it is gross and disgusting. */
+ /* 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
-# define STACK_GROWS_DOWN
-# endif
-# ifndef CPP_WORDSZ
-# define CPP_WORDSZ 32
-# endif
+#ifndef STACK_GROWS_UP
+# define STACK_GROWS_DOWN
+#endif
-# ifndef OS_TYPE
-# define OS_TYPE ""
-# endif
+#ifndef CPP_WORDSZ
+# define CPP_WORDSZ 32
+#endif
-# ifndef DATAEND
- extern int end[];
-# define DATAEND (end)
-# endif
+#ifndef OS_TYPE
+# define OS_TYPE ""
+#endif
-# if defined(SVR4) && !defined(GETPAGESIZE)
-# include <unistd.h>
-# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
-# endif
+#ifndef DATAEND
+ extern int end[];
+# define DATAEND (ptr_t)(end)
+#endif
-# ifndef GETPAGESIZE
-# if defined(SUNOS5) || defined(IRIX5)
-# include <unistd.h>
-# endif
-# define GETPAGESIZE() getpagesize()
-# endif
+#if defined(PLATFORM_ANDROID) && !defined(THREADS) \
+ && !defined(USE_GET_STACKBASE_FOR_MAIN)
+ /* Always use pthread_attr_getstack on Android ("-lpthread" option is */
+ /* not needed to be specified manually) since GC_linux_main_stack_base */
+ /* causes app crash if invoked inside Dalvik VM. */
+# define USE_GET_STACKBASE_FOR_MAIN
+#endif
-# if defined(SUNOS5) || defined(DRSNX) || defined(UTS4)
- /* OS has SVR4 generic features. Probably others also qualify. */
-# define SVR4
-# endif
+#if (defined(SVR4) || defined(PLATFORM_ANDROID)) && !defined(GETPAGESIZE)
+# include <unistd.h>
+# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
+#endif
-# if defined(SUNOS5) || defined(DRSNX)
- /* OS has SUNOS5 style semi-undocumented interface to dynamic */
- /* loader. */
-# define SUNOS5DL
- /* OS has SUNOS5 style signal handlers. */
-# define SUNOS5SIGS
+#ifndef GETPAGESIZE
+# if defined(SOLARIS) || defined(IRIX5) || defined(LINUX) \
+ || defined(NETBSD) || defined(FREEBSD) || defined(HPUX)
+# include <unistd.h>
# endif
+# define GETPAGESIZE() getpagesize()
+#endif
-# if defined(HPUX)
-# define SUNOS5SIGS
-# endif
+#if defined(SOLARIS) || defined(DRSNX) || defined(UTS4)
+ /* OS has SVR4 generic features. */
+ /* Probably others also qualify. */
+# define SVR4
+#endif
-# if defined(FREEBSD) && (__FreeBSD__ >= 4)
-# define SUNOS5SIGS
-# endif
+#if defined(SOLARIS) || defined(DRSNX)
+ /* OS has SOLARIS style semi-undocumented interface */
+ /* to dynamic loader. */
+# define SOLARISDL
+ /* OS has SOLARIS style signal handlers. */
+# define SUNOS5SIGS
+#endif
-# if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \
- || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
- || defined(DGUX) || defined(BSD) || defined(SUNOS4) \
- || defined(_AIX) || defined(DARWIN) || defined(OSF1)
-# define UNIX_LIKE /* Basic Unix-like system calls work. */
-# endif
+#if defined(HPUX)
+# define SUNOS5SIGS
+#endif
-# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
- -> bad word size
-# endif
+#if defined(FREEBSD) && (defined(__DragonFly__) || __FreeBSD__ >= 4 \
+ || (__FreeBSD_kernel__ >= 4))
+# define SUNOS5SIGS
+#endif
-# ifdef PCR
-# undef DYNAMIC_LOADING
-# undef STACKBOTTOM
-# undef HEURISTIC1
-# undef HEURISTIC2
-# undef PROC_VDB
-# undef MPROTECT_VDB
-# define PCR_VDB
-# endif
+#if !defined(GC_EXPLICIT_SIGNALS_UNBLOCK) && defined(SUNOS5SIGS) \
+ && !defined(GC_NO_PTHREAD_SIGMASK)
+# define GC_EXPLICIT_SIGNALS_UNBLOCK
+#endif
-# ifdef SRC_M3
- /* Postponed for now. */
-# undef PROC_VDB
-# undef MPROTECT_VDB
-# endif
+#ifdef GC_NETBSD_THREADS
+# define SIGRTMIN 33
+# define SIGRTMAX 63
+#endif
-# ifdef SMALL_CONFIG
- /* Presumably not worth the space it takes. */
-# undef PROC_VDB
-# undef MPROTECT_VDB
-# endif
+#if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \
+ || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
+ || defined(DGUX) || defined(BSD) || defined(HURD) \
+ || defined(AIX) || defined(DARWIN) || defined(OSF1)
+# define UNIX_LIKE /* Basic Unix-like system calls work. */
+#endif
-# ifdef USE_MUNMAP
-# undef MPROTECT_VDB /* Can't deal with address space holes. */
-# endif
+#if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
+# error --> bad word size
+#endif
-# ifdef PARALLEL_MARK
-# undef MPROTECT_VDB /* For now. */
-# endif
+#ifndef ALIGNMENT
+# error --> undefined ALIGNMENT
+#endif
-# if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB)
-# define DEFAULT_VDB
-# endif
+#ifdef PCR
+# undef DYNAMIC_LOADING
+# undef STACKBOTTOM
+# undef HEURISTIC1
+# undef HEURISTIC2
+# undef PROC_VDB
+# undef MPROTECT_VDB
+# define PCR_VDB
+#endif
-# ifndef PREFETCH
-# define PREFETCH(x)
-# define NO_PREFETCH
-# endif
+#if !defined(STACKBOTTOM) && (defined(ECOS) || defined(NOSYS))
+# error --> undefined STACKBOTTOM
+#endif
-# ifndef PREFETCH_FOR_WRITE
-# define PREFETCH_FOR_WRITE(x)
-# define NO_PREFETCH_FOR_WRITE
-# endif
+#ifdef IGNORE_DYNAMIC_LOADING
+# undef DYNAMIC_LOADING
+#endif
-# ifndef CACHE_LINE_SIZE
-# define CACHE_LINE_SIZE 32 /* Wild guess */
-# endif
+#if defined(SMALL_CONFIG) && !defined(GC_DISABLE_INCREMENTAL)
+ /* Presumably not worth the space it takes. */
+# define GC_DISABLE_INCREMENTAL
+#endif
-# ifdef LINUX
-# define REGISTER_LIBRARIES_EARLY
- /* We sometimes use dl_iterate_phdr, which may acquire an internal */
- /* lock. This isn't safe after the world has stopped. So we must */
- /* call GC_register_dynamic_libraries before stopping the world. */
- /* For performance reasons, this may be beneficial on other */
- /* platforms as well, though it should be avoided in win32. */
-# endif /* LINUX */
+#if (defined(MSWIN32) || defined(MSWINCE)) && !defined(USE_WINALLOC)
+ /* USE_WINALLOC is only an option for Cygwin. */
+# define USE_WINALLOC
+#endif
-# if defined(SEARCH_FOR_DATA_START)
- extern ptr_t GC_data_start;
-# define DATASTART GC_data_start
-# endif
+#ifdef USE_WINALLOC
+# undef USE_MMAP
+#endif
-# ifndef CLEAR_DOUBLE
-# define CLEAR_DOUBLE(x) \
- ((word*)x)[0] = 0; \
- ((word*)x)[1] = 0;
-# endif /* CLEAR_DOUBLE */
+#if defined(GC_DISABLE_INCREMENTAL) || defined(MANUAL_VDB)
+# undef GWW_VDB
+# undef MPROTECT_VDB
+# undef PCR_VDB
+# undef PROC_VDB
+#endif
- /* Internally we use GC_SOLARIS_THREADS to test for either old or pthreads. */
-# if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS)
-# define GC_SOLARIS_THREADS
-# endif
+#ifdef GC_DISABLE_INCREMENTAL
+# undef CHECKSUMS
+#endif
-# if defined(GC_IRIX_THREADS) && !defined(IRIX5)
- --> inconsistent configuration
-# endif
-# if defined(GC_LINUX_THREADS) && !defined(LINUX)
- --> inconsistent configuration
-# endif
-# if defined(GC_SOLARIS_THREADS) && !defined(SUNOS5)
- --> inconsistent configuration
-# endif
-# if defined(GC_HPUX_THREADS) && !defined(HPUX)
- --> inconsistent configuration
-# endif
-# if defined(GC_AIX_THREADS) && !defined(_AIX)
- --> inconsistent configuration
-# endif
-# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32)
- --> inconsistent configuration
-# endif
+#ifdef USE_GLOBAL_ALLOC
+ /* Cannot pass MEM_WRITE_WATCH to GlobalAlloc(). */
+# undef GWW_VDB
+#endif
-# if defined(PCR) || defined(SRC_M3) || \
- defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) || \
- defined(GC_PTHREADS)
-# define THREADS
-# endif
+#ifdef USE_MUNMAP
+ /* FIXME: Remove this undef if possible. */
+# undef MPROTECT_VDB /* Can't deal with address space holes. */
+#endif
+
+/* PARALLEL_MARK does not cause undef MPROTECT_VDB any longer. */
+
+#if defined(MPROTECT_VDB) && defined(GC_PREFER_MPROTECT_VDB)
+ /* Choose MPROTECT_VDB manually (if multiple strategies available). */
+# undef PCR_VDB
+# undef PROC_VDB
+ /* #undef GWW_VDB - handled in os_dep.c */
+#endif
+
+#ifdef PROC_VDB
+ /* Multi-VDB mode is not implemented. */
+# undef MPROTECT_VDB
+#endif
+
+#if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB) \
+ && !defined(GWW_VDB) && !defined(MANUAL_VDB) \
+ && !defined(GC_DISABLE_INCREMENTAL)
+# define DEFAULT_VDB
+#endif
-# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(DARWIN) \
- || defined(LINT) || defined(MSWINCE) || defined(ARM32) \
- || (defined(I386) && defined(__LCC__))
- /* Use setjmp based hack to mark from callee-save registers. */
- /* The define should move to the individual platform */
- /* descriptions. */
-# define USE_GENERIC_PUSH_REGS
+#if ((defined(UNIX_LIKE) && (defined(DARWIN) || defined(HURD) \
+ || defined(OPENBSD) || defined(ARM32) \
+ || defined(MIPS) || defined(AVR32))) \
+ || (defined(LINUX) && (defined(SPARC) || defined(M68K))) \
+ || ((defined(RTEMS) || defined(PLATFORM_ANDROID)) && defined(I386))) \
+ && !defined(NO_GETCONTEXT)
+# define NO_GETCONTEXT
+#endif
+
+#ifndef PREFETCH
+# define PREFETCH(x)
+# define NO_PREFETCH
+#endif
+
+#ifndef PREFETCH_FOR_WRITE
+# define PREFETCH_FOR_WRITE(x)
+# define NO_PREFETCH_FOR_WRITE
+#endif
+
+#ifndef CACHE_LINE_SIZE
+# define CACHE_LINE_SIZE 32 /* Wild guess */
+#endif
+
+#ifndef STATIC
+# ifndef NO_DEBUGGING
+# define STATIC /* ignore to aid profiling and possibly debugging */
+# else
+# define STATIC static
# endif
+#endif
+
+#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) \
+ || !defined(SMALL_CONFIG))
+# define NEED_PROC_MAPS
+#endif
+
+#if defined(LINUX) || defined(HURD) || defined(__GLIBC__)
+# define REGISTER_LIBRARIES_EARLY
+ /* We sometimes use dl_iterate_phdr, which may acquire an internal */
+ /* lock. This isn't safe after the world has stopped. So we must */
+ /* call GC_register_dynamic_libraries before stopping the world. */
+ /* For performance reasons, this may be beneficial on other */
+ /* platforms as well, though it should be avoided in win32. */
+#endif /* LINUX */
+
+#if defined(SEARCH_FOR_DATA_START)
+ extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
+#endif
-# if defined(MSWINCE)
-# define NO_GETENV
+#ifndef CLEAR_DOUBLE
+# define CLEAR_DOUBLE(x) (((word*)(x))[0] = 0, ((word*)(x))[1] = 0)
+#endif
+
+#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
+ && !defined(INCLUDE_LINUX_THREAD_DESCR)
+ /* Will not work, since libc and the dynamic loader use thread */
+ /* locals, sometimes as the only reference. */
+# define INCLUDE_LINUX_THREAD_DESCR
+#endif
+
+#if defined(GC_IRIX_THREADS) && !defined(IRIX5)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_LINUX_THREADS) && !defined(LINUX) && !defined(NACL)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_NETBSD_THREADS) && !defined(NETBSD)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_HPUX_THREADS) && !defined(HPUX)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_AIX_THREADS) && !defined(_AIX)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_GNU_THREADS) && !defined(HURD)
+# error --> inconsistent configuration
+#endif
+#if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32) \
+ && !defined(MSWINCE)
+# error --> inconsistent configuration
+#endif
+
+#if defined(PCR) || defined(GC_WIN32_THREADS) || defined(GC_PTHREADS) \
+ || defined(SN_TARGET_PS3)
+# define THREADS
+#endif
+
+#if defined(PARALLEL_MARK) && !defined(THREADS)
+# error "invalid config - PARALLEL_MARK requires GC_THREADS"
+#endif
+
+#if defined(UNIX_LIKE) && defined(THREADS) && !defined(NO_CANCEL_SAFE) \
+ && !defined(PLATFORM_ANDROID)
+ /* Make the code cancellation-safe. This basically means that we */
+ /* ensure that cancellation requests are ignored while we are in */
+ /* the collector. This applies only to Posix deferred cancellation; */
+ /* we don't handle Posix asynchronous cancellation. */
+ /* Note that this only works if pthread_setcancelstate is */
+ /* async-signal-safe, at least in the absence of asynchronous */
+ /* cancellation. This appears to be true for the glibc version, */
+ /* though it is not documented. Without that assumption, there */
+ /* seems to be no way to safely wait in a signal handler, which */
+ /* we need to do for thread suspension. */
+ /* Also note that little other code appears to be cancellation-safe. */
+ /* Hence it may make sense to turn this off for performance. */
+# define CANCEL_SAFE
+#endif
+
+#ifdef CANCEL_SAFE
+# define IF_CANCEL(x) x
+#else
+# define IF_CANCEL(x) /* empty */
+#endif
+
+#if !defined(CAN_HANDLE_FORK) && !defined(NO_HANDLE_FORK) \
+ && !defined(HAVE_NO_FORK) \
+ && ((defined(GC_PTHREADS) && !defined(NACL) \
+ && !defined(GC_WIN32_PTHREADS) && !defined(USE_WINALLOC)) \
+ || (defined(DARWIN) && defined(MPROTECT_VDB)) || defined(HANDLE_FORK))
+ /* Attempts (where supported and requested) to make GC_malloc work in */
+ /* a child process fork'ed from a multi-threaded parent. */
+# define CAN_HANDLE_FORK
+#endif
+
+#if defined(CAN_HANDLE_FORK) && !defined(CAN_CALL_ATFORK) \
+ && !defined(HURD) && !defined(PLATFORM_ANDROID)
+ /* Have working pthread_atfork(). */
+# define CAN_CALL_ATFORK
+#endif
+
+#if !defined(CAN_HANDLE_FORK) && !defined(HAVE_NO_FORK) \
+ && (defined(MSWIN32) || defined(MSWINCE) || defined(DOS4GW) \
+ || defined(OS2) || defined(SYMBIAN) /* and probably others ... */)
+# define HAVE_NO_FORK
+#endif
+
+#if !defined(USE_MARK_BITS) && !defined(USE_MARK_BYTES) \
+ && defined(PARALLEL_MARK)
+ /* Minimize compare-and-swap usage. */
+# define USE_MARK_BYTES
+#endif
+
+#if defined(MSWINCE) && !defined(__CEGCC__) && !defined(NO_GETENV)
+# define NO_GETENV
+#endif
+
+#if (defined(NO_GETENV) || defined(MSWINCE)) && !defined(NO_GETENV_WIN32)
+# define NO_GETENV_WIN32
+#endif
+
+#ifndef STRTOULL
+# if defined(_WIN64) && !defined(__GNUC__)
+# define STRTOULL _strtoui64
+# elif defined(_LLP64) || defined(__LLP64__) || defined(_WIN64)
+# define STRTOULL strtoull
+# else
+ /* strtoul() fits since sizeof(long) >= sizeof(word). */
+# define STRTOULL strtoul
# endif
+#endif /* !STRTOULL */
-# if defined(SPARC)
-# define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */
- /* include assembly code to do it well. */
+#ifndef GC_WORD_C
+# if defined(_WIN64) && !defined(__GNUC__)
+# define GC_WORD_C(val) val##ui64
+# elif defined(_LLP64) || defined(__LLP64__) || defined(_WIN64)
+# define GC_WORD_C(val) val##ULL
+# else
+# define GC_WORD_C(val) ((word)val##UL)
# endif
+#endif /* !GC_WORD_C */
- /* Can we save call chain in objects for debugging? */
- /* SET NFRAMES (# of saved frames) and NARGS (#of args for each */
- /* frame) to reasonable values for the platform. */
- /* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified */
- /* at build time, though we feel free to adjust it slightly. */
- /* Define NEED_CALLINFO if we either save the call stack or */
- /* GC_ADD_CALLER is defined. */
- /* GC_CAN_SAVE_CALL_STACKS is set in gc.h. */
+#if defined(SPARC)
+# define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */
+ /* include assembly code to do it well. */
+#endif
+/* Can we save call chain in objects for debugging? */
+/* SET NFRAMES (# of saved frames) and NARGS (#of args for each */
+/* frame) to reasonable values for the platform. */
+/* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified */
+/* at build time, though we feel free to adjust it slightly. */
+/* Define NEED_CALLINFO if we either save the call stack or */
+/* GC_ADD_CALLER is defined. */
+/* GC_CAN_SAVE_CALL_STACKS is set in gc.h. */
#if defined(SPARC)
# define CAN_SAVE_CALL_ARGS
#endif
-#if (defined(I386) || defined(X86_64)) && defined(LINUX)
- /* SAVE_CALL_CHAIN is supported if the code is compiled to save */
- /* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
+#if (defined(I386) || defined(X86_64)) \
+ && (defined(LINUX) || defined(__GLIBC__))
+ /* SAVE_CALL_CHAIN is supported if the code is compiled to save */
+ /* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
# define CAN_SAVE_CALL_ARGS
#endif
-# if defined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \
- && defined(GC_CAN_SAVE_CALL_STACKS)
-# define SAVE_CALL_CHAIN
-# endif
-# ifdef SAVE_CALL_CHAIN
-# if defined(SAVE_CALL_NARGS) && defined(CAN_SAVE_CALL_ARGS)
-# define NARGS SAVE_CALL_NARGS
-# else
-# define NARGS 0 /* Number of arguments to save for each call. */
-# endif
-# endif
-# ifdef SAVE_CALL_CHAIN
-# ifndef SAVE_CALL_COUNT
-# define NFRAMES 6 /* Number of frames to save. Even for */
- /* alignment reasons. */
-# else
-# define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1)
-# endif
-# define NEED_CALLINFO
-# endif /* SAVE_CALL_CHAIN */
-# ifdef GC_ADD_CALLER
-# define NFRAMES 1
-# define NARGS 0
-# define NEED_CALLINFO
+#if defined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \
+ && defined(GC_CAN_SAVE_CALL_STACKS)
+# define SAVE_CALL_CHAIN
+#endif
+#ifdef SAVE_CALL_CHAIN
+# if defined(SAVE_CALL_NARGS) && defined(CAN_SAVE_CALL_ARGS)
+# define NARGS SAVE_CALL_NARGS
+# else
+# define NARGS 0 /* Number of arguments to save for each call. */
# endif
+#endif
+#ifdef SAVE_CALL_CHAIN
+# ifndef SAVE_CALL_COUNT
+# define NFRAMES 6 /* Number of frames to save. Even for */
+ /* alignment reasons. */
+# else
+# define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1)
+# endif
+# define NEED_CALLINFO
+#endif /* SAVE_CALL_CHAIN */
+#ifdef GC_ADD_CALLER
+# define NFRAMES 1
+# define NARGS 0
+# define NEED_CALLINFO
+#endif
-# if defined(MAKE_BACK_GRAPH) && !defined(DBG_HDRS_ALL)
-# define DBG_HDRS_ALL
-# endif
+#if defined(MAKE_BACK_GRAPH) && !defined(DBG_HDRS_ALL)
+# define DBG_HDRS_ALL
+#endif
-# if defined(POINTER_MASK) && !defined(POINTER_SHIFT)
-# define POINTER_SHIFT 0
-# endif
+#if defined(POINTER_MASK) && !defined(POINTER_SHIFT)
+# define POINTER_SHIFT 0
+#endif
-# if defined(POINTER_SHIFT) && !defined(POINTER_MASK)
-# define POINTER_MASK ((GC_word)(-1))
-# endif
+#if defined(POINTER_SHIFT) && !defined(POINTER_MASK)
+# define POINTER_MASK ((GC_word)(-1))
+#endif
-# if !defined(FIXUP_POINTER) && defined(POINTER_MASK)
-# define FIXUP_POINTER(p) (p) = ((p) & (POINTER_MASK) << POINTER_SHIFT)
-# endif
+#if !defined(FIXUP_POINTER) && defined(POINTER_MASK)
+# define FIXUP_POINTER(p) (p = ((p) & POINTER_MASK) << POINTER_SHIFT)
+#endif
-# if defined(FIXUP_POINTER)
-# define NEED_FIXUP_POINTER 1
-# else
-# define NEED_FIXUP_POINTER 0
-# define FIXUP_POINTER(p)
-# endif
+#if defined(FIXUP_POINTER)
+# define NEED_FIXUP_POINTER 1
+#else
+# define NEED_FIXUP_POINTER 0
+# define FIXUP_POINTER(p)
+#endif
+
+#if !defined(MARK_BIT_PER_GRANULE) && !defined(MARK_BIT_PER_OBJ)
+# define MARK_BIT_PER_GRANULE /* Usually faster */
+#endif
+
+/* Some static sanity tests. */
+#if defined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ)
+# error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ.
+#endif
+
+#if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
+# error "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd."
+#endif
+#if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
+# error "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd."
+#endif
+
+#if defined(REDIRECT_MALLOC) && defined(THREADS) && !defined(LINUX)
+# error "REDIRECT_MALLOC with THREADS works at most on Linux."
+#endif
#ifdef GC_PRIVATE_H
- /* This relies on some type definitions from gc_priv.h, from */
- /* where it's normally included. */
- /* */
- /* How to get heap memory from the OS: */
- /* Note that sbrk()-like allocation is preferred, since it */
- /* usually makes it possible to merge consecutively allocated */
- /* chunks. It also avoids unintented recursion with */
- /* -DREDIRECT_MALLOC. */
- /* GET_MEM() returns a HLKSIZE aligned chunk. */
- /* 0 is taken to mean failure. */
- /* In the case os USE_MMAP, the argument must also be a */
- /* physical page size. */
- /* GET_MEM is currently not assumed to retrieve 0 filled space, */
- /* though we should perhaps take advantage of the case in which */
- /* does. */
- struct hblk; /* See gc_priv.h. */
-# ifdef PCR
- char * real_malloc();
-# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
- + GC_page_size-1)
-# else
-# ifdef OS2
- void * os2_alloc(size_t bytes);
-# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
- + GC_page_size) \
- + GC_page_size-1)
+ /* This relies on some type definitions from gc_priv.h, from */
+ /* where it's normally included. */
+ /* */
+ /* How to get heap memory from the OS: */
+ /* Note that sbrk()-like allocation is preferred, since it */
+ /* usually makes it possible to merge consecutively allocated */
+ /* chunks. It also avoids unintended recursion with */
+ /* REDIRECT_MALLOC macro defined. */
+ /* GET_MEM() returns a HLKSIZE aligned chunk. */
+ /* 0 is taken to mean failure. */
+ /* In the case os USE_MMAP, the argument must also be a */
+ /* physical page size. */
+ /* GET_MEM is currently not assumed to retrieve 0 filled space, */
+ /* though we should perhaps take advantage of the case in which */
+ /* does. */
+ struct hblk; /* See gc_priv.h. */
+# if defined(PCR)
+ char * real_malloc(size_t bytes);
+# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)(bytes) + GC_page_size) \
+ + GC_page_size-1)
+# elif defined(OS2)
+ void * os2_alloc(size_t bytes);
+# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)(bytes) \
+ + GC_page_size) + GC_page_size-1)
+# elif defined(NEXT) || defined(DOS4GW) || defined(NONSTOP) \
+ || (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) \
+ || (defined(SOLARIS) && !defined(USE_MMAP)) || defined(RTEMS) \
+ || defined(__CC_ARM)
+# define GET_MEM(bytes) HBLKPTR((size_t)calloc(1, \
+ (size_t)(bytes) + GC_page_size) \
+ + GC_page_size - 1)
+# elif defined(MSWIN32) || defined(CYGWIN32)
+ ptr_t GC_win32_get_mem(GC_word bytes);
+# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
+# elif defined(MACOS)
+# if defined(USE_TEMPORARY_MEMORY)
+ Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory);
+# define GET_MEM(bytes) HBLKPTR( \
+ GC_MacTemporaryNewPtr((bytes) + GC_page_size, true) \
+ + GC_page_size-1)
# else
-# if defined(NEXT) || defined(DOS4GW) || \
- (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
- (defined(SUNOS5) && !defined(USE_MMAP))
-# define GET_MEM(bytes) HBLKPTR((size_t) \
- calloc(1, (size_t)bytes + GC_page_size) \
- + GC_page_size-1)
-# else
-# ifdef MSWIN32
- extern ptr_t GC_win32_get_mem();
-# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
-# else
-# ifdef MACOS
-# if defined(USE_TEMPORARY_MEMORY)
- extern Ptr GC_MacTemporaryNewPtr(size_t size,
- Boolean clearMemory);
-# define GET_MEM(bytes) HBLKPTR( \
- GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
- + GC_page_size-1)
-# else
-# define GET_MEM(bytes) HBLKPTR( \
- NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
-# endif
-# else
-# ifdef MSWINCE
- extern ptr_t GC_wince_get_mem();
-# define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
-# else
-# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
- extern void *GC_amiga_get_mem(size_t size);
- define GET_MEM(bytes) HBLKPTR((size_t) \
- GC_amiga_get_mem((size_t)bytes + GC_page_size) \
- + GC_page_size-1)
-# else
- extern ptr_t GC_unix_get_mem();
-# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
+# define GET_MEM(bytes) HBLKPTR(NewPtrClear((bytes) + GC_page_size) \
+ + GC_page_size-1)
+# endif
+# elif defined(MSWINCE)
+ ptr_t GC_wince_get_mem(GC_word bytes);
+# define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
+# elif defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
+ void *GC_amiga_get_mem(size_t size);
+# define GET_MEM(bytes) HBLKPTR((size_t) \
+ GC_amiga_get_mem((size_t)(bytes) + GC_page_size) \
+ + GC_page_size-1)
+# elif defined(SN_TARGET_PS3)
+ void *ps3_get_mem(size_t size);
+# define GET_MEM(bytes) (struct hblk*)ps3_get_mem(bytes)
+# else
+ ptr_t GC_unix_get_mem(GC_word bytes);
+# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
# endif
-
#endif /* GC_PRIVATE_H */
-# endif /* GCCONFIG_H */
+#endif /* GCCONFIG_H */
diff --git a/boehm-gc/include/private/msvc_dbg.h b/boehm-gc/include/private/msvc_dbg.h
new file mode 100644
index 00000000000..1d3030aaabe
--- /dev/null
+++ b/boehm-gc/include/private/msvc_dbg.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (c) 2004-2005 Andrei Polushin
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+#ifndef _MSVC_DBG_H
+#define _MSVC_DBG_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !MSVC_DBG_DLL
+#define MSVC_DBG_EXPORT
+#elif MSVC_DBG_BUILD
+#define MSVC_DBG_EXPORT __declspec(dllexport)
+#else
+#define MSVC_DBG_EXPORT __declspec(dllimport)
+#endif
+
+#ifndef MAX_SYM_NAME
+#define MAX_SYM_NAME 2000
+#endif
+
+typedef void* HANDLE;
+typedef struct _CONTEXT CONTEXT;
+
+MSVC_DBG_EXPORT size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames);
+MSVC_DBG_EXPORT size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread, CONTEXT* context, size_t skip, void* frames[], size_t maxFrames);
+
+MSVC_DBG_EXPORT size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size);
+MSVC_DBG_EXPORT size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size);
+
+MSVC_DBG_EXPORT size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, size_t* offsetBytes);
+MSVC_DBG_EXPORT size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size, size_t* offsetBytes);
+
+MSVC_DBG_EXPORT size_t GetFileLineFromAddress(void* address, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes);
+MSVC_DBG_EXPORT size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes);
+
+MSVC_DBG_EXPORT size_t GetDescriptionFromAddress(void* address, const char* format, char* description, size_t size);
+MSVC_DBG_EXPORT size_t GetDescriptionFromStack(void*const frames[], size_t count, const char* format, char* description[], size_t size);
+
+/* Compatibility with <execinfo.h> */
+MSVC_DBG_EXPORT int backtrace(void* addresses[], int count);
+MSVC_DBG_EXPORT char** backtrace_symbols(void*const addresses[], int count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif/*_MSVC_DBG_H*/
diff --git a/boehm-gc/include/private/pthread_stop_world.h b/boehm-gc/include/private/pthread_stop_world.h
new file mode 100644
index 00000000000..cb67d230b38
--- /dev/null
+++ b/boehm-gc/include/private/pthread_stop_world.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef GC_PTHREAD_STOP_WORLD_H
+#define GC_PTHREAD_STOP_WORLD_H
+
+struct thread_stop_info {
+# ifndef GC_OPENBSD_THREADS
+ word last_stop_count; /* GC_last_stop_count value when thread */
+ /* last successfully handled a suspend */
+ /* signal. */
+# endif
+
+ ptr_t stack_ptr; /* Valid only when stopped. */
+
+# ifdef NACL
+ /* Grab NACL_GC_REG_STORAGE_SIZE pointers off the stack when */
+ /* going into a syscall. 20 is more than we need, but it's an */
+ /* overestimate in case the instrumented function uses any callee */
+ /* saved registers, they may be pushed to the stack much earlier. */
+ /* Also, on amd64 'push' puts 8 bytes on the stack even though */
+ /* our pointers are 4 bytes. */
+# define NACL_GC_REG_STORAGE_SIZE 20
+ ptr_t reg_storage[NACL_GC_REG_STORAGE_SIZE];
+# endif
+};
+
+GC_INNER void GC_stop_init(void);
+
+#endif
diff --git a/boehm-gc/include/private/pthread_support.h b/boehm-gc/include/private/pthread_support.h
new file mode 100644
index 00000000000..8820fc475c3
--- /dev/null
+++ b/boehm-gc/include/private/pthread_support.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifndef GC_PTHREAD_SUPPORT_H
+#define GC_PTHREAD_SUPPORT_H
+
+#include "private/gc_priv.h"
+
+#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
+
+#if defined(GC_DARWIN_THREADS)
+# include "private/darwin_stop_world.h"
+#else
+# include "private/pthread_stop_world.h"
+#endif
+
+#ifdef THREAD_LOCAL_ALLOC
+# include "thread_local_alloc.h"
+#endif
+
+/* We use the allocation lock to protect thread-related data structures. */
+
+/* The set of all known threads. We intercept thread creation and */
+/* joins. */
+/* Protected by allocation/GC lock. */
+/* Some of this should be declared volatile, but that's inconsistent */
+/* with some library routine declarations. */
+typedef struct GC_Thread_Rep {
+ struct GC_Thread_Rep * next; /* More recently allocated threads */
+ /* with a given pthread id come */
+ /* first. (All but the first are */
+ /* guaranteed to be dead, but we may */
+ /* not yet have registered the join.) */
+ pthread_t id;
+# ifdef PLATFORM_ANDROID
+ pid_t kernel_id;
+# endif
+ /* Extra bookkeeping information the stopping code uses */
+ struct thread_stop_info stop_info;
+
+ unsigned char flags;
+# define FINISHED 1 /* Thread has exited. */
+# define DETACHED 2 /* Thread is treated as detached. */
+ /* Thread may really be detached, or */
+ /* it may have been explicitly */
+ /* registered, in which case we can */
+ /* deallocate its GC_Thread_Rep once */
+ /* it unregisters itself, since it */
+ /* may not return a GC pointer. */
+# define MAIN_THREAD 4 /* True for the original thread only. */
+# define SUSPENDED_EXT 8 /* Thread was suspended externally */
+ /* (this is not used by the unmodified */
+ /* GC itself at present). */
+# define DISABLED_GC 0x10 /* Collections are disabled while the */
+ /* thread is exiting. */
+
+ unsigned char thread_blocked;
+ /* Protected by GC lock. */
+ /* Treated as a boolean value. If set, */
+ /* thread will acquire GC lock before */
+ /* doing any pointer manipulations, and */
+ /* has set its SP value. Thus it does */
+ /* not need to be sent a signal to stop */
+ /* it. */
+
+ unsigned short finalizer_skipped;
+ unsigned char finalizer_nested;
+ /* Used by GC_check_finalizer_nested() */
+ /* to minimize the level of recursion */
+ /* when a client finalizer allocates */
+ /* memory (initially both are 0). */
+
+ ptr_t stack_end; /* Cold end of the stack (except for */
+ /* main thread). */
+# if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
+ ptr_t topOfStack; /* Result of GC_FindTopOfStack(0); */
+ /* valid only if the thread is blocked; */
+ /* non-NULL value means already set. */
+# endif
+# ifdef IA64
+ ptr_t backing_store_end;
+ ptr_t backing_store_ptr;
+# endif
+
+ struct GC_traced_stack_sect_s *traced_stack_sect;
+ /* Points to the "frame" data held in stack by */
+ /* the innermost GC_call_with_gc_active() of */
+ /* this thread. May be NULL. */
+
+ void * status; /* The value returned from the thread. */
+ /* Used only to avoid premature */
+ /* reclamation of any data it might */
+ /* reference. */
+ /* This is unfortunately also the */
+ /* reason we need to intercept join */
+ /* and detach. */
+
+# ifdef THREAD_LOCAL_ALLOC
+ struct thread_local_freelists tlfs;
+# endif
+} * GC_thread;
+
+# define THREAD_TABLE_SZ 256 /* Must be power of 2 */
+GC_EXTERN volatile GC_thread GC_threads[THREAD_TABLE_SZ];
+
+GC_EXTERN GC_bool GC_thr_initialized;
+
+GC_INNER GC_thread GC_lookup_thread(pthread_t id);
+
+GC_EXTERN GC_bool GC_in_thread_creation;
+ /* We may currently be in thread creation or destruction. */
+ /* Only set to TRUE while allocation lock is held. */
+ /* When set, it is OK to run GC from unknown thread. */
+
+#ifdef NACL
+ GC_EXTERN __thread GC_thread GC_nacl_gc_thread_self;
+ GC_INNER void GC_nacl_initialize_gc_thread(void);
+ GC_INNER void GC_nacl_shutdown_gc_thread(void);
+#endif
+
+#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+ GC_INNER void GC_unblock_gc_signals(void);
+#endif
+
+GC_INNER GC_thread GC_start_rtn_prepare_thread(void *(**pstart)(void *),
+ void **pstart_arg,
+ struct GC_stack_base *sb, void *arg);
+GC_INNER void GC_thread_exit_proc(void *);
+
+#endif /* GC_PTHREADS && !GC_WIN32_THREADS */
+
+#endif /* GC_PTHREAD_SUPPORT_H */
diff --git a/boehm-gc/include/private/solaris_threads.h b/boehm-gc/include/private/solaris_threads.h
deleted file mode 100644
index b1f62620bd7..00000000000
--- a/boehm-gc/include/private/solaris_threads.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifdef GC_SOLARIS_THREADS
-
-/* The set of all known threads. We intercept thread creation and */
-/* joins. We never actually create detached threads. We allocate all */
-/* new thread stacks ourselves. These allow us to maintain this */
-/* data structure. */
-/* Protected by GC_thr_lock. */
-/* Some of this should be declared volatile, but that's incosnsistent */
-/* with some library routine declarations. In particular, the */
-/* definition of cond_t doesn't mention volatile! */
- typedef struct GC_Thread_Rep {
- struct GC_Thread_Rep * next;
- thread_t id;
- word flags;
-# define FINISHED 1 /* Thread has exited. */
-# define DETACHED 2 /* Thread is intended to be detached. */
-# define CLIENT_OWNS_STACK 4
- /* Stack was supplied by client. */
-# define SUSPNDED 8 /* Currently suspended. */
- /* SUSPENDED is used insystem header. */
- ptr_t stack;
- size_t stack_size;
- cond_t join_cv;
- void * status;
- } * GC_thread;
- extern GC_thread GC_new_thread(thread_t id);
-
- extern GC_bool GC_thr_initialized;
- extern volatile GC_thread GC_threads[];
- extern size_t GC_min_stack_sz;
- extern size_t GC_page_sz;
- extern void GC_thr_init(void);
- extern ptr_t GC_stack_alloc(size_t * stack_size);
- extern void GC_stack_free(ptr_t stack, size_t size);
-
-# endif /* GC_SOLARIS_THREADS */
-
diff --git a/boehm-gc/include/private/specific.h b/boehm-gc/include/private/specific.h
index d04e19f5a4b..7302fe32ca9 100644
--- a/boehm-gc/include/private/specific.h
+++ b/boehm-gc/include/private/specific.h
@@ -13,83 +13,86 @@
*/
#include <errno.h>
+#include "atomic_ops.h"
-/* Called during key creation or setspecific. */
-/* For the GC we already hold lock. */
-/* Currently allocated objects leak on thread exit. */
-/* That's hard to fix, but OK if we allocate garbage */
-/* collected memory. */
+/* Called during key creation or setspecific. */
+/* For the GC we already hold lock. */
+/* Currently allocated objects leak on thread exit. */
+/* That's hard to fix, but OK if we allocate garbage */
+/* collected memory. */
#define MALLOC_CLEAR(n) GC_INTERNAL_MALLOC(n, NORMAL)
-#define PREFIXED(name) GC_##name
#define TS_CACHE_SIZE 1024
-#define CACHE_HASH(n) (((((long)n) >> 8) ^ (long)n) & (TS_CACHE_SIZE - 1))
-#define TS_HASH_SIZE 1024
-#define HASH(n) (((((long)n) >> 8) ^ (long)n) & (TS_HASH_SIZE - 1))
+#define CACHE_HASH(n) ((((n) >> 8) ^ (n)) & (TS_CACHE_SIZE - 1))
-/* An entry describing a thread-specific value for a given thread. */
-/* All such accessible structures preserve the invariant that if either */
-/* thread is a valid pthread id or qtid is a valid "quick tread id" */
-/* for a thread, then value holds the corresponding thread specific */
-/* value. This invariant must be preserved at ALL times, since */
-/* asynchronous reads are allowed. */
+#define TS_HASH_SIZE 1024
+#define HASH(p) \
+ ((unsigned)((((word)(p)) >> 8) ^ (word)(p)) & (TS_HASH_SIZE - 1))
+
+/* An entry describing a thread-specific value for a given thread. */
+/* All such accessible structures preserve the invariant that if either */
+/* thread is a valid pthread id or qtid is a valid "quick tread id" */
+/* for a thread, then value holds the corresponding thread specific */
+/* value. This invariant must be preserved at ALL times, since */
+/* asynchronous reads are allowed. */
typedef struct thread_specific_entry {
- unsigned long qtid; /* quick thread id, only for cache */
- void * value;
- struct thread_specific_entry *next;
- pthread_t thread;
+ volatile AO_t qtid; /* quick thread id, only for cache */
+ void * value;
+ struct thread_specific_entry *next;
+ pthread_t thread;
} tse;
-
-/* We represent each thread-specific datum as two tables. The first is */
-/* a cache, indexed by a "quick thread identifier". The "quick" thread */
-/* identifier is an easy to compute value, which is guaranteed to */
-/* determine the thread, though a thread may correspond to more than */
-/* one value. We typically use the address of a page in the stack. */
-/* The second is a hash table, indexed by pthread_self(). It is used */
-/* only as a backup. */
-
-/* Return the "quick thread id". Default version. Assumes page size, */
-/* or at least thread stack separation, is at least 4K. */
-/* Must be defined so that it never returns 0. (Page 0 can't really */
-/* be part of any stack, since that would make 0 a valid stack pointer.)*/
-static __inline__ unsigned long quick_thread_id() {
- int dummy;
- return (unsigned long)(&dummy) >> 12;
-}
-
-#define INVALID_QTID ((unsigned long)0)
+/* We represent each thread-specific datum as two tables. The first is */
+/* a cache, indexed by a "quick thread identifier". The "quick" thread */
+/* identifier is an easy to compute value, which is guaranteed to */
+/* determine the thread, though a thread may correspond to more than */
+/* one value. We typically use the address of a page in the stack. */
+/* The second is a hash table, indexed by pthread_self(). It is used */
+/* only as a backup. */
+
+/* Return the "quick thread id". Default version. Assumes page size, */
+/* or at least thread stack separation, is at least 4K. */
+/* Must be defined so that it never returns 0. (Page 0 can't really be */
+/* part of any stack, since that would make 0 a valid stack pointer.) */
+#define quick_thread_id() (((word)GC_approx_sp()) >> 12)
+
+#define INVALID_QTID ((word)0)
#define INVALID_THREADID ((pthread_t)0)
+union ptse_ao_u {
+ tse *p;
+ volatile AO_t ao;
+};
+
typedef struct thread_specific_data {
tse * volatile cache[TS_CACHE_SIZE];
- /* A faster index to the hash table */
- tse * hash[TS_HASH_SIZE];
+ /* A faster index to the hash table */
+ union ptse_ao_u hash[TS_HASH_SIZE];
pthread_mutex_t lock;
} tsd;
-typedef tsd * PREFIXED(key_t);
-
-extern int PREFIXED(key_create) (tsd ** key_ptr, void (* destructor)(void *));
+typedef tsd * GC_key_t;
-extern int PREFIXED(setspecific) (tsd * key, void * value);
+#define GC_key_create(key, d) GC_key_create_inner(key)
+GC_INNER int GC_key_create_inner(tsd ** key_ptr);
+GC_INNER int GC_setspecific(tsd * key, void * value);
+GC_INNER void GC_remove_specific(tsd * key);
-extern void PREFIXED(remove_specific) (tsd * key);
+/* An internal version of getspecific that assumes a cache miss. */
+GC_INNER void * GC_slow_getspecific(tsd * key, word qtid,
+ tse * volatile * cache_entry);
-/* An internal version of getspecific that assumes a cache miss. */
-void * PREFIXED(slow_getspecific) (tsd * key, unsigned long qtid,
- tse * volatile * cache_entry);
+/* GC_INLINE is defined in gc_priv.h. */
+GC_INLINE void * GC_getspecific(tsd * key)
+{
+ word qtid = quick_thread_id();
+ tse * volatile * entry_ptr = &key->cache[CACHE_HASH(qtid)];
+ tse * entry = *entry_ptr; /* Must be loaded only once. */
-static __inline__ void * PREFIXED(getspecific) (tsd * key) {
- long qtid = quick_thread_id();
- unsigned hash_val = CACHE_HASH(qtid);
- tse * volatile * entry_ptr = key -> cache + hash_val;
- tse * entry = *entry_ptr; /* Must be loaded only once. */
- if (EXPECT(entry -> qtid == qtid, 1)) {
+ GC_ASSERT(qtid != INVALID_QTID);
+ if (EXPECT(entry -> qtid == qtid, TRUE)) {
GC_ASSERT(entry -> thread == pthread_self());
return entry -> value;
}
- return PREFIXED(slow_getspecific) (key, qtid, entry_ptr);
+ return GC_slow_getspecific(key, qtid, entry_ptr);
}
-
-
diff --git a/boehm-gc/include/private/thread_local_alloc.h b/boehm-gc/include/private/thread_local_alloc.h
new file mode 100644
index 00000000000..ce089edfc05
--- /dev/null
+++ b/boehm-gc/include/private/thread_local_alloc.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2000-2005 by Hewlett-Packard Company. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* Included indirectly from a thread-library-specific file. */
+/* This is the interface for thread-local allocation, whose */
+/* implementation is mostly thread-library-independent. */
+/* Here we describe only the interface that needs to be known */
+/* and invoked from the thread support layer; the actual */
+/* implementation also exports GC_malloc and friends, which */
+/* are declared in gc.h. */
+
+#ifndef GC_THREAD_LOCAL_ALLOC_H
+#define GC_THREAD_LOCAL_ALLOC_H
+
+#include "private/gc_priv.h"
+
+#ifdef THREAD_LOCAL_ALLOC
+
+#include "gc_inline.h"
+
+#if defined(USE_HPUX_TLS)
+# error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
+#endif
+
+#if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC) \
+ && !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) \
+ && !defined(USE_CUSTOM_SPECIFIC)
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+# if defined(CYGWIN32) && (__GNUC__ >= 4)
+# define USE_COMPILER_TLS
+# elif defined(__GNUC__) || defined(MSWINCE)
+# define USE_WIN32_SPECIFIC
+# else
+# define USE_WIN32_COMPILER_TLS
+# endif /* !GNU */
+# elif defined(LINUX) && !defined(ARM32) && !defined(AVR32) \
+ && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >=3))
+# define USE_COMPILER_TLS
+# elif defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) \
+ || defined(GC_AIX_THREADS) || defined(GC_DARWIN_THREADS) \
+ || defined(GC_FREEBSD_THREADS) || defined(GC_NETBSD_THREADS) \
+ || defined(GC_RTEMS_PTHREADS)
+# define USE_PTHREAD_SPECIFIC
+# elif defined(GC_HPUX_THREADS)
+# ifdef __GNUC__
+# define USE_PTHREAD_SPECIFIC
+ /* Empirically, as of gcc 3.3, USE_COMPILER_TLS doesn't work. */
+# else
+# define USE_COMPILER_TLS
+# endif
+# else
+# define USE_CUSTOM_SPECIFIC /* Use our own. */
+# endif
+#endif
+
+#include <stdlib.h>
+
+/* One of these should be declared as the tlfs field in the */
+/* structure pointed to by a GC_thread. */
+typedef struct thread_local_freelists {
+ void * ptrfree_freelists[TINY_FREELISTS];
+ void * normal_freelists[TINY_FREELISTS];
+# ifdef GC_GCJ_SUPPORT
+ void * gcj_freelists[TINY_FREELISTS];
+# define ERROR_FL ((void *)(word)-1)
+ /* Value used for gcj_freelist[-1]; allocation is */
+ /* erroneous. */
+# endif
+# ifdef ENABLE_DISCLAIM
+ void * finalized_freelists[TINY_FREELISTS];
+# endif
+ /* Free lists contain either a pointer or a small count */
+ /* reflecting the number of granules allocated at that */
+ /* size. */
+ /* 0 ==> thread-local allocation in use, free list */
+ /* empty. */
+ /* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
+ /* too few objects of this size have been */
+ /* allocated by this thread. */
+ /* >= HBLKSIZE => pointer to nonempty free list. */
+ /* > DIRECT_GRANULES, < HBLKSIZE ==> transition to */
+ /* local alloc, equivalent to 0. */
+# define DIRECT_GRANULES (HBLKSIZE/GRANULE_BYTES)
+ /* Don't use local free lists for up to this much */
+ /* allocation. */
+} *GC_tlfs;
+
+#if defined(USE_PTHREAD_SPECIFIC)
+# define GC_getspecific pthread_getspecific
+# define GC_setspecific pthread_setspecific
+# define GC_key_create pthread_key_create
+# define GC_remove_specific(key) /* No need for cleanup on exit. */
+ typedef pthread_key_t GC_key_t;
+#elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
+# define GC_getspecific(x) (x)
+# define GC_setspecific(key, v) ((key) = (v), 0)
+# define GC_key_create(key, d) 0
+# define GC_remove_specific(key) /* No need for cleanup on exit. */
+ typedef void * GC_key_t;
+#elif defined(USE_WIN32_SPECIFIC)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# define NOSERVICE
+# include <windows.h>
+# define GC_getspecific TlsGetValue
+# define GC_setspecific(key, v) !TlsSetValue(key, v)
+ /* We assume 0 == success, msft does the opposite. */
+# ifndef TLS_OUT_OF_INDEXES
+ /* this is currently missing in WinCE */
+# define TLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF
+# endif
+# define GC_key_create(key, d) \
+ ((d) != 0 || (*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? -1 : 0)
+# define GC_remove_specific(key) /* No need for cleanup on exit. */
+ /* Need TlsFree on process exit/detach? */
+ typedef DWORD GC_key_t;
+#elif defined(USE_CUSTOM_SPECIFIC)
+# include "private/specific.h"
+#else
+# error implement me
+#endif
+
+/* Each thread structure must be initialized. */
+/* This call must be made from the new thread. */
+/* Caller holds allocation lock. */
+GC_INNER void GC_init_thread_local(GC_tlfs p);
+
+/* Called when a thread is unregistered, or exits. */
+/* We hold the allocator lock. */
+GC_INNER void GC_destroy_thread_local(GC_tlfs p);
+
+/* The thread support layer must arrange to mark thread-local */
+/* free lists explicitly, since the link field is often */
+/* invisible to the marker. It knows how to find all threads; */
+/* we take care of an individual thread freelist structure. */
+GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p);
+
+#ifdef ENABLE_DISCLAIM
+ GC_EXTERN ptr_t * GC_finalized_objfreelist;
+#endif
+
+extern
+#if defined(USE_COMPILER_TLS)
+ __thread
+#elif defined(USE_WIN32_COMPILER_TLS)
+ __declspec(thread)
+#endif
+GC_key_t GC_thread_key;
+/* This is set up by the thread_local_alloc implementation. No need */
+/* for cleanup on thread exit. But the thread support layer makes sure */
+/* that GC_thread_key is traced, if necessary. */
+
+#endif /* THREAD_LOCAL_ALLOC */
+
+#endif /* GC_THREAD_LOCAL_ALLOC_H */
diff --git a/boehm-gc/include/weakpointer.h b/boehm-gc/include/weakpointer.h
index 84906b00a68..b9af99b596f 100644
--- a/boehm-gc/include/weakpointer.h
+++ b/boehm-gc/include/weakpointer.h
@@ -1,5 +1,5 @@
-#ifndef _weakpointer_h_
-#define _weakpointer_h_
+#ifndef _weakpointer_h_
+#define _weakpointer_h_
/****************************************************************************
@@ -13,8 +13,6 @@ WeakPointer and CleanUp
Permission is hereby granted to copy this code for any purpose,
provided the above notices are retained on all copies.
- Last modified on Mon Jul 17 18:16:01 PDT 1995 by ellis
-
****************************************************************************/
/****************************************************************************
@@ -118,7 +116,7 @@ static void Set( T* t, void c( Data* d, T* t ), Data* d = 0 )
and d can be null, but t cannot. Sets the clean-up queue for
BO(t) to be the collector's queue. When t is removed from its
clean-up queue, its clean-up will be applied by calling c(d,
- t). It is an error if *t is not a collected object. */
+ t). It is an error if *t is not a collected object. */
{_CleanUp_Set( t, c, d );}
static void Call( T* t )
@@ -217,5 +215,3 @@ extern "C" {
}
#endif /* _weakpointer_h_ */
-
-
diff --git a/boehm-gc/install-sh b/boehm-gc/install-sh
deleted file mode 100755
index 398a88e1421..00000000000
--- a/boehm-gc/install-sh
+++ /dev/null
@@ -1,251 +0,0 @@
-#!/bin/sh
-#
-# install - install a program, script, or datafile
-# This comes from X11R5 (mit/util/scripts/install.sh).
-#
-# Copyright 1991 by the Massachusetts Institute of Technology
-#
-# Permission to use, copy, modify, distribute, and sell this software and its
-# documentation for any purpose is hereby granted without fee, provided that
-# the above copyright notice appear in all copies and that both that
-# copyright notice and this permission notice appear in supporting
-# documentation, and that the name of M.I.T. not be used in advertising or
-# publicity pertaining to distribution of the software without specific,
-# written prior permission. M.I.T. makes no representations about the
-# suitability of this software for any purpose. It is provided "as is"
-# without express or implied warranty.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# `make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch. It can only install one file at a time, a restriction
-# shared with many OS's install programs.
-
-
-# set DOITPROG to echo to test this script
-
-# Don't use :- since 4.3BSD and earlier shells don't like it.
-doit="${DOITPROG-}"
-
-
-# put in absolute paths if you don't have them in your path; or use env. vars.
-
-mvprog="${MVPROG-mv}"
-cpprog="${CPPROG-cp}"
-chmodprog="${CHMODPROG-chmod}"
-chownprog="${CHOWNPROG-chown}"
-chgrpprog="${CHGRPPROG-chgrp}"
-stripprog="${STRIPPROG-strip}"
-rmprog="${RMPROG-rm}"
-mkdirprog="${MKDIRPROG-mkdir}"
-
-transformbasename=""
-transform_arg=""
-instcmd="$mvprog"
-chmodcmd="$chmodprog 0755"
-chowncmd=""
-chgrpcmd=""
-stripcmd=""
-rmcmd="$rmprog -f"
-mvcmd="$mvprog"
-src=""
-dst=""
-dir_arg=""
-
-while [ x"$1" != x ]; do
- case $1 in
- -c) instcmd="$cpprog"
- shift
- continue;;
-
- -d) dir_arg=true
- shift
- continue;;
-
- -m) chmodcmd="$chmodprog $2"
- shift
- shift
- continue;;
-
- -o) chowncmd="$chownprog $2"
- shift
- shift
- continue;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift
- shift
- continue;;
-
- -s) stripcmd="$stripprog"
- shift
- continue;;
-
- -t=*) transformarg=`echo $1 | sed 's/-t=//'`
- shift
- continue;;
-
- -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
- shift
- continue;;
-
- *) if [ x"$src" = x ]
- then
- src=$1
- else
- # this colon is to work around a 386BSD /bin/sh bug
- :
- dst=$1
- fi
- shift
- continue;;
- esac
-done
-
-if [ x"$src" = x ]
-then
- echo "install: no input file specified"
- exit 1
-else
- :
-fi
-
-if [ x"$dir_arg" != x ]; then
- dst=$src
- src=""
-
- if [ -d $dst ]; then
- instcmd=:
- chmodcmd=""
- else
- instcmd=$mkdirprog
- fi
-else
-
-# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
-# might cause directories to be created, which would be especially bad
-# if $src (and thus $dsttmp) contains '*'.
-
- if [ -f $src -o -d $src ]
- then
- :
- else
- echo "install: $src does not exist"
- exit 1
- fi
-
- if [ x"$dst" = x ]
- then
- echo "install: no destination specified"
- exit 1
- else
- :
- fi
-
-# If destination is a directory, append the input filename; if your system
-# does not like double slashes in filenames, you may need to add some logic
-
- if [ -d $dst ]
- then
- dst="$dst"/`basename $src`
- else
- :
- fi
-fi
-
-## this sed command emulates the dirname command
-dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
-
-# Make sure that the destination directory exists.
-# this part is taken from Noah Friedman's mkinstalldirs script
-
-# Skip lots of stat calls in the usual case.
-if [ ! -d "$dstdir" ]; then
-defaultIFS='
- '
-IFS="${IFS-${defaultIFS}}"
-
-oIFS="${IFS}"
-# Some sh's can't handle IFS=/ for some reason.
-IFS='%'
-set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
-IFS="${oIFS}"
-
-pathcomp=''
-
-while [ $# -ne 0 ] ; do
- pathcomp="${pathcomp}${1}"
- shift
-
- if [ ! -d "${pathcomp}" ] ;
- then
- $mkdirprog "${pathcomp}"
- else
- :
- fi
-
- pathcomp="${pathcomp}/"
-done
-fi
-
-if [ x"$dir_arg" != x ]
-then
- $doit $instcmd $dst &&
-
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi
-else
-
-# If we're going to rename the final executable, determine the name now.
-
- if [ x"$transformarg" = x ]
- then
- dstfile=`basename $dst`
- else
- dstfile=`basename $dst $transformbasename |
- sed $transformarg`$transformbasename
- fi
-
-# don't allow the sed command to completely eliminate the filename
-
- if [ x"$dstfile" = x ]
- then
- dstfile=`basename $dst`
- else
- :
- fi
-
-# Make a temp file name in the proper directory.
-
- dsttmp=$dstdir/#inst.$$#
-
-# Move or copy the file name to the temp name
-
- $doit $instcmd $src $dsttmp &&
-
- trap "rm -f ${dsttmp}" 0 &&
-
-# and set any options; do chmod last to preserve setuid bits
-
-# If any of these fail, we abort the whole thing. If we want to
-# ignore errors from any of these, just make sure not to ignore
-# errors from the above "$doit $instcmd $src $dsttmp" command.
-
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi &&
-
-# Now rename the file to the real destination.
-
- $doit $rmcmd -f $dstdir/$dstfile &&
- $doit $mvcmd $dsttmp $dstdir/$dstfile
-
-fi &&
-
-
-exit 0
diff --git a/boehm-gc/irix_threads.c b/boehm-gc/irix_threads.c
deleted file mode 100644
index 12204fdabc2..00000000000
--- a/boehm-gc/irix_threads.c
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
- * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
- * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/*
- * Support code for Irix (>=6.2) Pthreads. This relies on properties
- * not guaranteed by the Pthread standard. It may or may not be portable
- * to other implementations.
- *
- * This now also includes an initial attempt at thread support for
- * HP/UX 11.
- *
- * Note that there is a lot of code duplication between linux_threads.c
- * and irix_threads.c; any changes made here may need to be reflected
- * there too.
- */
-
-# if defined(GC_IRIX_THREADS)
-
-# include "private/gc_priv.h"
-# include <pthread.h>
-# include <semaphore.h>
-# include <time.h>
-# include <errno.h>
-# include <unistd.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-
-#undef pthread_create
-#undef pthread_sigmask
-#undef pthread_join
-#undef pthread_detach
-
-void GC_thr_init();
-
-#if 0
-void GC_print_sig_mask()
-{
- sigset_t blocked;
- int i;
-
- if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
- ABORT("pthread_sigmask");
- GC_printf0("Blocked: ");
- for (i = 1; i <= MAXSIG; i++) {
- if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
- }
- GC_printf0("\n");
-}
-#endif
-
-/* We use the allocation lock to protect thread-related data structures. */
-
-/* The set of all known threads. We intercept thread creation and */
-/* joins. We never actually create detached threads. We allocate all */
-/* new thread stacks ourselves. These allow us to maintain this */
-/* data structure. */
-/* Protected by GC_thr_lock. */
-/* Some of this should be declared volatile, but that's incosnsistent */
-/* with some library routine declarations. */
-typedef struct GC_Thread_Rep {
- struct GC_Thread_Rep * next; /* More recently allocated threads */
- /* with a given pthread id come */
- /* first. (All but the first are */
- /* guaranteed to be dead, but we may */
- /* not yet have registered the join.) */
- pthread_t id;
- word stop;
-# define NOT_STOPPED 0
-# define PLEASE_STOP 1
-# define STOPPED 2
- word flags;
-# define FINISHED 1 /* Thread has exited. */
-# define DETACHED 2 /* Thread is intended to be detached. */
-# define CLIENT_OWNS_STACK 4
- /* Stack was supplied by client. */
- ptr_t stack;
- ptr_t stack_ptr; /* Valid only when stopped. */
- /* But must be within stack region at */
- /* all times. */
- size_t stack_size; /* 0 for original thread. */
- void * status; /* Used only to avoid premature */
- /* reclamation of any data it might */
- /* reference. */
-} * GC_thread;
-
-GC_thread GC_lookup_thread(pthread_t id);
-
-/*
- * The only way to suspend threads given the pthread interface is to send
- * signals. Unfortunately, this means we have to reserve
- * a signal, and intercept client calls to change the signal mask.
- * We use SIG_SUSPEND, defined in gc_priv.h.
- */
-
-pthread_mutex_t GC_suspend_lock = PTHREAD_MUTEX_INITIALIZER;
- /* Number of threads stopped so far */
-pthread_cond_t GC_suspend_ack_cv = PTHREAD_COND_INITIALIZER;
-pthread_cond_t GC_continue_cv = PTHREAD_COND_INITIALIZER;
-
-void GC_suspend_handler(int sig)
-{
- int dummy;
- GC_thread me;
- sigset_t all_sigs;
- sigset_t old_sigs;
- int i;
-
- if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
- me = GC_lookup_thread(pthread_self());
- /* The lookup here is safe, since I'm doing this on behalf */
- /* of a thread which holds the allocation lock in order */
- /* to stop the world. Thus concurrent modification of the */
- /* data structure is impossible. */
- if (PLEASE_STOP != me -> stop) {
- /* Misdirected signal. */
- pthread_mutex_unlock(&GC_suspend_lock);
- return;
- }
- pthread_mutex_lock(&GC_suspend_lock);
- me -> stack_ptr = (ptr_t)(&dummy);
- me -> stop = STOPPED;
- pthread_cond_signal(&GC_suspend_ack_cv);
- pthread_cond_wait(&GC_continue_cv, &GC_suspend_lock);
- pthread_mutex_unlock(&GC_suspend_lock);
- /* GC_printf1("Continuing 0x%x\n", pthread_self()); */
-}
-
-
-GC_bool GC_thr_initialized = FALSE;
-
-size_t GC_min_stack_sz;
-
-# define N_FREE_LISTS 25
-ptr_t GC_stack_free_lists[N_FREE_LISTS] = { 0 };
- /* GC_stack_free_lists[i] is free list for stacks of */
- /* size GC_min_stack_sz*2**i. */
- /* Free lists are linked through first word. */
-
-/* Return a stack of size at least *stack_size. *stack_size is */
-/* replaced by the actual stack size. */
-/* Caller holds allocation lock. */
-ptr_t GC_stack_alloc(size_t * stack_size)
-{
- register size_t requested_sz = *stack_size;
- register size_t search_sz = GC_min_stack_sz;
- register int index = 0; /* = log2(search_sz/GC_min_stack_sz) */
- register ptr_t result;
-
- while (search_sz < requested_sz) {
- search_sz *= 2;
- index++;
- }
- if ((result = GC_stack_free_lists[index]) == 0
- && (result = GC_stack_free_lists[index+1]) != 0) {
- /* Try next size up. */
- search_sz *= 2; index++;
- }
- if (result != 0) {
- GC_stack_free_lists[index] = *(ptr_t *)result;
- } else {
- result = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_size);
- result = (ptr_t)(((word)result + GC_page_size) & ~(GC_page_size - 1));
- /* Protect hottest page to detect overflow. */
-# ifdef STACK_GROWS_UP
- /* mprotect(result + search_sz, GC_page_size, PROT_NONE); */
-# else
- /* mprotect(result, GC_page_size, PROT_NONE); */
- result += GC_page_size;
-# endif
- }
- *stack_size = search_sz;
- return(result);
-}
-
-/* Caller holds allocation lock. */
-void GC_stack_free(ptr_t stack, size_t size)
-{
- register int index = 0;
- register size_t search_sz = GC_min_stack_sz;
-
- while (search_sz < size) {
- search_sz *= 2;
- index++;
- }
- if (search_sz != size) ABORT("Bad stack size");
- *(ptr_t *)stack = GC_stack_free_lists[index];
- GC_stack_free_lists[index] = stack;
-}
-
-
-
-# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
-volatile GC_thread GC_threads[THREAD_TABLE_SZ];
-
-void GC_push_thread_structures GC_PROTO((void))
-{
- GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
-}
-
-/* Add a thread to GC_threads. We assume it wasn't already there. */
-/* Caller holds allocation lock. */
-GC_thread GC_new_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- GC_thread result;
- static struct GC_Thread_Rep first_thread;
- static GC_bool first_thread_used = FALSE;
-
- if (!first_thread_used) {
- result = &first_thread;
- first_thread_used = TRUE;
- /* Dont acquire allocation lock, since we may already hold it. */
- } else {
- result = (struct GC_Thread_Rep *)
- GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
- }
- if (result == 0) return(0);
- result -> id = id;
- result -> next = GC_threads[hv];
- GC_threads[hv] = result;
- /* result -> flags = 0; */
- /* result -> stop = 0; */
- return(result);
-}
-
-/* Delete a thread from GC_threads. We assume it is there. */
-/* (The code intentionally traps if it wasn't.) */
-/* Caller holds allocation lock. */
-void GC_delete_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (!pthread_equal(p -> id, id)) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
-}
-
-/* If a thread has been joined, but we have not yet */
-/* been notified, then there may be more than one thread */
-/* in the table with the same pthread id. */
-/* This is OK, but we need a way to delete a specific one. */
-void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (p != gc_id) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
-}
-
-/* Return a GC_thread corresponding to a given thread_t. */
-/* Returns 0 if it's not there. */
-/* Caller holds allocation lock or otherwise inhibits */
-/* updates. */
-/* If there is more than one thread with the given id we */
-/* return the most recent one. */
-GC_thread GC_lookup_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
-
- while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
- return(p);
-}
-
-
-/* Caller holds allocation lock. */
-void GC_stop_world()
-{
- pthread_t my_thread = pthread_self();
- register int i;
- register GC_thread p;
- register int result;
- struct timespec timeout;
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> id != my_thread) {
- if (p -> flags & FINISHED) {
- p -> stop = STOPPED;
- continue;
- }
- p -> stop = PLEASE_STOP;
- result = pthread_kill(p -> id, SIG_SUSPEND);
- /* GC_printf1("Sent signal to 0x%x\n", p -> id); */
- switch(result) {
- case ESRCH:
- /* Not really there anymore. Possible? */
- p -> stop = STOPPED;
- break;
- case 0:
- break;
- default:
- ABORT("pthread_kill failed");
- }
- }
- }
- }
- pthread_mutex_lock(&GC_suspend_lock);
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- while (p -> id != my_thread && p -> stop != STOPPED) {
- clock_gettime(CLOCK_REALTIME, &timeout);
- timeout.tv_nsec += 50000000; /* 50 msecs */
- if (timeout.tv_nsec >= 1000000000) {
- timeout.tv_nsec -= 1000000000;
- ++timeout.tv_sec;
- }
- result = pthread_cond_timedwait(&GC_suspend_ack_cv,
- &GC_suspend_lock,
- &timeout);
- if (result == ETIMEDOUT) {
- /* Signal was lost or misdirected. Try again. */
- /* Duplicate signals should be benign. */
- result = pthread_kill(p -> id, SIG_SUSPEND);
- }
- }
- }
- }
- pthread_mutex_unlock(&GC_suspend_lock);
- /* GC_printf1("World stopped 0x%x\n", pthread_self()); */
-}
-
-/* Caller holds allocation lock. */
-void GC_start_world()
-{
- GC_thread p;
- unsigned i;
-
- /* GC_printf0("World starting\n"); */
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- p -> stop = NOT_STOPPED;
- }
- }
- pthread_mutex_lock(&GC_suspend_lock);
- /* All other threads are at pthread_cond_wait in signal handler. */
- /* Otherwise we couldn't have acquired the lock. */
- pthread_mutex_unlock(&GC_suspend_lock);
- pthread_cond_broadcast(&GC_continue_cv);
-}
-
-# ifdef MMAP_STACKS
---> not really supported yet.
-int GC_is_thread_stack(ptr_t addr)
-{
- register int i;
- register GC_thread p;
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> stack_size != 0) {
- if (p -> stack <= addr &&
- addr < p -> stack + p -> stack_size)
- return 1;
- }
- }
- }
- return 0;
-}
-# endif
-
-/* We hold allocation lock. Should do exactly the right thing if the */
-/* world is stopped. Should not fail if it isn't. */
-void GC_push_all_stacks()
-{
- register int i;
- register GC_thread p;
- register ptr_t sp = GC_approx_sp();
- register ptr_t hot, cold;
- pthread_t me = pthread_self();
-
- if (!GC_thr_initialized) GC_thr_init();
- /* GC_printf1("Pushing stacks from thread 0x%x\n", me); */
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> flags & FINISHED) continue;
- if (pthread_equal(p -> id, me)) {
- hot = GC_approx_sp();
- } else {
- hot = p -> stack_ptr;
- }
- if (p -> stack_size != 0) {
-# ifdef STACK_GROWS_UP
- cold = p -> stack;
-# else
- cold = p -> stack + p -> stack_size;
-# endif
- } else {
- /* The original stack. */
- cold = GC_stackbottom;
- }
-# ifdef STACK_GROWS_UP
- GC_push_all_stack(cold, hot);
-# else
- GC_push_all_stack(hot, cold);
-# endif
- }
- }
-}
-
-
-/* We hold the allocation lock. */
-void GC_thr_init()
-{
- GC_thread t;
- struct sigaction act;
-
- if (GC_thr_initialized) return;
- GC_thr_initialized = TRUE;
- GC_min_stack_sz = HBLKSIZE;
- (void) sigaction(SIG_SUSPEND, 0, &act);
- if (act.sa_handler != SIG_DFL)
- ABORT("Previously installed SIG_SUSPEND handler");
- /* Install handler. */
- act.sa_handler = GC_suspend_handler;
- act.sa_flags = SA_RESTART;
- (void) sigemptyset(&act.sa_mask);
- if (0 != sigaction(SIG_SUSPEND, &act, 0))
- ABORT("Failed to install SIG_SUSPEND handler");
- /* Add the initial thread, so we can stop it. */
- t = GC_new_thread(pthread_self());
- t -> stack_size = 0;
- t -> stack_ptr = (ptr_t)(&t);
- t -> flags = DETACHED;
-}
-
-int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
-{
- sigset_t fudged_set;
-
- if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
- fudged_set = *set;
- sigdelset(&fudged_set, SIG_SUSPEND);
- set = &fudged_set;
- }
- return(pthread_sigmask(how, set, oset));
-}
-
-struct start_info {
- void *(*start_routine)(void *);
- void *arg;
- word flags;
- ptr_t stack;
- size_t stack_size;
- sem_t registered; /* 1 ==> in our thread table, but */
- /* parent hasn't yet noticed. */
-};
-
-void GC_thread_exit_proc(void *arg)
-{
- GC_thread me;
-
- LOCK();
- me = GC_lookup_thread(pthread_self());
- if (me -> flags & DETACHED) {
- GC_delete_thread(pthread_self());
- } else {
- me -> flags |= FINISHED;
- }
- UNLOCK();
-}
-
-int GC_pthread_join(pthread_t thread, void **retval)
-{
- int result;
- GC_thread thread_gc_id;
-
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- /* This is guaranteed to be the intended one, since the thread id */
- /* cant have been recycled by pthreads. */
- UNLOCK();
- result = pthread_join(thread, retval);
- /* Some versions of the Irix pthreads library can erroneously */
- /* return EINTR when the call succeeds. */
- if (EINTR == result) result = 0;
- if (result == 0) {
- LOCK();
- /* Here the pthread thread id may have been recycled. */
- GC_delete_gc_thread(thread, thread_gc_id);
- UNLOCK();
- }
- return result;
-}
-
-int GC_pthread_detach(pthread_t thread)
-{
- int result;
- GC_thread thread_gc_id;
-
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- UNLOCK();
- result = REAL_FUNC(pthread_detach)(thread);
- if (result == 0) {
- LOCK();
- thread_gc_id -> flags |= DETACHED;
- /* Here the pthread thread id may have been recycled. */
- if (thread_gc_id -> flags & FINISHED) {
- GC_delete_gc_thread(thread, thread_gc_id);
- }
- UNLOCK();
- }
- return result;
-}
-
-void * GC_start_routine(void * arg)
-{
- struct start_info * si = arg;
- void * result;
- GC_thread me;
- pthread_t my_pthread;
- void *(*start)(void *);
- void *start_arg;
-
- my_pthread = pthread_self();
- /* If a GC occurs before the thread is registered, that GC will */
- /* ignore this thread. That's fine, since it will block trying to */
- /* acquire the allocation lock, and won't yet hold interesting */
- /* pointers. */
- LOCK();
- /* We register the thread here instead of in the parent, so that */
- /* we don't need to hold the allocation lock during pthread_create. */
- /* Holding the allocation lock there would make REDIRECT_MALLOC */
- /* impossible. It probably still doesn't work, but we're a little */
- /* closer ... */
- /* This unfortunately means that we have to be careful the parent */
- /* doesn't try to do a pthread_join before we're registered. */
- me = GC_new_thread(my_pthread);
- me -> flags = si -> flags;
- me -> stack = si -> stack;
- me -> stack_size = si -> stack_size;
- me -> stack_ptr = (ptr_t)si -> stack + si -> stack_size - sizeof(word);
- UNLOCK();
- start = si -> start_routine;
- start_arg = si -> arg;
- sem_post(&(si -> registered));
- pthread_cleanup_push(GC_thread_exit_proc, 0);
- result = (*start)(start_arg);
- me -> status = result;
- me -> flags |= FINISHED;
- pthread_cleanup_pop(1);
- /* This involves acquiring the lock, ensuring that we can't exit */
- /* while a collection that thinks we're alive is trying to stop */
- /* us. */
- return(result);
-}
-
-# define copy_attr(pa_ptr, source) *(pa_ptr) = *(source)
-
-int
-GC_pthread_create(pthread_t *new_thread,
- const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg)
-{
- int result;
- GC_thread t;
- void * stack;
- size_t stacksize;
- pthread_attr_t new_attr;
- int detachstate;
- word my_flags = 0;
- struct start_info * si = GC_malloc(sizeof(struct start_info));
- /* This is otherwise saved only in an area mmapped by the thread */
- /* library, which isn't visible to the collector. */
-
- if (0 == si) return(ENOMEM);
- if (0 != sem_init(&(si -> registered), 0, 0)) {
- ABORT("sem_init failed");
- }
- si -> start_routine = start_routine;
- si -> arg = arg;
- LOCK();
- if (!GC_initialized) GC_init();
- if (NULL == attr) {
- stack = 0;
- (void) pthread_attr_init(&new_attr);
- } else {
- copy_attr(&new_attr, attr);
- pthread_attr_getstackaddr(&new_attr, &stack);
- }
- pthread_attr_getstacksize(&new_attr, &stacksize);
- pthread_attr_getdetachstate(&new_attr, &detachstate);
- if (stacksize < GC_min_stack_sz) ABORT("Stack too small");
- if (0 == stack) {
- stack = (void *)GC_stack_alloc(&stacksize);
- if (0 == stack) {
- UNLOCK();
- return(ENOMEM);
- }
- pthread_attr_setstackaddr(&new_attr, stack);
- } else {
- my_flags |= CLIENT_OWNS_STACK;
- }
- if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
- si -> flags = my_flags;
- si -> stack = stack;
- si -> stack_size = stacksize;
- result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
- if (0 == new_thread && !(my_flags & CLIENT_OWNS_STACK)) {
- GC_stack_free(stack, stacksize);
- }
- UNLOCK();
- /* Wait until child has been added to the thread table. */
- /* This also ensures that we hold onto si until the child is done */
- /* with it. Thus it doesn't matter whether it is otherwise */
- /* visible to the collector. */
- while (0 != sem_wait(&(si -> registered))) {
- if (errno != EINTR) {
- GC_printf1("Sem_wait: errno = %ld\n", (unsigned long) errno);
- ABORT("sem_wait failed");
- }
- }
- sem_destroy(&(si -> registered));
- pthread_attr_destroy(&new_attr); /* Probably unnecessary under Irix */
- return(result);
-}
-
-VOLATILE GC_bool GC_collecting = 0;
- /* A hint that we're in the collector and */
- /* holding the allocation lock for an */
- /* extended period. */
-
-/* Reasonably fast spin locks. Basically the same implementation */
-/* as STL alloc.h. */
-
-#define SLEEP_THRESHOLD 3
-
-unsigned long GC_allocate_lock = 0;
-# define GC_TRY_LOCK() !GC_test_and_set(&GC_allocate_lock,1)
-# define GC_LOCK_TAKEN GC_allocate_lock
-
-void GC_lock()
-{
-# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
-# define high_spin_max 1000 /* spin cycles for multiprocessor */
- static unsigned spin_max = low_spin_max;
- unsigned my_spin_max;
- static unsigned last_spins = 0;
- unsigned my_last_spins;
- volatile unsigned junk;
-# define PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk
- int i;
-
- if (GC_TRY_LOCK()) {
- return;
- }
- junk = 0;
- my_spin_max = spin_max;
- my_last_spins = last_spins;
- for (i = 0; i < my_spin_max; i++) {
- if (GC_collecting) goto yield;
- if (i < my_last_spins/2 || GC_LOCK_TAKEN) {
- PAUSE;
- continue;
- }
- if (GC_TRY_LOCK()) {
- /*
- * got it!
- * Spinning worked. Thus we're probably not being scheduled
- * against the other process with which we were contending.
- * Thus it makes sense to spin longer the next time.
- */
- last_spins = i;
- spin_max = high_spin_max;
- return;
- }
- }
- /* We are probably being scheduled against the other process. Sleep. */
- spin_max = low_spin_max;
-yield:
- for (i = 0;; ++i) {
- if (GC_TRY_LOCK()) {
- return;
- }
- if (i < SLEEP_THRESHOLD) {
- sched_yield();
- } else {
- struct timespec ts;
-
- if (i > 26) i = 26;
- /* Don't wait for more than about 60msecs, even */
- /* under extreme contention. */
- ts.tv_sec = 0;
- ts.tv_nsec = 1 << i;
- nanosleep(&ts, 0);
- }
- }
-}
-
-# else
-
-#ifndef LINT
- int GC_no_Irix_threads;
-#endif
-
-# endif /* GC_IRIX_THREADS */
-
diff --git a/boehm-gc/libtool.m4 b/boehm-gc/libtool.m4
deleted file mode 100644
index 066bf6a5ce6..00000000000
--- a/boehm-gc/libtool.m4
+++ /dev/null
@@ -1,3573 +0,0 @@
-# libtool.m4 - Configure libtool for the host system. -*-Shell-script-*-
-## Copyright 1996, 1997, 1998, 1999, 2000, 2001
-## Free Software Foundation, Inc.
-## Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-##
-## This program is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-##
-## This program is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-##
-## As a special exception to the GNU General Public License, if you
-## distribute this file as part of a program that contains a
-## configuration script generated by Autoconf, you may include it under
-## the same distribution terms that you use for the rest of that program.
-
-# serial 46 AC_PROG_LIBTOOL
-
-AC_DEFUN([AC_PROG_LIBTOOL],
-[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh"
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-AC_SUBST(LIBTOOL)dnl
-
-# Prevent multiple expansion
-define([AC_PROG_LIBTOOL], [])
-])
-
-AC_DEFUN([AC_LIBTOOL_SETUP],
-[AC_PREREQ(2.13)dnl
-AC_REQUIRE([AC_ENABLE_SHARED])dnl
-AC_REQUIRE([AC_ENABLE_STATIC])dnl
-AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_PROG_LD])dnl
-AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl
-AC_REQUIRE([AC_PROG_NM])dnl
-AC_REQUIRE([AC_PROG_LN_S])dnl
-AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl
-AC_REQUIRE([AC_OBJEXT])dnl
-AC_REQUIRE([AC_EXEEXT])dnl
-dnl
-
-_LT_AC_PROG_ECHO_BACKSLASH
-# Only perform the check for file, if the check method requires it
-case $deplibs_check_method in
-file_magic*)
- if test "$file_magic_cmd" = '$MAGIC_CMD'; then
- AC_PATH_MAGIC
- fi
- ;;
-esac
-
-AC_CHECK_TOOL(RANLIB, ranlib, :)
-AC_CHECK_TOOL(STRIP, strip, :)
-
-ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no)
-ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
-enable_win32_dll=yes, enable_win32_dll=no)
-
-AC_ARG_ENABLE(libtool-lock,
- [ --disable-libtool-lock avoid locking (might break parallel builds)])
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-*-*-irix6*)
- # Find out which ABI we are using.
- echo '[#]line __oline__ "configure"' > conftest.$ac_ext
- if AC_TRY_EVAL(ac_compile); then
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -32"
- ;;
- *N32*)
- LD="${LD-ld} -n32"
- ;;
- *64-bit*)
- LD="${LD-ld} -64"
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-
-*-*-sco3.2v5*)
- # On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -belf"
- AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
- [AC_LANG_SAVE
- AC_LANG_C
- AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
- AC_LANG_RESTORE])
- if test x"$lt_cv_cc_needs_belf" != x"yes"; then
- # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
- CFLAGS="$SAVE_CFLAGS"
- fi
- ;;
-
-ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
-[*-*-cygwin* | *-*-mingw* | *-*-pw32*)
- AC_CHECK_TOOL(DLLTOOL, dlltool, false)
- AC_CHECK_TOOL(AS, as, false)
- AC_CHECK_TOOL(OBJDUMP, objdump, false)
-
- # recent cygwin and mingw systems supply a stub DllMain which the user
- # can override, but on older systems we have to supply one
- AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain,
- [AC_TRY_LINK([],
- [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*);
- DllMain (0, 0, 0);],
- [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])])
-
- case $host/$CC in
- *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*)
- # old mingw systems require "-dll" to link a DLL, while more recent ones
- # require "-mdll"
- SAVE_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -mdll"
- AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch,
- [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])])
- CFLAGS="$SAVE_CFLAGS" ;;
- *-*-cygwin* | *-*-pw32*)
- # cygwin systems need to pass --dll to the linker, and not link
- # crt.o which will require a WinMain@16 definition.
- lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;;
- esac
- ;;
- ])
-esac
-
-_LT_AC_LTCONFIG_HACK
-
-])
-
-# AC_LIBTOOL_HEADER_ASSERT
-# ------------------------
-AC_DEFUN([AC_LIBTOOL_HEADER_ASSERT],
-[AC_CACHE_CHECK([whether $CC supports assert without backlinking],
- [lt_cv_func_assert_works],
- [case $host in
- *-*-solaris*)
- if test "$GCC" = yes && test "$with_gnu_ld" != yes; then
- case `$CC --version 2>/dev/null` in
- [[12]].*) lt_cv_func_assert_works=no ;;
- *) lt_cv_func_assert_works=yes ;;
- esac
- fi
- ;;
- esac])
-
-if test "x$lt_cv_func_assert_works" = xyes; then
- AC_CHECK_HEADERS(assert.h)
-fi
-])# AC_LIBTOOL_HEADER_ASSERT
-
-# _LT_AC_CHECK_DLFCN
-# --------------------
-AC_DEFUN([_LT_AC_CHECK_DLFCN],
-[AC_CHECK_HEADERS(dlfcn.h)
-])# _LT_AC_CHECK_DLFCN
-
-# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
-# ---------------------------------
-AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE],
-[AC_REQUIRE([AC_CANONICAL_HOST])
-AC_REQUIRE([AC_PROG_NM])
-AC_REQUIRE([AC_OBJEXT])
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-AC_MSG_CHECKING([command to parse $NM output])
-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [dnl
-
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix. What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[[BCDEGRST]]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
-
-# Transform the above into a raw symbol and a C symbol.
-symxfrm='\1 \2\3 \3'
-
-# Transform an extracted symbol line into a proper C declaration
-lt_cv_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'"
-
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
-
-# Define system-specific variables.
-case $host_os in
-aix*)
- symcode='[[BCDT]]'
- ;;
-cygwin* | mingw* | pw32*)
- symcode='[[ABCDGISTW]]'
- ;;
-hpux*) # Its linker distinguishes data from code symbols
- lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
- lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'"
- ;;
-irix*)
- symcode='[[BCDEGRST]]'
- ;;
-solaris* | sysv5*)
- symcode='[[BDT]]'
- ;;
-sysv4)
- symcode='[[DFNSTU]]'
- ;;
-esac
-
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $host_os in
-mingw*)
- opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp
- ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
- symcode='[[ABCDGISTW]]'
-fi
-
-# Try without a prefix undercore, then with it.
-for ac_symprfx in "" "_"; do
-
- # Write the raw and C identifiers.
-lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*\($ac_symprfx\)$sympat$opt_cr$/$symxfrm/p'"
-
- # Check to see that the pipe works correctly.
- pipe_works=no
- rm -f conftest*
- cat > conftest.$ac_ext <<EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-EOF
-
- if AC_TRY_EVAL(ac_compile); then
- # Now try to grab the symbols.
- nlist=conftest.nm
- if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
- # Try sorting and uniquifying the output.
- if sort "$nlist" | uniq > "$nlist"T; then
- mv -f "$nlist"T "$nlist"
- else
- rm -f "$nlist"T
- fi
-
- # Make sure that we snagged all the symbols we need.
- if egrep ' nm_test_var$' "$nlist" >/dev/null; then
- if egrep ' nm_test_func$' "$nlist" >/dev/null; then
- cat <<EOF > conftest.$ac_ext
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-EOF
- # Now generate the symbol file.
- eval "$lt_cv_global_symbol_to_cdecl"' < "$nlist" >> conftest.$ac_ext'
-
- cat <<EOF >> conftest.$ac_ext
-#if defined (__STDC__) && __STDC__
-# define lt_ptr void *
-#else
-# define lt_ptr char *
-# define const
-#endif
-
-/* The mapping between symbol names and symbols. */
-const struct {
- const char *name;
- lt_ptr address;
-}
-lt_preloaded_symbols[[]] =
-{
-EOF
- sed "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr) \&\2},/" < "$nlist" >> conftest.$ac_ext
- cat <<\EOF >> conftest.$ac_ext
- {0, (lt_ptr) 0}
-};
-
-#ifdef __cplusplus
-}
-#endif
-EOF
- # Now try linking the two files.
- mv conftest.$ac_objext conftstm.$ac_objext
- save_LIBS="$LIBS"
- save_CFLAGS="$CFLAGS"
- LIBS="conftstm.$ac_objext"
- CFLAGS="$CFLAGS$no_builtin_flag"
- if AC_TRY_EVAL(ac_link) && test -s conftest; then
- pipe_works=yes
- fi
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
- else
- echo "cannot find nm_test_func in $nlist" >&AC_FD_CC
- fi
- else
- echo "cannot find nm_test_var in $nlist" >&AC_FD_CC
- fi
- else
- echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AC_FD_CC
- fi
- else
- echo "$progname: failed program was:" >&AC_FD_CC
- cat conftest.$ac_ext >&5
- fi
- rm -f conftest* conftst*
-
- # Do not use the global_symbol_pipe unless it works.
- if test "$pipe_works" = yes; then
- break
- else
- lt_cv_sys_global_symbol_pipe=
- fi
-done
-])
-global_symbol_pipe="$lt_cv_sys_global_symbol_pipe"
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
- global_symbol_to_cdecl=
- global_symbol_to_c_name_address=
-else
- global_symbol_to_cdecl="$lt_cv_global_symbol_to_cdecl"
- global_symbol_to_c_name_address="$lt_cv_global_symbol_to_c_name_address"
-fi
-if test -z "$global_symbol_pipe$global_symbol_to_cdec$global_symbol_to_c_name_address";
-then
- AC_MSG_RESULT(failed)
-else
- AC_MSG_RESULT(ok)
-fi
-]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE
-
-# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR
-# ---------------------------------
-AC_DEFUN([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR],
-[# Find the correct PATH separator. Usually this is `:', but
-# DJGPP uses `;' like DOS.
-if test "X${PATH_SEPARATOR+set}" != Xset; then
- UNAME=${UNAME-`uname 2>/dev/null`}
- case X$UNAME in
- *-DOS) lt_cv_sys_path_separator=';' ;;
- *) lt_cv_sys_path_separator=':' ;;
- esac
- PATH_SEPARATOR=$lt_cv_sys_path_separator
-fi
-])# _LT_AC_LIBTOOL_SYS_PATH_SEPARATOR
-
-# _LT_AC_PROG_ECHO_BACKSLASH
-# --------------------------
-# Add some code to the start of the generated configure script which
-# will find an echo command which doesn't interpret backslashes.
-AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH],
-[ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
- [AC_DIVERT_PUSH(NOTICE)])
-_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR
-
-# Check that we are running under the correct shell.
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-case X$ECHO in
-X*--fallback-echo)
- # Remove one level of quotation (which was required for Make).
- ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
- ;;
-esac
-
-echo=${ECHO-echo}
-if test "X[$]1" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
-elif test "X[$]1" = X--fallback-echo; then
- # Avoid inline document here, it may be left over
- :
-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
- # Yippee, $echo works!
- :
-else
- # Restart under the correct shell.
- exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
-fi
-
-if test "X[$]1" = X--fallback-echo; then
- # used as fallback echo
- shift
- cat <<EOF
-$*
-EOF
- exit 0
-fi
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
-
-if test -z "$ECHO"; then
-if test "X${echo_test_string+set}" != Xset; then
-# find a string as large as possible, as long as the shell can cope with it
- for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
- # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
- if (echo_test_string="`eval $cmd`") 2>/dev/null &&
- echo_test_string="`eval $cmd`" &&
- (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null
- then
- break
- fi
- done
-fi
-
-if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- :
-else
- # The Solaris, AIX, and Digital Unix default echo programs unquote
- # backslashes. This makes it impossible to quote backslashes using
- # echo "$something" | sed 's/\\/\\\\/g'
- #
- # So, first we look for a working echo in the user's PATH.
-
- IFS="${IFS= }"; save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for dir in $PATH /usr/ucb; do
- if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
- test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- echo="$dir/echo"
- break
- fi
- done
- IFS="$save_ifs"
-
- if test "X$echo" = Xecho; then
- # We didn't find a better echo, so look for alternatives.
- if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- # This shell has a builtin print -r that does the trick.
- echo='print -r'
- elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
- test "X$CONFIG_SHELL" != X/bin/ksh; then
- # If we have ksh, try running configure again with it.
- ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
- export ORIGINAL_CONFIG_SHELL
- CONFIG_SHELL=/bin/ksh
- export CONFIG_SHELL
- exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
- else
- # Try using printf.
- echo='printf %s\n'
- if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
- echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- # Cool, printf works
- :
- elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
- test "X$echo_testing_string" = 'X\t' &&
- echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
- export CONFIG_SHELL
- SHELL="$CONFIG_SHELL"
- export SHELL
- echo="$CONFIG_SHELL [$]0 --fallback-echo"
- elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
- test "X$echo_testing_string" = 'X\t' &&
- echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
- test "X$echo_testing_string" = "X$echo_test_string"; then
- echo="$CONFIG_SHELL [$]0 --fallback-echo"
- else
- # maybe with a smaller string...
- prev=:
-
- for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
- if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null
- then
- break
- fi
- prev="$cmd"
- done
-
- if test "$prev" != 'sed 50q "[$]0"'; then
- echo_test_string=`eval $prev`
- export echo_test_string
- exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
- else
- # Oops. We lost completely, so just stick with echo.
- echo=echo
- fi
- fi
- fi
- fi
-fi
-fi
-
-# Copy echo and quote the copy suitably for passing to libtool from
-# the Makefile, instead of quoting the original, which is used later.
-ECHO=$echo
-if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
- ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
-fi
-
-AC_SUBST(ECHO)
-AC_DIVERT_POP
-])# _LT_AC_PROG_ECHO_BACKSLASH
-
-# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
-# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
-# ------------------------------------------------------------------
-AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF],
-[if test "$cross_compiling" = yes; then :
- [$4]
-else
- AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<EOF
-[#line __oline__ "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" void exit (int);
-#endif
-
-void fnord() { int i=42;}
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- /* dlclose (self); */
- }
-
- exit (status);
-}]
-EOF
- if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
- (./conftest; exit; ) 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) $1 ;;
- x$lt_dlneed_uscore) $2 ;;
- x$lt_unknown|x*) $3 ;;
- esac
- else :
- # compilation failed
- $3
- fi
-fi
-rm -fr conftest*
-])# _LT_AC_TRY_DLOPEN_SELF
-
-# AC_LIBTOOL_DLOPEN_SELF
-# -------------------
-AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF],
-[if test "x$enable_dlopen" != xyes; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
- lt_cv_dlopen=no
- lt_cv_dlopen_libs=
-
- case $host_os in
- beos*)
- lt_cv_dlopen="load_add_on"
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
- ;;
-
- cygwin* | mingw* | pw32*)
- lt_cv_dlopen="LoadLibrary"
- lt_cv_dlopen_libs=
- ;;
-
- *)
- AC_CHECK_FUNC([shl_load],
- [lt_cv_dlopen="shl_load"],
- [AC_CHECK_LIB([dld], [shl_load],
- [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"],
- [AC_CHECK_FUNC([dlopen],
- [lt_cv_dlopen="dlopen"],
- [AC_CHECK_LIB([dl], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
- [AC_CHECK_LIB([svld], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
- [AC_CHECK_LIB([dld], [dld_link],
- [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"])
- ])
- ])
- ])
- ])
- ])
- ;;
- esac
-
- if test "x$lt_cv_dlopen" != xno; then
- enable_dlopen=yes
- else
- enable_dlopen=no
- fi
-
- case $lt_cv_dlopen in
- dlopen)
- save_CPPFLAGS="$CPPFLAGS"
- AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl
- test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
- save_LDFLAGS="$LDFLAGS"
- eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
- save_LIBS="$LIBS"
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- AC_CACHE_CHECK([whether a program can dlopen itself],
- lt_cv_dlopen_self, [dnl
- _LT_AC_TRY_DLOPEN_SELF(
- lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
- lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
- ])
-
- if test "x$lt_cv_dlopen_self" = xyes; then
- LDFLAGS="$LDFLAGS $link_static_flag"
- AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
- lt_cv_dlopen_self_static, [dnl
- _LT_AC_TRY_DLOPEN_SELF(
- lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
- lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
- ])
- fi
-
- CPPFLAGS="$save_CPPFLAGS"
- LDFLAGS="$save_LDFLAGS"
- LIBS="$save_LIBS"
- ;;
- esac
-
- case $lt_cv_dlopen_self in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case $lt_cv_dlopen_self_static in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-])# AC_LIBTOOL_DLOPEN_SELF
-
-AC_DEFUN([_LT_AC_LTCONFIG_HACK],
-[AC_REQUIRE([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])dnl
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e s/^X//'
-sed_quote_subst='s/\([[\\"\\`$\\\\]]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([[\\"\\`\\\\]]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Constants:
-rm="rm -f"
-
-# Global variables:
-default_ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a `.a' archive for static linking (except M$VC,
-# which needs '.lib').
-libext=a
-ltmain="$ac_aux_dir/ltmain.sh"
-ofile="$default_ofile"
-with_gnu_ld="$lt_cv_prog_gnu_ld"
-need_locks="$enable_libtool_lock"
-
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
-
-# Set sane defaults for various variables
-test -z "$AR" && AR=ar
-test -z "$AR_FLAGS" && AR_FLAGS=cru
-test -z "$AS" && AS=as
-test -z "$CC" && CC=cc
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-test -z "$LD" && LD=ld
-test -z "$LN_S" && LN_S="ln -s"
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-test -z "$NM" && NM=nm
-test -z "$OBJDUMP" && OBJDUMP=objdump
-test -z "$RANLIB" && RANLIB=:
-test -z "$STRIP" && STRIP=:
-test -z "$ac_objext" && ac_objext=o
-
-if test x"$host" != x"$build"; then
- ac_tool_prefix=${host_alias}-
-else
- ac_tool_prefix=
-fi
-
-# Transform linux* to *-*-linux-gnu*, to support old configure scripts.
-case $host_os in
-linux-gnu*) ;;
-linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
-esac
-
-case $host_os in
-aix3*)
- # AIX sometimes has problems with the GCC collect2 program. For some
- # reason, if we set the COLLECT_NAMES environment variable, the problems
- # vanish in a puff of smoke.
- if test "X${COLLECT_NAMES+set}" != Xset; then
- COLLECT_NAMES=
- export COLLECT_NAMES
- fi
- ;;
-esac
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
- case $host_os in
- openbsd*)
- old_postinstall_cmds="\$RANLIB -t \$oldlib~$old_postinstall_cmds"
- ;;
- *)
- old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
- ;;
- esac
- old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
-fi
-
-# Allow CC to be a program name with arguments.
-set dummy $CC
-compiler="[$]2"
-
-## FIXME: this should be a separate macro
-##
-AC_MSG_CHECKING([for objdir])
-rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
- objdir=.libs
-else
- # MS-DOS does not allow filenames that begin with a dot.
- objdir=_libs
-fi
-rmdir .libs 2>/dev/null
-AC_MSG_RESULT($objdir)
-##
-## END FIXME
-
-
-## FIXME: this should be a separate macro
-##
-AC_ARG_WITH(pic,
-[ --with-pic try to use only PIC/non-PIC objects [default=use both]],
-pic_mode="$withval", pic_mode=default)
-test -z "$pic_mode" && pic_mode=default
-
-# We assume here that the value for lt_cv_prog_cc_pic will not be cached
-# in isolation, and that seeing it set (from the cache) indicates that
-# the associated values are set (in the cache) correctly too.
-AC_MSG_CHECKING([for $compiler option to produce PIC])
-AC_CACHE_VAL(lt_cv_prog_cc_pic,
-[ lt_cv_prog_cc_pic=
- lt_cv_prog_cc_shlib=
- lt_cv_prog_cc_wl=
- lt_cv_prog_cc_static=
- lt_cv_prog_cc_no_builtin=
- lt_cv_prog_cc_can_build_shared=$can_build_shared
-
- if test "$GCC" = yes; then
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static='-static'
-
- case $host_os in
- aix*)
- # Below there is a dirty hack to force normal static linking with -ldl
- # The problem is because libdl dynamically linked with both libc and
- # libC (AIX C++ library), which obviously doesn't included in libraries
- # list by gcc. This cause undefined symbols with -static flags.
- # This hack allows C programs to be linked with "-static -ldl", but
- # not sure about C++ programs.
- lt_cv_prog_cc_static="$lt_cv_prog_cc_static ${lt_cv_prog_cc_wl}-lC"
- ;;
- amigaos*)
- # FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
- lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4'
- ;;
- beos* | irix5* | irix6* | osf3* | osf4* | osf5*)
- # PIC is the default for these OSes.
- ;;
- darwin* | rhapsody*)
- # PIC is the default on this platform
- # Common symbols not allowed in MH_DYLIB files
- lt_cv_prog_cc_pic='-fno-common'
- ;;
- cygwin* | mingw* | pw32* | os2*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- lt_cv_prog_cc_pic='-DDLL_EXPORT'
- ;;
- sysv4*MP*)
- if test -d /usr/nec; then
- lt_cv_prog_cc_pic=-Kconform_pic
- fi
- ;;
- *)
- lt_cv_prog_cc_pic='-fPIC'
- ;;
- esac
- else
- # PORTME Check for PIC flags for the system compiler.
- case $host_os in
- aix3* | aix4* | aix5*)
- lt_cv_prog_cc_wl='-Wl,'
- # All AIX code is PIC.
- if test "$host_cpu" = ia64; then
- # AIX 5 now supports IA64 processor
- lt_cv_prog_cc_static='-Bstatic'
- else
- lt_cv_prog_cc_static='-bnso -bI:/lib/syscalls.exp'
- fi
- ;;
-
- hpux9* | hpux10* | hpux11*)
- # Is there a better lt_cv_prog_cc_static that works with the bundled CC?
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static="${lt_cv_prog_cc_wl}-a ${lt_cv_prog_cc_wl}archive"
- lt_cv_prog_cc_pic='+Z'
- ;;
-
- irix5* | irix6*)
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static='-non_shared'
- # PIC (with -KPIC) is the default.
- ;;
-
- cygwin* | mingw* | pw32* | os2*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- lt_cv_prog_cc_pic='-DDLL_EXPORT'
- ;;
-
- newsos6)
- lt_cv_prog_cc_pic='-KPIC'
- lt_cv_prog_cc_static='-Bstatic'
- ;;
-
- osf3* | osf4* | osf5*)
- # All OSF/1 code is PIC.
- lt_cv_prog_cc_wl='-Wl,'
- lt_cv_prog_cc_static='-non_shared'
- ;;
-
- sco3.2v5*)
- lt_cv_prog_cc_pic='-Kpic'
- lt_cv_prog_cc_static='-dn'
- lt_cv_prog_cc_shlib='-belf'
- ;;
-
- solaris*)
- lt_cv_prog_cc_pic='-KPIC'
- lt_cv_prog_cc_static='-Bstatic'
- lt_cv_prog_cc_wl='-Wl,'
- ;;
-
- sunos4*)
- lt_cv_prog_cc_pic='-PIC'
- lt_cv_prog_cc_static='-Bstatic'
- lt_cv_prog_cc_wl='-Qoption ld '
- ;;
-
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- lt_cv_prog_cc_pic='-KPIC'
- lt_cv_prog_cc_static='-Bstatic'
- if test "x$host_vendor" = xsni; then
- lt_cv_prog_cc_wl='-LD'
- else
- lt_cv_prog_cc_wl='-Wl,'
- fi
- ;;
-
- uts4*)
- lt_cv_prog_cc_pic='-pic'
- lt_cv_prog_cc_static='-Bstatic'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec ;then
- lt_cv_prog_cc_pic='-Kconform_pic'
- lt_cv_prog_cc_static='-Bstatic'
- fi
- ;;
-
- *)
- lt_cv_prog_cc_can_build_shared=no
- ;;
- esac
- fi
-])
-if test -z "$lt_cv_prog_cc_pic"; then
- AC_MSG_RESULT([none])
-else
- AC_MSG_RESULT([$lt_cv_prog_cc_pic])
-
- # Check to make sure the pic_flag actually works.
- AC_MSG_CHECKING([if $compiler PIC flag $lt_cv_prog_cc_pic works])
- AC_CACHE_VAL(lt_cv_prog_cc_pic_works, [dnl
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC"
- AC_TRY_COMPILE([], [], [dnl
- case $host_os in
- hpux9* | hpux10* | hpux11*)
- # On HP-UX, both CC and GCC only warn that PIC is supported... then
- # they create non-PIC objects. So, if there were any warnings, we
- # assume that PIC is not supported.
- if test -s conftest.err; then
- lt_cv_prog_cc_pic_works=no
- else
- lt_cv_prog_cc_pic_works=yes
- fi
- ;;
- *)
- lt_cv_prog_cc_pic_works=yes
- ;;
- esac
- ], [dnl
- lt_cv_prog_cc_pic_works=no
- ])
- CFLAGS="$save_CFLAGS"
- ])
-
- if test "X$lt_cv_prog_cc_pic_works" = Xno; then
- lt_cv_prog_cc_pic=
- lt_cv_prog_cc_can_build_shared=no
- else
- lt_cv_prog_cc_pic=" $lt_cv_prog_cc_pic"
- fi
-
- AC_MSG_RESULT([$lt_cv_prog_cc_pic_works])
-fi
-##
-## END FIXME
-
-# Check for any special shared library compilation flags.
-if test -n "$lt_cv_prog_cc_shlib"; then
- AC_MSG_WARN([\`$CC' requires \`$lt_cv_prog_cc_shlib' to build shared libraries])
- if echo "$old_CC $old_CFLAGS " | egrep -e "[[ ]]$lt_cv_prog_cc_shlib[[ ]]" >/dev/null; then :
- else
- AC_MSG_WARN([add \`$lt_cv_prog_cc_shlib' to the CC or CFLAGS env variable and reconfigure])
- lt_cv_prog_cc_can_build_shared=no
- fi
-fi
-
-## FIXME: this should be a separate macro
-##
-AC_MSG_CHECKING([if $compiler static flag $lt_cv_prog_cc_static works])
-AC_CACHE_VAL([lt_cv_prog_cc_static_works], [dnl
- lt_cv_prog_cc_static_works=no
- save_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static"
- AC_TRY_LINK([], [], [lt_cv_prog_cc_static_works=yes])
- LDFLAGS="$save_LDFLAGS"
-])
-
-# Belt *and* braces to stop my trousers falling down:
-test "X$lt_cv_prog_cc_static_works" = Xno && lt_cv_prog_cc_static=
-AC_MSG_RESULT([$lt_cv_prog_cc_static_works])
-
-pic_flag="$lt_cv_prog_cc_pic"
-special_shlib_compile_flags="$lt_cv_prog_cc_shlib"
-wl="$lt_cv_prog_cc_wl"
-link_static_flag="$lt_cv_prog_cc_static"
-no_builtin_flag="$lt_cv_prog_cc_no_builtin"
-can_build_shared="$lt_cv_prog_cc_can_build_shared"
-##
-## END FIXME
-
-
-## FIXME: this should be a separate macro
-##
-# Check to see if options -o and -c are simultaneously supported by compiler
-AC_MSG_CHECKING([if $compiler supports -c -o file.$ac_objext])
-AC_CACHE_VAL([lt_cv_compiler_c_o], [
-$rm -r conftest 2>/dev/null
-mkdir conftest
-cd conftest
-echo "int some_variable = 0;" > conftest.$ac_ext
-mkdir out
-# According to Tom Tromey, Ian Lance Taylor reported there are C compilers
-# that will create temporary files in the current directory regardless of
-# the output directory. Thus, making CWD read-only will cause this test
-# to fail, enabling locking or at least warning the user not to do parallel
-# builds.
-chmod -w .
-save_CFLAGS="$CFLAGS"
-CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
-compiler_c_o=no
-if { (eval echo configure:__oline__: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s out/conftest.err; then
- lt_cv_compiler_c_o=no
- else
- lt_cv_compiler_c_o=yes
- fi
-else
- # Append any errors to the config.log.
- cat out/conftest.err 1>&AC_FD_CC
- lt_cv_compiler_c_o=no
-fi
-CFLAGS="$save_CFLAGS"
-chmod u+w .
-$rm conftest* out/*
-rmdir out
-cd ..
-rmdir conftest
-$rm -r conftest 2>/dev/null
-])
-compiler_c_o=$lt_cv_compiler_c_o
-AC_MSG_RESULT([$compiler_c_o])
-
-if test x"$compiler_c_o" = x"yes"; then
- # Check to see if we can write to a .lo
- AC_MSG_CHECKING([if $compiler supports -c -o file.lo])
- AC_CACHE_VAL([lt_cv_compiler_o_lo], [
- lt_cv_compiler_o_lo=no
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -c -o conftest.lo"
- save_objext="$ac_objext"
- ac_objext=lo
- AC_TRY_COMPILE([], [int some_variable = 0;], [dnl
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- lt_cv_compiler_o_lo=no
- else
- lt_cv_compiler_o_lo=yes
- fi
- ])
- ac_objext="$save_objext"
- CFLAGS="$save_CFLAGS"
- ])
- compiler_o_lo=$lt_cv_compiler_o_lo
- AC_MSG_RESULT([$compiler_o_lo])
-else
- compiler_o_lo=no
-fi
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-# Check to see if we can do hard links to lock some files if needed
-hard_links="nottested"
-if test "$compiler_c_o" = no && test "$need_locks" != no; then
- # do not overwrite the value of need_locks provided by the user
- AC_MSG_CHECKING([if we can lock with hard links])
- hard_links=yes
- $rm conftest*
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- touch conftest.a
- ln conftest.a conftest.b 2>&5 || hard_links=no
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- AC_MSG_RESULT([$hard_links])
- if test "$hard_links" = no; then
- AC_MSG_WARN([\`$CC' does not support \`-c -o', so \`make -j' may be unsafe])
- need_locks=warn
- fi
-else
- need_locks=no
-fi
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-if test "$GCC" = yes; then
- # Check to see if options -fno-rtti -fno-exceptions are supported by compiler
- AC_MSG_CHECKING([if $compiler supports -fno-rtti -fno-exceptions])
- echo "int some_variable = 0;" > conftest.$ac_ext
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.$ac_ext"
- compiler_rtti_exceptions=no
- AC_TRY_COMPILE([], [int some_variable = 0;], [dnl
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- compiler_rtti_exceptions=no
- else
- compiler_rtti_exceptions=yes
- fi
- ])
- CFLAGS="$save_CFLAGS"
- AC_MSG_RESULT([$compiler_rtti_exceptions])
-
- if test "$compiler_rtti_exceptions" = "yes"; then
- no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions'
- else
- no_builtin_flag=' -fno-builtin'
- fi
-fi
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-# See if the linker supports building shared libraries.
-AC_MSG_CHECKING([whether the linker ($LD) supports shared libraries])
-
-allow_undefined_flag=
-no_undefined_flag=
-need_lib_prefix=unknown
-need_version=unknown
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-archive_cmds=
-archive_expsym_cmds=
-old_archive_from_new_cmds=
-old_archive_from_expsyms_cmds=
-export_dynamic_flag_spec=
-whole_archive_flag_spec=
-thread_safe_flag_spec=
-hardcode_into_libs=no
-hardcode_libdir_flag_spec=
-hardcode_libdir_separator=
-hardcode_direct=no
-hardcode_minus_L=no
-hardcode_shlibpath_var=unsupported
-runpath_var=
-link_all_deplibs=unknown
-always_export_symbols=no
-export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols'
-# include_expsyms should be a list of space-separated symbols to be *always*
-# included in the symbol list
-include_expsyms=
-# exclude_expsyms can be an egrep regular expression of symbols to exclude
-# it will be wrapped by ` (' and `)$', so one must not match beginning or
-# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
-# as well as any symbol that contains `d'.
-exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
-# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
-# platforms (ab)use it in PIC code, but their linkers get confused if
-# the symbol is explicitly referenced. Since portable code cannot
-# rely on this symbol name, it's probably fine to never include it in
-# preloaded symbol tables.
-extract_expsyms_cmds=
-
-case $host_os in
-cygwin* | mingw* | pw32*)
- # FIXME: the MSVC++ port hasn't been tested in a loooong time
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- if test "$GCC" != yes; then
- with_gnu_ld=no
- fi
- ;;
-openbsd*)
- with_gnu_ld=no
- ;;
-esac
-
-ld_shlibs=yes
-if test "$with_gnu_ld" = yes; then
- # If archive_cmds runs LD, not CC, wlarc should be empty
- wlarc='${wl}'
-
- # See if GNU ld supports shared libraries.
- case $host_os in
- aix3* | aix4* | aix5*)
- # On AIX, the GNU linker is very broken
- # Note:Check GNU linker on AIX 5-IA64 when/if it becomes available.
- ld_shlibs=no
- cat <<EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.9.1, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support. If you
-*** really care for shared libraries, you may want to modify your PATH
-*** so that a non-GNU linker is found, and then restart.
-
-EOF
- ;;
-
- amigaos*)
- archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
-
- # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
- # that the semantics of dynamic libraries on AmigaOS, at least up
- # to version 4, is to share data among multiple programs linked
- # with the same dynamic library. Since this doesn't match the
- # behavior of shared libraries on other platforms, we can use
- # them.
- ld_shlibs=no
- ;;
-
- beos*)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- allow_undefined_flag=unsupported
- # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
- # support --undefined. This deserves some investigation. FIXME
- archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- cygwin* | mingw* | pw32*)
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec='-L$libdir'
- allow_undefined_flag=unsupported
- always_export_symbols=yes
-
- extract_expsyms_cmds='test -f $output_objdir/impgen.c || \
- sed -e "/^# \/\* impgen\.c starts here \*\//,/^# \/\* impgen.c ends here \*\// { s/^# //;s/^# *$//; p; }" -e d < $''0 > $output_objdir/impgen.c~
- test -f $output_objdir/impgen.exe || (cd $output_objdir && \
- if test "x$HOST_CC" != "x" ; then $HOST_CC -o impgen impgen.c ; \
- else $CC -o impgen impgen.c ; fi)~
- $output_objdir/impgen $dir/$soroot > $output_objdir/$soname-def'
-
- old_archive_from_expsyms_cmds='$DLLTOOL --as=$AS --dllname $soname --def $output_objdir/$soname-def --output-lib $output_objdir/$newlib'
-
- # cygwin and mingw dlls have different entry points and sets of symbols
- # to exclude.
- # FIXME: what about values for MSVC?
- dll_entry=__cygwin_dll_entry@12
- dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12~
- case $host_os in
- mingw*)
- # mingw values
- dll_entry=_DllMainCRTStartup@12
- dll_exclude_symbols=DllMain@12,DllMainCRTStartup@12,DllEntryPoint@12~
- ;;
- esac
-
- # mingw and cygwin differ, and it's simplest to just exclude the union
- # of the two symbol sets.
- dll_exclude_symbols=DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12,DllMainCRTStartup@12,DllEntryPoint@12
-
- # recent cygwin and mingw systems supply a stub DllMain which the user
- # can override, but on older systems we have to supply one (in ltdll.c)
- if test "x$lt_cv_need_dllmain" = "xyes"; then
- ltdll_obj='$output_objdir/$soname-ltdll.'"$ac_objext "
- ltdll_cmds='test -f $output_objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $''0 > $output_objdir/$soname-ltdll.c~
- test -f $output_objdir/$soname-ltdll.$ac_objext || (cd $output_objdir && $CC -c $soname-ltdll.c)~'
- else
- ltdll_obj=
- ltdll_cmds=
- fi
-
- # Extract the symbol export list from an `--export-all' def file,
- # then regenerate the def file from the symbol export list, so that
- # the compiled dll only exports the symbol export list.
- # Be careful not to strip the DATA tag left be newer dlltools.
- export_symbols_cmds="$ltdll_cmds"'
- $DLLTOOL --export-all --exclude-symbols '$dll_exclude_symbols' --output-def $output_objdir/$soname-def '$ltdll_obj'$libobjs $convenience~
- sed -e "1,/EXPORTS/d" -e "s/ @ [[0-9]]*//" -e "s/ *;.*$//" < $output_objdir/$soname-def > $export_symbols'
-
- # If the export-symbols file already is a .def file (1st line
- # is EXPORTS), use it as is.
- # If DATA tags from a recent dlltool are present, honour them!
- archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then
- cp $export_symbols $output_objdir/$soname-def;
- else
- echo EXPORTS > $output_objdir/$soname-def;
- _lt_hint=1;
- cat $export_symbols | while read symbol; do
- set dummy \$symbol;
- case \[$]# in
- 2) echo " \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;;
- *) echo " \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;;
- esac;
- _lt_hint=`expr 1 + \$_lt_hint`;
- done;
- fi~
- '"$ltdll_cmds"'
- $CC -Wl,--base-file,$output_objdir/$soname-base '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
- $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp~
- $CC -Wl,--base-file,$output_objdir/$soname-base $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags~
- $DLLTOOL --as=$AS --dllname $soname --exclude-symbols '$dll_exclude_symbols' --def $output_objdir/$soname-def --base-file $output_objdir/$soname-base --output-exp $output_objdir/$soname-exp --output-lib $output_objdir/$libname.dll.a~
- $CC $output_objdir/$soname-exp '$lt_cv_cc_dll_switch' -Wl,-e,'$dll_entry' -o $output_objdir/$soname '$ltdll_obj'$libobjs $deplibs $compiler_flags'
- ;;
-
- netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
- wlarc=
- else
- archive_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared -nodefaultlibs $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- fi
- ;;
-
- solaris* | sysv5*)
- if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then
- ld_shlibs=no
- cat <<EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-EOF
- elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- sunos4*)
- archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- wlarc=
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- *)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
- esac
-
- if test "$ld_shlibs" = yes; then
- runpath_var=LD_RUN_PATH
- hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
- export_dynamic_flag_spec='${wl}--export-dynamic'
- case $host_os in
- cygwin* | mingw* | pw32*)
- # dlltool doesn't understand --whole-archive et. al.
- whole_archive_flag_spec=
- ;;
- *)
- # ancient GNU ld didn't support --whole-archive et. al.
- if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then
- whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
- else
- whole_archive_flag_spec=
- fi
- ;;
- esac
- fi
-else
- # PORTME fill in a description of your system's linker (not GNU ld)
- case $host_os in
- aix3*)
- allow_undefined_flag=unsupported
- always_export_symbols=yes
- archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
- # Note: this linker hardcodes the directories in LIBPATH if there
- # are no directories specified by -L.
- hardcode_minus_L=yes
- if test "$GCC" = yes && test -z "$link_static_flag"; then
- # Neither direct hardcoding nor static linking is supported with a
- # broken collect2.
- hardcode_direct=unsupported
- fi
- ;;
-
- aix4* | aix5*)
- if test "$host_cpu" = ia64; then
- # On IA64, the linker does run time linking by default, so we don't
- # have to do anything special.
- aix_use_runtimelinking=no
- exp_sym_flag='-Bexport'
- no_entry_flag=""
- else
- aix_use_runtimelinking=no
-
- # Test if we are trying to use run time linking or normal
- # AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
- case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*)
- for ld_flag in $LDFLAGS; do
- if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
- aix_use_runtimelinking=yes
- break
- fi
- done
- esac
-
- exp_sym_flag='-bexport'
- no_entry_flag='-bnoentry'
- fi
-
- # When large executables or shared objects are built, AIX ld can
- # have problems creating the table of contents. If linking a library
- # or program results in "error TOC overflow" add -mminimal-toc to
- # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
- # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
- hardcode_direct=yes
- archive_cmds=''
- hardcode_libdir_separator=':'
- if test "$GCC" = yes; then
- case $host_os in aix4.[[012]]|aix4.[[012]].*)
- collect2name=`${CC} -print-prog-name=collect2`
- if test -f "$collect2name" && \
- strings "$collect2name" | grep resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- hardcode_direct=yes
- else
- # We have old collect2
- hardcode_direct=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- hardcode_minus_L=yes
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_libdir_separator=
- fi
- esac
-
- shared_flag='-shared'
- else
- # not using gcc
- if test "$host_cpu" = ia64; then
- shared_flag='${wl}-G'
- else
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag='${wl}-G'
- else
- shared_flag='${wl}-bM:SRE'
- fi
- fi
- fi
-
- # It seems that -bexpall can do strange things, so it is better to
- # generate a list of symbols to export.
- always_export_symbols=yes
- if test "$aix_use_runtimelinking" = yes; then
- # Warning - without using the other runtime loading flags (-brtl),
- # -berok will link without error, but may produce a broken library.
- allow_undefined_flag='-berok'
- hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:/usr/lib:/lib'
- archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols $shared_flag"
- else
- if test "$host_cpu" = ia64; then
- hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
- allow_undefined_flag="-z nodefs"
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname ${wl}-h$soname $libobjs $deplibs $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"
- else
- hardcode_libdir_flag_spec='${wl}-bnolibpath ${wl}-blibpath:$libdir:/usr/lib:/lib'
- # Warning - without using the other run time loading flags,
- # -berok will link without error, but may produce a broken library.
- allow_undefined_flag='${wl}-berok'
- # This is a bit strange, but is similar to how AIX traditionally builds
- # it's shared libraries.
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs $compiler_flags ${allow_undefined_flag} '"\${wl}$no_entry_flag \${wl}$exp_sym_flag:\$export_symbols"' ~$AR -crlo $objdir/$libname$release.a $objdir/$soname'
- fi
- fi
- ;;
-
- amigaos*)
- archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- # see comment about different semantics on the GNU ld section
- ld_shlibs=no
- ;;
-
- cygwin* | mingw* | pw32*)
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec=' '
- allow_undefined_flag=unsupported
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # FIXME: Setting linknames here is a bad hack.
- archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames='
- # The linker will automatically build a .lib file if we build a DLL.
- old_archive_from_new_cmds='true'
- # FIXME: Should let the user specify the lib program.
- old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs'
- fix_srcfile_path='`cygpath -w "$srcfile"`'
- ;;
-
- darwin* | rhapsody*)
- case "$host_os" in
- rhapsody* | darwin1.[[012]])
- allow_undefined_flag='-undefined suppress'
- ;;
- *) # Darwin 1.3 on
- allow_undefined_flag='-flat_namespace -undefined suppress'
- ;;
- esac
- # FIXME: Relying on posixy $() will cause problems for
- # cross-compilation, but unfortunately the echo tests do not
- # yet detect zsh echo's removal of \ escapes.
- archive_cmds='$nonopt $(test "x$module" = xyes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring'
- # We need to add '_' to the symbols in $export_symbols first
- #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- whole_archive_flag_spec='-all_load $convenience'
- ;;
-
- freebsd1*)
- ld_shlibs=no
- ;;
-
- # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
- # support. Future versions do this automatically, but an explicit c++rt0.o
- # does not break anything, and helps significantly (at the cost of a little
- # extra space).
- freebsd2.2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- # Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd*)
- archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- hpux9* | hpux10* | hpux11*)
- case $host_os in
- hpux9*) archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ;;
- *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ;;
- esac
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator=:
- hardcode_direct=yes
- hardcode_minus_L=yes # Not in the search PATH, but as the default
- # location of the library.
- export_dynamic_flag_spec='${wl}-E'
- ;;
-
- irix5* | irix6*)
- if test "$GCC" = yes; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- else
- archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
- fi
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- link_all_deplibs=yes
- ;;
-
- netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
- else
- archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
- fi
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- newsos6)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- hardcode_shlibpath_var=no
- ;;
-
- openbsd*)
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- export_dynamic_flag_spec='${wl}-E'
- else
- case "$host_os" in
- openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-R$libdir'
- ;;
- *)
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- ;;
- esac
- fi
- ;;
-
- os2*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- allow_undefined_flag=unsupported
- archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
- old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
- ;;
-
- osf3*)
- if test "$GCC" = yes; then
- allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- else
- allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
- fi
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- ;;
-
- osf4* | osf5*) # as osf3* with the addition of -msym flag
- if test "$GCC" = yes; then
- allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- else
- allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib'
- archive_expsym_cmds='for i in `cat $export_symbols`; do printf "-exported_symbol " >> $lib.exp; echo "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~
- $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib~$rm $lib.exp'
-
- #Both c and cxx compiler support -rpath directly
- hardcode_libdir_flag_spec='-rpath $libdir'
- fi
- hardcode_libdir_separator=:
- ;;
-
- sco3.2v5*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- export_dynamic_flag_spec='${wl}-Bexport'
- ;;
-
- solaris*)
- # gcc --version < 3.0 without binutils cannot create self contained
- # shared libraries reliably, requiring libgcc.a to resolve some of
- # the object symbols generated in some cases. Libraries that use
- # assert need libgcc.a to resolve __eprintf, for example. Linking
- # a copy of libgcc.a into every shared library to guarantee resolving
- # such symbols causes other problems: According to Tim Van Holder
- # <tim.van.holder@pandora.be>, C++ libraries end up with a separate
- # (to the application) exception stack for one thing.
- no_undefined_flag=' -z defs'
- if test "$GCC" = yes; then
- case `$CC --version 2>/dev/null` in
- [[12]].*)
- cat <<EOF 1>&2
-
-*** Warning: Releases of GCC earlier than version 3.0 cannot reliably
-*** create self contained shared libraries on Solaris systems, without
-*** introducing a dependency on libgcc.a. Therefore, libtool is disabling
-*** -no-undefined support, which will at least allow you to build shared
-*** libraries. However, you may find that when you link such libraries
-*** into an application without using GCC, you have to manually add
-*** \`gcc --print-libgcc-file-name\` to the link command. We urge you to
-*** upgrade to a newer version of GCC. Another option is to rebuild your
-*** current GCC to use the GNU linker from GNU binutils 2.9.1 or newer.
-
-EOF
- no_undefined_flag=
- ;;
- esac
- fi
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_shlibpath_var=no
- case $host_os in
- solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
- *) # Supported since Solaris 2.6 (maybe 2.5.1?)
- whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
- esac
- link_all_deplibs=yes
- ;;
-
- sunos4*)
- if test "x$host_vendor" = xsequent; then
- # Use $CC to link under sequent, because it throws in some extra .o
- # files that make .init and .fini sections work.
- archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
- fi
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- sysv4)
- if test "x$host_vendor" = xsno; then
- archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes # is this really true???
- else
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=no #Motorola manual says yes, but my tests say they lie
- fi
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
- ;;
-
- sysv4.3*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- export_dynamic_flag_spec='-Bexport'
- ;;
-
- sysv5*)
- no_undefined_flag=' -z text'
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp'
- hardcode_libdir_flag_spec=
- hardcode_shlibpath_var=no
- runpath_var='LD_RUN_PATH'
- ;;
-
- uts4*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- dgux*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ld_shlibs=yes
- fi
- ;;
-
- sysv4.2uw2*)
- archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_minus_L=no
- hardcode_shlibpath_var=no
- hardcode_runpath_var=yes
- runpath_var=LD_RUN_PATH
- ;;
-
- sysv5uw7* | unixware7*)
- no_undefined_flag='${wl}-z ${wl}text'
- if test "$GCC" = yes; then
- archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$CC -G ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
- fi
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
- ;;
-
- *)
- ld_shlibs=no
- ;;
- esac
-fi
-AC_MSG_RESULT([$ld_shlibs])
-test "$ld_shlibs" = no && can_build_shared=no
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-# Check hardcoding attributes.
-AC_MSG_CHECKING([how to hardcode library paths into programs])
-hardcode_action=
-if test -n "$hardcode_libdir_flag_spec" || \
- test -n "$runpath_var"; then
-
- # We can hardcode non-existant directories.
- if test "$hardcode_direct" != no &&
- # If the only mechanism to avoid hardcoding is shlibpath_var, we
- # have to relink, otherwise we might link with an installed library
- # when we should be linking with a yet-to-be-installed one
- ## test "$hardcode_shlibpath_var" != no &&
- test "$hardcode_minus_L" != no; then
- # Linking always hardcodes the temporary library directory.
- hardcode_action=relink
- else
- # We can link without hardcoding, and we can hardcode nonexisting dirs.
- hardcode_action=immediate
- fi
-else
- # We cannot hardcode anything, or else we can only hardcode existing
- # directories.
- hardcode_action=unsupported
-fi
-AC_MSG_RESULT([$hardcode_action])
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-striplib=
-old_striplib=
-AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-##
-## END FIXME
-
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-## FIXME: this should be a separate macro
-##
-# PORTME Fill in your ld.so characteristics
-AC_MSG_CHECKING([dynamic linker characteristics])
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-
-case $host_os in
-aix3*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix $libname.a'
- shlibpath_var=LIBPATH
-
- # AIX has no versioning support, so we append a major version to the name.
- soname_spec='${libname}${release}.so$major'
- ;;
-
-aix4* | aix5*)
- version_type=linux
- if test "$host_cpu" = ia64; then
- # AIX 5 supports IA64
- library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- else
- # With GCC up to 2.95.x, collect2 would create an import file
- # for dependence libraries. The import file would start with
- # the line `#! .'. This would cause the generated library to
- # depend on `.', always an invalid library. This was fixed in
- # development snapshots of GCC prior to 3.0.
- case $host_os in
- aix4 | aix4.[[01]] | aix4.[[01]].*)
- if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
- echo ' yes '
- echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then
- :
- else
- can_build_shared=no
- fi
- ;;
- esac
- # AIX (on Power*) has no versioning support, so currently we can
- # not hardcode correct soname into executable. Probably we can
- # add versioning support to collect2, so additional links can
- # be useful in future.
- if test "$aix_use_runtimelinking" = yes; then
- # If using run time linking (on AIX 4.2 or later) use lib<name>.so
- # instead of lib<name>.a to let people know that these are not
- # typical AIX shared libraries.
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- else
- # We preserve .a as extension for shared libraries through AIX4.2
- # and later when we are not doing run time linking.
- library_names_spec='${libname}${release}.a $libname.a'
- soname_spec='${libname}${release}.so$major'
- fi
- shlibpath_var=LIBPATH
- fi
- ;;
-
-amigaos*)
- library_names_spec='$libname.ixlibrary $libname.a'
- # Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done'
- ;;
-
-beos*)
- library_names_spec='${libname}.so'
- dynamic_linker="$host_os ld.so"
- shlibpath_var=LIBRARY_PATH
- ;;
-
-bsdi4*)
- version_type=linux
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
- sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
- export_dynamic_flag_spec=-rdynamic
- # the default ld.so.conf also contains /usr/contrib/lib and
- # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
- # libtool to hard-code these into programs
- ;;
-
-cygwin* | mingw* | pw32*)
- version_type=windows
- need_version=no
- need_lib_prefix=no
- case $GCC,$host_os in
- yes,cygwin*)
- library_names_spec='$libname.dll.a'
- soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll'
- postinstall_cmds='dlpath=`bash 2>&1 -c '\''. $dir/${file}i;echo \$dlname'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog .libs/$dlname \$dldir/$dlname'
- postuninstall_cmds='dldll=`bash 2>&1 -c '\''. $file; echo \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $rm \$dlpath'
- ;;
- yes,mingw*)
- library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll'
- sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"`
- ;;
- yes,pw32*)
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll'
- ;;
- *)
- library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll $libname.lib'
- ;;
- esac
- dynamic_linker='Win32 ld.exe'
- # FIXME: first we should search . and the directory the executable is in
- shlibpath_var=PATH
- ;;
-
-darwin* | rhapsody*)
- dynamic_linker="$host_os dyld"
- version_type=darwin
- need_lib_prefix=no
- need_version=no
- # FIXME: Relying on posixy $() will cause problems for
- # cross-compilation, but unfortunately the echo tests do not
- # yet detect zsh echo's removal of \ escapes.
- library_names_spec='${libname}${release}${versuffix}.$(test .$module = .yes && echo so || echo dylib) ${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib) ${libname}.$(test .$module = .yes && echo so || echo dylib)'
- soname_spec='${libname}${release}${major}.$(test .$module = .yes && echo so || echo dylib)'
- shlibpath_overrides_runpath=yes
- shlibpath_var=DYLD_LIBRARY_PATH
- ;;
-
-freebsd1*)
- dynamic_linker=no
- ;;
-
-freebsd*)
- objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
- version_type=freebsd-$objformat
- case $version_type in
- freebsd-elf*)
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
- need_version=no
- need_lib_prefix=no
- ;;
- freebsd-*)
- library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix'
- need_version=yes
- ;;
- esac
- shlibpath_var=LD_LIBRARY_PATH
- case $host_os in
- freebsd2*)
- shlibpath_overrides_runpath=yes
- ;;
- *)
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
- esac
- ;;
-
-gnu*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- hardcode_into_libs=yes
- ;;
-
-hpux9* | hpux10* | hpux11*)
- # Give a soname corresponding to the major version so that dld.sl refuses to
- # link against other versions.
- dynamic_linker="$host_os dld.sl"
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- shlibpath_var=SHLIB_PATH
- shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl'
- soname_spec='${libname}${release}.sl$major'
- # HP-UX runs *really* slowly unless shared libraries are mode 555.
- postinstall_cmds='chmod 555 $lib'
- ;;
-
-irix5* | irix6*)
- version_type=irix
- need_lib_prefix=no
- need_version=no
- soname_spec='${libname}${release}.so$major'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so'
- case $host_os in
- irix5*)
- libsuff= shlibsuff=
- ;;
- *)
- case $LD in # libtool.m4 will add one of these switches to LD
- *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;;
- *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;;
- *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;;
- *) libsuff= shlibsuff= libmagic=never-match;;
- esac
- ;;
- esac
- shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
- sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
- ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*)
- dynamic_linker=no
- ;;
-
-# This must be Linux ELF.
-linux-gnu*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- # This implies no fast_install, which is unacceptable.
- # Some rework will be needed to allow for fast_install
- # before this can be enabled.
- hardcode_into_libs=yes
-
- # We used to test for /lib/ld.so.1 and disable shared libraries on
- # powerpc, because MkLinux only supported shared libraries with the
- # GNU dynamic linker. Since this was broken with cross compilers,
- # most powerpc-linux boxes support dynamic linking these days and
- # people can always --disable-shared, the test was removed, and we
- # assume the GNU/Linux dynamic linker is in use.
- dynamic_linker='GNU/Linux ld.so'
- ;;
-
-netbsd*)
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- dynamic_linker='NetBSD (a.out) ld.so'
- else
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so'
- soname_spec='${libname}${release}.so$major'
- dynamic_linker='NetBSD ld.elf_so'
- fi
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
-
-newsos6)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- ;;
-
-openbsd*)
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- case "$host_os" in
- openbsd2.[[89]] | openbsd2.[[89]].*)
- shlibpath_overrides_runpath=no
- ;;
- *)
- shlibpath_overrides_runpath=yes
- ;;
- esac
- else
- shlibpath_overrides_runpath=yes
- fi
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-os2*)
- libname_spec='$name'
- need_lib_prefix=no
- library_names_spec='$libname.dll $libname.a'
- dynamic_linker='OS/2 ld.exe'
- shlibpath_var=LIBPATH
- ;;
-
-osf3* | osf4* | osf5*)
- version_type=osf
- need_version=no
- soname_spec='${libname}${release}.so'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
- ;;
-
-sco3.2v5*)
- version_type=osf
- soname_spec='${libname}${release}.so$major'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-solaris*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- # ldd complains unless libraries are executable
- postinstall_cmds='chmod +x $lib'
- ;;
-
-sunos4*)
- version_type=sunos
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- if test "$with_gnu_ld" = yes; then
- need_lib_prefix=no
- fi
- need_version=yes
- ;;
-
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- case $host_vendor in
- sni)
- shlibpath_overrides_runpath=no
- ;;
- motorola)
- need_lib_prefix=no
- need_version=no
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
- ;;
- esac
- ;;
-
-uts4*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-dgux*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-sysv4*MP*)
- if test -d /usr/nec ;then
- version_type=linux
- library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so'
- soname_spec='$libname.so.$major'
- shlibpath_var=LD_LIBRARY_PATH
- fi
- ;;
-
-*)
- dynamic_linker=no
- ;;
-esac
-AC_MSG_RESULT([$dynamic_linker])
-test "$dynamic_linker" = no && can_build_shared=no
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-# Report the final consequences.
-AC_MSG_CHECKING([if libtool supports shared libraries])
-AC_MSG_RESULT([$can_build_shared])
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-AC_MSG_CHECKING([whether to build shared libraries])
-test "$can_build_shared" = "no" && enable_shared=no
-
-# On AIX, shared libraries and static libraries use the same namespace, and
-# are all built from PIC.
-case "$host_os" in
-aix3*)
- test "$enable_shared" = yes && enable_static=no
- if test -n "$RANLIB"; then
- archive_cmds="$archive_cmds~\$RANLIB \$lib"
- postinstall_cmds='$RANLIB $lib'
- fi
- ;;
-
-aix4*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
- fi
- ;;
-esac
-AC_MSG_RESULT([$enable_shared])
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-AC_MSG_CHECKING([whether to build static libraries])
-# Make sure either enable_shared or enable_static is yes.
-test "$enable_shared" = yes || enable_static=yes
-AC_MSG_RESULT([$enable_static])
-##
-## END FIXME
-
-if test "$hardcode_action" = relink; then
- # Fast installation is not supported
- enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
- test "$enable_shared" = no; then
- # Fast installation is not necessary
- enable_fast_install=needless
-fi
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-AC_LIBTOOL_DLOPEN_SELF
-
-## FIXME: this should be a separate macro
-##
-if test "$enable_shared" = yes && test "$GCC" = yes; then
- case $archive_cmds in
- *'~'*)
- # FIXME: we may have to deal with multi-command sequences.
- ;;
- '$CC '*)
- # Test whether the compiler implicitly links with -lc since on some
- # systems, -lgcc has to come before -lc. If gcc already passes -lc
- # to ld, don't add -lc before -lgcc.
- AC_MSG_CHECKING([whether -lc should be explicitly linked in])
- AC_CACHE_VAL([lt_cv_archive_cmds_need_lc],
- [$rm conftest*
- echo 'static int dummy;' > conftest.$ac_ext
-
- if AC_TRY_EVAL(ac_compile); then
- soname=conftest
- lib=conftest
- libobjs=conftest.$ac_objext
- deplibs=
- wl=$lt_cv_prog_cc_wl
- compiler_flags=-v
- linker_flags=-v
- verstring=
- output_objdir=.
- libname=conftest
- save_allow_undefined_flag=$allow_undefined_flag
- allow_undefined_flag=
- if AC_TRY_EVAL(archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1)
- then
- lt_cv_archive_cmds_need_lc=no
- else
- lt_cv_archive_cmds_need_lc=yes
- fi
- allow_undefined_flag=$save_allow_undefined_flag
- else
- cat conftest.err 1>&5
- fi])
- AC_MSG_RESULT([$lt_cv_archive_cmds_need_lc])
- ;;
- esac
-fi
-need_lc=${lt_cv_archive_cmds_need_lc-yes}
-##
-## END FIXME
-
-## FIXME: this should be a separate macro
-##
-# The second clause should only fire when bootstrapping the
-# libtool distribution, otherwise you forgot to ship ltmain.sh
-# with your package, and you will get complaints that there are
-# no rules to generate ltmain.sh.
-if test -f "$ltmain"; then
- :
-else
- # If there is no Makefile yet, we rely on a make rule to execute
- # `config.status --recheck' to rerun these tests and create the
- # libtool script then.
- test -f Makefile && make "$ltmain"
-fi
-
-if test -f "$ltmain"; then
- trap "$rm \"${ofile}T\"; exit 1" 1 2 15
- $rm -f "${ofile}T"
-
- echo creating $ofile
-
- # Now quote all the things that may contain metacharacters while being
- # careful not to overquote the AC_SUBSTed values. We take copies of the
- # variables and quote the copies for generation of the libtool script.
- for var in echo old_CC old_CFLAGS \
- AR AR_FLAGS CC LD LN_S NM SHELL \
- reload_flag reload_cmds wl \
- pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \
- thread_safe_flag_spec whole_archive_flag_spec libname_spec \
- library_names_spec soname_spec \
- RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \
- old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds \
- postuninstall_cmds extract_expsyms_cmds old_archive_from_expsyms_cmds \
- old_striplib striplib file_magic_cmd export_symbols_cmds \
- deplibs_check_method allow_undefined_flag no_undefined_flag \
- finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \
- global_symbol_to_c_name_address \
- hardcode_libdir_flag_spec hardcode_libdir_separator \
- sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
- compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do
-
- case $var in
- reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \
- old_postinstall_cmds | old_postuninstall_cmds | \
- export_symbols_cmds | archive_cmds | archive_expsym_cmds | \
- extract_expsyms_cmds | old_archive_from_expsyms_cmds | \
- postinstall_cmds | postuninstall_cmds | \
- finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
- # Double-quote double-evaled strings.
- eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
- ;;
- *)
- eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
- ;;
- esac
- done
-
- cat <<__EOF__ > "${ofile}T"
-#! $SHELL
-
-# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-#
-# Copyright (C) 1996-2000 Free Software Foundation, Inc.
-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="sed -e s/^X//"
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
-
-# ### BEGIN LIBTOOL CONFIG
-
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-
-# Shell to use when invoking shell scripts.
-SHELL=$lt_SHELL
-
-# Whether or not to build shared libraries.
-build_libtool_libs=$enable_shared
-
-# Whether or not to build static libraries.
-build_old_libs=$enable_static
-
-# Whether or not to add -lc for building shared libraries.
-build_libtool_need_lc=$need_lc
-
-# Whether or not to optimize for fast installation.
-fast_install=$enable_fast_install
-
-# The host system.
-host_alias=$host_alias
-host=$host
-
-# An echo program that does not interpret backslashes.
-echo=$lt_echo
-
-# The archiver.
-AR=$lt_AR
-AR_FLAGS=$lt_AR_FLAGS
-
-# The default C compiler.
-CC=$lt_CC
-
-# Is the compiler the GNU C compiler?
-with_gcc=$GCC
-
-# The linker used to build libraries.
-LD=$lt_LD
-
-# Whether we need hard or soft links.
-LN_S=$lt_LN_S
-
-# A BSD-compatible nm program.
-NM=$lt_NM
-
-# A symbol stripping program
-STRIP=$STRIP
-
-# Used to examine libraries when file_magic_cmd begins "file"
-MAGIC_CMD=$MAGIC_CMD
-
-# Used on cygwin: DLL creation program.
-DLLTOOL="$DLLTOOL"
-
-# Used on cygwin: object dumper.
-OBJDUMP="$OBJDUMP"
-
-# Used on cygwin: assembler.
-AS="$AS"
-
-# The name of the directory that contains temporary libtool files.
-objdir=$objdir
-
-# How to create reloadable object files.
-reload_flag=$lt_reload_flag
-reload_cmds=$lt_reload_cmds
-
-# How to pass a linker flag through the compiler.
-wl=$lt_wl
-
-# Object file suffix (normally "o").
-objext="$ac_objext"
-
-# Old archive suffix (normally "a").
-libext="$libext"
-
-# Executable file suffix (normally "").
-exeext="$exeext"
-
-# Additional compiler flags for building library objects.
-pic_flag=$lt_pic_flag
-pic_mode=$pic_mode
-
-# Does compiler simultaneously support -c and -o options?
-compiler_c_o=$lt_compiler_c_o
-
-# Can we write directly to a .lo ?
-compiler_o_lo=$lt_compiler_o_lo
-
-# Must we lock files when doing compilation ?
-need_locks=$lt_need_locks
-
-# Do we need the lib prefix for modules?
-need_lib_prefix=$need_lib_prefix
-
-# Do we need a version for libraries?
-need_version=$need_version
-
-# Whether dlopen is supported.
-dlopen_support=$enable_dlopen
-
-# Whether dlopen of programs is supported.
-dlopen_self=$enable_dlopen_self
-
-# Whether dlopen of statically linked programs is supported.
-dlopen_self_static=$enable_dlopen_self_static
-
-# Compiler flag to prevent dynamic linking.
-link_static_flag=$lt_link_static_flag
-
-# Compiler flag to turn off builtin functions.
-no_builtin_flag=$lt_no_builtin_flag
-
-# Compiler flag to allow reflexive dlopens.
-export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
-
-# Compiler flag to generate shared objects directly from archives.
-whole_archive_flag_spec=$lt_whole_archive_flag_spec
-
-# Compiler flag to generate thread-safe objects.
-thread_safe_flag_spec=$lt_thread_safe_flag_spec
-
-# Library versioning type.
-version_type=$version_type
-
-# Format of library name prefix.
-libname_spec=$lt_libname_spec
-
-# List of archive names. First name is the real one, the rest are links.
-# The last name is the one that the linker finds with -lNAME.
-library_names_spec=$lt_library_names_spec
-
-# The coded name of the library, if different from the real name.
-soname_spec=$lt_soname_spec
-
-# Commands used to build and install an old-style archive.
-RANLIB=$lt_RANLIB
-old_archive_cmds=$lt_old_archive_cmds
-old_postinstall_cmds=$lt_old_postinstall_cmds
-old_postuninstall_cmds=$lt_old_postuninstall_cmds
-
-# Create an old-style archive from a shared archive.
-old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
-
-# Create a temporary old-style archive to link instead of a shared archive.
-old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
-
-# Commands used to build and install a shared archive.
-archive_cmds=$lt_archive_cmds
-archive_expsym_cmds=$lt_archive_expsym_cmds
-postinstall_cmds=$lt_postinstall_cmds
-postuninstall_cmds=$lt_postuninstall_cmds
-
-# Commands to strip libraries.
-old_striplib=$lt_old_striplib
-striplib=$lt_striplib
-
-# Method to check whether dependent libraries are shared objects.
-deplibs_check_method=$lt_deplibs_check_method
-
-# Command to use when deplibs_check_method == file_magic.
-file_magic_cmd=$lt_file_magic_cmd
-
-# Flag that allows shared libraries with undefined symbols to be built.
-allow_undefined_flag=$lt_allow_undefined_flag
-
-# Flag that forces no undefined symbols.
-no_undefined_flag=$lt_no_undefined_flag
-
-# Commands used to finish a libtool library installation in a directory.
-finish_cmds=$lt_finish_cmds
-
-# Same as above, but a single script fragment to be evaled but not shown.
-finish_eval=$lt_finish_eval
-
-# Take the output of nm and produce a listing of raw symbols and C names.
-global_symbol_pipe=$lt_global_symbol_pipe
-
-# Transform the output of nm in a proper C declaration
-global_symbol_to_cdecl=$lt_global_symbol_to_cdecl
-
-# Transform the output of nm in a C name address pair
-global_symbol_to_c_name_address=$lt_global_symbol_to_c_name_address
-
-# This is the shared library runtime path variable.
-runpath_var=$runpath_var
-
-# This is the shared library path variable.
-shlibpath_var=$shlibpath_var
-
-# Is shlibpath searched before the hard-coded library search path?
-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
-
-# How to hardcode a shared library path into an executable.
-hardcode_action=$hardcode_action
-
-# Whether we should hardcode library paths into libraries.
-hardcode_into_libs=$hardcode_into_libs
-
-# Flag to hardcode \$libdir into a binary during linking.
-# This must work even if \$libdir does not exist.
-hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
-
-# Whether we need a single -rpath flag with a separated argument.
-hardcode_libdir_separator=$lt_hardcode_libdir_separator
-
-# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
-# resulting binary.
-hardcode_direct=$hardcode_direct
-
-# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
-# resulting binary.
-hardcode_minus_L=$hardcode_minus_L
-
-# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
-# the resulting binary.
-hardcode_shlibpath_var=$hardcode_shlibpath_var
-
-# Variables whose values should be saved in libtool wrapper scripts and
-# restored at relink time.
-variables_saved_for_relink="$variables_saved_for_relink"
-
-# Whether libtool must link a program against all its dependency libraries.
-link_all_deplibs=$link_all_deplibs
-
-# Compile-time system search path for libraries
-sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
-
-# Run-time system search path for libraries
-sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
-
-# Fix the shell variable \$srcfile for the compiler.
-fix_srcfile_path="$fix_srcfile_path"
-
-# Set to yes if exported symbols are required.
-always_export_symbols=$always_export_symbols
-
-# The commands to list exported symbols.
-export_symbols_cmds=$lt_export_symbols_cmds
-
-# The commands to extract the exported symbol list from a shared archive.
-extract_expsyms_cmds=$lt_extract_expsyms_cmds
-
-# Symbols that should not be listed in the preloaded symbols.
-exclude_expsyms=$lt_exclude_expsyms
-
-# Symbols that must always be exported.
-include_expsyms=$lt_include_expsyms
-
-# ### END LIBTOOL CONFIG
-
-__EOF__
-
- case $host_os in
- aix3*)
- cat <<\EOF >> "${ofile}T"
-
-# AIX sometimes has problems with the GCC collect2 program. For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
- COLLECT_NAMES=
- export COLLECT_NAMES
-fi
-EOF
- ;;
- esac
-
- case $host_os in
- cygwin* | mingw* | pw32* | os2*)
- cat <<'EOF' >> "${ofile}T"
- # This is a source program that is used to create dlls on Windows
- # Don't remove nor modify the starting and closing comments
-# /* ltdll.c starts here */
-# #define WIN32_LEAN_AND_MEAN
-# #include <windows.h>
-# #undef WIN32_LEAN_AND_MEAN
-# #include <stdio.h>
-#
-# #ifndef __CYGWIN__
-# # ifdef __CYGWIN32__
-# # define __CYGWIN__ __CYGWIN32__
-# # endif
-# #endif
-#
-# #ifdef __cplusplus
-# extern "C" {
-# #endif
-# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
-# #ifdef __cplusplus
-# }
-# #endif
-#
-# #ifdef __CYGWIN__
-# #include <cygwin/cygwin_dll.h>
-# DECLARE_CYGWIN_DLL( DllMain );
-# #endif
-# HINSTANCE __hDllInstance_base;
-#
-# BOOL APIENTRY
-# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
-# {
-# __hDllInstance_base = hInst;
-# return TRUE;
-# }
-# /* ltdll.c ends here */
- # This is a source program that is used to create import libraries
- # on Windows for dlls which lack them. Don't remove nor modify the
- # starting and closing comments
-# /* impgen.c starts here */
-# /* Copyright (C) 1999-2000 Free Software Foundation, Inc.
-#
-# This file is part of GNU libtool.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-# */
-#
-# #include <stdio.h> /* for printf() */
-# #include <unistd.h> /* for open(), lseek(), read() */
-# #include <fcntl.h> /* for O_RDONLY, O_BINARY */
-# #include <string.h> /* for strdup() */
-#
-# /* O_BINARY isn't required (or even defined sometimes) under Unix */
-# #ifndef O_BINARY
-# #define O_BINARY 0
-# #endif
-#
-# static unsigned int
-# pe_get16 (fd, offset)
-# int fd;
-# int offset;
-# {
-# unsigned char b[2];
-# lseek (fd, offset, SEEK_SET);
-# read (fd, b, 2);
-# return b[0] + (b[1]<<8);
-# }
-#
-# static unsigned int
-# pe_get32 (fd, offset)
-# int fd;
-# int offset;
-# {
-# unsigned char b[4];
-# lseek (fd, offset, SEEK_SET);
-# read (fd, b, 4);
-# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# static unsigned int
-# pe_as32 (ptr)
-# void *ptr;
-# {
-# unsigned char *b = ptr;
-# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# int
-# main (argc, argv)
-# int argc;
-# char *argv[];
-# {
-# int dll;
-# unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
-# unsigned long export_rva, export_size, nsections, secptr, expptr;
-# unsigned long name_rvas, nexp;
-# unsigned char *expdata, *erva;
-# char *filename, *dll_name;
-#
-# filename = argv[1];
-#
-# dll = open(filename, O_RDONLY|O_BINARY);
-# if (dll < 1)
-# return 1;
-#
-# dll_name = filename;
-#
-# for (i=0; filename[i]; i++)
-# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':')
-# dll_name = filename + i +1;
-#
-# pe_header_offset = pe_get32 (dll, 0x3c);
-# opthdr_ofs = pe_header_offset + 4 + 20;
-# num_entries = pe_get32 (dll, opthdr_ofs + 92);
-#
-# if (num_entries < 1) /* no exports */
-# return 1;
-#
-# export_rva = pe_get32 (dll, opthdr_ofs + 96);
-# export_size = pe_get32 (dll, opthdr_ofs + 100);
-# nsections = pe_get16 (dll, pe_header_offset + 4 +2);
-# secptr = (pe_header_offset + 4 + 20 +
-# pe_get16 (dll, pe_header_offset + 4 + 16));
-#
-# expptr = 0;
-# for (i = 0; i < nsections; i++)
-# {
-# char sname[8];
-# unsigned long secptr1 = secptr + 40 * i;
-# unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
-# unsigned long vsize = pe_get32 (dll, secptr1 + 16);
-# unsigned long fptr = pe_get32 (dll, secptr1 + 20);
-# lseek(dll, secptr1, SEEK_SET);
-# read(dll, sname, 8);
-# if (vaddr <= export_rva && vaddr+vsize > export_rva)
-# {
-# expptr = fptr + (export_rva - vaddr);
-# if (export_rva + export_size > vaddr + vsize)
-# export_size = vsize - (export_rva - vaddr);
-# break;
-# }
-# }
-#
-# expdata = (unsigned char*)malloc(export_size);
-# lseek (dll, expptr, SEEK_SET);
-# read (dll, expdata, export_size);
-# erva = expdata - export_rva;
-#
-# nexp = pe_as32 (expdata+24);
-# name_rvas = pe_as32 (expdata+32);
-#
-# printf ("EXPORTS\n");
-# for (i = 0; i<nexp; i++)
-# {
-# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4);
-# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i);
-# }
-#
-# return 0;
-# }
-# /* impgen.c ends here */
-
-EOF
- ;;
- esac
-
- # We use sed instead of cat because bash on DJGPP gets confused if
- # if finds mixed CR/LF and LF-only lines. Since sed operates in
- # text mode, it properly converts lines to CR/LF. This bash problem
- # is reportedly fixed, but why not run on old versions too?
- sed '$q' "$ltmain" >> "${ofile}T" || (rm -f "${ofile}T"; exit 1)
-
- mv -f "${ofile}T" "$ofile" || \
- (rm -f "$ofile" && cp "${ofile}T" "$ofile" && rm -f "${ofile}T")
- chmod +x "$ofile"
-fi
-##
-## END FIXME
-
-])# _LT_AC_LTCONFIG_HACK
-
-# AC_LIBTOOL_DLOPEN - enable checks for dlopen support
-AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])])
-
-# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's
-AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])])
-
-# AC_ENABLE_SHARED - implement the --enable-shared flag
-# Usage: AC_ENABLE_SHARED[(DEFAULT)]
-# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
-# `yes'.
-AC_DEFUN([AC_ENABLE_SHARED],
-[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(shared,
-changequote(<<, >>)dnl
-<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case $enableval in
-yes) enable_shared=yes ;;
-no) enable_shared=no ;;
-*)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac],
-enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl
-])
-
-# AC_DISABLE_SHARED - set the default shared flag to --disable-shared
-AC_DEFUN([AC_DISABLE_SHARED],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_SHARED(no)])
-
-# AC_ENABLE_STATIC - implement the --enable-static flag
-# Usage: AC_ENABLE_STATIC[(DEFAULT)]
-# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
-# `yes'.
-AC_DEFUN([AC_ENABLE_STATIC],
-[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(static,
-changequote(<<, >>)dnl
-<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case $enableval in
-yes) enable_static=yes ;;
-no) enable_static=no ;;
-*)
- enable_static=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_static=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac],
-enable_static=AC_ENABLE_STATIC_DEFAULT)dnl
-])
-
-# AC_DISABLE_STATIC - set the default static flag to --disable-static
-AC_DEFUN([AC_DISABLE_STATIC],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_STATIC(no)])
-
-
-# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag
-# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)]
-# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
-# `yes'.
-AC_DEFUN([AC_ENABLE_FAST_INSTALL],
-[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(fast-install,
-changequote(<<, >>)dnl
-<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case $enableval in
-yes) enable_fast_install=yes ;;
-no) enable_fast_install=no ;;
-*)
- enable_fast_install=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_fast_install=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac],
-enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl
-])
-
-# AC_DISABLE_FAST_INSTALL - set the default to --disable-fast-install
-AC_DEFUN([AC_DISABLE_FAST_INSTALL],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_FAST_INSTALL(no)])
-
-# AC_LIBTOOL_PICMODE - implement the --with-pic flag
-# Usage: AC_LIBTOOL_PICMODE[(MODE)]
-# Where MODE is either `yes' or `no'. If omitted, it defaults to
-# `both'.
-AC_DEFUN([AC_LIBTOOL_PICMODE],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-pic_mode=ifelse($#,1,$1,default)])
-
-
-# AC_PATH_TOOL_PREFIX - find a file program which can recognise shared library
-AC_DEFUN([AC_PATH_TOOL_PREFIX],
-[AC_MSG_CHECKING([for $1])
-AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
-[case $MAGIC_CMD in
- /*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
- ;;
- ?:/*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path.
- ;;
- *)
- ac_save_MAGIC_CMD="$MAGIC_CMD"
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
-dnl $ac_dummy forces splitting on constant user-supplied paths.
-dnl POSIX.2 word splitting is done only on the output of word expansions,
-dnl not every word. This closes a longstanding sh security hole.
- ac_dummy="ifelse([$2], , $PATH, [$2])"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$1; then
- lt_cv_path_MAGIC_CMD="$ac_dir/$1"
- if test -n "$file_magic_test_file"; then
- case $deplibs_check_method in
- "file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- egrep "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS="$ac_save_ifs"
- MAGIC_CMD="$ac_save_MAGIC_CMD"
- ;;
-esac])
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
-if test -n "$MAGIC_CMD"; then
- AC_MSG_RESULT($MAGIC_CMD)
-else
- AC_MSG_RESULT(no)
-fi
-])
-
-
-# AC_PATH_MAGIC - find a file program which can recognise a shared library
-AC_DEFUN([AC_PATH_MAGIC],
-[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl
-AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin:$PATH)
-if test -z "$lt_cv_path_MAGIC_CMD"; then
- if test -n "$ac_tool_prefix"; then
- AC_PATH_TOOL_PREFIX(file, /usr/bin:$PATH)
- else
- MAGIC_CMD=:
- fi
-fi
-])
-
-
-# AC_PROG_LD - find the path to the GNU or non-GNU linker
-AC_DEFUN([AC_PROG_LD],
-[AC_ARG_WITH(gnu-ld,
-[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
-test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl
-ac_prog=ld
-if test "$GCC" = yes; then
- # Check if gcc -print-prog-name=ld gives a path.
- AC_MSG_CHECKING([for ld used by GCC])
- case $host in
- *-*-mingw*)
- # gcc leaves a trailing carriage return which upsets mingw
- ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
- *)
- ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
- esac
- case $ac_prog in
- # Accept absolute paths.
- [[\\/]]* | [[A-Za-z]]:[[\\/]]*)
- re_direlt='/[[^/]][[^/]]*/\.\./'
- # Canonicalize the path of ld
- ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
- while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
- ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
- done
- test -z "$LD" && LD="$ac_prog"
- ;;
- "")
- # If it fails, then pretend we aren't using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
-elif test "$with_gnu_ld" = yes; then
- AC_MSG_CHECKING([for GNU ld])
-else
- AC_MSG_CHECKING([for non-GNU ld])
-fi
-AC_CACHE_VAL(lt_cv_path_LD,
-[if test -z "$LD"; then
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH; do
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- lt_cv_path_LD="$ac_dir/$ac_prog"
- # Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some GNU ld's only accept -v.
- # Break only if it was the GNU/non-GNU ld that we prefer.
- if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
- test "$with_gnu_ld" != no && break
- else
- test "$with_gnu_ld" != yes && break
- fi
- fi
- done
- IFS="$ac_save_ifs"
-else
- lt_cv_path_LD="$LD" # Let the user override the test with a path.
-fi])
-LD="$lt_cv_path_LD"
-if test -n "$LD"; then
- AC_MSG_RESULT($LD)
-else
- AC_MSG_RESULT(no)
-fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
-AC_PROG_LD_GNU
-])
-
-# AC_PROG_LD_GNU -
-AC_DEFUN([AC_PROG_LD_GNU],
-[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
-[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
-if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
- lt_cv_prog_gnu_ld=yes
-else
- lt_cv_prog_gnu_ld=no
-fi])
-with_gnu_ld=$lt_cv_prog_gnu_ld
-])
-
-# AC_PROG_LD_RELOAD_FLAG - find reload flag for linker
-# -- PORTME Some linkers may need a different reload flag.
-AC_DEFUN([AC_PROG_LD_RELOAD_FLAG],
-[AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag,
-[lt_cv_ld_reload_flag='-r'])
-reload_flag=$lt_cv_ld_reload_flag
-test -n "$reload_flag" && reload_flag=" $reload_flag"
-])
-
-# AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies
-# -- PORTME fill in with the dynamic library characteristics
-AC_DEFUN([AC_DEPLIBS_CHECK_METHOD],
-[AC_CACHE_CHECK([how to recognise dependant libraries],
-lt_cv_deplibs_check_method,
-[lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given egrep regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
-
-case $host_os in
-aix4* | aix5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-beos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-bsdi4*)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- lt_cv_file_magic_test_file=/shlib/libc.so
- ;;
-
-cygwin* | mingw* | pw32*)
- lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- ;;
-
-darwin* | rhapsody*)
- lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- case "$host_os" in
- rhapsody* | darwin1.[[012]])
- lt_cv_file_magic_test_file=`echo /System/Library/Frameworks/System.framework/Versions/*/System | head -1`
- ;;
- *) # Darwin 1.3 on
- lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib'
- ;;
- esac
- ;;
-
-freebsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
- case $host_cpu in
- i*86 )
- # Not sure whether the presence of OpenBSD here was a mistake.
- # Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[[3-9]]86 (compact )?demand paged shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- ;;
- esac
- else
- lt_cv_deplibs_check_method=pass_all
- fi
- ;;
-
-gnu*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-hpux10.20*|hpux11*)
- lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libc.sl
- ;;
-
-irix5* | irix6*)
- case $host_os in
- irix5*)
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1"
- ;;
- *)
- case $LD in
- *-32|*"-32 ") libmagic=32-bit;;
- *-n32|*"-n32 ") libmagic=N32;;
- *-64|*"-64 ") libmagic=64-bit;;
- *) libmagic=never-match;;
- esac
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[[1234]] dynamic lib MIPS - version 1"
- ;;
- esac
- lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*`
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-# This must be Linux ELF.
-linux-gnu*)
- case $host_cpu in
- alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* )
- lt_cv_deplibs_check_method=pass_all ;;
- *)
- # glibc up to 2.1.1 does not perform some relocations on ARM
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;;
- esac
- lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
- ;;
-
-netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then
- lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so\.[[0-9]]+\.[[0-9]]+$'
- else
- lt_cv_deplibs_check_method='match_pattern /lib[[^/\.]]+\.so$'
- fi
- ;;
-
-newos6*)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libnls.so
- ;;
-
-openbsd*)
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB shared object'
- else
- lt_cv_deplibs_check_method='file_magic OpenBSD.* shared library'
- fi
- ;;
-
-osf3* | osf4* | osf5*)
- # this will be overridden with pass_all, but let us keep it just in case
- lt_cv_deplibs_check_method='file_magic COFF format alpha shared library'
- lt_cv_file_magic_test_file=/shlib/libc.so
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sco3.2v5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-solaris*)
- lt_cv_deplibs_check_method=pass_all
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
-
-sysv5uw[[78]]* | sysv4*uw2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- case $host_vendor in
- motorola)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
- ;;
- ncr)
- lt_cv_deplibs_check_method=pass_all
- ;;
- sequent)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
- ;;
- sni)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
- esac
- ;;
-esac
-])
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-])
-
-
-# AC_PROG_NM - find the path to a BSD-compatible name lister
-AC_DEFUN([AC_PROG_NM],
-[AC_REQUIRE([_LT_AC_LIBTOOL_SYS_PATH_SEPARATOR])dnl
-AC_MSG_CHECKING([for BSD-compatible nm])
-AC_CACHE_VAL(lt_cv_path_NM,
-[if test -n "$NM"; then
- # Let the user override the test.
- lt_cv_path_NM="$NM"
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
- test -z "$ac_dir" && ac_dir=.
- tmp_nm=$ac_dir/${ac_tool_prefix}nm
- if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- # Tru64's nm complains that /dev/null is an invalid object file
- if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then
- lt_cv_path_NM="$tmp_nm -B"
- break
- elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
- lt_cv_path_NM="$tmp_nm -p"
- break
- else
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
- fi
- fi
- done
- IFS="$ac_save_ifs"
- test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
-fi])
-NM="$lt_cv_path_NM"
-AC_MSG_RESULT([$NM])
-])
-
-# AC_CHECK_LIBM - check for math library
-AC_DEFUN([AC_CHECK_LIBM],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-LIBM=
-case $host in
-*-*-beos* | *-*-cygwin* | *-*-pw32*)
- # These system don't have libm
- ;;
-*-ncr-sysv4.3*)
- AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
- AC_CHECK_LIB(m, main, LIBM="$LIBM -lm")
- ;;
-*)
- AC_CHECK_LIB(m, main, LIBM="-lm")
- ;;
-esac
-])
-
-# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for
-# the libltdl convenience library and INCLTDL to the include flags for
-# the libltdl header and adds --enable-ltdl-convenience to the
-# configure arguments. Note that LIBLTDL and INCLTDL are not
-# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not
-# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed
-# with '${top_builddir}/' and INCLTDL will be prefixed with
-# '${top_srcdir}/' (note the single quotes!). If your package is not
-# flat and you're not using automake, define top_builddir and
-# top_srcdir appropriately in the Makefiles.
-AC_DEFUN([AC_LIBLTDL_CONVENIENCE],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
- case $enable_ltdl_convenience in
- no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
- "") enable_ltdl_convenience=yes
- ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
- esac
- LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la
- INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
-])
-
-# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for
-# the libltdl installable library and INCLTDL to the include flags for
-# the libltdl header and adds --enable-ltdl-install to the configure
-# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is
-# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed
-# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will
-# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed
-# with '${top_srcdir}/' (note the single quotes!). If your package is
-# not flat and you're not using automake, define top_builddir and
-# top_srcdir appropriately in the Makefiles.
-# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
-AC_DEFUN([AC_LIBLTDL_INSTALLABLE],
-[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
- AC_CHECK_LIB(ltdl, main,
- [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
- [if test x"$enable_ltdl_install" = xno; then
- AC_MSG_WARN([libltdl not installed, but installation disabled])
- else
- enable_ltdl_install=yes
- fi
- ])
- if test x"$enable_ltdl_install" = x"yes"; then
- ac_configure_args="$ac_configure_args --enable-ltdl-install"
- LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la
- INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl'])
- else
- ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
- LIBLTDL="-lltdl"
- INCLTDL=
- fi
-])
-
-# old names
-AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL])
-AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
-AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
-AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
-AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
-AC_DEFUN([AM_PROG_LD], [AC_PROG_LD])
-AC_DEFUN([AM_PROG_NM], [AC_PROG_NM])
-
-# This is just to silence aclocal about the macro not being used
-ifelse([AC_DISABLE_FAST_INSTALL])
diff --git a/boehm-gc/linux_threads.c b/boehm-gc/linux_threads.c
deleted file mode 100644
index b63dfb7fd7e..00000000000
--- a/boehm-gc/linux_threads.c
+++ /dev/null
@@ -1,1728 +0,0 @@
-/*
- * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
- * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
- * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
- * Copyright (c) 2000-2001 by Hewlett-Packard Company. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/*
- * Support code for LinuxThreads, the clone()-based kernel
- * thread package for Linux which is included in libc6.
- *
- * This code relies on implementation details of LinuxThreads,
- * (i.e. properties not guaranteed by the Pthread standard),
- * though this version now does less of that than the other Pthreads
- * support code.
- *
- * Note that there is a lot of code duplication between linux_threads.c
- * and thread support for some of the other Posix platforms; any changes
- * made here may need to be reflected there too.
- */
-/*
- * Linux_threads.c now also includes some code to support HPUX and
- * OSF1 (Compaq Tru64 Unix, really). The OSF1 support is not yet
- * functional. The OSF1 code is based on Eric Benson's
- * patch, though that was originally against hpux_irix_threads. The code
- * here is completely untested. With 0.0000001% probability, it might
- * actually work.
- *
- * Eric also suggested an alternate basis for a lock implementation in
- * his code:
- * + #elif defined(OSF1)
- * + unsigned long GC_allocate_lock = 0;
- * + msemaphore GC_allocate_semaphore;
- * + # define GC_TRY_LOCK() \
- * + ((msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) == 0) \
- * + ? (GC_allocate_lock = 1) \
- * + : 0)
- * + # define GC_LOCK_TAKEN GC_allocate_lock
- */
-
-/* #define DEBUG_THREADS 1 */
-
-/* ANSI C requires that a compilation unit contains something */
-
-# include "gc.h"
-
-# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
- && !defined(GC_IRIX_THREADS)
-
-# include "private/gc_priv.h"
-
-# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
- && !defined(USE_HPUX_TLS)
-# define USE_HPUX_TLS
-# endif
-
-# ifdef THREAD_LOCAL_ALLOC
-# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_HPUX_TLS)
-# include "private/specific.h"
-# endif
-# if defined(USE_PTHREAD_SPECIFIC)
-# define GC_getspecific pthread_getspecific
-# define GC_setspecific pthread_setspecific
-# define GC_key_create pthread_key_create
- typedef pthread_key_t GC_key_t;
-# endif
-# if defined(USE_HPUX_TLS)
-# define GC_getspecific(x) (x)
-# define GC_setspecific(key, v) ((key) = (v), 0)
-# define GC_key_create(key, d) 0
- typedef void * GC_key_t;
-# endif
-# endif
-# include <stdlib.h>
-# include <pthread.h>
-# include <sched.h>
-# include <time.h>
-# include <errno.h>
-# include <unistd.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-# include <semaphore.h>
-# include <signal.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <fcntl.h>
-
-#ifndef __GNUC__
-# define __inline__
-#endif
-
-#ifdef GC_USE_LD_WRAP
-# define WRAP_FUNC(f) __wrap_##f
-# define REAL_FUNC(f) __real_##f
-#else
-# define WRAP_FUNC(f) GC_##f
-# define REAL_FUNC(f) f
-# undef pthread_create
-# undef pthread_sigmask
-# undef pthread_join
-# undef pthread_detach
-#endif
-
-
-void GC_thr_init();
-
-#if 0
-void GC_print_sig_mask()
-{
- sigset_t blocked;
- int i;
-
- if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
- ABORT("pthread_sigmask");
- GC_printf0("Blocked: ");
- for (i = 1; i <= MAXSIG; i++) {
- if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
- }
- GC_printf0("\n");
-}
-#endif
-
-
-/* We use the allocation lock to protect thread-related data structures. */
-
-/* The set of all known threads. We intercept thread creation and */
-/* joins. */
-/* Protected by allocation/GC lock. */
-/* Some of this should be declared volatile, but that's inconsistent */
-/* with some library routine declarations. */
-typedef struct GC_Thread_Rep {
- struct GC_Thread_Rep * next; /* More recently allocated threads */
- /* with a given pthread id come */
- /* first. (All but the first are */
- /* guaranteed to be dead, but we may */
- /* not yet have registered the join.) */
- pthread_t id;
- short flags;
-# define FINISHED 1 /* Thread has exited. */
-# define DETACHED 2 /* Thread is intended to be detached. */
-# define MAIN_THREAD 4 /* True for the original thread only. */
- short thread_blocked; /* Protected by GC lock. */
- /* Treated as a boolean value. If set, */
- /* thread will acquire GC lock before */
- /* doing any pointer manipulations, and */
- /* has set its sp value. Thus it does */
- /* not need to be sent a signal to stop */
- /* it. */
- ptr_t stack_end; /* Cold end of the stack. */
- ptr_t stack_ptr; /* Valid only when stopped. */
-# ifdef IA64
- ptr_t backing_store_end;
- ptr_t backing_store_ptr;
-# endif
- int signal;
- void * status; /* The value returned from the thread. */
- /* Used only to avoid premature */
- /* reclamation of any data it might */
- /* reference. */
-# ifdef THREAD_LOCAL_ALLOC
-# if CPP_WORDSZ == 64 && defined(ALIGN_DOUBLE)
-# define GRANULARITY 16
-# define NFREELISTS 49
-# else
-# define GRANULARITY 8
-# define NFREELISTS 65
-# endif
- /* The ith free list corresponds to size i*GRANULARITY */
-# define INDEX_FROM_BYTES(n) ((ADD_SLOP(n) + GRANULARITY - 1)/GRANULARITY)
-# define BYTES_FROM_INDEX(i) ((i) * GRANULARITY - EXTRA_BYTES)
-# define SMALL_ENOUGH(bytes) (ADD_SLOP(bytes) <= \
- (NFREELISTS-1)*GRANULARITY)
- ptr_t ptrfree_freelists[NFREELISTS];
- ptr_t normal_freelists[NFREELISTS];
-# ifdef GC_GCJ_SUPPORT
- ptr_t gcj_freelists[NFREELISTS];
-# endif
- /* Free lists contain either a pointer or a small count */
- /* reflecting the number of granules allocated at that */
- /* size. */
- /* 0 ==> thread-local allocation in use, free list */
- /* empty. */
- /* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
- /* too few objects of this size have been */
- /* allocated by this thread. */
- /* >= HBLKSIZE => pointer to nonempty free list. */
- /* > DIRECT_GRANULES, < HBLKSIZE ==> transition to */
- /* local alloc, equivalent to 0. */
-# define DIRECT_GRANULES (HBLKSIZE/GRANULARITY)
- /* Don't use local free lists for up to this much */
- /* allocation. */
-# endif
-} * GC_thread;
-
-GC_thread GC_lookup_thread(pthread_t id);
-
-static GC_bool parallel_initialized = FALSE;
-
-# if defined(__GNUC__)
- void GC_init_parallel() __attribute__ ((constructor));
-# else
- void GC_init_parallel();
-# endif
-
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
-
-/* We don't really support thread-local allocation with DBG_HDRS_ALL */
-
-#ifdef USE_HPUX_TLS
- __thread
-#endif
-GC_key_t GC_thread_key;
-
-static GC_bool keys_initialized;
-
-/* Recover the contents of the freelist array fl into the global one gfl.*/
-/* Note that the indexing scheme differs, in that gfl has finer size */
-/* resolution, even if not all entries are used. */
-/* We hold the allocator lock. */
-static void return_freelists(ptr_t *fl, ptr_t *gfl)
-{
- int i;
- ptr_t q, *qptr;
- size_t nwords;
-
- for (i = 1; i < NFREELISTS; ++i) {
- nwords = i * (GRANULARITY/sizeof(word));
- qptr = fl + i;
- q = *qptr;
- if ((word)q < HBLKSIZE) continue;
- if (gfl[nwords] == 0) {
- gfl[nwords] = q;
- } else {
- /* Concatenate: */
- for (; (word)q >= HBLKSIZE; qptr = &(obj_link(q)), q = *qptr);
- GC_ASSERT(0 == q);
- *qptr = gfl[nwords];
- gfl[nwords] = fl[i];
- }
- /* Clear fl[i], since the thread structure may hang around. */
- /* Do it in a way that is likely to trap if we access it. */
- fl[i] = (ptr_t)HBLKSIZE;
- }
-}
-
-/* We statically allocate a single "size 0" object. It is linked to */
-/* itself, and is thus repeatedly reused for all size 0 allocation */
-/* requests. (Size 0 gcj allocation requests are incorrect, and */
-/* we arrange for those to fault asap.) */
-static ptr_t size_zero_object = (ptr_t)(&size_zero_object);
-
-/* Each thread structure must be initialized. */
-/* This call must be made from the new thread. */
-/* Caller holds allocation lock. */
-void GC_init_thread_local(GC_thread p)
-{
- int i;
-
- if (!keys_initialized) {
- if (0 != GC_key_create(&GC_thread_key, 0)) {
- ABORT("Failed to create key for local allocator");
- }
- keys_initialized = TRUE;
- }
- if (0 != GC_setspecific(GC_thread_key, p)) {
- ABORT("Failed to set thread specific allocation pointers");
- }
- for (i = 1; i < NFREELISTS; ++i) {
- p -> ptrfree_freelists[i] = (ptr_t)1;
- p -> normal_freelists[i] = (ptr_t)1;
-# ifdef GC_GCJ_SUPPORT
- p -> gcj_freelists[i] = (ptr_t)1;
-# endif
- }
- /* Set up the size 0 free lists. */
- p -> ptrfree_freelists[0] = (ptr_t)(&size_zero_object);
- p -> normal_freelists[0] = (ptr_t)(&size_zero_object);
-# ifdef GC_GCJ_SUPPORT
- p -> gcj_freelists[0] = (ptr_t)(-1);
-# endif
-}
-
-#ifdef GC_GCJ_SUPPORT
- extern ptr_t * GC_gcjobjfreelist;
-#endif
-
-/* We hold the allocator lock. */
-void GC_destroy_thread_local(GC_thread p)
-{
- /* We currently only do this from the thread itself. */
- GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
- return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
- return_freelists(p -> normal_freelists, GC_objfreelist);
-# ifdef GC_GCJ_SUPPORT
- return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
-# endif
-}
-
-extern GC_PTR GC_generic_malloc_many();
-
-GC_PTR GC_local_malloc(size_t bytes)
-{
- if (EXPECT(!SMALL_ENOUGH(bytes),0)) {
- return(GC_malloc(bytes));
- } else {
- int index = INDEX_FROM_BYTES(bytes);
- ptr_t * my_fl;
- ptr_t my_entry;
- GC_key_t k = GC_thread_key;
- void * tsd;
-
-# if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC) \
- || !defined(__GNUC__)
- if (EXPECT(0 == k, 0)) {
- /* This can happen if we get called when the world is */
- /* being initialized. Whether we can actually complete */
- /* the initialization then is unclear. */
- GC_init_parallel();
- k = GC_thread_key;
- }
-# endif
- tsd = GC_getspecific(GC_thread_key);
-# ifdef GC_ASSERTIONS
- LOCK();
- GC_ASSERT(tsd == (void *)GC_lookup_thread(pthread_self()));
- UNLOCK();
-# endif
- my_fl = ((GC_thread)tsd) -> normal_freelists + index;
- my_entry = *my_fl;
- if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
- ptr_t next = obj_link(my_entry);
- GC_PTR result = (GC_PTR)my_entry;
- *my_fl = next;
- obj_link(my_entry) = 0;
- PREFETCH_FOR_WRITE(next);
- return result;
- } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
- *my_fl = my_entry + index + 1;
- return GC_malloc(bytes);
- } else {
- GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl);
- if (*my_fl == 0) return GC_oom_fn(bytes);
- return GC_local_malloc(bytes);
- }
- }
-}
-
-GC_PTR GC_local_malloc_atomic(size_t bytes)
-{
- if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
- return(GC_malloc_atomic(bytes));
- } else {
- int index = INDEX_FROM_BYTES(bytes);
- ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
- -> ptrfree_freelists + index;
- ptr_t my_entry = *my_fl;
- if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
- GC_PTR result = (GC_PTR)my_entry;
- *my_fl = obj_link(my_entry);
- return result;
- } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
- *my_fl = my_entry + index + 1;
- return GC_malloc_atomic(bytes);
- } else {
- GC_generic_malloc_many(BYTES_FROM_INDEX(index), PTRFREE, my_fl);
- /* *my_fl is updated while the collector is excluded; */
- /* the free list is always visible to the collector as */
- /* such. */
- if (*my_fl == 0) return GC_oom_fn(bytes);
- return GC_local_malloc_atomic(bytes);
- }
- }
-}
-
-#ifdef GC_GCJ_SUPPORT
-
-#include "include/gc_gcj.h"
-
-#ifdef GC_ASSERTIONS
- extern GC_bool GC_gcj_malloc_initialized;
-#endif
-
-extern int GC_gcj_kind;
-
-GC_PTR GC_local_gcj_malloc(size_t bytes,
- void * ptr_to_struct_containing_descr)
-{
- GC_ASSERT(GC_gcj_malloc_initialized);
- if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
- return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
- } else {
- int index = INDEX_FROM_BYTES(bytes);
- ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
- -> gcj_freelists + index;
- ptr_t my_entry = *my_fl;
- if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
- GC_PTR result = (GC_PTR)my_entry;
- GC_ASSERT(!GC_incremental);
- /* We assert that any concurrent marker will stop us. */
- /* Thus it is impossible for a mark procedure to see the */
- /* allocation of the next object, but to see this object */
- /* still containing a free list pointer. Otherwise the */
- /* marker might find a random "mark descriptor". */
- *(volatile ptr_t *)my_fl = obj_link(my_entry);
- /* We must update the freelist before we store the pointer. */
- /* Otherwise a GC at this point would see a corrupted */
- /* free list. */
- /* A memory barrier is probably never needed, since the */
- /* action of stopping this thread will cause prior writes */
- /* to complete. */
- *(void * volatile *)result = ptr_to_struct_containing_descr;
- return result;
- } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
- *my_fl = my_entry + index + 1;
- return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
- } else {
- GC_generic_malloc_many(BYTES_FROM_INDEX(index), GC_gcj_kind, my_fl);
- if (*my_fl == 0) return GC_oom_fn(bytes);
- return GC_local_gcj_malloc(bytes, ptr_to_struct_containing_descr);
- }
- }
-}
-
-#endif /* GC_GCJ_SUPPORT */
-
-# else /* !THREAD_LOCAL_ALLOC && !DBG_HDRS_ALL */
-
-# define GC_destroy_thread_local(t)
-
-# endif /* !THREAD_LOCAL_ALLOC */
-
-/*
- * We use signals to stop threads during GC.
- *
- * Suspended threads wait in signal handler for SIG_THR_RESTART.
- * That's more portable than semaphores or condition variables.
- * (We do use sem_post from a signal handler, but that should be portable.)
- *
- * The thread suspension signal SIG_SUSPEND is now defined in gc_priv.h.
- * Note that we can't just stop a thread; we need it to save its stack
- * pointer(s) and acknowledge.
- */
-
-#ifndef SIG_THR_RESTART
-# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
-# define SIG_THR_RESTART _SIGRTMIN + 5
-# else
-# define SIG_THR_RESTART SIGXCPU
-# endif
-#endif
-
-sem_t GC_suspend_ack_sem;
-
-#if 0
-/*
-To make sure that we're using LinuxThreads and not some other thread
-package, we generate a dummy reference to `pthread_kill_other_threads_np'
-(was `__pthread_initial_thread_bos' but that disappeared),
-which is a symbol defined in LinuxThreads, but (hopefully) not in other
-thread packages.
-
-We no longer do this, since this code is now portable enough that it might
-actually work for something else.
-*/
-void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np;
-#endif /* 0 */
-
-#if defined(SPARC) || defined(IA64)
- extern word GC_save_regs_in_stack();
-#endif
-
-long GC_nprocs = 1; /* Number of processors. We may not have */
- /* access to all of them, but this is as good */
- /* a guess as any ... */
-
-#ifdef PARALLEL_MARK
-
-# ifndef MAX_MARKERS
-# define MAX_MARKERS 16
-# endif
-
-static ptr_t marker_sp[MAX_MARKERS] = {0};
-
-void * GC_mark_thread(void * id)
-{
- word my_mark_no = 0;
-
- marker_sp[(word)id] = GC_approx_sp();
- for (;; ++my_mark_no) {
- /* GC_mark_no is passed only to allow GC_help_marker to terminate */
- /* promptly. This is important if it were called from the signal */
- /* handler or from the GC lock acquisition code. Under Linux, it's */
- /* not safe to call it from a signal handler, since it uses mutexes */
- /* and condition variables. Since it is called only here, the */
- /* argument is unnecessary. */
- if (my_mark_no < GC_mark_no || my_mark_no > GC_mark_no + 2) {
- /* resynchronize if we get far off, e.g. because GC_mark_no */
- /* wrapped. */
- my_mark_no = GC_mark_no;
- }
-# ifdef DEBUG_THREADS
- GC_printf1("Starting mark helper for mark number %ld\n", my_mark_no);
-# endif
- GC_help_marker(my_mark_no);
- }
-}
-
-extern long GC_markers; /* Number of mark threads we would */
- /* like to have. Includes the */
- /* initiating thread. */
-
-pthread_t GC_mark_threads[MAX_MARKERS];
-
-#define PTHREAD_CREATE REAL_FUNC(pthread_create)
-
-static void start_mark_threads()
-{
- unsigned i;
- pthread_attr_t attr;
-
- if (GC_markers > MAX_MARKERS) {
- WARN("Limiting number of mark threads\n", 0);
- GC_markers = MAX_MARKERS;
- }
- if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
-
- if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
- ABORT("pthread_attr_setdetachstate failed");
-
-# ifdef HPUX
- /* Default stack size is usually too small: fix it. */
- /* Otherwise marker threads or GC may run out of */
- /* space. */
-# define MIN_STACK_SIZE (8*HBLKSIZE*sizeof(word))
- {
- size_t old_size;
- int code;
-
- if (pthread_attr_getstacksize(&attr, &old_size) != 0)
- ABORT("pthread_attr_getstacksize failed\n");
- if (old_size < MIN_STACK_SIZE) {
- if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
- ABORT("pthread_attr_getstacksize failed\n");
- }
- }
-# endif /* HPUX */
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Starting %ld marker threads\n", GC_markers - 1);
- }
-# endif
- for (i = 0; i < GC_markers - 1; ++i) {
- if (0 != PTHREAD_CREATE(GC_mark_threads + i, &attr,
- GC_mark_thread, (void *)(word)i)) {
- WARN("Marker thread creation failed, errno = %ld.\n", errno);
- }
- }
-}
-
-#else /* !PARALLEL_MARK */
-
-static __inline__ void start_mark_threads()
-{
-}
-
-#endif /* !PARALLEL_MARK */
-
-void GC_suspend_handler(int sig)
-{
- int dummy;
- pthread_t my_thread = pthread_self();
- GC_thread me;
- sigset_t all_sigs;
- sigset_t old_sigs;
- int i;
- sigset_t mask;
-# ifdef PARALLEL_MARK
- word my_mark_no = GC_mark_no;
- /* Marker can't proceed until we acknowledge. Thus this is */
- /* guaranteed to be the mark_no correspending to our */
- /* suspension, i.e. the marker can't have incremented it yet. */
-# endif
-
- if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
-
-#if DEBUG_THREADS
- GC_printf1("Suspending 0x%x\n", my_thread);
-#endif
-
- me = GC_lookup_thread(my_thread);
- /* The lookup here is safe, since I'm doing this on behalf */
- /* of a thread which holds the allocation lock in order */
- /* to stop the world. Thus concurrent modification of the */
- /* data structure is impossible. */
-# ifdef SPARC
- me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
-# else
- me -> stack_ptr = (ptr_t)(&dummy);
-# endif
-# ifdef IA64
- me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
-# endif
-
- /* Tell the thread that wants to stop the world that this */
- /* thread has been stopped. Note that sem_post() is */
- /* the only async-signal-safe primitive in LinuxThreads. */
- sem_post(&GC_suspend_ack_sem);
-
- /* Wait until that thread tells us to restart by sending */
- /* this thread a SIG_THR_RESTART signal. */
- /* SIG_THR_RESTART should be masked at this point. Thus there */
- /* is no race. */
- if (sigfillset(&mask) != 0) ABORT("sigfillset() failed");
- if (sigdelset(&mask, SIG_THR_RESTART) != 0) ABORT("sigdelset() failed");
-# ifdef NO_SIGNALS
- if (sigdelset(&mask, SIGINT) != 0) ABORT("sigdelset() failed");
- if (sigdelset(&mask, SIGQUIT) != 0) ABORT("sigdelset() failed");
- if (sigdelset(&mask, SIGTERM) != 0) ABORT("sigdelset() failed");
- if (sigdelset(&mask, SIGABRT) != 0) ABORT("sigdelset() failed");
-# endif
- do {
- me->signal = 0;
- sigsuspend(&mask); /* Wait for signal */
- } while (me->signal != SIG_THR_RESTART);
-
-#if DEBUG_THREADS
- GC_printf1("Continuing 0x%x\n", my_thread);
-#endif
-}
-
-void GC_restart_handler(int sig)
-{
- GC_thread me;
-
- if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
-
- /* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
- /* The lookup here is safe, since I'm doing this on behalf */
- /* of a thread which holds the allocation lock in order */
- /* to stop the world. Thus concurrent modification of the */
- /* data structure is impossible. */
- me = GC_lookup_thread(pthread_self());
- me->signal = SIG_THR_RESTART;
-
- /*
- ** Note: even if we didn't do anything useful here,
- ** it would still be necessary to have a signal handler,
- ** rather than ignoring the signals, otherwise
- ** the signals will not be delivered at all, and
- ** will thus not interrupt the sigsuspend() above.
- */
-
-#if DEBUG_THREADS
- GC_printf1("In GC_restart_handler for 0x%x\n", pthread_self());
-#endif
-}
-
-/* Defining INSTALL_LOOPING_SEGV_HANDLER causes SIGSEGV and SIGBUS to */
-/* result in an infinite loop in a signal handler. This can be very */
-/* useful for debugging, since (as of RH7) gdb still seems to have */
-/* serious problems with threads. */
-#ifdef INSTALL_LOOPING_SEGV_HANDLER
-void GC_looping_handler(int sig)
-{
- GC_printf3("Signal %ld in thread %lx, pid %ld\n",
- sig, pthread_self(), getpid());
- for (;;);
-}
-#endif
-
-GC_bool GC_thr_initialized = FALSE;
-
-# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
-volatile GC_thread GC_threads[THREAD_TABLE_SZ];
-
-void GC_push_thread_structures GC_PROTO((void))
-{
- GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
-}
-
-#ifdef THREAD_LOCAL_ALLOC
-/* We must explicitly mark ptrfree and gcj free lists, since the free */
-/* list links wouldn't otherwise be found. We also set them in the */
-/* normal free lists, since that involves touching less memory than if */
-/* we scanned them normally. */
-void GC_mark_thread_local_free_lists(void)
-{
- int i, j;
- GC_thread p;
- ptr_t q;
-
- for (i = 0; i < THREAD_TABLE_SZ; ++i) {
- for (p = GC_threads[i]; 0 != p; p = p -> next) {
- for (j = 1; j < NFREELISTS; ++j) {
- q = p -> ptrfree_freelists[j];
- if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
- q = p -> normal_freelists[j];
- if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
-# ifdef GC_GCJ_SUPPORT
- q = p -> gcj_freelists[j];
- if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
-# endif /* GC_GCJ_SUPPORT */
- }
- }
- }
-}
-#endif /* THREAD_LOCAL_ALLOC */
-
-/* Add a thread to GC_threads. We assume it wasn't already there. */
-/* Caller holds allocation lock. */
-GC_thread GC_new_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- GC_thread result;
- static struct GC_Thread_Rep first_thread;
- static GC_bool first_thread_used = FALSE;
-
- if (!first_thread_used) {
- result = &first_thread;
- first_thread_used = TRUE;
- } else {
- result = (struct GC_Thread_Rep *)
- GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
- }
- if (result == 0) return(0);
- result -> id = id;
- result -> next = GC_threads[hv];
- GC_threads[hv] = result;
- GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
- return(result);
-}
-
-/* Delete a thread from GC_threads. We assume it is there. */
-/* (The code intentionally traps if it wasn't.) */
-/* Caller holds allocation lock. */
-void GC_delete_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (!pthread_equal(p -> id, id)) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
- GC_INTERNAL_FREE(p);
-}
-
-/* If a thread has been joined, but we have not yet */
-/* been notified, then there may be more than one thread */
-/* in the table with the same pthread id. */
-/* This is OK, but we need a way to delete a specific one. */
-void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (p != gc_id) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
- GC_INTERNAL_FREE(p);
-}
-
-/* Return a GC_thread corresponding to a given thread_t. */
-/* Returns 0 if it's not there. */
-/* Caller holds allocation lock or otherwise inhibits */
-/* updates. */
-/* If there is more than one thread with the given id we */
-/* return the most recent one. */
-GC_thread GC_lookup_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
-
- while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
- return(p);
-}
-
-/* There seems to be a very rare thread stopping problem. To help us */
-/* debug that, we save the ids of the stopping thread. */
-pthread_t GC_stopping_thread;
-int GC_stopping_pid;
-
-/* Caller holds allocation lock. */
-void GC_stop_world()
-{
- pthread_t my_thread = pthread_self();
- register int i;
- register GC_thread p;
- register int n_live_threads = 0;
- register int result;
-
- GC_stopping_thread = my_thread; /* debugging only. */
- GC_stopping_pid = getpid(); /* debugging only. */
- /* Make sure all free list construction has stopped before we start. */
- /* No new construction can start, since free list construction is */
- /* required to acquire and release the GC lock before it starts, */
- /* and we have the lock. */
-# ifdef PARALLEL_MARK
- GC_acquire_mark_lock();
- GC_ASSERT(GC_fl_builder_count == 0);
- /* We should have previously waited for it to become zero. */
-# endif /* PARALLEL_MARK */
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> id != my_thread) {
- if (p -> flags & FINISHED) continue;
- if (p -> thread_blocked) /* Will wait */ continue;
- n_live_threads++;
- #if DEBUG_THREADS
- GC_printf1("Sending suspend signal to 0x%x\n", p -> id);
- #endif
- result = pthread_kill(p -> id, SIG_SUSPEND);
- switch(result) {
- case ESRCH:
- /* Not really there anymore. Possible? */
- n_live_threads--;
- break;
- case 0:
- break;
- default:
- ABORT("pthread_kill failed");
- }
- }
- }
- }
- for (i = 0; i < n_live_threads; i++) {
- if (0 != sem_wait(&GC_suspend_ack_sem))
- ABORT("sem_wait in handler failed");
- }
-# ifdef PARALLEL_MARK
- GC_release_mark_lock();
-# endif
- #if DEBUG_THREADS
- GC_printf1("World stopped 0x%x\n", pthread_self());
- #endif
- GC_stopping_thread = 0; /* debugging only */
-}
-
-/* Caller holds allocation lock, and has held it continuously since */
-/* the world stopped. */
-void GC_start_world()
-{
- pthread_t my_thread = pthread_self();
- register int i;
- register GC_thread p;
- register int n_live_threads = 0;
- register int result;
-
-# if DEBUG_THREADS
- GC_printf0("World starting\n");
-# endif
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> id != my_thread) {
- if (p -> flags & FINISHED) continue;
- if (p -> thread_blocked) continue;
- n_live_threads++;
- #if DEBUG_THREADS
- GC_printf1("Sending restart signal to 0x%x\n", p -> id);
- #endif
- result = pthread_kill(p -> id, SIG_THR_RESTART);
- switch(result) {
- case ESRCH:
- /* Not really there anymore. Possible? */
- n_live_threads--;
- break;
- case 0:
- break;
- default:
- ABORT("pthread_kill failed");
- }
- }
- }
- }
- #if DEBUG_THREADS
- GC_printf0("World started\n");
- #endif
-}
-
-# ifdef IA64
-# define IF_IA64(x) x
-# else
-# define IF_IA64(x)
-# endif
-/* We hold allocation lock. Should do exactly the right thing if the */
-/* world is stopped. Should not fail if it isn't. */
-void GC_push_all_stacks()
-{
- int i;
- GC_thread p;
- ptr_t sp = GC_approx_sp();
- ptr_t lo, hi;
- /* On IA64, we also need to scan the register backing store. */
- IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
- pthread_t me = pthread_self();
-
- if (!GC_thr_initialized) GC_thr_init();
- #if DEBUG_THREADS
- GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
- #endif
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> flags & FINISHED) continue;
- if (pthread_equal(p -> id, me)) {
-# ifdef SPARC
- lo = (ptr_t)GC_save_regs_in_stack();
-# else
- lo = GC_approx_sp();
-# endif
- IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
- } else {
- lo = p -> stack_ptr;
- IF_IA64(bs_hi = p -> backing_store_ptr;)
- }
- if ((p -> flags & MAIN_THREAD) == 0) {
- hi = p -> stack_end;
- IF_IA64(bs_lo = p -> backing_store_end);
- } else {
- /* The original stack. */
- hi = GC_stackbottom;
- IF_IA64(bs_lo = BACKING_STORE_BASE;)
- }
- #if DEBUG_THREADS
- GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
- (unsigned long) p -> id,
- (unsigned long) lo, (unsigned long) hi);
- #endif
- if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
-# ifdef STACK_GROWS_UP
- /* We got them backwards! */
- GC_push_all_stack(hi, lo);
-# else
- GC_push_all_stack(lo, hi);
-# endif
-# ifdef IA64
- if (pthread_equal(p -> id, me)) {
- GC_push_all_eager(bs_lo, bs_hi);
- } else {
- GC_push_all_stack(bs_lo, bs_hi);
- }
-# endif
- }
- }
-}
-
-#ifdef USE_PROC_FOR_LIBRARIES
-int GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
-{
- int i;
- GC_thread p;
-
-# ifdef PARALLEL_MARK
- for (i = 0; i < GC_markers; ++i) {
- if (marker_sp[i] > lo & marker_sp[i] < hi) return 1;
- }
-# endif
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (0 != p -> stack_end) {
-# ifdef STACK_GROWS_UP
- if (p -> stack_end >= lo && p -> stack_end < hi) return 1;
-# else /* STACK_GROWS_DOWN */
- if (p -> stack_end > lo && p -> stack_end <= hi) return 1;
-# endif
- }
- }
- }
- return 0;
-}
-#endif /* USE_PROC_FOR_LIBRARIES */
-
-#ifdef GC_LINUX_THREADS
-/* Return the number of processors, or i<= 0 if it can't be determined. */
-int GC_get_nprocs()
-{
- /* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that */
- /* appears to be buggy in many cases. */
- /* We look for lines "cpu<n>" in /proc/stat. */
-# define STAT_BUF_SIZE 4096
-# if defined(GC_USE_LD_WRAP)
-# define STAT_READ __real_read
-# else
-# define STAT_READ read
-# endif
- char stat_buf[STAT_BUF_SIZE];
- int f;
- char c;
- word result = 1;
- /* Some old kernels only have a single "cpu nnnn ..." */
- /* entry in /proc/stat. We identify those as */
- /* uniprocessors. */
- size_t i, len = 0;
-
- f = open("/proc/stat", O_RDONLY);
- if (f < 0 || (len = STAT_READ(f, stat_buf, STAT_BUF_SIZE)) < 100) {
- WARN("Couldn't read /proc/stat\n", 0);
- return -1;
- }
- for (i = 0; i < len - 100; ++i) {
- if (stat_buf[i] == '\n' && stat_buf[i+1] == 'c'
- && stat_buf[i+2] == 'p' && stat_buf[i+3] == 'u') {
- int cpu_no = atoi(stat_buf + i + 4);
- if (cpu_no >= result) result = cpu_no + 1;
- }
- }
- return result;
-}
-#endif /* GC_LINUX_THREADS */
-
-/* We hold the allocation lock. */
-void GC_thr_init()
-{
- int dummy;
- GC_thread t;
- struct sigaction act;
-
- if (GC_thr_initialized) return;
- GC_thr_initialized = TRUE;
-
- if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
- ABORT("sem_init failed");
-
- act.sa_flags = SA_RESTART;
- if (sigfillset(&act.sa_mask) != 0) {
- ABORT("sigfillset() failed");
- }
-# ifdef NO_SIGNALS
- if (sigdelset(&act.sa_mask, SIGINT) != 0
- || sigdelset(&act.sa_mask, SIGQUIT != 0)
- || sigdelset(&act.sa_mask, SIGABRT != 0)
- || sigdelset(&act.sa_mask, SIGTERM != 0)) {
- ABORT("sigdelset() failed");
- }
-# endif
-
- /* SIG_THR_RESTART is unmasked by the handler when necessary. */
- act.sa_handler = GC_suspend_handler;
- if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
- ABORT("Cannot set SIG_SUSPEND handler");
- }
-
- act.sa_handler = GC_restart_handler;
- if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
- ABORT("Cannot set SIG_THR_RESTART handler");
- }
-# ifdef INSTALL_LOOPING_SEGV_HANDLER
- act.sa_handler = GC_looping_handler;
- if (sigaction(SIGSEGV, &act, NULL) != 0
- || sigaction(SIGBUS, &act, NULL) != 0) {
- ABORT("Cannot set SIGSEGV or SIGBUS looping handler");
- }
-# endif /* INSTALL_LOOPING_SEGV_HANDLER */
-
- /* Add the initial thread, so we can stop it. */
- t = GC_new_thread(pthread_self());
- t -> stack_ptr = (ptr_t)(&dummy);
- t -> flags = DETACHED | MAIN_THREAD;
-
- /* Set GC_nprocs. */
- {
- char * nprocs_string = GETENV("GC_NPROCS");
- GC_nprocs = -1;
- if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string);
- }
- if (GC_nprocs <= 0) {
-# if defined(GC_HPUX_THREADS)
- GC_nprocs = pthread_num_processors_np();
-# endif
-# if defined(GC_OSF1_THREADS) || defined(GC_FREEBSD_THREADS)
- GC_nprocs = 1;
-# endif
-# if defined(GC_LINUX_THREADS)
- GC_nprocs = GC_get_nprocs();
-# endif
- }
- if (GC_nprocs <= 0) {
- WARN("GC_get_nprocs() returned %ld\n", GC_nprocs);
- GC_nprocs = 2;
-# ifdef PARALLEL_MARK
- GC_markers = 1;
-# endif
- } else {
-# ifdef PARALLEL_MARK
- GC_markers = GC_nprocs;
-# endif
- }
-# ifdef PARALLEL_MARK
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf2("Number of processors = %ld, "
- "number of marker threads = %ld\n", GC_nprocs, GC_markers);
- }
-# endif
- if (GC_markers == 1) {
- GC_parallel = FALSE;
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0("Single marker thread, turning off parallel marking\n");
- }
-# endif
- } else {
- GC_parallel = TRUE;
- }
-# endif
-}
-
-
-/* Perform all initializations, including those that */
-/* may require allocation. */
-/* Called as constructor without allocation lock. */
-/* Must be called before a second thread is created. */
-/* Called without allocation lock. */
-void GC_init_parallel()
-{
- if (parallel_initialized) return;
- parallel_initialized = TRUE;
- /* GC_init() calls us back, so set flag first. */
- if (!GC_is_initialized) GC_init();
- /* If we are using a parallel marker, start the helper threads. */
-# ifdef PARALLEL_MARK
- if (GC_parallel) start_mark_threads();
-# endif
- /* Initialize thread local free lists if used. */
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
- LOCK();
- GC_init_thread_local(GC_lookup_thread(pthread_self()));
- UNLOCK();
-# endif
-}
-
-
-int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
-{
- sigset_t fudged_set;
-
- if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
- fudged_set = *set;
- sigdelset(&fudged_set, SIG_SUSPEND);
- set = &fudged_set;
- }
- return(REAL_FUNC(pthread_sigmask)(how, set, oset));
-}
-
-/* Wrappers for functions that are likely to block for an appreciable */
-/* length of time. Must be called in pairs, if at all. */
-/* Nothing much beyond the system call itself should be executed */
-/* between these. */
-
-void GC_start_blocking(void) {
-# define SP_SLOP 128
- GC_thread me;
- LOCK();
- me = GC_lookup_thread(pthread_self());
- GC_ASSERT(!(me -> thread_blocked));
-# ifdef SPARC
- me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
-# else
- me -> stack_ptr = (ptr_t)GC_approx_sp();
-# endif
-# ifdef IA64
- me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack() + SP_SLOP;
-# endif
- /* Add some slop to the stack pointer, since the wrapped call may */
- /* end up pushing more callee-save registers. */
-# ifdef STACK_GROWS_UP
- me -> stack_ptr += SP_SLOP;
-# else
- me -> stack_ptr -= SP_SLOP;
-# endif
- me -> thread_blocked = TRUE;
- UNLOCK();
-}
-
-GC_end_blocking(void) {
- GC_thread me;
- LOCK(); /* This will block if the world is stopped. */
- me = GC_lookup_thread(pthread_self());
- GC_ASSERT(me -> thread_blocked);
- me -> thread_blocked = FALSE;
- UNLOCK();
-}
-
-/* A wrapper for the standard C sleep function */
-int WRAP_FUNC(sleep) (unsigned int seconds)
-{
- int result;
-
- GC_start_blocking();
- result = REAL_FUNC(sleep)(seconds);
- GC_end_blocking();
- return result;
-}
-
-struct start_info {
- void *(*start_routine)(void *);
- void *arg;
- word flags;
- sem_t registered; /* 1 ==> in our thread table, but */
- /* parent hasn't yet noticed. */
-};
-
-/* Called at thread exit. */
-/* Never called for main thread. That's OK, since it */
-/* results in at most a tiny one-time leak. And */
-/* linuxthreads doesn't reclaim the main threads */
-/* resources or id anyway. */
-void GC_thread_exit_proc(void *arg)
-{
- GC_thread me;
-
- LOCK();
- me = GC_lookup_thread(pthread_self());
- GC_destroy_thread_local(me);
- if (me -> flags & DETACHED) {
- GC_delete_thread(pthread_self());
- } else {
- me -> flags |= FINISHED;
- }
-# if defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_SPECIFIC) \
- && !defined(USE_HPUX_TLS) && !defined(DBG_HDRS_ALL)
- GC_remove_specific(GC_thread_key);
-# endif
- if (GC_incremental && GC_collection_in_progress()) {
- int old_gc_no = GC_gc_no;
-
- /* Make sure that no part of our stack is still on the mark stack, */
- /* since it's about to be unmapped. */
- while (GC_incremental && GC_collection_in_progress()
- && old_gc_no == GC_gc_no) {
- ENTER_GC();
- GC_collect_a_little_inner(1);
- EXIT_GC();
- UNLOCK();
- sched_yield();
- LOCK();
- }
- }
- UNLOCK();
-}
-
-int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
-{
- int result;
- GC_thread thread_gc_id;
-
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- /* This is guaranteed to be the intended one, since the thread id */
- /* cant have been recycled by pthreads. */
- UNLOCK();
- result = REAL_FUNC(pthread_join)(thread, retval);
-# if defined (GC_FREEBSD_THREADS)
- /* On FreeBSD, the wrapped pthread_join() sometimes returns (what
- appears to be) a spurious EINTR which caused the test and real code
- to gratuitously fail. Having looked at system pthread library source
- code, I see how this return code may be generated. In one path of
- code, pthread_join() just returns the errno setting of the thread
- being joined. This does not match the POSIX specification or the
- local man pages thus I have taken the liberty to catch this one
- spurious return value properly conditionalized on GC_FREEBSD_THREADS. */
- if (result == EINTR) result = 0;
-# endif
- if (result == 0) {
- LOCK();
- /* Here the pthread thread id may have been recycled. */
- GC_delete_gc_thread(thread, thread_gc_id);
- UNLOCK();
- }
- return result;
-}
-
-int
-WRAP_FUNC(pthread_detach)(pthread_t thread)
-{
- int result;
- GC_thread thread_gc_id;
-
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- UNLOCK();
- result = REAL_FUNC(pthread_detach)(thread);
- if (result == 0) {
- LOCK();
- thread_gc_id -> flags |= DETACHED;
- /* Here the pthread thread id may have been recycled. */
- if (thread_gc_id -> flags & FINISHED) {
- GC_delete_gc_thread(thread, thread_gc_id);
- }
- UNLOCK();
- }
- return result;
-}
-
-void * GC_start_routine(void * arg)
-{
- int dummy;
- struct start_info * si = arg;
- void * result;
- GC_thread me;
- pthread_t my_pthread;
- void *(*start)(void *);
- void *start_arg;
-
- my_pthread = pthread_self();
-# ifdef DEBUG_THREADS
- GC_printf1("Starting thread 0x%lx\n", my_pthread);
- GC_printf1("pid = %ld\n", (long) getpid());
- GC_printf1("sp = 0x%lx\n", (long) &arg);
-# endif
- LOCK();
- me = GC_new_thread(my_pthread);
- me -> flags = si -> flags;
- me -> stack_ptr = 0;
- /* me -> stack_end = GC_linux_stack_base(); -- currently (11/99) */
- /* doesn't work because the stack base in /proc/self/stat is the */
- /* one for the main thread. There is a strong argument that that's */
- /* a kernel bug, but a pervasive one. */
-# ifdef STACK_GROWS_DOWN
- me -> stack_end = (ptr_t)(((word)(&dummy) + (GC_page_size - 1))
- & ~(GC_page_size - 1));
- me -> stack_ptr = me -> stack_end - 0x10;
- /* Needs to be plausible, since an asynchronous stack mark */
- /* should not crash. */
-# else
- me -> stack_end = (ptr_t)((word)(&dummy) & ~(GC_page_size - 1));
- me -> stack_ptr = me -> stack_end + 0x10;
-# endif
- /* This is dubious, since we may be more than a page into the stack, */
- /* and hence skip some of it, though it's not clear that matters. */
-# ifdef IA64
- me -> backing_store_end = (ptr_t)
- (GC_save_regs_in_stack() & ~(GC_page_size - 1));
- /* This is also < 100% convincing. We should also read this */
- /* from /proc, but the hook to do so isn't there yet. */
-# endif /* IA64 */
- UNLOCK();
- start = si -> start_routine;
-# ifdef DEBUG_THREADS
- GC_printf1("start_routine = 0x%lx\n", start);
-# endif
- start_arg = si -> arg;
- sem_post(&(si -> registered)); /* Last action on si. */
- /* OK to deallocate. */
- pthread_cleanup_push(GC_thread_exit_proc, 0);
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
- LOCK();
- GC_init_thread_local(me);
- UNLOCK();
-# endif
- result = (*start)(start_arg);
-#if DEBUG_THREADS
- GC_printf1("Finishing thread 0x%x\n", pthread_self());
-#endif
- me -> status = result;
- me -> flags |= FINISHED;
- pthread_cleanup_pop(1);
- /* Cleanup acquires lock, ensuring that we can't exit */
- /* while a collection that thinks we're alive is trying to stop */
- /* us. */
- return(result);
-}
-
-int
-WRAP_FUNC(pthread_create)(pthread_t *new_thread,
- const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg)
-{
- int result;
- GC_thread t;
- pthread_t my_new_thread;
- int detachstate;
- word my_flags = 0;
- struct start_info * si;
- /* This is otherwise saved only in an area mmapped by the thread */
- /* library, which isn't visible to the collector. */
-
- LOCK();
- si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info), NORMAL);
- UNLOCK();
- if (!parallel_initialized) GC_init_parallel();
- if (0 == si) return(ENOMEM);
- sem_init(&(si -> registered), 0, 0);
- si -> start_routine = start_routine;
- si -> arg = arg;
- LOCK();
- if (!GC_thr_initialized) GC_thr_init();
- if (NULL == attr) {
- detachstate = PTHREAD_CREATE_JOINABLE;
- } else {
- pthread_attr_getdetachstate(attr, &detachstate);
- }
- if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
- si -> flags = my_flags;
- UNLOCK();
-# ifdef DEBUG_THREADS
- GC_printf1("About to start new thread from thread 0x%X\n",
- pthread_self());
-# endif
- result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
-# ifdef DEBUG_THREADS
- GC_printf1("Started thread 0x%X\n", *new_thread);
-# endif
- /* Wait until child has been added to the thread table. */
- /* This also ensures that we hold onto si until the child is done */
- /* with it. Thus it doesn't matter whether it is otherwise */
- /* visible to the collector. */
- while (0 != sem_wait(&(si -> registered))) {
- if (EINTR != errno) ABORT("sem_wait failed");
- }
- sem_destroy(&(si -> registered));
- LOCK();
- GC_INTERNAL_FREE(si);
- UNLOCK();
- return(result);
-}
-
-#ifdef GENERIC_COMPARE_AND_SWAP
- pthread_mutex_t GC_compare_and_swap_lock = PTHREAD_MUTEX_INITIALIZER;
-
- GC_bool GC_compare_and_exchange(volatile GC_word *addr,
- GC_word old, GC_word new_val)
- {
- GC_bool result;
- pthread_mutex_lock(&GC_compare_and_swap_lock);
- if (*addr == old) {
- *addr = new_val;
- result = TRUE;
- } else {
- result = FALSE;
- }
- pthread_mutex_unlock(&GC_compare_and_swap_lock);
- return result;
- }
-
- GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much)
- {
- GC_word old;
- pthread_mutex_lock(&GC_compare_and_swap_lock);
- old = *addr;
- *addr = old + how_much;
- pthread_mutex_unlock(&GC_compare_and_swap_lock);
- return old;
- }
-
-#endif /* GENERIC_COMPARE_AND_SWAP */
-/* Spend a few cycles in a way that can't introduce contention with */
-/* othre threads. */
-void GC_pause()
-{
- int i;
- volatile word dummy = 0;
-
- for (i = 0; i < 10; ++i) {
-# ifdef __GNUC__
- __asm__ __volatile__ (" " : : : "memory");
-# else
- /* Something that's unlikely to be optimized away. */
- GC_noop(++dummy);
-# endif
- }
-}
-
-#define SPIN_MAX 1024 /* Maximum number of calls to GC_pause before */
- /* give up. */
-
-VOLATILE GC_bool GC_collecting = 0;
- /* A hint that we're in the collector and */
- /* holding the allocation lock for an */
- /* extended period. */
-
-#if !defined(USE_SPIN_LOCK) || defined(PARALLEL_MARK)
-/* If we don't want to use the below spinlock implementation, either */
-/* because we don't have a GC_test_and_set implementation, or because */
-/* we don't want to risk sleeping, we can still try spinning on */
-/* pthread_mutex_trylock for a while. This appears to be very */
-/* beneficial in many cases. */
-/* I suspect that under high contention this is nearly always better */
-/* than the spin lock. But it's a bit slower on a uniprocessor. */
-/* Hence we still default to the spin lock. */
-/* This is also used to acquire the mark lock for the parallel */
-/* marker. */
-
-/* Here we use a strict exponential backoff scheme. I don't know */
-/* whether that's better or worse than the above. We eventually */
-/* yield by calling pthread_mutex_lock(); it never makes sense to */
-/* explicitly sleep. */
-
-void GC_generic_lock(pthread_mutex_t * lock)
-{
- unsigned pause_length = 1;
- unsigned i;
-
- if (0 == pthread_mutex_trylock(lock)) return;
- for (; pause_length <= SPIN_MAX; pause_length <<= 1) {
- for (i = 0; i < pause_length; ++i) {
- GC_pause();
- }
- switch(pthread_mutex_trylock(lock)) {
- case 0:
- return;
- case EBUSY:
- break;
- default:
- ABORT("Unexpected error from pthread_mutex_trylock");
- }
- }
- pthread_mutex_lock(lock);
-}
-
-#endif /* !USE_SPIN_LOCK || PARALLEL_MARK */
-
-#if defined(USE_SPIN_LOCK)
-
-/* Reasonably fast spin locks. Basically the same implementation */
-/* as STL alloc.h. This isn't really the right way to do this. */
-/* but until the POSIX scheduling mess gets straightened out ... */
-
-volatile unsigned int GC_allocate_lock = 0;
-
-
-void GC_lock()
-{
-# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
-# define high_spin_max SPIN_MAX /* spin cycles for multiprocessor */
- static unsigned spin_max = low_spin_max;
- unsigned my_spin_max;
- static unsigned last_spins = 0;
- unsigned my_last_spins;
- int i;
-
- if (!GC_test_and_set(&GC_allocate_lock)) {
- return;
- }
- my_spin_max = spin_max;
- my_last_spins = last_spins;
- for (i = 0; i < my_spin_max; i++) {
- if (GC_collecting || GC_nprocs == 1) goto yield;
- if (i < my_last_spins/2 || GC_allocate_lock) {
- GC_pause();
- continue;
- }
- if (!GC_test_and_set(&GC_allocate_lock)) {
- /*
- * got it!
- * Spinning worked. Thus we're probably not being scheduled
- * against the other process with which we were contending.
- * Thus it makes sense to spin longer the next time.
- */
- last_spins = i;
- spin_max = high_spin_max;
- return;
- }
- }
- /* We are probably being scheduled against the other process. Sleep. */
- spin_max = low_spin_max;
-yield:
- for (i = 0;; ++i) {
- if (!GC_test_and_set(&GC_allocate_lock)) {
- return;
- }
-# define SLEEP_THRESHOLD 12
- /* nanosleep(<= 2ms) just spins under Linux. We */
- /* want to be careful to avoid that behavior. */
- if (i < SLEEP_THRESHOLD) {
- sched_yield();
- } else {
- struct timespec ts;
-
- if (i > 24) i = 24;
- /* Don't wait for more than about 15msecs, even */
- /* under extreme contention. */
- ts.tv_sec = 0;
- ts.tv_nsec = 1 << i;
- nanosleep(&ts, 0);
- }
- }
-}
-
-#else /* !USE_SPINLOCK */
-
-void GC_lock()
-{
- if (1 == GC_nprocs || GC_collecting) {
- pthread_mutex_lock(&GC_allocate_ml);
- } else {
- GC_generic_lock(&GC_allocate_ml);
- }
-}
-
-#endif /* !USE_SPINLOCK */
-
-#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
-
-#ifdef GC_ASSERTIONS
- pthread_t GC_mark_lock_holder = NO_THREAD;
-#endif
-
-#if 0
- /* Ugly workaround for a linux threads bug in the final versions */
- /* of glibc2.1. Pthread_mutex_trylock sets the mutex owner */
- /* field even when it fails to acquire the mutex. This causes */
- /* pthread_cond_wait to die. Remove for glibc2.2. */
- /* According to the man page, we should use */
- /* PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, but that isn't actually */
- /* defined. */
- static pthread_mutex_t mark_mutex =
- {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}};
-#else
- static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
-
-void GC_acquire_mark_lock()
-{
-/*
- if (pthread_mutex_lock(&mark_mutex) != 0) {
- ABORT("pthread_mutex_lock failed");
- }
-*/
- GC_generic_lock(&mark_mutex);
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = pthread_self();
-# endif
-}
-
-void GC_release_mark_lock()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = NO_THREAD;
-# endif
- if (pthread_mutex_unlock(&mark_mutex) != 0) {
- ABORT("pthread_mutex_unlock failed");
- }
-}
-
-/* Collector must wait for a freelist builders for 2 reasons: */
-/* 1) Mark bits may still be getting examined without lock. */
-/* 2) Partial free lists referenced only by locals may not be scanned */
-/* correctly, e.g. if they contain "pointer-free" objects, since the */
-/* free-list link may be ignored. */
-void GC_wait_builder()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = NO_THREAD;
-# endif
- if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
- ABORT("pthread_cond_wait failed");
- }
- GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = pthread_self();
-# endif
-}
-
-void GC_wait_for_reclaim()
-{
- GC_acquire_mark_lock();
- while (GC_fl_builder_count > 0) {
- GC_wait_builder();
- }
- GC_release_mark_lock();
-}
-
-void GC_notify_all_builder()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
- if (pthread_cond_broadcast(&builder_cv) != 0) {
- ABORT("pthread_cond_broadcast failed");
- }
-}
-
-#endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
-
-#ifdef PARALLEL_MARK
-
-static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
-
-void GC_wait_marker()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = NO_THREAD;
-# endif
- if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
- ABORT("pthread_cond_wait failed");
- }
- GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = pthread_self();
-# endif
-}
-
-void GC_notify_all_marker()
-{
- if (pthread_cond_broadcast(&mark_cv) != 0) {
- ABORT("pthread_cond_broadcast failed");
- }
-}
-
-#endif /* PARALLEL_MARK */
-
-# endif /* GC_LINUX_THREADS and friends */
-
diff --git a/boehm-gc/ltconfig b/boehm-gc/ltconfig
deleted file mode 100755
index 962057f05fe..00000000000
--- a/boehm-gc/ltconfig
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-# I could find no versions of autoconf that don't invoke ltconfig, but
-# libtool no longer includes an ltconfig. Yuch.
diff --git a/boehm-gc/ltmain.sh b/boehm-gc/ltmain.sh
deleted file mode 100644
index 6e5bf3657c9..00000000000
--- a/boehm-gc/ltmain.sh
+++ /dev/null
@@ -1,4984 +0,0 @@
-# ltmain.sh - Provide generalized library-building support services.
-# NOTE: Changing this file will not affect anything until you rerun configure.
-#
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
-# Free Software Foundation, Inc.
-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Check that we have a working $echo.
-if test "X$1" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
-elif test "X$1" = X--fallback-echo; then
- # Avoid inline document here, it may be left over
- :
-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
- # Yippee, $echo works!
- :
-else
- # Restart under the correct shell, and then maybe $echo will work.
- exec $SHELL "$0" --no-reexec ${1+"$@"}
-fi
-
-if test "X$1" = X--fallback-echo; then
- # used as fallback echo
- shift
- cat <<EOF
-$*
-EOF
- exit 0
-fi
-
-# The name of this program.
-progname=`$echo "$0" | sed 's%^.*/%%'`
-modename="$progname"
-
-# Constants.
-PROGRAM=ltmain.sh
-PACKAGE=libtool
-VERSION=1.4.2
-TIMESTAMP=" (1.922.2.53 2001/09/11 03:18:52)"
-
-default_mode=
-help="Try \`$progname --help' for more information."
-magic="%%%MAGIC variable%%%"
-mkdir="mkdir"
-mv="mv -f"
-rm="rm -f"
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e 1s/^X//'
-sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
-SP2NL='tr \040 \012'
-NL2SP='tr \015\012 \040\040'
-
-# NLS nuisances.
-# Only set LANG and LC_ALL to C if already set.
-# These must not be set unconditionally because not all systems understand
-# e.g. LANG=C (notably SCO).
-# We save the old values to restore during execute mode.
-if test "${LC_ALL+set}" = set; then
- save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
-fi
-if test "${LANG+set}" = set; then
- save_LANG="$LANG"; LANG=C; export LANG
-fi
-
-# Make sure IFS has a sensible default
-: ${IFS=" "}
-
-if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
- echo "$modename: not configured to build any kind of library" 1>&2
- echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit 1
-fi
-
-# Global variables.
-mode=$default_mode
-nonopt=
-prev=
-prevopt=
-run=
-show="$echo"
-show_help=
-execute_dlfiles=
-lo2o="s/\\.lo\$/.${objext}/"
-o2lo="s/\\.${objext}\$/.lo/"
-
-# Parse our command line options once, thoroughly.
-while test $# -gt 0
-do
- arg="$1"
- shift
-
- case $arg in
- -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
- *) optarg= ;;
- esac
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- case $prev in
- execute_dlfiles)
- execute_dlfiles="$execute_dlfiles $arg"
- ;;
- *)
- eval "$prev=\$arg"
- ;;
- esac
-
- prev=
- prevopt=
- continue
- fi
-
- # Have we seen a non-optional argument yet?
- case $arg in
- --help)
- show_help=yes
- ;;
-
- --version)
- echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
- exit 0
- ;;
-
- --config)
- sed -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0
- exit 0
- ;;
-
- --debug)
- echo "$progname: enabling shell trace mode"
- set -x
- ;;
-
- --dry-run | -n)
- run=:
- ;;
-
- --features)
- echo "host: $host"
- if test "$build_libtool_libs" = yes; then
- echo "enable shared libraries"
- else
- echo "disable shared libraries"
- fi
- if test "$build_old_libs" = yes; then
- echo "enable static libraries"
- else
- echo "disable static libraries"
- fi
- exit 0
- ;;
-
- --finish) mode="finish" ;;
-
- --mode) prevopt="--mode" prev=mode ;;
- --mode=*) mode="$optarg" ;;
-
- --quiet | --silent)
- show=:
- ;;
-
- -dlopen)
- prevopt="-dlopen"
- prev=execute_dlfiles
- ;;
-
- -*)
- $echo "$modename: unrecognized option \`$arg'" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
-
- *)
- nonopt="$arg"
- break
- ;;
- esac
-done
-
-if test -n "$prevopt"; then
- $echo "$modename: option \`$prevopt' requires an argument" 1>&2
- $echo "$help" 1>&2
- exit 1
-fi
-
-# If this variable is set in any of the actions, the command in it
-# will be execed at the end. This prevents here-documents from being
-# left over by shells.
-exec_cmd=
-
-if test -z "$show_help"; then
-
- # Infer the operation mode.
- if test -z "$mode"; then
- case $nonopt in
- *cc | *++ | gcc* | *-gcc*)
- mode=link
- for arg
- do
- case $arg in
- -c)
- mode=compile
- break
- ;;
- esac
- done
- ;;
- *db | *dbx | *strace | *truss)
- mode=execute
- ;;
- *install*|cp|mv)
- mode=install
- ;;
- *rm)
- mode=uninstall
- ;;
- *)
- # If we have no mode, but dlfiles were specified, then do execute mode.
- test -n "$execute_dlfiles" && mode=execute
-
- # Just use the default operation mode.
- if test -z "$mode"; then
- if test -n "$nonopt"; then
- $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
- else
- $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
- fi
- fi
- ;;
- esac
- fi
-
- # Only execute mode is allowed to have -dlopen flags.
- if test -n "$execute_dlfiles" && test "$mode" != execute; then
- $echo "$modename: unrecognized option \`-dlopen'" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Change the help message to a mode-specific one.
- generic_help="$help"
- help="Try \`$modename --help --mode=$mode' for more information."
-
- # These modes are in order of execution frequency so that they run quickly.
- case $mode in
- # libtool compile mode
- compile)
- modename="$modename: compile"
- # Get the compilation command and the source file.
- base_compile=
- prev=
- lastarg=
- srcfile="$nonopt"
- suppress_output=
-
- user_target=no
- for arg
- do
- case $prev in
- "") ;;
- xcompiler)
- # Aesthetically quote the previous argument.
- prev=
- lastarg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
-
- case $arg in
- # Double-quote args containing other shell metacharacters.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
-
- # Add the previous argument to base_compile.
- if test -z "$base_compile"; then
- base_compile="$lastarg"
- else
- base_compile="$base_compile $lastarg"
- fi
- continue
- ;;
- esac
-
- # Accept any command-line options.
- case $arg in
- -o)
- if test "$user_target" != "no"; then
- $echo "$modename: you cannot specify \`-o' more than once" 1>&2
- exit 1
- fi
- user_target=next
- ;;
-
- -static)
- build_old_libs=yes
- continue
- ;;
-
- -prefer-pic)
- pic_mode=yes
- continue
- ;;
-
- -prefer-non-pic)
- pic_mode=no
- continue
- ;;
-
- -Xcompiler)
- prev=xcompiler
- continue
- ;;
-
- -Wc,*)
- args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
- lastarg=
- save_ifs="$IFS"; IFS=','
- for arg in $args; do
- IFS="$save_ifs"
-
- # Double-quote args containing other shell metacharacters.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- lastarg="$lastarg $arg"
- done
- IFS="$save_ifs"
- lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
-
- # Add the arguments to base_compile.
- if test -z "$base_compile"; then
- base_compile="$lastarg"
- else
- base_compile="$base_compile $lastarg"
- fi
- continue
- ;;
- esac
-
- case $user_target in
- next)
- # The next one is the -o target name
- user_target=yes
- continue
- ;;
- yes)
- # We got the output file
- user_target=set
- libobj="$arg"
- continue
- ;;
- esac
-
- # Accept the current argument as the source file.
- lastarg="$srcfile"
- srcfile="$arg"
-
- # Aesthetically quote the previous argument.
-
- # Backslashify any backslashes, double quotes, and dollar signs.
- # These are the only characters that are still specially
- # interpreted inside of double-quoted scrings.
- lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
-
- # Double-quote args containing other shell metacharacters.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- case $lastarg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- lastarg="\"$lastarg\""
- ;;
- esac
-
- # Add the previous argument to base_compile.
- if test -z "$base_compile"; then
- base_compile="$lastarg"
- else
- base_compile="$base_compile $lastarg"
- fi
- done
-
- case $user_target in
- set)
- ;;
- no)
- # Get the name of the library object.
- libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
- ;;
- *)
- $echo "$modename: you must specify a target with \`-o'" 1>&2
- exit 1
- ;;
- esac
-
- # Recognize several different file suffixes.
- # If the user specifies -o file.o, it is replaced with file.lo
- xform='[cCFSfmso]'
- case $libobj in
- *.ada) xform=ada ;;
- *.adb) xform=adb ;;
- *.ads) xform=ads ;;
- *.asm) xform=asm ;;
- *.c++) xform=c++ ;;
- *.cc) xform=cc ;;
- *.cpp) xform=cpp ;;
- *.cxx) xform=cxx ;;
- *.f90) xform=f90 ;;
- *.for) xform=for ;;
- esac
-
- libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
-
- case $libobj in
- *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
- *)
- $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
- exit 1
- ;;
- esac
-
- if test -z "$base_compile"; then
- $echo "$modename: you must specify a compilation command" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Delete any leftover library objects.
- if test "$build_old_libs" = yes; then
- removelist="$obj $libobj"
- else
- removelist="$libobj"
- fi
-
- $run $rm $removelist
- trap "$run $rm $removelist; exit 1" 1 2 15
-
- # On Cygwin there's no "real" PIC flag so we must build both object types
- case $host_os in
- cygwin* | mingw* | pw32* | os2*)
- pic_mode=default
- ;;
- esac
- if test $pic_mode = no && test "$deplibs_check_method" != pass_all; then
- # non-PIC code in shared libraries is not supported
- pic_mode=default
- fi
-
- # Calculate the filename of the output object if compiler does
- # not support -o with -c
- if test "$compiler_c_o" = no; then
- output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
- lockfile="$output_obj.lock"
- removelist="$removelist $output_obj $lockfile"
- trap "$run $rm $removelist; exit 1" 1 2 15
- else
- need_locks=no
- lockfile=
- fi
-
- # Lock this critical section if it is needed
- # We use this script file to make the link, it avoids creating a new file
- if test "$need_locks" = yes; then
- until $run ln "$0" "$lockfile" 2>/dev/null; do
- $show "Waiting for $lockfile to be removed"
- sleep 2
- done
- elif test "$need_locks" = warn; then
- if test -f "$lockfile"; then
- echo "\
-*** ERROR, $lockfile exists and contains:
-`cat $lockfile 2>/dev/null`
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit 1
- fi
- echo $srcfile > "$lockfile"
- fi
-
- if test -n "$fix_srcfile_path"; then
- eval srcfile=\"$fix_srcfile_path\"
- fi
-
- # Only build a PIC object if we are building libtool libraries.
- if test "$build_libtool_libs" = yes; then
- # Without this assignment, base_compile gets emptied.
- fbsd_hideous_sh_bug=$base_compile
-
- if test "$pic_mode" != no; then
- # All platforms use -DPIC, to notify preprocessed assembler code.
- command="$base_compile $srcfile $pic_flag -DPIC"
- else
- # Don't build PIC code
- command="$base_compile $srcfile"
- fi
- if test "$build_old_libs" = yes; then
- lo_libobj="$libobj"
- dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$dir" = "X$libobj"; then
- dir="$objdir"
- else
- dir="$dir/$objdir"
- fi
- libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'`
-
- if test -d "$dir"; then
- $show "$rm $libobj"
- $run $rm $libobj
- else
- $show "$mkdir $dir"
- $run $mkdir $dir
- status=$?
- if test $status -ne 0 && test ! -d $dir; then
- exit $status
- fi
- fi
- fi
- if test "$compiler_o_lo" = yes; then
- output_obj="$libobj"
- command="$command -o $output_obj"
- elif test "$compiler_c_o" = yes; then
- output_obj="$obj"
- command="$command -o $output_obj"
- fi
-
- $run $rm "$output_obj"
- $show "$command"
- if $run eval "$command"; then :
- else
- test -n "$output_obj" && $run $rm $removelist
- exit 1
- fi
-
- if test "$need_locks" = warn &&
- test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
- echo "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit 1
- fi
-
- # Just move the object if needed, then go on to compile the next one
- if test x"$output_obj" != x"$libobj"; then
- $show "$mv $output_obj $libobj"
- if $run $mv $output_obj $libobj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # If we have no pic_flag, then copy the object into place and finish.
- if (test -z "$pic_flag" || test "$pic_mode" != default) &&
- test "$build_old_libs" = yes; then
- # Rename the .lo from within objdir to obj
- if test -f $obj; then
- $show $rm $obj
- $run $rm $obj
- fi
-
- $show "$mv $libobj $obj"
- if $run $mv $libobj $obj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
-
- xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$obj"; then
- xdir="."
- else
- xdir="$xdir"
- fi
- baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"`
- libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"`
- # Now arrange that obj and lo_libobj become the same file
- $show "(cd $xdir && $LN_S $baseobj $libobj)"
- if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then
- # Unlock the critical section if it was locked
- if test "$need_locks" != no; then
- $run $rm "$lockfile"
- fi
- exit 0
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # Allow error messages only from the first compilation.
- suppress_output=' >/dev/null 2>&1'
- fi
-
- # Only build a position-dependent object if we build old libraries.
- if test "$build_old_libs" = yes; then
- if test "$pic_mode" != yes; then
- # Don't build PIC code
- command="$base_compile $srcfile"
- else
- # All platforms use -DPIC, to notify preprocessed assembler code.
- command="$base_compile $srcfile $pic_flag -DPIC"
- fi
- if test "$compiler_c_o" = yes; then
- command="$command -o $obj"
- output_obj="$obj"
- fi
-
- # Suppress compiler output if we already did a PIC compilation.
- command="$command$suppress_output"
- $run $rm "$output_obj"
- $show "$command"
- if $run eval "$command"; then :
- else
- $run $rm $removelist
- exit 1
- fi
-
- if test "$need_locks" = warn &&
- test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
- echo "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit 1
- fi
-
- # Just move the object if needed
- if test x"$output_obj" != x"$obj"; then
- $show "$mv $output_obj $obj"
- if $run $mv $output_obj $obj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # Create an invalid libtool object if no PIC, so that we do not
- # accidentally link it into a program.
- if test "$build_libtool_libs" != yes; then
- $show "echo timestamp > $libobj"
- $run eval "echo timestamp > \$libobj" || exit $?
- else
- # Move the .lo from within objdir
- $show "$mv $libobj $lo_libobj"
- if $run $mv $libobj $lo_libobj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
- fi
-
- # Unlock the critical section if it was locked
- if test "$need_locks" != no; then
- $run $rm "$lockfile"
- fi
-
- exit 0
- ;;
-
- # libtool link mode
- link | relink)
- modename="$modename: link"
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- # It is impossible to link a dll without this setting, and
- # we shouldn't force the makefile maintainer to figure out
- # which system we are compiling for in order to pass an extra
- # flag for every libtool invokation.
- # allow_undefined=no
-
- # FIXME: Unfortunately, there are problems with the above when trying
- # to make a dll which has undefined symbols, in which case not
- # even a static library is built. For now, we need to specify
- # -no-undefined on the libtool link line when we can be certain
- # that all symbols are satisfied, otherwise we get a static library.
- allow_undefined=yes
- ;;
- *)
- allow_undefined=yes
- ;;
- esac
- libtool_args="$nonopt"
- compile_command="$nonopt"
- finalize_command="$nonopt"
-
- compile_rpath=
- finalize_rpath=
- compile_shlibpath=
- finalize_shlibpath=
- convenience=
- old_convenience=
- deplibs=
- old_deplibs=
- compiler_flags=
- linker_flags=
- dllsearchpath=
- lib_search_path=`pwd`
-
- avoid_version=no
- dlfiles=
- dlprefiles=
- dlself=no
- export_dynamic=no
- export_symbols=
- export_symbols_regex=
- generated=
- libobjs=
- ltlibs=
- module=no
- no_install=no
- objs=
- prefer_static_libs=no
- preload=no
- prev=
- prevarg=
- release=
- rpath=
- xrpath=
- perm_rpath=
- temp_rpath=
- thread_safe=no
- vinfo=
-
- # We need to know -static, to get the right output filenames.
- for arg
- do
- case $arg in
- -all-static | -static)
- if test "X$arg" = "X-all-static"; then
- if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
- $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
- fi
- if test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- else
- if test -z "$pic_flag" && test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- fi
- build_libtool_libs=no
- build_old_libs=yes
- prefer_static_libs=yes
- break
- ;;
- esac
- done
-
- # See if our shared archives depend on static archives.
- test -n "$old_archive_from_new_cmds" && build_old_libs=yes
-
- # Go through the arguments, transforming them on the way.
- while test $# -gt 0; do
- arg="$1"
- shift
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
- ;;
- *) qarg=$arg ;;
- esac
- libtool_args="$libtool_args $qarg"
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- case $prev in
- output)
- compile_command="$compile_command @OUTPUT@"
- finalize_command="$finalize_command @OUTPUT@"
- ;;
- esac
-
- case $prev in
- dlfiles|dlprefiles)
- if test "$preload" = no; then
- # Add the symbol object into the linking commands.
- compile_command="$compile_command @SYMFILE@"
- finalize_command="$finalize_command @SYMFILE@"
- preload=yes
- fi
- case $arg in
- *.la | *.lo) ;; # We handle these cases below.
- force)
- if test "$dlself" = no; then
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- self)
- if test "$prev" = dlprefiles; then
- dlself=yes
- elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
- dlself=yes
- else
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- *)
- if test "$prev" = dlfiles; then
- dlfiles="$dlfiles $arg"
- else
- dlprefiles="$dlprefiles $arg"
- fi
- prev=
- continue
- ;;
- esac
- ;;
- expsyms)
- export_symbols="$arg"
- if test ! -f "$arg"; then
- $echo "$modename: symbol file \`$arg' does not exist"
- exit 1
- fi
- prev=
- continue
- ;;
- expsyms_regex)
- export_symbols_regex="$arg"
- prev=
- continue
- ;;
- release)
- release="-$arg"
- prev=
- continue
- ;;
- rpath | xrpath)
- # We need an absolute path.
- case $arg in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- $echo "$modename: only absolute run-paths are allowed" 1>&2
- exit 1
- ;;
- esac
- if test "$prev" = rpath; then
- case "$rpath " in
- *" $arg "*) ;;
- *) rpath="$rpath $arg" ;;
- esac
- else
- case "$xrpath " in
- *" $arg "*) ;;
- *) xrpath="$xrpath $arg" ;;
- esac
- fi
- prev=
- continue
- ;;
- xcompiler)
- compiler_flags="$compiler_flags $qarg"
- prev=
- compile_command="$compile_command $qarg"
- finalize_command="$finalize_command $qarg"
- continue
- ;;
- xlinker)
- linker_flags="$linker_flags $qarg"
- compiler_flags="$compiler_flags $wl$qarg"
- prev=
- compile_command="$compile_command $wl$qarg"
- finalize_command="$finalize_command $wl$qarg"
- continue
- ;;
- *)
- eval "$prev=\"\$arg\""
- prev=
- continue
- ;;
- esac
- fi # test -n $prev
-
- prevarg="$arg"
-
- case $arg in
- -all-static)
- if test -n "$link_static_flag"; then
- compile_command="$compile_command $link_static_flag"
- finalize_command="$finalize_command $link_static_flag"
- fi
- continue
- ;;
-
- -allow-undefined)
- # FIXME: remove this flag sometime in the future.
- $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
- continue
- ;;
-
- -avoid-version)
- avoid_version=yes
- continue
- ;;
-
- -dlopen)
- prev=dlfiles
- continue
- ;;
-
- -dlpreopen)
- prev=dlprefiles
- continue
- ;;
-
- -export-dynamic)
- export_dynamic=yes
- continue
- ;;
-
- -export-symbols | -export-symbols-regex)
- if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
- $echo "$modename: more than one -exported-symbols argument is not allowed"
- exit 1
- fi
- if test "X$arg" = "X-export-symbols"; then
- prev=expsyms
- else
- prev=expsyms_regex
- fi
- continue
- ;;
-
- # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
- # so, if we see these flags be careful not to treat them like -L
- -L[A-Z][A-Z]*:*)
- case $with_gcc/$host in
- no/*-*-irix*)
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- ;;
- esac
- continue
- ;;
-
- -L*)
- dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- absdir=`cd "$dir" && pwd`
- if test -z "$absdir"; then
- $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
- exit 1
- fi
- dir="$absdir"
- ;;
- esac
- case "$deplibs " in
- *" -L$dir "*) ;;
- *)
- deplibs="$deplibs -L$dir"
- lib_search_path="$lib_search_path $dir"
- ;;
- esac
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- case :$dllsearchpath: in
- *":$dir:"*) ;;
- *) dllsearchpath="$dllsearchpath:$dir";;
- esac
- ;;
- esac
- continue
- ;;
-
- -l*)
- if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
- case $host in
- *-*-cygwin* | *-*-pw32* | *-*-beos*)
- # These systems don't actually have a C or math library (as such)
- continue
- ;;
- *-*-mingw* | *-*-os2*)
- # These systems don't actually have a C library (as such)
- test "X$arg" = "X-lc" && continue
- ;;
- *-*-openbsd*)
- # Do not include libc due to us having libc/libc_r.
- test "X$arg" = "X-lc" && continue
- ;;
- esac
- elif test "X$arg" = "X-lc_r"; then
- case $host in
- *-*-openbsd*)
- # Do not include libc_r directly, use -pthread flag.
- continue
- ;;
- esac
- fi
- deplibs="$deplibs $arg"
- continue
- ;;
-
- -module)
- module=yes
- continue
- ;;
-
- -no-fast-install)
- fast_install=no
- continue
- ;;
-
- -no-install)
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- # The PATH hackery in wrapper scripts is required on Windows
- # in order for the loader to find any dlls it needs.
- $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
- $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
- fast_install=no
- ;;
- *) no_install=yes ;;
- esac
- continue
- ;;
-
- -no-undefined)
- allow_undefined=no
- continue
- ;;
-
- -o) prev=output ;;
-
- -release)
- prev=release
- continue
- ;;
-
- -rpath)
- prev=rpath
- continue
- ;;
-
- -R)
- prev=xrpath
- continue
- ;;
-
- -R*)
- dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- $echo "$modename: only absolute run-paths are allowed" 1>&2
- exit 1
- ;;
- esac
- case "$xrpath " in
- *" $dir "*) ;;
- *) xrpath="$xrpath $dir" ;;
- esac
- continue
- ;;
-
- -static)
- # The effects of -static are defined in a previous loop.
- # We used to do the same as -all-static on platforms that
- # didn't have a PIC flag, but the assumption that the effects
- # would be equivalent was wrong. It would break on at least
- # Digital Unix and AIX.
- continue
- ;;
-
- -thread-safe)
- thread_safe=yes
- continue
- ;;
-
- -version-info)
- prev=vinfo
- continue
- ;;
-
- -Wc,*)
- args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
- arg=
- save_ifs="$IFS"; IFS=','
- for flag in $args; do
- IFS="$save_ifs"
- case $flag in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- flag="\"$flag\""
- ;;
- esac
- arg="$arg $wl$flag"
- compiler_flags="$compiler_flags $flag"
- done
- IFS="$save_ifs"
- arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
- ;;
-
- -Wl,*)
- args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
- arg=
- save_ifs="$IFS"; IFS=','
- for flag in $args; do
- IFS="$save_ifs"
- case $flag in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- flag="\"$flag\""
- ;;
- esac
- arg="$arg $wl$flag"
- compiler_flags="$compiler_flags $wl$flag"
- linker_flags="$linker_flags $flag"
- done
- IFS="$save_ifs"
- arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
- ;;
-
- -Xcompiler)
- prev=xcompiler
- continue
- ;;
-
- -Xlinker)
- prev=xlinker
- continue
- ;;
-
- # Some other compiler flag.
- -* | +*)
- # Unknown arguments in both finalize_command and compile_command need
- # to be aesthetically quoted because they are evaled later.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- ;;
-
- *.lo | *.$objext)
- # A library or standard object.
- if test "$prev" = dlfiles; then
- # This file was specified with -dlopen.
- if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
- dlfiles="$dlfiles $arg"
- prev=
- continue
- else
- # If libtool objects are unsupported, then we need to preload.
- prev=dlprefiles
- fi
- fi
-
- if test "$prev" = dlprefiles; then
- # Preload the old-style object.
- dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"`
- prev=
- else
- case $arg in
- *.lo) libobjs="$libobjs $arg" ;;
- *) objs="$objs $arg" ;;
- esac
- fi
- ;;
-
- *.$libext)
- # An archive.
- deplibs="$deplibs $arg"
- old_deplibs="$old_deplibs $arg"
- continue
- ;;
-
- *.la)
- # A libtool-controlled library.
-
- if test "$prev" = dlfiles; then
- # This library was specified with -dlopen.
- dlfiles="$dlfiles $arg"
- prev=
- elif test "$prev" = dlprefiles; then
- # The library was specified with -dlpreopen.
- dlprefiles="$dlprefiles $arg"
- prev=
- else
- deplibs="$deplibs $arg"
- fi
- continue
- ;;
-
- # Some other compiler argument.
- *)
- # Unknown arguments in both finalize_command and compile_command need
- # to be aesthetically quoted because they are evaled later.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- ;;
- esac # arg
-
- # Now actually substitute the argument into the commands.
- if test -n "$arg"; then
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- fi
- done # argument parsing loop
-
- if test -n "$prev"; then
- $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
- eval arg=\"$export_dynamic_flag_spec\"
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- fi
-
- # calculate the name of the file, without its directory
- outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
- libobjs_save="$libobjs"
-
- if test -n "$shlibpath_var"; then
- # get the directories listed in $shlibpath_var
- eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
- else
- shlib_search_path=
- fi
- eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
- eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
-
- output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$output_objdir" = "X$output"; then
- output_objdir="$objdir"
- else
- output_objdir="$output_objdir/$objdir"
- fi
- # Create the object directory.
- if test ! -d $output_objdir; then
- $show "$mkdir $output_objdir"
- $run $mkdir $output_objdir
- status=$?
- if test $status -ne 0 && test ! -d $output_objdir; then
- exit $status
- fi
- fi
-
- # Determine the type of output
- case $output in
- "")
- $echo "$modename: you must specify an output file" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
- *.$libext) linkmode=oldlib ;;
- *.lo | *.$objext) linkmode=obj ;;
- *.la) linkmode=lib ;;
- *) linkmode=prog ;; # Anything else should be a program.
- esac
-
- specialdeplibs=
- libs=
- # Find all interdependent deplibs by searching for libraries
- # that are linked more than once (e.g. -la -lb -la)
- for deplib in $deplibs; do
- case "$libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- libs="$libs $deplib"
- done
- deplibs=
- newdependency_libs=
- newlib_search_path=
- need_relink=no # whether we're linking any uninstalled libtool libraries
- notinst_deplibs= # not-installed libtool libraries
- notinst_path= # paths that contain not-installed libtool libraries
- case $linkmode in
- lib)
- passes="conv link"
- for file in $dlfiles $dlprefiles; do
- case $file in
- *.la) ;;
- *)
- $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
- exit 1
- ;;
- esac
- done
- ;;
- prog)
- compile_deplibs=
- finalize_deplibs=
- alldeplibs=no
- newdlfiles=
- newdlprefiles=
- passes="conv scan dlopen dlpreopen link"
- ;;
- *) passes="conv"
- ;;
- esac
- for pass in $passes; do
- if test $linkmode = prog; then
- # Determine which files to process
- case $pass in
- dlopen)
- libs="$dlfiles"
- save_deplibs="$deplibs" # Collect dlpreopened libraries
- deplibs=
- ;;
- dlpreopen) libs="$dlprefiles" ;;
- link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
- esac
- fi
- for deplib in $libs; do
- lib=
- found=no
- case $deplib in
- -l*)
- if test $linkmode = oldlib && test $linkmode = obj; then
- $echo "$modename: warning: \`-l' is ignored for archives/objects: $deplib" 1>&2
- continue
- fi
- if test $pass = conv; then
- deplibs="$deplib $deplibs"
- continue
- fi
- name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
- for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
- # Search the libtool library
- lib="$searchdir/lib${name}.la"
- if test -f "$lib"; then
- found=yes
- break
- fi
- done
- if test "$found" != yes; then
- # deplib doesn't seem to be a libtool library
- if test "$linkmode,$pass" = "prog,link"; then
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- deplibs="$deplib $deplibs"
- test $linkmode = lib && newdependency_libs="$deplib $newdependency_libs"
- fi
- continue
- fi
- ;; # -l
- -L*)
- case $linkmode in
- lib)
- deplibs="$deplib $deplibs"
- test $pass = conv && continue
- newdependency_libs="$deplib $newdependency_libs"
- newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
- ;;
- prog)
- if test $pass = conv; then
- deplibs="$deplib $deplibs"
- continue
- fi
- if test $pass = scan; then
- deplibs="$deplib $deplibs"
- newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
- else
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- fi
- ;;
- *)
- $echo "$modename: warning: \`-L' is ignored for archives/objects: $deplib" 1>&2
- ;;
- esac # linkmode
- continue
- ;; # -L
- -R*)
- if test $pass = link; then
- dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
- # Make sure the xrpath contains only unique directories.
- case "$xrpath " in
- *" $dir "*) ;;
- *) xrpath="$xrpath $dir" ;;
- esac
- fi
- deplibs="$deplib $deplibs"
- continue
- ;;
- *.la) lib="$deplib" ;;
- *.$libext)
- if test $pass = conv; then
- deplibs="$deplib $deplibs"
- continue
- fi
- case $linkmode in
- lib)
- if test "$deplibs_check_method" != pass_all; then
- echo
- echo "*** Warning: This library needs some functionality provided by $deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- else
- echo
- echo "*** Warning: Linking the shared library $output against the"
- echo "*** static library $deplib is not portable!"
- deplibs="$deplib $deplibs"
- fi
- continue
- ;;
- prog)
- if test $pass != link; then
- deplibs="$deplib $deplibs"
- else
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- fi
- continue
- ;;
- esac # linkmode
- ;; # *.$libext
- *.lo | *.$objext)
- if test $pass = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
- # If there is no dlopen support or we're linking statically,
- # we need to preload.
- newdlprefiles="$newdlprefiles $deplib"
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- newdlfiles="$newdlfiles $deplib"
- fi
- continue
- ;;
- %DEPLIBS%)
- alldeplibs=yes
- continue
- ;;
- esac # case $deplib
- if test $found = yes || test -f "$lib"; then :
- else
- $echo "$modename: cannot find the library \`$lib'" 1>&2
- exit 1
- fi
-
- # Check to see that this really is a libtool archive.
- if (sed -e '2q' $lib | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit 1
- fi
-
- ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
- test "X$ladir" = "X$lib" && ladir="."
-
- dlname=
- dlopen=
- dlpreopen=
- libdir=
- library_names=
- old_library=
- # If the library was installed with an old release of libtool,
- # it will not redefine variable installed.
- installed=yes
-
- # Read the .la file
- case $lib in
- */* | *\\*) . $lib ;;
- *) . ./$lib ;;
- esac
-
- if test "$linkmode,$pass" = "lib,link" ||
- test "$linkmode,$pass" = "prog,scan" ||
- { test $linkmode = oldlib && test $linkmode = obj; }; then
- # Add dl[pre]opened files of deplib
- test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
- test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
- fi
-
- if test $pass = conv; then
- # Only check for convenience libraries
- deplibs="$lib $deplibs"
- if test -z "$libdir"; then
- if test -z "$old_library"; then
- $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
- exit 1
- fi
- # It is a libtool convenience library, so add in its objects.
- convenience="$convenience $ladir/$objdir/$old_library"
- old_convenience="$old_convenience $ladir/$objdir/$old_library"
- tmp_libs=
- for deplib in $dependency_libs; do
- deplibs="$deplib $deplibs"
- case "$tmp_libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- tmp_libs="$tmp_libs $deplib"
- done
- elif test $linkmode != prog && test $linkmode != lib; then
- $echo "$modename: \`$lib' is not a convenience library" 1>&2
- exit 1
- fi
- continue
- fi # $pass = conv
-
- # Get the name of the library we link against.
- linklib=
- for l in $old_library $library_names; do
- linklib="$l"
- done
- if test -z "$linklib"; then
- $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
- exit 1
- fi
-
- # This library was specified with -dlopen.
- if test $pass = dlopen; then
- if test -z "$libdir"; then
- $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
- exit 1
- fi
- if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
- # If there is no dlname, no dlopen support or we're linking
- # statically, we need to preload.
- dlprefiles="$dlprefiles $lib"
- else
- newdlfiles="$newdlfiles $lib"
- fi
- continue
- fi # $pass = dlopen
-
- # We need an absolute path.
- case $ladir in
- [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
- *)
- abs_ladir=`cd "$ladir" && pwd`
- if test -z "$abs_ladir"; then
- $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
- $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
- abs_ladir="$ladir"
- fi
- ;;
- esac
- laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
-
- # Find the relevant object directory and library name.
- if test "X$installed" = Xyes; then
- if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
- $echo "$modename: warning: library \`$lib' was moved." 1>&2
- dir="$ladir"
- absdir="$abs_ladir"
- libdir="$abs_ladir"
- else
- dir="$libdir"
- absdir="$libdir"
- fi
- else
- dir="$ladir/$objdir"
- absdir="$abs_ladir/$objdir"
- # Remove this search path later
- notinst_path="$notinst_path $abs_ladir"
- fi # $installed = yes
- name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
-
- # This library was specified with -dlpreopen.
- if test $pass = dlpreopen; then
- if test -z "$libdir"; then
- $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
- exit 1
- fi
- # Prefer using a static library (so that no silly _DYNAMIC symbols
- # are required to link).
- if test -n "$old_library"; then
- newdlprefiles="$newdlprefiles $dir/$old_library"
- # Otherwise, use the dlname, so that lt_dlopen finds it.
- elif test -n "$dlname"; then
- newdlprefiles="$newdlprefiles $dir/$dlname"
- else
- newdlprefiles="$newdlprefiles $dir/$linklib"
- fi
- fi # $pass = dlpreopen
-
- if test -z "$libdir"; then
- # Link the convenience library
- if test $linkmode = lib; then
- deplibs="$dir/$old_library $deplibs"
- elif test "$linkmode,$pass" = "prog,link"; then
- compile_deplibs="$dir/$old_library $compile_deplibs"
- finalize_deplibs="$dir/$old_library $finalize_deplibs"
- else
- deplibs="$lib $deplibs"
- fi
- continue
- fi
-
- if test $linkmode = prog && test $pass != link; then
- newlib_search_path="$newlib_search_path $ladir"
- deplibs="$lib $deplibs"
-
- linkalldeplibs=no
- if test "$link_all_deplibs" != no || test -z "$library_names" ||
- test "$build_libtool_libs" = no; then
- linkalldeplibs=yes
- fi
-
- tmp_libs=
- for deplib in $dependency_libs; do
- case $deplib in
- -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
- esac
- # Need to link against all dependency_libs?
- if test $linkalldeplibs = yes; then
- deplibs="$deplib $deplibs"
- else
- # Need to hardcode shared library paths
- # or/and link against static libraries
- newdependency_libs="$deplib $newdependency_libs"
- fi
- case "$tmp_libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- tmp_libs="$tmp_libs $deplib"
- done # for deplib
- continue
- fi # $linkmode = prog...
-
- link_static=no # Whether the deplib will be linked statically
- if test -n "$library_names" &&
- { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
- # Link against this shared library
-
- if test "$linkmode,$pass" = "prog,link" ||
- { test $linkmode = lib && test $hardcode_into_libs = yes; }; then
- # Hardcode the library path.
- # Skip directories that are in the system default run-time
- # search path.
- case " $sys_lib_dlsearch_path " in
- *" $absdir "*) ;;
- *)
- case "$compile_rpath " in
- *" $absdir "*) ;;
- *) compile_rpath="$compile_rpath $absdir"
- esac
- ;;
- esac
- case " $sys_lib_dlsearch_path " in
- *" $libdir "*) ;;
- *)
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir"
- esac
- ;;
- esac
- if test $linkmode = prog; then
- # We need to hardcode the library path
- if test -n "$shlibpath_var"; then
- # Make sure the rpath contains only unique directories.
- case "$temp_rpath " in
- *" $dir "*) ;;
- *" $absdir "*) ;;
- *) temp_rpath="$temp_rpath $dir" ;;
- esac
- fi
- fi
- fi # $linkmode,$pass = prog,link...
-
- if test "$alldeplibs" = yes &&
- { test "$deplibs_check_method" = pass_all ||
- { test "$build_libtool_libs" = yes &&
- test -n "$library_names"; }; }; then
- # We only need to search for static libraries
- continue
- fi
-
- if test "$installed" = no; then
- notinst_deplibs="$notinst_deplibs $lib"
- need_relink=yes
- fi
-
- if test -n "$old_archive_from_expsyms_cmds"; then
- # figure out the soname
- set dummy $library_names
- realname="$2"
- shift; shift
- libname=`eval \\$echo \"$libname_spec\"`
- # use dlname if we got it. it's perfectly good, no?
- if test -n "$dlname"; then
- soname="$dlname"
- elif test -n "$soname_spec"; then
- # bleh windows
- case $host in
- *cygwin*)
- major=`expr $current - $age`
- versuffix="-$major"
- ;;
- esac
- eval soname=\"$soname_spec\"
- else
- soname="$realname"
- fi
-
- # Make a new name for the extract_expsyms_cmds to use
- soroot="$soname"
- soname=`echo $soroot | sed -e 's/^.*\///'`
- newlib="libimp-`echo $soname | sed 's/^lib//;s/\.dll$//'`.a"
-
- # If the library has no export list, then create one now
- if test -f "$output_objdir/$soname-def"; then :
- else
- $show "extracting exported symbol list from \`$soname'"
- save_ifs="$IFS"; IFS='~'
- eval cmds=\"$extract_expsyms_cmds\"
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
-
- # Create $newlib
- if test -f "$output_objdir/$newlib"; then :; else
- $show "generating import library for \`$soname'"
- save_ifs="$IFS"; IFS='~'
- eval cmds=\"$old_archive_from_expsyms_cmds\"
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
- # make sure the library variables are pointing to the new library
- dir=$output_objdir
- linklib=$newlib
- fi # test -n $old_archive_from_expsyms_cmds
-
- if test $linkmode = prog || test "$mode" != relink; then
- add_shlibpath=
- add_dir=
- add=
- lib_linked=yes
- case $hardcode_action in
- immediate | unsupported)
- if test "$hardcode_direct" = no; then
- add="$dir/$linklib"
- elif test "$hardcode_minus_L" = no; then
- case $host in
- *-*-sunos*) add_shlibpath="$dir" ;;
- esac
- add_dir="-L$dir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = no; then
- add_shlibpath="$dir"
- add="-l$name"
- else
- lib_linked=no
- fi
- ;;
- relink)
- if test "$hardcode_direct" = yes; then
- add="$dir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- add_dir="-L$dir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
- add_shlibpath="$dir"
- add="-l$name"
- else
- lib_linked=no
- fi
- ;;
- *) lib_linked=no ;;
- esac
-
- if test "$lib_linked" != yes; then
- $echo "$modename: configuration error: unsupported hardcode properties"
- exit 1
- fi
-
- if test -n "$add_shlibpath"; then
- case :$compile_shlibpath: in
- *":$add_shlibpath:"*) ;;
- *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
- esac
- fi
- if test $linkmode = prog; then
- test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
- test -n "$add" && compile_deplibs="$add $compile_deplibs"
- else
- test -n "$add_dir" && deplibs="$add_dir $deplibs"
- test -n "$add" && deplibs="$add $deplibs"
- if test "$hardcode_direct" != yes && \
- test "$hardcode_minus_L" != yes && \
- test "$hardcode_shlibpath_var" = yes; then
- case :$finalize_shlibpath: in
- *":$libdir:"*) ;;
- *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
- esac
- fi
- fi
- fi
-
- if test $linkmode = prog || test "$mode" = relink; then
- add_shlibpath=
- add_dir=
- add=
- # Finalize command for both is simple: just hardcode it.
- if test "$hardcode_direct" = yes; then
- add="$libdir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- add_dir="-L$libdir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
- case :$finalize_shlibpath: in
- *":$libdir:"*) ;;
- *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
- esac
- add="-l$name"
- else
- # We cannot seem to hardcode it, guess we'll fake it.
- add_dir="-L$libdir"
- add="-l$name"
- fi
-
- if test $linkmode = prog; then
- test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
- test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
- else
- test -n "$add_dir" && deplibs="$add_dir $deplibs"
- test -n "$add" && deplibs="$add $deplibs"
- fi
- fi
- elif test $linkmode = prog; then
- if test "$alldeplibs" = yes &&
- { test "$deplibs_check_method" = pass_all ||
- { test "$build_libtool_libs" = yes &&
- test -n "$library_names"; }; }; then
- # We only need to search for static libraries
- continue
- fi
-
- # Try to link the static library
- # Here we assume that one of hardcode_direct or hardcode_minus_L
- # is not unsupported. This is valid on all known static and
- # shared platforms.
- if test "$hardcode_direct" != unsupported; then
- test -n "$old_library" && linklib="$old_library"
- compile_deplibs="$dir/$linklib $compile_deplibs"
- finalize_deplibs="$dir/$linklib $finalize_deplibs"
- else
- compile_deplibs="-l$name -L$dir $compile_deplibs"
- finalize_deplibs="-l$name -L$dir $finalize_deplibs"
- fi
- elif test "$build_libtool_libs" = yes; then
- # Not a shared library
- if test "$deplibs_check_method" != pass_all; then
- # We're trying link a shared library against a static one
- # but the system doesn't support it.
-
- # Just print a warning and add the library to dependency_libs so
- # that the program can be linked against the static library.
- echo
- echo "*** Warning: This library needs some functionality provided by $lib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- if test "$module" = yes; then
- echo "*** Therefore, libtool will create a static module, that should work "
- echo "*** as long as the dlopening application is linked with the -dlopen flag."
- if test -z "$global_symbol_pipe"; then
- echo
- echo "*** However, this would only work if libtool was able to extract symbol"
- echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
- echo "*** not find such a program. So, this module is probably useless."
- echo "*** \`nm' from GNU binutils and a full rebuild may help."
- fi
- if test "$build_old_libs" = no; then
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- fi
- else
- convenience="$convenience $dir/$old_library"
- old_convenience="$old_convenience $dir/$old_library"
- deplibs="$dir/$old_library $deplibs"
- link_static=yes
- fi
- fi # link shared/static library?
-
- if test $linkmode = lib; then
- if test -n "$dependency_libs" &&
- { test $hardcode_into_libs != yes || test $build_old_libs = yes ||
- test $link_static = yes; }; then
- # Extract -R from dependency_libs
- temp_deplibs=
- for libdir in $dependency_libs; do
- case $libdir in
- -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
- case " $xrpath " in
- *" $temp_xrpath "*) ;;
- *) xrpath="$xrpath $temp_xrpath";;
- esac;;
- *) temp_deplibs="$temp_deplibs $libdir";;
- esac
- done
- dependency_libs="$temp_deplibs"
- fi
-
- newlib_search_path="$newlib_search_path $absdir"
- # Link against this library
- test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
- # ... and its dependency_libs
- tmp_libs=
- for deplib in $dependency_libs; do
- newdependency_libs="$deplib $newdependency_libs"
- case "$tmp_libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- tmp_libs="$tmp_libs $deplib"
- done
-
- if test $link_all_deplibs != no; then
- # Add the search paths of all dependency libraries
- for deplib in $dependency_libs; do
- case $deplib in
- -L*) path="$deplib" ;;
- *.la)
- dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$deplib" && dir="."
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
- *)
- absdir=`cd "$dir" && pwd`
- if test -z "$absdir"; then
- $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
- absdir="$dir"
- fi
- ;;
- esac
- if grep "^installed=no" $deplib > /dev/null; then
- path="-L$absdir/$objdir"
- else
- eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
- if test -z "$libdir"; then
- $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
- exit 1
- fi
- if test "$absdir" != "$libdir"; then
- $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
- fi
- path="-L$absdir"
- fi
- ;;
- *) continue ;;
- esac
- case " $deplibs " in
- *" $path "*) ;;
- *) deplibs="$deplibs $path" ;;
- esac
- done
- fi # link_all_deplibs != no
- fi # linkmode = lib
- done # for deplib in $libs
- if test $pass = dlpreopen; then
- # Link the dlpreopened libraries before other libraries
- for deplib in $save_deplibs; do
- deplibs="$deplib $deplibs"
- done
- fi
- if test $pass != dlopen; then
- test $pass != scan && dependency_libs="$newdependency_libs"
- if test $pass != conv; then
- # Make sure lib_search_path contains only unique directories.
- lib_search_path=
- for dir in $newlib_search_path; do
- case "$lib_search_path " in
- *" $dir "*) ;;
- *) lib_search_path="$lib_search_path $dir" ;;
- esac
- done
- newlib_search_path=
- fi
-
- if test "$linkmode,$pass" != "prog,link"; then
- vars="deplibs"
- else
- vars="compile_deplibs finalize_deplibs"
- fi
- for var in $vars dependency_libs; do
- # Add libraries to $var in reverse order
- eval tmp_libs=\"\$$var\"
- new_libs=
- for deplib in $tmp_libs; do
- case $deplib in
- -L*) new_libs="$deplib $new_libs" ;;
- *)
- case " $specialdeplibs " in
- *" $deplib "*) new_libs="$deplib $new_libs" ;;
- *)
- case " $new_libs " in
- *" $deplib "*) ;;
- *) new_libs="$deplib $new_libs" ;;
- esac
- ;;
- esac
- ;;
- esac
- done
- tmp_libs=
- for deplib in $new_libs; do
- case $deplib in
- -L*)
- case " $tmp_libs " in
- *" $deplib "*) ;;
- *) tmp_libs="$tmp_libs $deplib" ;;
- esac
- ;;
- *) tmp_libs="$tmp_libs $deplib" ;;
- esac
- done
- eval $var=\"$tmp_libs\"
- done # for var
- fi
- if test "$pass" = "conv" &&
- { test "$linkmode" = "lib" || test "$linkmode" = "prog"; }; then
- libs="$deplibs" # reset libs
- deplibs=
- fi
- done # for pass
- if test $linkmode = prog; then
- dlfiles="$newdlfiles"
- dlprefiles="$newdlprefiles"
- fi
-
- case $linkmode in
- oldlib)
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
- fi
-
- if test -n "$rpath"; then
- $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
- fi
-
- if test -n "$xrpath"; then
- $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
- fi
-
- if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
- $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
- fi
-
- # Now set the variables for building old libraries.
- build_libtool_libs=no
- oldlibs="$output"
- objs="$objs$old_deplibs"
- ;;
-
- lib)
- # Make sure we only generate libraries of the form `libNAME.la'.
- case $outputname in
- lib*)
- name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
- eval libname=\"$libname_spec\"
- ;;
- *)
- if test "$module" = no; then
- $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
- if test "$need_lib_prefix" != no; then
- # Add the "lib" prefix for modules if required
- name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
- eval libname=\"$libname_spec\"
- else
- libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
- fi
- ;;
- esac
-
- if test -n "$objs"; then
- if test "$deplibs_check_method" != pass_all; then
- $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
- exit 1
- else
- echo
- echo "*** Warning: Linking the shared library $output against the non-libtool"
- echo "*** objects $objs is not portable!"
- libobjs="$libobjs $objs"
- fi
- fi
-
- if test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
- fi
-
- set dummy $rpath
- if test $# -gt 2; then
- $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
- fi
- install_libdir="$2"
-
- oldlibs=
- if test -z "$rpath"; then
- if test "$build_libtool_libs" = yes; then
- # Building a libtool convenience library.
- libext=al
- oldlibs="$output_objdir/$libname.$libext $oldlibs"
- build_libtool_libs=convenience
- build_old_libs=yes
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
- fi
- else
-
- # Parse the version information argument.
- save_ifs="$IFS"; IFS=':'
- set dummy $vinfo 0 0 0
- IFS="$save_ifs"
-
- if test -n "$8"; then
- $echo "$modename: too many parameters to \`-version-info'" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- current="$2"
- revision="$3"
- age="$4"
-
- # Check that each of the things are valid numbers.
- case $current in
- 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
- *)
- $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- ;;
- esac
-
- case $revision in
- 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
- *)
- $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- ;;
- esac
-
- case $age in
- 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
- *)
- $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- ;;
- esac
-
- if test $age -gt $current; then
- $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- fi
-
- # Calculate the version variables.
- major=
- versuffix=
- verstring=
- case $version_type in
- none) ;;
-
- darwin)
- # Like Linux, but with the current version available in
- # verstring for coding it into the library header
- major=.`expr $current - $age`
- versuffix="$major.$age.$revision"
- # Darwin ld doesn't like 0 for these options...
- minor_current=`expr $current + 1`
- verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
- ;;
-
- freebsd-aout)
- major=".$current"
- versuffix=".$current.$revision";
- ;;
-
- freebsd-elf)
- major=".$current"
- versuffix=".$current";
- ;;
-
- irix)
- major=`expr $current - $age + 1`
- verstring="sgi$major.$revision"
-
- # Add in all the interfaces that we are compatible with.
- loop=$revision
- while test $loop != 0; do
- iface=`expr $revision - $loop`
- loop=`expr $loop - 1`
- verstring="sgi$major.$iface:$verstring"
- done
-
- # Before this point, $major must not contain `.'.
- major=.$major
- versuffix="$major.$revision"
- ;;
-
- linux)
- major=.`expr $current - $age`
- versuffix="$major.$age.$revision"
- ;;
-
- osf)
- major=`expr $current - $age`
- versuffix=".$current.$age.$revision"
- verstring="$current.$age.$revision"
-
- # Add in all the interfaces that we are compatible with.
- loop=$age
- while test $loop != 0; do
- iface=`expr $current - $loop`
- loop=`expr $loop - 1`
- verstring="$verstring:${iface}.0"
- done
-
- # Make executables depend on our current version.
- verstring="$verstring:${current}.0"
- ;;
-
- sunos)
- major=".$current"
- versuffix=".$current.$revision"
- ;;
-
- windows)
- # Use '-' rather than '.', since we only want one
- # extension on DOS 8.3 filesystems.
- major=`expr $current - $age`
- versuffix="-$major"
- ;;
-
- *)
- $echo "$modename: unknown library version type \`$version_type'" 1>&2
- echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit 1
- ;;
- esac
-
- # Clear the version info if we defaulted, and they specified a release.
- if test -z "$vinfo" && test -n "$release"; then
- major=
- verstring="0.0"
- case $version_type in
- darwin)
- # we can't check for "0.0" in archive_cmds due to quoting
- # problems, so we reset it completely
- verstring=""
- ;;
- *)
- verstring="0.0"
- ;;
- esac
- if test "$need_version" = no; then
- versuffix=
- else
- versuffix=".0.0"
- fi
- fi
-
- # Remove version info from name if versioning should be avoided
- if test "$avoid_version" = yes && test "$need_version" = no; then
- major=
- versuffix=
- verstring=""
- fi
-
- # Check to see if the archive will have undefined symbols.
- if test "$allow_undefined" = yes; then
- if test "$allow_undefined_flag" = unsupported; then
- $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
- build_libtool_libs=no
- build_old_libs=yes
- fi
- else
- # Don't allow undefined symbols.
- allow_undefined_flag="$no_undefined_flag"
- fi
- fi
-
- if test "$mode" != relink; then
- # Remove our outputs.
- $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*"
- $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*
- fi
-
- # Now set the variables for building old libraries.
- if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
- oldlibs="$oldlibs $output_objdir/$libname.$libext"
-
- # Transform .lo files to .o files.
- oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
- fi
-
- # Eliminate all temporary directories.
- for path in $notinst_path; do
- lib_search_path=`echo "$lib_search_path " | sed -e 's% $path % %g'`
- deplibs=`echo "$deplibs " | sed -e 's% -L$path % %g'`
- dependency_libs=`echo "$dependency_libs " | sed -e 's% -L$path % %g'`
- done
-
- if test -n "$xrpath"; then
- # If the user specified any rpath flags, then add them.
- temp_xrpath=
- for libdir in $xrpath; do
- temp_xrpath="$temp_xrpath -R$libdir"
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir" ;;
- esac
- done
- if test $hardcode_into_libs != yes || test $build_old_libs = yes; then
- dependency_libs="$temp_xrpath $dependency_libs"
- fi
- fi
-
- # Make sure dlfiles contains only unique files that won't be dlpreopened
- old_dlfiles="$dlfiles"
- dlfiles=
- for lib in $old_dlfiles; do
- case " $dlprefiles $dlfiles " in
- *" $lib "*) ;;
- *) dlfiles="$dlfiles $lib" ;;
- esac
- done
-
- # Make sure dlprefiles contains only unique files
- old_dlprefiles="$dlprefiles"
- dlprefiles=
- for lib in $old_dlprefiles; do
- case "$dlprefiles " in
- *" $lib "*) ;;
- *) dlprefiles="$dlprefiles $lib" ;;
- esac
- done
-
- if test "$build_libtool_libs" = yes; then
- if test -n "$rpath"; then
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
- # these systems don't actually have a c library (as such)!
- ;;
- *-*-rhapsody* | *-*-darwin1.[012])
- # Rhapsody C library is in the System framework
- deplibs="$deplibs -framework System"
- ;;
- *-*-netbsd*)
- # Don't link with libc until the a.out ld.so is fixed.
- ;;
- *-*-openbsd*)
- # Do not include libc due to us having libc/libc_r.
- ;;
- *)
- # Add libc to deplibs on all other systems if necessary.
- if test $build_libtool_need_lc = "yes"; then
- deplibs="$deplibs -lc"
- fi
- ;;
- esac
- fi
-
- # Transform deplibs into only deplibs that can be linked in shared.
- name_save=$name
- libname_save=$libname
- release_save=$release
- versuffix_save=$versuffix
- major_save=$major
- # I'm not sure if I'm treating the release correctly. I think
- # release should show up in the -l (ie -lgmp5) so we don't want to
- # add it in twice. Is that correct?
- release=""
- versuffix=""
- major=""
- newdeplibs=
- droppeddeps=no
- case $deplibs_check_method in
- pass_all)
- # Don't check for shared/static. Everything works.
- # This might be a little naive. We might want to check
- # whether the library exists or not. But this is on
- # osf3 & osf4 and I'm not really sure... Just
- # implementing what was already the behaviour.
- newdeplibs=$deplibs
- ;;
- test_compile)
- # This code stresses the "libraries are programs" paradigm to its
- # limits. Maybe even breaks it. We compile a program, linking it
- # against the deplibs as a proxy for the library. Then we can check
- # whether they linked in statically or dynamically with ldd.
- $rm conftest.c
- cat > conftest.c <<EOF
- int main() { return 0; }
-EOF
- $rm conftest
- $CC -o conftest conftest.c $deplibs
- if test $? -eq 0 ; then
- ldd_output=`ldd conftest`
- for i in $deplibs; do
- name="`expr $i : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test -n "$name" && test "$name" != "0"; then
- libname=`eval \\$echo \"$libname_spec\"`
- deplib_matches=`eval \\$echo \"$library_names_spec\"`
- set dummy $deplib_matches
- deplib_match=$2
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
- newdeplibs="$newdeplibs $i"
- else
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $i."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- newdeplibs="$newdeplibs $i"
- fi
- done
- else
- # Error occured in the first compile. Let's try to salvage the situation:
- # Compile a seperate program for each library.
- for i in $deplibs; do
- name="`expr $i : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test -n "$name" && test "$name" != "0"; then
- $rm conftest
- $CC -o conftest conftest.c $i
- # Did it work?
- if test $? -eq 0 ; then
- ldd_output=`ldd conftest`
- libname=`eval \\$echo \"$libname_spec\"`
- deplib_matches=`eval \\$echo \"$library_names_spec\"`
- set dummy $deplib_matches
- deplib_match=$2
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
- newdeplibs="$newdeplibs $i"
- else
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $i."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- droppeddeps=yes
- echo
- echo "*** Warning! Library $i is needed by this library but I was not able to"
- echo "*** make it link in! You will probably need to install it or some"
- echo "*** library that it depends on before this library will be fully"
- echo "*** functional. Installing it before continuing would be even better."
- fi
- else
- newdeplibs="$newdeplibs $i"
- fi
- done
- fi
- ;;
- file_magic*)
- set dummy $deplibs_check_method
- file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
- for a_deplib in $deplibs; do
- name="`expr $a_deplib : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test -n "$name" && test "$name" != "0"; then
- libname=`eval \\$echo \"$libname_spec\"`
- for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
- potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
- for potent_lib in $potential_libs; do
- # Follow soft links.
- if ls -lLd "$potent_lib" 2>/dev/null \
- | grep " -> " >/dev/null; then
- continue
- fi
- # The statement above tries to avoid entering an
- # endless loop below, in case of cyclic links.
- # We might still enter an endless loop, since a link
- # loop can be closed while we follow links,
- # but so what?
- potlib="$potent_lib"
- while test -h "$potlib" 2>/dev/null; do
- potliblink=`ls -ld $potlib | sed 's/.* -> //'`
- case $potliblink in
- [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
- *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
- esac
- done
- if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
- | sed 10q \
- | egrep "$file_magic_regex" > /dev/null; then
- newdeplibs="$newdeplibs $a_deplib"
- a_deplib=""
- break 2
- fi
- done
- done
- if test -n "$a_deplib" ; then
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $a_deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- # Add a -L argument.
- newdeplibs="$newdeplibs $a_deplib"
- fi
- done # Gone through all deplibs.
- ;;
- match_pattern*)
- set dummy $deplibs_check_method
- match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
- for a_deplib in $deplibs; do
- name="`expr $a_deplib : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test -n "$name" && test "$name" != "0"; then
- libname=`eval \\$echo \"$libname_spec\"`
- for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
- potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
- for potent_lib in $potential_libs; do
- if eval echo \"$potent_lib\" 2>/dev/null \
- | sed 10q \
- | egrep "$match_pattern_regex" > /dev/null; then
- newdeplibs="$newdeplibs $a_deplib"
- a_deplib=""
- break 2
- fi
- done
- done
- if test -n "$a_deplib" ; then
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $a_deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- # Add a -L argument.
- newdeplibs="$newdeplibs $a_deplib"
- fi
- done # Gone through all deplibs.
- ;;
- none | unknown | *)
- newdeplibs=""
- if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
- -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' |
- grep . >/dev/null; then
- echo
- if test "X$deplibs_check_method" = "Xnone"; then
- echo "*** Warning: inter-library dependencies are not supported in this platform."
- else
- echo "*** Warning: inter-library dependencies are not known to be supported."
- fi
- echo "*** All declared inter-library dependencies are being dropped."
- droppeddeps=yes
- fi
- ;;
- esac
- versuffix=$versuffix_save
- major=$major_save
- release=$release_save
- libname=$libname_save
- name=$name_save
-
- case $host in
- *-*-rhapsody* | *-*-darwin1.[012])
- # On Rhapsody replace the C library is the System framework
- newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
- ;;
- esac
-
- if test "$droppeddeps" = yes; then
- if test "$module" = yes; then
- echo
- echo "*** Warning: libtool could not satisfy all declared inter-library"
- echo "*** dependencies of module $libname. Therefore, libtool will create"
- echo "*** a static module, that should work as long as the dlopening"
- echo "*** application is linked with the -dlopen flag."
- if test -z "$global_symbol_pipe"; then
- echo
- echo "*** However, this would only work if libtool was able to extract symbol"
- echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
- echo "*** not find such a program. So, this module is probably useless."
- echo "*** \`nm' from GNU binutils and a full rebuild may help."
- fi
- if test "$build_old_libs" = no; then
- oldlibs="$output_objdir/$libname.$libext"
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- else
- echo "*** The inter-library dependencies that have been dropped here will be"
- echo "*** automatically added whenever a program is linked with this library"
- echo "*** or is declared to -dlopen it."
-
- if test $allow_undefined = no; then
- echo
- echo "*** Since this library must not contain undefined symbols,"
- echo "*** because either the platform does not support them or"
- echo "*** it was explicitly requested with -no-undefined,"
- echo "*** libtool will only create a static version of it."
- if test "$build_old_libs" = no; then
- oldlibs="$output_objdir/$libname.$libext"
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- fi
- fi
- fi
- # Done checking deplibs!
- deplibs=$newdeplibs
- fi
-
- # All the library-specific variables (install_libdir is set above).
- library_names=
- old_library=
- dlname=
-
- # Test again, we may have decided not to build it any more
- if test "$build_libtool_libs" = yes; then
- if test $hardcode_into_libs = yes; then
- # Hardcode the library paths
- hardcode_libdirs=
- dep_rpath=
- rpath="$finalize_rpath"
- test "$mode" != relink && rpath="$compile_rpath$rpath"
- for libdir in $rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- dep_rpath="$dep_rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$perm_rpath " in
- *" $libdir "*) ;;
- *) perm_rpath="$perm_rpath $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval dep_rpath=\"$hardcode_libdir_flag_spec\"
- fi
- if test -n "$runpath_var" && test -n "$perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $perm_rpath; do
- rpath="$rpath$dir:"
- done
- eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
- fi
- test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
- fi
-
- shlibpath="$finalize_shlibpath"
- test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
- if test -n "$shlibpath"; then
- eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
- fi
-
- # Get the real and link names of the library.
- eval library_names=\"$library_names_spec\"
- set dummy $library_names
- realname="$2"
- shift; shift
-
- if test -n "$soname_spec"; then
- eval soname=\"$soname_spec\"
- else
- soname="$realname"
- fi
- test -z "$dlname" && dlname=$soname
-
- lib="$output_objdir/$realname"
- for link
- do
- linknames="$linknames $link"
- done
-
- # Ensure that we have .o objects for linkers which dislike .lo
- # (e.g. aix) in case we are running --disable-static
- for obj in $libobjs; do
- xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$obj"; then
- xdir="."
- else
- xdir="$xdir"
- fi
- baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
- oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"`
- if test ! -f $xdir/$oldobj; then
- $show "(cd $xdir && ${LN_S} $baseobj $oldobj)"
- $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $?
- fi
- done
-
- # Use standard objects if they are pic
- test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
- $show "generating symbol list for \`$libname.la'"
- export_symbols="$output_objdir/$libname.exp"
- $run $rm $export_symbols
- eval cmds=\"$export_symbols_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- if test -n "$export_symbols_regex"; then
- $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
- $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
- $show "$mv \"${export_symbols}T\" \"$export_symbols\""
- $run eval '$mv "${export_symbols}T" "$export_symbols"'
- fi
- fi
- fi
-
- if test -n "$export_symbols" && test -n "$include_expsyms"; then
- $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
- fi
-
- if test -n "$convenience"; then
- if test -n "$whole_archive_flag_spec"; then
- eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
- else
- gentop="$output_objdir/${outputname}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "mkdir $gentop"
- $run mkdir "$gentop"
- status=$?
- if test $status -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
- generated="$generated $gentop"
-
- for xlib in $convenience; do
- # Extract the objects.
- case $xlib in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "mkdir $xdir"
- $run mkdir "$xdir"
- status=$?
- if test $status -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
-
- libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
- done
- fi
- fi
-
- if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
- eval flag=\"$thread_safe_flag_spec\"
- linker_flags="$linker_flags $flag"
- fi
-
- # Make a backup of the uninstalled library when relinking
- if test "$mode" = relink; then
- $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
- fi
-
- # Do each of the archive commands.
- if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
- eval cmds=\"$archive_expsym_cmds\"
- else
- eval cmds=\"$archive_cmds\"
- fi
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
-
- # Restore the uninstalled library and exit
- if test "$mode" = relink; then
- $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
- exit 0
- fi
-
- # Create links to the real library.
- for linkname in $linknames; do
- if test "$realname" != "$linkname"; then
- $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
- $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
- fi
- done
-
- # If -module or -export-dynamic was specified, set the dlname.
- if test "$module" = yes || test "$export_dynamic" = yes; then
- # On all known operating systems, these are identical.
- dlname="$soname"
- fi
- fi
- ;;
-
- obj)
- if test -n "$deplibs"; then
- $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
- fi
-
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
- fi
-
- if test -n "$rpath"; then
- $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
- fi
-
- if test -n "$xrpath"; then
- $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
- fi
-
- case $output in
- *.lo)
- if test -n "$objs$old_deplibs"; then
- $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
- exit 1
- fi
- libobj="$output"
- obj=`$echo "X$output" | $Xsed -e "$lo2o"`
- ;;
- *)
- libobj=
- obj="$output"
- ;;
- esac
-
- # Delete the old objects.
- $run $rm $obj $libobj
-
- # Objects from convenience libraries. This assumes
- # single-version convenience libraries. Whenever we create
- # different ones for PIC/non-PIC, this we'll have to duplicate
- # the extraction.
- reload_conv_objs=
- gentop=
- # reload_cmds runs $LD directly, so let us get rid of
- # -Wl from whole_archive_flag_spec
- wl=
-
- if test -n "$convenience"; then
- if test -n "$whole_archive_flag_spec"; then
- eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
- else
- gentop="$output_objdir/${obj}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "mkdir $gentop"
- $run mkdir "$gentop"
- status=$?
- if test $status -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
- generated="$generated $gentop"
-
- for xlib in $convenience; do
- # Extract the objects.
- case $xlib in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "mkdir $xdir"
- $run mkdir "$xdir"
- status=$?
- if test $status -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
-
- reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
- done
- fi
- fi
-
- # Create the old-style object.
- reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
-
- output="$obj"
- eval cmds=\"$reload_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
-
- # Exit if we aren't doing a library object file.
- if test -z "$libobj"; then
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- exit 0
- fi
-
- if test "$build_libtool_libs" != yes; then
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- # Create an invalid libtool object if no PIC, so that we don't
- # accidentally link it into a program.
- $show "echo timestamp > $libobj"
- $run eval "echo timestamp > $libobj" || exit $?
- exit 0
- fi
-
- if test -n "$pic_flag" || test "$pic_mode" != default; then
- # Only do commands if we really have different PIC objects.
- reload_objs="$libobjs $reload_conv_objs"
- output="$libobj"
- eval cmds=\"$reload_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- else
- # Just create a symlink.
- $show $rm $libobj
- $run $rm $libobj
- xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$libobj"; then
- xdir="."
- else
- xdir="$xdir"
- fi
- baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'`
- oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"`
- $show "(cd $xdir && $LN_S $oldobj $baseobj)"
- $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $?
- fi
-
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- exit 0
- ;;
-
- prog)
- case $host in
- *cygwin*) output=`echo $output | sed -e 's,.exe$,,;s,$,.exe,'` ;;
- esac
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
- fi
-
- if test "$preload" = yes; then
- if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
- test "$dlopen_self_static" = unknown; then
- $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
- fi
- fi
-
- case $host in
- *-*-rhapsody* | *-*-darwin1.[012])
- # On Rhapsody replace the C library is the System framework
- compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
- finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
- ;;
- esac
-
- compile_command="$compile_command $compile_deplibs"
- finalize_command="$finalize_command $finalize_deplibs"
-
- if test -n "$rpath$xrpath"; then
- # If the user specified any rpath flags, then add them.
- for libdir in $rpath $xrpath; do
- # This is the magic to use -rpath.
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir" ;;
- esac
- done
- fi
-
- # Now hardcode the library paths
- rpath=
- hardcode_libdirs=
- for libdir in $compile_rpath $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- rpath="$rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$perm_rpath " in
- *" $libdir "*) ;;
- *) perm_rpath="$perm_rpath $libdir" ;;
- esac
- fi
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- case :$dllsearchpath: in
- *":$libdir:"*) ;;
- *) dllsearchpath="$dllsearchpath:$libdir";;
- esac
- ;;
- esac
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- compile_rpath="$rpath"
-
- rpath=
- hardcode_libdirs=
- for libdir in $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- rpath="$rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$finalize_perm_rpath " in
- *" $libdir "*) ;;
- *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- finalize_rpath="$rpath"
-
- if test -n "$libobjs" && test "$build_old_libs" = yes; then
- # Transform all the library objects into standard objects.
- compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- fi
-
- dlsyms=
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- if test -n "$NM" && test -n "$global_symbol_pipe"; then
- dlsyms="${outputname}S.c"
- else
- $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
- fi
- fi
-
- if test -n "$dlsyms"; then
- case $dlsyms in
- "") ;;
- *.c)
- # Discover the nlist of each of the dlfiles.
- nlist="$output_objdir/${outputname}.nm"
-
- $show "$rm $nlist ${nlist}S ${nlist}T"
- $run $rm "$nlist" "${nlist}S" "${nlist}T"
-
- # Parse the name list into a source file.
- $show "creating $output_objdir/$dlsyms"
-
- test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
-/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
-/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
-
-#ifdef __cplusplus
-extern \"C\" {
-#endif
-
-/* Prevent the only kind of declaration conflicts we can make. */
-#define lt_preloaded_symbols some_other_symbol
-
-/* External symbol declarations for the compiler. */\
-"
-
- if test "$dlself" = yes; then
- $show "generating symbol list for \`$output'"
-
- test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
-
- # Add our own program objects to the symbol list.
- progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- for arg in $progfiles; do
- $show "extracting global C symbols from \`$arg'"
- $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
- done
-
- if test -n "$exclude_expsyms"; then
- $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
- $run eval '$mv "$nlist"T "$nlist"'
- fi
-
- if test -n "$export_symbols_regex"; then
- $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T'
- $run eval '$mv "$nlist"T "$nlist"'
- fi
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- export_symbols="$output_objdir/$output.exp"
- $run $rm $export_symbols
- $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
- else
- $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
- $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
- $run eval 'mv "$nlist"T "$nlist"'
- fi
- fi
-
- for arg in $dlprefiles; do
- $show "extracting global C symbols from \`$arg'"
- name=`echo "$arg" | sed -e 's%^.*/%%'`
- $run eval 'echo ": $name " >> "$nlist"'
- $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
- done
-
- if test -z "$run"; then
- # Make sure we have at least an empty file.
- test -f "$nlist" || : > "$nlist"
-
- if test -n "$exclude_expsyms"; then
- egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
- $mv "$nlist"T "$nlist"
- fi
-
- # Try sorting and uniquifying the output.
- if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then
- :
- else
- grep -v "^: " < "$nlist" > "$nlist"S
- fi
-
- if test -f "$nlist"S; then
- eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
- else
- echo '/* NONE */' >> "$output_objdir/$dlsyms"
- fi
-
- $echo >> "$output_objdir/$dlsyms" "\
-
-#undef lt_preloaded_symbols
-
-#if defined (__STDC__) && __STDC__
-# define lt_ptr void *
-#else
-# define lt_ptr char *
-# define const
-#endif
-
-/* The mapping between symbol names and symbols. */
-const struct {
- const char *name;
- lt_ptr address;
-}
-lt_preloaded_symbols[] =
-{\
-"
-
- eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
-
- $echo >> "$output_objdir/$dlsyms" "\
- {0, (lt_ptr) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
- return lt_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif\
-"
- fi
-
- pic_flag_for_symtable=
- case $host in
- # compiling the symbol table file with pic_flag works around
- # a FreeBSD bug that causes programs to crash when -lm is
- # linked before any other PIC object. But we must not use
- # pic_flag when linking with -static. The problem exists in
- # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
- *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
- case "$compile_command " in
- *" -static "*) ;;
- *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";;
- esac;;
- *-*-hpux*)
- case "$compile_command " in
- *" -static "*) ;;
- *) pic_flag_for_symtable=" $pic_flag -DPIC";;
- esac
- esac
-
- # Now compile the dynamic symbol file.
- $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
- $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
-
- # Clean up the generated files.
- $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
- $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
-
- # Transform the symbol file into the correct name.
- compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- ;;
- *)
- $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
- exit 1
- ;;
- esac
- else
- # We keep going just in case the user didn't refer to
- # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
- # really was required.
-
- # Nullify the symbol file.
- compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
- fi
-
- if test $need_relink = no || test "$build_libtool_libs" != yes; then
- # Replace the output file specification.
- compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
- link_command="$compile_command$compile_rpath"
-
- # We have no uninstalled library dependencies, so finalize right now.
- $show "$link_command"
- $run eval "$link_command"
- status=$?
-
- # Delete the generated files.
- if test -n "$dlsyms"; then
- $show "$rm $output_objdir/${outputname}S.${objext}"
- $run $rm "$output_objdir/${outputname}S.${objext}"
- fi
-
- exit $status
- fi
-
- if test -n "$shlibpath_var"; then
- # We should set the shlibpath_var
- rpath=
- for dir in $temp_rpath; do
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*)
- # Absolute path.
- rpath="$rpath$dir:"
- ;;
- *)
- # Relative path: add a thisdir entry.
- rpath="$rpath\$thisdir/$dir:"
- ;;
- esac
- done
- temp_rpath="$rpath"
- fi
-
- if test -n "$compile_shlibpath$finalize_shlibpath"; then
- compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
- fi
- if test -n "$finalize_shlibpath"; then
- finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
- fi
-
- compile_var=
- finalize_var=
- if test -n "$runpath_var"; then
- if test -n "$perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $perm_rpath; do
- rpath="$rpath$dir:"
- done
- compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- if test -n "$finalize_perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $finalize_perm_rpath; do
- rpath="$rpath$dir:"
- done
- finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- fi
-
- if test "$no_install" = yes; then
- # We don't need to create a wrapper script.
- link_command="$compile_var$compile_command$compile_rpath"
- # Replace the output file specification.
- link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
- # Delete the old output file.
- $run $rm $output
- # Link the executable and exit
- $show "$link_command"
- $run eval "$link_command" || exit $?
- exit 0
- fi
-
- if test "$hardcode_action" = relink; then
- # Fast installation is not supported
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
-
- $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
- $echo "$modename: \`$output' will be relinked during installation" 1>&2
- else
- if test "$fast_install" != no; then
- link_command="$finalize_var$compile_command$finalize_rpath"
- if test "$fast_install" = yes; then
- relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
- else
- # fast_install is set to needless
- relink_command=
- fi
- else
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
- fi
- fi
-
- # Replace the output file specification.
- link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
-
- # Delete the old output files.
- $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
-
- $show "$link_command"
- $run eval "$link_command" || exit $?
-
- # Now create the wrapper script.
- $show "creating $output"
-
- # Quote the relink command for shipping.
- if test -n "$relink_command"; then
- # Preserve any variables that may affect compiler behavior
- for var in $variables_saved_for_relink; do
- if eval test -z \"\${$var+set}\"; then
- relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
- elif eval var_value=\$$var; test -z "$var_value"; then
- relink_command="$var=; export $var; $relink_command"
- else
- var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
- relink_command="$var=\"$var_value\"; export $var; $relink_command"
- fi
- done
- relink_command="cd `pwd`; $relink_command"
- relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
- fi
-
- # Quote $echo for shipping.
- if test "X$echo" = "X$SHELL $0 --fallback-echo"; then
- case $0 in
- [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";;
- *) qecho="$SHELL `pwd`/$0 --fallback-echo";;
- esac
- qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
- else
- qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
- fi
-
- # Only actually do things if our run command is non-null.
- if test -z "$run"; then
- # win32 will think the script is a binary if it has
- # a .exe suffix, so we strip it off here.
- case $output in
- *.exe) output=`echo $output|sed 's,.exe$,,'` ;;
- esac
- # test for cygwin because mv fails w/o .exe extensions
- case $host in
- *cygwin*) exeext=.exe ;;
- *) exeext= ;;
- esac
- $rm $output
- trap "$rm $output; exit 1" 1 2 15
-
- $echo > $output "\
-#! $SHELL
-
-# $output - temporary wrapper script for $objdir/$outputname
-# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-#
-# The $output program cannot be directly executed until all the libtool
-# libraries that it depends on are installed.
-#
-# This wrapper script should never be moved out of the build directory.
-# If it is, it will not operate correctly.
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e 1s/^X//'
-sed_quote_subst='$sed_quote_subst'
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi
-
-relink_command=\"$relink_command\"
-
-# This environment variable determines our operation mode.
-if test \"\$libtool_install_magic\" = \"$magic\"; then
- # install mode needs the following variable:
- notinst_deplibs='$notinst_deplibs'
-else
- # When we are sourced in execute mode, \$file and \$echo are already set.
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- echo=\"$qecho\"
- file=\"\$0\"
- # Make sure echo works.
- if test \"X\$1\" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
- elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
- # Yippee, \$echo works!
- :
- else
- # Restart under the correct shell, and then maybe \$echo will work.
- exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
- fi
- fi\
-"
- $echo >> $output "\
-
- # Find the directory that this script lives in.
- thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
- test \"x\$thisdir\" = \"x\$file\" && thisdir=.
-
- # Follow symbolic links until we get to the real thisdir.
- file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\`
- while test -n \"\$file\"; do
- destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
-
- # If there was a directory component, then change thisdir.
- if test \"x\$destdir\" != \"x\$file\"; then
- case \"\$destdir\" in
- [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
- *) thisdir=\"\$thisdir/\$destdir\" ;;
- esac
- fi
-
- file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
- file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\`
- done
-
- # Try to get the absolute directory name.
- absdir=\`cd \"\$thisdir\" && pwd\`
- test -n \"\$absdir\" && thisdir=\"\$absdir\"
-"
-
- if test "$fast_install" = yes; then
- echo >> $output "\
- program=lt-'$outputname'$exeext
- progdir=\"\$thisdir/$objdir\"
-
- if test ! -f \"\$progdir/\$program\" || \\
- { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\
- test \"X\$file\" != \"X\$progdir/\$program\"; }; then
-
- file=\"\$\$-\$program\"
-
- if test ! -d \"\$progdir\"; then
- $mkdir \"\$progdir\"
- else
- $rm \"\$progdir/\$file\"
- fi"
-
- echo >> $output "\
-
- # relink executable if necessary
- if test -n \"\$relink_command\"; then
- if relink_command_output=\`eval \$relink_command 2>&1\`; then :
- else
- $echo \"\$relink_command_output\" >&2
- $rm \"\$progdir/\$file\"
- exit 1
- fi
- fi
-
- $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
- { $rm \"\$progdir/\$program\";
- $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
- $rm \"\$progdir/\$file\"
- fi"
- else
- echo >> $output "\
- program='$outputname'
- progdir=\"\$thisdir/$objdir\"
-"
- fi
-
- echo >> $output "\
-
- if test -f \"\$progdir/\$program\"; then"
-
- # Export our shlibpath_var if we have one.
- if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
- $echo >> $output "\
- # Add our own library path to $shlibpath_var
- $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
-
- # Some systems cannot cope with colon-terminated $shlibpath_var
- # The second colon is a workaround for a bug in BeOS R4 sed
- $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
-
- export $shlibpath_var
-"
- fi
-
- # fixup the dll searchpath if we need to.
- if test -n "$dllsearchpath"; then
- $echo >> $output "\
- # Add the dll search path components to the executable PATH
- PATH=$dllsearchpath:\$PATH
-"
- fi
-
- $echo >> $output "\
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- # Run the actual program with our arguments.
-"
- case $host in
- # win32 systems need to use the prog path for dll
- # lookup to work
- *-*-cygwin* | *-*-pw32*)
- $echo >> $output "\
- exec \$progdir/\$program \${1+\"\$@\"}
-"
- ;;
-
- # Backslashes separate directories on plain windows
- *-*-mingw | *-*-os2*)
- $echo >> $output "\
- exec \$progdir\\\\\$program \${1+\"\$@\"}
-"
- ;;
-
- *)
- $echo >> $output "\
- # Export the path to the program.
- PATH=\"\$progdir:\$PATH\"
- export PATH
-
- exec \$program \${1+\"\$@\"}
-"
- ;;
- esac
- $echo >> $output "\
- \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
- exit 1
- fi
- else
- # The program doesn't exist.
- \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
- \$echo \"This script is just a wrapper for \$program.\" 1>&2
- echo \"See the $PACKAGE documentation for more information.\" 1>&2
- exit 1
- fi
-fi\
-"
- chmod +x $output
- fi
- exit 0
- ;;
- esac
-
- # See if we need to build an old-fashioned archive.
- for oldlib in $oldlibs; do
-
- if test "$build_libtool_libs" = convenience; then
- oldobjs="$libobjs_save"
- addlibs="$convenience"
- build_libtool_libs=no
- else
- if test "$build_libtool_libs" = module; then
- oldobjs="$libobjs_save"
- build_libtool_libs=no
- else
- oldobjs="$objs$old_deplibs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`
- fi
- addlibs="$old_convenience"
- fi
-
- if test -n "$addlibs"; then
- gentop="$output_objdir/${outputname}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "mkdir $gentop"
- $run mkdir "$gentop"
- status=$?
- if test $status -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
- generated="$generated $gentop"
-
- # Add in members from convenience archives.
- for xlib in $addlibs; do
- # Extract the objects.
- case $xlib in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "mkdir $xdir"
- $run mkdir "$xdir"
- status=$?
- if test $status -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
-
- oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
- done
- fi
-
- # Do each command in the archive commands.
- if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
- eval cmds=\"$old_archive_from_new_cmds\"
- else
- # Ensure that we have .o objects in place in case we decided
- # not to build a shared library, and have fallen back to building
- # static libs even though --disable-static was passed!
- for oldobj in $oldobjs; do
- if test ! -f $oldobj; then
- xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$oldobj"; then
- xdir="."
- else
- xdir="$xdir"
- fi
- baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'`
- obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"`
- $show "(cd $xdir && ${LN_S} $obj $baseobj)"
- $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $?
- fi
- done
-
- eval cmds=\"$old_archive_cmds\"
- fi
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- done
-
- if test -n "$generated"; then
- $show "${rm}r$generated"
- $run ${rm}r$generated
- fi
-
- # Now create the libtool archive.
- case $output in
- *.la)
- old_library=
- test "$build_old_libs" = yes && old_library="$libname.$libext"
- $show "creating $output"
-
- # Preserve any variables that may affect compiler behavior
- for var in $variables_saved_for_relink; do
- if eval test -z \"\${$var+set}\"; then
- relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
- elif eval var_value=\$$var; test -z "$var_value"; then
- relink_command="$var=; export $var; $relink_command"
- else
- var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
- relink_command="$var=\"$var_value\"; export $var; $relink_command"
- fi
- done
- # Quote the link command for shipping.
- relink_command="cd `pwd`; $SHELL $0 --mode=relink $libtool_args"
- relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
-
- # Only create the output if not a dry run.
- if test -z "$run"; then
- for installed in no yes; do
- if test "$installed" = yes; then
- if test -z "$install_libdir"; then
- break
- fi
- output="$output_objdir/$outputname"i
- # Replace all uninstalled libtool libraries with the installed ones
- newdependency_libs=
- for deplib in $dependency_libs; do
- case $deplib in
- *.la)
- name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
- eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
- if test -z "$libdir"; then
- $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
- exit 1
- fi
- newdependency_libs="$newdependency_libs $libdir/$name"
- ;;
- *) newdependency_libs="$newdependency_libs $deplib" ;;
- esac
- done
- dependency_libs="$newdependency_libs"
- newdlfiles=
- for lib in $dlfiles; do
- name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
- eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
- if test -z "$libdir"; then
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit 1
- fi
- newdlfiles="$newdlfiles $libdir/$name"
- done
- dlfiles="$newdlfiles"
- newdlprefiles=
- for lib in $dlprefiles; do
- name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
- eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
- if test -z "$libdir"; then
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit 1
- fi
- newdlprefiles="$newdlprefiles $libdir/$name"
- done
- dlprefiles="$newdlprefiles"
- fi
- $rm $output
- # place dlname in correct position for cygwin
- tdlname=$dlname
- case $host,$output,$installed,$module,$dlname in
- *cygwin*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
- esac
- $echo > $output "\
-# $outputname - a libtool library file
-# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# The name that we can dlopen(3).
-dlname='$tdlname'
-
-# Names of this library.
-library_names='$library_names'
-
-# The name of the static archive.
-old_library='$old_library'
-
-# Libraries that this one depends upon.
-dependency_libs='$dependency_libs'
-
-# Version information for $libname.
-current=$current
-age=$age
-revision=$revision
-
-# Is this an already installed library?
-installed=$installed
-
-# Files to dlopen/dlpreopen
-dlopen='$dlfiles'
-dlpreopen='$dlprefiles'
-
-# Directory that this library needs to be installed in:
-libdir='$install_libdir'"
- if test "$installed" = no && test $need_relink = yes; then
- $echo >> $output "\
-relink_command=\"$relink_command\""
- fi
- done
- fi
-
- # Do a symbolic link so that the libtool archive can be found in
- # LD_LIBRARY_PATH before the program is installed.
- $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
- $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
- ;;
- esac
- exit 0
- ;;
-
- # libtool install mode
- install)
- modename="$modename: install"
-
- # There may be an optional sh(1) argument at the beginning of
- # install_prog (especially on Windows NT).
- if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
- # Allow the use of GNU shtool's install command.
- $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then
- # Aesthetically quote it.
- arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- install_prog="$arg "
- arg="$1"
- shift
- else
- install_prog=
- arg="$nonopt"
- fi
-
- # The real first argument should be the name of the installation program.
- # Aesthetically quote it.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- install_prog="$install_prog$arg"
-
- # We need to accept at least all the BSD install flags.
- dest=
- files=
- opts=
- prev=
- install_type=
- isdir=no
- stripme=
- for arg
- do
- if test -n "$dest"; then
- files="$files $dest"
- dest="$arg"
- continue
- fi
-
- case $arg in
- -d) isdir=yes ;;
- -f) prev="-f" ;;
- -g) prev="-g" ;;
- -m) prev="-m" ;;
- -o) prev="-o" ;;
- -s)
- stripme=" -s"
- continue
- ;;
- -*) ;;
-
- *)
- # If the previous option needed an argument, then skip it.
- if test -n "$prev"; then
- prev=
- else
- dest="$arg"
- continue
- fi
- ;;
- esac
-
- # Aesthetically quote the argument.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- install_prog="$install_prog $arg"
- done
-
- if test -z "$install_prog"; then
- $echo "$modename: you must specify an install program" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- if test -n "$prev"; then
- $echo "$modename: the \`$prev' option requires an argument" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- if test -z "$files"; then
- if test -z "$dest"; then
- $echo "$modename: no file or destination specified" 1>&2
- else
- $echo "$modename: you must specify a destination" 1>&2
- fi
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Strip any trailing slash from the destination.
- dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
-
- # Check to see that the destination is a directory.
- test -d "$dest" && isdir=yes
- if test "$isdir" = yes; then
- destdir="$dest"
- destname=
- else
- destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
- test "X$destdir" = "X$dest" && destdir=.
- destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
-
- # Not a directory, so check to see that there is only one file specified.
- set dummy $files
- if test $# -gt 2; then
- $echo "$modename: \`$dest' is not a directory" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
- fi
- case $destdir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- for file in $files; do
- case $file in
- *.lo) ;;
- *)
- $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
- esac
- done
- ;;
- esac
-
- # This variable tells wrapper scripts just to set variables rather
- # than running their programs.
- libtool_install_magic="$magic"
-
- staticlibs=
- future_libdirs=
- current_libdirs=
- for file in $files; do
-
- # Do each installation.
- case $file in
- *.$libext)
- # Do the static libraries later.
- staticlibs="$staticlibs $file"
- ;;
-
- *.la)
- # Check to see that this really is a libtool archive.
- if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- library_names=
- old_library=
- relink_command=
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Add the libdir to current_libdirs if it is the destination.
- if test "X$destdir" = "X$libdir"; then
- case "$current_libdirs " in
- *" $libdir "*) ;;
- *) current_libdirs="$current_libdirs $libdir" ;;
- esac
- else
- # Note the libdir as a future libdir.
- case "$future_libdirs " in
- *" $libdir "*) ;;
- *) future_libdirs="$future_libdirs $libdir" ;;
- esac
- fi
-
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
- test "X$dir" = "X$file/" && dir=
- dir="$dir$objdir"
-
- if test -n "$relink_command"; then
- $echo "$modename: warning: relinking \`$file'" 1>&2
- $show "$relink_command"
- if $run eval "$relink_command"; then :
- else
- $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
- continue
- fi
- fi
-
- # See the names of the shared library.
- set dummy $library_names
- if test -n "$2"; then
- realname="$2"
- shift
- shift
-
- srcname="$realname"
- test -n "$relink_command" && srcname="$realname"T
-
- # Install the shared library and build the symlinks.
- $show "$install_prog $dir/$srcname $destdir/$realname"
- $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
- if test -n "$stripme" && test -n "$striplib"; then
- $show "$striplib $destdir/$realname"
- $run eval "$striplib $destdir/$realname" || exit $?
- fi
-
- if test $# -gt 0; then
- # Delete the old symlinks, and create new ones.
- for linkname
- do
- if test "$linkname" != "$realname"; then
- $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
- $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
- fi
- done
- fi
-
- # Do each command in the postinstall commands.
- lib="$destdir/$realname"
- eval cmds=\"$postinstall_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
-
- # Install the pseudo-library for information purposes.
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- instname="$dir/$name"i
- $show "$install_prog $instname $destdir/$name"
- $run eval "$install_prog $instname $destdir/$name" || exit $?
-
- # Maybe install the static library, too.
- test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
- ;;
-
- *.lo)
- # Install (i.e. copy) a libtool object.
-
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile="$destdir/$destname"
- else
- destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- destfile="$destdir/$destfile"
- fi
-
- # Deduce the name of the destination old-style object file.
- case $destfile in
- *.lo)
- staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
- ;;
- *.$objext)
- staticdest="$destfile"
- destfile=
- ;;
- *)
- $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
- esac
-
- # Install the libtool object if requested.
- if test -n "$destfile"; then
- $show "$install_prog $file $destfile"
- $run eval "$install_prog $file $destfile" || exit $?
- fi
-
- # Install the old object if enabled.
- if test "$build_old_libs" = yes; then
- # Deduce the name of the old-style object file.
- staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
-
- $show "$install_prog $staticobj $staticdest"
- $run eval "$install_prog \$staticobj \$staticdest" || exit $?
- fi
- exit 0
- ;;
-
- *)
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile="$destdir/$destname"
- else
- destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- destfile="$destdir/$destfile"
- fi
-
- # Do a test to see if this is really a libtool program.
- if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- notinst_deplibs=
- relink_command=
-
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Check the variables that should have been set.
- if test -z "$notinst_deplibs"; then
- $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2
- exit 1
- fi
-
- finalize=yes
- for lib in $notinst_deplibs; do
- # Check to see that each library is installed.
- libdir=
- if test -f "$lib"; then
- # If there is no directory component, then add one.
- case $lib in
- */* | *\\*) . $lib ;;
- *) . ./$lib ;;
- esac
- fi
- libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
- if test -n "$libdir" && test ! -f "$libfile"; then
- $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
- finalize=no
- fi
- done
-
- relink_command=
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- outputname=
- if test "$fast_install" = no && test -n "$relink_command"; then
- if test "$finalize" = yes && test -z "$run"; then
- tmpdir="/tmp"
- test -n "$TMPDIR" && tmpdir="$TMPDIR"
- tmpdir="$tmpdir/libtool-$$"
- if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then :
- else
- $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
- continue
- fi
- file=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- outputname="$tmpdir/$file"
- # Replace the output file specification.
- relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
-
- $show "$relink_command"
- if $run eval "$relink_command"; then :
- else
- $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
- ${rm}r "$tmpdir"
- continue
- fi
- file="$outputname"
- else
- $echo "$modename: warning: cannot relink \`$file'" 1>&2
- fi
- else
- # Install the binary that we compiled earlier.
- file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
- fi
- fi
-
- # remove .exe since cygwin /usr/bin/install will append another
- # one anyways
- case $install_prog,$host in
- /usr/bin/install*,*cygwin*)
- case $file:$destfile in
- *.exe:*.exe)
- # this is ok
- ;;
- *.exe:*)
- destfile=$destfile.exe
- ;;
- *:*.exe)
- destfile=`echo $destfile | sed -e 's,.exe$,,'`
- ;;
- esac
- ;;
- esac
- $show "$install_prog$stripme $file $destfile"
- $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
- test -n "$outputname" && ${rm}r "$tmpdir"
- ;;
- esac
- done
-
- for file in $staticlibs; do
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
-
- # Set up the ranlib parameters.
- oldlib="$destdir/$name"
-
- $show "$install_prog $file $oldlib"
- $run eval "$install_prog \$file \$oldlib" || exit $?
-
- if test -n "$stripme" && test -n "$striplib"; then
- $show "$old_striplib $oldlib"
- $run eval "$old_striplib $oldlib" || exit $?
- fi
-
- # Do each command in the postinstall commands.
- eval cmds=\"$old_postinstall_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- done
-
- if test -n "$future_libdirs"; then
- $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
- fi
-
- if test -n "$current_libdirs"; then
- # Maybe just do a dry run.
- test -n "$run" && current_libdirs=" -n$current_libdirs"
- exec_cmd='$SHELL $0 --finish$current_libdirs'
- else
- exit 0
- fi
- ;;
-
- # libtool finish mode
- finish)
- modename="$modename: finish"
- libdirs="$nonopt"
- admincmds=
-
- if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
- for dir
- do
- libdirs="$libdirs $dir"
- done
-
- for libdir in $libdirs; do
- if test -n "$finish_cmds"; then
- # Do each command in the finish commands.
- eval cmds=\"$finish_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || admincmds="$admincmds
- $cmd"
- done
- IFS="$save_ifs"
- fi
- if test -n "$finish_eval"; then
- # Do the single finish_eval.
- eval cmds=\"$finish_eval\"
- $run eval "$cmds" || admincmds="$admincmds
- $cmds"
- fi
- done
- fi
-
- # Exit here if they wanted silent mode.
- test "$show" = ":" && exit 0
-
- echo "----------------------------------------------------------------------"
- echo "Libraries have been installed in:"
- for libdir in $libdirs; do
- echo " $libdir"
- done
- echo
- echo "If you ever happen to want to link against installed libraries"
- echo "in a given directory, LIBDIR, you must either use libtool, and"
- echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
- echo "flag during linking and do at least one of the following:"
- if test -n "$shlibpath_var"; then
- echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
- echo " during execution"
- fi
- if test -n "$runpath_var"; then
- echo " - add LIBDIR to the \`$runpath_var' environment variable"
- echo " during linking"
- fi
- if test -n "$hardcode_libdir_flag_spec"; then
- libdir=LIBDIR
- eval flag=\"$hardcode_libdir_flag_spec\"
-
- echo " - use the \`$flag' linker flag"
- fi
- if test -n "$admincmds"; then
- echo " - have your system administrator run these commands:$admincmds"
- fi
- if test -f /etc/ld.so.conf; then
- echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
- fi
- echo
- echo "See any operating system documentation about shared libraries for"
- echo "more information, such as the ld(1) and ld.so(8) manual pages."
- echo "----------------------------------------------------------------------"
- exit 0
- ;;
-
- # libtool execute mode
- execute)
- modename="$modename: execute"
-
- # The first argument is the command name.
- cmd="$nonopt"
- if test -z "$cmd"; then
- $echo "$modename: you must specify a COMMAND" 1>&2
- $echo "$help"
- exit 1
- fi
-
- # Handle -dlopen flags immediately.
- for file in $execute_dlfiles; do
- if test ! -f "$file"; then
- $echo "$modename: \`$file' is not a file" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- dir=
- case $file in
- *.la)
- # Check to see that this really is a libtool archive.
- if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Read the libtool library.
- dlname=
- library_names=
-
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Skip this library if it cannot be dlopened.
- if test -z "$dlname"; then
- # Warn if it was a shared library.
- test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
- continue
- fi
-
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$file" && dir=.
-
- if test -f "$dir/$objdir/$dlname"; then
- dir="$dir/$objdir"
- else
- $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
- exit 1
- fi
- ;;
-
- *.lo)
- # Just add the directory containing the .lo file.
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$file" && dir=.
- ;;
-
- *)
- $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
- continue
- ;;
- esac
-
- # Get the absolute pathname.
- absdir=`cd "$dir" && pwd`
- test -n "$absdir" && dir="$absdir"
-
- # Now add the directory to shlibpath_var.
- if eval "test -z \"\$$shlibpath_var\""; then
- eval "$shlibpath_var=\"\$dir\""
- else
- eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
- fi
- done
-
- # This variable tells wrapper scripts just to set shlibpath_var
- # rather than running their programs.
- libtool_execute_magic="$magic"
-
- # Check if any of the arguments is a wrapper script.
- args=
- for file
- do
- case $file in
- -*) ;;
- *)
- # Do a test to see if this is really a libtool program.
- if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Transform arg to wrapped name.
- file="$progdir/$program"
- fi
- ;;
- esac
- # Quote arguments (to preserve shell metacharacters).
- file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
- args="$args \"$file\""
- done
-
- if test -z "$run"; then
- if test -n "$shlibpath_var"; then
- # Export the shlibpath_var.
- eval "export $shlibpath_var"
- fi
-
- # Restore saved enviroment variables
- if test "${save_LC_ALL+set}" = set; then
- LC_ALL="$save_LC_ALL"; export LC_ALL
- fi
- if test "${save_LANG+set}" = set; then
- LANG="$save_LANG"; export LANG
- fi
-
- # Now prepare to actually exec the command.
- exec_cmd='"$cmd"$args'
- else
- # Display what would be done.
- if test -n "$shlibpath_var"; then
- eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
- $echo "export $shlibpath_var"
- fi
- $echo "$cmd$args"
- exit 0
- fi
- ;;
-
- # libtool clean and uninstall mode
- clean | uninstall)
- modename="$modename: $mode"
- rm="$nonopt"
- files=
- rmforce=
- exit_status=0
-
- # This variable tells wrapper scripts just to set variables rather
- # than running their programs.
- libtool_install_magic="$magic"
-
- for arg
- do
- case $arg in
- -f) rm="$rm $arg"; rmforce=yes ;;
- -*) rm="$rm $arg" ;;
- *) files="$files $arg" ;;
- esac
- done
-
- if test -z "$rm"; then
- $echo "$modename: you must specify an RM program" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- rmdirs=
-
- for file in $files; do
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$dir" = "X$file"; then
- dir=.
- objdir="$objdir"
- else
- objdir="$dir/$objdir"
- fi
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- test $mode = uninstall && objdir="$dir"
-
- # Remember objdir for removal later, being careful to avoid duplicates
- if test $mode = clean; then
- case " $rmdirs " in
- *" $objdir "*) ;;
- *) rmdirs="$rmdirs $objdir" ;;
- esac
- fi
-
- # Don't error if the file doesn't exist and rm -f was used.
- if (test -L "$file") >/dev/null 2>&1 \
- || (test -h "$file") >/dev/null 2>&1 \
- || test -f "$file"; then
- :
- elif test -d "$file"; then
- exit_status=1
- continue
- elif test "$rmforce" = yes; then
- continue
- fi
-
- rmfiles="$file"
-
- case $name in
- *.la)
- # Possibly a libtool archive, so verify it.
- if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- . $dir/$name
-
- # Delete the libtool libraries and symlinks.
- for n in $library_names; do
- rmfiles="$rmfiles $objdir/$n"
- done
- test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
- test $mode = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
-
- if test $mode = uninstall; then
- if test -n "$library_names"; then
- # Do each command in the postuninstall commands.
- eval cmds=\"$postuninstall_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd"
- if test $? != 0 && test "$rmforce" != yes; then
- exit_status=1
- fi
- done
- IFS="$save_ifs"
- fi
-
- if test -n "$old_library"; then
- # Do each command in the old_postuninstall commands.
- eval cmds=\"$old_postuninstall_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd"
- if test $? != 0 && test "$rmforce" != yes; then
- exit_status=1
- fi
- done
- IFS="$save_ifs"
- fi
- # FIXME: should reinstall the best remaining shared library.
- fi
- fi
- ;;
-
- *.lo)
- if test "$build_old_libs" = yes; then
- oldobj=`$echo "X$name" | $Xsed -e "$lo2o"`
- rmfiles="$rmfiles $dir/$oldobj"
- fi
- ;;
-
- *)
- # Do a test to see if this is a libtool program.
- if test $mode = clean &&
- (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- relink_command=
- . $dir/$file
-
- rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
- if test "$fast_install" = yes && test -n "$relink_command"; then
- rmfiles="$rmfiles $objdir/lt-$name"
- fi
- fi
- ;;
- esac
- $show "$rm $rmfiles"
- $run $rm $rmfiles || exit_status=1
- done
-
- # Try to remove the ${objdir}s in the directories where we deleted files
- for dir in $rmdirs; do
- if test -d "$dir"; then
- $show "rmdir $dir"
- $run rmdir $dir >/dev/null 2>&1
- fi
- done
-
- exit $exit_status
- ;;
-
- "")
- $echo "$modename: you must specify a MODE" 1>&2
- $echo "$generic_help" 1>&2
- exit 1
- ;;
- esac
-
- if test -z "$exec_cmd"; then
- $echo "$modename: invalid operation mode \`$mode'" 1>&2
- $echo "$generic_help" 1>&2
- exit 1
- fi
-fi # test -z "$show_help"
-
-if test -n "$exec_cmd"; then
- eval exec $exec_cmd
- exit 1
-fi
-
-# We need to display help for each of the modes.
-case $mode in
-"") $echo \
-"Usage: $modename [OPTION]... [MODE-ARG]...
-
-Provide generalized library-building support services.
-
- --config show all configuration variables
- --debug enable verbose shell tracing
--n, --dry-run display commands without modifying any files
- --features display basic configuration information and exit
- --finish same as \`--mode=finish'
- --help display this help message and exit
- --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
- --quiet same as \`--silent'
- --silent don't print informational messages
- --version print version information
-
-MODE must be one of the following:
-
- clean remove files from the build directory
- compile compile a source file into a libtool object
- execute automatically set library path, then run a program
- finish complete the installation of libtool libraries
- install install libraries or executables
- link create a library or an executable
- uninstall remove libraries from an installed directory
-
-MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
-a more detailed description of MODE."
- exit 0
- ;;
-
-clean)
- $echo \
-"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
-
-Remove files from the build directory.
-
-RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
-to RM.
-
-If FILE is a libtool library, object or program, all the files associated
-with it are deleted. Otherwise, only FILE itself is deleted using RM."
- ;;
-
-compile)
- $echo \
-"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
-
-Compile a source file into a libtool library object.
-
-This mode accepts the following additional options:
-
- -o OUTPUT-FILE set the output file name to OUTPUT-FILE
- -prefer-pic try to building PIC objects only
- -prefer-non-pic try to building non-PIC objects only
- -static always build a \`.o' file suitable for static linking
-
-COMPILE-COMMAND is a command to be used in creating a \`standard' object file
-from the given SOURCEFILE.
-
-The output file name is determined by removing the directory component from
-SOURCEFILE, then substituting the C source code suffix \`.c' with the
-library object suffix, \`.lo'."
- ;;
-
-execute)
- $echo \
-"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
-
-Automatically set library path, then run a program.
-
-This mode accepts the following additional options:
-
- -dlopen FILE add the directory containing FILE to the library path
-
-This mode sets the library path environment variable according to \`-dlopen'
-flags.
-
-If any of the ARGS are libtool executable wrappers, then they are translated
-into their corresponding uninstalled binary, and any of their required library
-directories are added to the library path.
-
-Then, COMMAND is executed, with ARGS as arguments."
- ;;
-
-finish)
- $echo \
-"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
-
-Complete the installation of libtool libraries.
-
-Each LIBDIR is a directory that contains libtool libraries.
-
-The commands that this mode executes may require superuser privileges. Use
-the \`--dry-run' option if you just want to see what would be executed."
- ;;
-
-install)
- $echo \
-"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
-
-Install executables or libraries.
-
-INSTALL-COMMAND is the installation command. The first component should be
-either the \`install' or \`cp' program.
-
-The rest of the components are interpreted as arguments to that command (only
-BSD-compatible install options are recognized)."
- ;;
-
-link)
- $echo \
-"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
-
-Link object files or libraries together to form another library, or to
-create an executable program.
-
-LINK-COMMAND is a command using the C compiler that you would use to create
-a program from several object files.
-
-The following components of LINK-COMMAND are treated specially:
-
- -all-static do not do any dynamic linking at all
- -avoid-version do not add a version suffix if possible
- -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
- -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
- -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
- -export-symbols SYMFILE
- try to export only the symbols listed in SYMFILE
- -export-symbols-regex REGEX
- try to export only the symbols matching REGEX
- -LLIBDIR search LIBDIR for required installed libraries
- -lNAME OUTPUT-FILE requires the installed library libNAME
- -module build a library that can dlopened
- -no-fast-install disable the fast-install mode
- -no-install link a not-installable executable
- -no-undefined declare that a library does not refer to external symbols
- -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
- -release RELEASE specify package release information
- -rpath LIBDIR the created library will eventually be installed in LIBDIR
- -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
- -static do not do any dynamic linking of libtool libraries
- -version-info CURRENT[:REVISION[:AGE]]
- specify library version info [each variable defaults to 0]
-
-All other options (arguments beginning with \`-') are ignored.
-
-Every other argument is treated as a filename. Files ending in \`.la' are
-treated as uninstalled libtool libraries, other files are standard or library
-object files.
-
-If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
-only library objects (\`.lo' files) may be specified, and \`-rpath' is
-required, except when creating a convenience library.
-
-If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
-using \`ar' and \`ranlib', or on Windows using \`lib'.
-
-If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
-is created, otherwise an executable program is created."
- ;;
-
-uninstall)
- $echo \
-"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
-
-Remove libraries from an installation directory.
-
-RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
-to RM.
-
-If FILE is a libtool library, all the files associated with it are deleted.
-Otherwise, only FILE itself is deleted using RM."
- ;;
-
-*)
- $echo "$modename: invalid operation mode \`$mode'" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
-esac
-
-echo
-$echo "Try \`$modename --help' for more information about other modes."
-
-exit 0
-
-# Local Variables:
-# mode:shell-script
-# sh-indentation:2
-# End:
diff --git a/boehm-gc/acinclude.m4 b/boehm-gc/m4/gc_set_version.m4
index 72602a0040b..e805a7a3de7 100644
--- a/boehm-gc/acinclude.m4
+++ b/boehm-gc/m4/gc_set_version.m4
@@ -1,30 +1,27 @@
-#
-#
+#
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-#
+#
# Permission is hereby granted to use or copy this program
# for any purpose, provided the above notices are retained on all copies.
# Permission to modify the code and to distribute modified code is granted,
# provided the above notices are retained, and a notice that the code was
# modified is included with the above copyright notice.
-#
-# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
# GC_SET_VERSION
# sets and AC_DEFINEs GC_VERSION_MAJOR, GC_VERSION_MINOR and GC_ALPHA_VERSION
# based on the contents of PACKAGE_VERSION; PACKAGE_VERSION must conform to
-# [0-9]+[.][0-9]+(alpha[0.9]+)?
+# [0-9]+[.][0-9]+(alpha[0.9]+)?
# in lex syntax; if there is no alpha number, GC_ALPHA_VERSION is empty
#
-AC_DEFUN(GC_SET_VERSION, [
+AC_DEFUN([GC_SET_VERSION], [
AC_MSG_CHECKING(GC version numbers)
GC_VERSION_MAJOR=`echo $PACKAGE_VERSION | sed 's/^\([[0-9]][[0-9]]*\)[[.]].*$/\1/g'`
GC_VERSION_MINOR=`echo $PACKAGE_VERSION | sed 's/^[[^.]]*[[.]]\([[0-9]][[0-9]]*\).*$/\1/g'`
GC_ALPHA_VERSION=`echo $PACKAGE_VERSION | sed 's/^[[^.]]*[[.]][[0-9]]*//'`
case "$GC_ALPHA_VERSION" in
- alpha*)
+ alpha*)
GC_ALPHA_VERSION=`echo $GC_ALPHA_VERSION \
| sed 's/alpha\([[0-9]][[0-9]]*\)/\1/'` ;;
*) GC_ALPHA_MAJOR='' ;;
@@ -36,11 +33,14 @@ AC_DEFUN(GC_SET_VERSION, [
AC_MSG_RESULT(invalid)
AC_MSG_ERROR([nonconforming PACKAGE_VERSION='$PACKAGE_VERSION'])
fi
-
- AC_DEFINE_UNQUOTED(GC_VERSION_MAJOR, $GC_VERSION_MAJOR)
- AC_DEFINE_UNQUOTED(GC_VERSION_MINOR, $GC_VERSION_MINOR)
+
+ AC_DEFINE_UNQUOTED([GC_VERSION_MAJOR], $GC_VERSION_MAJOR,
+ [The major version number of this GC release.])
+ AC_DEFINE_UNQUOTED([GC_VERSION_MINOR], $GC_VERSION_MINOR,
+ [The minor version number of this GC release.])
if test :$GC_ALPHA_VERSION: != :: ; then
- AC_DEFINE_UNQUOTED(GC_ALPHA_VERSION, $GC_ALPHA_VERSION)
+ AC_DEFINE_UNQUOTED([GC_ALPHA_VERSION], $GC_ALPHA_VERSION,
+ [The alpha version number, if applicable.])
fi
AC_MSG_RESULT(major=$GC_VERSION_MAJOR minor=$GC_VERSION_MINOR \
${GC_ALPHA_VERSION:+alpha=}$GC_ALPHA_VERSION)
diff --git a/boehm-gc/mach_dep.c b/boehm-gc/mach_dep.c
index 327e11ca690..dec9e7dfe9d 100644
--- a/boehm-gc/mach_dep.c
+++ b/boehm-gc/mach_dep.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
*
@@ -11,185 +11,154 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, November 17, 1995 12:13 pm PST */
-# include "private/gc_priv.h"
-# include <stdio.h>
-# include <setjmp.h>
-# if defined(OS2) || defined(CX_UX)
-# define _setjmp(b) setjmp(b)
-# define _longjmp(b,v) longjmp(b,v)
-# endif
-# ifdef AMIGA
-# ifndef __GNUC__
-# include <dos.h>
-# else
-# include <machine/reg.h>
-# endif
+
+#include "private/gc_priv.h"
+
+#include <stdio.h>
+
+#ifdef AMIGA
+# ifndef __GNUC__
+# include <dos.h>
+# else
+# include <machine/reg.h>
# endif
+#endif
-#if defined(__MWERKS__) && !defined(POWERPC)
+#if defined(MACOS) && defined(__MWERKS__)
-asm static void PushMacRegisters()
-{
- sub.w #4,sp // reserve space for one parameter.
+#if defined(POWERPC)
+
+# define NONVOLATILE_GPR_COUNT 19
+ struct ppc_registers {
+ unsigned long gprs[NONVOLATILE_GPR_COUNT]; /* R13-R31 */
+ };
+ typedef struct ppc_registers ppc_registers;
+
+ asm static void getRegisters(register ppc_registers* regs)
+ {
+ stmw r13,regs->gprs /* save R13-R31 */
+ blr
+ }
+
+ static void PushMacRegisters(void)
+ {
+ ppc_registers regs;
+ int i;
+ getRegisters(&regs);
+ for (i = 0; i < NONVOLATILE_GPR_COUNT; i++)
+ GC_push_one(regs.gprs[i]);
+ }
+
+#else /* M68K */
+
+ asm static void PushMacRegisters(void)
+ {
+ sub.w #4,sp /* reserve space for one parameter */
move.l a2,(sp)
- jsr GC_push_one
+ jsr GC_push_one
move.l a3,(sp)
- jsr GC_push_one
+ jsr GC_push_one
move.l a4,(sp)
- jsr GC_push_one
+ jsr GC_push_one
# if !__option(a6frames)
- // <pcb> perhaps a6 should be pushed if stack frames are not being used.
- move.l a6,(sp)
- jsr GC_push_one
+ /* <pcb> perhaps a6 should be pushed if stack frames are not being used */
+ move.l a6,(sp)
+ jsr GC_push_one
# endif
- // skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
+ /* skip a5 (globals), a6 (frame pointer), and a7 (stack pointer) */
move.l d2,(sp)
- jsr GC_push_one
+ jsr GC_push_one
move.l d3,(sp)
- jsr GC_push_one
+ jsr GC_push_one
move.l d4,(sp)
- jsr GC_push_one
+ jsr GC_push_one
move.l d5,(sp)
- jsr GC_push_one
+ jsr GC_push_one
move.l d6,(sp)
- jsr GC_push_one
+ jsr GC_push_one
move.l d7,(sp)
- jsr GC_push_one
- add.w #4,sp // fix stack.
+ jsr GC_push_one
+ add.w #4,sp /* fix stack */
rts
-}
+ }
-#endif /* __MWERKS__ */
+#endif /* M68K */
+
+#endif /* MACOS && __MWERKS__ */
# if defined(SPARC) || defined(IA64)
/* Value returned from register flushing routine; either sp (SPARC) */
- /* or ar.bsp (IA64) */
- word GC_save_regs_ret_val;
+ /* or ar.bsp (IA64). */
+ GC_INNER ptr_t GC_save_regs_ret_val = NULL;
# endif
/* Routine to mark from registers that are preserved by the C compiler. */
-/* This must be ported to every new architecture. There is a generic */
-/* version at the end, that is likely, but not guaranteed to work */
-/* on your architecture. Run the test_setjmp program to see whether */
-/* there is any chance it will work. */
+/* This must be ported to every new architecture. It is not optional, */
+/* and should not be used on platforms that are either UNIX-like, or */
+/* require thread support. */
-#if !defined(USE_GENERIC_PUSH_REGS) && !defined(USE_ASM_PUSH_REGS)
#undef HAVE_PUSH_REGS
-void GC_push_regs()
-{
-# ifdef RT
- register long TMP_SP; /* must be bound to r11 */
-# endif
-
-# ifdef VAX
- /* VAX - generic code below does not work under 4.2 */
- /* r1 through r5 are caller save, and therefore */
- /* on the stack or dead. */
- asm("pushl r11"); asm("calls $1,_GC_push_one");
- asm("pushl r10"); asm("calls $1,_GC_push_one");
- asm("pushl r9"); asm("calls $1,_GC_push_one");
- asm("pushl r8"); asm("calls $1,_GC_push_one");
- asm("pushl r7"); asm("calls $1,_GC_push_one");
- asm("pushl r6"); asm("calls $1,_GC_push_one");
-# define HAVE_PUSH_REGS
-# endif
-# if defined(M68K) && (defined(SUNOS4) || defined(NEXT))
- /* M68K SUNOS - could be replaced by generic code */
- /* a0, a1 and d1 are caller save */
- /* and therefore are on stack or dead. */
-
- asm("subqw #0x4,sp"); /* allocate word on top of stack */
-
- asm("movl a2,sp@"); asm("jbsr _GC_push_one");
- asm("movl a3,sp@"); asm("jbsr _GC_push_one");
- asm("movl a4,sp@"); asm("jbsr _GC_push_one");
- asm("movl a5,sp@"); asm("jbsr _GC_push_one");
- /* Skip frame pointer and stack pointer */
- asm("movl d1,sp@"); asm("jbsr _GC_push_one");
- asm("movl d2,sp@"); asm("jbsr _GC_push_one");
- asm("movl d3,sp@"); asm("jbsr _GC_push_one");
- asm("movl d4,sp@"); asm("jbsr _GC_push_one");
- asm("movl d5,sp@"); asm("jbsr _GC_push_one");
- asm("movl d6,sp@"); asm("jbsr _GC_push_one");
- asm("movl d7,sp@"); asm("jbsr _GC_push_one");
-
- asm("addqw #0x4,sp"); /* put stack back where it was */
-# define HAVE_PUSH_REGS
-# endif
-
-# if defined(M68K) && defined(HP)
- /* M68K HP - could be replaced by generic code */
- /* a0, a1 and d1 are caller save. */
-
- asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
-
- asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
- /* Skip frame pointer and stack pointer */
- asm("mov.l %d1,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
-
- asm("addq.w &0x4,%sp"); /* put stack back where it was */
-# define HAVE_PUSH_REGS
-# endif /* M68K HP */
-
-# if defined(M68K) && defined(AMIGA)
- /* AMIGA - could be replaced by generic code */
- /* a0, a1, d0 and d1 are caller save */
-
-# ifdef __GNUC__
- asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
-
- asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one");
- /* Skip frame pointer and stack pointer */
- asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
- asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
- asm("addq.w &0x4,%sp"); /* put stack back where it was */
-# define HAVE_PUSH_REGS
-# else /* !__GNUC__ */
- GC_push_one(getreg(REG_A2));
- GC_push_one(getreg(REG_A3));
+#if defined(USE_ASM_PUSH_REGS)
+# define HAVE_PUSH_REGS
+#else /* No asm implementation */
+
+# if defined(M68K) && defined(AMIGA)
+ /* This function is not static because it could also be */
+ /* errorneously defined in .S file, so this error would be caught */
+ /* by the linker. */
+ void GC_push_regs(void)
+ {
+ /* AMIGA - could be replaced by generic code */
+ /* a0, a1, d0 and d1 are caller save */
+
+# ifdef __GNUC__
+ asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
+
+ asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
+ asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
+ asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
+ asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
+ asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one");
+ /* Skip frame pointer and stack pointer */
+ asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
+ asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
+ asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
+ asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
+ asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
+ asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
+
+ asm("addq.w &0x4,%sp"); /* put stack back where it was */
+# else /* !__GNUC__ */
+ GC_push_one(getreg(REG_A2));
+ GC_push_one(getreg(REG_A3));
# ifndef __SASC
- /* Can probably be changed to #if 0 -Kjetil M. (a4=globals)*/
- GC_push_one(getreg(REG_A4));
-# endif
- GC_push_one(getreg(REG_A5));
- GC_push_one(getreg(REG_A6));
- /* Skip stack pointer */
- GC_push_one(getreg(REG_D2));
- GC_push_one(getreg(REG_D3));
- GC_push_one(getreg(REG_D4));
- GC_push_one(getreg(REG_D5));
- GC_push_one(getreg(REG_D6));
- GC_push_one(getreg(REG_D7));
-# define HAVE_PUSH_REGS
-# endif /* !__GNUC__ */
-# endif /* AMIGA */
-
-# if defined(M68K) && defined(MACOS)
-# if defined(THINK_C)
-# define PushMacReg(reg) \
+ /* Can probably be changed to #if 0 -Kjetil M. (a4=globals) */
+ GC_push_one(getreg(REG_A4));
+# endif
+ GC_push_one(getreg(REG_A5));
+ GC_push_one(getreg(REG_A6));
+ /* Skip stack pointer */
+ GC_push_one(getreg(REG_D2));
+ GC_push_one(getreg(REG_D3));
+ GC_push_one(getreg(REG_D4));
+ GC_push_one(getreg(REG_D5));
+ GC_push_one(getreg(REG_D6));
+ GC_push_one(getreg(REG_D7));
+# endif /* !__GNUC__ */
+ }
+# define HAVE_PUSH_REGS
+
+# elif defined(MACOS)
+
+# if defined(M68K) && defined(THINK_C)
+# define PushMacReg(reg) \
move.l reg,(sp) \
jsr GC_push_one
- asm {
- sub.w #4,sp ; reserve space for one parameter.
+ void GC_push_regs(void)
+ {
+ asm {
+ sub.w #4,sp ; reserve space for one parameter.
PushMacReg(a2);
PushMacReg(a3);
PushMacReg(a4);
@@ -200,401 +169,143 @@ void GC_push_regs()
PushMacReg(d5);
PushMacReg(d6);
PushMacReg(d7);
- add.w #4,sp ; fix stack.
- }
-# define HAVE_PUSH_REGS
-# undef PushMacReg
-# endif /* THINK_C */
-# if defined(__MWERKS__)
- PushMacRegisters();
-# define HAVE_PUSH_REGS
-# endif /* __MWERKS__ */
-# endif /* MACOS */
-
-# if defined(I386) &&!defined(OS2) &&!defined(SVR4) \
- && (defined(__MINGW32__) || !defined(MSWIN32)) \
- && !defined(SCO) && !defined(SCO_ELF) \
- && !(defined(LINUX) && defined(__ELF__)) \
- && !(defined(FREEBSD) && defined(__ELF__)) \
- && !(defined(NETBSD) && defined(__ELF__)) \
- && !(defined(OPENBSD) && defined(__ELF__)) \
- && !(defined(BEOS) && defined(__ELF__)) \
- && !defined(DOS4GW) && !defined(HURD)
- /* I386 code, generic code does not appear to work */
- /* It does appear to work under OS2, and asms dont */
- /* This is used for some 38g UNIX variants and for CYGWIN32 */
- asm("pushl %eax"); asm("call _GC_push_one"); asm("addl $4,%esp");
- asm("pushl %ecx"); asm("call _GC_push_one"); asm("addl $4,%esp");
- asm("pushl %edx"); asm("call _GC_push_one"); asm("addl $4,%esp");
- asm("pushl %ebp"); asm("call _GC_push_one"); asm("addl $4,%esp");
- asm("pushl %esi"); asm("call _GC_push_one"); asm("addl $4,%esp");
- asm("pushl %edi"); asm("call _GC_push_one"); asm("addl $4,%esp");
- asm("pushl %ebx"); asm("call _GC_push_one"); asm("addl $4,%esp");
-# define HAVE_PUSH_REGS
-# endif
-
-# if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \
- || ( defined(I386) && defined(FREEBSD) && defined(__ELF__) ) \
- || ( defined(I386) && defined(NETBSD) && defined(__ELF__) ) \
- || ( defined(I386) && defined(OPENBSD) && defined(__ELF__) ) \
- || ( defined(I386) && defined(HURD) && defined(__ELF__) ) \
- || ( defined(I386) && defined(DGUX) )
-
- /* This is modified for Linux with ELF (Note: _ELF_ only) */
- /* This section handles FreeBSD with ELF. */
- /* Eax is caller-save and dead here. Other caller-save */
- /* registers could also be skipped. We assume there are no */
- /* pointers in MMX registers, etc. */
- /* We combine instructions in a single asm to prevent gcc from */
- /* inserting code in the middle. */
- asm("pushl %ecx; call GC_push_one; addl $4,%esp");
- asm("pushl %edx; call GC_push_one; addl $4,%esp");
- asm("pushl %ebp; call GC_push_one; addl $4,%esp");
- asm("pushl %esi; call GC_push_one; addl $4,%esp");
- asm("pushl %edi; call GC_push_one; addl $4,%esp");
- asm("pushl %ebx; call GC_push_one; addl $4,%esp");
-# define HAVE_PUSH_REGS
-# endif
-
-# if ( defined(I386) && defined(BEOS) && defined(__ELF__) )
- /* As far as I can understand from */
- /* http://www.beunited.org/articles/jbq/nasm.shtml, */
- /* only ebp, esi, edi and ebx are not scratch. How MMX */
- /* etc. registers should be treated, I have no idea. */
- asm("pushl %ebp; call GC_push_one; addl $4,%esp");
- asm("pushl %esi; call GC_push_one; addl $4,%esp");
- asm("pushl %edi; call GC_push_one; addl $4,%esp");
- asm("pushl %ebx; call GC_push_one; addl $4,%esp");
-# define HAVE_PUSH_REGS
-# endif
-
-# if defined(I386) && defined(MSWIN32) && !defined(__MINGW32__) \
- && !defined(USE_GENERIC)
- /* I386 code, Microsoft variant */
- __asm push eax
- __asm call GC_push_one
- __asm add esp,4
- __asm push ebx
- __asm call GC_push_one
- __asm add esp,4
- __asm push ecx
- __asm call GC_push_one
- __asm add esp,4
- __asm push edx
- __asm call GC_push_one
- __asm add esp,4
- __asm push ebp
- __asm call GC_push_one
- __asm add esp,4
- __asm push esi
- __asm call GC_push_one
- __asm add esp,4
- __asm push edi
- __asm call GC_push_one
- __asm add esp,4
-# define HAVE_PUSH_REGS
-# endif
-
-# if defined(I386) && (defined(SVR4) || defined(SCO) || defined(SCO_ELF))
- /* I386 code, SVR4 variant, generic code does not appear to work */
- asm("pushl %eax"); asm("call GC_push_one"); asm("addl $4,%esp");
- asm("pushl %ebx"); asm("call GC_push_one"); asm("addl $4,%esp");
- asm("pushl %ecx"); asm("call GC_push_one"); asm("addl $4,%esp");
- asm("pushl %edx"); asm("call GC_push_one"); asm("addl $4,%esp");
- asm("pushl %ebp"); asm("call GC_push_one"); asm("addl $4,%esp");
- asm("pushl %esi"); asm("call GC_push_one"); asm("addl $4,%esp");
- asm("pushl %edi"); asm("call GC_push_one"); asm("addl $4,%esp");
-# define HAVE_PUSH_REGS
-# endif
+ add.w #4,sp ; fix stack.
+ }
+ }
+# define HAVE_PUSH_REGS
+# undef PushMacReg
+# elif defined(__MWERKS__)
+ void GC_push_regs(void)
+ {
+ PushMacRegisters();
+ }
+# define HAVE_PUSH_REGS
+# endif /* __MWERKS__ */
+# endif /* MACOS */
+
+#endif /* !USE_ASM_PUSH_REGS */
+
+#if defined(HAVE_PUSH_REGS) && defined(THREADS)
+# error GC_push_regs cannot be used with threads
+ /* Would fail for GC_do_blocking. There are probably other safety */
+ /* issues. */
+# undef HAVE_PUSH_REGS
+#endif
-# ifdef NS32K
- asm ("movd r3, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
- asm ("movd r4, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
- asm ("movd r5, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
- asm ("movd r6, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
- asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
-# define HAVE_PUSH_REGS
-# endif
+#if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
+# include <signal.h>
+# ifndef NO_GETCONTEXT
+# if defined(DARWIN) \
+ && (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 /*MAC_OS_X_VERSION_10_6*/)
+# include <sys/ucontext.h>
+# else
+# include <ucontext.h>
+# endif /* !DARWIN */
+# ifdef GETCONTEXT_FPU_EXCMASK_BUG
+# include <fenv.h>
+# endif
+# endif
+#endif /* !HAVE_PUSH_REGS */
-# if defined(SPARC)
- GC_save_regs_ret_val = GC_save_regs_in_stack();
-# define HAVE_PUSH_REGS
+/* Ensure that either registers are pushed, or callee-save registers */
+/* are somewhere on the stack, and then call fn(arg, ctxt). */
+/* ctxt is either a pointer to a ucontext_t we generated, or NULL. */
+GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
+ ptr_t arg)
+{
+ volatile int dummy;
+ void * context = 0;
+
+# if defined(HAVE_PUSH_REGS)
+ GC_push_regs();
+# elif defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
+ /* Older versions of Darwin seem to lack getcontext(). */
+ /* ARM and MIPS Linux often doesn't support a real */
+ /* getcontext(). */
+ ucontext_t ctxt;
+# ifdef GETCONTEXT_FPU_EXCMASK_BUG
+ /* Workaround a bug (clearing the FPU exception mask) in */
+ /* getcontext on Linux/x86_64. */
+# ifdef X86_64
+ /* We manipulate FPU control word here just not to force the */
+ /* client application to use -lm linker option. */
+ unsigned short old_fcw;
+ __asm__ __volatile__ ("fstcw %0" : "=m" (*&old_fcw));
+# else
+ int except_mask = fegetexcept();
# endif
-
-# ifdef RT
- GC_push_one(TMP_SP); /* GC_push_one from r11 */
-
- asm("cas r11, r6, r0"); GC_push_one(TMP_SP); /* r6 */
- asm("cas r11, r7, r0"); GC_push_one(TMP_SP); /* through */
- asm("cas r11, r8, r0"); GC_push_one(TMP_SP); /* r10 */
- asm("cas r11, r9, r0"); GC_push_one(TMP_SP);
- asm("cas r11, r10, r0"); GC_push_one(TMP_SP);
-
- asm("cas r11, r12, r0"); GC_push_one(TMP_SP); /* r12 */
- asm("cas r11, r13, r0"); GC_push_one(TMP_SP); /* through */
- asm("cas r11, r14, r0"); GC_push_one(TMP_SP); /* r15 */
- asm("cas r11, r15, r0"); GC_push_one(TMP_SP);
-# define HAVE_PUSH_REGS
+# endif
+ if (getcontext(&ctxt) < 0)
+ ABORT ("getcontext failed: Use another register retrieval method?");
+# ifdef GETCONTEXT_FPU_EXCMASK_BUG
+# ifdef X86_64
+ __asm__ __volatile__ ("fldcw %0" : : "m" (*&old_fcw));
+ {
+ unsigned mxcsr;
+ /* And now correct the exception mask in SSE MXCSR. */
+ __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr));
+ mxcsr = (mxcsr & ~(FE_ALL_EXCEPT << 7)) |
+ ((old_fcw & FE_ALL_EXCEPT) << 7);
+ __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr));
+ }
+# else /* !X86_64 */
+ if (feenableexcept(except_mask) < 0)
+ ABORT("feenableexcept failed");
# endif
-
-# if defined(M68K) && defined(SYSV)
- /* Once again similar to SUN and HP, though setjmp appears to work.
- --Parag
- */
-# ifdef __GNUC__
- asm("subqw #0x4,%sp"); /* allocate word on top of stack */
-
- asm("movl %a2,%sp@"); asm("jbsr GC_push_one");
- asm("movl %a3,%sp@"); asm("jbsr GC_push_one");
- asm("movl %a4,%sp@"); asm("jbsr GC_push_one");
- asm("movl %a5,%sp@"); asm("jbsr GC_push_one");
- /* Skip frame pointer and stack pointer */
- asm("movl %d1,%sp@"); asm("jbsr GC_push_one");
- asm("movl %d2,%sp@"); asm("jbsr GC_push_one");
- asm("movl %d3,%sp@"); asm("jbsr GC_push_one");
- asm("movl %d4,%sp@"); asm("jbsr GC_push_one");
- asm("movl %d5,%sp@"); asm("jbsr GC_push_one");
- asm("movl %d6,%sp@"); asm("jbsr GC_push_one");
- asm("movl %d7,%sp@"); asm("jbsr GC_push_one");
-
- asm("addqw #0x4,%sp"); /* put stack back where it was */
-# define HAVE_PUSH_REGS
-# else /* !__GNUC__*/
- asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
-
- asm("mov.l %a2,(%sp)"); asm("jsr GC_push_one");
- asm("mov.l %a3,(%sp)"); asm("jsr GC_push_one");
- asm("mov.l %a4,(%sp)"); asm("jsr GC_push_one");
- asm("mov.l %a5,(%sp)"); asm("jsr GC_push_one");
- /* Skip frame pointer and stack pointer */
- asm("mov.l %d1,(%sp)"); asm("jsr GC_push_one");
- asm("mov.l %d2,(%sp)"); asm("jsr GC_push_one");
- asm("mov.l %d3,(%sp)"); asm("jsr GC_push_one");
- asm("mov.l %d4,(%sp)"); asm("jsr GC_push_one");
- asm("mov.l %d5,(%sp)"); asm("jsr GC_push_one");
- asm("mov.l %d6,(%sp)"); asm("jsr GC_push_one");
- asm("mov.l %d7,(%sp)"); asm("jsr GC_push_one");
-
- asm("addq.w &0x4,%sp"); /* put stack back where it was */
-# define HAVE_PUSH_REGS
-# endif /* !__GNUC__ */
-# endif /* M68K/SYSV */
-
-# if defined(PJ)
- {
- register int * sp asm ("optop");
- extern int *__libc_stack_end;
-
- GC_push_all_stack (sp, __libc_stack_end);
-# define HAVE_PUSH_REGS
- /* Isn't this redundant with the code to push the stack? */
- }
# endif
-
- /* other machines... */
-# if !defined(HAVE_PUSH_REGS)
- --> We just generated an empty GC_push_regs, which
- --> is almost certainly broken. Try defining
- --> USE_GENERIC_PUSH_REGS instead.
+ context = &ctxt;
+# if defined(SPARC) || defined(IA64)
+ /* On a register window machine, we need to save register */
+ /* contents on the stack for this to work. This may already be */
+ /* subsumed by the getcontext() call. */
+ GC_save_regs_ret_val = GC_save_regs_in_stack();
+# endif /* register windows. */
+# elif defined(HAVE_BUILTIN_UNWIND_INIT)
+ /* This was suggested by Richard Henderson as the way to */
+ /* force callee-save registers and register windows onto */
+ /* the stack. */
+ __builtin_unwind_init();
+# else /* !HAVE_BUILTIN_UNWIND_INIT && !UNIX_LIKE */
+ /* && !HAVE_PUSH_REGS */
+ /* Generic code */
+ /* The idea is due to Parag Patel at HP. */
+ /* We're not sure whether he would like */
+ /* to be acknowledged for it or not. */
+ jmp_buf regs;
+ register word * i = (word *) regs;
+ register ptr_t lim = (ptr_t)(regs) + (sizeof regs);
+
+ /* Setjmp doesn't always clear all of the buffer. */
+ /* That tends to preserve garbage. Clear it. */
+ for (; (word)i < (word)lim; i++) {
+ *i = 0;
+ }
+# if defined(MSWIN32) || defined(MSWINCE) || defined(UTS4) \
+ || defined(OS2) || defined(CX_UX) || defined(__CC_ARM) \
+ || defined(LINUX) || defined(EWS4800) || defined(RTEMS)
+ (void) setjmp(regs);
+# else
+ (void) _setjmp(regs);
+ /* We don't want to mess with signals. According to */
+ /* SUSV3, setjmp() may or may not save signal mask. */
+ /* _setjmp won't, but is less portable. */
# endif
+# endif /* !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 */
+ /* contents before we get a chance to look at them. */
+ GC_noop1((word)(&dummy));
}
-#endif /* !USE_GENERIC_PUSH_REGS && !USE_ASM_PUSH_REGS */
-
-#if defined(USE_GENERIC_PUSH_REGS)
-void GC_generic_push_regs(cold_gc_frame)
-ptr_t cold_gc_frame;
-{
- {
- word dummy;
-
-# ifdef HAVE_BUILTIN_UNWIND_INIT
- /* This was suggested by Richard Henderson as the way to */
- /* force callee-save registers and register windows onto */
- /* the stack. */
- __builtin_unwind_init();
-# else /* !HAVE_BUILTIN_UNWIND_INIT */
- /* Generic code */
- /* The idea is due to Parag Patel at HP. */
- /* We're not sure whether he would like */
- /* to be he acknowledged for it or not. */
- jmp_buf regs;
- register word * i = (word *) regs;
- register ptr_t lim = (ptr_t)(regs) + (sizeof regs);
-
- /* Setjmp doesn't always clear all of the buffer. */
- /* That tends to preserve garbage. Clear it. */
- for (; (char *)i < lim; i++) {
- *i = 0;
- }
-# if defined(POWERPC) || defined(MSWIN32) || defined(MSWINCE) \
- || defined(UTS4) || defined(LINUX) || defined(EWS4800)
- (void) setjmp(regs);
-# else
- (void) _setjmp(regs);
- /* We don't want to mess with signals. According to */
- /* SUSV3, setjmp() may or may not save signal mask. */
- /* _setjmp won't, but is less portable. */
-# endif
-# endif /* !HAVE_BUILTIN_UNWIND_INIT */
-# if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \
- || defined(IA64)
- /* On a register window machine, we need to save register */
- /* contents on the stack for this to work. The setjmp */
- /* is probably not needed on SPARC, since pointers are */
- /* only stored in windowed or scratch registers. It is */
- /* needed on IA64, since some non-windowed registers are */
- /* preserved. */
- {
- GC_save_regs_ret_val = GC_save_regs_in_stack();
- /* On IA64 gcc, could use __builtin_ia64_flushrs() and */
- /* __builtin_ia64_flushrs(). The latter will be done */
- /* implicitly by __builtin_unwind_init() for gcc3.0.1 */
- /* and later. */
- }
-# endif
- GC_push_current_stack(cold_gc_frame);
- /* Strongly discourage the compiler from treating the above */
- /* as a tail-call, since that would pop the register */
- /* contents before we get a chance to look at them. */
- GC_noop1((word)(&dummy));
- }
-}
-#endif /* USE_GENERIC_PUSH_REGS */
-/* On register window machines, we need a way to force registers into */
-/* the stack. Return sp. */
-# ifdef SPARC
- asm(" .seg \"text\"");
-# if defined(SVR4) || defined(NETBSD)
- asm(" .globl GC_save_regs_in_stack");
- asm("GC_save_regs_in_stack:");
- asm(" .type GC_save_regs_in_stack,#function");
-# else
- asm(" .globl _GC_save_regs_in_stack");
- asm("_GC_save_regs_in_stack:");
-# endif
-# if defined(__arch64__) || defined(__sparcv9)
- asm(" save %sp,-128,%sp");
- asm(" flushw");
- asm(" ret");
- asm(" restore %sp,2047+128,%o0");
-# else
- asm(" ta 0x3 ! ST_FLUSH_WINDOWS");
- asm(" retl");
- asm(" mov %sp,%o0");
-# endif
-# ifdef SVR4
- asm(" .GC_save_regs_in_stack_end:");
- asm(" .size GC_save_regs_in_stack,.GC_save_regs_in_stack_end-GC_save_regs_in_stack");
-# endif
-# ifdef LINT
- word GC_save_regs_in_stack() { return(0 /* sp really */);}
-# endif
-# endif
-
-/* On IA64, we also need to flush register windows. But they end */
-/* up on the other side of the stack segment. */
-/* Returns the backing store pointer for the register stack. */
-/* We now implement this as a separate assembly file, since inline */
-/* assembly code here doesn't work with either the Intel or HP */
-/* compilers. */
-# if 0
-# ifdef LINUX
- asm(" .text");
- asm(" .psr abi64");
- asm(" .psr lsb");
- asm(" .lsb");
- asm("");
- asm(" .text");
- asm(" .align 16");
- asm(" .global GC_save_regs_in_stack");
- asm(" .proc GC_save_regs_in_stack");
- asm("GC_save_regs_in_stack:");
- asm(" .body");
- asm(" flushrs");
- asm(" ;;");
- asm(" mov r8=ar.bsp");
- asm(" br.ret.sptk.few rp");
- asm(" .endp GC_save_regs_in_stack");
-# endif /* LINUX */
-# if 0 /* Other alternatives that don't work on HP/UX */
- word GC_save_regs_in_stack() {
-# if USE_BUILTINS
- __builtin_ia64_flushrs();
- return __builtin_ia64_bsp();
-# else
-# ifdef HPUX
- _asm(" flushrs");
- _asm(" ;;");
- _asm(" mov r8=ar.bsp");
- _asm(" br.ret.sptk.few rp");
-# else
- asm(" flushrs");
- asm(" ;;");
- asm(" mov r8=ar.bsp");
- asm(" br.ret.sptk.few rp");
-# endif
-# endif
- }
-# endif
-# endif
-
-/* GC_clear_stack_inner(arg, limit) clears stack area up to limit and */
-/* returns arg. Stack clearing is crucial on SPARC, so we supply */
-/* an assembly version that's more careful. Assumes limit is hotter */
-/* than sp, and limit is 8 byte aligned. */
#if defined(ASM_CLEAR_CODE)
-#ifndef SPARC
- --> fix it
-#endif
-# ifdef SUNOS4
- asm(".globl _GC_clear_stack_inner");
- asm("_GC_clear_stack_inner:");
-# else
- asm(".globl GC_clear_stack_inner");
- asm("GC_clear_stack_inner:");
- asm(".type GC_save_regs_in_stack,#function");
-# endif
-#if defined(__arch64__) || defined(__sparcv9)
- asm("mov %sp,%o2"); /* Save sp */
- asm("add %sp,2047-8,%o3"); /* p = sp+bias-8 */
- asm("add %o1,-2047-192,%sp"); /* Move sp out of the way, */
- /* so that traps still work. */
- /* Includes some extra words */
- /* so we can be sloppy below. */
- asm("loop:");
- asm("stx %g0,[%o3]"); /* *(long *)p = 0 */
- asm("cmp %o3,%o1");
- asm("bgu,pt %xcc, loop"); /* if (p > limit) goto loop */
- asm("add %o3,-8,%o3"); /* p -= 8 (delay slot) */
- asm("retl");
- asm("mov %o2,%sp"); /* Restore sp., delay slot */
-#else
- asm("mov %sp,%o2"); /* Save sp */
- asm("add %sp,-8,%o3"); /* p = sp-8 */
- asm("clr %g1"); /* [g0,g1] = 0 */
- asm("add %o1,-0x60,%sp"); /* Move sp out of the way, */
- /* so that traps still work. */
- /* Includes some extra words */
- /* so we can be sloppy below. */
- asm("loop:");
- asm("std %g0,[%o3]"); /* *(long long *)p = 0 */
- asm("cmp %o3,%o1");
- asm("bgu loop "); /* if (p > limit) goto loop */
- asm("add %o3,-8,%o3"); /* p -= 8 (delay slot) */
- asm("retl");
- asm("mov %o2,%sp"); /* Restore sp., delay slot */
-#endif /* old SPARC */
- /* First argument = %o0 = return value */
-# ifdef SVR4
- asm(" .GC_clear_stack_inner_end:");
- asm(" .size GC_clear_stack_inner,.GC_clear_stack_inner_end-GC_clear_stack_inner");
-# endif
-
# ifdef LINT
- /*ARGSUSED*/
- ptr_t GC_clear_stack_inner(arg, limit)
- ptr_t arg; word limit;
- { return(arg); }
+ ptr_t GC_clear_stack_inner(ptr_t arg, word limit)
+ {
+ return limit ? arg : 0; /* use both arguments */
+ }
+ /* The real version is in a .S file */
# endif
-#endif
+#endif /* ASM_CLEAR_CODE */
diff --git a/boehm-gc/malloc.c b/boehm-gc/malloc.c
index cb3f3766386..c10f60aeedc 100644
--- a/boehm-gc/malloc.c
+++ b/boehm-gc/malloc.c
@@ -1,7 +1,7 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
- * Copyright (c) 2000 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -12,330 +12,358 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, February 7, 1996 4:32 pm PST */
-
-#include <stdio.h>
+
#include "private/gc_priv.h"
-extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
-void GC_extend_size_map(); /* in misc.c. */
+#include <stdio.h>
+#include <string.h>
-/* Allocate reclaim list for kind: */
-/* Return TRUE on success */
-GC_bool GC_alloc_reclaim_list(kind)
-register struct obj_kind * kind;
+/* Allocate reclaim list for kind: */
+/* Return TRUE on success */
+STATIC GC_bool GC_alloc_reclaim_list(struct obj_kind *kind)
{
struct hblk ** result = (struct hblk **)
- GC_scratch_alloc((MAXOBJSZ+1) * sizeof(struct hblk *));
+ GC_scratch_alloc((MAXOBJGRANULES+1) * sizeof(struct hblk *));
if (result == 0) return(FALSE);
- BZERO(result, (MAXOBJSZ+1)*sizeof(struct hblk *));
+ BZERO(result, (MAXOBJGRANULES+1)*sizeof(struct hblk *));
kind -> ok_reclaim_list = result;
return(TRUE);
}
-/* Allocate a large block of size lw words. */
-/* The block is not cleared. */
-/* Flags is 0 or IGNORE_OFF_PAGE. */
-/* We hold the allocation lock. */
-ptr_t GC_alloc_large(lw, k, flags)
-word lw;
-int k;
-unsigned flags;
+GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
+ GC_bool ignore_off_page,
+ GC_bool retry); /* from alloc.c */
+
+/* Allocate a large block of size lb bytes. */
+/* The block is not cleared. */
+/* Flags is 0 or IGNORE_OFF_PAGE. */
+/* We hold the allocation lock. */
+/* EXTRA_BYTES were already added to lb. */
+GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags)
{
struct hblk * h;
- word n_blocks = OBJ_SZ_TO_BLOCKS(lw);
+ word n_blocks;
ptr_t result;
-
- if (!GC_is_initialized) GC_init_inner();
+ GC_bool retry = FALSE;
+
+ /* Round up to a multiple of a granule. */
+ lb = (lb + GRANULE_BYTES - 1) & ~(GRANULE_BYTES - 1);
+ n_blocks = OBJ_SZ_TO_BLOCKS(lb);
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
/* Do our share of marking work */
- if(GC_incremental && !GC_dont_gc)
- GC_collect_a_little_inner((int)n_blocks);
- h = GC_allochblk(lw, k, flags);
+ if (GC_incremental && !GC_dont_gc)
+ GC_collect_a_little_inner((int)n_blocks);
+ h = GC_allochblk(lb, k, flags);
# ifdef USE_MUNMAP
- if (0 == h) {
- GC_merge_unmapped();
- h = GC_allochblk(lw, k, flags);
- }
+ if (0 == h) {
+ GC_merge_unmapped();
+ h = GC_allochblk(lb, k, flags);
+ }
# endif
- while (0 == h && GC_collect_or_expand(n_blocks, (flags != 0))) {
- h = GC_allochblk(lw, k, flags);
+ while (0 == h && GC_collect_or_expand(n_blocks, flags != 0, retry)) {
+ h = GC_allochblk(lb, k, flags);
+ retry = TRUE;
}
if (h == 0) {
- result = 0;
+ result = 0;
} else {
- int total_bytes = n_blocks * HBLKSIZE;
- if (n_blocks > 1) {
- GC_large_allocd_bytes += total_bytes;
- if (GC_large_allocd_bytes > GC_max_large_allocd_bytes)
- GC_max_large_allocd_bytes = GC_large_allocd_bytes;
- }
- result = (ptr_t) (h -> hb_body);
- GC_words_wasted += BYTES_TO_WORDS(total_bytes) - lw;
+ size_t total_bytes = n_blocks * HBLKSIZE;
+ if (n_blocks > 1) {
+ GC_large_allocd_bytes += total_bytes;
+ if (GC_large_allocd_bytes > GC_max_large_allocd_bytes)
+ GC_max_large_allocd_bytes = GC_large_allocd_bytes;
+ }
+ /* FIXME: Do we need some way to reset GC_max_large_allocd_bytes? */
+ result = h -> hb_body;
}
return result;
}
-
-/* Allocate a large block of size lb bytes. Clear if appropriate. */
-/* We hold the allocation lock. */
-ptr_t GC_alloc_large_and_clear(lw, k, flags)
-word lw;
-int k;
-unsigned flags;
+/* Allocate a large block of size lb bytes. Clear if appropriate. */
+/* We hold the allocation lock. */
+/* EXTRA_BYTES were already added to lb. */
+STATIC ptr_t GC_alloc_large_and_clear(size_t lb, int k, unsigned flags)
{
- ptr_t result = GC_alloc_large(lw, k, flags);
- word n_blocks = OBJ_SZ_TO_BLOCKS(lw);
+ ptr_t result = GC_alloc_large(lb, k, flags);
+ word n_blocks = OBJ_SZ_TO_BLOCKS(lb);
if (0 == result) return 0;
if (GC_debugging_started || GC_obj_kinds[k].ok_init) {
- /* Clear the whole block, in case of GC_realloc call. */
- BZERO(result, n_blocks * HBLKSIZE);
+ /* Clear the whole block, in case of GC_realloc call. */
+ BZERO(result, n_blocks * HBLKSIZE);
}
return result;
}
-/* allocate lb bytes for an object of kind k. */
-/* Should not be used to directly to allocate */
-/* objects such as STUBBORN objects that */
-/* require special handling on allocation. */
-/* First a version that assumes we already */
-/* hold lock: */
-ptr_t GC_generic_malloc_inner(lb, k)
-register word lb;
-register int k;
+/* allocate lb bytes for an object of kind k. */
+/* Should not be used to directly to allocate */
+/* objects such as STUBBORN objects that */
+/* require special handling on allocation. */
+/* First a version that assumes we already */
+/* hold lock: */
+GC_INNER void * GC_generic_malloc_inner(size_t lb, int k)
{
-register word lw;
-register ptr_t op;
-register ptr_t *opp;
+ void *op;
- if( SMALL_OBJ(lb) ) {
- register struct obj_kind * kind = GC_obj_kinds + k;
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
- if (lw == 0) lw = MIN_WORDS;
-# endif
- opp = &(kind -> ok_freelist[lw]);
- if( (op = *opp) == 0 ) {
-# ifdef MERGE_SIZES
- if (GC_size_map[lb] == 0) {
- if (!GC_is_initialized) GC_init_inner();
- if (GC_size_map[lb] == 0) GC_extend_size_map(lb);
- return(GC_generic_malloc_inner(lb, k));
- }
-# else
- if (!GC_is_initialized) {
- GC_init_inner();
- return(GC_generic_malloc_inner(lb, k));
- }
-# endif
- if (kind -> ok_reclaim_list == 0) {
- if (!GC_alloc_reclaim_list(kind)) goto out;
- }
- op = GC_allocobj(lw, k);
- if (op == 0) goto out;
+ if(SMALL_OBJ(lb)) {
+ struct obj_kind * kind = GC_obj_kinds + k;
+ size_t lg = GC_size_map[lb];
+ void ** opp = &(kind -> ok_freelist[lg]);
+
+ op = *opp;
+ if (EXPECT(0 == op, FALSE)) {
+ if (lg == 0) {
+ if (!EXPECT(GC_is_initialized, TRUE)) {
+ GC_init();
+ lg = GC_size_map[lb];
+ }
+ if (0 == lg) {
+ GC_extend_size_map(lb);
+ lg = GC_size_map[lb];
+ GC_ASSERT(lg != 0);
+ }
+ /* Retry */
+ opp = &(kind -> ok_freelist[lg]);
+ op = *opp;
+ }
+ if (0 == op) {
+ if (0 == kind -> ok_reclaim_list &&
+ !GC_alloc_reclaim_list(kind))
+ return NULL;
+ op = GC_allocobj(lg, k);
+ if (0 == op)
+ return NULL;
+ }
}
- /* Here everything is in a consistent state. */
- /* We assume the following assignment is */
- /* atomic. If we get aborted */
- /* after the assignment, we lose an object, */
- /* but that's benign. */
- /* Volatile declarations may need to be added */
- /* to prevent the compiler from breaking things.*/
- /* If we only execute the second of the */
- /* following assignments, we lose the free */
- /* list, but that should still be OK, at least */
- /* for garbage collected memory. */
*opp = obj_link(op);
obj_link(op) = 0;
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
} else {
- lw = ROUNDED_UP_WORDS(lb);
- op = (ptr_t)GC_alloc_large_and_clear(lw, k, 0);
+ op = (ptr_t)GC_alloc_large_and_clear(ADD_SLOP(lb), k, 0);
+ GC_bytes_allocd += lb;
}
- GC_words_allocd += lw;
-
-out:
+
return op;
}
/* Allocate a composite object of size n bytes. The caller guarantees */
/* that pointers past the first page are not relevant. Caller holds */
/* allocation lock. */
-ptr_t GC_generic_malloc_inner_ignore_off_page(lb, k)
-register size_t lb;
-register int k;
+GC_INNER void * GC_generic_malloc_inner_ignore_off_page(size_t lb, int k)
{
- register word lw;
- ptr_t op;
+ word lb_adjusted;
+ void * op;
if (lb <= HBLKSIZE)
- return(GC_generic_malloc_inner((word)lb, k));
- lw = ROUNDED_UP_WORDS(lb);
- op = (ptr_t)GC_alloc_large_and_clear(lw, k, IGNORE_OFF_PAGE);
- GC_words_allocd += lw;
+ return(GC_generic_malloc_inner(lb, k));
+ lb_adjusted = ADD_SLOP(lb);
+ op = GC_alloc_large_and_clear(lb_adjusted, k, IGNORE_OFF_PAGE);
+ GC_bytes_allocd += lb_adjusted;
return op;
}
-ptr_t GC_generic_malloc(lb, k)
-register word lb;
-register int k;
+#ifdef GC_COLLECT_AT_MALLOC
+ /* Parameter to force GC at every malloc of size greater or equal to */
+ /* the given value. This might be handy during debugging. */
+ size_t GC_dbg_collect_at_malloc_min_lb = (GC_COLLECT_AT_MALLOC);
+#endif
+
+GC_API void * GC_CALL GC_generic_malloc(size_t lb, int k)
{
- ptr_t result;
+ void * result;
DCL_LOCK_STATE;
- if (GC_have_errors) GC_print_all_errors();
+ if (EXPECT(GC_have_errors, FALSE))
+ GC_print_all_errors();
GC_INVOKE_FINALIZERS();
+ GC_DBG_COLLECT_AT_MALLOC(lb);
if (SMALL_OBJ(lb)) {
- DISABLE_SIGNALS();
- LOCK();
+ LOCK();
result = GC_generic_malloc_inner((word)lb, k);
- UNLOCK();
- ENABLE_SIGNALS();
+ UNLOCK();
} else {
- word lw;
- word n_blocks;
- GC_bool init;
- lw = ROUNDED_UP_WORDS(lb);
- n_blocks = OBJ_SZ_TO_BLOCKS(lw);
- init = GC_obj_kinds[k].ok_init;
- DISABLE_SIGNALS();
- LOCK();
- result = (ptr_t)GC_alloc_large(lw, k, 0);
- if (0 != result) {
- if (GC_debugging_started) {
- BZERO(result, n_blocks * HBLKSIZE);
- } else {
+ size_t lg;
+ size_t lb_rounded;
+ word n_blocks;
+ GC_bool init;
+
+ lg = ROUNDED_UP_GRANULES(lb);
+ lb_rounded = GRANULES_TO_BYTES(lg);
+ if (lb_rounded < lb)
+ return((*GC_get_oom_fn())(lb));
+ n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded);
+ init = GC_obj_kinds[k].ok_init;
+ LOCK();
+ result = (ptr_t)GC_alloc_large(lb_rounded, k, 0);
+ if (0 != result) {
+ if (GC_debugging_started) {
+ BZERO(result, n_blocks * HBLKSIZE);
+ } else {
# ifdef THREADS
- /* Clear any memory that might be used for GC descriptors */
- /* before we release the lock. */
- ((word *)result)[0] = 0;
- ((word *)result)[1] = 0;
- ((word *)result)[lw-1] = 0;
- ((word *)result)[lw-2] = 0;
-# endif
- }
- }
- GC_words_allocd += lw;
- UNLOCK();
- ENABLE_SIGNALS();
- if (init && !GC_debugging_started && 0 != result) {
- BZERO(result, n_blocks * HBLKSIZE);
+ /* Clear any memory that might be used for GC descriptors */
+ /* before we release the lock. */
+ ((word *)result)[0] = 0;
+ ((word *)result)[1] = 0;
+ ((word *)result)[GRANULES_TO_WORDS(lg)-1] = 0;
+ ((word *)result)[GRANULES_TO_WORDS(lg)-2] = 0;
+# endif
+ }
+ }
+ GC_bytes_allocd += lb_rounded;
+ UNLOCK();
+ if (init && !GC_debugging_started && 0 != result) {
+ BZERO(result, n_blocks * HBLKSIZE);
}
}
if (0 == result) {
- return((*GC_oom_fn)(lb));
+ return((*GC_get_oom_fn())(lb));
} else {
return(result);
}
-}
-
-
-#define GENERAL_MALLOC(lb,k) \
- (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
-/* We make the GC_clear_stack_call a tail call, hoping to get more of */
-/* the stack. */
+}
/* Allocate lb bytes of atomic (pointerfree) data */
-# ifdef __STDC__
- GC_PTR GC_malloc_atomic(size_t lb)
-# else
- GC_PTR GC_malloc_atomic(lb)
- size_t lb;
-# endif
+#ifdef THREAD_LOCAL_ALLOC
+ GC_INNER void * GC_core_malloc_atomic(size_t lb)
+#else
+ GC_API void * GC_CALL GC_malloc_atomic(size_t lb)
+#endif
{
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-DCL_LOCK_STATE;
-
- if( EXPECT(SMALL_OBJ(lb), 1) ) {
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_aobjfreelist[lw]);
- FASTLOCK();
- if( EXPECT(!FASTLOCK_SUCCEEDED() || (op = *opp) == 0, 0) ) {
- FASTUNLOCK();
+ void *op;
+ void ** opp;
+ size_t lg;
+ DCL_LOCK_STATE;
+
+ if(SMALL_OBJ(lb)) {
+ GC_DBG_COLLECT_AT_MALLOC(lb);
+ lg = GC_size_map[lb];
+ opp = &(GC_aobjfreelist[lg]);
+ LOCK();
+ if (EXPECT((op = *opp) == 0, FALSE)) {
+ UNLOCK();
return(GENERAL_MALLOC((word)lb, PTRFREE));
}
- /* See above comment on signals. */
*opp = obj_link(op);
- GC_words_allocd += lw;
- FASTUNLOCK();
- return((GC_PTR) op);
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+ UNLOCK();
+ return((void *) op);
} else {
return(GENERAL_MALLOC((word)lb, PTRFREE));
}
}
/* Allocate lb bytes of composite (pointerful) data */
-# ifdef __STDC__
- GC_PTR GC_malloc(size_t lb)
-# else
- GC_PTR GC_malloc(lb)
- size_t lb;
-# endif
+#ifdef THREAD_LOCAL_ALLOC
+ GC_INNER void * GC_core_malloc(size_t lb)
+#else
+ GC_API void * GC_CALL GC_malloc(size_t lb)
+#endif
{
-register ptr_t op;
-register ptr_t *opp;
-register word lw;
-DCL_LOCK_STATE;
-
- if( EXPECT(SMALL_OBJ(lb), 1) ) {
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_objfreelist[lw]);
- FASTLOCK();
- if( EXPECT(!FASTLOCK_SUCCEEDED() || (op = *opp) == 0, 0) ) {
- FASTUNLOCK();
- return(GENERAL_MALLOC((word)lb, NORMAL));
+ void *op;
+ void **opp;
+ size_t lg;
+ DCL_LOCK_STATE;
+
+ if(SMALL_OBJ(lb)) {
+ GC_DBG_COLLECT_AT_MALLOC(lb);
+ lg = GC_size_map[lb];
+ opp = (void **)&(GC_objfreelist[lg]);
+ LOCK();
+ if (EXPECT((op = *opp) == 0, FALSE)) {
+ UNLOCK();
+ return (GENERAL_MALLOC((word)lb, NORMAL));
}
- /* See above comment on signals. */
- GC_ASSERT(0 == obj_link(op)
- || (word)obj_link(op)
- <= (word)GC_greatest_plausible_heap_addr
- && (word)obj_link(op)
- >= (word)GC_least_plausible_heap_addr);
+ GC_ASSERT(0 == obj_link(op)
+ || ((word)obj_link(op)
+ <= (word)GC_greatest_plausible_heap_addr
+ && (word)obj_link(op)
+ >= (word)GC_least_plausible_heap_addr));
*opp = obj_link(op);
obj_link(op) = 0;
- GC_words_allocd += lw;
- FASTUNLOCK();
- return((GC_PTR) op);
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+ UNLOCK();
+ return op;
} else {
- return(GENERAL_MALLOC((word)lb, NORMAL));
+ return(GENERAL_MALLOC(lb, NORMAL));
}
}
-# ifdef REDIRECT_MALLOC
+/* Allocate lb bytes of pointerful, traced, but not collectable data */
+GC_API void * GC_CALL GC_malloc_uncollectable(size_t lb)
+{
+ void *op;
+ void **opp;
+ size_t lg;
+ DCL_LOCK_STATE;
+
+ if( SMALL_OBJ(lb) ) {
+ GC_DBG_COLLECT_AT_MALLOC(lb);
+ if (EXTRA_BYTES != 0 && lb != 0) lb--;
+ /* We don't need the extra byte, since this won't be */
+ /* collected anyway. */
+ lg = GC_size_map[lb];
+ opp = &(GC_uobjfreelist[lg]);
+ LOCK();
+ op = *opp;
+ if (EXPECT(0 != op, TRUE)) {
+ *opp = obj_link(op);
+ obj_link(op) = 0;
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+ /* Mark bit ws already set on free list. It will be */
+ /* cleared only temporarily during a collection, as a */
+ /* result of the normal free list mark bit clearing. */
+ GC_non_gc_bytes += GRANULES_TO_BYTES(lg);
+ UNLOCK();
+ } else {
+ UNLOCK();
+ op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
+ /* For small objects, the free lists are completely marked. */
+ }
+ GC_ASSERT(0 == op || GC_is_marked(op));
+ return((void *) op);
+ } else {
+ hdr * hhdr;
+
+ op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
+ if (0 == op) return(0);
+
+ GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0); /* large block */
+ hhdr = HDR(op);
+ /* We don't need the lock here, since we have an undisguised */
+ /* pointer. We do need to hold the lock while we adjust */
+ /* mark bits. */
+ LOCK();
+ set_mark_bit_from_hdr(hhdr, 0); /* Only object. */
+# ifndef THREADS
+ GC_ASSERT(hhdr -> hb_n_marks == 0);
+ /* This is not guaranteed in the multi-threaded case */
+ /* because the counter could be updated before locking. */
+# endif
+ hhdr -> hb_n_marks = 1;
+ UNLOCK();
+ return((void *) op);
+ }
+}
+
+#ifdef REDIRECT_MALLOC
-/* Avoid unnecessary nested procedure calls here, by #defining some */
-/* malloc replacements. Otherwise we end up saving a */
-/* meaningless return address in the object. It also speeds things up, */
-/* but it is admittedly quite ugly. */
-# ifdef GC_ADD_CALLER
-# define RA GC_RETURN_ADDR,
-# else
-# define RA
+# ifndef MSWINCE
+# include <errno.h>
# endif
+
+/* Avoid unnecessary nested procedure calls here, by #defining some */
+/* malloc replacements. Otherwise we end up saving a */
+/* meaningless return address in the object. It also speeds things up, */
+/* but it is admittedly quite ugly. */
+
# define GC_debug_malloc_replacement(lb) \
- GC_debug_malloc(lb, RA "unknown", 0)
+ GC_debug_malloc(lb, GC_DBG_RA "unknown", 0)
-# ifdef __STDC__
- GC_PTR malloc(size_t lb)
-# else
- GC_PTR malloc(lb)
- size_t lb;
-# endif
- {
- /* It might help to manually inline the GC_malloc call here. */
- /* But any decent compiler should reduce the extra procedure call */
- /* to at most a jump instruction in this case. */
+void * malloc(size_t lb)
+{
+ /* It might help to manually inline the GC_malloc call here. */
+ /* But any decent compiler should reduce the extra procedure call */
+ /* to at most a jump instruction in this case. */
# if defined(I386) && defined(GC_SOLARIS_THREADS)
/*
* Thread initialisation can call malloc before
@@ -344,159 +372,240 @@ DCL_LOCK_STATE;
* The thread implementation may well call malloc at other
* inopportune times.
*/
- if (!GC_is_initialized) return sbrk(lb);
+ if (!EXPECT(GC_is_initialized, TRUE)) return sbrk(lb);
# endif /* I386 && GC_SOLARIS_THREADS */
- return((GC_PTR)REDIRECT_MALLOC(lb));
- }
+ return((void *)REDIRECT_MALLOC(lb));
+}
-# ifdef __STDC__
- GC_PTR calloc(size_t n, size_t lb)
-# else
- GC_PTR calloc(n, lb)
- size_t n, lb;
-# endif
+#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;
+ STATIC ptr_t GC_libld_end = 0;
+
+ STATIC void GC_init_lib_bounds(void)
{
- return((GC_PTR)REDIRECT_MALLOC(n*lb));
+ if (GC_libpthread_start != 0) return;
+ GC_init(); /* if not called yet */
+ 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("ld-", &GC_libld_start, &GC_libld_end)) {
+ WARN("Failed to find ld.so text mapping: Expect crash\n", 0);
+ }
}
+#endif /* GC_LINUX_THREADS */
+
+#include <limits.h>
+#ifdef SIZE_MAX
+# define GC_SIZE_MAX SIZE_MAX
+#else
+# define GC_SIZE_MAX (~(size_t)0)
+#endif
+
+#define GC_SQRT_SIZE_MAX ((1U << (WORDSZ / 2)) - 1)
+
+void * calloc(size_t n, size_t lb)
+{
+ if ((lb | n) > GC_SQRT_SIZE_MAX /* fast initial test */
+ && lb && n > GC_SIZE_MAX / lb)
+ return NULL;
+# if defined(GC_LINUX_THREADS) /* && !defined(USE_PROC_FOR_LIBRARIES) */
+ /* libpthread allocated some memory that is only pointed to by */
+ /* mmapped thread stacks. Make sure it's not collectable. */
+ {
+ static GC_bool lib_bounds_set = FALSE;
+ ptr_t caller = (ptr_t)__builtin_return_address(0);
+ /* This test does not need to ensure memory visibility, since */
+ /* the bounds will be set when/if we create another thread. */
+ if (!EXPECT(lib_bounds_set, TRUE)) {
+ GC_init_lib_bounds();
+ lib_bounds_set = TRUE;
+ }
+ if (((word)caller >= (word)GC_libpthread_start
+ && (word)caller < (word)GC_libpthread_end)
+ || ((word)caller >= (word)GC_libld_start
+ && (word)caller < (word)GC_libld_end))
+ return GC_malloc_uncollectable(n*lb);
+ /* The two ranges are actually usually adjacent, so there may */
+ /* be a way to speed this up. */
+ }
+# endif
+ return((void *)REDIRECT_MALLOC(n*lb));
+}
#ifndef strdup
-# include <string.h>
-# ifdef __STDC__
- char *strdup(const char *s)
-# else
- char *strdup(s)
- char *s;
-# endif
+ char *strdup(const char *s)
{
- size_t len = strlen(s) + 1;
- char * result = ((char *)REDIRECT_MALLOC(len+1));
- BCOPY(s, result, len+1);
+ size_t lb = strlen(s) + 1;
+ char *result = (char *)REDIRECT_MALLOC(lb);
+ if (result == 0) {
+ errno = ENOMEM;
+ return 0;
+ }
+ BCOPY(s, result, lb);
return result;
}
#endif /* !defined(strdup) */
/* If strdup is macro defined, we assume that it actually calls malloc, */
- /* and thus the right thing will happen even without overriding it. */
- /* This seems to be true on most Linux systems. */
+ /* and thus the right thing will happen even without overriding it. */
+ /* This seems to be true on most Linux systems. */
+
+#ifndef strndup
+ /* This is similar to strdup(). */
+ char *strndup(const char *str, size_t size)
+ {
+ char *copy;
+ size_t len = strlen(str);
+ if (len > size)
+ len = size;
+ copy = (char *)REDIRECT_MALLOC(len + 1);
+ if (copy == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ BCOPY(str, copy, len);
+ copy[len] = '\0';
+ return copy;
+ }
+#endif /* !strndup */
#undef GC_debug_malloc_replacement
-# endif /* REDIRECT_MALLOC */
+#endif /* REDIRECT_MALLOC */
-/* Explicitly deallocate an object p. */
-# ifdef __STDC__
- void GC_free(GC_PTR p)
-# else
- void GC_free(p)
- GC_PTR p;
-# endif
+/* Explicitly deallocate an object p. */
+GC_API void GC_CALL GC_free(void * p)
{
- register struct hblk *h;
- register hdr *hhdr;
- register signed_word sz;
- register ptr_t * flh;
- register int knd;
- register struct obj_kind * ok;
+ struct hblk *h;
+ hdr *hhdr;
+ size_t sz; /* In bytes */
+ size_t ngranules; /* sz in granules */
+ void **flh;
+ int knd;
+ struct obj_kind * ok;
DCL_LOCK_STATE;
if (p == 0) return;
- /* Required by ANSI. It's not my fault ... */
+ /* Required by ANSI. It's not my fault ... */
+# ifdef LOG_ALLOCS
+ GC_log_printf("GC_free(%p), GC: %lu\n", p, (unsigned long)GC_gc_no);
+# endif
h = HBLKPTR(p);
hhdr = HDR(h);
- GC_ASSERT(GC_base(p) == p);
# if defined(REDIRECT_MALLOC) && \
- (defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \
- || defined(__MINGW32__)) /* Should this be MSWIN32 in general? */
- /* For Solaris, we have to redirect malloc calls during */
- /* initialization. For the others, this seems to happen */
- /* implicitly. */
- /* Don't try to deallocate that memory. */
- if (0 == hhdr) return;
+ (defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \
+ || defined(MSWIN32))
+ /* For Solaris, we have to redirect malloc calls during */
+ /* initialization. For the others, this seems to happen */
+ /* implicitly. */
+ /* Don't try to deallocate that memory. */
+ if (0 == hhdr) return;
# endif
- knd = hhdr -> hb_obj_kind;
+ GC_ASSERT(GC_base(p) == p);
sz = hhdr -> hb_sz;
+ ngranules = BYTES_TO_GRANULES(sz);
+ knd = hhdr -> hb_obj_kind;
ok = &GC_obj_kinds[knd];
- if (EXPECT((sz <= MAXOBJSZ), 1)) {
-# ifdef THREADS
- DISABLE_SIGNALS();
- LOCK();
-# endif
- GC_mem_freed += sz;
- /* A signal here can make GC_mem_freed and GC_non_gc_bytes */
- /* inconsistent. We claim this is benign. */
- if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
- /* Its unnecessary to clear the mark bit. If the */
- /* object is reallocated, it doesn't matter. O.w. the */
- /* collector will do it, since it's on a free list. */
- if (ok -> ok_init) {
- BZERO((word *)p + 1, WORDS_TO_BYTES(sz-1));
- }
- flh = &(ok -> ok_freelist[sz]);
- obj_link(p) = *flh;
- *flh = (ptr_t)p;
-# ifdef THREADS
- UNLOCK();
- ENABLE_SIGNALS();
-# endif
+ if (EXPECT(ngranules <= MAXOBJGRANULES, TRUE)) {
+ LOCK();
+ GC_bytes_freed += sz;
+ if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
+ /* Its unnecessary to clear the mark bit. If the */
+ /* object is reallocated, it doesn't matter. O.w. the */
+ /* collector will do it, since it's on a free list. */
+ if (ok -> ok_init) {
+ BZERO((word *)p + 1, sz-sizeof(word));
+ }
+ flh = &(ok -> ok_freelist[ngranules]);
+ obj_link(p) = *flh;
+ *flh = (ptr_t)p;
+ UNLOCK();
} else {
- DISABLE_SIGNALS();
+ size_t nblocks = OBJ_SZ_TO_BLOCKS(sz);
LOCK();
- GC_mem_freed += sz;
- if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
+ GC_bytes_freed += sz;
+ if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
+ if (nblocks > 1) {
+ GC_large_allocd_bytes -= nblocks * HBLKSIZE;
+ }
GC_freehblk(h);
UNLOCK();
- ENABLE_SIGNALS();
}
}
-/* Explicitly deallocate an object p when we already hold lock. */
-/* Only used for internally allocated objects, so we can take some */
-/* shortcuts. */
+/* Explicitly deallocate an object p when we already hold lock. */
+/* Only used for internally allocated objects, so we can take some */
+/* shortcuts. */
#ifdef THREADS
-void GC_free_inner(GC_PTR p)
-{
- register struct hblk *h;
- register hdr *hhdr;
- register signed_word sz;
- register ptr_t * flh;
- register int knd;
- register struct obj_kind * ok;
- DCL_LOCK_STATE;
+ GC_INNER void GC_free_inner(void * p)
+ {
+ struct hblk *h;
+ hdr *hhdr;
+ size_t sz; /* bytes */
+ size_t ngranules; /* sz in granules */
+ void ** flh;
+ int knd;
+ struct obj_kind * ok;
h = HBLKPTR(p);
hhdr = HDR(h);
knd = hhdr -> hb_obj_kind;
sz = hhdr -> hb_sz;
+ ngranules = BYTES_TO_GRANULES(sz);
ok = &GC_obj_kinds[knd];
- if (sz <= MAXOBJSZ) {
- GC_mem_freed += sz;
- if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
- if (ok -> ok_init) {
- BZERO((word *)p + 1, WORDS_TO_BYTES(sz-1));
- }
- flh = &(ok -> ok_freelist[sz]);
- obj_link(p) = *flh;
- *flh = (ptr_t)p;
+ if (ngranules <= MAXOBJGRANULES) {
+ GC_bytes_freed += sz;
+ if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
+ if (ok -> ok_init) {
+ BZERO((word *)p + 1, sz-sizeof(word));
+ }
+ flh = &(ok -> ok_freelist[ngranules]);
+ obj_link(p) = *flh;
+ *flh = (ptr_t)p;
} else {
- GC_mem_freed += sz;
- if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= WORDS_TO_BYTES(sz);
+ 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);
}
-}
+ }
#endif /* THREADS */
-# if defined(REDIRECT_MALLOC) && !defined(REDIRECT_FREE)
-# define REDIRECT_FREE GC_free
-# endif
-# ifdef REDIRECT_FREE
-# ifdef __STDC__
- void free(GC_PTR p)
-# else
- void free(p)
- GC_PTR p;
-# endif
+#if defined(REDIRECT_MALLOC) && !defined(REDIRECT_FREE)
+# define REDIRECT_FREE GC_free
+#endif
+
+#ifdef REDIRECT_FREE
+ void free(void * p)
{
+# if defined(GC_LINUX_THREADS) && !defined(USE_PROC_FOR_LIBRARIES)
+ {
+ /* Don't bother with initialization checks. If nothing */
+ /* has been initialized, the check fails, and that's safe, */
+ /* since we haven't allocated uncollectable objects either. */
+ ptr_t caller = (ptr_t)__builtin_return_address(0);
+ /* This test does not need to ensure memory visibility, since */
+ /* the bounds will be set when/if we create another thread. */
+ if (((word)caller >= (word)GC_libpthread_start
+ && (word)caller < (word)GC_libpthread_end)
+ || ((word)caller >= (word)GC_libld_start
+ && (word)caller < (word)GC_libld_end)) {
+ GC_free(p);
+ return;
+ }
+ }
+# endif
# ifndef IGNORE_FREE
REDIRECT_FREE(p);
# endif
}
-# endif /* REDIRECT_MALLOC */
+#endif /* REDIRECT_FREE */
diff --git a/boehm-gc/mallocx.c b/boehm-gc/mallocx.c
index d45f21e8e51..bf7f9f06013 100644
--- a/boehm-gc/mallocx.c
+++ b/boehm-gc/mallocx.c
@@ -14,6 +14,8 @@
* modified is included with the above copyright notice.
*/
+#include "private/gc_priv.h"
+
/*
* These are extra allocation routines which are likely to be less
* frequently used than those in malloc.c. They are separate in the
@@ -22,123 +24,125 @@
*/
#include <stdio.h>
-#include "private/gc_priv.h"
+#include <string.h>
-extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
-void GC_extend_size_map(); /* in misc.c. */
-GC_bool GC_alloc_reclaim_list(); /* in malloc.c */
+#ifdef MSWINCE
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# define NOSERVICE
+# include <windows.h>
+#else
+# include <errno.h>
+#endif
/* Some externally visible but unadvertised variables to allow access to */
-/* free lists from inlined allocators without including gc_priv.h */
-/* or introducing dependencies on internal data structure layouts. */
-ptr_t * GC_CONST GC_objfreelist_ptr = GC_objfreelist;
-ptr_t * GC_CONST GC_aobjfreelist_ptr = GC_aobjfreelist;
-ptr_t * GC_CONST GC_uobjfreelist_ptr = GC_uobjfreelist;
+/* free lists from inlined allocators without including gc_priv.h */
+/* or introducing dependencies on internal data structure layouts. */
+void ** const GC_objfreelist_ptr = GC_objfreelist;
+void ** const GC_aobjfreelist_ptr = GC_aobjfreelist;
+void ** const GC_uobjfreelist_ptr = GC_uobjfreelist;
# ifdef ATOMIC_UNCOLLECTABLE
- ptr_t * GC_CONST GC_auobjfreelist_ptr = GC_auobjfreelist;
+ void ** const GC_auobjfreelist_ptr = GC_auobjfreelist;
# endif
-GC_PTR GC_generic_or_special_malloc(lb,knd)
-word lb;
-int knd;
+STATIC void * GC_generic_or_special_malloc(size_t lb, int knd)
{
switch(knd) {
# ifdef STUBBORN_ALLOC
- case STUBBORN:
- return(GC_malloc_stubborn((size_t)lb));
+ case STUBBORN:
+ return(GC_malloc_stubborn((size_t)lb));
# endif
- case PTRFREE:
- return(GC_malloc_atomic((size_t)lb));
- case NORMAL:
- return(GC_malloc((size_t)lb));
- case UNCOLLECTABLE:
- return(GC_malloc_uncollectable((size_t)lb));
+ case PTRFREE:
+ return(GC_malloc_atomic((size_t)lb));
+ case NORMAL:
+ return(GC_malloc((size_t)lb));
+ case UNCOLLECTABLE:
+ return(GC_malloc_uncollectable((size_t)lb));
# ifdef ATOMIC_UNCOLLECTABLE
- case AUNCOLLECTABLE:
- return(GC_malloc_atomic_uncollectable((size_t)lb));
-# endif /* ATOMIC_UNCOLLECTABLE */
- default:
- return(GC_generic_malloc(lb,knd));
+ case AUNCOLLECTABLE:
+ return(GC_malloc_atomic_uncollectable((size_t)lb));
+# endif /* ATOMIC_UNCOLLECTABLE */
+ default:
+ return(GC_generic_malloc(lb,knd));
}
}
-
/* Change the size of the block pointed to by p to contain at least */
/* lb bytes. The object may be (and quite likely will be) moved. */
-/* The kind (e.g. atomic) is the same as that of the old. */
+/* The kind (e.g. atomic) is the same as that of the old. */
/* Shrinking of large blocks is not implemented well. */
-# ifdef __STDC__
- GC_PTR GC_realloc(GC_PTR p, size_t lb)
-# else
- GC_PTR GC_realloc(p,lb)
- GC_PTR p;
- size_t lb;
-# endif
+GC_API void * GC_CALL GC_realloc(void * p, size_t lb)
{
-register struct hblk * h;
-register hdr * hhdr;
-register word sz; /* Current size in bytes */
-register word orig_sz; /* Original sz in bytes */
-int obj_kind;
+ struct hblk * h;
+ hdr * hhdr;
+ size_t sz; /* Current size in bytes */
+ size_t orig_sz; /* Original sz in bytes */
+ int obj_kind;
- if (p == 0) return(GC_malloc(lb)); /* Required by ANSI */
+ if (p == 0) return(GC_malloc(lb)); /* Required by ANSI */
h = HBLKPTR(p);
hhdr = HDR(h);
sz = hhdr -> hb_sz;
obj_kind = hhdr -> hb_obj_kind;
- sz = WORDS_TO_BYTES(sz);
orig_sz = sz;
if (sz > MAXOBJBYTES) {
- /* Round it up to the next whole heap block */
- register word descr;
-
- sz = (sz+HBLKSIZE-1) & (~HBLKMASK);
- hhdr -> hb_sz = BYTES_TO_WORDS(sz);
- descr = GC_obj_kinds[obj_kind].ok_descriptor;
+ /* Round it up to the next whole heap block */
+ word descr;
+
+ sz = (sz+HBLKSIZE-1) & (~HBLKMASK);
+ hhdr -> hb_sz = sz;
+ descr = GC_obj_kinds[obj_kind].ok_descriptor;
if (GC_obj_kinds[obj_kind].ok_relocate_descr) descr += sz;
hhdr -> hb_descr = descr;
- if (IS_UNCOLLECTABLE(obj_kind)) GC_non_gc_bytes += (sz - orig_sz);
- /* Extra area is already cleared by GC_alloc_large_and_clear. */
+# ifdef MARK_BIT_PER_OBJ
+ GC_ASSERT(hhdr -> hb_inv_sz == LARGE_INV_SZ);
+# else
+ GC_ASSERT(hhdr -> hb_large_block &&
+ hhdr -> hb_map[ANY_INDEX] == 1);
+# endif
+ if (IS_UNCOLLECTABLE(obj_kind)) GC_non_gc_bytes += (sz - orig_sz);
+ /* Extra area is already cleared by GC_alloc_large_and_clear. */
}
if (ADD_SLOP(lb) <= sz) {
- if (lb >= (sz >> 1)) {
-# ifdef STUBBORN_ALLOC
- if (obj_kind == STUBBORN) GC_change_stubborn(p);
-# endif
- if (orig_sz > lb) {
- /* Clear unneeded part of object to avoid bogus pointer */
- /* tracing. */
- /* Safe for stubborn objects. */
- BZERO(((ptr_t)p) + lb, orig_sz - lb);
- }
- return(p);
- } else {
- /* shrink */
- GC_PTR result =
- GC_generic_or_special_malloc((word)lb, obj_kind);
-
- if (result == 0) return(0);
- /* Could also return original object. But this */
- /* gives the client warning of imminent disaster. */
- BCOPY(p, result, lb);
-# ifndef IGNORE_FREE
- GC_free(p);
-# endif
- return(result);
- }
+ if (lb >= (sz >> 1)) {
+# ifdef STUBBORN_ALLOC
+ if (obj_kind == STUBBORN) GC_change_stubborn(p);
+# endif
+ if (orig_sz > lb) {
+ /* Clear unneeded part of object to avoid bogus pointer */
+ /* tracing. */
+ /* Safe for stubborn objects. */
+ BZERO(((ptr_t)p) + lb, orig_sz - lb);
+ }
+ return(p);
+ } else {
+ /* shrink */
+ void * result =
+ GC_generic_or_special_malloc((word)lb, obj_kind);
+
+ if (result == 0) return(0);
+ /* Could also return original object. But this */
+ /* gives the client warning of imminent disaster. */
+ BCOPY(p, result, lb);
+# ifndef IGNORE_FREE
+ GC_free(p);
+# endif
+ return(result);
+ }
} else {
- /* grow */
- GC_PTR result =
- GC_generic_or_special_malloc((word)lb, obj_kind);
-
- if (result == 0) return(0);
- BCOPY(p, result, sz);
-# ifndef IGNORE_FREE
- GC_free(p);
-# endif
- return(result);
+ /* grow */
+ void * result =
+ GC_generic_or_special_malloc((word)lb, obj_kind);
+
+ if (result == 0) return(0);
+ BCOPY(p, result, sz);
+# ifndef IGNORE_FREE
+ GC_free(p);
+# endif
+ return(result);
}
}
@@ -148,22 +152,12 @@ int obj_kind;
# ifdef REDIRECT_REALLOC
-/* As with malloc, avoid two levels of extra calls here. */
-# ifdef GC_ADD_CALLER
-# define RA GC_RETURN_ADDR,
-# else
-# define RA
-# endif
+/* As with malloc, avoid two levels of extra calls here. */
+
# define GC_debug_realloc_replacement(p, lb) \
- GC_debug_realloc(p, lb, RA "unknown", 0)
-
-# ifdef __STDC__
- GC_PTR realloc(GC_PTR p, size_t lb)
-# else
- GC_PTR realloc(p,lb)
- GC_PTR p;
- size_t lb;
-# endif
+ GC_debug_realloc(p, lb, GC_DBG_RA "unknown", 0)
+
+void * realloc(void * p, size_t lb)
{
return(REDIRECT_REALLOC(p, lb));
}
@@ -172,523 +166,447 @@ int obj_kind;
# endif /* REDIRECT_REALLOC */
-/* The same thing, except caller does not hold allocation lock. */
-/* We avoid holding allocation lock while we clear memory. */
-ptr_t GC_generic_malloc_ignore_off_page(lb, k)
-register size_t lb;
-register int k;
+/* Allocate memory such that only pointers to near the */
+/* beginning of the object are considered. */
+/* We avoid holding allocation lock while we clear memory. */
+GC_INNER void * GC_generic_malloc_ignore_off_page(size_t lb, int k)
{
- register ptr_t result;
- word lw;
+ void *result;
+ size_t lg;
+ size_t lb_rounded;
word n_blocks;
GC_bool init;
DCL_LOCK_STATE;
-
+
if (SMALL_OBJ(lb))
return(GC_generic_malloc((word)lb, k));
- lw = ROUNDED_UP_WORDS(lb);
- n_blocks = OBJ_SZ_TO_BLOCKS(lw);
+ lg = ROUNDED_UP_GRANULES(lb);
+ lb_rounded = GRANULES_TO_BYTES(lg);
+ if (lb_rounded < lb)
+ return((*GC_get_oom_fn())(lb));
+ n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded);
init = GC_obj_kinds[k].ok_init;
- if (GC_have_errors) GC_print_all_errors();
+ if (EXPECT(GC_have_errors, FALSE))
+ GC_print_all_errors();
GC_INVOKE_FINALIZERS();
- DISABLE_SIGNALS();
+ GC_DBG_COLLECT_AT_MALLOC(lb);
LOCK();
- result = (ptr_t)GC_alloc_large(lw, k, IGNORE_OFF_PAGE);
+ result = (ptr_t)GC_alloc_large(ADD_SLOP(lb), k, IGNORE_OFF_PAGE);
if (0 != result) {
if (GC_debugging_started) {
- BZERO(result, n_blocks * HBLKSIZE);
+ BZERO(result, n_blocks * HBLKSIZE);
} else {
# ifdef THREADS
- /* Clear any memory that might be used for GC descriptors */
- /* before we release the lock. */
- ((word *)result)[0] = 0;
- ((word *)result)[1] = 0;
- ((word *)result)[lw-1] = 0;
- ((word *)result)[lw-2] = 0;
-# endif
+ /* Clear any memory that might be used for GC descriptors */
+ /* before we release the lock. */
+ ((word *)result)[0] = 0;
+ ((word *)result)[1] = 0;
+ ((word *)result)[GRANULES_TO_WORDS(lg)-1] = 0;
+ ((word *)result)[GRANULES_TO_WORDS(lg)-2] = 0;
+# endif
}
}
- GC_words_allocd += lw;
- UNLOCK();
- ENABLE_SIGNALS();
+ GC_bytes_allocd += lb_rounded;
if (0 == result) {
- return((*GC_oom_fn)(lb));
+ GC_oom_func oom_fn = GC_oom_fn;
+ UNLOCK();
+ return((*oom_fn)(lb));
} else {
- if (init && !GC_debugging_started) {
- BZERO(result, n_blocks * HBLKSIZE);
+ UNLOCK();
+ if (init && !GC_debugging_started) {
+ BZERO(result, n_blocks * HBLKSIZE);
}
return(result);
}
}
-# if defined(__STDC__) || defined(__cplusplus)
- void * GC_malloc_ignore_off_page(size_t lb)
-# else
- char * GC_malloc_ignore_off_page(lb)
- register size_t lb;
-# endif
+GC_API void * GC_CALL GC_malloc_ignore_off_page(size_t lb)
{
- return((GC_PTR)GC_generic_malloc_ignore_off_page(lb, NORMAL));
+ return((void *)GC_generic_malloc_ignore_off_page(lb, NORMAL));
}
-# if defined(__STDC__) || defined(__cplusplus)
- void * GC_malloc_atomic_ignore_off_page(size_t lb)
-# else
- char * GC_malloc_atomic_ignore_off_page(lb)
- register size_t lb;
-# endif
+GC_API void * GC_CALL GC_malloc_atomic_ignore_off_page(size_t lb)
{
- return((GC_PTR)GC_generic_malloc_ignore_off_page(lb, PTRFREE));
+ return((void *)GC_generic_malloc_ignore_off_page(lb, PTRFREE));
}
-/* Increment GC_words_allocd from code that doesn't have direct access */
-/* to GC_arrays. */
-# ifdef __STDC__
-void GC_incr_words_allocd(size_t n)
+/* Increment GC_bytes_allocd from code that doesn't have direct access */
+/* to GC_arrays. */
+GC_API void GC_CALL GC_incr_bytes_allocd(size_t n)
{
- GC_words_allocd += n;
+ GC_bytes_allocd += n;
}
-/* The same for GC_mem_freed. */
-void GC_incr_mem_freed(size_t n)
+/* The same for GC_bytes_freed. */
+GC_API void GC_CALL GC_incr_bytes_freed(size_t n)
{
- GC_mem_freed += n;
+ GC_bytes_freed += n;
}
-# endif /* __STDC__ */
-
-/* Analogous to the above, but assumes a small object size, and */
-/* bypasses MERGE_SIZES mechanism. Used by gc_inline.h. */
-ptr_t GC_generic_malloc_words_small_inner(lw, k)
-register word lw;
-register int k;
-{
-register ptr_t op;
-register ptr_t *opp;
-register struct obj_kind * kind = GC_obj_kinds + k;
-
- opp = &(kind -> ok_freelist[lw]);
- if( (op = *opp) == 0 ) {
- if (!GC_is_initialized) {
- GC_init_inner();
- }
- if (kind -> ok_reclaim_list != 0 || GC_alloc_reclaim_list(kind)) {
- op = GC_clear_stack(GC_allocobj((word)lw, k));
- }
- if (op == 0) {
- UNLOCK();
- ENABLE_SIGNALS();
- return ((*GC_oom_fn)(WORDS_TO_BYTES(lw)));
- }
- }
- *opp = obj_link(op);
- obj_link(op) = 0;
- GC_words_allocd += lw;
- return((ptr_t)op);
-}
-
-/* Analogous to the above, but assumes a small object size, and */
-/* bypasses MERGE_SIZES mechanism. Used by gc_inline.h. */
-#ifdef __STDC__
- ptr_t GC_generic_malloc_words_small(size_t lw, int k)
-#else
- ptr_t GC_generic_malloc_words_small(lw, k)
- register word lw;
- register int k;
-#endif
-{
-register ptr_t op;
-DCL_LOCK_STATE;
- if (GC_have_errors) GC_print_all_errors();
- GC_INVOKE_FINALIZERS();
- DISABLE_SIGNALS();
- LOCK();
- op = GC_generic_malloc_words_small_inner(lw, k);
- UNLOCK();
- ENABLE_SIGNALS();
- return((ptr_t)op);
-}
-
-#if defined(THREADS) && !defined(SRC_M3)
-
-extern signed_word GC_mem_found; /* Protected by GC lock. */
-
-#ifdef PARALLEL_MARK
-volatile signed_word GC_words_allocd_tmp = 0;
- /* Number of words of memory allocated since */
+# ifdef PARALLEL_MARK
+ STATIC volatile AO_t GC_bytes_allocd_tmp = 0;
+ /* Number of bytes of memory allocated since */
/* we released the GC lock. Instead of */
/* reacquiring the GC lock just to add this in, */
/* we add it in the next time we reacquire */
/* the lock. (Atomically adding it doesn't */
/* work, since we would have to atomically */
/* update it in GC_malloc, which is too */
- /* expensive. */
-#endif /* PARALLEL_MARK */
+ /* expensive.) */
+# endif /* PARALLEL_MARK */
-/* See reclaim.c: */
-extern ptr_t GC_reclaim_generic();
-
-/* Return a list of 1 or more objects of the indicated size, linked */
-/* through the first word in the object. This has the advantage that */
-/* it acquires the allocation lock only once, and may greatly reduce */
+/* Return a list of 1 or more objects of the indicated size, linked */
+/* through the first word in the object. This has the advantage that */
+/* it acquires the allocation lock only once, and may greatly reduce */
/* time wasted contending for the allocation lock. Typical usage would */
-/* be in a thread that requires many items of the same size. It would */
-/* keep its own free list in thread-local storage, and call */
-/* GC_malloc_many or friends to replenish it. (We do not round up */
-/* object sizes, since a call indicates the intention to consume many */
-/* objects of exactly this size.) */
-/* We return the free-list by assigning it to *result, since it is */
-/* not safe to return, e.g. a linked list of pointer-free objects, */
-/* since the collector would not retain the entire list if it were */
-/* invoked just as we were returning. */
-/* Note that the client should usually clear the link field. */
-void GC_generic_malloc_many(lb, k, result)
-register word lb;
-register int k;
-ptr_t *result;
+/* be in a thread that requires many items of the same size. It would */
+/* keep its own free list in thread-local storage, and call */
+/* GC_malloc_many or friends to replenish it. (We do not round up */
+/* object sizes, since a call indicates the intention to consume many */
+/* objects of exactly this size.) */
+/* We assume that the size is a multiple of GRANULE_BYTES. */
+/* We return the free-list by assigning it to *result, since it is */
+/* not safe to return, e.g. a linked list of pointer-free objects, */
+/* since the collector would not retain the entire list if it were */
+/* invoked just as we were returning. */
+/* Note that the client should usually clear the link field. */
+GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result)
{
-ptr_t op;
-ptr_t p;
-ptr_t *opp;
-word lw;
-word my_words_allocd = 0;
-struct obj_kind * ok = &(GC_obj_kinds[k]);
-DCL_LOCK_STATE;
-
-# if defined(GATHERSTATS) || defined(PARALLEL_MARK)
-# define COUNT_ARG , &my_words_allocd
-# else
-# define COUNT_ARG
-# define NEED_TO_COUNT
-# endif
+ void *op;
+ void *p;
+ void **opp;
+ size_t lw; /* Length in words. */
+ size_t lg; /* Length in granules. */
+ signed_word my_bytes_allocd = 0;
+ struct obj_kind * ok = &(GC_obj_kinds[k]);
+ DCL_LOCK_STATE;
+
+ GC_ASSERT(lb != 0 && (lb & (GRANULE_BYTES-1)) == 0);
if (!SMALL_OBJ(lb)) {
op = GC_generic_malloc(lb, k);
- if(0 != op) obj_link(op) = 0;
- *result = op;
+ if (EXPECT(0 != op, TRUE))
+ obj_link(op) = 0;
+ *result = op;
return;
}
- lw = ALIGNED_WORDS(lb);
- if (GC_have_errors) GC_print_all_errors();
+ lw = BYTES_TO_WORDS(lb);
+ lg = BYTES_TO_GRANULES(lb);
+ if (EXPECT(GC_have_errors, FALSE))
+ GC_print_all_errors();
GC_INVOKE_FINALIZERS();
- DISABLE_SIGNALS();
+ GC_DBG_COLLECT_AT_MALLOC(lb);
LOCK();
- if (!GC_is_initialized) GC_init_inner();
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
/* Do our share of marking work */
if (GC_incremental && !GC_dont_gc) {
ENTER_GC();
- GC_collect_a_little_inner(1);
+ GC_collect_a_little_inner(1);
EXIT_GC();
}
/* First see if we can reclaim a page of objects waiting to be */
- /* reclaimed. */
+ /* reclaimed. */
{
- struct hblk ** rlh = ok -> ok_reclaim_list;
- struct hblk * hbp;
- hdr * hhdr;
+ struct hblk ** rlh = ok -> ok_reclaim_list;
+ struct hblk * hbp;
+ hdr * hhdr;
- rlh += lw;
- while ((hbp = *rlh) != 0) {
+ rlh += lg;
+ while ((hbp = *rlh) != 0) {
hhdr = HDR(hbp);
*rlh = hhdr -> hb_next;
- hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
-# ifdef PARALLEL_MARK
- {
- signed_word my_words_allocd_tmp = GC_words_allocd_tmp;
-
- GC_ASSERT(my_words_allocd_tmp >= 0);
- /* We only decrement it while holding the GC lock. */
- /* Thus we can't accidentally adjust it down in more */
- /* than one thread simultaneously. */
- if (my_words_allocd_tmp != 0) {
- (void)GC_atomic_add(
- (volatile GC_word *)(&GC_words_allocd_tmp),
- (GC_word)(-my_words_allocd_tmp));
- GC_words_allocd += my_words_allocd_tmp;
- }
- }
- GC_acquire_mark_lock();
- ++ GC_fl_builder_count;
- UNLOCK();
- ENABLE_SIGNALS();
- GC_release_mark_lock();
-# endif
- op = GC_reclaim_generic(hbp, hhdr, lw,
- ok -> ok_init, 0 COUNT_ARG);
+ GC_ASSERT(hhdr -> hb_sz == lb);
+ hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
+# ifdef PARALLEL_MARK
+ if (GC_parallel) {
+ signed_word my_bytes_allocd_tmp =
+ (signed_word)AO_load(&GC_bytes_allocd_tmp);
+ GC_ASSERT(my_bytes_allocd_tmp >= 0);
+ /* We only decrement it while holding the GC lock. */
+ /* Thus we can't accidentally adjust it down in more */
+ /* than one thread simultaneously. */
+
+ if (my_bytes_allocd_tmp != 0) {
+ (void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
+ (AO_t)(-my_bytes_allocd_tmp));
+ GC_bytes_allocd += my_bytes_allocd_tmp;
+ }
+ GC_acquire_mark_lock();
+ ++ GC_fl_builder_count;
+ UNLOCK();
+ GC_release_mark_lock();
+ }
+# endif
+ op = GC_reclaim_generic(hbp, hhdr, lb,
+ ok -> ok_init, 0, &my_bytes_allocd);
if (op != 0) {
-# ifdef NEED_TO_COUNT
- /* We are neither gathering statistics, nor marking in */
- /* parallel. Thus GC_reclaim_generic doesn't count */
- /* for us. */
- for (p = op; p != 0; p = obj_link(p)) {
- my_words_allocd += lw;
- }
-# endif
-# if defined(GATHERSTATS)
- /* We also reclaimed memory, so we need to adjust */
- /* that count. */
- /* This should be atomic, so the results may be */
- /* inaccurate. */
- GC_mem_found += my_words_allocd;
-# endif
-# ifdef PARALLEL_MARK
- *result = op;
- (void)GC_atomic_add(
- (volatile GC_word *)(&GC_words_allocd_tmp),
- (GC_word)(my_words_allocd));
- GC_acquire_mark_lock();
- -- GC_fl_builder_count;
- if (GC_fl_builder_count == 0) GC_notify_all_builder();
- GC_release_mark_lock();
- (void) GC_clear_stack(0);
- return;
-# else
- GC_words_allocd += my_words_allocd;
- goto out;
-# endif
- }
-# ifdef PARALLEL_MARK
- GC_acquire_mark_lock();
- -- GC_fl_builder_count;
- if (GC_fl_builder_count == 0) GC_notify_all_builder();
- GC_release_mark_lock();
- DISABLE_SIGNALS();
- LOCK();
- /* GC lock is needed for reclaim list access. We */
- /* must decrement fl_builder_count before reaquiring GC */
- /* lock. Hopefully this path is rare. */
-# endif
- }
+ /* We also reclaimed memory, so we need to adjust */
+ /* that count. */
+ /* This should be atomic, so the results may be */
+ /* inaccurate. */
+ GC_bytes_found += my_bytes_allocd;
+# ifdef PARALLEL_MARK
+ if (GC_parallel) {
+ *result = op;
+ (void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
+ (AO_t)my_bytes_allocd);
+ GC_acquire_mark_lock();
+ -- GC_fl_builder_count;
+ if (GC_fl_builder_count == 0) GC_notify_all_builder();
+ GC_release_mark_lock();
+ (void) GC_clear_stack(0);
+ return;
+ }
+# endif
+ GC_bytes_allocd += my_bytes_allocd;
+ goto out;
+ }
+# ifdef PARALLEL_MARK
+ if (GC_parallel) {
+ GC_acquire_mark_lock();
+ -- GC_fl_builder_count;
+ if (GC_fl_builder_count == 0) GC_notify_all_builder();
+ GC_release_mark_lock();
+ LOCK();
+ /* GC lock is needed for reclaim list access. We */
+ /* must decrement fl_builder_count before reaquiring GC */
+ /* lock. Hopefully this path is rare. */
+ }
+# endif
+ }
}
- /* Next try to use prefix of global free list if there is one. */
- /* We don't refill it, but we need to use it up before allocating */
- /* a new block ourselves. */
- opp = &(GC_obj_kinds[k].ok_freelist[lw]);
+ /* Next try to use prefix of global free list if there is one. */
+ /* We don't refill it, but we need to use it up before allocating */
+ /* a new block ourselves. */
+ opp = &(GC_obj_kinds[k].ok_freelist[lg]);
if ( (op = *opp) != 0 ) {
- *opp = 0;
- my_words_allocd = 0;
+ *opp = 0;
+ my_bytes_allocd = 0;
for (p = op; p != 0; p = obj_link(p)) {
- my_words_allocd += lw;
- if (my_words_allocd >= BODY_SZ) {
+ my_bytes_allocd += lb;
+ if ((word)my_bytes_allocd >= HBLKSIZE) {
*opp = obj_link(p);
obj_link(p) = 0;
break;
- }
+ }
}
- GC_words_allocd += my_words_allocd;
- goto out;
+ GC_bytes_allocd += my_bytes_allocd;
+ goto out;
}
- /* Next try to allocate a new block worth of objects of this size. */
+ /* Next try to allocate a new block worth of objects of this size. */
{
- struct hblk *h = GC_allochblk(lw, k, 0);
- if (h != 0) {
- if (IS_UNCOLLECTABLE(k)) GC_set_hdr_marks(HDR(h));
- GC_words_allocd += BYTES_TO_WORDS(HBLKSIZE)
- - BYTES_TO_WORDS(HBLKSIZE) % lw;
-# ifdef PARALLEL_MARK
- GC_acquire_mark_lock();
- ++ GC_fl_builder_count;
- UNLOCK();
- ENABLE_SIGNALS();
- GC_release_mark_lock();
-# endif
-
- op = GC_build_fl(h, lw, ok -> ok_init, 0);
-# ifdef PARALLEL_MARK
- *result = op;
- GC_acquire_mark_lock();
- -- GC_fl_builder_count;
- if (GC_fl_builder_count == 0) GC_notify_all_builder();
- GC_release_mark_lock();
- (void) GC_clear_stack(0);
- return;
-# else
- goto out;
-# endif
- }
+ struct hblk *h = GC_allochblk(lb, k, 0);
+ if (h != 0) {
+ if (IS_UNCOLLECTABLE(k)) GC_set_hdr_marks(HDR(h));
+ GC_bytes_allocd += HBLKSIZE - HBLKSIZE % lb;
+# ifdef PARALLEL_MARK
+ if (GC_parallel) {
+ GC_acquire_mark_lock();
+ ++ GC_fl_builder_count;
+ UNLOCK();
+ GC_release_mark_lock();
+
+ op = GC_build_fl(h, lw,
+ (ok -> ok_init || GC_debugging_started), 0);
+
+ *result = op;
+ GC_acquire_mark_lock();
+ -- GC_fl_builder_count;
+ if (GC_fl_builder_count == 0) GC_notify_all_builder();
+ GC_release_mark_lock();
+ (void) GC_clear_stack(0);
+ return;
+ }
+# endif
+ op = GC_build_fl(h, lw, (ok -> ok_init || GC_debugging_started), 0);
+ goto out;
+ }
}
-
- /* As a last attempt, try allocating a single object. Note that */
- /* this may trigger a collection or expand the heap. */
+
+ /* As a last attempt, try allocating a single object. Note that */
+ /* this may trigger a collection or expand the heap. */
op = GC_generic_malloc_inner(lb, k);
if (0 != op) obj_link(op) = 0;
-
+
out:
*result = op;
UNLOCK();
- ENABLE_SIGNALS();
(void) GC_clear_stack(0);
}
-GC_PTR GC_malloc_many(size_t lb)
+/* Note that the "atomic" version of this would be unsafe, since the */
+/* links would not be seen by the collector. */
+GC_API void * GC_CALL GC_malloc_many(size_t lb)
{
- ptr_t result;
- GC_generic_malloc_many(lb, NORMAL, &result);
+ void *result;
+ GC_generic_malloc_many((lb + EXTRA_BYTES + GRANULE_BYTES-1)
+ & ~(GRANULE_BYTES-1),
+ NORMAL, &result);
return result;
}
-/* Note that the "atomic" version of this would be unsafe, since the */
-/* links would not be seen by the collector. */
-# endif
-
-/* Allocate lb bytes of pointerful, traced, but not collectable data */
-# ifdef __STDC__
- GC_PTR GC_malloc_uncollectable(size_t lb)
-# else
- GC_PTR GC_malloc_uncollectable(lb)
- size_t lb;
-# endif
-{
-register ptr_t op;
-register ptr_t *opp;
-register word lw;
-DCL_LOCK_STATE;
-
- if( SMALL_OBJ(lb) ) {
-# ifdef MERGE_SIZES
- if (EXTRA_BYTES != 0 && lb != 0) lb--;
- /* We don't need the extra byte, since this won't be */
- /* collected anyway. */
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_uobjfreelist[lw]);
- FASTLOCK();
- if( FASTLOCK_SUCCEEDED() && (op = *opp) != 0 ) {
- /* See above comment on signals. */
- *opp = obj_link(op);
- obj_link(op) = 0;
- GC_words_allocd += lw;
- /* Mark bit ws already set on free list. It will be */
- /* cleared only temporarily during a collection, as a */
- /* result of the normal free list mark bit clearing. */
- GC_non_gc_bytes += WORDS_TO_BYTES(lw);
- FASTUNLOCK();
- return((GC_PTR) op);
- }
- FASTUNLOCK();
- op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
- } else {
- op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
- }
- if (0 == op) return(0);
- /* We don't need the lock here, since we have an undisguised */
- /* pointer. We do need to hold the lock while we adjust */
- /* mark bits. */
- {
- register struct hblk * h;
-
- h = HBLKPTR(op);
- lw = HDR(h) -> hb_sz;
-
- DISABLE_SIGNALS();
- LOCK();
- GC_set_mark_bit(op);
- GC_non_gc_bytes += WORDS_TO_BYTES(lw);
- UNLOCK();
- ENABLE_SIGNALS();
- return((GC_PTR) op);
- }
-}
-
-#ifdef __STDC__
-/* Not well tested nor integrated. */
-/* Debug version is tricky and currently missing. */
+/* Not well tested nor integrated. */
+/* Debug version is tricky and currently missing. */
#include <limits.h>
-GC_PTR GC_memalign(size_t align, size_t lb)
-{
+GC_API void * GC_CALL GC_memalign(size_t align, size_t lb)
+{
size_t new_lb;
size_t offset;
ptr_t result;
-# ifdef ALIGN_DOUBLE
- if (align <= WORDS_TO_BYTES(2) && lb > align) return GC_malloc(lb);
-# endif
- if (align <= WORDS_TO_BYTES(1)) return GC_malloc(lb);
+ if (align <= GRANULE_BYTES) return GC_malloc(lb);
if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) {
- if (align > HBLKSIZE) return GC_oom_fn(LONG_MAX-1024) /* Fail */;
- return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb);
- /* Will be HBLKSIZE aligned. */
+ if (align > HBLKSIZE) {
+ return (*GC_get_oom_fn())(LONG_MAX-1024); /* Fail */
+ }
+ return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb);
+ /* Will be HBLKSIZE aligned. */
}
/* We could also try to make sure that the real rounded-up object size */
- /* is a multiple of align. That would be correct up to HBLKSIZE. */
+ /* is a multiple of align. That would be correct up to HBLKSIZE. */
new_lb = lb + align - 1;
result = GC_malloc(new_lb);
+ /* It is ok not to check result for NULL as in that case */
+ /* GC_memalign returns NULL too since (0 + 0 % align) is 0. */
offset = (word)result % align;
if (offset != 0) {
- offset = align - offset;
+ offset = align - offset;
if (!GC_all_interior_pointers) {
- if (offset >= VALID_OFFSET_SZ) return GC_malloc(HBLKSIZE);
- GC_register_displacement(offset);
- }
+ if (offset >= VALID_OFFSET_SZ) return GC_malloc(HBLKSIZE);
+ GC_register_displacement(offset);
+ }
}
- result = (GC_PTR) ((ptr_t)result + offset);
+ result = (void *) ((ptr_t)result + offset);
GC_ASSERT((word)result % align == 0);
return result;
}
-#endif
-# ifdef ATOMIC_UNCOLLECTABLE
-/* Allocate lb bytes of pointerfree, untraced, uncollectable data */
-/* This is normally roughly equivalent to the system malloc. */
-/* But it may be useful if malloc is redefined. */
-# ifdef __STDC__
- GC_PTR GC_malloc_atomic_uncollectable(size_t lb)
-# else
- GC_PTR GC_malloc_atomic_uncollectable(lb)
- size_t lb;
-# endif
+/* This one exists largerly to redirect posix_memalign for leaks finding. */
+GC_API int GC_CALL GC_posix_memalign(void **memptr, size_t align, size_t lb)
{
-register ptr_t op;
-register ptr_t *opp;
-register word lw;
-DCL_LOCK_STATE;
+ /* Check alignment properly. */
+ if (((align - 1) & align) != 0 || align < sizeof(void *)) {
+# ifdef MSWINCE
+ return ERROR_INVALID_PARAMETER;
+# else
+ return EINVAL;
+# endif
+ }
+
+ if ((*memptr = GC_memalign(align, lb)) == NULL) {
+# ifdef MSWINCE
+ return ERROR_NOT_ENOUGH_MEMORY;
+# else
+ return ENOMEM;
+# endif
+ }
+ return 0;
+}
+
+#ifdef ATOMIC_UNCOLLECTABLE
+ /* Allocate lb bytes of pointerfree, untraced, uncollectable data */
+ /* This is normally roughly equivalent to the system malloc. */
+ /* But it may be useful if malloc is redefined. */
+ GC_API void * GC_CALL GC_malloc_atomic_uncollectable(size_t lb)
+ {
+ void *op;
+ void **opp;
+ size_t lg;
+ DCL_LOCK_STATE;
if( SMALL_OBJ(lb) ) {
-# ifdef MERGE_SIZES
- if (EXTRA_BYTES != 0 && lb != 0) lb--;
- /* We don't need the extra byte, since this won't be */
- /* collected anyway. */
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_auobjfreelist[lw]);
- FASTLOCK();
- if( FASTLOCK_SUCCEEDED() && (op = *opp) != 0 ) {
- /* See above comment on signals. */
+ GC_DBG_COLLECT_AT_MALLOC(lb);
+ if (EXTRA_BYTES != 0 && lb != 0) lb--;
+ /* We don't need the extra byte, since this won't be */
+ /* collected anyway. */
+ lg = GC_size_map[lb];
+ opp = &(GC_auobjfreelist[lg]);
+ LOCK();
+ op = *opp;
+ if (EXPECT(0 != op, TRUE)) {
*opp = obj_link(op);
obj_link(op) = 0;
- GC_words_allocd += lw;
- /* Mark bit was already set while object was on free list. */
- GC_non_gc_bytes += WORDS_TO_BYTES(lw);
- FASTUNLOCK();
- return((GC_PTR) op);
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+ /* Mark bit was already set while object was on free list. */
+ GC_non_gc_bytes += GRANULES_TO_BYTES(lg);
+ UNLOCK();
+ } else {
+ UNLOCK();
+ op = (ptr_t)GC_generic_malloc(lb, AUNCOLLECTABLE);
}
- FASTUNLOCK();
- op = (ptr_t)GC_generic_malloc((word)lb, AUNCOLLECTABLE);
+ GC_ASSERT(0 == op || GC_is_marked(op));
+ return((void *) op);
} else {
- op = (ptr_t)GC_generic_malloc((word)lb, AUNCOLLECTABLE);
- }
- if (0 == op) return(0);
- /* We don't need the lock here, since we have an undisguised */
- /* pointer. We do need to hold the lock while we adjust */
- /* mark bits. */
- {
- register struct hblk * h;
-
- h = HBLKPTR(op);
- lw = HDR(h) -> hb_sz;
-
- DISABLE_SIGNALS();
- LOCK();
- GC_set_mark_bit(op);
- GC_non_gc_bytes += WORDS_TO_BYTES(lw);
- UNLOCK();
- ENABLE_SIGNALS();
- return((GC_PTR) op);
+ hdr * hhdr;
+
+ op = (ptr_t)GC_generic_malloc(lb, AUNCOLLECTABLE);
+ if (0 == op) return(0);
+
+ GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0);
+ hhdr = HDR(op);
+
+ LOCK();
+ set_mark_bit_from_hdr(hhdr, 0); /* Only object. */
+# ifndef THREADS
+ GC_ASSERT(hhdr -> hb_n_marks == 0);
+# endif
+ hhdr -> hb_n_marks = 1;
+ UNLOCK();
+ return((void *) op);
}
+ }
+#endif /* ATOMIC_UNCOLLECTABLE */
+
+/* provide a version of strdup() that uses the collector to allocate the
+ copy of the string */
+GC_API char * GC_CALL GC_strdup(const char *s)
+{
+ char *copy;
+ size_t lb;
+ if (s == NULL) return NULL;
+ lb = strlen(s) + 1;
+ if ((copy = GC_malloc_atomic(lb)) == NULL) {
+# ifndef MSWINCE
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+ BCOPY(s, copy, lb);
+ return copy;
}
-#endif /* ATOMIC_UNCOLLECTABLE */
+GC_API char * GC_CALL GC_strndup(const char *str, size_t size)
+{
+ char *copy;
+ size_t len = strlen(str); /* str is expected to be non-NULL */
+ if (len > size)
+ len = size;
+ copy = GC_malloc_atomic(len + 1);
+ if (copy == NULL) {
+# ifndef MSWINCE
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+ BCOPY(str, copy, len);
+ copy[len] = '\0';
+ return copy;
+}
+
+#ifdef GC_REQUIRE_WCSDUP
+# include <wchar.h> /* for wcslen() */
+
+ GC_API wchar_t * GC_CALL GC_wcsdup(const wchar_t *str)
+ {
+ size_t lb = (wcslen(str) + 1) * sizeof(wchar_t);
+ wchar_t *copy = GC_malloc_atomic(lb);
+ if (copy == NULL) {
+# ifndef MSWINCE
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+ BCOPY(str, copy, lb);
+ return copy;
+ }
+#endif /* GC_REQUIRE_WCSDUP */
diff --git a/boehm-gc/mark.c b/boehm-gc/mark.c
index c645bc0eeec..e941abf8feb 100644
--- a/boehm-gc/mark.c
+++ b/boehm-gc/mark.c
@@ -1,4 +1,3 @@
-
/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
@@ -15,82 +14,87 @@
*
*/
+#include "private/gc_pmark.h"
-# include <stdio.h>
-# include "private/gc_pmark.h"
+#include <stdio.h>
#if defined(MSWIN32) && defined(__GNUC__)
# include <excpt.h>
#endif
-/* We put this here to minimize the risk of inlining. */
-/*VARARGS*/
-#ifdef __WATCOMC__
- void GC_noop(void *p, ...) {}
-#else
- void GC_noop() {}
-#endif
+/* Make arguments appear live to compiler. Put here to minimize the */
+/* risk of inlining. Used to minimize junk left in registers. */
+void GC_noop6(word arg1 GC_ATTR_UNUSED, word arg2 GC_ATTR_UNUSED,
+ word arg3 GC_ATTR_UNUSED, word arg4 GC_ATTR_UNUSED,
+ word arg5 GC_ATTR_UNUSED, word arg6 GC_ATTR_UNUSED)
+{
+ /* Empty */
+}
/* Single argument version, robust against whole program analysis. */
-void GC_noop1(x)
-word x;
+volatile word GC_noop_sink;
+GC_API void GC_CALL GC_noop1(word x)
{
- static VOLATILE word sink;
-
- sink = x;
+ GC_noop_sink = x;
}
/* mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0} -- declared in gc_priv.h */
-word GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
+GC_INNER unsigned GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
-/* Initialize GC_obj_kinds properly and standard free lists properly. */
-/* This must be done statically since they may be accessed before */
-/* GC_init is called. */
-/* It's done here, since we need to deal with mark descriptors. */
-struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
+/* Initialize GC_obj_kinds properly and standard free lists properly. */
+/* This must be done statically since they may be accessed before */
+/* GC_init is called. */
+/* It's done here, since we need to deal with mark descriptors. */
+GC_INNER struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
/* PTRFREE */ { &GC_aobjfreelist[0], 0 /* filled in dynamically */,
- 0 | GC_DS_LENGTH, FALSE, FALSE },
+ 0 | GC_DS_LENGTH, FALSE, FALSE
+ /*, */ OK_DISCLAIM_INITZ },
/* NORMAL */ { &GC_objfreelist[0], 0,
- 0 | GC_DS_LENGTH, /* Adjusted in GC_init_inner for EXTRA_BYTES */
- TRUE /* add length to descr */, TRUE },
+ 0 | GC_DS_LENGTH, /* Adjusted in GC_init for EXTRA_BYTES */
+ TRUE /* add length to descr */, TRUE
+ /*, */ OK_DISCLAIM_INITZ },
/* UNCOLLECTABLE */
- { &GC_uobjfreelist[0], 0,
- 0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE },
+ { &GC_uobjfreelist[0], 0,
+ 0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE
+ /*, */ OK_DISCLAIM_INITZ },
# ifdef ATOMIC_UNCOLLECTABLE
/* AUNCOLLECTABLE */
- { &GC_auobjfreelist[0], 0,
- 0 | GC_DS_LENGTH, FALSE /* add length to descr */, FALSE },
+ { &GC_auobjfreelist[0], 0,
+ 0 | GC_DS_LENGTH, FALSE /* add length to descr */, FALSE
+ /*, */ OK_DISCLAIM_INITZ },
# endif
# ifdef STUBBORN_ALLOC
-/*STUBBORN*/ { &GC_sobjfreelist[0], 0,
- 0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE },
+/*STUBBORN*/ { (void **)&GC_sobjfreelist[0], 0,
+ 0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE
+ /*, */ OK_DISCLAIM_INITZ },
# endif
};
# ifdef ATOMIC_UNCOLLECTABLE
# ifdef STUBBORN_ALLOC
- int GC_n_kinds = 5;
+# define GC_N_KINDS_INITIAL_VALUE 5
# else
- int GC_n_kinds = 4;
+# define GC_N_KINDS_INITIAL_VALUE 4
# endif
# else
# ifdef STUBBORN_ALLOC
- int GC_n_kinds = 4;
+# define GC_N_KINDS_INITIAL_VALUE 4
# else
- int GC_n_kinds = 3;
+# define GC_N_KINDS_INITIAL_VALUE 3
# endif
# endif
+GC_INNER unsigned GC_n_kinds = GC_N_KINDS_INITIAL_VALUE;
# ifndef INITIAL_MARK_STACK_SIZE
# define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE)
- /* INITIAL_MARK_STACK_SIZE * sizeof(mse) should be a */
- /* multiple of HBLKSIZE. */
- /* The incremental collector actually likes a larger */
- /* size, since it want to push all marked dirty objs */
- /* before marking anything new. Currently we let it */
- /* grow dynamically. */
+ /* INITIAL_MARK_STACK_SIZE * sizeof(mse) should be a */
+ /* multiple of HBLKSIZE. */
+ /* The incremental collector actually likes a larger */
+ /* size, since it want to push all marked dirty objs */
+ /* before marking anything new. Currently we let it */
+ /* grow dynamically. */
# endif
/*
@@ -99,324 +103,355 @@ struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
* need to be marked from.
*/
-word GC_n_rescuing_pages; /* Number of dirty pages we marked from */
- /* excludes ptrfree pages, etc. */
-
-mse * GC_mark_stack;
+STATIC word GC_n_rescuing_pages = 0;
+ /* Number of dirty pages we marked from */
+ /* excludes ptrfree pages, etc. */
-mse * GC_mark_stack_limit;
+GC_INNER mse * GC_mark_stack = NULL;
+GC_INNER mse * GC_mark_stack_limit = NULL;
+GC_INNER size_t GC_mark_stack_size = 0;
-word GC_mark_stack_size = 0;
-
#ifdef PARALLEL_MARK
- mse * VOLATILE GC_mark_stack_top;
+ GC_INNER mse * volatile GC_mark_stack_top = NULL;
+ /* Updated only with mark lock held, but read asynchronously. */
+ STATIC volatile AO_t GC_first_nonempty = 0;
+ /* Lowest entry on mark stack */
+ /* that may be nonempty. */
+ /* Updated only by initiating */
+ /* thread. */
#else
- mse * GC_mark_stack_top;
+ GC_INNER mse * GC_mark_stack_top = NULL;
#endif
-static struct hblk * scan_ptr;
+GC_INNER mark_state_t GC_mark_state = MS_NONE;
-mark_state_t GC_mark_state = MS_NONE;
+GC_INNER GC_bool GC_mark_stack_too_small = FALSE;
-GC_bool GC_mark_stack_too_small = FALSE;
+static struct hblk * scan_ptr;
-GC_bool GC_objects_are_marked = FALSE; /* Are there collectable marked */
- /* objects in the heap? */
+STATIC GC_bool GC_objects_are_marked = FALSE;
+ /* Are there collectable marked objects in the heap? */
-/* Is a collection in progress? Note that this can return true in the */
-/* nonincremental case, if a collection has been abandoned and the */
-/* mark state is now MS_INVALID. */
-GC_bool GC_collection_in_progress()
+/* Is a collection in progress? Note that this can return true in the */
+/* nonincremental case, if a collection has been abandoned and the */
+/* mark state is now MS_INVALID. */
+GC_INNER GC_bool GC_collection_in_progress(void)
{
return(GC_mark_state != MS_NONE);
}
/* clear all mark bits in the header */
-void GC_clear_hdr_marks(hhdr)
-register hdr * hhdr;
+GC_INNER void GC_clear_hdr_marks(hdr *hhdr)
{
-# ifdef USE_MARK_BYTES
- BZERO(hhdr -> hb_marks, MARK_BITS_SZ);
-# else
- BZERO(hhdr -> hb_marks, MARK_BITS_SZ*sizeof(word));
-# endif
+ size_t last_bit = FINAL_MARK_BIT(hhdr -> hb_sz);
+ BZERO(hhdr -> hb_marks, sizeof(hhdr->hb_marks));
+ set_mark_bit_from_hdr(hhdr, last_bit);
+ hhdr -> hb_n_marks = 0;
}
/* Set all mark bits in the header. Used for uncollectable blocks. */
-void GC_set_hdr_marks(hhdr)
-register hdr * hhdr;
+GC_INNER void GC_set_hdr_marks(hdr *hhdr)
{
- register int i;
+ unsigned i;
+ size_t sz = hhdr -> hb_sz;
+ unsigned n_marks = (unsigned)FINAL_MARK_BIT(sz);
- for (i = 0; i < MARK_BITS_SZ; ++i) {
-# ifdef USE_MARK_BYTES
- hhdr -> hb_marks[i] = 1;
-# else
- hhdr -> hb_marks[i] = ONES;
-# endif
- }
+# ifdef USE_MARK_BYTES
+ for (i = 0; i <= n_marks; i += (unsigned)MARK_BIT_OFFSET(sz)) {
+ hhdr -> hb_marks[i] = 1;
+ }
+# else
+ for (i = 0; i < divWORDSZ(n_marks + WORDSZ); ++i) {
+ hhdr -> hb_marks[i] = ONES;
+ }
+# endif
+# ifdef MARK_BIT_PER_OBJ
+ hhdr -> hb_n_marks = n_marks - 1;
+# else
+ hhdr -> hb_n_marks = HBLK_OBJS(sz);
+# endif
}
/*
* Clear all mark bits associated with block h.
*/
-/*ARGSUSED*/
-# if defined(__STDC__) || defined(__cplusplus)
- static void clear_marks_for_block(struct hblk *h, word dummy)
-# else
- static void clear_marks_for_block(h, dummy)
- struct hblk *h;
- word dummy;
-# endif
+static void clear_marks_for_block(struct hblk *h, word dummy GC_ATTR_UNUSED)
{
register hdr * hhdr = HDR(h);
-
+
if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) return;
- /* Mark bit for these is cleared only once the object is */
- /* explicitly deallocated. This either frees the block, or */
- /* the bit is cleared once the object is on the free list. */
+ /* Mark bit for these is cleared only once the object is */
+ /* explicitly deallocated. This either frees the block, or */
+ /* the bit is cleared once the object is on the free list. */
GC_clear_hdr_marks(hhdr);
}
/* Slow but general routines for setting/clearing/asking about mark bits */
-void GC_set_mark_bit(p)
-ptr_t p;
+GC_API void GC_CALL GC_set_mark_bit(const void *p)
{
- register struct hblk *h = HBLKPTR(p);
- register hdr * hhdr = HDR(h);
- register int word_no = (word *)p - (word *)h;
-
- set_mark_bit_from_hdr(hhdr, word_no);
+ struct hblk *h = HBLKPTR(p);
+ hdr * hhdr = HDR(h);
+ word bit_no = MARK_BIT_NO((ptr_t)p - (ptr_t)h, hhdr -> hb_sz);
+
+ if (!mark_bit_from_hdr(hhdr, bit_no)) {
+ set_mark_bit_from_hdr(hhdr, bit_no);
+ ++hhdr -> hb_n_marks;
+ }
}
-void GC_clear_mark_bit(p)
-ptr_t p;
+GC_API void GC_CALL GC_clear_mark_bit(const void *p)
{
- register struct hblk *h = HBLKPTR(p);
- register hdr * hhdr = HDR(h);
- register int word_no = (word *)p - (word *)h;
-
- clear_mark_bit_from_hdr(hhdr, word_no);
+ struct hblk *h = HBLKPTR(p);
+ hdr * hhdr = HDR(h);
+ word bit_no = MARK_BIT_NO((ptr_t)p - (ptr_t)h, hhdr -> hb_sz);
+
+ if (mark_bit_from_hdr(hhdr, bit_no)) {
+ size_t n_marks;
+ clear_mark_bit_from_hdr(hhdr, bit_no);
+ n_marks = hhdr -> hb_n_marks - 1;
+# ifdef PARALLEL_MARK
+ if (n_marks != 0 || !GC_parallel)
+ hhdr -> hb_n_marks = n_marks;
+ /* Don't decrement to zero. The counts are approximate due to */
+ /* concurrency issues, but we need to ensure that a count of */
+ /* zero implies an empty block. */
+# else
+ hhdr -> hb_n_marks = n_marks;
+# endif
+ }
}
-GC_bool GC_is_marked(p)
-ptr_t p;
+GC_API int GC_CALL GC_is_marked(const void *p)
{
- register struct hblk *h = HBLKPTR(p);
- register hdr * hhdr = HDR(h);
- register int word_no = (word *)p - (word *)h;
-
- return(mark_bit_from_hdr(hhdr, word_no));
-}
+ struct hblk *h = HBLKPTR(p);
+ hdr * hhdr = HDR(h);
+ word bit_no = MARK_BIT_NO((ptr_t)p - (ptr_t)h, hhdr -> hb_sz);
+ return (int)mark_bit_from_hdr(hhdr, bit_no); /* 0 or 1 */
+}
/*
* Clear mark bits in all allocated heap blocks. This invalidates
* the marker invariant, and sets GC_mark_state to reflect this.
* (This implicitly starts marking to reestablish the invariant.)
*/
-void GC_clear_marks()
+GC_INNER void GC_clear_marks(void)
{
GC_apply_to_all_blocks(clear_marks_for_block, (word)0);
GC_objects_are_marked = FALSE;
GC_mark_state = MS_INVALID;
scan_ptr = 0;
-# ifdef GATHERSTATS
- /* Counters reflect currently marked objects: reset here */
- GC_composite_in_use = 0;
- GC_atomic_in_use = 0;
-# endif
-
}
-/* Initiate a garbage collection. Initiates a full collection if the */
-/* mark state is invalid. */
-/*ARGSUSED*/
-void GC_initiate_gc()
+#ifdef CHECKSUMS
+ void GC_check_dirty(void);
+#endif
+
+/* Initiate a garbage collection. Initiates a full collection if the */
+/* mark state is invalid. */
+GC_INNER void GC_initiate_gc(void)
{
- if (GC_dirty_maintained) GC_read_dirty();
+# ifndef GC_DISABLE_INCREMENTAL
+ if (GC_dirty_maintained) GC_read_dirty();
+# endif
# ifdef STUBBORN_ALLOC
- GC_read_changed();
+ GC_read_changed();
# endif
# ifdef CHECKSUMS
- {
- extern void GC_check_dirty();
-
- if (GC_dirty_maintained) GC_check_dirty();
- }
+ if (GC_dirty_maintained) GC_check_dirty();
# endif
GC_n_rescuing_pages = 0;
if (GC_mark_state == MS_NONE) {
GC_mark_state = MS_PUSH_RESCUERS;
} else if (GC_mark_state != MS_INVALID) {
- ABORT("unexpected state");
- } /* else this is really a full collection, and mark */
- /* bits are invalid. */
+ ABORT("Unexpected state");
+ } /* else this is really a full collection, and mark */
+ /* bits are invalid. */
scan_ptr = 0;
}
+#ifdef PARALLEL_MARK
+ STATIC void GC_do_parallel_mark(void); /* initiate parallel marking. */
+#endif /* PARALLEL_MARK */
-static void alloc_mark_stack();
+#ifdef GC_DISABLE_INCREMENTAL
+# define GC_push_next_marked_dirty(h) GC_push_next_marked(h)
+#else
+ STATIC struct hblk * GC_push_next_marked_dirty(struct hblk *h);
+ /* Invoke GC_push_marked on next dirty block above h. */
+ /* Return a pointer just past the end of this block. */
+#endif /* !GC_DISABLE_INCREMENTAL */
+STATIC struct hblk * GC_push_next_marked(struct hblk *h);
+ /* Ditto, but also mark from clean pages. */
+STATIC struct hblk * GC_push_next_marked_uncollectable(struct hblk *h);
+ /* Ditto, but mark only from uncollectable pages. */
+
+static void alloc_mark_stack(size_t);
+
+# if (defined(MSWIN32) || defined(MSWINCE)) && !defined(__GNUC__) \
+ || defined(MSWIN32) && defined(I386) /* for Win98 */ \
+ || defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS)
+ /* Under rare conditions, we may end up marking from nonexistent memory. */
+ /* Hence we need to be prepared to recover by running GC_mark_some */
+ /* with a suitable handler in place. */
+ /* FIXME: Should we really need it for WinCE? If yes then */
+ /* WRAP_MARK_SOME should be also defined for CeGCC which requires */
+ /* CPU/OS-specific code in mark_ex_handler() and GC_mark_some() */
+ /* (for manual stack unwinding and exception handler installation). */
+# define WRAP_MARK_SOME
+# endif
-/* Perform a small amount of marking. */
-/* We try to touch roughly a page of memory. */
-/* Return TRUE if we just finished a mark phase. */
-/* Cold_gc_frame is an address inside a GC frame that */
-/* remains valid until all marking is complete. */
-/* A zero value indicates that it's OK to miss some */
-/* register values. */
-/* We hold the allocation lock. In the case of */
+/* Perform a small amount of marking. */
+/* We try to touch roughly a page of memory. */
+/* Return TRUE if we just finished a mark phase. */
+/* Cold_gc_frame is an address inside a GC frame that */
+/* remains valid until all marking is complete. */
+/* A zero value indicates that it's OK to miss some */
+/* register values. */
+/* We hold the allocation lock. In the case of */
/* incremental collection, the world may not be stopped.*/
-#ifdef MSWIN32
- /* For win32, this is called after we establish a structured */
- /* exception handler, in case Windows unmaps one of our root */
- /* segments. See below. In either case, we acquire the */
- /* allocator lock long before we get here. */
- GC_bool GC_mark_some_inner(cold_gc_frame)
- ptr_t cold_gc_frame;
+#ifdef WRAP_MARK_SOME
+ /* For win32, this is called after we establish a structured */
+ /* exception handler, in case Windows unmaps one of our root */
+ /* segments. See below. In either case, we acquire the */
+ /* allocator lock long before we get here. */
+ STATIC GC_bool GC_mark_some_inner(ptr_t cold_gc_frame)
#else
- GC_bool GC_mark_some(cold_gc_frame)
- ptr_t cold_gc_frame;
+ GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame)
#endif
{
switch(GC_mark_state) {
- case MS_NONE:
- return(FALSE);
-
- case MS_PUSH_RESCUERS:
- if (GC_mark_stack_top
- >= GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/2) {
- /* Go ahead and mark, even though that might cause us to */
- /* see more marked dirty objects later on. Avoid this */
- /* in the future. */
- GC_mark_stack_too_small = TRUE;
- MARK_FROM_MARK_STACK();
- return(FALSE);
- } else {
- scan_ptr = GC_push_next_marked_dirty(scan_ptr);
- if (scan_ptr == 0) {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Marked from %lu dirty pages\n",
- (unsigned long)GC_n_rescuing_pages);
- }
-# endif
- GC_push_roots(FALSE, cold_gc_frame);
- GC_objects_are_marked = TRUE;
- if (GC_mark_state != MS_INVALID) {
- GC_mark_state = MS_ROOTS_PUSHED;
- }
- }
- }
- return(FALSE);
-
- case MS_PUSH_UNCOLLECTABLE:
- if (GC_mark_stack_top
- >= GC_mark_stack + GC_mark_stack_size/4) {
-# ifdef PARALLEL_MARK
- /* Avoid this, since we don't parallelize the marker */
- /* here. */
- if (GC_parallel) GC_mark_stack_too_small = TRUE;
-# endif
- MARK_FROM_MARK_STACK();
- return(FALSE);
- } else {
- scan_ptr = GC_push_next_marked_uncollectable(scan_ptr);
- if (scan_ptr == 0) {
- GC_push_roots(TRUE, cold_gc_frame);
- GC_objects_are_marked = TRUE;
- if (GC_mark_state != MS_INVALID) {
- GC_mark_state = MS_ROOTS_PUSHED;
- }
- }
- }
- return(FALSE);
-
- case MS_ROOTS_PUSHED:
-# ifdef PARALLEL_MARK
- /* In the incremental GC case, this currently doesn't */
- /* quite do the right thing, since it runs to */
- /* completion. On the other hand, starting a */
- /* parallel marker is expensive, so perhaps it is */
- /* the right thing? */
- /* Eventually, incremental marking should run */
- /* asynchronously in multiple threads, without grabbing */
- /* the allocation lock. */
- if (GC_parallel) {
- GC_do_parallel_mark();
- GC_ASSERT(GC_mark_stack_top < GC_first_nonempty);
- GC_mark_stack_top = GC_mark_stack - 1;
- if (GC_mark_stack_too_small) {
- alloc_mark_stack(2*GC_mark_stack_size);
- }
- if (GC_mark_state == MS_ROOTS_PUSHED) {
- GC_mark_state = MS_NONE;
- return(TRUE);
- } else {
- return(FALSE);
- }
- }
-# endif
- if (GC_mark_stack_top >= GC_mark_stack) {
- MARK_FROM_MARK_STACK();
- return(FALSE);
- } else {
- GC_mark_state = MS_NONE;
- if (GC_mark_stack_too_small) {
- alloc_mark_stack(2*GC_mark_stack_size);
- }
- return(TRUE);
- }
-
- case MS_INVALID:
- case MS_PARTIALLY_INVALID:
- if (!GC_objects_are_marked) {
- GC_mark_state = MS_PUSH_UNCOLLECTABLE;
- return(FALSE);
- }
- if (GC_mark_stack_top >= GC_mark_stack) {
- MARK_FROM_MARK_STACK();
- return(FALSE);
- }
- if (scan_ptr == 0 && GC_mark_state == MS_INVALID) {
- /* About to start a heap scan for marked objects. */
- /* Mark stack is empty. OK to reallocate. */
- if (GC_mark_stack_too_small) {
- alloc_mark_stack(2*GC_mark_stack_size);
- }
- GC_mark_state = MS_PARTIALLY_INVALID;
- }
- scan_ptr = GC_push_next_marked(scan_ptr);
- if (scan_ptr == 0 && GC_mark_state == MS_PARTIALLY_INVALID) {
- GC_push_roots(TRUE, cold_gc_frame);
- GC_objects_are_marked = TRUE;
- if (GC_mark_state != MS_INVALID) {
- GC_mark_state = MS_ROOTS_PUSHED;
- }
- }
- return(FALSE);
- default:
- ABORT("GC_mark_some: bad state");
- return(FALSE);
+ case MS_NONE:
+ break;
+
+ case MS_PUSH_RESCUERS:
+ if ((word)GC_mark_stack_top
+ >= (word)(GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/2)) {
+ /* Go ahead and mark, even though that might cause us to */
+ /* see more marked dirty objects later on. Avoid this */
+ /* in the future. */
+ GC_mark_stack_too_small = TRUE;
+ MARK_FROM_MARK_STACK();
+ break;
+ } else {
+ scan_ptr = GC_push_next_marked_dirty(scan_ptr);
+ if (scan_ptr == 0) {
+ GC_COND_LOG_PRINTF("Marked from %lu dirty pages\n",
+ (unsigned long)GC_n_rescuing_pages);
+ GC_push_roots(FALSE, cold_gc_frame);
+ GC_objects_are_marked = TRUE;
+ if (GC_mark_state != MS_INVALID) {
+ GC_mark_state = MS_ROOTS_PUSHED;
+ }
+ }
+ }
+ break;
+
+ case MS_PUSH_UNCOLLECTABLE:
+ if ((word)GC_mark_stack_top
+ >= (word)(GC_mark_stack + GC_mark_stack_size/4)) {
+# ifdef PARALLEL_MARK
+ /* Avoid this, since we don't parallelize the marker */
+ /* here. */
+ if (GC_parallel) GC_mark_stack_too_small = TRUE;
+# endif
+ MARK_FROM_MARK_STACK();
+ break;
+ } else {
+ scan_ptr = GC_push_next_marked_uncollectable(scan_ptr);
+ if (scan_ptr == 0) {
+ GC_push_roots(TRUE, cold_gc_frame);
+ GC_objects_are_marked = TRUE;
+ if (GC_mark_state != MS_INVALID) {
+ GC_mark_state = MS_ROOTS_PUSHED;
+ }
+ }
+ }
+ break;
+
+ case MS_ROOTS_PUSHED:
+# ifdef PARALLEL_MARK
+ /* In the incremental GC case, this currently doesn't */
+ /* quite do the right thing, since it runs to */
+ /* completion. On the other hand, starting a */
+ /* parallel marker is expensive, so perhaps it is */
+ /* the right thing? */
+ /* Eventually, incremental marking should run */
+ /* asynchronously in multiple threads, without grabbing */
+ /* the allocation lock. */
+ if (GC_parallel) {
+ GC_do_parallel_mark();
+ GC_ASSERT((word)GC_mark_stack_top < (word)GC_first_nonempty);
+ GC_mark_stack_top = GC_mark_stack - 1;
+ if (GC_mark_stack_too_small) {
+ alloc_mark_stack(2*GC_mark_stack_size);
+ }
+ if (GC_mark_state == MS_ROOTS_PUSHED) {
+ GC_mark_state = MS_NONE;
+ return(TRUE);
+ }
+ break;
+ }
+# endif
+ if ((word)GC_mark_stack_top >= (word)GC_mark_stack) {
+ MARK_FROM_MARK_STACK();
+ break;
+ } else {
+ GC_mark_state = MS_NONE;
+ if (GC_mark_stack_too_small) {
+ alloc_mark_stack(2*GC_mark_stack_size);
+ }
+ return(TRUE);
+ }
+
+ case MS_INVALID:
+ case MS_PARTIALLY_INVALID:
+ if (!GC_objects_are_marked) {
+ GC_mark_state = MS_PUSH_UNCOLLECTABLE;
+ break;
+ }
+ if ((word)GC_mark_stack_top >= (word)GC_mark_stack) {
+ MARK_FROM_MARK_STACK();
+ break;
+ }
+ if (scan_ptr == 0 && GC_mark_state == MS_INVALID) {
+ /* About to start a heap scan for marked objects. */
+ /* Mark stack is empty. OK to reallocate. */
+ if (GC_mark_stack_too_small) {
+ alloc_mark_stack(2*GC_mark_stack_size);
+ }
+ GC_mark_state = MS_PARTIALLY_INVALID;
+ }
+ scan_ptr = GC_push_next_marked(scan_ptr);
+ if (scan_ptr == 0 && GC_mark_state == MS_PARTIALLY_INVALID) {
+ GC_push_roots(TRUE, cold_gc_frame);
+ GC_objects_are_marked = TRUE;
+ if (GC_mark_state != MS_INVALID) {
+ GC_mark_state = MS_ROOTS_PUSHED;
+ }
+ }
+ break;
+
+ default:
+ ABORT("GC_mark_some: bad state");
}
+ return(FALSE);
}
+#ifdef WRAP_MARK_SOME
-#ifdef MSWIN32
-
-# ifdef __GNUC__
+# if (defined(MSWIN32) || defined(MSWINCE)) && defined(__GNUC__)
typedef struct {
EXCEPTION_REGISTRATION ex_reg;
void *alt_path;
} ext_ex_regn;
-
static EXCEPTION_DISPOSITION mark_ex_handler(
- struct _EXCEPTION_RECORD *ex_rec,
+ struct _EXCEPTION_RECORD *ex_rec,
void *est_frame,
struct _CONTEXT *context,
- void *disp_ctxt)
+ void *disp_ctxt GC_ATTR_UNUSED)
{
if (ex_rec->ExceptionCode == STATUS_ACCESS_VIOLATION) {
ext_ex_regn *xer = (ext_ex_regn *)est_frame;
@@ -439,15 +474,20 @@ static void alloc_mark_stack();
return ExceptionContinueSearch;
}
}
-# endif /* __GNUC__ */
+# endif /* __GNUC__ && MSWIN32 */
+#if defined(GC_WIN32_THREADS) && !defined(__GNUC__)
+ GC_bool GC_started_thread_while_stopped(void);
+ /* In win32_threads.c. Did we invalidate mark phase with an */
+ /* unexpected thread start? */
+#endif
- GC_bool GC_mark_some(cold_gc_frame)
- ptr_t cold_gc_frame;
+ GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame)
{
GC_bool ret_val;
-# ifndef __GNUC__
+# if defined(MSWIN32) || defined(MSWINCE)
+# ifndef __GNUC__
/* Windows 98 appears to asynchronously create and remove */
/* writable memory mappings, for reasons we haven't yet */
/* understood. Since we look for writable regions to */
@@ -455,12 +495,33 @@ static void alloc_mark_stack();
/* address range that disappeared since we started the */
/* collection. Thus we have to recover from faults here. */
/* This code does not appear to be necessary for Windows */
- /* 95/NT/2000. Note that this code should never generate */
+ /* 95/NT/2000+. Note that this code should never generate */
/* an incremental GC write fault. */
+ /* This code seems to be necessary for WinCE (at least in */
+ /* the case we'd decide to add MEM_PRIVATE sections to */
+ /* data roots in GC_register_dynamic_libraries()). */
+ /* It's conceivable that this is the same issue with */
+ /* terminating threads that we see with Linux and */
+ /* USE_PROC_FOR_LIBRARIES. */
__try {
+ ret_val = GC_mark_some_inner(cold_gc_frame);
+ } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+ goto handle_ex;
+ }
+# ifdef GC_WIN32_THREADS
+ /* With DllMain-based thread tracking, a thread may have */
+ /* started while we were marking. This is logically equivalent */
+ /* to the exception case; our results are invalid and we have */
+ /* to start over. This cannot be prevented since we can't */
+ /* block in DllMain. */
+ if (GC_started_thread_while_stopped()) goto handle_ex;
+# endif
+ rm_handler:
+ return ret_val;
-# else /* __GNUC__ */
+# else /* __GNUC__ */
/* Manually install an exception handler since GCC does */
/* not yet support Structured Exception Handling (SEH) on */
@@ -470,134 +531,71 @@ static void alloc_mark_stack();
er.alt_path = &&handle_ex;
er.ex_reg.handler = mark_ex_handler;
- asm volatile ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));
- asm volatile ("movl %0, %%fs:0" : : "r" (&er));
-
-# endif /* __GNUC__ */
-
- ret_val = GC_mark_some_inner(cold_gc_frame);
-
-# ifndef __GNUC__
-
- } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
- EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
-
-# else /* __GNUC__ */
-
- /* Prevent GCC from considering the following code unreachable */
- /* and thus eliminating it. */
- if (er.alt_path != 0)
- goto rm_handler;
-
-handle_ex:
- /* Execution resumes from here on an access violation. */
-
-# endif /* __GNUC__ */
-
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0("Caught ACCESS_VIOLATION in marker. "
- "Memory mapping disappeared.\n");
- }
-# endif /* CONDPRINT */
-
- /* We have bad roots on the stack. Discard mark stack. */
- /* Rescan from marked objects. Redetermine roots. */
- GC_invalidate_mark_state();
- scan_ptr = 0;
-
- ret_val = FALSE;
-
-# ifndef __GNUC__
-
- }
-
-# else /* __GNUC__ */
-
-rm_handler:
+ __asm__ __volatile__ ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));
+ __asm__ __volatile__ ("movl %0, %%fs:0" : : "r" (&er));
+ ret_val = GC_mark_some_inner(cold_gc_frame);
+ /* Prevent GCC from considering the following code unreachable */
+ /* and thus eliminating it. */
+ if (er.alt_path == 0)
+ goto handle_ex;
+ rm_handler:
/* Uninstall the exception handler */
- asm volatile ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
-
-# endif /* __GNUC__ */
+ __asm__ __volatile__ ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
+ return ret_val;
+# endif /* __GNUC__ */
+# else /* !MSWIN32 */
+ /* Here we are handling the case in which /proc is used for root */
+ /* finding, and we have threads. We may find a stack for a */
+ /* thread that is in the process of exiting, and disappears */
+ /* while we are marking it. This seems extremely difficult to */
+ /* avoid otherwise. */
+ if (GC_incremental) {
+ WARN("Incremental GC incompatible with /proc roots\n", 0);
+ /* I'm not sure if this could still work ... */
+ }
+ GC_setup_temporary_fault_handler();
+ if(SETJMP(GC_jmp_buf) != 0) goto handle_ex;
+ ret_val = GC_mark_some_inner(cold_gc_frame);
+ rm_handler:
+ GC_reset_fault_handler();
return ret_val;
- }
-#endif /* MSWIN32 */
+# endif /* !MSWIN32 */
-GC_bool GC_mark_stack_empty()
-{
- return(GC_mark_stack_top < GC_mark_stack);
-}
+handle_ex:
+ /* Exception handler starts here for all cases. */
+ GC_COND_LOG_PRINTF(
+ "Caught ACCESS_VIOLATION in marker; memory mapping disappeared\n");
-#ifdef PROF_MARKER
- word GC_prof_array[10];
-# define PROF(n) GC_prof_array[n]++
-#else
-# define PROF(n)
-#endif
+ /* We have bad roots on the stack. Discard mark stack. */
+ /* Rescan from marked objects. Redetermine roots. */
+ GC_invalidate_mark_state();
+ scan_ptr = 0;
-/* Given a pointer to someplace other than a small object page or the */
-/* first page of a large object, either: */
-/* - return a pointer to somewhere in the first page of the large */
-/* object, if current points to a large object. */
-/* In this case *hhdr is replaced with a pointer to the header */
-/* for the large object. */
-/* - just return current if it does not point to a large object. */
-/*ARGSUSED*/
-ptr_t GC_find_start(current, hhdr, new_hdr_p)
-register ptr_t current;
-register hdr *hhdr, **new_hdr_p;
-{
- if (GC_all_interior_pointers) {
- if (hhdr != 0) {
- register ptr_t orig = current;
-
- current = (ptr_t)HBLKPTR(current);
- do {
- current = current - HBLKSIZE*(word)hhdr;
- hhdr = HDR(current);
- } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
- /* current points to near the start of the large object */
- if (hhdr -> hb_flags & IGNORE_OFF_PAGE) return(orig);
- if ((word *)orig - (word *)current
- >= (ptrdiff_t)(hhdr->hb_sz)) {
- /* Pointer past the end of the block */
- return(orig);
- }
- *new_hdr_p = hhdr;
- return(current);
- } else {
- return(current);
- }
- } else {
- return(current);
- }
-}
+ ret_val = FALSE;
+ goto rm_handler; /* Back to platform-specific code. */
+ }
+#endif /* WRAP_MARK_SOME */
-void GC_invalidate_mark_state()
+GC_INNER void GC_invalidate_mark_state(void)
{
GC_mark_state = MS_INVALID;
GC_mark_stack_top = GC_mark_stack-1;
}
-mse * GC_signal_mark_stack_overflow(msp)
-mse * msp;
+GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp)
{
GC_mark_state = MS_INVALID;
GC_mark_stack_too_small = TRUE;
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Mark stack overflow; current size = %lu entries\n",
- GC_mark_stack_size);
- }
-# endif
+ GC_COND_LOG_PRINTF("Mark stack overflow; current size = %lu entries\n",
+ (unsigned long)GC_mark_stack_size);
return(msp - GC_MARK_STACK_DISCARDS);
}
/*
* Mark objects pointed to by the regions described by
- * mark stack entries between GC_mark_stack and GC_mark_stack_top,
+ * mark stack entries between mark_stack and mark_stack_top,
* inclusive. Assumes the upper limit of a mark stack entry
* is never 0. A mark stack entry never has size 0.
* We try to traverse on the order of a hblk of memory before we return.
@@ -607,200 +605,263 @@ mse * msp;
* things up. In particular, we avoid procedure calls on the common
* path, we take advantage of peculiarities of the mark descriptor
* encoding, we optionally maintain a cache for the block address to
- * header mapping, we prefetch when an object is "grayed", etc.
+ * header mapping, we prefetch when an object is "grayed", etc.
*/
-mse * GC_mark_from(mark_stack_top, mark_stack, mark_stack_limit)
-mse * mark_stack_top;
-mse * mark_stack;
-mse * mark_stack_limit;
+GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
+ mse *mark_stack_limit)
{
- int credit = HBLKSIZE; /* Remaining credit for marking work */
- register word * current_p; /* Pointer to current candidate ptr. */
- register word current; /* Candidate pointer. */
- register word * limit; /* (Incl) limit of current candidate */
- /* range */
- register word descr;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
+ signed_word credit = HBLKSIZE; /* Remaining credit for marking work */
+ ptr_t current_p; /* Pointer to current candidate ptr. */
+ word current; /* Candidate pointer. */
+ ptr_t limit; /* (Incl) limit of current candidate */
+ /* range */
+ word descr;
+ ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+ ptr_t least_ha = GC_least_plausible_heap_addr;
DECLARE_HDR_CACHE;
-# define SPLIT_RANGE_WORDS 128 /* Must be power of 2. */
+# define SPLIT_RANGE_WORDS 128 /* Must be power of 2. */
GC_objects_are_marked = TRUE;
INIT_HDR_CACHE;
# ifdef OS2 /* Use untweaked version to circumvent compiler problem */
- while (mark_stack_top >= mark_stack && credit >= 0) {
+ while ((word)mark_stack_top >= (word)mark_stack && credit >= 0)
# else
- while ((((ptr_t)mark_stack_top - (ptr_t)mark_stack) | credit)
- >= 0) {
+ while ((((ptr_t)mark_stack_top - (ptr_t)mark_stack) | credit) >= 0)
# endif
+ {
current_p = mark_stack_top -> mse_start;
- descr = mark_stack_top -> mse_descr;
+ descr = mark_stack_top -> mse_descr.w;
retry:
- /* current_p and descr describe the current object. */
- /* *mark_stack_top is vacant. */
- /* The following is 0 only for small objects described by a simple */
- /* length descriptor. For many applications this is the common */
- /* case, so we try to detect it quickly. */
+ /* current_p and descr describe the current object. */
+ /* *mark_stack_top is vacant. */
+ /* The following is 0 only for small objects described by a simple */
+ /* length descriptor. For many applications this is the common */
+ /* case, so we try to detect it quickly. */
if (descr & ((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS) - 1)) | GC_DS_TAGS)) {
word tag = descr & GC_DS_TAGS;
-
+
switch(tag) {
case GC_DS_LENGTH:
- /* Large length. */
- /* Process part of the range to avoid pushing too much on the */
- /* stack. */
- GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
- - (word)GC_least_plausible_heap_addr);
-# ifdef PARALLEL_MARK
-# define SHARE_BYTES 2048
- if (descr > SHARE_BYTES && GC_parallel
- && mark_stack_top < mark_stack_limit - 1) {
- int new_size = (descr/2) & ~(sizeof(word)-1);
- mark_stack_top -> mse_start = current_p;
- mark_stack_top -> mse_descr = new_size + sizeof(word);
- /* makes sure we handle */
- /* misaligned pointers. */
- mark_stack_top++;
- current_p = (word *) ((char *)current_p + new_size);
- descr -= new_size;
- goto retry;
- }
-# endif /* PARALLEL_MARK */
+ /* Large length. */
+ /* Process part of the range to avoid pushing too much on the */
+ /* stack. */
+ GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
+ - (word)GC_least_plausible_heap_addr);
+# ifdef ENABLE_TRACE
+ if ((word)GC_trace_addr >= (word)current_p
+ && (word)GC_trace_addr < (word)(current_p + descr)) {
+ GC_log_printf("GC:%u Large section; start %p len %lu\n",
+ (unsigned)GC_gc_no, current_p, (unsigned long)descr);
+ }
+# endif /* ENABLE_TRACE */
+# ifdef PARALLEL_MARK
+# define SHARE_BYTES 2048
+ if (descr > SHARE_BYTES && GC_parallel
+ && (word)mark_stack_top < (word)(mark_stack_limit - 1)) {
+ int new_size = (descr/2) & ~(sizeof(word)-1);
+ mark_stack_top -> mse_start = current_p;
+ mark_stack_top -> mse_descr.w = new_size + sizeof(word);
+ /* makes sure we handle */
+ /* misaligned pointers. */
+ mark_stack_top++;
+# ifdef ENABLE_TRACE
+ if ((word)GC_trace_addr >= (word)current_p
+ && (word)GC_trace_addr < (word)(current_p + descr)) {
+ GC_log_printf("GC:%u Splitting (parallel) %p at %p\n",
+ (unsigned)GC_gc_no, current_p, current_p + new_size);
+ }
+# endif /* ENABLE_TRACE */
+ current_p += new_size;
+ descr -= new_size;
+ goto retry;
+ }
+# endif /* PARALLEL_MARK */
mark_stack_top -> mse_start =
- limit = current_p + SPLIT_RANGE_WORDS-1;
- mark_stack_top -> mse_descr =
- descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
- /* Make sure that pointers overlapping the two ranges are */
- /* considered. */
- limit = (word *)((char *)limit + sizeof(word) - ALIGNMENT);
+ limit = current_p + WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
+ mark_stack_top -> mse_descr.w =
+ descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
+# ifdef ENABLE_TRACE
+ if ((word)GC_trace_addr >= (word)current_p
+ && (word)GC_trace_addr < (word)(current_p + descr)) {
+ GC_log_printf("GC:%u Splitting %p at %p\n",
+ (unsigned)GC_gc_no, current_p, limit);
+ }
+# endif /* ENABLE_TRACE */
+ /* Make sure that pointers overlapping the two ranges are */
+ /* considered. */
+ limit += sizeof(word) - ALIGNMENT;
break;
case GC_DS_BITMAP:
mark_stack_top--;
+# ifdef ENABLE_TRACE
+ if ((word)GC_trace_addr >= (word)current_p
+ && (word)GC_trace_addr < (word)(current_p
+ + WORDS_TO_BYTES(WORDSZ-2))) {
+ GC_log_printf("GC:%u Tracing from %p bitmap descr %lu\n",
+ (unsigned)GC_gc_no, current_p, (unsigned long)descr);
+ }
+# endif /* ENABLE_TRACE */
descr &= ~GC_DS_TAGS;
credit -= WORDS_TO_BYTES(WORDSZ/2); /* guess */
while (descr != 0) {
if ((signed_word)descr < 0) {
- current = *current_p;
- FIXUP_POINTER(current);
- if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
- PREFETCH((ptr_t)current);
- HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
- mark_stack_limit, current_p, exit1);
- }
+ current = *(word *)current_p;
+ FIXUP_POINTER(current);
+ if (current >= (word)least_ha && current < (word)greatest_ha) {
+ PREFETCH((ptr_t)current);
+# ifdef ENABLE_TRACE
+ if (GC_trace_addr == current_p) {
+ GC_log_printf("GC:%u Considering(3) %p -> %p\n",
+ (unsigned)GC_gc_no, current_p, (ptr_t)current);
+ }
+# endif /* ENABLE_TRACE */
+ PUSH_CONTENTS((ptr_t)current, mark_stack_top,
+ mark_stack_limit, current_p, exit1);
+ }
}
- descr <<= 1;
- ++ current_p;
+ descr <<= 1;
+ current_p += sizeof(word);
}
continue;
case GC_DS_PROC:
mark_stack_top--;
+# ifdef ENABLE_TRACE
+ if ((word)GC_trace_addr >= (word)current_p
+ && GC_base(current_p) != 0
+ && GC_base(current_p) == GC_base(GC_trace_addr)) {
+ GC_log_printf("GC:%u Tracing from %p proc descr %lu\n",
+ (unsigned)GC_gc_no, current_p, (unsigned long)descr);
+ }
+# endif /* ENABLE_TRACE */
credit -= GC_PROC_BYTES;
mark_stack_top =
(*PROC(descr))
- (current_p, mark_stack_top,
- mark_stack_limit, ENV(descr));
+ ((word *)current_p, mark_stack_top,
+ mark_stack_limit, ENV(descr));
continue;
case GC_DS_PER_OBJECT:
- if ((signed_word)descr >= 0) {
- /* Descriptor is in the object. */
- descr = *(word *)((ptr_t)current_p + descr - GC_DS_PER_OBJECT);
- } else {
- /* Descriptor is in type descriptor pointed to by first */
- /* word in object. */
- ptr_t type_descr = *(ptr_t *)current_p;
- /* type_descr is either a valid pointer to the descriptor */
- /* structure, or this object was on a free list. If it */
- /* it was anything but the last object on the free list, */
- /* we will misinterpret the next object on the free list as */
- /* the type descriptor, and get a 0 GC descriptor, which */
- /* is ideal. Unfortunately, we need to check for the last */
- /* object case explicitly. */
- if (0 == type_descr) {
- /* Rarely executed. */
- mark_stack_top--;
- continue;
- }
+ if ((signed_word)descr >= 0) {
+ /* Descriptor is in the object. */
+ descr = *(word *)(current_p + descr - GC_DS_PER_OBJECT);
+ } else {
+ /* Descriptor is in type descriptor pointed to by first */
+ /* word in object. */
+ ptr_t type_descr = *(ptr_t *)current_p;
+ /* type_descr is either a valid pointer to the descriptor */
+ /* structure, or this object was on a free list. If it */
+ /* it was anything but the last object on the free list, */
+ /* we will misinterpret the next object on the free list as */
+ /* the type descriptor, and get a 0 GC descriptor, which */
+ /* is ideal. Unfortunately, we need to check for the last */
+ /* object case explicitly. */
+ if (0 == type_descr) {
+ /* Rarely executed. */
+ mark_stack_top--;
+ continue;
+ }
descr = *(word *)(type_descr
- - (descr - (GC_DS_PER_OBJECT
- - GC_INDIR_PER_OBJ_BIAS)));
- }
- if (0 == descr) {
- /* Can happen either because we generated a 0 descriptor */
- /* or we saw a pointer to a free object. */
- mark_stack_top--;
- continue;
- }
+ - (descr + (GC_INDIR_PER_OBJ_BIAS
+ - GC_DS_PER_OBJECT)));
+ }
+ if (0 == descr) {
+ /* Can happen either because we generated a 0 descriptor */
+ /* or we saw a pointer to a free object. */
+ mark_stack_top--;
+ continue;
+ }
goto retry;
+ default:
+ limit = 0; /* initialized to prevent warning. */
+ ABORT_RET("GC_mark_from: bad state");
}
} else /* Small object with length descriptor */ {
mark_stack_top--;
- limit = (word *)(((ptr_t)current_p) + (word)descr);
+ limit = current_p + (word)descr;
}
- /* The simple case in which we're scanning a range. */
+# ifdef ENABLE_TRACE
+ if ((word)GC_trace_addr >= (word)current_p
+ && (word)GC_trace_addr < (word)limit) {
+ GC_log_printf("GC:%u Tracing from %p, length is %lu\n",
+ (unsigned)GC_gc_no, current_p, (unsigned long)descr);
+ }
+# endif /* ENABLE_TRACE */
+ /* The simple case in which we're scanning a range. */
GC_ASSERT(!((word)current_p & (ALIGNMENT-1)));
- credit -= (ptr_t)limit - (ptr_t)current_p;
- limit -= 1;
+ credit -= limit - current_p;
+ limit -= sizeof(word);
{
# define PREF_DIST 4
# ifndef SMALL_CONFIG
word deferred;
- /* Try to prefetch the next pointer to be examined asap. */
- /* Empirically, this also seems to help slightly without */
- /* prefetches, at least on linux/X86. Presumably this loop */
- /* ends up with less register pressure, and gcc thus ends up */
- /* generating slightly better code. Overall gcc code quality */
- /* for this loop is still not great. */
- for(;;) {
- PREFETCH((ptr_t)limit - PREF_DIST*CACHE_LINE_SIZE);
- GC_ASSERT(limit >= current_p);
- deferred = *limit;
- FIXUP_POINTER(deferred);
- limit = (word *)((char *)limit - ALIGNMENT);
- if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
- PREFETCH((ptr_t)deferred);
- break;
- }
- if (current_p > limit) goto next_object;
- /* Unroll once, so we don't do too many of the prefetches */
- /* based on limit. */
- deferred = *limit;
- FIXUP_POINTER(deferred);
- limit = (word *)((char *)limit - ALIGNMENT);
- if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
- PREFETCH((ptr_t)deferred);
- break;
- }
- if (current_p > limit) goto next_object;
- }
+ /* Try to prefetch the next pointer to be examined asap. */
+ /* Empirically, this also seems to help slightly without */
+ /* prefetches, at least on linux/X86. Presumably this loop */
+ /* ends up with less register pressure, and gcc thus ends up */
+ /* generating slightly better code. Overall gcc code quality */
+ /* for this loop is still not great. */
+ for(;;) {
+ PREFETCH(limit - PREF_DIST*CACHE_LINE_SIZE);
+ GC_ASSERT((word)limit >= (word)current_p);
+ deferred = *(word *)limit;
+ FIXUP_POINTER(deferred);
+ limit -= ALIGNMENT;
+ if (deferred >= (word)least_ha && deferred < (word)greatest_ha) {
+ PREFETCH((ptr_t)deferred);
+ break;
+ }
+ if ((word)current_p > (word)limit) goto next_object;
+ /* Unroll once, so we don't do too many of the prefetches */
+ /* based on limit. */
+ deferred = *(word *)limit;
+ FIXUP_POINTER(deferred);
+ limit -= ALIGNMENT;
+ if (deferred >= (word)least_ha && deferred < (word)greatest_ha) {
+ PREFETCH((ptr_t)deferred);
+ break;
+ }
+ if ((word)current_p > (word)limit) goto next_object;
+ }
# endif
- while (current_p <= limit) {
- /* Empirically, unrolling this loop doesn't help a lot. */
- /* Since HC_PUSH_CONTENTS expands to a lot of code, */
- /* we don't. */
- current = *current_p;
- FIXUP_POINTER(current);
- PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE);
- if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
- /* Prefetch the contents of the object we just pushed. It's */
- /* likely we will need them soon. */
- PREFETCH((ptr_t)current);
- HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
- mark_stack_limit, current_p, exit2);
+ while ((word)current_p <= (word)limit) {
+ /* Empirically, unrolling this loop doesn't help a lot. */
+ /* Since PUSH_CONTENTS expands to a lot of code, */
+ /* we don't. */
+ current = *(word *)current_p;
+ FIXUP_POINTER(current);
+ PREFETCH(current_p + PREF_DIST*CACHE_LINE_SIZE);
+ if (current >= (word)least_ha && current < (word)greatest_ha) {
+ /* Prefetch the contents of the object we just pushed. It's */
+ /* likely we will need them soon. */
+ PREFETCH((ptr_t)current);
+# ifdef ENABLE_TRACE
+ if (GC_trace_addr == current_p) {
+ GC_log_printf("GC:%u Considering(1) %p -> %p\n",
+ (unsigned)GC_gc_no, current_p, (ptr_t)current);
+ }
+# endif /* ENABLE_TRACE */
+ PUSH_CONTENTS((ptr_t)current, mark_stack_top,
+ mark_stack_limit, current_p, exit2);
}
- current_p = (word *)((char *)current_p + ALIGNMENT);
+ current_p += ALIGNMENT;
}
# ifndef SMALL_CONFIG
- /* We still need to mark the entry we previously prefetched. */
- /* We alrady know that it passes the preliminary pointer */
- /* validity test. */
- HC_PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
- mark_stack_limit, current_p, exit4);
- next_object:;
+ /* We still need to mark the entry we previously prefetched. */
+ /* We already know that it passes the preliminary pointer */
+ /* validity test. */
+# ifdef ENABLE_TRACE
+ if (GC_trace_addr == current_p) {
+ GC_log_printf("GC:%u Considering(2) %p -> %p\n",
+ (unsigned)GC_gc_no, current_p, (ptr_t)deferred);
+ }
+# endif /* ENABLE_TRACE */
+ PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
+ mark_stack_limit, current_p, exit4);
+ next_object:;
# endif
}
}
@@ -809,316 +870,304 @@ mse * mark_stack_limit;
#ifdef PARALLEL_MARK
-/* We assume we have an ANSI C Compiler. */
-GC_bool GC_help_wanted = FALSE;
-unsigned GC_helper_count = 0;
-unsigned GC_active_count = 0;
-mse * VOLATILE GC_first_nonempty;
-word GC_mark_no = 0;
+STATIC GC_bool GC_help_wanted = FALSE; /* Protected by mark lock */
+STATIC unsigned GC_helper_count = 0; /* Number of running helpers. */
+ /* Protected by mark lock */
+STATIC unsigned GC_active_count = 0; /* Number of active helpers. */
+ /* Protected by mark lock */
+ /* May increase and decrease */
+ /* within each mark cycle. But */
+ /* once it returns to 0, it */
+ /* stays zero for the cycle. */
+
+GC_INNER word GC_mark_no = 0;
#define LOCAL_MARK_STACK_SIZE HBLKSIZE
- /* Under normal circumstances, this is big enough to guarantee */
- /* We don't overflow half of it in a single call to */
- /* GC_mark_from. */
-
-
-/* Steal mark stack entries starting at mse low into mark stack local */
-/* until we either steal mse high, or we have max entries. */
-/* Return a pointer to the top of the local mark stack. */
-/* *next is replaced by a pointer to the next unscanned mark stack */
-/* entry. */
-mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
- unsigned max, mse **next)
+ /* Under normal circumstances, this is big enough to guarantee */
+ /* we don't overflow half of it in a single call to */
+ /* GC_mark_from. */
+
+
+/* Steal mark stack entries starting at mse low into mark stack local */
+/* until we either steal mse high, or we have max entries. */
+/* Return a pointer to the top of the local mark stack. */
+/* *next is replaced by a pointer to the next unscanned mark stack */
+/* entry. */
+STATIC mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
+ unsigned max, mse **next)
{
mse *p;
mse *top = local - 1;
unsigned i = 0;
- /* Make sure that prior writes to the mark stack are visible. */
- /* On some architectures, the fact that the reads are */
- /* volatile should suffice. */
-# if !defined(IA64) && !defined(HP_PA) && !defined(I386)
- GC_memory_barrier();
-# endif
- GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size);
- for (p = low; p <= high && i <= max; ++p) {
- word descr = *(volatile word *) &(p -> mse_descr);
- /* In the IA64 memory model, the following volatile store is */
- /* ordered after this read of descr. Thus a thread must read */
- /* the original nonzero value. HP_PA appears to be similar, */
- /* and if I'm reading the P4 spec correctly, X86 is probably */
- /* also OK. In some other cases we need a barrier. */
-# if !defined(IA64) && !defined(HP_PA) && !defined(I386)
- GC_memory_barrier();
-# endif
- if (descr != 0) {
- *(volatile word *) &(p -> mse_descr) = 0;
- /* More than one thread may get this entry, but that's only */
- /* a minor performance problem. */
- ++top;
- top -> mse_descr = descr;
- top -> mse_start = p -> mse_start;
- GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH ||
- top -> mse_descr < GC_greatest_plausible_heap_addr
- - GC_least_plausible_heap_addr);
- /* If this is a big object, count it as */
- /* size/256 + 1 objects. */
- ++i;
- if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) i += (descr >> 8);
- }
+ GC_ASSERT((word)high >= (word)(low - 1)
+ && (word)(high - low + 1) <= GC_mark_stack_size);
+ for (p = low; (word)p <= (word)high && i <= max; ++p) {
+ word descr = (word)AO_load(&p->mse_descr.ao);
+ if (descr != 0) {
+ /* Must be ordered after read of descr: */
+ AO_store_release_write(&p->mse_descr.ao, 0);
+ /* More than one thread may get this entry, but that's only */
+ /* a minor performance problem. */
+ ++top;
+ top -> mse_descr.w = descr;
+ top -> mse_start = p -> mse_start;
+ GC_ASSERT((top->mse_descr.w & GC_DS_TAGS) != GC_DS_LENGTH ||
+ top->mse_descr.w < (word)GC_greatest_plausible_heap_addr
+ - (word)GC_least_plausible_heap_addr);
+ /* If this is a big object, count it as */
+ /* size/256 + 1 objects. */
+ ++i;
+ if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) i += (int)(descr >> 8);
+ }
}
*next = p;
return top;
}
-/* Copy back a local mark stack. */
-/* low and high are inclusive bounds. */
-void GC_return_mark_stack(mse * low, mse * high)
+/* Copy back a local mark stack. */
+/* low and high are inclusive bounds. */
+STATIC void GC_return_mark_stack(mse * low, mse * high)
{
mse * my_top;
mse * my_start;
size_t stack_size;
- if (high < low) return;
+ if ((word)high < (word)low) return;
stack_size = high - low + 1;
GC_acquire_mark_lock();
- my_top = GC_mark_stack_top;
+ my_top = GC_mark_stack_top; /* Concurrent modification impossible. */
my_start = my_top + 1;
- if (my_start - GC_mark_stack + stack_size > GC_mark_stack_size) {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0("No room to copy back mark stack.");
- }
-# endif
+ if ((word)(my_start - GC_mark_stack + stack_size)
+ > (word)GC_mark_stack_size) {
+ GC_COND_LOG_PRINTF("No room to copy back mark stack\n");
GC_mark_state = MS_INVALID;
GC_mark_stack_too_small = TRUE;
- /* We drop the local mark stack. We'll fix things later. */
+ /* We drop the local mark stack. We'll fix things later. */
} else {
BCOPY(low, my_start, stack_size * sizeof(mse));
- GC_ASSERT(GC_mark_stack_top = my_top);
-# if !defined(IA64) && !defined(HP_PA)
- GC_memory_barrier();
-# endif
- /* On IA64, the volatile write acts as a release barrier. */
- GC_mark_stack_top = my_top + stack_size;
+ GC_ASSERT((mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))
+ == my_top);
+ AO_store_release_write((volatile AO_t *)(&GC_mark_stack_top),
+ (AO_t)(my_top + stack_size));
+ /* Ensures visibility of previously written stack contents. */
}
GC_release_mark_lock();
GC_notify_all_marker();
}
-/* Mark from the local mark stack. */
-/* On return, the local mark stack is empty. */
-/* But this may be achieved by copying the */
-/* local mark stack back into the global one. */
-void GC_do_local_mark(mse *local_mark_stack, mse *local_top)
+/* Mark from the local mark stack. */
+/* On return, the local mark stack is empty. */
+/* But this may be achieved by copying the */
+/* local mark stack back into the global one. */
+STATIC void GC_do_local_mark(mse *local_mark_stack, mse *local_top)
{
unsigned n;
# define N_LOCAL_ITERS 1
# ifdef GC_ASSERTIONS
/* Make sure we don't hold mark lock. */
- GC_acquire_mark_lock();
- GC_release_mark_lock();
+ GC_acquire_mark_lock();
+ GC_release_mark_lock();
# endif
for (;;) {
for (n = 0; n < N_LOCAL_ITERS; ++n) {
- local_top = GC_mark_from(local_top, local_mark_stack,
- local_mark_stack + LOCAL_MARK_STACK_SIZE);
- if (local_top < local_mark_stack) return;
- if (local_top - local_mark_stack >= LOCAL_MARK_STACK_SIZE/2) {
- GC_return_mark_stack(local_mark_stack, local_top);
- return;
- }
- }
- if (GC_mark_stack_top < GC_first_nonempty &&
- GC_active_count < GC_helper_count
- && local_top > local_mark_stack + 1) {
- /* Try to share the load, since the main stack is empty, */
- /* and helper threads are waiting for a refill. */
- /* The entries near the bottom of the stack are likely */
- /* to require more work. Thus we return those, eventhough */
- /* it's harder. */
- mse * p;
- mse * new_bottom = local_mark_stack
- + (local_top - local_mark_stack)/2;
- GC_ASSERT(new_bottom > local_mark_stack
- && new_bottom < local_top);
- GC_return_mark_stack(local_mark_stack, new_bottom - 1);
- memmove(local_mark_stack, new_bottom,
- (local_top - new_bottom + 1) * sizeof(mse));
- local_top -= (new_bottom - local_mark_stack);
- }
+ local_top = GC_mark_from(local_top, local_mark_stack,
+ local_mark_stack + LOCAL_MARK_STACK_SIZE);
+ if ((word)local_top < (word)local_mark_stack) return;
+ if ((word)(local_top - local_mark_stack)
+ >= LOCAL_MARK_STACK_SIZE / 2) {
+ GC_return_mark_stack(local_mark_stack, local_top);
+ return;
+ }
+ }
+ if ((word)AO_load((volatile AO_t *)&GC_mark_stack_top)
+ < (word)AO_load(&GC_first_nonempty)
+ && GC_active_count < GC_helper_count
+ && (word)local_top > (word)(local_mark_stack + 1)) {
+ /* Try to share the load, since the main stack is empty, */
+ /* and helper threads are waiting for a refill. */
+ /* The entries near the bottom of the stack are likely */
+ /* to require more work. Thus we return those, eventhough */
+ /* it's harder. */
+ mse * new_bottom = local_mark_stack
+ + (local_top - local_mark_stack)/2;
+ GC_ASSERT((word)new_bottom > (word)local_mark_stack
+ && (word)new_bottom < (word)local_top);
+ GC_return_mark_stack(local_mark_stack, new_bottom - 1);
+ memmove(local_mark_stack, new_bottom,
+ (local_top - new_bottom + 1) * sizeof(mse));
+ local_top -= (new_bottom - local_mark_stack);
+ }
}
}
#define ENTRIES_TO_GET 5
-long GC_markers = 2; /* Normally changed by thread-library- */
- /* -specific code. */
-
-/* Mark using the local mark stack until the global mark stack is empty */
-/* and there are no active workers. Update GC_first_nonempty to reflect */
-/* progress. */
-/* Caller does not hold mark lock. */
-/* Caller has already incremented GC_helper_count. We decrement it, */
-/* and maintain GC_active_count. */
-void GC_mark_local(mse *local_mark_stack, int id)
+/* Mark using the local mark stack until the global mark stack is empty */
+/* and there are no active workers. Update GC_first_nonempty to reflect */
+/* progress. */
+/* Caller does not hold mark lock. */
+/* Caller has already incremented GC_helper_count. We decrement it, */
+/* and maintain GC_active_count. */
+STATIC void GC_mark_local(mse *local_mark_stack, int id)
{
mse * my_first_nonempty;
GC_acquire_mark_lock();
GC_active_count++;
- my_first_nonempty = GC_first_nonempty;
- GC_ASSERT(GC_first_nonempty >= GC_mark_stack &&
- GC_first_nonempty <= GC_mark_stack_top + 1);
-# ifdef PRINTSTATS
- GC_printf1("Starting mark helper %lu\n", (unsigned long)id);
-# endif
+ my_first_nonempty = (mse *)AO_load(&GC_first_nonempty);
+ GC_ASSERT((word)AO_load(&GC_first_nonempty) >= (word)GC_mark_stack &&
+ (word)AO_load(&GC_first_nonempty) <=
+ (word)AO_load((volatile AO_t *)&GC_mark_stack_top) + sizeof(mse));
+ GC_VERBOSE_LOG_PRINTF("Starting mark helper %lu\n", (unsigned long)id);
GC_release_mark_lock();
for (;;) {
- size_t n_on_stack;
- size_t n_to_get;
- mse *next;
- mse * my_top;
- mse * local_top;
- mse * global_first_nonempty = GC_first_nonempty;
-
- GC_ASSERT(my_first_nonempty >= GC_mark_stack &&
- my_first_nonempty <= GC_mark_stack_top + 1);
- GC_ASSERT(global_first_nonempty >= GC_mark_stack &&
- global_first_nonempty <= GC_mark_stack_top + 1);
- if (my_first_nonempty < global_first_nonempty) {
- my_first_nonempty = global_first_nonempty;
- } else if (global_first_nonempty < my_first_nonempty) {
- GC_compare_and_exchange((word *)(&GC_first_nonempty),
- (word) global_first_nonempty,
- (word) my_first_nonempty);
- /* If this fails, we just go ahead, without updating */
- /* GC_first_nonempty. */
- }
- /* Perhaps we should also update GC_first_nonempty, if it */
- /* is less. But that would require using atomic updates. */
- my_top = GC_mark_stack_top;
- n_on_stack = my_top - my_first_nonempty + 1;
+ size_t n_on_stack;
+ unsigned n_to_get;
+ mse * my_top;
+ mse * local_top;
+ mse * global_first_nonempty = (mse *)AO_load(&GC_first_nonempty);
+
+ GC_ASSERT((word)my_first_nonempty >= (word)GC_mark_stack &&
+ (word)my_first_nonempty <=
+ (word)AO_load((volatile AO_t *)&GC_mark_stack_top)
+ + sizeof(mse));
+ GC_ASSERT((word)global_first_nonempty >= (word)GC_mark_stack &&
+ (word)global_first_nonempty <=
+ (word)AO_load((volatile AO_t *)&GC_mark_stack_top)
+ + sizeof(mse));
+ if ((word)my_first_nonempty < (word)global_first_nonempty) {
+ my_first_nonempty = global_first_nonempty;
+ } else if ((word)global_first_nonempty < (word)my_first_nonempty) {
+ AO_compare_and_swap(&GC_first_nonempty,
+ (AO_t) global_first_nonempty,
+ (AO_t) my_first_nonempty);
+ /* If this fails, we just go ahead, without updating */
+ /* GC_first_nonempty. */
+ }
+ /* Perhaps we should also update GC_first_nonempty, if it */
+ /* is less. But that would require using atomic updates. */
+ my_top = (mse *)AO_load_acquire((volatile AO_t *)(&GC_mark_stack_top));
+ n_on_stack = my_top - my_first_nonempty + 1;
if (0 == n_on_stack) {
- GC_acquire_mark_lock();
+ GC_acquire_mark_lock();
my_top = GC_mark_stack_top;
+ /* Asynchronous modification impossible here, */
+ /* since we hold mark lock. */
n_on_stack = my_top - my_first_nonempty + 1;
- if (0 == n_on_stack) {
- GC_active_count--;
- GC_ASSERT(GC_active_count <= GC_helper_count);
- /* Other markers may redeposit objects */
- /* on the stack. */
- if (0 == GC_active_count) GC_notify_all_marker();
- while (GC_active_count > 0
- && GC_first_nonempty > GC_mark_stack_top) {
- /* We will be notified if either GC_active_count */
- /* reaches zero, or if more objects are pushed on */
- /* the global mark stack. */
- GC_wait_marker();
- }
- if (GC_active_count == 0 &&
- GC_first_nonempty > GC_mark_stack_top) {
- GC_bool need_to_notify = FALSE;
- /* The above conditions can't be falsified while we */
- /* hold the mark lock, since neither */
- /* GC_active_count nor GC_mark_stack_top can */
- /* change. GC_first_nonempty can only be */
- /* incremented asynchronously. Thus we know that */
- /* both conditions actually held simultaneously. */
- GC_helper_count--;
- if (0 == GC_helper_count) need_to_notify = TRUE;
-# ifdef PRINTSTATS
- GC_printf1(
- "Finished mark helper %lu\n", (unsigned long)id);
-# endif
- GC_release_mark_lock();
- if (need_to_notify) GC_notify_all_marker();
- return;
- }
- /* else there's something on the stack again, or */
- /* another helper may push something. */
- GC_active_count++;
- GC_ASSERT(GC_active_count > 0);
- GC_release_mark_lock();
- continue;
- } else {
- GC_release_mark_lock();
- }
- }
- n_to_get = ENTRIES_TO_GET;
- if (n_on_stack < 2 * ENTRIES_TO_GET) n_to_get = 1;
- local_top = GC_steal_mark_stack(my_first_nonempty, my_top,
- local_mark_stack, n_to_get,
- &my_first_nonempty);
- GC_ASSERT(my_first_nonempty >= GC_mark_stack &&
- my_first_nonempty <= GC_mark_stack_top + 1);
- GC_do_local_mark(local_mark_stack, local_top);
+ if (0 == n_on_stack) {
+ GC_active_count--;
+ GC_ASSERT(GC_active_count <= GC_helper_count);
+ /* Other markers may redeposit objects */
+ /* on the stack. */
+ if (0 == GC_active_count) GC_notify_all_marker();
+ while (GC_active_count > 0
+ && (word)AO_load(&GC_first_nonempty)
+ > (word)GC_mark_stack_top) {
+ /* We will be notified if either GC_active_count */
+ /* reaches zero, or if more objects are pushed on */
+ /* the global mark stack. */
+ GC_wait_marker();
+ }
+ if (GC_active_count == 0
+ && (word)AO_load(&GC_first_nonempty)
+ > (word)GC_mark_stack_top) {
+ GC_bool need_to_notify = FALSE;
+ /* The above conditions can't be falsified while we */
+ /* hold the mark lock, since neither */
+ /* GC_active_count nor GC_mark_stack_top can */
+ /* change. GC_first_nonempty can only be */
+ /* incremented asynchronously. Thus we know that */
+ /* both conditions actually held simultaneously. */
+ GC_helper_count--;
+ if (0 == GC_helper_count) need_to_notify = TRUE;
+ GC_VERBOSE_LOG_PRINTF("Finished mark helper %lu\n",
+ (unsigned long)id);
+ GC_release_mark_lock();
+ if (need_to_notify) GC_notify_all_marker();
+ return;
+ }
+ /* else there's something on the stack again, or */
+ /* another helper may push something. */
+ GC_active_count++;
+ GC_ASSERT(GC_active_count > 0);
+ GC_release_mark_lock();
+ continue;
+ } else {
+ GC_release_mark_lock();
+ }
+ }
+ n_to_get = ENTRIES_TO_GET;
+ if (n_on_stack < 2 * ENTRIES_TO_GET) n_to_get = 1;
+ local_top = GC_steal_mark_stack(my_first_nonempty, my_top,
+ local_mark_stack, n_to_get,
+ &my_first_nonempty);
+ GC_ASSERT((word)my_first_nonempty >= (word)GC_mark_stack &&
+ (word)my_first_nonempty <=
+ (word)AO_load((volatile AO_t *)&GC_mark_stack_top)
+ + sizeof(mse));
+ GC_do_local_mark(local_mark_stack, local_top);
}
}
-/* Perform Parallel mark. */
-/* We hold the GC lock, not the mark lock. */
-/* Currently runs until the mark stack is */
-/* empty. */
-void GC_do_parallel_mark()
+/* Perform Parallel mark. */
+/* We hold the GC lock, not the mark lock. */
+/* Currently runs until the mark stack is */
+/* empty. */
+STATIC void GC_do_parallel_mark(void)
{
mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
- mse * local_top;
- mse * my_top;
+ /* Note: local_mark_stack is quite big (up to 128 KiB). */
GC_acquire_mark_lock();
GC_ASSERT(I_HOLD_LOCK());
- /* This could be a GC_ASSERT, but it seems safer to keep it on */
- /* all the time, especially since it's cheap. */
+ /* This could be a GC_ASSERT, but it seems safer to keep it on */
+ /* all the time, especially since it's cheap. */
if (GC_help_wanted || GC_active_count != 0 || GC_helper_count != 0)
- ABORT("Tried to start parallel mark in bad state");
-# ifdef PRINTSTATS
- GC_printf1("Starting marking for mark phase number %lu\n",
- (unsigned long)GC_mark_no);
-# endif
- GC_first_nonempty = GC_mark_stack;
+ ABORT("Tried to start parallel mark in bad state");
+ GC_VERBOSE_LOG_PRINTF("Starting marking for mark phase number %lu\n",
+ (unsigned long)GC_mark_no);
+ GC_first_nonempty = (AO_t)GC_mark_stack;
GC_active_count = 0;
GC_helper_count = 1;
GC_help_wanted = TRUE;
GC_release_mark_lock();
GC_notify_all_marker();
- /* Wake up potential helpers. */
+ /* Wake up potential helpers. */
GC_mark_local(local_mark_stack, 0);
GC_acquire_mark_lock();
GC_help_wanted = FALSE;
- /* Done; clean up. */
+ /* Done; clean up. */
while (GC_helper_count > 0) GC_wait_marker();
/* GC_helper_count cannot be incremented while GC_help_wanted == FALSE */
-# ifdef PRINTSTATS
- GC_printf1(
- "Finished marking for mark phase number %lu\n",
- (unsigned long)GC_mark_no);
-# endif
+ GC_VERBOSE_LOG_PRINTF("Finished marking for mark phase number %lu\n",
+ (unsigned long)GC_mark_no);
GC_mark_no++;
GC_release_mark_lock();
GC_notify_all_marker();
}
-/* Try to help out the marker, if it's running. */
-/* We do not hold the GC lock, but the requestor does. */
-void GC_help_marker(word my_mark_no)
+/* Try to help out the marker, if it's running. */
+/* We do not hold the GC lock, but the requestor does. */
+GC_INNER void GC_help_marker(word my_mark_no)
{
- mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
unsigned my_id;
- mse * my_first_nonempty;
+ mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
+ /* Note: local_mark_stack is quite big (up to 128 KiB). */
if (!GC_parallel) return;
+
GC_acquire_mark_lock();
while (GC_mark_no < my_mark_no
- || !GC_help_wanted && GC_mark_no == my_mark_no) {
+ || (!GC_help_wanted && GC_mark_no == my_mark_no)) {
GC_wait_marker();
}
my_id = GC_helper_count;
- if (GC_mark_no != my_mark_no || my_id >= GC_markers) {
- /* Second test is useful only if original threads can also */
- /* act as helpers. Under Linux they can't. */
+ if (GC_mark_no != my_mark_no || my_id > (unsigned)GC_markers_m1) {
+ /* Second test is useful only if original threads can also */
+ /* act as helpers. Under Linux they can't. */
GC_release_mark_lock();
return;
}
@@ -1130,56 +1179,61 @@ void GC_help_marker(word my_mark_no)
#endif /* PARALLEL_MARK */
-/* Allocate or reallocate space for mark stack of size s words */
-/* May silently fail. */
-static void alloc_mark_stack(n)
-word n;
+/* Allocate or reallocate space for mark stack of size n entries. */
+/* May silently fail. */
+static void alloc_mark_stack(size_t n)
{
mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct GC_ms_entry));
-
+# ifdef GWW_VDB
+ /* Don't recycle a stack segment obtained with the wrong flags. */
+ /* Win32 GetWriteWatch requires the right kind of memory. */
+ static GC_bool GC_incremental_at_stack_alloc = FALSE;
+ GC_bool recycle_old = (!GC_incremental || GC_incremental_at_stack_alloc);
+
+ GC_incremental_at_stack_alloc = GC_incremental;
+# else
+# define recycle_old TRUE
+# endif
+
GC_mark_stack_too_small = FALSE;
if (GC_mark_stack_size != 0) {
if (new_stack != 0) {
- word displ = (word)GC_mark_stack & (GC_page_size - 1);
- signed_word size = GC_mark_stack_size * sizeof(struct GC_ms_entry);
-
- /* Recycle old space */
- if (0 != displ) displ = GC_page_size - displ;
- size = (size - displ) & ~(GC_page_size - 1);
- if (size > 0) {
- GC_add_to_heap((struct hblk *)
- ((word)GC_mark_stack + displ), (word)size);
- }
+ if (recycle_old) {
+ /* Recycle old space */
+ size_t page_offset = (word)GC_mark_stack & (GC_page_size - 1);
+ size_t size = GC_mark_stack_size * sizeof(struct GC_ms_entry);
+ size_t displ = 0;
+
+ if (0 != page_offset) displ = GC_page_size - page_offset;
+ size = (size - displ) & ~(GC_page_size - 1);
+ if (size > 0) {
+ GC_add_to_heap((struct hblk *)
+ ((word)GC_mark_stack + displ), (word)size);
+ }
+ }
GC_mark_stack = new_stack;
GC_mark_stack_size = n;
- GC_mark_stack_limit = new_stack + n;
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Grew mark stack to %lu frames\n",
- (unsigned long) GC_mark_stack_size);
- }
-# endif
+ /* FIXME: Do we need some way to reset GC_mark_stack_size? */
+ GC_mark_stack_limit = new_stack + n;
+ GC_COND_LOG_PRINTF("Grew mark stack to %lu frames\n",
+ (unsigned long)GC_mark_stack_size);
} else {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Failed to grow mark stack to %lu frames\n",
- (unsigned long) n);
- }
-# endif
+ GC_COND_LOG_PRINTF("Failed to grow mark stack to %lu frames\n",
+ (unsigned long)n);
}
} else {
if (new_stack == 0) {
- GC_err_printf0("No space for mark stack\n");
+ GC_err_printf("No space for mark stack\n");
EXIT();
}
GC_mark_stack = new_stack;
GC_mark_stack_size = n;
- GC_mark_stack_limit = new_stack + n;
+ GC_mark_stack_limit = new_stack + n;
}
GC_mark_stack_top = GC_mark_stack-1;
}
-void GC_mark_init()
+GC_INNER void GC_mark_init(void)
{
alloc_mark_stack(INITIAL_MARK_STACK_SIZE);
}
@@ -1191,210 +1245,186 @@ void GC_mark_init()
* Should only be used if there is no possibility of mark stack
* overflow.
*/
-void GC_push_all(bottom, top)
-ptr_t bottom;
-ptr_t top;
+GC_API void GC_CALL GC_push_all(char *bottom, char *top)
{
register word length;
-
- bottom = (ptr_t)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
- top = (ptr_t)(((word) top) & ~(ALIGNMENT-1));
- if (top == 0 || bottom == top) return;
+
+ bottom = (char *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
+ top = (char *)(((word) top) & ~(ALIGNMENT-1));
+ if ((word)bottom >= (word)top) return;
+
GC_mark_stack_top++;
- if (GC_mark_stack_top >= GC_mark_stack_limit) {
- ABORT("unexpected mark stack overflow");
+ if ((word)GC_mark_stack_top >= (word)GC_mark_stack_limit) {
+ ABORT("Unexpected mark stack overflow");
}
length = top - bottom;
# if GC_DS_TAGS > ALIGNMENT - 1
- length += GC_DS_TAGS;
- length &= ~GC_DS_TAGS;
+ length += GC_DS_TAGS;
+ length &= ~GC_DS_TAGS;
# endif
- GC_mark_stack_top -> mse_start = (word *)bottom;
- GC_mark_stack_top -> mse_descr = length;
+ GC_mark_stack_top -> mse_start = bottom;
+ GC_mark_stack_top -> mse_descr.w = length;
}
-/*
- * Analogous to the above, but push only those pages h with dirty_fn(h) != 0.
- * We use push_fn to actually push the block.
- * Used both to selectively push dirty pages, or to push a block
- * in piecemeal fashion, to allow for more marking concurrency.
- * Will not overflow mark stack if push_fn pushes a small fixed number
- * of entries. (This is invoked only if push_fn pushes a single entry,
- * or if it marks each object before pushing it, thus ensuring progress
- * in the event of a stack overflow.)
- */
-void GC_push_selected(bottom, top, dirty_fn, push_fn)
-ptr_t bottom;
-ptr_t top;
-int (*dirty_fn) GC_PROTO((struct hblk * h));
-void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top));
-{
- register struct hblk * h;
+#ifndef GC_DISABLE_INCREMENTAL
+
+ /* Analogous to the above, but push only those pages h with */
+ /* dirty_fn(h) != 0. We use GC_push_all to actually push the block. */
+ /* Used both to selectively push dirty pages, or to push a block in */
+ /* piecemeal fashion, to allow for more marking concurrency. */
+ /* Will not overflow mark stack if GC_push_all pushes a small fixed */
+ /* number of entries. (This is invoked only if GC_push_all pushes */
+ /* a single entry, or if it marks each object before pushing it, thus */
+ /* ensuring progress in the event of a stack overflow.) */
+ STATIC void GC_push_selected(ptr_t bottom, ptr_t top,
+ GC_bool (*dirty_fn)(struct hblk *))
+ {
+ struct hblk * h;
- bottom = (ptr_t)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
- top = (ptr_t)(((long) top) & ~(ALIGNMENT-1));
+ bottom = (ptr_t)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
+ top = (ptr_t)(((word) top) & ~(ALIGNMENT-1));
+ if ((word)bottom >= (word)top) return;
- if (top == 0 || bottom == top) return;
h = HBLKPTR(bottom + HBLKSIZE);
- if (top <= (ptr_t) h) {
- if ((*dirty_fn)(h-1)) {
- (*push_fn)(bottom, top);
- }
- return;
+ if ((word)top <= (word)h) {
+ if ((*dirty_fn)(h-1)) {
+ GC_push_all(bottom, top);
+ }
+ return;
}
if ((*dirty_fn)(h-1)) {
- (*push_fn)(bottom, (ptr_t)h);
+ GC_push_all(bottom, (ptr_t)h);
}
- while ((ptr_t)(h+1) <= top) {
- if ((*dirty_fn)(h)) {
- if ((word)(GC_mark_stack_top - GC_mark_stack)
- > 3 * GC_mark_stack_size / 4) {
- /* Danger of mark stack overflow */
- (*push_fn)((ptr_t)h, top);
- return;
- } else {
- (*push_fn)((ptr_t)h, (ptr_t)(h+1));
- }
- }
- h++;
- }
- if ((ptr_t)h != top) {
- if ((*dirty_fn)(h)) {
- (*push_fn)((ptr_t)h, top);
+
+ while ((word)(h+1) <= (word)top) {
+ if ((*dirty_fn)(h)) {
+ if ((word)(GC_mark_stack_top - GC_mark_stack)
+ > 3 * GC_mark_stack_size / 4) {
+ /* Danger of mark stack overflow */
+ GC_push_all((ptr_t)h, top);
+ return;
+ } else {
+ GC_push_all((ptr_t)h, (ptr_t)(h+1));
+ }
}
+ h++;
}
- if (GC_mark_stack_top >= GC_mark_stack_limit) {
- ABORT("unexpected mark stack overflow");
- }
-}
-
-# ifndef SMALL_CONFIG
-
-#ifdef PARALLEL_MARK
- /* Break up root sections into page size chunks to better spread */
- /* out work. */
- GC_bool GC_true_func(struct hblk *h) { return TRUE; }
-# define GC_PUSH_ALL(b,t) GC_push_selected(b,t,GC_true_func,GC_push_all);
-#else
-# define GC_PUSH_ALL(b,t) GC_push_all(b,t);
-#endif
+ if ((ptr_t)h != top && (*dirty_fn)(h)) {
+ GC_push_all((ptr_t)h, top);
+ }
+ if ((word)GC_mark_stack_top >= (word)GC_mark_stack_limit) {
+ ABORT("Unexpected mark stack overflow");
+ }
+ }
-void GC_push_conditional(bottom, top, all)
-ptr_t bottom;
-ptr_t top;
-int all;
-{
- if (all) {
- if (GC_dirty_maintained) {
-# ifdef PROC_VDB
- /* Pages that were never dirtied cannot contain pointers */
- GC_push_selected(bottom, top, GC_page_was_ever_dirty, GC_push_all);
-# else
- GC_push_all(bottom, top);
-# endif
- } else {
- GC_push_all(bottom, top);
- }
+ GC_API void GC_CALL GC_push_conditional(char *bottom, char *top, int all)
+ {
+ if (!all) {
+ GC_push_selected((ptr_t)bottom, (ptr_t)top, GC_page_was_dirty);
} else {
- GC_push_selected(bottom, top, GC_page_was_dirty, GC_push_all);
+# ifdef PROC_VDB
+ if (GC_dirty_maintained) {
+ /* Pages that were never dirtied cannot contain pointers. */
+ GC_push_selected((ptr_t)bottom, (ptr_t)top, GC_page_was_ever_dirty);
+ } else
+# endif
+ /* else */ {
+ GC_push_all(bottom, top);
+ }
}
-}
-#endif
+ }
+#else
+ GC_API void GC_CALL GC_push_conditional(char *bottom, char *top,
+ int all GC_ATTR_UNUSED)
+ {
+ GC_push_all(bottom, top);
+ }
+#endif /* GC_DISABLE_INCREMENTAL */
-# if defined(MSWIN32) || defined(MSWINCE)
- void __cdecl GC_push_one(p)
-# else
- void GC_push_one(p)
-# endif
-word p;
+#if defined(MSWIN32) || defined(MSWINCE)
+ void __cdecl GC_push_one(word p)
+#else
+ void GC_push_one(word p)
+#endif
{
GC_PUSH_ONE_STACK(p, MARKED_FROM_REGISTER);
}
-struct GC_ms_entry *GC_mark_and_push(obj, mark_stack_ptr, mark_stack_limit, src)
-GC_PTR obj;
-struct GC_ms_entry * mark_stack_ptr;
-struct GC_ms_entry * mark_stack_limit;
-GC_PTR *src;
+GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void *obj,
+ mse *mark_stack_ptr,
+ mse *mark_stack_limit,
+ void ** src GC_ATTR_UNUSED)
{
- PREFETCH(obj);
- PUSH_CONTENTS(obj, mark_stack_ptr /* modified */, mark_stack_limit, src,
- was_marked /* internally generated exit label */);
- return mark_stack_ptr;
+ hdr * hhdr;
+
+ PREFETCH(obj);
+ GET_HDR(obj, hhdr);
+ if ((EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)
+ && (!GC_all_interior_pointers
+ || NULL == (hhdr = GC_find_header(GC_base(obj)))))
+ || EXPECT(HBLK_IS_FREE(hhdr), FALSE)) {
+ GC_ADD_TO_BLACK_LIST_NORMAL(obj, (ptr_t)src);
+ return mark_stack_ptr;
+ }
+
+ PUSH_CONTENTS_HDR(obj, mark_stack_ptr /* modified */, mark_stack_limit,
+ (ptr_t)src, was_marked, hhdr, TRUE);
+ was_marked:
+ return mark_stack_ptr;
}
-# ifdef __STDC__
-# define BASE(p) (word)GC_base((void *)(p))
-# else
-# define BASE(p) (word)GC_base((char *)(p))
-# endif
+#if defined(MANUAL_VDB) && defined(THREADS)
+ void GC_dirty(ptr_t p);
+#endif
-/* Mark and push (i.e. gray) a single object p onto the main */
-/* mark stack. Consider p to be valid if it is an interior */
-/* pointer. */
-/* The object p has passed a preliminary pointer validity */
-/* test, but we do not definitely know whether it is valid. */
-/* Mark bits are NOT atomically updated. Thus this must be the */
-/* only thread setting them. */
+/* Mark and push (i.e. gray) a single object p onto the main */
+/* mark stack. Consider p to be valid if it is an interior */
+/* pointer. */
+/* The object p has passed a preliminary pointer validity */
+/* test, but we do not definitely know whether it is valid. */
+/* Mark bits are NOT atomically updated. Thus this must be the */
+/* only thread setting them. */
# if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
- void GC_mark_and_push_stack(p, source)
- ptr_t source;
+ GC_INNER void GC_mark_and_push_stack(ptr_t p, ptr_t source)
# else
- void GC_mark_and_push_stack(p)
-# define source 0
+ GC_INNER void GC_mark_and_push_stack(ptr_t p)
+# define source ((ptr_t)0)
# endif
-register word p;
{
- register word r;
- register hdr * hhdr;
- register int displ;
-
+ hdr * hhdr;
+ ptr_t r = p;
+
+ PREFETCH(p);
GET_HDR(p, hhdr);
- if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+ if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)) {
if (hhdr != 0) {
- r = BASE(p);
- hhdr = HDR(r);
- displ = BYTES_TO_WORDS(HBLKDISPL(r));
- }
- } else {
- register map_entry_type map_entry;
-
- displ = HBLKDISPL(p);
- map_entry = MAP_ENTRY((hhdr -> hb_map), displ);
- if (map_entry >= MAX_OFFSET) {
- if (map_entry == OFFSET_TOO_BIG || !GC_all_interior_pointers) {
- r = BASE(p);
- displ = BYTES_TO_WORDS(HBLKDISPL(r));
- if (r == 0) hhdr = 0;
- } else {
- /* Offset invalid, but map reflects interior pointers */
- hhdr = 0;
- }
- } else {
- displ = BYTES_TO_WORDS(displ);
- displ -= map_entry;
- r = (word)((word *)(HBLKPTR(p)) + displ);
+ r = GC_base(p);
+ hhdr = HDR(r);
+ }
+ if (hhdr == 0) {
+ GC_ADD_TO_BLACK_LIST_STACK(p, source);
+ return;
}
}
- /* If hhdr != 0 then r == GC_base(p), only we did it faster. */
- /* displ is the word index within the block. */
- if (hhdr == 0) {
-# ifdef PRINT_BLACK_LIST
- GC_add_to_black_list_stack(p, source);
-# else
- GC_add_to_black_list_stack(p);
-# endif
-# undef source /* In case we had to define it. */
- } else {
- if (!mark_bit_from_hdr(hhdr, displ)) {
- set_mark_bit_from_hdr(hhdr, displ);
- GC_STORE_BACK_PTR(source, (ptr_t)r);
- PUSH_OBJ((word *)r, hhdr, GC_mark_stack_top,
- GC_mark_stack_limit);
- }
+ if (EXPECT(HBLK_IS_FREE(hhdr), FALSE)) {
+ GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
+ return;
}
+# if defined(MANUAL_VDB) && defined(THREADS)
+ /* Pointer is on the stack. We may have dirtied the object */
+ /* it points to, but not yet have called GC_dirty(); */
+ GC_dirty(p); /* Implicitly affects entire object. */
+# endif
+ PUSH_CONTENTS_HDR(r, GC_mark_stack_top, GC_mark_stack_limit,
+ source, mark_and_push_exit, hhdr, FALSE);
+ mark_and_push_exit: ;
+ /* We silently ignore pointers to near the end of a block, */
+ /* which is very mildly suboptimal. */
+ /* FIXME: We should probably add a header word to address */
+ /* this. */
}
+# undef source
# ifdef TRACE_BUF
@@ -1403,7 +1433,7 @@ register word p;
struct trace_entry {
char * kind;
word gc_no;
- word words_allocd;
+ word bytes_allocd;
word arg1;
word arg2;
} GC_trace_buf[TRACE_ENTRIES];
@@ -1414,7 +1444,7 @@ void GC_add_trace_entry(char *kind, word arg1, word arg2)
{
GC_trace_buf[GC_trace_buf_ptr].kind = kind;
GC_trace_buf[GC_trace_buf_ptr].gc_no = GC_gc_no;
- GC_trace_buf[GC_trace_buf_ptr].words_allocd = GC_words_allocd;
+ GC_trace_buf[GC_trace_buf_ptr].bytes_allocd = GC_bytes_allocd;
GC_trace_buf[GC_trace_buf_ptr].arg1 = arg1 ^ 0x80000000;
GC_trace_buf[GC_trace_buf_ptr].arg2 = arg2 ^ 0x80000000;
GC_trace_buf_ptr++;
@@ -1425,15 +1455,17 @@ void GC_print_trace(word gc_no, GC_bool lock)
{
int i;
struct trace_entry *p;
-
+ DCL_LOCK_STATE;
+
if (lock) LOCK();
for (i = GC_trace_buf_ptr-1; i != GC_trace_buf_ptr; i--) {
- if (i < 0) i = TRACE_ENTRIES-1;
- p = GC_trace_buf + i;
- if (p -> gc_no < gc_no || p -> kind == 0) return;
- printf("Trace:%s (gc:%d,words:%d) 0x%X, 0x%X\n",
- p -> kind, p -> gc_no, p -> words_allocd,
- (p -> arg1) ^ 0x80000000, (p -> arg2) ^ 0x80000000);
+ if (i < 0) i = TRACE_ENTRIES-1;
+ p = GC_trace_buf + i;
+ if (p -> gc_no < gc_no || p -> kind == 0) return;
+ printf("Trace:%s (gc:%u,bytes:%lu) 0x%X, 0x%X\n",
+ p -> kind, (unsigned)p -> gc_no,
+ (unsigned long)p -> bytes_allocd,
+ (p -> arg1) ^ 0x80000000, (p -> arg2) ^ 0x80000000);
}
printf("Trace incomplete\n");
if (lock) UNLOCK();
@@ -1446,12 +1478,10 @@ void GC_print_trace(word gc_no, GC_bool lock)
* and scans the entire region immediately, in case the contents
* change.
*/
-void GC_push_all_eager(bottom, top)
-ptr_t bottom;
-ptr_t top;
+GC_INNER void GC_push_all_eager(ptr_t bottom, ptr_t top)
{
- word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
- word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
+ word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
+ word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
register word *p;
register word q;
register word *lim;
@@ -1461,324 +1491,347 @@ ptr_t top;
# define GC_least_plausible_heap_addr least_ha
if (top == 0) return;
- /* check all pointers in range and push if they appear */
- /* to be valid. */
+ /* check all pointers in range and push if they appear */
+ /* to be valid. */
lim = t - 1 /* longword */;
- for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
- q = *p;
- GC_PUSH_ONE_STACK(q, p);
+ for (p = b; (word)p <= (word)lim;
+ p = (word *)(((ptr_t)p) + ALIGNMENT)) {
+ q = *p;
+ GC_PUSH_ONE_STACK(q, p);
}
# undef GC_greatest_plausible_heap_addr
# undef GC_least_plausible_heap_addr
}
-#ifndef THREADS
-/*
- * A version of GC_push_all that treats all interior pointers as valid
- * and scans part of the area immediately, to make sure that saved
- * register values are not lost.
- * Cold_gc_frame delimits the stack section that must be scanned
- * eagerly. A zero value indicates that no eager scanning is needed.
- */
-void GC_push_all_stack_partially_eager(bottom, top, cold_gc_frame)
-ptr_t bottom;
-ptr_t top;
-ptr_t cold_gc_frame;
+GC_INNER void GC_push_all_stack(ptr_t bottom, ptr_t top)
{
- if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
-# define EAGER_BYTES 1024
- /* Push the hot end of the stack eagerly, so that register values */
- /* saved inside GC frames are marked before they disappear. */
- /* The rest of the marking can be deferred until later. */
- if (0 == cold_gc_frame) {
- GC_push_all_stack(bottom, top);
- return;
- }
- GC_ASSERT(bottom <= cold_gc_frame && cold_gc_frame <= top);
-# ifdef STACK_GROWS_DOWN
- GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
- GC_push_all_eager(bottom, cold_gc_frame);
-# else /* STACK_GROWS_UP */
- GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t));
- GC_push_all_eager(cold_gc_frame, top);
-# endif /* STACK_GROWS_UP */
- } else {
+# if defined(THREADS) && defined(MPROTECT_VDB)
GC_push_all_eager(bottom, top);
- }
-# ifdef TRACE_BUF
- GC_add_trace_entry("GC_push_all_stack", bottom, top);
+# else
+ if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
+ GC_push_all(bottom, top);
+ } else {
+ GC_push_all_eager(bottom, top);
+ }
# endif
}
-#endif /* !THREADS */
-void GC_push_all_stack(bottom, top)
-ptr_t bottom;
-ptr_t top;
-{
- if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
- GC_push_all(bottom, top);
- } else {
- GC_push_all_eager(bottom, top);
- }
-}
+#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) && \
+ defined(MARK_BIT_PER_GRANULE)
+# if GC_GRANULE_WORDS == 1
+# define USE_PUSH_MARKED_ACCELERATORS
+# define PUSH_GRANULE(q) \
+ { word qcontents = (q)[0]; \
+ GC_PUSH_ONE_HEAP(qcontents, q, GC_mark_stack_top); }
+# elif GC_GRANULE_WORDS == 2
+# define USE_PUSH_MARKED_ACCELERATORS
+# define PUSH_GRANULE(q) \
+ { word qcontents = (q)[0]; \
+ GC_PUSH_ONE_HEAP(qcontents, q, GC_mark_stack_top); \
+ qcontents = (q)[1]; \
+ GC_PUSH_ONE_HEAP(qcontents, (q)+1, GC_mark_stack_top); }
+# elif GC_GRANULE_WORDS == 4
+# define USE_PUSH_MARKED_ACCELERATORS
+# define PUSH_GRANULE(q) \
+ { word qcontents = (q)[0]; \
+ GC_PUSH_ONE_HEAP(qcontents, q, GC_mark_stack_top); \
+ qcontents = (q)[1]; \
+ GC_PUSH_ONE_HEAP(qcontents, (q)+1, GC_mark_stack_top); \
+ qcontents = (q)[2]; \
+ GC_PUSH_ONE_HEAP(qcontents, (q)+2, GC_mark_stack_top); \
+ qcontents = (q)[3]; \
+ GC_PUSH_ONE_HEAP(qcontents, (q)+3, GC_mark_stack_top); }
+# endif
+#endif /* !USE_MARK_BYTES && MARK_BIT_PER_GRANULE */
-#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
+#ifdef USE_PUSH_MARKED_ACCELERATORS
/* Push all objects reachable from marked objects in the given block */
-/* of size 1 objects. */
-void GC_push_marked1(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
+/* containing objects of size 1 granule. */
+STATIC void GC_push_marked1(struct hblk *h, hdr *hhdr)
{
word * mark_word_addr = &(hhdr->hb_marks[0]);
- register word *p;
+ word *p;
word *plim;
- register int i;
- register word q;
- register word mark_word;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
- register mse * mark_stack_top = GC_mark_stack_top;
- register mse * mark_stack_limit = GC_mark_stack_limit;
+ word *q;
+ word mark_word;
+
+ /* Allow registers to be used for some frequently acccessed */
+ /* global variables. Otherwise aliasing issues are likely */
+ /* to prevent that. */
+ ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+ ptr_t least_ha = GC_least_plausible_heap_addr;
+ mse * mark_stack_top = GC_mark_stack_top;
+ mse * mark_stack_limit = GC_mark_stack_limit;
# define GC_mark_stack_top mark_stack_top
# define GC_mark_stack_limit mark_stack_limit
# define GC_greatest_plausible_heap_addr greatest_ha
# define GC_least_plausible_heap_addr least_ha
-
+
p = (word *)(h->hb_body);
plim = (word *)(((word)h) + HBLKSIZE);
/* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- i = 0;
- while(mark_word != 0) {
- if (mark_word & 1) {
- q = p[i];
- GC_PUSH_ONE_HEAP(q, p + i);
- }
- i++;
- mark_word >>= 1;
- }
- p += WORDSZ;
- }
+ while ((word)p < (word)plim) {
+ mark_word = *mark_word_addr++;
+ q = p;
+ while(mark_word != 0) {
+ if (mark_word & 1) {
+ PUSH_GRANULE(q);
+ }
+ q += GC_GRANULE_WORDS;
+ mark_word >>= 1;
+ }
+ p += WORDSZ*GC_GRANULE_WORDS;
+ }
+
# undef GC_greatest_plausible_heap_addr
-# undef GC_least_plausible_heap_addr
+# undef GC_least_plausible_heap_addr
# undef GC_mark_stack_top
# undef GC_mark_stack_limit
+
GC_mark_stack_top = mark_stack_top;
}
-#ifndef UNALIGNED
+#ifndef UNALIGNED_PTRS
/* Push all objects reachable from marked objects in the given block */
-/* of size 2 objects. */
-void GC_push_marked2(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
+/* of size 2 (granules) objects. */
+STATIC void GC_push_marked2(struct hblk *h, hdr *hhdr)
{
word * mark_word_addr = &(hhdr->hb_marks[0]);
- register word *p;
+ word *p;
word *plim;
- register int i;
- register word q;
- register word mark_word;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
- register mse * mark_stack_top = GC_mark_stack_top;
- register mse * mark_stack_limit = GC_mark_stack_limit;
+ word *q;
+ word mark_word;
+
+ ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+ ptr_t least_ha = GC_least_plausible_heap_addr;
+ mse * mark_stack_top = GC_mark_stack_top;
+ mse * mark_stack_limit = GC_mark_stack_limit;
+
# define GC_mark_stack_top mark_stack_top
# define GC_mark_stack_limit mark_stack_limit
# define GC_greatest_plausible_heap_addr greatest_ha
# define GC_least_plausible_heap_addr least_ha
-
+
p = (word *)(h->hb_body);
plim = (word *)(((word)h) + HBLKSIZE);
/* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- i = 0;
- while(mark_word != 0) {
- if (mark_word & 1) {
- q = p[i];
- GC_PUSH_ONE_HEAP(q, p + i);
- q = p[i+1];
- GC_PUSH_ONE_HEAP(q, p + i);
- }
- i += 2;
- mark_word >>= 2;
- }
- p += WORDSZ;
- }
+ while ((word)p < (word)plim) {
+ mark_word = *mark_word_addr++;
+ q = p;
+ while(mark_word != 0) {
+ if (mark_word & 1) {
+ PUSH_GRANULE(q);
+ PUSH_GRANULE(q + GC_GRANULE_WORDS);
+ }
+ q += 2 * GC_GRANULE_WORDS;
+ mark_word >>= 2;
+ }
+ p += WORDSZ*GC_GRANULE_WORDS;
+ }
+
# undef GC_greatest_plausible_heap_addr
-# undef GC_least_plausible_heap_addr
+# undef GC_least_plausible_heap_addr
# undef GC_mark_stack_top
# undef GC_mark_stack_limit
+
GC_mark_stack_top = mark_stack_top;
}
+# if GC_GRANULE_WORDS < 4
/* Push all objects reachable from marked objects in the given block */
-/* of size 4 objects. */
+/* of size 4 (granules) objects. */
/* There is a risk of mark stack overflow here. But we handle that. */
/* And only unmarked objects get pushed, so it's not very likely. */
-void GC_push_marked4(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
+STATIC void GC_push_marked4(struct hblk *h, hdr *hhdr)
{
word * mark_word_addr = &(hhdr->hb_marks[0]);
- register word *p;
+ word *p;
word *plim;
- register int i;
- register word q;
- register word mark_word;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
- register mse * mark_stack_top = GC_mark_stack_top;
- register mse * mark_stack_limit = GC_mark_stack_limit;
+ word *q;
+ word mark_word;
+
+ ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+ ptr_t least_ha = GC_least_plausible_heap_addr;
+ mse * mark_stack_top = GC_mark_stack_top;
+ mse * mark_stack_limit = GC_mark_stack_limit;
# define GC_mark_stack_top mark_stack_top
# define GC_mark_stack_limit mark_stack_limit
# define GC_greatest_plausible_heap_addr greatest_ha
# define GC_least_plausible_heap_addr least_ha
-
+
p = (word *)(h->hb_body);
plim = (word *)(((word)h) + HBLKSIZE);
/* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- i = 0;
- while(mark_word != 0) {
- if (mark_word & 1) {
- q = p[i];
- GC_PUSH_ONE_HEAP(q, p + i);
- q = p[i+1];
- GC_PUSH_ONE_HEAP(q, p + i + 1);
- q = p[i+2];
- GC_PUSH_ONE_HEAP(q, p + i + 2);
- q = p[i+3];
- GC_PUSH_ONE_HEAP(q, p + i + 3);
- }
- i += 4;
- mark_word >>= 4;
- }
- p += WORDSZ;
- }
+ while ((word)p < (word)plim) {
+ mark_word = *mark_word_addr++;
+ q = p;
+ while(mark_word != 0) {
+ if (mark_word & 1) {
+ PUSH_GRANULE(q);
+ PUSH_GRANULE(q + GC_GRANULE_WORDS);
+ PUSH_GRANULE(q + 2*GC_GRANULE_WORDS);
+ PUSH_GRANULE(q + 3*GC_GRANULE_WORDS);
+ }
+ q += 4 * GC_GRANULE_WORDS;
+ mark_word >>= 4;
+ }
+ p += WORDSZ*GC_GRANULE_WORDS;
+ }
# undef GC_greatest_plausible_heap_addr
-# undef GC_least_plausible_heap_addr
+# undef GC_least_plausible_heap_addr
# undef GC_mark_stack_top
# undef GC_mark_stack_limit
GC_mark_stack_top = mark_stack_top;
}
-#endif /* UNALIGNED */
+#endif /* GC_GRANULE_WORDS < 4 */
+
+#endif /* UNALIGNED_PTRS */
-#endif /* SMALL_CONFIG */
+#endif /* USE_PUSH_MARKED_ACCELERATORS */
/* Push all objects reachable from marked objects in the given block */
-void GC_push_marked(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
+STATIC void GC_push_marked(struct hblk *h, hdr *hhdr)
{
- register int sz = hhdr -> hb_sz;
- register int descr = hhdr -> hb_descr;
- register word * p;
- register int word_no;
- register word * lim;
- register mse * GC_mark_stack_top_reg;
- register mse * mark_stack_limit = GC_mark_stack_limit;
-
+ size_t sz = hhdr -> hb_sz;
+ word descr = hhdr -> hb_descr;
+ ptr_t p;
+ word bit_no;
+ ptr_t lim;
+ mse * GC_mark_stack_top_reg;
+ mse * mark_stack_limit = GC_mark_stack_limit;
+
/* Some quick shortcuts: */
- if ((0 | GC_DS_LENGTH) == descr) return;
+ if ((0 | GC_DS_LENGTH) == descr) return;
if (GC_block_empty(hhdr)/* nothing marked */) return;
GC_n_rescuing_pages++;
GC_objects_are_marked = TRUE;
- if (sz > MAXOBJSZ) {
- lim = (word *)h;
+ if (sz > MAXOBJBYTES) {
+ lim = h -> hb_body;
} else {
- lim = (word *)(h + 1) - sz;
+ lim = (h + 1)->hb_body - sz;
}
-
- switch(sz) {
-# if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
+
+ switch(BYTES_TO_GRANULES(sz)) {
+# if defined(USE_PUSH_MARKED_ACCELERATORS)
case 1:
GC_push_marked1(h, hhdr);
break;
+# if !defined(UNALIGNED_PTRS)
+ case 2:
+ GC_push_marked2(h, hhdr);
+ break;
+# if GC_GRANULE_WORDS < 4
+ case 4:
+ GC_push_marked4(h, hhdr);
+ break;
+# endif
+# endif
# endif
-# if !defined(SMALL_CONFIG) && !defined(UNALIGNED) && \
- !defined(USE_MARK_BYTES)
- case 2:
- GC_push_marked2(h, hhdr);
- break;
- case 4:
- GC_push_marked4(h, hhdr);
- break;
-# endif
default:
GC_mark_stack_top_reg = GC_mark_stack_top;
- for (p = (word *)h, word_no = 0; p <= lim; p += sz, word_no += sz) {
- if (mark_bit_from_hdr(hhdr, word_no)) {
+ for (p = h -> hb_body, bit_no = 0; (word)p <= (word)lim;
+ p += sz, bit_no += MARK_BIT_OFFSET(sz)) {
+ if (mark_bit_from_hdr(hhdr, bit_no)) {
/* Mark from fields inside the object */
- PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
-# ifdef GATHERSTATS
- /* Subtract this object from total, since it was */
- /* added in twice. */
- GC_composite_in_use -= sz;
-# endif
+ PUSH_OBJ(p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
}
}
GC_mark_stack_top = GC_mark_stack_top_reg;
}
}
-#ifndef SMALL_CONFIG
-/* Test whether any page in the given block is dirty */
-GC_bool GC_block_was_dirty(h, hhdr)
-struct hblk *h;
-register hdr * hhdr;
-{
- register int sz = hhdr -> hb_sz;
-
- if (sz <= MAXOBJSZ) {
+#ifdef ENABLE_DISCLAIM
+/* Unconditionally mark from all objects which have not been reclaimed. */
+/* This is useful in order to retain pointes which are reachable from */
+/* the disclaim notifiers. */
+/* */
+/* To determine whether an object has been reclaimed, we require that */
+/* any live object has a non-zero as one of the two lowest bits of the */
+/* first word. On the other hand, a reclaimed object is a members of */
+/* free-lists, and thus contains a word-aligned next-pointer as the */
+/* first word. */
+ STATIC void GC_push_unconditionally(struct hblk *h, hdr *hhdr)
+ {
+ size_t sz = hhdr -> hb_sz;
+ word descr = hhdr -> hb_descr;
+ ptr_t p;
+ ptr_t lim;
+ mse * GC_mark_stack_top_reg;
+ mse * mark_stack_limit = GC_mark_stack_limit;
+
+ if ((0 | GC_DS_LENGTH) == descr)
+ return;
+
+ GC_n_rescuing_pages++;
+ GC_objects_are_marked = TRUE;
+ if (sz > MAXOBJBYTES)
+ lim = h -> hb_body;
+ else
+ lim = (h + 1)->hb_body - sz;
+
+ GC_mark_stack_top_reg = GC_mark_stack_top;
+ for (p = h -> hb_body; (word)p <= (word)lim; p += sz)
+ if ((*(GC_word *)p & 0x3) != 0)
+ PUSH_OBJ(p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
+ GC_mark_stack_top = GC_mark_stack_top_reg;
+ }
+#endif /* ENABLE_DISCLAIM */
+
+#ifndef GC_DISABLE_INCREMENTAL
+ /* Test whether any page in the given block is dirty. */
+ STATIC GC_bool GC_block_was_dirty(struct hblk *h, hdr *hhdr)
+ {
+ size_t sz = hhdr -> hb_sz;
+
+ if (sz <= MAXOBJBYTES) {
return(GC_page_was_dirty(h));
} else {
- register ptr_t p = (ptr_t)h;
- sz = WORDS_TO_BYTES(sz);
- while (p < (ptr_t)h + sz) {
+ ptr_t p = (ptr_t)h;
+ while ((word)p < (word)h + sz) {
if (GC_page_was_dirty((struct hblk *)p)) return(TRUE);
p += HBLKSIZE;
}
return(FALSE);
}
-}
-#endif /* SMALL_CONFIG */
+ }
+#endif /* GC_DISABLE_INCREMENTAL */
-/* Similar to GC_push_next_marked, but return address of next block */
-struct hblk * GC_push_next_marked(h)
-struct hblk *h;
+/* Similar to GC_push_marked, but skip over unallocated blocks */
+/* and return address of next plausible block. */
+STATIC struct hblk * GC_push_next_marked(struct hblk *h)
{
- register hdr * hhdr;
-
- h = GC_next_used_block(h);
- if (h == 0) return(0);
- hhdr = HDR(h);
+ hdr * hhdr = HDR(h);
+
+ if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr), FALSE)) {
+ h = GC_next_used_block(h);
+ if (h == 0) return(0);
+ hhdr = GC_find_header((ptr_t)h);
+ }
GC_push_marked(h, hhdr);
return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
}
-#ifndef SMALL_CONFIG
-/* Identical to above, but mark only from dirty pages */
-struct hblk * GC_push_next_marked_dirty(h)
-struct hblk *h;
-{
- register hdr * hhdr;
-
- if (!GC_dirty_maintained) { ABORT("dirty bits not set up"); }
+#ifndef GC_DISABLE_INCREMENTAL
+ /* Identical to above, but mark only from dirty pages */
+ STATIC struct hblk * GC_push_next_marked_dirty(struct hblk *h)
+ {
+ hdr * hhdr = HDR(h);
+
+ if (!GC_dirty_maintained) ABORT("Dirty bits not set up");
for (;;) {
- h = GC_next_used_block(h);
- if (h == 0) return(0);
- hhdr = HDR(h);
-# ifdef STUBBORN_ALLOC
+ if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr)
+ || HBLK_IS_FREE(hhdr), FALSE)) {
+ h = GC_next_used_block(h);
+ if (h == 0) return(0);
+ hhdr = GC_find_header((ptr_t)h);
+ }
+# ifdef STUBBORN_ALLOC
if (hhdr -> hb_obj_kind == STUBBORN) {
if (GC_page_was_changed(h) && GC_block_was_dirty(h, hhdr)) {
break;
@@ -1786,32 +1839,42 @@ struct hblk *h;
} else {
if (GC_block_was_dirty(h, hhdr)) break;
}
-# else
- if (GC_block_was_dirty(h, hhdr)) break;
-# endif
+# else
+ if (GC_block_was_dirty(h, hhdr)) break;
+# endif
h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
+ hhdr = HDR(h);
}
GC_push_marked(h, hhdr);
return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
-}
-#endif
+ }
+#endif /* !GC_DISABLE_INCREMENTAL */
-/* Similar to above, but for uncollectable pages. Needed since we */
-/* do not clear marks for such pages, even for full collections. */
-struct hblk * GC_push_next_marked_uncollectable(h)
-struct hblk *h;
+/* Similar to above, but for uncollectable pages. Needed since we */
+/* do not clear marks for such pages, even for full collections. */
+STATIC struct hblk * GC_push_next_marked_uncollectable(struct hblk *h)
{
- register hdr * hhdr = HDR(h);
-
+ hdr * hhdr = HDR(h);
+
for (;;) {
- h = GC_next_used_block(h);
- if (h == 0) return(0);
- hhdr = HDR(h);
- if (hhdr -> hb_obj_kind == UNCOLLECTABLE) break;
+ if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr)
+ || HBLK_IS_FREE(hhdr), FALSE)) {
+ h = GC_next_used_block(h);
+ if (h == 0) return(0);
+ hhdr = GC_find_header((ptr_t)h);
+ }
+ if (hhdr -> hb_obj_kind == UNCOLLECTABLE) {
+ GC_push_marked(h, hhdr);
+ break;
+ }
+# ifdef ENABLE_DISCLAIM
+ if ((hhdr -> hb_flags & MARK_UNCONDITIONALLY) != 0) {
+ GC_push_unconditionally(h, hhdr);
+ break;
+ }
+# endif
h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
+ hhdr = HDR(h);
}
- GC_push_marked(h, hhdr);
return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
}
-
-
diff --git a/boehm-gc/mark_rts.c b/boehm-gc/mark_rts.c
index 55eb5d54339..7ffe82a6df1 100644
--- a/boehm-gc/mark_rts.c
+++ b/boehm-gc/mark_rts.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
*
@@ -11,190 +11,192 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-# include <stdio.h>
-# include "private/gc_priv.h"
-/* Data structure for list of root sets. */
-/* We keep a hash table, so that we can filter out duplicate additions. */
-/* Under Win32, we need to do a better job of filtering overlaps, so */
-/* we resort to sequential search, and pay the price. */
+#include "private/gc_priv.h"
+
+#include <stdio.h>
+
+/* Data structure for list of root sets. */
+/* We keep a hash table, so that we can filter out duplicate additions. */
+/* Under Win32, we need to do a better job of filtering overlaps, so */
+/* we resort to sequential search, and pay the price. */
/* This is really declared in gc_priv.h:
struct roots {
- ptr_t r_start;
- ptr_t r_end;
- # if !defined(MSWIN32) && !defined(MSWINCE)
- struct roots * r_next;
- # endif
- GC_bool r_tmp;
- -- Delete before registering new dynamic libraries
+ ptr_t r_start;
+ ptr_t r_end;
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ struct roots * r_next;
+# endif
+ GC_bool r_tmp;
+ -- Delete before registering new dynamic libraries
};
struct roots GC_static_roots[MAX_ROOT_SETS];
*/
-int GC_no_dls = 0; /* Register dynamic library data segments. */
+int GC_no_dls = 0; /* Register dynamic library data segments. */
static int n_root_sets = 0;
+ /* GC_static_roots[0..n_root_sets) contains the valid root sets. */
- /* GC_static_roots[0..n_root_sets) contains the valid root sets. */
+#if !defined(NO_DEBUGGING) || defined(GC_ASSERTIONS)
+ /* Should return the same value as GC_root_size. */
+ GC_INNER word GC_compute_root_size(void)
+ {
+ int i;
+ word size = 0;
-# if !defined(NO_DEBUGGING)
-/* For debugging: */
-void GC_print_static_roots()
-{
- register int i;
- size_t total = 0;
-
for (i = 0; i < n_root_sets; i++) {
- GC_printf2("From 0x%lx to 0x%lx ",
- (unsigned long) GC_static_roots[i].r_start,
- (unsigned long) GC_static_roots[i].r_end);
- if (GC_static_roots[i].r_tmp) {
- GC_printf0(" (temporary)\n");
- } else {
- GC_printf0("\n");
- }
- total += GC_static_roots[i].r_end - GC_static_roots[i].r_start;
- }
- GC_printf1("Total size: %ld\n", (unsigned long) total);
- if (GC_root_size != total) {
- GC_printf1("GC_root_size incorrect: %ld!!\n",
- (unsigned long) GC_root_size);
+ size += GC_static_roots[i].r_end - GC_static_roots[i].r_start;
}
-}
-# endif /* NO_DEBUGGING */
+ return size;
+ }
+#endif /* !NO_DEBUGGING || GC_ASSERTIONS */
+
+#if !defined(NO_DEBUGGING)
+ /* For debugging: */
+ void GC_print_static_roots(void)
+ {
+ int i;
+ word size;
-/* Primarily for debugging support: */
-/* Is the address p in one of the registered static */
-/* root sections? */
-GC_bool GC_is_static_root(p)
-ptr_t p;
-{
+ for (i = 0; i < n_root_sets; i++) {
+ GC_printf("From %p to %p%s\n",
+ GC_static_roots[i].r_start, GC_static_roots[i].r_end,
+ GC_static_roots[i].r_tmp ? " (temporary)" : "");
+ }
+ GC_printf("GC_root_size: %lu\n", (unsigned long)GC_root_size);
+
+ if ((size = GC_compute_root_size()) != GC_root_size)
+ GC_err_printf("GC_root_size incorrect!! Should be: %lu\n",
+ (unsigned long)size);
+ }
+#endif /* !NO_DEBUGGING */
+
+#ifndef THREADS
+ /* Primarily for debugging support: */
+ /* Is the address p in one of the registered static root sections? */
+ GC_INNER GC_bool GC_is_static_root(ptr_t p)
+ {
static int last_root_set = MAX_ROOT_SETS;
- register int i;
-
-
+ int i;
+
if (last_root_set < n_root_sets
- && p >= GC_static_roots[last_root_set].r_start
- && p < GC_static_roots[last_root_set].r_end) return(TRUE);
+ && (word)p >= (word)GC_static_roots[last_root_set].r_start
+ && (word)p < (word)GC_static_roots[last_root_set].r_end)
+ return(TRUE);
for (i = 0; i < n_root_sets; i++) {
- if (p >= GC_static_roots[i].r_start
- && p < GC_static_roots[i].r_end) {
- last_root_set = i;
- return(TRUE);
+ if ((word)p >= (word)GC_static_roots[i].r_start
+ && (word)p < (word)GC_static_roots[i].r_end) {
+ last_root_set = i;
+ return(TRUE);
}
}
return(FALSE);
-}
+ }
+#endif /* !THREADS */
-#if !defined(MSWIN32) && !defined(MSWINCE)
-/*
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+/*
# define LOG_RT_SIZE 6
# define RT_SIZE (1 << LOG_RT_SIZE) -- Power of 2, may be != MAX_ROOT_SETS
struct roots * GC_root_index[RT_SIZE];
- -- Hash table header. Used only to check whether a range is
- -- already present.
- -- really defined in gc_priv.h
+ -- Hash table header. Used only to check whether a range is
+ -- already present.
+ -- really defined in gc_priv.h
*/
-static int rt_hash(addr)
-char * addr;
-{
+ GC_INLINE int rt_hash(ptr_t addr)
+ {
word result = (word) addr;
# if CPP_WORDSZ > 8*LOG_RT_SIZE
- result ^= result >> 8*LOG_RT_SIZE;
+ result ^= result >> 8*LOG_RT_SIZE;
# endif
# if CPP_WORDSZ > 4*LOG_RT_SIZE
- result ^= result >> 4*LOG_RT_SIZE;
+ result ^= result >> 4*LOG_RT_SIZE;
# endif
result ^= result >> 2*LOG_RT_SIZE;
result ^= result >> LOG_RT_SIZE;
result &= (RT_SIZE-1);
return(result);
-}
+ }
+
+ /* Is a range starting at b already in the table? If so return a */
+ /* pointer to it, else NULL. */
+ GC_INNER void * GC_roots_present(ptr_t b)
+ {
+ int h = rt_hash(b);
+ struct roots *p = GC_root_index[h];
-/* Is a range starting at b already in the table? If so return a */
-/* pointer to it, else NIL. */
-struct roots * GC_roots_present(b)
-char *b;
-{
- register int h = rt_hash(b);
- register struct roots *p = GC_root_index[h];
-
while (p != 0) {
if (p -> r_start == (ptr_t)b) return(p);
p = p -> r_next;
}
- return(FALSE);
-}
+ return NULL;
+ }
+
+ /* Add the given root structure to the index. */
+ GC_INLINE void add_roots_to_index(struct roots *p)
+ {
+ int h = rt_hash(p -> r_start);
-/* Add the given root structure to the index. */
-static void add_roots_to_index(p)
-struct roots *p;
-{
- register int h = rt_hash(p -> r_start);
-
p -> r_next = GC_root_index[h];
GC_root_index[h] = p;
-}
-
-# else /* MSWIN32 || MSWINCE */
-
-# define add_roots_to_index(p)
-
-# endif
+ }
+#endif /* !MSWIN32 && !MSWINCE && !CYGWIN32 */
+GC_INNER word GC_root_size = 0;
-
-
-word GC_root_size = 0;
-
-void GC_add_roots(b, e)
-char * b; char * e;
+GC_API void GC_CALL GC_add_roots(void *b, void *e)
{
DCL_LOCK_STATE;
-
- DISABLE_SIGNALS();
+
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
LOCK();
- GC_add_roots_inner(b, e, FALSE);
+ GC_add_roots_inner((ptr_t)b, (ptr_t)e, FALSE);
UNLOCK();
- ENABLE_SIGNALS();
}
-/* Add [b,e) to the root set. Adding the same interval a second time */
-/* is a moderately fast noop, and hence benign. We do not handle */
-/* different but overlapping intervals efficiently. (We do handle */
-/* them correctly.) */
-/* Tmp specifies that the interval may be deleted before */
-/* reregistering dynamic libraries. */
-void GC_add_roots_inner(b, e, tmp)
-char * b; char * e;
-GC_bool tmp;
+/* Add [b,e) to the root set. Adding the same interval a second time */
+/* is a moderately fast no-op, and hence benign. We do not handle */
+/* different but overlapping intervals efficiently. (We do handle */
+/* them correctly.) */
+/* Tmp specifies that the interval may be deleted before */
+/* re-registering dynamic libraries. */
+void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp)
{
struct roots * old;
-
-# if defined(MSWIN32) || defined(MSWINCE)
- /* Spend the time to ensure that there are no overlapping */
- /* or adjacent intervals. */
- /* This could be done faster with e.g. a */
- /* balanced tree. But the execution time here is */
- /* virtually guaranteed to be dominated by the time it */
- /* takes to scan the roots. */
+
+ GC_ASSERT((word)b <= (word)e);
+ b = (ptr_t)(((word)b + (sizeof(word) - 1)) & ~(sizeof(word) - 1));
+ /* round b up to word boundary */
+ e = (ptr_t)((word)e & ~(sizeof(word) - 1));
+ /* round e down to word boundary */
+ if ((word)b >= (word)e) return; /* nothing to do */
+
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+ /* Spend the time to ensure that there are no overlapping */
+ /* or adjacent intervals. */
+ /* This could be done faster with e.g. a */
+ /* balanced tree. But the execution time here is */
+ /* virtually guaranteed to be dominated by the time it */
+ /* takes to scan the roots. */
{
register int i;
-
+ old = 0; /* initialized to prevent warning. */
for (i = 0; i < n_root_sets; i++) {
old = GC_static_roots + i;
- if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
- if ((ptr_t)b < old -> r_start) {
- old -> r_start = (ptr_t)b;
- GC_root_size += (old -> r_start - (ptr_t)b);
+ if ((word)b <= (word)old->r_end
+ && (word)e >= (word)old->r_start) {
+ if ((word)b < (word)old->r_start) {
+ GC_root_size += old->r_start - b;
+ old -> r_start = b;
}
- if ((ptr_t)e > old -> r_end) {
- old -> r_end = (ptr_t)e;
- GC_root_size += ((ptr_t)e - old -> r_end);
+ if ((word)e > (word)old->r_end) {
+ GC_root_size += e - old->r_end;
+ old -> r_end = e;
}
old -> r_tmp &= tmp;
break;
@@ -203,81 +205,88 @@ GC_bool tmp;
if (i < n_root_sets) {
/* merge other overlapping intervals */
struct roots *other;
-
+
for (i++; i < n_root_sets; i++) {
other = GC_static_roots + i;
- b = (char *)(other -> r_start);
- e = (char *)(other -> r_end);
- if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
- if ((ptr_t)b < old -> r_start) {
- old -> r_start = (ptr_t)b;
- GC_root_size += (old -> r_start - (ptr_t)b);
+ b = other -> r_start;
+ e = other -> r_end;
+ if ((word)b <= (word)old->r_end
+ && (word)e >= (word)old->r_start) {
+ if ((word)b < (word)old->r_start) {
+ GC_root_size += old->r_start - b;
+ old -> r_start = b;
}
- if ((ptr_t)e > old -> r_end) {
- old -> r_end = (ptr_t)e;
- GC_root_size += ((ptr_t)e - old -> r_end);
+ if ((word)e > (word)old->r_end) {
+ GC_root_size += e - old->r_end;
+ old -> r_end = e;
}
old -> r_tmp &= other -> r_tmp;
/* Delete this entry. */
GC_root_size -= (other -> r_end - other -> r_start);
other -> r_start = GC_static_roots[n_root_sets-1].r_start;
other -> r_end = GC_static_roots[n_root_sets-1].r_end;
- n_root_sets--;
+ n_root_sets--;
}
}
return;
}
}
# else
- old = GC_roots_present(b);
+ old = (struct roots *)GC_roots_present(b);
if (old != 0) {
- if ((ptr_t)e <= old -> r_end) /* already there */ return;
+ if ((word)e <= (word)old->r_end) /* already there */ return;
/* else extend */
- GC_root_size += (ptr_t)e - old -> r_end;
- old -> r_end = (ptr_t)e;
+ GC_root_size += e - old -> r_end;
+ old -> r_end = e;
return;
}
# endif
if (n_root_sets == MAX_ROOT_SETS) {
- ABORT("Too many root sets\n");
+ ABORT("Too many root sets");
}
+
+# ifdef DEBUG_ADD_DEL_ROOTS
+ GC_log_printf("Adding data root section %d: %p .. %p\n",
+ n_root_sets, b, e);
+# endif
GC_static_roots[n_root_sets].r_start = (ptr_t)b;
GC_static_roots[n_root_sets].r_end = (ptr_t)e;
GC_static_roots[n_root_sets].r_tmp = tmp;
-# if !defined(MSWIN32) && !defined(MSWINCE)
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
GC_static_roots[n_root_sets].r_next = 0;
+ add_roots_to_index(GC_static_roots + n_root_sets);
# endif
- add_roots_to_index(GC_static_roots + n_root_sets);
- GC_root_size += (ptr_t)e - (ptr_t)b;
+ GC_root_size += e - b;
n_root_sets++;
}
static GC_bool roots_were_cleared = FALSE;
-void GC_clear_roots GC_PROTO((void))
+GC_API void GC_CALL GC_clear_roots(void)
{
DCL_LOCK_STATE;
-
- DISABLE_SIGNALS();
+
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
LOCK();
roots_were_cleared = TRUE;
n_root_sets = 0;
GC_root_size = 0;
-# if !defined(MSWIN32) && !defined(MSWINCE)
- {
- register int i;
-
- for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
- }
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ BZERO(GC_root_index, RT_SIZE * sizeof(void *));
+# endif
+# ifdef DEBUG_ADD_DEL_ROOTS
+ GC_log_printf("Clear all data root sections\n");
# endif
UNLOCK();
- ENABLE_SIGNALS();
}
-/* Internal use only; lock held. */
-static void GC_remove_root_at_pos(i)
-int i;
+/* Internal use only; lock held. */
+STATIC void GC_remove_root_at_pos(int i)
{
+# ifdef DEBUG_ADD_DEL_ROOTS
+ GC_log_printf("Remove data root section %d: %p .. %p\n",
+ i, GC_static_roots[i].r_start, GC_static_roots[i].r_end);
+# endif
GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
@@ -285,98 +294,104 @@ int i;
n_root_sets--;
}
-#if !defined(MSWIN32) && !defined(MSWINCE)
-static void GC_rebuild_root_index()
-{
- register int i;
-
- for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ STATIC void GC_rebuild_root_index(void)
+ {
+ int i;
+ BZERO(GC_root_index, RT_SIZE * sizeof(void *));
for (i = 0; i < n_root_sets; i++)
- add_roots_to_index(GC_static_roots + i);
-}
+ add_roots_to_index(GC_static_roots + i);
+ }
#endif
-/* Internal use only; lock held. */
-void GC_remove_tmp_roots()
+#if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
+ || defined(PCR) || defined(CYGWIN32)
+/* Internal use only; lock held. */
+STATIC void GC_remove_tmp_roots(void)
{
- register int i;
-
+ int i;
+
for (i = 0; i < n_root_sets; ) {
- if (GC_static_roots[i].r_tmp) {
+ if (GC_static_roots[i].r_tmp) {
GC_remove_root_at_pos(i);
- } else {
- i++;
- }
+ } else {
+ i++;
+ }
}
- #if !defined(MSWIN32) && !defined(MSWINCE)
- GC_rebuild_root_index();
- #endif
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ GC_rebuild_root_index();
+# endif
}
+#endif
-#if !defined(MSWIN32) && !defined(MSWINCE)
-void GC_remove_roots(b, e)
-char * b; char * e;
-{
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ STATIC void GC_remove_roots_inner(ptr_t b, ptr_t e);
+
+ GC_API void GC_CALL GC_remove_roots(void *b, void *e)
+ {
DCL_LOCK_STATE;
-
- DISABLE_SIGNALS();
+
+ /* Quick check whether has nothing to do */
+ if ((((word)b + (sizeof(word) - 1)) & ~(sizeof(word) - 1)) >=
+ ((word)e & ~(sizeof(word) - 1)))
+ return;
+
LOCK();
- GC_remove_roots_inner(b, e);
+ GC_remove_roots_inner((ptr_t)b, (ptr_t)e);
UNLOCK();
- ENABLE_SIGNALS();
-}
+ }
-/* Should only be called when the lock is held */
-void GC_remove_roots_inner(b,e)
-char * b; char * e;
-{
+ /* Should only be called when the lock is held */
+ STATIC void GC_remove_roots_inner(ptr_t b, ptr_t e)
+ {
int i;
for (i = 0; i < n_root_sets; ) {
- if (GC_static_roots[i].r_start >= (ptr_t)b && GC_static_roots[i].r_end <= (ptr_t)e) {
+ if ((word)GC_static_roots[i].r_start >= (word)b
+ && (word)GC_static_roots[i].r_end <= (word)e) {
GC_remove_root_at_pos(i);
- } else {
- i++;
- }
+ } else {
+ i++;
+ }
}
GC_rebuild_root_index();
-}
-#endif /* !defined(MSWIN32) && !defined(MSWINCE) */
-
-#if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
-/* Workaround for the OS mapping and unmapping behind our back: */
-/* Is the address p in one of the temporary static root sections? */
-GC_bool GC_is_tmp_root(p)
-ptr_t p;
-{
+ }
+#endif /* !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) */
+
+#if (defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)) \
+ && !defined(NO_DEBUGGING)
+ /* Not used at present (except for, may be, debugging purpose). */
+ /* Workaround for the OS mapping and unmapping behind our back: */
+ /* Is the address p in one of the temporary static root sections? */
+ GC_bool GC_is_tmp_root(ptr_t p)
+ {
static int last_root_set = MAX_ROOT_SETS;
register int i;
-
+
if (last_root_set < n_root_sets
- && p >= GC_static_roots[last_root_set].r_start
- && p < GC_static_roots[last_root_set].r_end)
- return GC_static_roots[last_root_set].r_tmp;
+ && (word)p >= (word)GC_static_roots[last_root_set].r_start
+ && (word)p < (word)GC_static_roots[last_root_set].r_end)
+ return GC_static_roots[last_root_set].r_tmp;
for (i = 0; i < n_root_sets; i++) {
- if (p >= GC_static_roots[i].r_start
- && p < GC_static_roots[i].r_end) {
+ if ((word)p >= (word)GC_static_roots[i].r_start
+ && (word)p < (word)GC_static_roots[i].r_end) {
last_root_set = i;
return GC_static_roots[i].r_tmp;
}
}
return(FALSE);
-}
-#endif /* MSWIN32 || _WIN32_WCE_EMULATION */
+ }
+#endif /* MSWIN32 || MSWINCE || CYGWIN32 */
-ptr_t GC_approx_sp()
+GC_INNER ptr_t GC_approx_sp(void)
{
- word dummy;
-
-# ifdef _MSC_VER
-# pragma warning(disable:4172)
-# endif
- return((ptr_t)(&dummy));
-# ifdef _MSC_VER
-# pragma warning(default:4172)
-# endif
+ volatile word sp;
+ sp = (word)&sp;
+ /* Also force stack to grow if necessary. Otherwise the */
+ /* later accesses might cause the kernel to think we're */
+ /* doing something wrong. */
+ return((ptr_t)sp);
+ /* GNU C: alternatively, we may return the value of */
+ /*__builtin_frame_address(0). */
}
/*
@@ -389,60 +404,62 @@ struct exclusion {
};
struct exclusion GC_excl_table[MAX_EXCLUSIONS];
- -- Array of exclusions, ascending
- -- address order.
+ -- Array of exclusions, ascending
+ -- address order.
*/
-size_t GC_excl_table_entries = 0; /* Number of entries in use. */
+STATIC size_t GC_excl_table_entries = 0;/* Number of entries in use. */
/* Return the first exclusion range that includes an address >= start_addr */
-/* Assumes the exclusion table contains at least one entry (namely the */
-/* GC data structures). */
-struct exclusion * GC_next_exclusion(start_addr)
-ptr_t start_addr;
+/* Assumes the exclusion table contains at least one entry (namely the */
+/* GC data structures). */
+STATIC struct exclusion * GC_next_exclusion(ptr_t start_addr)
{
size_t low = 0;
size_t high = GC_excl_table_entries - 1;
size_t mid;
while (high > low) {
- mid = (low + high) >> 1;
- /* low <= mid < high */
- if ((word) GC_excl_table[mid].e_end <= (word) start_addr) {
- low = mid + 1;
- } else {
- high = mid;
- }
+ mid = (low + high) >> 1;
+ /* low <= mid < high */
+ if ((word) GC_excl_table[mid].e_end <= (word) start_addr) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
}
if ((word) GC_excl_table[low].e_end <= (word) start_addr) return 0;
return GC_excl_table + low;
}
-void GC_exclude_static_roots(start, finish)
-GC_PTR start;
-GC_PTR finish;
+/* Should only be called when the lock is held. The range boundaries */
+/* should be properly aligned and valid. */
+GC_INNER void GC_exclude_static_roots_inner(void *start, void *finish)
{
struct exclusion * next;
size_t next_index, i;
+ GC_ASSERT((word)start % sizeof(word) == 0);
+ GC_ASSERT((word)start < (word)finish);
+
if (0 == GC_excl_table_entries) {
- next = 0;
+ next = 0;
} else {
- next = GC_next_exclusion(start);
+ next = GC_next_exclusion(start);
}
if (0 != next) {
if ((word)(next -> e_start) < (word) finish) {
- /* incomplete error check. */
- ABORT("exclusion ranges overlap");
- }
+ /* incomplete error check. */
+ ABORT("Exclusion ranges overlap");
+ }
if ((word)(next -> e_start) == (word) finish) {
- /* extend old range backwards */
+ /* extend old range backwards */
next -> e_start = (ptr_t)start;
- return;
+ return;
}
next_index = next - GC_excl_table;
for (i = GC_excl_table_entries; i > next_index; --i) {
- GC_excl_table[i] = GC_excl_table[i-1];
+ GC_excl_table[i] = GC_excl_table[i-1];
}
} else {
next_index = GC_excl_table_entries;
@@ -453,102 +470,264 @@ GC_PTR finish;
++GC_excl_table_entries;
}
+GC_API void GC_CALL GC_exclude_static_roots(void *b, void *e)
+{
+ DCL_LOCK_STATE;
+
+ if (b == e) return; /* nothing to exclude? */
+
+ /* Round boundaries (in direction reverse to that of GC_add_roots). */
+ b = (void *)((word)b & ~(sizeof(word) - 1));
+ e = (void *)(((word)e + (sizeof(word) - 1)) & ~(sizeof(word) - 1));
+ if (0 == e) e = (void *)(word)(~(sizeof(word) - 1)); /* handle overflow */
+
+ LOCK();
+ GC_exclude_static_roots_inner(b, e);
+ UNLOCK();
+}
+
/* Invoke push_conditional on ranges that are not excluded. */
-void GC_push_conditional_with_exclusions(bottom, top, all)
-ptr_t bottom;
-ptr_t top;
-int all;
+STATIC void GC_push_conditional_with_exclusions(ptr_t bottom, ptr_t top,
+ GC_bool all GC_ATTR_UNUSED)
{
struct exclusion * next;
ptr_t excl_start;
- while (bottom < top) {
+ while ((word)bottom < (word)top) {
next = GC_next_exclusion(bottom);
- if (0 == next || (excl_start = next -> e_start) >= top) {
- GC_push_conditional(bottom, top, all);
- return;
- }
- if (excl_start > bottom) GC_push_conditional(bottom, excl_start, all);
- bottom = next -> e_end;
+ if (0 == next || (word)(excl_start = next -> e_start) >= (word)top) {
+ GC_PUSH_CONDITIONAL(bottom, top, all);
+ return;
+ }
+ if ((word)excl_start > (word)bottom)
+ GC_PUSH_CONDITIONAL(bottom, excl_start, all);
+ bottom = next -> e_end;
}
}
+#ifdef IA64
+ /* Similar to GC_push_all_stack_sections() but for IA-64 registers store. */
+ GC_INNER void GC_push_all_register_sections(ptr_t bs_lo, ptr_t bs_hi,
+ int eager, struct GC_traced_stack_sect_s *traced_stack_sect)
+ {
+ while (traced_stack_sect != NULL) {
+ ptr_t frame_bs_lo = traced_stack_sect -> backing_store_end;
+ GC_ASSERT((word)frame_bs_lo <= (word)bs_hi);
+ if (eager) {
+ GC_push_all_eager(frame_bs_lo, bs_hi);
+ } else {
+ GC_push_all_stack(frame_bs_lo, bs_hi);
+ }
+ bs_hi = traced_stack_sect -> saved_backing_store_ptr;
+ traced_stack_sect = traced_stack_sect -> prev;
+ }
+ GC_ASSERT((word)bs_lo <= (word)bs_hi);
+ if (eager) {
+ GC_push_all_eager(bs_lo, bs_hi);
+ } else {
+ GC_push_all_stack(bs_lo, bs_hi);
+ }
+ }
+#endif /* IA64 */
+
+#ifdef THREADS
+
+GC_INNER void GC_push_all_stack_sections(ptr_t lo, ptr_t hi,
+ struct GC_traced_stack_sect_s *traced_stack_sect)
+{
+ while (traced_stack_sect != NULL) {
+ GC_ASSERT((word)lo HOTTER_THAN (word)traced_stack_sect);
+# ifdef STACK_GROWS_UP
+ GC_push_all_stack((ptr_t)traced_stack_sect, lo);
+# else /* STACK_GROWS_DOWN */
+ GC_push_all_stack(lo, (ptr_t)traced_stack_sect);
+# endif
+ lo = traced_stack_sect -> saved_stack_ptr;
+ GC_ASSERT(lo != NULL);
+ traced_stack_sect = traced_stack_sect -> prev;
+ }
+ GC_ASSERT(!((word)hi HOTTER_THAN (word)lo));
+# ifdef STACK_GROWS_UP
+ /* We got them backwards! */
+ GC_push_all_stack(hi, lo);
+# else /* STACK_GROWS_DOWN */
+ GC_push_all_stack(lo, hi);
+# endif
+}
+
+#else /* !THREADS */
+
+# ifdef TRACE_BUF
+ /* Defined in mark.c. */
+ void GC_add_trace_entry(char *kind, word arg1, word arg2);
+# endif
+
+ /* Similar to GC_push_all_eager, but only the */
+ /* part hotter than cold_gc_frame is scanned */
+ /* immediately. Needed to ensure that callee- */
+ /* save registers are not missed. */
+/*
+ * A version of GC_push_all that treats all interior pointers as valid
+ * and scans part of the area immediately, to make sure that saved
+ * register values are not lost.
+ * Cold_gc_frame delimits the stack section that must be scanned
+ * eagerly. A zero value indicates that no eager scanning is needed.
+ * We don't need to worry about the MANUAL_VDB case here, since this
+ * is only called in the single-threaded case. We assume that we
+ * cannot collect between an assignment and the corresponding
+ * GC_dirty() call.
+ */
+STATIC void GC_push_all_stack_partially_eager(ptr_t bottom, ptr_t top,
+ ptr_t cold_gc_frame)
+{
+ if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
+ /* Push the hot end of the stack eagerly, so that register values */
+ /* saved inside GC frames are marked before they disappear. */
+ /* The rest of the marking can be deferred until later. */
+ if (0 == cold_gc_frame) {
+ GC_push_all_stack(bottom, top);
+ return;
+ }
+ GC_ASSERT((word)bottom <= (word)cold_gc_frame
+ && (word)cold_gc_frame <= (word)top);
+# ifdef STACK_GROWS_DOWN
+ GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
+ GC_push_all_eager(bottom, cold_gc_frame);
+# else /* STACK_GROWS_UP */
+ GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t));
+ GC_push_all_eager(cold_gc_frame, top);
+# endif /* STACK_GROWS_UP */
+ } else {
+ GC_push_all_eager(bottom, top);
+ }
+# ifdef TRACE_BUF
+ GC_add_trace_entry("GC_push_all_stack", bottom, top);
+# endif
+}
+
+/* Similar to GC_push_all_stack_sections() but also uses cold_gc_frame. */
+STATIC void GC_push_all_stack_part_eager_sections(ptr_t lo, ptr_t hi,
+ ptr_t cold_gc_frame, struct GC_traced_stack_sect_s *traced_stack_sect)
+{
+ GC_ASSERT(traced_stack_sect == NULL || cold_gc_frame == NULL ||
+ (word)cold_gc_frame HOTTER_THAN (word)traced_stack_sect);
+
+ while (traced_stack_sect != NULL) {
+ GC_ASSERT((word)lo HOTTER_THAN (word)traced_stack_sect);
+# ifdef STACK_GROWS_UP
+ GC_push_all_stack_partially_eager((ptr_t)traced_stack_sect, lo,
+ cold_gc_frame);
+# else /* STACK_GROWS_DOWN */
+ GC_push_all_stack_partially_eager(lo, (ptr_t)traced_stack_sect,
+ cold_gc_frame);
+# endif
+ lo = traced_stack_sect -> saved_stack_ptr;
+ GC_ASSERT(lo != NULL);
+ traced_stack_sect = traced_stack_sect -> prev;
+ cold_gc_frame = NULL; /* Use at most once. */
+ }
+
+ GC_ASSERT(!((word)hi HOTTER_THAN (word)lo));
+# ifdef STACK_GROWS_UP
+ /* We got them backwards! */
+ GC_push_all_stack_partially_eager(hi, lo, cold_gc_frame);
+# else /* STACK_GROWS_DOWN */
+ GC_push_all_stack_partially_eager(lo, hi, cold_gc_frame);
+# endif
+}
+
+#endif /* !THREADS */
+
+ /* Push enough of the current stack eagerly to */
+ /* ensure that callee-save registers saved in */
+ /* GC frames are scanned. */
+ /* In the non-threads case, schedule entire */
+ /* stack for scanning. */
+ /* The second argument is a pointer to the */
+ /* (possibly null) thread context, for */
+ /* (currently hypothetical) more precise */
+ /* stack scanning. */
/*
* In the absence of threads, push the stack contents.
* In the presence of threads, push enough of the current stack
* to ensure that callee-save registers saved in collector frames have been
* seen.
+ * FIXME: Merge with per-thread stuff.
*/
-void GC_push_current_stack(cold_gc_frame)
-ptr_t cold_gc_frame;
+STATIC void GC_push_current_stack(ptr_t cold_gc_frame,
+ void * context GC_ATTR_UNUSED)
{
# if defined(THREADS)
- if (0 == cold_gc_frame) return;
+ if (0 == cold_gc_frame) return;
# ifdef STACK_GROWS_DOWN
- GC_push_all_eager(GC_approx_sp(), cold_gc_frame);
- /* For IA64, the register stack backing store is handled */
- /* in the thread-specific code. */
+ GC_push_all_eager(GC_approx_sp(), cold_gc_frame);
+ /* For IA64, the register stack backing store is handled */
+ /* in the thread-specific code. */
# else
- GC_push_all_eager( cold_gc_frame, GC_approx_sp() );
+ GC_push_all_eager(cold_gc_frame, GC_approx_sp());
# endif
# else
-# ifdef STACK_GROWS_DOWN
- GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom,
- cold_gc_frame );
-# ifdef IA64
- /* We also need to push the register stack backing store. */
- /* This should really be done in the same way as the */
- /* regular stack. For now we fudge it a bit. */
- /* Note that the backing store grows up, so we can't use */
- /* GC_push_all_stack_partially_eager. */
- {
- extern word GC_save_regs_ret_val;
- /* Previously set to backing store pointer. */
- ptr_t bsp = (ptr_t) GC_save_regs_ret_val;
- ptr_t cold_gc_bs_pointer;
- if (GC_all_interior_pointers) {
- cold_gc_bs_pointer = bsp - 2048;
- if (cold_gc_bs_pointer < BACKING_STORE_BASE) {
- cold_gc_bs_pointer = BACKING_STORE_BASE;
- } else {
- GC_push_all_stack(BACKING_STORE_BASE, cold_gc_bs_pointer);
- }
- } else {
- cold_gc_bs_pointer = BACKING_STORE_BASE;
- }
- GC_push_all_eager(cold_gc_bs_pointer, bsp);
- /* All values should be sufficiently aligned that we */
- /* dont have to worry about the boundary. */
- }
-# endif
-# else
- GC_push_all_stack_partially_eager( GC_stackbottom, GC_approx_sp(),
- cold_gc_frame );
+ GC_push_all_stack_part_eager_sections(GC_approx_sp(), GC_stackbottom,
+ cold_gc_frame, GC_traced_stack_sect);
+# ifdef IA64
+ /* We also need to push the register stack backing store. */
+ /* This should really be done in the same way as the */
+ /* regular stack. For now we fudge it a bit. */
+ /* Note that the backing store grows up, so we can't use */
+ /* GC_push_all_stack_partially_eager. */
+ {
+ ptr_t bsp = GC_save_regs_ret_val;
+ ptr_t cold_gc_bs_pointer = bsp - 2048;
+ if (GC_all_interior_pointers
+ && (word)cold_gc_bs_pointer > (word)BACKING_STORE_BASE) {
+ /* Adjust cold_gc_bs_pointer if below our innermost */
+ /* "traced stack section" in backing store. */
+ if (GC_traced_stack_sect != NULL
+ && (word)cold_gc_bs_pointer
+ < (word)GC_traced_stack_sect->backing_store_end)
+ cold_gc_bs_pointer =
+ GC_traced_stack_sect->backing_store_end;
+ GC_push_all_register_sections(BACKING_STORE_BASE,
+ cold_gc_bs_pointer, FALSE, GC_traced_stack_sect);
+ GC_push_all_eager(cold_gc_bs_pointer, bsp);
+ } else {
+ GC_push_all_register_sections(BACKING_STORE_BASE, bsp,
+ TRUE /* eager */, GC_traced_stack_sect);
+ }
+ /* All values should be sufficiently aligned that we */
+ /* don't have to worry about the boundary. */
+ }
# endif
# endif /* !THREADS */
}
+GC_INNER void (*GC_push_typed_structures)(void) = 0;
+
+ /* Push GC internal roots. These are normally */
+ /* included in the static data segment, and */
+ /* Thus implicitly pushed. But we must do this */
+ /* explicitly if normal root processing is */
+ /* disabled. */
/*
* Push GC internal roots. Only called if there is some reason to believe
* these would not otherwise get registered.
*/
-void GC_push_gc_structures GC_PROTO((void))
+STATIC void GC_push_gc_structures(void)
{
- GC_push_finalizer_structures();
- GC_push_stubborn_structures();
+# ifndef GC_NO_FINALIZATION
+ GC_push_finalizer_structures();
+# endif
# if defined(THREADS)
GC_push_thread_structures();
# endif
+ if( GC_push_typed_structures )
+ GC_push_typed_structures();
}
-#ifdef THREAD_LOCAL_ALLOC
- void GC_mark_thread_local_free_lists();
-#endif
-
-void GC_cond_register_dynamic_libraries()
+GC_INNER void GC_cond_register_dynamic_libraries(void)
{
-# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
- || defined(PCR)) && !defined(SRC_M3)
+# if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
+ || defined(CYGWIN32) || defined(PCR)
GC_remove_tmp_roots();
if (!GC_no_dls) GC_register_dynamic_libraries();
# else
@@ -556,31 +735,35 @@ void GC_cond_register_dynamic_libraries()
# endif
}
+STATIC void GC_push_regs_and_stack(ptr_t cold_gc_frame)
+{
+ GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame);
+}
+
/*
- * Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional
- * on groups of pointers) on every top level accessible pointer.
+ * Call the mark routines (GC_tl_push for a single pointer,
+ * GC_push_conditional on groups of pointers) on every top level
+ * accessible pointer.
* If all is FALSE, arrange to push only possibly altered values.
* Cold_gc_frame is an address inside a GC frame that
* remains valid until all marking is complete.
* A zero value indicates that it's OK to miss some
* register values.
*/
-void GC_push_roots(all, cold_gc_frame)
-GC_bool all;
-ptr_t cold_gc_frame;
+GC_INNER void GC_push_roots(GC_bool all, ptr_t cold_gc_frame)
{
int i;
- int kind;
+ unsigned kind;
/*
* Next push static data. This must happen early on, since it's
* not robust against mark stack overflow.
*/
- /* Reregister dynamic libraries, in case one got added. */
- /* There is some argument for doing this as late as possible, */
- /* especially on win32, where it can change asynchronously. */
- /* In those cases, we do it here. But on other platforms, it's */
- /* not safe with the world stopped, so we do it earlier. */
+ /* Re-register dynamic libraries, in case one got added. */
+ /* There is some argument for doing this as late as possible, */
+ /* especially on win32, where it can change asynchronously. */
+ /* In those cases, we do it here. But on other platforms, it's */
+ /* not safe with the world stopped, so we do it earlier. */
# if !defined(REGISTER_LIBRARIES_EARLY)
GC_cond_register_dynamic_libraries();
# endif
@@ -588,34 +771,34 @@ ptr_t cold_gc_frame;
/* Mark everything in static data areas */
for (i = 0; i < n_root_sets; i++) {
GC_push_conditional_with_exclusions(
- GC_static_roots[i].r_start,
- GC_static_roots[i].r_end, all);
+ GC_static_roots[i].r_start,
+ GC_static_roots[i].r_end, all);
}
- /* Mark all free list header blocks, if those were allocated from */
- /* the garbage collected heap. This makes sure they don't */
- /* disappear if we are not marking from static data. It also */
- /* saves us the trouble of scanning them, and possibly that of */
- /* marking the freelists. */
+ /* Mark all free list header blocks, if those were allocated from */
+ /* the garbage collected heap. This makes sure they don't */
+ /* disappear if we are not marking from static data. It also */
+ /* saves us the trouble of scanning them, and possibly that of */
+ /* marking the freelists. */
for (kind = 0; kind < GC_n_kinds; kind++) {
- GC_PTR base = GC_base(GC_obj_kinds[kind].ok_freelist);
- if (0 != base) {
- GC_set_mark_bit(base);
- }
+ void *base = GC_base(GC_obj_kinds[kind].ok_freelist);
+ if (0 != base) {
+ GC_set_mark_bit(base);
+ }
}
-
- /* Mark from GC internal roots if those might otherwise have */
- /* been excluded. */
+
+ /* Mark from GC internal roots if those might otherwise have */
+ /* been excluded. */
if (GC_no_dls || roots_were_cleared) {
- GC_push_gc_structures();
+ GC_push_gc_structures();
}
- /* Mark thread local free lists, even if their mark */
- /* descriptor excludes the link field. */
- /* If the world is not stopped, this is unsafe. It is */
- /* also unnecessary, since we will do this again with the */
- /* world stopped. */
-# ifdef THREAD_LOCAL_ALLOC
+ /* Mark thread local free lists, even if their mark */
+ /* descriptor excludes the link field. */
+ /* If the world is not stopped, this is unsafe. It is */
+ /* also unnecessary, since we will do this again with the */
+ /* world stopped. */
+# if defined(THREAD_LOCAL_ALLOC)
if (GC_world_stopped) GC_mark_thread_local_free_lists();
# endif
@@ -623,27 +806,14 @@ ptr_t cold_gc_frame;
* Now traverse stacks, and mark from register contents.
* These must be done last, since they can legitimately overflow
* the mark stack.
+ * This is usually done by saving the current context on the
+ * stack, and then just tracing from the stack.
*/
-# ifdef USE_GENERIC_PUSH_REGS
- GC_generic_push_regs(cold_gc_frame);
- /* Also pushes stack, so that we catch callee-save registers */
- /* saved inside the GC_push_regs frame. */
-# else
- /*
- * push registers - i.e., call GC_push_one(r) for each
- * register contents r.
- */
- GC_push_regs(); /* usually defined in machine_dep.c */
- GC_push_current_stack(cold_gc_frame);
- /* In the threads case, this only pushes collector frames. */
- /* In the case of linux threads on IA64, the hot section of */
- /* the main stack is marked here, but the register stack */
- /* backing store is handled in the threads-specific code. */
-# endif
+ GC_push_regs_and_stack(cold_gc_frame);
+
if (GC_push_other_roots != 0) (*GC_push_other_roots)();
- /* In the threads case, this also pushes thread stacks. */
- /* Note that without interior pointer recognition lots */
- /* of stuff may have been pushed already, and this */
- /* should be careful about mark stack overflows. */
+ /* In the threads case, this also pushes thread stacks. */
+ /* Note that without interior pointer recognition lots */
+ /* of stuff may have been pushed already, and this */
+ /* should be careful about mark stack overflows. */
}
-
diff --git a/boehm-gc/mips_sgi_mach_dep.s b/boehm-gc/mips_sgi_mach_dep.s
deleted file mode 100644
index 56390280a71..00000000000
--- a/boehm-gc/mips_sgi_mach_dep.s
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <sys/regdef.h>
-#include <sys/asm.h>
-/* This file must be preprocessed. But the SGI assembler always does */
-/* that. Furthermore, a generic preprocessor won't do, since some of */
-/* the SGI-supplied include files rely on behavior of the MIPS */
-/* assembler. Hence we treat and name this file as though it required */
-/* no preprocessing. */
-
-# define call_push(x) move $4,x; jal GC_push_one
-
- .option pic2
- .text
-/* Mark from machine registers that are saved by C compiler */
-# define FRAMESZ 32
-# define RAOFF FRAMESZ-SZREG
-# define GPOFF FRAMESZ-(2*SZREG)
- NESTED(GC_push_regs, FRAMESZ, ra)
- .mask 0x80000000,-SZREG # inform debugger of saved ra loc
- move t0,gp
- SETUP_GPX(t8)
- PTR_SUBU sp,FRAMESZ
-# ifdef SETUP_GP64
- SETUP_GP64(GPOFF, GC_push_regs)
-# endif
- SAVE_GP(GPOFF)
- REG_S ra,RAOFF(sp)
-# if (_MIPS_SIM == _MIPS_SIM_ABI32)
- call_push($2)
- call_push($3)
-# endif
- call_push($16)
- call_push($17)
- call_push($18)
- call_push($19)
- call_push($20)
- call_push($21)
- call_push($22)
- call_push($23)
- call_push($30)
- REG_L ra,RAOFF(sp)
-# ifdef RESTORE_GP64
- RESTORE_GP64
-# endif
- PTR_ADDU sp,FRAMESZ
- j ra
- .end GC_push_regs
diff --git a/boehm-gc/mips_ultrix_mach_dep.s b/boehm-gc/mips_ultrix_mach_dep.s
deleted file mode 100644
index 178224e31c8..00000000000
--- a/boehm-gc/mips_ultrix_mach_dep.s
+++ /dev/null
@@ -1,26 +0,0 @@
-# define call_push(x) move $4,x; jal GC_push_one
-
- .text
- # Mark from machine registers that are saved by C compiler
- .globl GC_push_regs
- .ent GC_push_regs
-GC_push_regs:
- subu $sp,8 ## Need to save only return address
- sw $31,4($sp)
- .mask 0x80000000,-4
- .frame $sp,8,$31
- call_push($2)
- call_push($3)
- call_push($16)
- call_push($17)
- call_push($18)
- call_push($19)
- call_push($20)
- call_push($21)
- call_push($22)
- call_push($23)
- call_push($30)
- lw $31,4($sp)
- addu $sp,8
- j $31
- .end GC_push_regs
diff --git a/boehm-gc/misc.c b/boehm-gc/misc.c
index 5b10feeb961..7d3a1e9f866 100644
--- a/boehm-gc/misc.c
+++ b/boehm-gc/misc.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
@@ -12,89 +12,71 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, July 31, 1995 5:02 pm PDT */
+#include "private/gc_pmark.h"
#include <stdio.h>
#include <limits.h>
-#ifndef _WIN32_WCE
-#include <signal.h>
-#endif
+#include <stdarg.h>
-#define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */
-#include "private/gc_pmark.h"
+#ifndef MSWINCE
+# include <signal.h>
+#endif
#ifdef GC_SOLARIS_THREADS
# include <sys/syscall.h>
#endif
-#if defined(MSWIN32) || defined(MSWINCE)
-# define WIN32_LEAN_AND_MEAN
+#if defined(MSWIN32) || defined(MSWINCE) \
+ || (defined(CYGWIN32) && defined(GC_READ_ENV_FILE))
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
# define NOSERVICE
# include <windows.h>
-# include <tchar.h>
#endif
-# ifdef THREADS
-# ifdef PCR
-# include "il/PCR_IL.h"
- PCR_Th_ML GC_allocate_ml;
-# else
-# ifdef SRC_M3
- /* Critical section counter is defined in the M3 runtime */
- /* That's all we use. */
-# else
-# ifdef GC_SOLARIS_THREADS
- mutex_t GC_allocate_ml; /* Implicitly initialized. */
-# else
-# if defined(GC_WIN32_THREADS)
-# if defined(GC_PTHREADS)
- pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
-# elif defined(GC_DLL)
- __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
-# else
- CRITICAL_SECTION GC_allocate_ml;
-# endif
-# else
-# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS)
-# if defined(USE_SPIN_LOCK)
- pthread_t GC_lock_holder = NO_THREAD;
-# else
- pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
- pthread_t GC_lock_holder = NO_THREAD;
- /* Used only for assertions, and to prevent */
- /* recursive reentry in the system call wrapper. */
-# endif
-# else
- --> declare allocator lock here
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
+#if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(SYMBIAN)
+# include <fcntl.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
-#if defined(NOSYS) || defined(ECOS)
-#undef STACKBASE
+#ifdef NONSTOP
+# include <floss.h>
#endif
-/* Dont unnecessarily call GC_register_main_static_data() in case */
-/* dyn_load.c isn't linked in. */
+#ifdef THREADS
+# ifdef PCR
+# include "il/PCR_IL.h"
+ GC_INNER PCR_Th_ML GC_allocate_ml;
+# elif defined(SN_TARGET_PS3)
+# include <pthread.h>
+ GC_INNER pthread_mutex_t GC_allocate_ml;
+# endif
+ /* For other platforms with threads, the lock and possibly */
+ /* GC_lock_holder variables are defined in the thread support code. */
+#endif /* THREADS */
+
#ifdef DYNAMIC_LOADING
+ /* We need to register the main data segment. Returns TRUE unless */
+ /* this is done implicitly as part of dynamic library registration. */
# define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data()
+#elif defined(GC_DONT_REGISTER_MAIN_STATIC_DATA)
+# define GC_REGISTER_MAIN_STATIC_DATA() FALSE
#else
+ /* Don't unnecessarily call GC_register_main_static_data() in case */
+ /* dyn_load.c isn't linked in. */
# define GC_REGISTER_MAIN_STATIC_DATA() TRUE
#endif
-GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */;
-
-
-GC_bool GC_debugging_started = FALSE;
- /* defined here so we don't have to load debug_malloc.o */
+#ifdef NEED_CANCEL_DISABLE_COUNT
+ __thread unsigned char GC_cancel_disable_count = 0;
+#endif
-void (*GC_check_heap) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
-void (*GC_print_all_smashed) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
+GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */;
-void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
+GC_INNER GC_bool GC_debugging_started = FALSE;
+ /* defined here so we don't have to load debug_malloc.o */
ptr_t GC_stackbottom = 0;
@@ -102,23 +84,30 @@ ptr_t GC_stackbottom = 0;
ptr_t GC_register_stackbottom = 0;
#endif
-GC_bool GC_dont_gc = 0;
+int GC_dont_gc = FALSE;
-GC_bool GC_dont_precollect = 0;
+int GC_dont_precollect = FALSE;
-GC_bool GC_quiet = 0;
+GC_bool GC_quiet = 0; /* used also in pcr_interface.c */
-GC_bool GC_print_stats = 0;
+#ifndef SMALL_CONFIG
+ int GC_real_print_stats = 0;
+#endif
-GC_bool GC_print_back_height = 0;
+#ifdef GC_PRINT_BACK_HEIGHT
+ GC_INNER GC_bool GC_print_back_height = TRUE;
+#else
+ GC_INNER GC_bool GC_print_back_height = FALSE;
+#endif
#ifndef NO_DEBUGGING
- GC_bool GC_dump_regularly = 0; /* Generate regular debugging dumps. */
+ GC_INNER GC_bool GC_dump_regularly = FALSE;
+ /* Generate regular debugging dumps. */
#endif
#ifdef KEEP_BACK_PTRS
- long GC_backtraces = 0; /* Number of random backtraces to */
- /* generate for each GC. */
+ GC_INNER long GC_backtraces = 0;
+ /* Number of random backtraces to generate for each GC. */
#endif
#ifdef FIND_LEAK
@@ -127,131 +116,180 @@ GC_bool GC_print_back_height = 0;
int GC_find_leak = 0;
#endif
+#ifndef SHORT_DBG_HDRS
+# ifdef GC_FINDLEAK_DELAY_FREE
+ GC_INNER GC_bool GC_findleak_delay_free = TRUE;
+# else
+ GC_INNER GC_bool GC_findleak_delay_free = FALSE;
+# endif
+#endif /* !SHORT_DBG_HDRS */
+
#ifdef ALL_INTERIOR_POINTERS
int GC_all_interior_pointers = 1;
#else
int GC_all_interior_pointers = 0;
#endif
-long GC_large_alloc_warn_interval = 5;
- /* Interval between unsuppressed warnings. */
+#ifdef FINALIZE_ON_DEMAND
+ int GC_finalize_on_demand = 1;
+#else
+ int GC_finalize_on_demand = 0;
+#endif
+
+#ifdef JAVA_FINALIZATION
+ int GC_java_finalization = 1;
+#else
+ int GC_java_finalization = 0;
+#endif
+
+/* All accesses to it should be synchronized to avoid data races. */
+GC_finalizer_notifier_proc GC_finalizer_notifier =
+ (GC_finalizer_notifier_proc)0;
-long GC_large_alloc_warn_suppressed = 0;
- /* Number of warnings suppressed so far. */
+#ifdef GC_FORCE_UNMAP_ON_GCOLLECT
+ /* Has no effect unless USE_MUNMAP. */
+ /* Has no effect on implicitly-initiated garbage collections. */
+ GC_INNER GC_bool GC_force_unmap_on_gcollect = TRUE;
+#else
+ GC_INNER GC_bool GC_force_unmap_on_gcollect = FALSE;
+#endif
+
+#ifndef GC_LARGE_ALLOC_WARN_INTERVAL
+# define GC_LARGE_ALLOC_WARN_INTERVAL 5
+#endif
+GC_INNER long GC_large_alloc_warn_interval = GC_LARGE_ALLOC_WARN_INTERVAL;
+ /* Interval between unsuppressed warnings. */
-/*ARGSUSED*/
-GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested))
+STATIC void * GC_CALLBACK GC_default_oom_fn(
+ size_t bytes_requested GC_ATTR_UNUSED)
{
return(0);
}
-GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) = GC_default_oom_fn;
+/* All accesses to it should be synchronized to avoid data races. */
+GC_oom_func GC_oom_fn = GC_default_oom_fn;
-extern signed_word GC_mem_found;
+#ifdef CAN_HANDLE_FORK
+# ifdef HANDLE_FORK
+ GC_INNER int GC_handle_fork = 1;
+ /* The value is examined by GC_thr_init. */
+# else
+ GC_INNER int GC_handle_fork = FALSE;
+# endif
+
+#elif !defined(HAVE_NO_FORK)
+
+ /* Same as above but with GC_CALL calling conventions. */
+ GC_API void GC_CALL GC_atfork_prepare(void)
+ {
+# ifdef THREADS
+ ABORT("fork() handling unsupported");
+# endif
+ }
-void * GC_project2(arg1, arg2)
-void *arg1;
-void *arg2;
+ GC_API void GC_CALL GC_atfork_parent(void)
+ {
+ /* empty */
+ }
+
+ GC_API void GC_CALL GC_atfork_child(void)
+ {
+ /* empty */
+ }
+#endif /* !CAN_HANDLE_FORK && !HAVE_NO_FORK */
+
+/* Overrides the default automatic handle-fork mode. Has effect only */
+/* if called before GC_INIT. */
+GC_API void GC_CALL GC_set_handle_fork(int value GC_ATTR_UNUSED)
{
- return arg2;
+# ifdef CAN_HANDLE_FORK
+ if (!GC_is_initialized)
+ GC_handle_fork = value >= -1 ? value : 1;
+ /* Map all negative values except for -1 to a positive one. */
+# elif defined(THREADS) || (defined(DARWIN) && defined(MPROTECT_VDB))
+ if (!GC_is_initialized && value) {
+# ifndef SMALL_CONFIG
+ GC_init(); /* just to initialize GC_stderr */
+# endif
+ ABORT("fork() handling unsupported");
+ }
+# else
+ /* No at-fork handler is needed in the single-threaded mode. */
+# endif
}
-# ifdef MERGE_SIZES
- /* Set things up so that GC_size_map[i] >= words(i), */
- /* but not too much bigger */
- /* and so that size_map contains relatively few distinct entries */
- /* This is stolen from Russ Atkinson's Cedar quantization */
- /* alogrithm (but we precompute it). */
-
+/* Set things up so that GC_size_map[i] >= granules(i), */
+/* but not too much bigger */
+/* and so that size_map contains relatively few distinct entries */
+/* This was originally stolen from Russ Atkinson's Cedar */
+/* quantization algorithm (but we precompute it). */
+STATIC void GC_init_size_map(void)
+{
+ int i;
+
+ /* Map size 0 to something bigger. */
+ /* This avoids problems at lower levels. */
+ GC_size_map[0] = 1;
+ for (i = 1; i <= GRANULES_TO_BYTES(TINY_FREELISTS-1) - EXTRA_BYTES; i++) {
+ GC_size_map[i] = ROUNDED_UP_GRANULES(i);
+# ifndef _MSC_VER
+ GC_ASSERT(GC_size_map[i] < TINY_FREELISTS);
+ /* Seems to tickle bug in VC++ 2008 for AMD64 */
+# endif
+ }
+ /* We leave the rest of the array to be filled in on demand. */
+}
- void GC_init_size_map()
- {
- register unsigned i;
-
- /* Map size 0 to something bigger. */
- /* This avoids problems at lower levels. */
- /* One word objects don't have to be 2 word aligned, */
- /* unless we're using mark bytes. */
- for (i = 0; i < sizeof(word); i++) {
- GC_size_map[i] = MIN_WORDS;
- }
-# if MIN_WORDS > 1
- GC_size_map[sizeof(word)] = MIN_WORDS;
-# else
- GC_size_map[sizeof(word)] = ROUNDED_UP_WORDS(sizeof(word));
-# endif
- for (i = sizeof(word) + 1; i <= 8 * sizeof(word); i++) {
- GC_size_map[i] = ALIGNED_WORDS(i);
- }
- for (i = 8*sizeof(word) + 1; i <= 16 * sizeof(word); i++) {
- GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 1) & (~1);
- }
-# ifdef GC_GCJ_SUPPORT
- /* Make all sizes up to 32 words predictable, so that a */
- /* compiler can statically perform the same computation, */
- /* or at least a computation that results in similar size */
- /* classes. */
- for (i = 16*sizeof(word) + 1; i <= 32 * sizeof(word); i++) {
- GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 3) & (~3);
- }
-# endif
- /* We leave the rest of the array to be filled in on demand. */
+/* Fill in additional entries in GC_size_map, including the ith one */
+/* We assume the ith entry is currently 0. */
+/* Note that a filled in section of the array ending at n always */
+/* has length at least n/4. */
+GC_INNER void GC_extend_size_map(size_t i)
+{
+ size_t orig_granule_sz = ROUNDED_UP_GRANULES(i);
+ size_t granule_sz = orig_granule_sz;
+ size_t byte_sz = GRANULES_TO_BYTES(granule_sz);
+ /* The size we try to preserve. */
+ /* Close to i, unless this would */
+ /* introduce too many distinct sizes. */
+ size_t smaller_than_i = byte_sz - (byte_sz >> 3);
+ size_t much_smaller_than_i = byte_sz - (byte_sz >> 2);
+ size_t low_limit; /* The lowest indexed entry we */
+ /* initialize. */
+ size_t j;
+
+ if (GC_size_map[smaller_than_i] == 0) {
+ low_limit = much_smaller_than_i;
+ while (GC_size_map[low_limit] != 0) low_limit++;
+ } else {
+ low_limit = smaller_than_i + 1;
+ while (GC_size_map[low_limit] != 0) low_limit++;
+ granule_sz = ROUNDED_UP_GRANULES(low_limit);
+ granule_sz += granule_sz >> 3;
+ if (granule_sz < orig_granule_sz) granule_sz = orig_granule_sz;
+ }
+ /* For these larger sizes, we use an even number of granules. */
+ /* This makes it easier to, for example, construct a 16byte-aligned */
+ /* allocator even if GRANULE_BYTES is 8. */
+ granule_sz += 1;
+ granule_sz &= ~1;
+ if (granule_sz > MAXOBJGRANULES) {
+ granule_sz = MAXOBJGRANULES;
}
-
- /* Fill in additional entries in GC_size_map, including the ith one */
- /* We assume the ith entry is currently 0. */
- /* Note that a filled in section of the array ending at n always */
- /* has length at least n/4. */
- void GC_extend_size_map(i)
- word i;
+ /* If we can fit the same number of larger objects in a block, */
+ /* do so. */
{
- word orig_word_sz = ROUNDED_UP_WORDS(i);
- word word_sz = orig_word_sz;
- register word byte_sz = WORDS_TO_BYTES(word_sz);
- /* The size we try to preserve. */
- /* Close to to i, unless this would */
- /* introduce too many distinct sizes. */
- word smaller_than_i = byte_sz - (byte_sz >> 3);
- word much_smaller_than_i = byte_sz - (byte_sz >> 2);
- register word low_limit; /* The lowest indexed entry we */
- /* initialize. */
- register word j;
-
- if (GC_size_map[smaller_than_i] == 0) {
- low_limit = much_smaller_than_i;
- while (GC_size_map[low_limit] != 0) low_limit++;
- } else {
- low_limit = smaller_than_i + 1;
- while (GC_size_map[low_limit] != 0) low_limit++;
- word_sz = ROUNDED_UP_WORDS(low_limit);
- word_sz += word_sz >> 3;
- if (word_sz < orig_word_sz) word_sz = orig_word_sz;
- }
-# ifdef ALIGN_DOUBLE
- word_sz += 1;
- word_sz &= ~1;
-# endif
- if (word_sz > MAXOBJSZ) {
- word_sz = MAXOBJSZ;
- }
- /* If we can fit the same number of larger objects in a block, */
- /* do so. */
- {
- size_t number_of_objs = BODY_SZ/word_sz;
- word_sz = BODY_SZ/number_of_objs;
-# ifdef ALIGN_DOUBLE
- word_sz &= ~1;
-# endif
- }
- byte_sz = WORDS_TO_BYTES(word_sz);
- if (GC_all_interior_pointers) {
- /* We need one extra byte; don't fill in GC_size_map[byte_sz] */
- byte_sz--;
- }
-
- for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz;
+ size_t number_of_objs = HBLK_GRANULES/granule_sz;
+ granule_sz = HBLK_GRANULES/number_of_objs;
+ granule_sz &= ~1;
}
-# endif
+ byte_sz = GRANULES_TO_BYTES(granule_sz);
+ /* We may need one extra byte; */
+ /* don't always fill in GC_size_map[byte_sz] */
+ byte_sz -= EXTRA_BYTES;
+
+ for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = granule_sz;
+}
/*
@@ -262,332 +300,637 @@ void *arg2;
* that are not written. We partially address this by clearing
* sections of the stack whenever we get control.
*/
-word GC_stack_last_cleared = 0; /* GC_no when we last did this */
# ifdef THREADS
-# define BIG_CLEAR_SIZE 2048 /* Clear this much now and then. */
-# define SMALL_CLEAR_SIZE 256 /* Clear this much every time. */
+# define BIG_CLEAR_SIZE 2048 /* Clear this much now and then. */
+# define SMALL_CLEAR_SIZE 256 /* Clear this much every time. */
+# else
+ STATIC word GC_stack_last_cleared = 0; /* GC_no when we last did this */
+ STATIC ptr_t GC_min_sp = NULL;
+ /* Coolest stack pointer value from which */
+ /* we've already cleared the stack. */
+ STATIC ptr_t GC_high_water = NULL;
+ /* "hottest" stack pointer value we have seen */
+ /* recently. Degrades over time. */
+ STATIC word GC_bytes_allocd_at_reset = 0;
+# define DEGRADE_RATE 50
# endif
-# define CLEAR_SIZE 213 /* Granularity for GC_clear_stack_inner */
-# define DEGRADE_RATE 50
-word GC_min_sp; /* Coolest stack pointer value from which we've */
- /* already cleared the stack. */
-
-word GC_high_water;
- /* "hottest" stack pointer value we have seen */
- /* recently. Degrades over time. */
-
-word GC_words_allocd_at_reset;
+# define CLEAR_SIZE 213 /* Granularity for GC_clear_stack_inner */
#if defined(ASM_CLEAR_CODE)
- extern ptr_t GC_clear_stack_inner();
-#else
-/* Clear the stack up to about limit. Return arg. */
-/*ARGSUSED*/
-ptr_t GC_clear_stack_inner(arg, limit)
-ptr_t arg;
-word limit;
-{
- word dummy[CLEAR_SIZE];
-
- BZERO(dummy, CLEAR_SIZE*sizeof(word));
- if ((word)(dummy) COOLER_THAN limit) {
+ void *GC_clear_stack_inner(void *, ptr_t);
+#else
+ /* Clear the stack up to about limit. Return arg. This function is */
+ /* not static because it could also be errorneously defined in .S */
+ /* file, so this error would be caught by the linker. */
+ void * GC_clear_stack_inner(void *arg, ptr_t limit)
+ {
+ volatile word dummy[CLEAR_SIZE];
+
+ BZERO((/* no volatile */ void *)dummy, sizeof(dummy));
+ if ((word)GC_approx_sp() COOLER_THAN (word)limit) {
(void) GC_clear_stack_inner(arg, limit);
}
- /* Make sure the recursive call is not a tail call, and the bzero */
- /* call is not recognized as dead code. */
+ /* Make sure the recursive call is not a tail call, and the bzero */
+ /* call is not recognized as dead code. */
GC_noop1((word)dummy);
return(arg);
-}
+ }
#endif
-/* Clear some of the inaccessible part of the stack. Returns its */
+/* Clear some of the inaccessible part of the stack. Returns its */
/* argument, so it can be used in a tail call position, hence clearing */
-/* another frame. */
-ptr_t GC_clear_stack(arg)
-ptr_t arg;
+/* another frame. */
+GC_API void * GC_CALL GC_clear_stack(void *arg)
{
- register word sp = (word)GC_approx_sp(); /* Hotter than actual sp */
+ ptr_t sp = GC_approx_sp(); /* Hotter than actual sp */
# ifdef THREADS
- word dummy[SMALL_CLEAR_SIZE];
- static unsigned random_no = 0;
- /* Should be more random than it is ... */
- /* Used to occasionally clear a bigger */
- /* chunk. */
+ word volatile dummy[SMALL_CLEAR_SIZE];
+ static unsigned random_no = 0;
+ /* Should be more random than it is ... */
+ /* Used to occasionally clear a bigger */
+ /* chunk. */
# endif
- register word limit;
-
+ ptr_t limit;
+
# define SLOP 400
- /* Extra bytes we clear every time. This clears our own */
- /* activation record, and should cause more frequent */
- /* clearing near the cold end of the stack, a good thing. */
+ /* Extra bytes we clear every time. This clears our own */
+ /* activation record, and should cause more frequent */
+ /* clearing near the cold end of the stack, a good thing. */
# define GC_SLOP 4000
- /* We make GC_high_water this much hotter than we really saw */
- /* saw it, to cover for GC noise etc. above our current frame. */
+ /* We make GC_high_water this much hotter than we really saw */
+ /* saw it, to cover for GC noise etc. above our current frame. */
# define CLEAR_THRESHOLD 100000
- /* We restart the clearing process after this many bytes of */
- /* allocation. Otherwise very heavily recursive programs */
- /* with sparse stacks may result in heaps that grow almost */
- /* without bounds. As the heap gets larger, collection */
- /* frequency decreases, thus clearing frequency would decrease, */
- /* thus more junk remains accessible, thus the heap gets */
- /* larger ... */
+ /* We restart the clearing process after this many bytes of */
+ /* allocation. Otherwise very heavily recursive programs */
+ /* with sparse stacks may result in heaps that grow almost */
+ /* without bounds. As the heap gets larger, collection */
+ /* frequency decreases, thus clearing frequency would decrease, */
+ /* thus more junk remains accessible, thus the heap gets */
+ /* larger ... */
# ifdef THREADS
if (++random_no % 13 == 0) {
- limit = sp;
- MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
- limit &= ~0xf; /* Make it sufficiently aligned for assembly */
- /* implementations of GC_clear_stack_inner. */
- return GC_clear_stack_inner(arg, limit);
+ limit = sp;
+ MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
+ limit = (ptr_t)((word)limit & ~0xf);
+ /* Make it sufficiently aligned for assembly */
+ /* implementations of GC_clear_stack_inner. */
+ return GC_clear_stack_inner(arg, limit);
} else {
- BZERO(dummy, SMALL_CLEAR_SIZE*sizeof(word));
- return arg;
+ BZERO((void *)dummy, SMALL_CLEAR_SIZE*sizeof(word));
+ return arg;
}
# else
if (GC_gc_no > GC_stack_last_cleared) {
/* Start things over, so we clear the entire stack again */
- if (GC_stack_last_cleared == 0) GC_high_water = (word) GC_stackbottom;
+ if (GC_stack_last_cleared == 0) GC_high_water = (ptr_t)GC_stackbottom;
GC_min_sp = GC_high_water;
GC_stack_last_cleared = GC_gc_no;
- GC_words_allocd_at_reset = GC_words_allocd;
+ GC_bytes_allocd_at_reset = GC_bytes_allocd;
}
/* Adjust GC_high_water */
MAKE_COOLER(GC_high_water, WORDS_TO_BYTES(DEGRADE_RATE) + GC_SLOP);
- if (sp HOTTER_THAN GC_high_water) {
+ if ((word)sp HOTTER_THAN (word)GC_high_water) {
GC_high_water = sp;
}
MAKE_HOTTER(GC_high_water, GC_SLOP);
limit = GC_min_sp;
MAKE_HOTTER(limit, SLOP);
- if (sp COOLER_THAN limit) {
- limit &= ~0xf; /* Make it sufficiently aligned for assembly */
- /* implementations of GC_clear_stack_inner. */
+ if ((word)sp COOLER_THAN (word)limit) {
+ limit = (ptr_t)((word)limit & ~0xf);
+ /* Make it sufficiently aligned for assembly */
+ /* implementations of GC_clear_stack_inner. */
GC_min_sp = sp;
return(GC_clear_stack_inner(arg, limit));
- } else if (WORDS_TO_BYTES(GC_words_allocd - GC_words_allocd_at_reset)
- > CLEAR_THRESHOLD) {
- /* Restart clearing process, but limit how much clearing we do. */
- GC_min_sp = sp;
- MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
- if (GC_min_sp HOTTER_THAN GC_high_water) GC_min_sp = GC_high_water;
- GC_words_allocd_at_reset = GC_words_allocd;
- }
+ } else if (GC_bytes_allocd - GC_bytes_allocd_at_reset > CLEAR_THRESHOLD) {
+ /* Restart clearing process, but limit how much clearing we do. */
+ GC_min_sp = sp;
+ MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
+ if ((word)GC_min_sp HOTTER_THAN (word)GC_high_water)
+ GC_min_sp = GC_high_water;
+ GC_bytes_allocd_at_reset = GC_bytes_allocd;
+ }
return(arg);
# endif
}
-/* Return a pointer to the base address of p, given a pointer to a */
-/* an address within an object. Return 0 o.w. */
-# ifdef __STDC__
- GC_PTR GC_base(GC_PTR p)
-# else
- GC_PTR GC_base(p)
- GC_PTR p;
-# endif
+/* Return a pointer to the base address of p, given a pointer to a */
+/* an address within an object. Return 0 o.w. */
+GC_API void * GC_CALL GC_base(void * p)
{
- register word r;
- register struct hblk *h;
- register bottom_index *bi;
- register hdr *candidate_hdr;
- register word limit;
-
- r = (word)p;
- if (!GC_is_initialized) return 0;
+ ptr_t r;
+ struct hblk *h;
+ bottom_index *bi;
+ hdr *candidate_hdr;
+ ptr_t limit;
+
+ r = p;
+ if (!EXPECT(GC_is_initialized, TRUE)) return 0;
h = HBLKPTR(r);
GET_BI(r, bi);
candidate_hdr = HDR_FROM_BI(bi, r);
if (candidate_hdr == 0) return(0);
- /* If it's a pointer to the middle of a large object, move it */
- /* to the beginning. */
- while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
- h = FORWARDED_ADDR(h,candidate_hdr);
- r = (word)h;
- candidate_hdr = HDR(h);
- }
- if (candidate_hdr -> hb_map == GC_invalid_map) return(0);
+ /* If it's a pointer to the middle of a large object, move it */
+ /* to the beginning. */
+ while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
+ h = FORWARDED_ADDR(h,candidate_hdr);
+ r = (ptr_t)h;
+ candidate_hdr = HDR(h);
+ }
+ if (HBLK_IS_FREE(candidate_hdr)) return(0);
/* Make sure r points to the beginning of the object */
- r &= ~(WORDS_TO_BYTES(1) - 1);
+ r = (ptr_t)((word)r & ~(WORDS_TO_BYTES(1) - 1));
{
- register int offset = HBLKDISPL(r);
- register signed_word sz = candidate_hdr -> hb_sz;
- register signed_word map_entry;
-
- map_entry = MAP_ENTRY((candidate_hdr -> hb_map), offset);
- if (map_entry > CPP_MAX_OFFSET) {
- map_entry = (signed_word)(BYTES_TO_WORDS(offset)) % sz;
+ size_t offset = HBLKDISPL(r);
+ word sz = candidate_hdr -> hb_sz;
+ size_t obj_displ = offset % sz;
+
+ r -= obj_displ;
+ limit = r + sz;
+ if ((word)limit > (word)(h + 1) && sz <= HBLKSIZE) {
+ return(0);
}
- r -= WORDS_TO_BYTES(map_entry);
- limit = r + WORDS_TO_BYTES(sz);
- if (limit > (word)(h + 1)
- && sz <= BYTES_TO_WORDS(HBLKSIZE)) {
- return(0);
- }
- if ((word)p >= limit) return(0);
- }
- return((GC_PTR)r);
-}
-
-
-/* Return the size of an object, given a pointer to its base. */
-/* (For small obects this also happens to work from interior pointers, */
-/* but that shouldn't be relied upon.) */
-# ifdef __STDC__
- size_t GC_size(GC_PTR p)
-# else
- size_t GC_size(p)
- GC_PTR p;
-# endif
+ if ((word)p >= (word)limit) return(0);
+ }
+ return((void *)r);
+}
+
+/* Return TRUE if and only if p points to somewhere in GC heap. */
+GC_API int GC_CALL GC_is_heap_ptr(const void *p)
+{
+ bottom_index *bi;
+
+ GC_ASSERT(GC_is_initialized);
+ GET_BI(p, bi);
+ return HDR_FROM_BI(bi, p) != 0;
+}
+
+/* Return the size of an object, given a pointer to its base. */
+/* (For small objects this also happens to work from interior pointers, */
+/* but that shouldn't be relied upon.) */
+GC_API size_t GC_CALL GC_size(const void * p)
+{
+ hdr * hhdr = HDR(p);
+
+ return hhdr -> hb_sz;
+}
+
+
+/* These getters remain unsynchronized for compatibility (since some */
+/* clients could call some of them from a GC callback holding the */
+/* allocator lock). */
+GC_API size_t GC_CALL GC_get_heap_size(void)
{
- register int sz;
- register hdr * hhdr = HDR(p);
-
- sz = WORDS_TO_BYTES(hhdr -> hb_sz);
- return(sz);
+ /* ignore the memory space returned to OS (i.e. count only the */
+ /* space owned by the garbage collector) */
+ return (size_t)(GC_heapsize - GC_unmapped_bytes);
}
-size_t GC_get_heap_size GC_PROTO(())
+GC_API size_t GC_CALL GC_get_free_bytes(void)
{
- return ((size_t) GC_heapsize);
+ /* ignore the memory space returned to OS */
+ return (size_t)(GC_large_free_bytes - GC_unmapped_bytes);
}
-size_t GC_get_free_bytes GC_PROTO(())
+GC_API size_t GC_CALL GC_get_unmapped_bytes(void)
{
- return ((size_t) GC_large_free_bytes);
+ return (size_t)GC_unmapped_bytes;
}
-size_t GC_get_bytes_since_gc GC_PROTO(())
+GC_API size_t GC_CALL GC_get_bytes_since_gc(void)
{
- return ((size_t) WORDS_TO_BYTES(GC_words_allocd));
+ return (size_t)GC_bytes_allocd;
}
-size_t GC_get_total_bytes GC_PROTO(())
+GC_API size_t GC_CALL GC_get_total_bytes(void)
{
- return ((size_t) WORDS_TO_BYTES(GC_words_allocd+GC_words_allocd_before_gc));
+ return (size_t)(GC_bytes_allocd + GC_bytes_allocd_before_gc);
}
-GC_bool GC_is_initialized = FALSE;
+#ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
-void GC_init()
+/* Return the heap usage information. This is a thread-safe (atomic) */
+/* alternative for the five above getters. NULL pointer is allowed for */
+/* any argument. Returned (filled in) values are of word type. */
+GC_API void GC_CALL GC_get_heap_usage_safe(GC_word *pheap_size,
+ GC_word *pfree_bytes, GC_word *punmapped_bytes,
+ GC_word *pbytes_since_gc, GC_word *ptotal_bytes)
{
+ DCL_LOCK_STATE;
+
+ LOCK();
+ if (pheap_size != NULL)
+ *pheap_size = GC_heapsize - GC_unmapped_bytes;
+ if (pfree_bytes != NULL)
+ *pfree_bytes = GC_large_free_bytes - GC_unmapped_bytes;
+ if (punmapped_bytes != NULL)
+ *punmapped_bytes = GC_unmapped_bytes;
+ if (pbytes_since_gc != NULL)
+ *pbytes_since_gc = GC_bytes_allocd;
+ if (ptotal_bytes != NULL)
+ *ptotal_bytes = GC_bytes_allocd + GC_bytes_allocd_before_gc;
+ UNLOCK();
+}
+
+ GC_INNER word GC_reclaimed_bytes_before_gc = 0;
+
+ /* Fill in GC statistics provided the destination is of enough size. */
+ static void fill_prof_stats(struct GC_prof_stats_s *pstats)
+ {
+ pstats->heapsize_full = GC_heapsize;
+ pstats->free_bytes_full = GC_large_free_bytes;
+ pstats->unmapped_bytes = GC_unmapped_bytes;
+ pstats->bytes_allocd_since_gc = GC_bytes_allocd;
+ pstats->allocd_bytes_before_gc = GC_bytes_allocd_before_gc;
+ pstats->non_gc_bytes = GC_non_gc_bytes;
+ pstats->gc_no = GC_gc_no; /* could be -1 */
+# ifdef PARALLEL_MARK
+ pstats->markers_m1 = (word)GC_markers_m1;
+# else
+ pstats->markers_m1 = 0; /* one marker */
+# endif
+ pstats->bytes_reclaimed_since_gc = GC_bytes_found > 0 ?
+ (word)GC_bytes_found : 0;
+ pstats->reclaimed_bytes_before_gc = GC_reclaimed_bytes_before_gc;
+ }
+
+# include <string.h> /* for memset() */
+
+ GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s *pstats,
+ size_t stats_sz)
+ {
+ struct GC_prof_stats_s stats;
DCL_LOCK_STATE;
-
- DISABLE_SIGNALS();
-
-#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
- if (!GC_is_initialized) {
- BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
- HMODULE hK32 = GetModuleHandle("kernel32.dll");
- if (hK32)
- (FARPROC) pfn = GetProcAddress(hK32,
- "InitializeCriticalSectionAndSpinCount");
- if (pfn)
- pfn(&GC_allocate_ml, 4000);
- else
- InitializeCriticalSection (&GC_allocate_ml);
- }
-#endif /* MSWIN32 */
LOCK();
- GC_init_inner();
+ fill_prof_stats(stats_sz >= sizeof(stats) ? pstats : &stats);
UNLOCK();
- ENABLE_SIGNALS();
-# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
- /* Make sure marker threads and started and thread local */
- /* allocation is initialized, in case we didn't get */
- /* called from GC_init_parallel(); */
- {
- extern void GC_init_parallel(void);
- GC_init_parallel();
- }
-# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
+ if (stats_sz == sizeof(stats)) {
+ return sizeof(stats);
+ } else if (stats_sz > sizeof(stats)) {
+ /* Fill in the remaining part with -1. */
+ memset((char *)pstats + sizeof(stats), 0xff, stats_sz - sizeof(stats));
+ return sizeof(stats);
+ } else {
+ BCOPY(&stats, pstats, stats_sz);
+ return stats_sz;
+ }
+ }
-# if defined(DYNAMIC_LOADING) && defined(DARWIN)
+# ifdef THREADS
+ /* The _unsafe version assumes the caller holds the allocation lock. */
+ GC_API size_t GC_CALL GC_get_prof_stats_unsafe(
+ struct GC_prof_stats_s *pstats,
+ size_t stats_sz)
{
- /* This must be called WITHOUT the allocation lock held
- and before any threads are created */
- extern void GC_init_dyld();
- GC_init_dyld();
+ struct GC_prof_stats_s stats;
+
+ if (stats_sz >= sizeof(stats)) {
+ fill_prof_stats(pstats);
+ if (stats_sz > sizeof(stats))
+ memset((char *)pstats + sizeof(stats), 0xff,
+ stats_sz - sizeof(stats));
+ return sizeof(stats);
+ } else {
+ fill_prof_stats(&stats);
+ BCOPY(&stats, pstats, stats_sz);
+ return stats_sz;
+ }
}
-# endif
-}
+# endif /* THREADS */
-#if defined(MSWIN32) || defined(MSWINCE)
- CRITICAL_SECTION GC_write_cs;
-#endif
+#endif /* !GC_GET_HEAP_USAGE_NOT_NEEDED */
-#ifdef MSWIN32
- extern void GC_init_win32 GC_PROTO((void));
-#endif
+#if defined(GC_DARWIN_THREADS) || defined(GC_OPENBSD_THREADS) \
+ || defined(GC_WIN32_THREADS) || (defined(NACL) && defined(THREADS))
+ /* GC does not use signals to suspend and restart threads. */
+ GC_API void GC_CALL GC_set_suspend_signal(int sig GC_ATTR_UNUSED)
+ {
+ /* empty */
+ }
-extern void GC_setpagesize();
+ GC_API void GC_CALL GC_set_thr_restart_signal(int sig GC_ATTR_UNUSED)
+ {
+ /* empty */
+ }
+ GC_API int GC_CALL GC_get_suspend_signal(void)
+ {
+ return -1;
+ }
-#ifdef MSWIN32
-extern GC_bool GC_no_win32_dlls;
-#else
-# define GC_no_win32_dlls FALSE
+ GC_API int GC_CALL GC_get_thr_restart_signal(void)
+ {
+ return -1;
+ }
+#endif /* GC_DARWIN_THREADS || GC_WIN32_THREADS || ... */
+
+#if !defined(_MAX_PATH) && (defined(MSWIN32) || defined(MSWINCE) \
+ || defined(CYGWIN32))
+# define _MAX_PATH MAX_PATH
#endif
-void GC_exit_check GC_PROTO((void))
-{
- GC_gcollect();
-}
+#ifdef GC_READ_ENV_FILE
+ /* This works for Win32/WinCE for now. Really useful only for WinCE. */
+ STATIC char *GC_envfile_content = NULL;
+ /* The content of the GC "env" file with CR and */
+ /* LF replaced to '\0'. NULL if the file is */
+ /* missing or empty. Otherwise, always ends */
+ /* with '\0'. */
+ STATIC unsigned GC_envfile_length = 0;
+ /* Length of GC_envfile_content (if non-NULL). */
+
+# ifndef GC_ENVFILE_MAXLEN
+# define GC_ENVFILE_MAXLEN 0x4000
+# endif
-#ifdef SEARCH_FOR_DATA_START
- extern void GC_init_linux_data_start GC_PROTO((void));
-#endif
+ /* The routine initializes GC_envfile_content from the GC "env" file. */
+ STATIC void GC_envfile_init(void)
+ {
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+ HANDLE hFile;
+ char *content;
+ unsigned ofs;
+ unsigned len;
+ DWORD nBytesRead;
+ TCHAR path[_MAX_PATH + 0x10]; /* buffer for path + ext */
+ len = (unsigned)GetModuleFileName(NULL /* hModule */, path,
+ _MAX_PATH + 1);
+ /* If GetModuleFileName() has failed then len is 0. */
+ if (len > 4 && path[len - 4] == (TCHAR)'.') {
+ len -= 4; /* strip executable file extension */
+ }
+ BCOPY(TEXT(".gc.env"), &path[len], sizeof(TEXT(".gc.env")));
+ hFile = CreateFile(path, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL /* lpSecurityAttributes */, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL /* hTemplateFile */);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return; /* the file is absent or the operation is failed */
+ len = (unsigned)GetFileSize(hFile, NULL);
+ if (len <= 1 || len >= GC_ENVFILE_MAXLEN) {
+ CloseHandle(hFile);
+ return; /* invalid file length - ignoring the file content */
+ }
+ /* At this execution point, GC_setpagesize() and GC_init_win32() */
+ /* must already be called (for GET_MEM() to work correctly). */
+ content = (char *)GET_MEM(len + 1);
+ if (content == NULL) {
+ CloseHandle(hFile);
+ return; /* allocation failure */
+ }
+ ofs = 0;
+ nBytesRead = (DWORD)-1L;
+ /* Last ReadFile() call should clear nBytesRead on success. */
+ while (ReadFile(hFile, content + ofs, len - ofs + 1, &nBytesRead,
+ NULL /* lpOverlapped */) && nBytesRead != 0) {
+ if ((ofs += nBytesRead) > len)
+ break;
+ }
+ CloseHandle(hFile);
+ if (ofs != len || nBytesRead != 0)
+ return; /* read operation is failed - ignoring the file content */
+ content[ofs] = '\0';
+ while (ofs-- > 0) {
+ if (content[ofs] == '\r' || content[ofs] == '\n')
+ content[ofs] = '\0';
+ }
+ GC_envfile_length = len + 1;
+ GC_envfile_content = content;
+# endif
+ }
+
+ /* This routine scans GC_envfile_content for the specified */
+ /* environment variable (and returns its value if found). */
+ GC_INNER char * GC_envfile_getenv(const char *name)
+ {
+ char *p;
+ char *end_of_content;
+ unsigned namelen;
+# ifndef NO_GETENV
+ p = getenv(name); /* try the standard getenv() first */
+ if (p != NULL)
+ return *p != '\0' ? p : NULL;
+# endif
+ p = GC_envfile_content;
+ if (p == NULL)
+ return NULL; /* "env" file is absent (or empty) */
+ namelen = strlen(name);
+ if (namelen == 0) /* a sanity check */
+ return NULL;
+ for (end_of_content = p + GC_envfile_length;
+ p != end_of_content; p += strlen(p) + 1) {
+ if (strncmp(p, name, namelen) == 0 && *(p += namelen) == '=') {
+ p++; /* the match is found; skip '=' */
+ return *p != '\0' ? p : NULL;
+ }
+ /* If not matching then skip to the next line. */
+ }
+ return NULL; /* no match found */
+ }
+#endif /* GC_READ_ENV_FILE */
-#ifdef UNIX_LIKE
+GC_INNER GC_bool GC_is_initialized = FALSE;
-extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int)));
+#if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS)
+ GC_INNER CRITICAL_SECTION GC_write_cs;
+#endif
-static void looping_handler(sig)
-int sig;
+STATIC void GC_exit_check(void)
{
- GC_err_printf1("Caught signal %d: looping in handler\n", sig);
- for(;;);
+ if (GC_find_leak) {
+ GC_gcollect();
+ }
}
-static GC_bool installed_looping_handler = FALSE;
+#if defined(UNIX_LIKE) && !defined(NO_DEBUGGING)
+ static void looping_handler(int sig)
+ {
+ GC_err_printf("Caught signal %d: looping in handler\n", sig);
+ for (;;) {
+ /* empty */
+ }
+ }
-static void maybe_install_looping_handler()
-{
- /* Install looping handler before the write fault handler, so we */
- /* handle write faults correctly. */
- if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) {
- GC_set_and_save_fault_handler(looping_handler);
- installed_looping_handler = TRUE;
- }
-}
+ static GC_bool installed_looping_handler = FALSE;
-#else /* !UNIX_LIKE */
+ static void maybe_install_looping_handler(void)
+ {
+ /* Install looping handler before the write fault handler, so we */
+ /* handle write faults correctly. */
+ if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) {
+ GC_set_and_save_fault_handler(looping_handler);
+ installed_looping_handler = TRUE;
+ }
+ }
+#else /* !UNIX_LIKE */
# define maybe_install_looping_handler()
+#endif
+#define GC_DEFAULT_STDOUT_FD 1
+#define GC_DEFAULT_STDERR_FD 2
+
+#if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
+ STATIC int GC_stdout = GC_DEFAULT_STDOUT_FD;
+ STATIC int GC_stderr = GC_DEFAULT_STDERR_FD;
+ STATIC int GC_log = GC_DEFAULT_STDERR_FD;
#endif
-void GC_init_inner()
+STATIC word GC_parse_mem_size_arg(const char *str)
+{
+ char *endptr;
+ word result = 0; /* bad value */
+ char ch;
+
+ if (*str != '\0') {
+ result = (word)STRTOULL(str, &endptr, 10);
+ ch = *endptr;
+ if (ch != '\0') {
+ if (*(endptr + 1) != '\0')
+ return 0;
+ /* Allow k, M or G suffix. */
+ switch (ch) {
+ case 'K':
+ case 'k':
+ result <<= 10;
+ break;
+ case 'M':
+ case 'm':
+ result <<= 20;
+ break;
+ case 'G':
+ case 'g':
+ result <<= 30;
+ break;
+ default:
+ result = 0;
+ }
+ }
+ }
+ return result;
+}
+
+#define GC_LOG_STD_NAME "gc.log"
+
+GC_API void GC_CALL GC_init(void)
{
-# if !defined(THREADS) && defined(GC_ASSERTIONS)
- word dummy;
+ /* LOCK(); -- no longer does anything this early. */
+ word initial_heap_sz;
+ IF_CANCEL(int cancel_state;)
+
+ if (EXPECT(GC_is_initialized, TRUE)) return;
+# ifdef REDIRECT_MALLOC
+ {
+ static GC_bool init_started = FALSE;
+ if (init_started)
+ ABORT("Redirected malloc() called during GC init");
+ init_started = TRUE;
+ }
# endif
- word initial_heap_sz = (word)MINHINCR;
-
- if (GC_is_initialized) return;
-# ifdef PRINTSTATS
- GC_print_stats = 1;
+
+# ifdef GC_INITIAL_HEAP_SIZE
+ initial_heap_sz = divHBLKSZ(GC_INITIAL_HEAP_SIZE);
+# else
+ initial_heap_sz = (word)MINHINCR;
# endif
-# if defined(MSWIN32) || defined(MSWINCE)
+ DISABLE_CANCEL(cancel_state);
+ /* 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);
+# ifdef SN_TARGET_PS3
+ {
+ pthread_mutexattr_t mattr;
+ pthread_mutexattr_init(&mattr);
+ pthread_mutex_init(&GC_allocate_ml, &mattr);
+ pthread_mutexattr_destroy(&mattr);
+ }
+# endif
+# endif /* THREADS */
+# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
+ {
+# ifndef MSWINCE
+ BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
+ HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
+ if (hK32)
+ pfn = (BOOL (WINAPI *) (LPCRITICAL_SECTION, DWORD))
+ GetProcAddress (hK32,
+ "InitializeCriticalSectionAndSpinCount");
+ if (pfn)
+ pfn(&GC_allocate_ml, 4000);
+ else
+# endif /* !MSWINCE */
+ /* else */ InitializeCriticalSection (&GC_allocate_ml);
+ }
+# endif /* GC_WIN32_THREADS */
+# if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS)
InitializeCriticalSection(&GC_write_cs);
# endif
- if (0 != GETENV("GC_PRINT_STATS")) {
- GC_print_stats = 1;
- }
+ GC_setpagesize();
+# ifdef MSWIN32
+ GC_init_win32();
+# endif
+# ifdef GC_READ_ENV_FILE
+ GC_envfile_init();
+# endif
+# ifndef SMALL_CONFIG
+# ifdef GC_PRINT_VERBOSE_STATS
+ /* This is useful for debugging and profiling on platforms with */
+ /* missing getenv() (like WinCE). */
+ GC_real_print_stats = VERBOSE;
+# else
+ if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) {
+ GC_real_print_stats = VERBOSE;
+ } else if (0 != GETENV("GC_PRINT_STATS")) {
+ GC_real_print_stats = 1;
+ }
+# endif
+# if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(SYMBIAN)
+ {
+ char * file_name = GETENV("GC_LOG_FILE");
+# ifdef GC_LOG_TO_FILE_ALWAYS
+ if (NULL == file_name)
+ file_name = GC_LOG_STD_NAME;
+# else
+ if (0 != file_name)
+# endif
+ {
+ int log_d = open(file_name, O_CREAT|O_WRONLY|O_APPEND, 0666);
+ if (log_d < 0) {
+ GC_err_printf("Failed to open %s as log file\n", file_name);
+ } else {
+ char *str;
+ GC_log = log_d;
+ str = GETENV("GC_ONLY_LOG_TO_FILE");
+# ifdef GC_ONLY_LOG_TO_FILE
+ /* The similar environment variable set to "0" */
+ /* overrides the effect of the macro defined. */
+ if (str != NULL && *str == '0' && *(str + 1) == '\0')
+# else
+ /* Otherwise setting the environment variable */
+ /* to anything other than "0" will prevent from */
+ /* redirecting stdout/err to the log file. */
+ if (str == NULL || (*str == '0' && *(str + 1) == '\0'))
+# endif
+ {
+ GC_stdout = log_d;
+ GC_stderr = log_d;
+ }
+ }
+ }
+ }
+# endif
+# endif /* !SMALL_CONFIG */
# ifndef NO_DEBUGGING
if (0 != GETENV("GC_DUMP_REGULARLY")) {
- GC_dump_regularly = 1;
+ GC_dump_regularly = TRUE;
}
# endif
# ifdef KEEP_BACK_PTRS
@@ -595,16 +938,18 @@ void GC_init_inner()
char * backtraces_string = GETENV("GC_BACKTRACES");
if (0 != backtraces_string) {
GC_backtraces = atol(backtraces_string);
- if (backtraces_string[0] == '\0') GC_backtraces = 1;
+ if (backtraces_string[0] == '\0') GC_backtraces = 1;
}
}
# endif
if (0 != GETENV("GC_FIND_LEAK")) {
GC_find_leak = 1;
-# ifdef __STDC__
- atexit(GC_exit_check);
-# endif
}
+# ifndef SHORT_DBG_HDRS
+ if (0 != GETENV("GC_FINDLEAK_DELAY_FREE")) {
+ GC_findleak_delay_free = TRUE;
+ }
+# endif
if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
GC_all_interior_pointers = 1;
}
@@ -612,564 +957,1252 @@ void GC_init_inner()
GC_dont_gc = 1;
}
if (0 != GETENV("GC_PRINT_BACK_HEIGHT")) {
- GC_print_back_height = 1;
+ GC_print_back_height = TRUE;
}
if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) {
GC_large_alloc_warn_interval = LONG_MAX;
}
{
- char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
- if (0 != time_limit_string) {
- long time_limit = atol(time_limit_string);
- if (time_limit < 5) {
- WARN("GC_PAUSE_TIME_TARGET environment variable value too small "
- "or bad syntax: Ignoring\n", 0);
- } else {
- GC_time_limit = time_limit;
- }
+ char * addr_string = GETENV("GC_TRACE");
+ if (0 != addr_string) {
+# ifndef ENABLE_TRACE
+ WARN("Tracing not enabled: Ignoring GC_TRACE value\n", 0);
+# else
+ word addr = (word)STRTOULL(addr_string, NULL, 16);
+ if (addr < 0x1000)
+ WARN("Unlikely trace address: %p\n", addr);
+ GC_trace_addr = (ptr_t)addr;
+# endif
}
}
+# ifdef GC_COLLECT_AT_MALLOC
+ {
+ char * string = GETENV("GC_COLLECT_AT_MALLOC");
+ if (0 != string) {
+ size_t min_lb = (size_t)STRTOULL(string, NULL, 10);
+ if (min_lb > 0)
+ GC_dbg_collect_at_malloc_min_lb = min_lb;
+ }
+ }
+# endif
+# ifndef GC_DISABLE_INCREMENTAL
+ {
+ char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
+ if (0 != time_limit_string) {
+ long time_limit = atol(time_limit_string);
+ if (time_limit < 5) {
+ WARN("GC_PAUSE_TIME_TARGET environment variable value too small "
+ "or bad syntax: Ignoring\n", 0);
+ } else {
+ GC_time_limit = time_limit;
+ }
+ }
+ }
+# endif
+# ifndef SMALL_CONFIG
+ {
+ char * full_freq_string = GETENV("GC_FULL_FREQUENCY");
+ if (full_freq_string != NULL) {
+ int full_freq = atoi(full_freq_string);
+ if (full_freq > 0)
+ GC_full_freq = full_freq;
+ }
+ }
+# endif
{
char * interval_string = GETENV("GC_LARGE_ALLOC_WARN_INTERVAL");
if (0 != interval_string) {
long interval = atol(interval_string);
if (interval <= 0) {
- WARN("GC_LARGE_ALLOC_WARN_INTERVAL environment variable has "
- "bad value: Ignoring\n", 0);
+ WARN("GC_LARGE_ALLOC_WARN_INTERVAL environment variable has "
+ "bad value: Ignoring\n", 0);
} else {
- GC_large_alloc_warn_interval = interval;
+ GC_large_alloc_warn_interval = interval;
}
}
}
+ {
+ char * space_divisor_string = GETENV("GC_FREE_SPACE_DIVISOR");
+ if (space_divisor_string != NULL) {
+ int space_divisor = atoi(space_divisor_string);
+ if (space_divisor > 0)
+ GC_free_space_divisor = (GC_word)space_divisor;
+ }
+ }
+# ifdef USE_MUNMAP
+ {
+ char * string = GETENV("GC_UNMAP_THRESHOLD");
+ if (string != NULL) {
+ if (*string == '0' && *(string + 1) == '\0') {
+ /* "0" is used to disable unmapping. */
+ GC_unmap_threshold = 0;
+ } else {
+ int unmap_threshold = atoi(string);
+ if (unmap_threshold > 0)
+ GC_unmap_threshold = unmap_threshold;
+ }
+ }
+ }
+ {
+ char * string = GETENV("GC_FORCE_UNMAP_ON_GCOLLECT");
+ if (string != NULL) {
+ if (*string == '0' && *(string + 1) == '\0') {
+ /* "0" is used to turn off the mode. */
+ GC_force_unmap_on_gcollect = FALSE;
+ } else {
+ GC_force_unmap_on_gcollect = TRUE;
+ }
+ }
+ }
+ {
+ char * string = GETENV("GC_USE_ENTIRE_HEAP");
+ if (string != NULL) {
+ if (*string == '0' && *(string + 1) == '\0') {
+ /* "0" is used to turn off the mode. */
+ GC_use_entire_heap = FALSE;
+ } else {
+ GC_use_entire_heap = TRUE;
+ }
+ }
+ }
+# endif
maybe_install_looping_handler();
- /* Adjust normal object descriptor for extra allocation. */
+ /* Adjust normal object descriptor for extra allocation. */
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
}
- GC_setpagesize();
- GC_exclude_static_roots(beginGC_arrays, endGC_arrays);
- GC_exclude_static_roots(beginGC_obj_kinds, endGC_obj_kinds);
+ GC_exclude_static_roots_inner(beginGC_arrays, endGC_arrays);
+ GC_exclude_static_roots_inner(beginGC_obj_kinds, endGC_obj_kinds);
# ifdef SEPARATE_GLOBALS
- GC_exclude_static_roots(beginGC_objfreelist, endGC_objfreelist);
- GC_exclude_static_roots(beginGC_aobjfreelist, endGC_aobjfreelist);
+ GC_exclude_static_roots_inner(beginGC_objfreelist, endGC_objfreelist);
+ GC_exclude_static_roots_inner(beginGC_aobjfreelist, endGC_aobjfreelist);
# endif
-# ifdef MSWIN32
- GC_init_win32();
+# if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
+ WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0);
+ /* If thread stacks are cached, they tend to be scanned in */
+ /* entirety as part of the root set. This wil grow them to */
+ /* maximum size, and is generally not desirable. */
# endif
# if defined(SEARCH_FOR_DATA_START)
- GC_init_linux_data_start();
+ GC_init_linux_data_start();
# endif
-# if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
- GC_init_netbsd_elf();
+# if defined(NETBSD) && defined(__ELF__)
+ GC_init_netbsd_elf();
# endif
-# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
- || defined(GC_WIN32_THREADS)
- GC_thr_init();
-# endif
-# ifdef GC_SOLARIS_THREADS
- /* We need dirty bits in order to find live stack sections. */
- GC_dirty_init();
-# endif
-# if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \
- || defined(GC_SOLARIS_THREADS)
+# if !defined(THREADS) || defined(GC_PTHREADS) \
+ || defined(GC_WIN32_THREADS) || defined(GC_SOLARIS_THREADS)
if (GC_stackbottom == 0) {
- GC_stackbottom = GC_get_stack_base();
+ GC_stackbottom = GC_get_main_stack_base();
# if (defined(LINUX) || defined(HPUX)) && defined(IA64)
- GC_register_stackbottom = GC_get_register_stack_base();
+ GC_register_stackbottom = GC_get_register_stack_base();
# endif
} else {
# if (defined(LINUX) || defined(HPUX)) && defined(IA64)
- if (GC_register_stackbottom == 0) {
- WARN("GC_register_stackbottom should be set with GC_stackbottom", 0);
- /* The following may fail, since we may rely on */
- /* alignment properties that may not hold with a user set */
- /* GC_stackbottom. */
- GC_register_stackbottom = GC_get_register_stack_base();
- }
-# endif
+ if (GC_register_stackbottom == 0) {
+ WARN("GC_register_stackbottom should be set with GC_stackbottom\n", 0);
+ /* The following may fail, since we may rely on */
+ /* alignment properties that may not hold with a user set */
+ /* GC_stackbottom. */
+ GC_register_stackbottom = GC_get_register_stack_base();
+ }
+# endif
}
# endif
GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word));
GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
# ifndef THREADS
-# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
- ABORT(
- "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
-# endif
-# if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
- ABORT(
- "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
-# endif
-# ifdef STACK_GROWS_DOWN
- GC_ASSERT((word)(&dummy) <= (word)GC_stackbottom);
-# else
- GC_ASSERT((word)(&dummy) >= (word)GC_stackbottom);
-# endif
+ GC_ASSERT(!((word)GC_stackbottom HOTTER_THAN (word)GC_approx_sp()));
# endif
# if !defined(_AUX_SOURCE) || defined(__GNUC__)
- GC_ASSERT((word)(-1) > (word)0);
+ GC_STATIC_ASSERT((word)(-1) > (word)0);
/* word should be unsigned */
# endif
- GC_ASSERT((signed_word)(-1) < (signed_word)0);
-
- /* Add initial guess of root sets. Do this first, since sbrk(0) */
- /* might be used. */
+ /* We no longer check for ((void*)(-1) > NULL) since all pointers */
+ /* are explicitly cast to word in every less-greater comparison. */
+ GC_STATIC_ASSERT((signed_word)(-1) < (signed_word)0);
+# ifndef GC_DISABLE_INCREMENTAL
+ if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
+ /* For GWW_VDB on Win32, this needs to happen before any */
+ /* heap memory is allocated. */
+ GC_dirty_init();
+ GC_ASSERT(GC_bytes_allocd == 0);
+ GC_incremental = TRUE;
+ }
+# endif
+
+ /* Add initial guess of root sets. Do this first, since sbrk(0) */
+ /* might be used. */
if (GC_REGISTER_MAIN_STATIC_DATA()) GC_register_data_segments();
GC_init_headers();
GC_bl_init();
GC_mark_init();
{
- char * sz_str = GETENV("GC_INITIAL_HEAP_SIZE");
- if (sz_str != NULL) {
- initial_heap_sz = atoi(sz_str);
- if (initial_heap_sz <= MINHINCR * HBLKSIZE) {
- WARN("Bad initial heap size %s - ignoring it.\n",
- sz_str);
- }
- initial_heap_sz = divHBLKSZ(initial_heap_sz);
- }
+ char * sz_str = GETENV("GC_INITIAL_HEAP_SIZE");
+ if (sz_str != NULL) {
+ initial_heap_sz = GC_parse_mem_size_arg(sz_str);
+ if (initial_heap_sz <= MINHINCR * HBLKSIZE) {
+ WARN("Bad initial heap size %s - ignoring it.\n", sz_str);
+ }
+ initial_heap_sz = divHBLKSZ(initial_heap_sz);
+ }
}
{
- char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE");
- if (sz_str != NULL) {
- word max_heap_sz = (word)atol(sz_str);
- if (max_heap_sz < initial_heap_sz * HBLKSIZE) {
- WARN("Bad maximum heap size %s - ignoring it.\n",
- sz_str);
- }
- if (0 == GC_max_retries) GC_max_retries = 2;
- GC_set_max_heap_size(max_heap_sz);
- }
+ char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE");
+ if (sz_str != NULL) {
+ word max_heap_sz = GC_parse_mem_size_arg(sz_str);
+ if (max_heap_sz < initial_heap_sz * HBLKSIZE) {
+ WARN("Bad maximum heap size %s - ignoring it.\n", sz_str);
+ }
+ if (0 == GC_max_retries) GC_max_retries = 2;
+ GC_set_max_heap_size(max_heap_sz);
+ }
}
if (!GC_expand_hp_inner(initial_heap_sz)) {
- GC_err_printf0("Can't start up: not enough memory\n");
+ GC_err_printf("Can't start up: not enough memory\n");
EXIT();
+ } else {
+ GC_requested_heapsize += initial_heap_sz;
}
- /* Preallocate large object map. It's otherwise inconvenient to */
- /* deal with failure. */
- if (!GC_add_map_entry((word)0)) {
- GC_err_printf0("Can't start up: not enough memory\n");
- EXIT();
- }
+ if (GC_all_interior_pointers)
+ GC_initialize_offsets();
GC_register_displacement_inner(0L);
-# ifdef MERGE_SIZES
- GC_init_size_map();
+# if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
+ if (!GC_all_interior_pointers) {
+ /* TLS ABI uses pointer-sized offsets for dtv. */
+ GC_register_displacement_inner(sizeof(void *));
+ }
# endif
+ GC_init_size_map();
# ifdef PCR
if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
!= PCR_ERes_okay) {
- ABORT("Can't lock load state\n");
+ ABORT("Can't lock load state");
} else if (PCR_IL_Unlock() != PCR_ERes_okay) {
- ABORT("Can't unlock load state\n");
+ ABORT("Can't unlock load state");
}
PCR_IL_Unlock();
GC_pcr_install();
# endif
-# if !defined(SMALL_CONFIG)
- if (!GC_no_win32_dlls && 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
- GC_ASSERT(!GC_incremental);
- GC_setpagesize();
-# ifndef GC_SOLARIS_THREADS
- GC_dirty_init();
-# endif
- GC_ASSERT(GC_words_allocd == 0)
- GC_incremental = TRUE;
- }
-# endif /* !SMALL_CONFIG */
+ GC_is_initialized = TRUE;
+# if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
+ GC_thr_init();
+# endif
COND_DUMP;
/* Get black list set up and/or incremental GC started */
if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
- GC_is_initialized = TRUE;
# ifdef STUBBORN_ALLOC
- GC_stubborn_init();
+ GC_stubborn_init();
# endif
- /* Convince lint that some things are used */
-# ifdef LINT
- {
- extern char * GC_copyright[];
- extern int GC_read();
- extern void GC_register_finalizer_no_order();
-
- GC_noop(GC_copyright, GC_find_header,
- GC_push_one, GC_call_with_alloc_lock, GC_read,
- GC_dont_expand,
-# ifndef NO_DEBUGGING
- GC_dump,
-# endif
- GC_register_finalizer_no_order);
- }
+ if (GC_find_leak) {
+ /* This is to give us at least one chance to detect leaks. */
+ /* This may report some very benign leaks, but ... */
+ atexit(GC_exit_check);
+ }
+
+ /* 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 are 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. */
+ GC_init_dyld();
# endif
+ RESTORE_CANCEL(cancel_state);
}
-void GC_enable_incremental GC_PROTO(())
+GC_API void GC_CALL GC_enable_incremental(void)
{
-# if !defined(SMALL_CONFIG)
- if (!GC_find_leak) {
+# if !defined(GC_DISABLE_INCREMENTAL) && !defined(KEEP_BACK_PTRS)
DCL_LOCK_STATE;
-
- DISABLE_SIGNALS();
- LOCK();
- if (GC_incremental) goto out;
- GC_setpagesize();
- if (GC_no_win32_dlls) goto out;
-# ifndef GC_SOLARIS_THREADS
- maybe_install_looping_handler(); /* Before write fault handler! */
- GC_dirty_init();
-# endif
- if (!GC_is_initialized) {
- GC_init_inner();
- }
- if (GC_incremental) goto out;
- if (GC_dont_gc) {
- /* Can't easily do it. */
- UNLOCK();
- ENABLE_SIGNALS();
- return;
+ /* If we are keeping back pointers, the GC itself dirties all */
+ /* pages on which objects have been marked, making */
+ /* incremental GC pointless. */
+ if (!GC_find_leak && 0 == GETENV("GC_DISABLE_INCREMENTAL")) {
+ LOCK();
+ if (!GC_incremental) {
+ GC_setpagesize();
+ /* if (GC_no_win32_dlls) goto out; Should be win32S test? */
+ maybe_install_looping_handler(); /* Before write fault handler! */
+ GC_incremental = TRUE;
+ if (!GC_is_initialized) {
+ GC_init();
+ } else {
+ GC_dirty_init();
+ }
+ if (GC_dirty_maintained && !GC_dont_gc) {
+ /* Can't easily do it if GC_dont_gc. */
+ if (GC_bytes_allocd > 0) {
+ /* There may be unmarked reachable objects. */
+ GC_gcollect_inner();
+ }
+ /* else we're OK in assuming everything's */
+ /* clean since nothing can point to an */
+ /* unmarked object. */
+ GC_read_dirty();
+ }
+ }
+ UNLOCK();
+ return;
}
- if (GC_words_allocd > 0) {
- /* There may be unmarked reachable objects */
- GC_gcollect_inner();
- } /* else we're OK in assuming everything's */
- /* clean since nothing can point to an */
- /* unmarked object. */
- GC_read_dirty();
- GC_incremental = TRUE;
-out:
- UNLOCK();
- ENABLE_SIGNALS();
- }
# endif
+ GC_init();
}
+#if defined(THREADS) && (!defined(PARALLEL_MARK) || !defined(CAN_HANDLE_FORK))
+ GC_API void GC_CALL GC_start_mark_threads(void)
+ {
+ /* No action since parallel markers are disabled (or no POSIX fork). */
+ GC_ASSERT(I_DONT_HOLD_LOCK());
+ }
+#endif
#if defined(MSWIN32) || defined(MSWINCE)
-# define LOG_FILE _T("gc.log")
- HANDLE GC_stdout = 0;
+# if defined(_MSC_VER) && defined(_DEBUG) && !defined(MSWINCE)
+# include <crtdbg.h>
+# endif
- void GC_deinit()
+ STATIC HANDLE GC_log = 0;
+
+ void GC_deinit(void)
{
+# ifdef THREADS
if (GC_is_initialized) {
- DeleteCriticalSection(&GC_write_cs);
+ DeleteCriticalSection(&GC_write_cs);
+ }
+# endif
+ }
+
+# ifdef THREADS
+# ifdef PARALLEL_MARK
+# define IF_NEED_TO_LOCK(x) if (GC_parallel || GC_need_to_lock) x
+# else
+# define IF_NEED_TO_LOCK(x) if (GC_need_to_lock) x
+# endif
+# else
+# define IF_NEED_TO_LOCK(x)
+# endif /* !THREADS */
+
+ STATIC HANDLE GC_CreateLogFile(void)
+ {
+ HANDLE hFile;
+ TCHAR *logPath;
+ BOOL appendToFile = FALSE;
+# if !defined(NO_GETENV_WIN32) || !defined(OLD_WIN32_LOG_FILE)
+ TCHAR pathBuf[_MAX_PATH + 0x10]; /* buffer for path + ext */
+
+ logPath = pathBuf;
+# endif
+
+ /* Use GetEnvironmentVariable instead of GETENV() for unicode support. */
+# ifndef NO_GETENV_WIN32
+ if (GetEnvironmentVariable(TEXT("GC_LOG_FILE"), pathBuf,
+ _MAX_PATH + 1) - 1U < (DWORD)_MAX_PATH) {
+ appendToFile = TRUE;
+ } else
+# endif
+ /* else */ {
+ /* Env var not found or its value too long. */
+# ifdef OLD_WIN32_LOG_FILE
+ logPath = TEXT(GC_LOG_STD_NAME);
+# else
+ int len = (int)GetModuleFileName(NULL /* hModule */, pathBuf,
+ _MAX_PATH + 1);
+ /* If GetModuleFileName() has failed then len is 0. */
+ if (len > 4 && pathBuf[len - 4] == (TCHAR)'.') {
+ len -= 4; /* strip executable file extension */
+ }
+ BCOPY(TEXT("." GC_LOG_STD_NAME), &pathBuf[len],
+ sizeof(TEXT("." GC_LOG_STD_NAME)));
+# endif
+ }
+
+ hFile = CreateFile(logPath, GENERIC_WRITE, FILE_SHARE_READ,
+ NULL /* lpSecurityAttributes */,
+ appendToFile ? OPEN_ALWAYS : CREATE_ALWAYS,
+ GC_print_stats == VERBOSE ? FILE_ATTRIBUTE_NORMAL :
+ /* immediately flush writes unless very verbose */
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
+ NULL /* hTemplateFile */);
+# ifndef NO_GETENV_WIN32
+ if (appendToFile && hFile != INVALID_HANDLE_VALUE) {
+ LONG posHigh = 0;
+ (void)SetFilePointer(hFile, 0, &posHigh, FILE_END);
+ /* Seek to file end (ignoring any error) */
}
+# endif
+ return hFile;
}
- int GC_write(buf, len)
- GC_CONST char * buf;
- size_t len;
+ STATIC int GC_write(const char *buf, size_t len)
{
BOOL tmp;
DWORD written;
+# if (defined(THREADS) && defined(GC_ASSERTIONS)) \
+ || !defined(GC_PRINT_VERBOSE_STATS)
+ static GC_bool inside_write = FALSE;
+ /* to prevent infinite recursion at abort. */
+ if (inside_write)
+ return -1;
+# endif
+
if (len == 0)
- return 0;
- EnterCriticalSection(&GC_write_cs);
- if (GC_stdout == INVALID_HANDLE_VALUE) {
- return -1;
- } else if (GC_stdout == 0) {
- GC_stdout = CreateFile(LOG_FILE, GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
- NULL);
- if (GC_stdout == INVALID_HANDLE_VALUE) ABORT("Open of log file failed");
+ return 0;
+ IF_NEED_TO_LOCK(EnterCriticalSection(&GC_write_cs));
+# if defined(THREADS) && defined(GC_ASSERTIONS)
+ if (GC_write_disabled) {
+ inside_write = TRUE;
+ ABORT("Assertion failure: GC_write called with write_disabled");
+ }
+# endif
+ if (GC_log == INVALID_HANDLE_VALUE) {
+ IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs));
+ return -1;
+ } else if (GC_log == 0) {
+ GC_log = GC_CreateLogFile();
+ /* Ignore open log failure if the collector is built with */
+ /* print_stats always set on. */
+# ifndef GC_PRINT_VERBOSE_STATS
+ if (GC_log == INVALID_HANDLE_VALUE) {
+ inside_write = TRUE;
+ ABORT("Open of log file failed");
+ }
+# endif
}
- tmp = WriteFile(GC_stdout, buf, len, &written, NULL);
+ tmp = WriteFile(GC_log, buf, (DWORD)len, &written, NULL);
if (!tmp)
- DebugBreak();
- LeaveCriticalSection(&GC_write_cs);
+ DebugBreak();
+# if defined(_MSC_VER) && defined(_DEBUG)
+# ifdef MSWINCE
+ /* There is no CrtDbgReport() in WinCE */
+ {
+ WCHAR wbuf[1024];
+ /* Always use Unicode variant of OutputDebugString() */
+ wbuf[MultiByteToWideChar(CP_ACP, 0 /* dwFlags */,
+ buf, len, wbuf,
+ sizeof(wbuf) / sizeof(wbuf[0]) - 1)] = 0;
+ OutputDebugStringW(wbuf);
+ }
+# else
+ _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%.*s", len, buf);
+# endif
+# endif
+ IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs));
return tmp ? (int)written : -1;
}
-#endif
+ /* FIXME: This is pretty ugly ... */
+# define WRITE(f, buf, len) GC_write(buf, len)
-#if defined(OS2) || defined(MACOS)
-FILE * GC_stdout = NULL;
-FILE * GC_stderr = NULL;
-int GC_tmp; /* Should really be local ... */
+#elif defined(OS2) || defined(MACOS)
+ STATIC FILE * GC_stdout = NULL;
+ STATIC FILE * GC_stderr = NULL;
+ STATIC FILE * GC_log = NULL;
- void GC_set_files()
+ /* Initialize GC_log (and the friends) passed to GC_write(). */
+ STATIC void GC_set_files(void)
{
- if (GC_stdout == NULL) {
- GC_stdout = stdout;
+ if (GC_stdout == NULL) {
+ GC_stdout = stdout;
}
if (GC_stderr == NULL) {
- GC_stderr = stderr;
+ GC_stderr = stderr;
+ }
+ if (GC_log == NULL) {
+ GC_log = stderr;
}
}
-#endif
-#if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
- int GC_stdout = 1;
- int GC_stderr = 2;
-# if !defined(AMIGA)
+ GC_INLINE int GC_write(FILE *f, const char *buf, size_t len)
+ {
+ int res = fwrite(buf, 1, len, f);
+ fflush(f);
+ return res;
+ }
+
+# define WRITE(f, buf, len) (GC_set_files(), GC_write(f, buf, len))
+
+#else
+# if !defined(AMIGA) && !defined(__CC_ARM)
# include <unistd.h>
# endif
+
+ STATIC int GC_write(int fd, const char *buf, size_t len)
+ {
+# if defined(ECOS) || defined(NOSYS)
+# ifdef ECOS
+ /* FIXME: This seems to be defined nowhere at present. */
+ /* _Jv_diag_write(buf, len); */
+# else
+ /* No writing. */
+# endif
+ return len;
+# else
+ int bytes_written = 0;
+ int result;
+ IF_CANCEL(int cancel_state;)
+
+ DISABLE_CANCEL(cancel_state);
+ while ((size_t)bytes_written < len) {
+# ifdef GC_SOLARIS_THREADS
+ result = syscall(SYS_write, fd, buf + bytes_written,
+ len - bytes_written);
+# else
+ result = write(fd, buf + bytes_written, len - bytes_written);
+# endif
+ if (-1 == result) {
+ RESTORE_CANCEL(cancel_state);
+ return(result);
+ }
+ bytes_written += result;
+ }
+ RESTORE_CANCEL(cancel_state);
+ return(bytes_written);
+# endif
+ }
+
+# define WRITE(f, buf, len) GC_write(f, buf, len)
+#endif /* !MSWIN32 && !OS2 && !MACOS */
+
+#ifdef GC_ANDROID_LOG
+# include <android/log.h>
+
+# ifndef GC_ANDROID_LOG_TAG
+# define GC_ANDROID_LOG_TAG "BDWGC"
+# endif
#endif
-#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) \
- && !defined(MACOS) && !defined(ECOS) && !defined(NOSYS)
-int GC_write(fd, buf, len)
-int fd;
-GC_CONST char *buf;
-size_t len;
-{
- register int bytes_written = 0;
- register int result;
-
- while (bytes_written < len) {
-# ifdef GC_SOLARIS_THREADS
- result = syscall(SYS_write, fd, buf + bytes_written,
- len - bytes_written);
-# else
- result = write(fd, buf + bytes_written, len - bytes_written);
-# endif
- if (-1 == result) return(result);
- bytes_written += result;
- }
- return(bytes_written);
-}
-#endif /* UN*X */
+#define BUFSZ 1024
-#ifdef ECOS
-int GC_write(fd, buf, len)
+#ifdef NO_VSNPRINTF
+ /* In case this function is missing (eg., in DJGPP v2.0.3). */
+# define vsnprintf(buf, bufsz, format, args) vsprintf(buf, format, args)
+#elif defined(_MSC_VER)
+# ifdef MSWINCE
+ /* _vsnprintf is deprecated in WinCE */
+# define vsnprintf StringCchVPrintfA
+# else
+# define vsnprintf _vsnprintf
+# endif
+#endif
+
+/* A version of printf that is unlikely to call malloc, and is thus safer */
+/* to call from the collector in case malloc has been bound to GC_malloc. */
+/* Floating point arguments and formats should be avoided, since FP */
+/* conversion is more likely to allocate memory. */
+/* Assumes that no more than BUFSZ-1 characters are written at once. */
+#define GC_PRINTF_FILLBUF(buf, format) { \
+ va_list args; \
+ va_start(args, format); \
+ (buf)[sizeof(buf) - 1] = 0x15; /* guard */ \
+ (void)vsnprintf(buf, sizeof(buf) - 1, format, args); \
+ va_end(args); \
+ if ((buf)[sizeof(buf) - 1] != 0x15) \
+ ABORT("GC_printf clobbered stack"); \
+ }
+
+void GC_printf(const char *format, ...)
{
- _Jv_diag_write (buf, len);
- return len;
+ char buf[BUFSZ + 1];
+
+# ifdef GC_ANDROID_LOG
+ GC_PRINTF_FILLBUF(buf, format);
+ __android_log_write(ANDROID_LOG_DEBUG, GC_ANDROID_LOG_TAG, buf);
+ if (GC_stdout == GC_DEFAULT_STDOUT_FD)
+ return; /* skip duplicate write to stdout */
+# endif
+ if (!GC_quiet) {
+# ifndef GC_ANDROID_LOG
+ GC_PRINTF_FILLBUF(buf, format);
+# endif
+ if (WRITE(GC_stdout, buf, strlen(buf)) < 0)
+ ABORT("write to stdout failed");
+ }
}
-#endif
-#ifdef NOSYS
-int GC_write(fd, buf, len)
+void GC_err_printf(const char *format, ...)
{
- /* No writing. */
- return len;
+ char buf[BUFSZ + 1];
+
+ GC_PRINTF_FILLBUF(buf, format);
+ GC_err_puts(buf);
}
-#endif
+#ifndef GC_ANDROID_LOG
+
+ void GC_log_printf(const char *format, ...)
+ {
+ char buf[BUFSZ + 1];
+
+ GC_PRINTF_FILLBUF(buf, format);
+ if (WRITE(GC_log, buf, strlen(buf)) < 0)
+ ABORT("write to GC log failed");
+ }
+
+# define GC_warn_printf GC_err_printf
-#if defined(MSWIN32) || defined(MSWINCE)
-# define WRITE(f, buf, len) GC_write(buf, len)
#else
-# if defined(OS2) || defined(MACOS)
-# define WRITE(f, buf, len) (GC_set_files(), \
- GC_tmp = fwrite((buf), 1, (len), (f)), \
- fflush(f), GC_tmp)
-# else
-# define WRITE(f, buf, len) GC_write((f), (buf), (len))
-# endif
-#endif
-/* A version of printf that is unlikely to call malloc, and is thus safer */
-/* to call from the collector in case malloc has been bound to GC_malloc. */
-/* Assumes that no more than 1023 characters are written at once. */
-/* Assumes that all arguments have been converted to something of the */
-/* same size as long, and that the format conversions expect something */
-/* of that size. */
-void GC_printf(format, a, b, c, d, e, f)
-GC_CONST char * format;
-long a, b, c, d, e, f;
-{
- char buf[1025];
-
- if (GC_quiet) return;
- buf[1024] = 0x15;
- (void) sprintf(buf, format, a, b, c, d, e, f);
- if (buf[1024] != 0x15) ABORT("GC_printf clobbered stack");
- if (WRITE(GC_stdout, buf, strlen(buf)) < 0) ABORT("write to stdout failed");
-}
-
-void GC_err_printf(format, a, b, c, d, e, f)
-GC_CONST char * format;
-long a, b, c, d, e, f;
-{
- char buf[1025];
-
- buf[1024] = 0x15;
- (void) sprintf(buf, format, a, b, c, d, e, f);
- if (buf[1024] != 0x15) ABORT("GC_err_printf clobbered stack");
- if (WRITE(GC_stderr, buf, strlen(buf)) < 0) ABORT("write to stderr failed");
-}
-
-void GC_err_puts(s)
-GC_CONST char *s;
+# define GC_LOG_PRINTF_IMPL(loglevel, fileLogCond, format) \
+ { \
+ char buf[BUFSZ + 1]; \
+ GC_PRINTF_FILLBUF(buf, format); \
+ __android_log_write(loglevel, GC_ANDROID_LOG_TAG, buf); \
+ if (GC_log != GC_DEFAULT_STDERR_FD && (fileLogCond) \
+ && WRITE(GC_log, buf, strlen(buf)) < 0) \
+ ABORT("write to GC log file failed"); \
+ }
+
+ void GC_log_printf(const char *format, ...)
+ {
+ GC_LOG_PRINTF_IMPL(ANDROID_LOG_DEBUG, TRUE, format);
+ }
+
+ GC_INNER void GC_stats_log_printf(const char *format, ...)
+ {
+ GC_LOG_PRINTF_IMPL(ANDROID_LOG_INFO, GC_real_print_stats != 0, format);
+ }
+
+ GC_INNER void GC_verbose_log_printf(const char *format, ...)
+ {
+ GC_LOG_PRINTF_IMPL(ANDROID_LOG_VERBOSE, GC_real_print_stats == VERBOSE,
+ format);
+ }
+
+ STATIC void GC_warn_printf(const char *format, ...)
+ {
+ char buf[BUFSZ + 1];
+
+ GC_PRINTF_FILLBUF(buf, format);
+ __android_log_write(ANDROID_LOG_WARN, GC_ANDROID_LOG_TAG, buf);
+ if (GC_real_print_stats && GC_stderr != GC_DEFAULT_STDERR_FD
+ && WRITE(GC_stderr, buf, strlen(buf)) < 0)
+ ABORT("write to stderr failed");
+ }
+
+#endif /* GC_ANDROID_LOG */
+
+void GC_err_puts(const char *s)
{
+# ifdef GC_ANDROID_LOG
+ __android_log_write(ANDROID_LOG_ERROR, GC_ANDROID_LOG_TAG, s);
+ if (GC_stderr == GC_DEFAULT_STDERR_FD)
+ return; /* skip duplicate write to stderr */
+# endif
if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed");
}
-#if defined(LINUX) && !defined(SMALL_CONFIG)
-void GC_err_write(buf, len)
-GC_CONST char *buf;
-size_t len;
+STATIC void GC_CALLBACK GC_default_warn_proc(char *msg, GC_word arg)
{
- if (WRITE(GC_stderr, buf, len) < 0) ABORT("write to stderr failed");
+ /* TODO: Add assertion on arg comply with msg (format). */
+ GC_warn_printf(msg, arg);
}
-#endif
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_default_warn_proc(char *msg, GC_word arg)
-# else
- void GC_default_warn_proc(msg, arg)
- char *msg;
- GC_word arg;
-# endif
+GC_INNER GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
+
+/* This is recommended for production code (release). */
+GC_API void GC_CALLBACK GC_ignore_warn_proc(char *msg, GC_word arg)
{
- GC_err_printf1(msg, (unsigned long)arg);
+ if (GC_print_stats) {
+ /* Don't ignore warnings if stats printing is on. */
+ GC_default_warn_proc(msg, arg);
+ }
}
-GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
-
-# if defined(__STDC__) || defined(__cplusplus)
- GC_warn_proc GC_set_warn_proc(GC_warn_proc p)
-# else
- GC_warn_proc GC_set_warn_proc(p)
- GC_warn_proc p;
-# endif
+GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc p)
{
- GC_warn_proc result;
-
+ DCL_LOCK_STATE;
+ GC_ASSERT(p != 0);
# ifdef GC_WIN32_THREADS
- GC_ASSERT(GC_is_initialized);
+# ifdef CYGWIN32
+ /* Need explicit GC_INIT call */
+ GC_ASSERT(GC_is_initialized);
+# else
+ if (!GC_is_initialized) GC_init();
+# endif
# endif
LOCK();
- result = GC_current_warn_proc;
GC_current_warn_proc = p;
UNLOCK();
- return(result);
}
-# if defined(__STDC__) || defined(__cplusplus)
- GC_word GC_set_free_space_divisor (GC_word value)
-# else
- GC_word GC_set_free_space_divisor (value)
- GC_word value;
-# endif
+GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void)
{
- GC_word old = GC_free_space_divisor;
- GC_free_space_divisor = value;
- return old;
+ GC_warn_proc result;
+ DCL_LOCK_STATE;
+ LOCK();
+ result = GC_current_warn_proc;
+ UNLOCK();
+ return(result);
}
-#ifndef PCR
-void GC_abort(msg)
-GC_CONST char * msg;
-{
-# if defined(MSWIN32)
- (void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK);
-# else
- GC_err_printf1("%s\n", msg);
+#if !defined(PCR) && !defined(SMALL_CONFIG)
+ /* Print (or display) a message before abnormal exit (including */
+ /* abort). Invoked from ABORT(msg) macro (there msg is non-NULL) */
+ /* and from EXIT() macro (msg is NULL in that case). */
+ STATIC void GC_CALLBACK GC_default_on_abort(const char *msg)
+ {
+ GC_find_leak = FALSE; /* disable at-exit GC_gcollect() */
+
+ if (msg != NULL) {
+# if defined(MSWIN32)
+# ifndef DONT_USE_USER32_DLL
+ /* Use static binding to "user32.dll". */
+ (void)MessageBoxA(NULL, msg, "Fatal error in GC",
+ MB_ICONERROR | MB_OK);
+# else
+ /* This simplifies linking - resolve "MessageBoxA" at run-time. */
+ HINSTANCE hU32 = LoadLibrary(TEXT("user32.dll"));
+ if (hU32) {
+ FARPROC pfn = GetProcAddress(hU32, "MessageBoxA");
+ if (pfn)
+ (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))pfn)(
+ NULL /* hWnd */, msg, "Fatal error in GC",
+ MB_ICONERROR | MB_OK);
+ (void)FreeLibrary(hU32);
+ }
+# endif
+ /* Also duplicate msg to GC log file. */
+# endif
+ /* Avoid calling GC_err_printf() here, as GC_on_abort() could be */
+ /* called from it. Note 1: this is not an atomic output. */
+ /* Note 2: possible write errors are ignored. */
+
+# if defined(THREADS) && defined(GC_ASSERTIONS) \
+ && (defined(MSWIN32) || defined(MSWINCE))
+ if (!GC_write_disabled)
+# endif
+ {
+ if (WRITE(GC_stderr, (void *)msg, strlen(msg)) >= 0)
+ (void)WRITE(GC_stderr, (void *)("\n"), 1);
+ }
+# ifdef GC_ANDROID_LOG
+ __android_log_assert("*" /* cond */, GC_ANDROID_LOG_TAG, "%s\n", msg);
# endif
- if (GETENV("GC_LOOP_ON_ABORT") != NULL) {
- /* In many cases it's easier to debug a running process. */
- /* It's arguably nicer to sleep, but that makes it harder */
- /* to look at the thread if the debugger doesn't know much */
- /* about threads. */
- for(;;) {}
}
-# if defined(MSWIN32) || defined(MSWINCE)
- DebugBreak();
-# else
- (void) abort();
+
+# if !defined(NO_DEBUGGING) && !defined(GC_ANDROID_LOG)
+ if (GETENV("GC_LOOP_ON_ABORT") != NULL) {
+ /* In many cases it's easier to debug a running process. */
+ /* It's arguably nicer to sleep, but that makes it harder */
+ /* to look at the thread if the debugger doesn't know much */
+ /* about threads. */
+ for(;;) {
+ /* Empty */
+ }
+ }
# endif
-}
-#endif
+ }
+
+ GC_abort_func GC_on_abort = GC_default_on_abort;
+
+ GC_API void GC_CALL GC_set_abort_func(GC_abort_func fn)
+ {
+ DCL_LOCK_STATE;
+ GC_ASSERT(fn != 0);
+ LOCK();
+ GC_on_abort = fn;
+ UNLOCK();
+ }
-void GC_enable()
+ GC_API GC_abort_func GC_CALL GC_get_abort_func(void)
+ {
+ GC_abort_func fn;
+ DCL_LOCK_STATE;
+ LOCK();
+ fn = GC_on_abort;
+ UNLOCK();
+ return fn;
+ }
+#endif /* !SMALL_CONFIG */
+
+GC_API void GC_CALL GC_enable(void)
{
+ DCL_LOCK_STATE;
LOCK();
GC_dont_gc--;
UNLOCK();
}
-void GC_disable()
+GC_API void GC_CALL GC_disable(void)
{
+ DCL_LOCK_STATE;
LOCK();
GC_dont_gc++;
UNLOCK();
}
-/* Helper procedures for new kind creation. */
-void ** GC_new_free_list_inner()
+GC_API int GC_CALL GC_is_disabled(void)
{
- void *result = GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
+ return GC_dont_gc != 0;
+}
+
+/* Helper procedures for new kind creation. */
+GC_API void ** GC_CALL GC_new_free_list_inner(void)
+{
+ void *result = GC_INTERNAL_MALLOC((MAXOBJGRANULES+1)*sizeof(ptr_t),
+ PTRFREE);
if (result == 0) ABORT("Failed to allocate freelist for new kind");
- BZERO(result, (MAXOBJSZ+1)*sizeof(ptr_t));
+ BZERO(result, (MAXOBJGRANULES+1)*sizeof(ptr_t));
return result;
}
-void ** GC_new_free_list()
+GC_API void ** GC_CALL GC_new_free_list(void)
{
void *result;
- LOCK(); DISABLE_SIGNALS();
+ DCL_LOCK_STATE;
+ LOCK();
result = GC_new_free_list_inner();
- UNLOCK(); ENABLE_SIGNALS();
+ UNLOCK();
return result;
}
-int GC_new_kind_inner(fl, descr, adjust, clear)
-void **fl;
-GC_word descr;
-int adjust;
-int clear;
+GC_API unsigned GC_CALL GC_new_kind_inner(void **fl, GC_word descr,
+ int adjust, int clear)
{
- int result = GC_n_kinds++;
+ unsigned result = GC_n_kinds++;
if (GC_n_kinds > MAXOBJKINDS) ABORT("Too many kinds");
- GC_obj_kinds[result].ok_freelist = (ptr_t *)fl;
+ GC_obj_kinds[result].ok_freelist = fl;
GC_obj_kinds[result].ok_reclaim_list = 0;
GC_obj_kinds[result].ok_descriptor = descr;
GC_obj_kinds[result].ok_relocate_descr = adjust;
GC_obj_kinds[result].ok_init = clear;
+# ifdef ENABLE_DISCLAIM
+ GC_obj_kinds[result].ok_mark_unconditionally = FALSE;
+ GC_obj_kinds[result].ok_disclaim_proc = 0;
+# endif
return result;
}
-int GC_new_kind(fl, descr, adjust, clear)
-void **fl;
-GC_word descr;
-int adjust;
-int clear;
+GC_API unsigned GC_CALL GC_new_kind(void **fl, GC_word descr, int adjust,
+ int clear)
{
- int result;
- LOCK(); DISABLE_SIGNALS();
+ unsigned result;
+ DCL_LOCK_STATE;
+ LOCK();
result = GC_new_kind_inner(fl, descr, adjust, clear);
- UNLOCK(); ENABLE_SIGNALS();
+ UNLOCK();
return result;
}
-int GC_new_proc_inner(proc)
-GC_mark_proc proc;
+GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc proc)
{
- int result = GC_n_mark_procs++;
+ unsigned result = GC_n_mark_procs++;
if (GC_n_mark_procs > MAX_MARK_PROCS) ABORT("Too many mark procedures");
GC_mark_procs[result] = proc;
return result;
}
-int GC_new_proc(proc)
-GC_mark_proc proc;
+GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc proc)
{
- int result;
- LOCK(); DISABLE_SIGNALS();
+ unsigned result;
+ DCL_LOCK_STATE;
+ LOCK();
result = GC_new_proc_inner(proc);
- UNLOCK(); ENABLE_SIGNALS();
+ UNLOCK();
return result;
}
+GC_API void * GC_CALL GC_call_with_alloc_lock(GC_fn_type fn, void *client_data)
+{
+ void * result;
+ DCL_LOCK_STATE;
-#if !defined(NO_DEBUGGING)
+# ifdef THREADS
+ LOCK();
+ /* FIXME - This looks wrong!! */
+ SET_LOCK_HOLDER();
+# endif
+ result = (*fn)(client_data);
+# ifdef THREADS
+# ifndef GC_ASSERTIONS
+ UNSET_LOCK_HOLDER();
+# endif /* o.w. UNLOCK() does it implicitly */
+ UNLOCK();
+# endif
+ return(result);
+}
-void GC_dump()
+GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func fn, void *arg)
{
- GC_printf0("***Static roots:\n");
+ struct GC_stack_base base;
+ void *result;
+
+ base.mem_base = (void *)&base;
+# ifdef IA64
+ base.reg_base = (void *)GC_save_regs_in_stack();
+ /* Unnecessarily flushes register stack, */
+ /* but that probably doesn't hurt. */
+# endif
+ result = fn(&base, arg);
+ /* Strongly discourage the compiler from treating the above */
+ /* as a tail call. */
+ GC_noop1((word)(&base));
+ return result;
+}
+
+#ifndef THREADS
+
+GC_INNER ptr_t GC_blocked_sp = NULL;
+ /* NULL value means we are not inside GC_do_blocking() call. */
+# ifdef IA64
+ STATIC ptr_t GC_blocked_register_sp = NULL;
+# endif
+
+GC_INNER struct GC_traced_stack_sect_s *GC_traced_stack_sect = NULL;
+
+/* This is nearly the same as in win32_threads.c */
+GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
+ void * client_data)
+{
+ struct GC_traced_stack_sect_s stacksect;
+ GC_ASSERT(GC_is_initialized);
+
+ /* Adjust our stack base value (this could happen if */
+ /* GC_get_main_stack_base() is unimplemented or broken for */
+ /* the platform). */
+ if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect))
+ GC_stackbottom = (ptr_t)(&stacksect);
+
+ if (GC_blocked_sp == NULL) {
+ /* We are not inside GC_do_blocking() - do nothing more. */
+ return fn(client_data);
+ }
+
+ /* Setup new "stack section". */
+ stacksect.saved_stack_ptr = GC_blocked_sp;
+# ifdef IA64
+ /* This is the same as in GC_call_with_stack_base(). */
+ stacksect.backing_store_end = GC_save_regs_in_stack();
+ /* Unnecessarily flushes register stack, */
+ /* but that probably doesn't hurt. */
+ stacksect.saved_backing_store_ptr = GC_blocked_register_sp;
+# endif
+ stacksect.prev = GC_traced_stack_sect;
+ GC_blocked_sp = NULL;
+ GC_traced_stack_sect = &stacksect;
+
+ client_data = fn(client_data);
+ GC_ASSERT(GC_blocked_sp == NULL);
+ GC_ASSERT(GC_traced_stack_sect == &stacksect);
+
+ /* Restore original "stack section". */
+ GC_traced_stack_sect = stacksect.prev;
+# ifdef IA64
+ GC_blocked_register_sp = stacksect.saved_backing_store_ptr;
+# endif
+ GC_blocked_sp = stacksect.saved_stack_ptr;
+
+ return client_data; /* result */
+}
+
+/* This is nearly the same as in win32_threads.c */
+STATIC void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
+{
+ struct blocking_data * d = (struct blocking_data *) data;
+ GC_ASSERT(GC_is_initialized);
+ GC_ASSERT(GC_blocked_sp == NULL);
+# ifdef SPARC
+ GC_blocked_sp = GC_save_regs_in_stack();
+# else
+ GC_blocked_sp = (ptr_t) &d; /* save approx. sp */
+# endif
+# ifdef IA64
+ GC_blocked_register_sp = GC_save_regs_in_stack();
+# endif
+
+ d -> client_data = (d -> fn)(d -> client_data);
+
+# ifdef SPARC
+ GC_ASSERT(GC_blocked_sp != NULL);
+# else
+ GC_ASSERT(GC_blocked_sp == (ptr_t) &d);
+# endif
+ GC_blocked_sp = NULL;
+}
+
+#endif /* !THREADS */
+
+/* Wrapper for functions that are likely to block (or, at least, do not */
+/* allocate garbage collected memory and/or manipulate pointers to the */
+/* garbage collected heap) for an appreciable length of time. */
+/* In the single threaded case, GC_do_blocking() (together */
+/* with GC_call_with_gc_active()) might be used to make stack scanning */
+/* more precise (i.e. scan only stack frames of functions that allocate */
+/* garbage collected memory and/or manipulate pointers to the garbage */
+/* collected heap). */
+GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data)
+{
+ struct blocking_data my_data;
+
+ my_data.fn = fn;
+ my_data.client_data = client_data;
+ GC_with_callee_saves_pushed(GC_do_blocking_inner, (ptr_t)(&my_data));
+ return my_data.client_data; /* result */
+}
+
+#if !defined(NO_DEBUGGING)
+ GC_API void GC_CALL GC_dump(void)
+ {
+ GC_printf("***Static roots:\n");
GC_print_static_roots();
- GC_printf0("\n***Heap sections:\n");
+ GC_printf("\n***Heap sections:\n");
GC_print_heap_sects();
- GC_printf0("\n***Free blocks:\n");
+ GC_printf("\n***Free blocks:\n");
GC_print_hblkfreelist();
- GC_printf0("\n***Blocks in use:\n");
+ GC_printf("\n***Blocks in use:\n");
GC_print_block_list();
- GC_printf0("\n***Finalization statistics:\n");
- GC_print_finalization_stats();
+ }
+#endif /* !NO_DEBUGGING */
+
+/* Getter functions for the public Read-only variables. */
+
+/* GC_get_gc_no() is unsynchronized and should be typically called */
+/* inside the context of GC_call_with_alloc_lock() to prevent data */
+/* races (on multiprocessors). */
+GC_API GC_word GC_CALL GC_get_gc_no(void)
+{
+ return GC_gc_no;
+}
+
+#ifdef THREADS
+ GC_API int GC_CALL GC_get_parallel(void)
+ {
+ /* GC_parallel is initialized at start-up. */
+ return GC_parallel;
+ }
+#endif
+
+/* Setter and getter functions for the public R/W function variables. */
+/* These functions are synchronized (like GC_set_warn_proc() and */
+/* GC_get_warn_proc()). */
+
+GC_API void GC_CALL GC_set_oom_fn(GC_oom_func fn)
+{
+ GC_ASSERT(fn != 0);
+ DCL_LOCK_STATE;
+ LOCK();
+ GC_oom_fn = fn;
+ UNLOCK();
+}
+
+GC_API GC_oom_func GC_CALL GC_get_oom_fn(void)
+{
+ GC_oom_func fn;
+ DCL_LOCK_STATE;
+ LOCK();
+ fn = GC_oom_fn;
+ UNLOCK();
+ return fn;
+}
+
+GC_API void GC_CALL GC_set_on_heap_resize(GC_on_heap_resize_proc fn)
+{
+ /* fn may be 0 (means no event notifier). */
+ DCL_LOCK_STATE;
+ LOCK();
+ GC_on_heap_resize = fn;
+ UNLOCK();
+}
+
+GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void)
+{
+ GC_on_heap_resize_proc fn;
+ DCL_LOCK_STATE;
+ LOCK();
+ fn = GC_on_heap_resize;
+ UNLOCK();
+ return fn;
+}
+
+GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc fn)
+{
+ /* fn may be 0 (means no finalizer notifier). */
+ DCL_LOCK_STATE;
+ LOCK();
+ GC_finalizer_notifier = fn;
+ UNLOCK();
+}
+
+GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void)
+{
+ GC_finalizer_notifier_proc fn;
+ DCL_LOCK_STATE;
+ LOCK();
+ fn = GC_finalizer_notifier;
+ UNLOCK();
+ return fn;
+}
+
+/* Setter and getter functions for the public numeric R/W variables. */
+/* It is safe to call these functions even before GC_INIT(). */
+/* These functions are unsynchronized and should be typically called */
+/* inside the context of GC_call_with_alloc_lock() (if called after */
+/* GC_INIT()) to prevent data races (unless it is guaranteed the */
+/* collector is not multi-threaded at that execution point). */
+
+GC_API void GC_CALL GC_set_find_leak(int value)
+{
+ /* value is of boolean type. */
+ GC_find_leak = value;
+}
+
+GC_API int GC_CALL GC_get_find_leak(void)
+{
+ return GC_find_leak;
}
-#endif /* NO_DEBUGGING */
+GC_API void GC_CALL GC_set_all_interior_pointers(int value)
+{
+ DCL_LOCK_STATE;
+
+ GC_all_interior_pointers = value ? 1 : 0;
+ if (GC_is_initialized) {
+ /* It is not recommended to change GC_all_interior_pointers value */
+ /* after GC is initialized but it seems GC could work correctly */
+ /* even after switching the mode. */
+ LOCK();
+ GC_initialize_offsets(); /* NOTE: this resets manual offsets as well */
+ if (!GC_all_interior_pointers)
+ GC_bl_init_no_interiors();
+ UNLOCK();
+ }
+}
+
+GC_API int GC_CALL GC_get_all_interior_pointers(void)
+{
+ return GC_all_interior_pointers;
+}
+
+GC_API void GC_CALL GC_set_finalize_on_demand(int value)
+{
+ GC_ASSERT(value != -1);
+ /* value is of boolean type. */
+ GC_finalize_on_demand = value;
+}
+
+GC_API int GC_CALL GC_get_finalize_on_demand(void)
+{
+ return GC_finalize_on_demand;
+}
+
+GC_API void GC_CALL GC_set_java_finalization(int value)
+{
+ GC_ASSERT(value != -1);
+ /* value is of boolean type. */
+ GC_java_finalization = value;
+}
+
+GC_API int GC_CALL GC_get_java_finalization(void)
+{
+ return GC_java_finalization;
+}
+
+GC_API void GC_CALL GC_set_dont_expand(int value)
+{
+ GC_ASSERT(value != -1);
+ /* value is of boolean type. */
+ GC_dont_expand = value;
+}
+
+GC_API int GC_CALL GC_get_dont_expand(void)
+{
+ return GC_dont_expand;
+}
+
+GC_API void GC_CALL GC_set_no_dls(int value)
+{
+ GC_ASSERT(value != -1);
+ /* value is of boolean type. */
+ GC_no_dls = value;
+}
+
+GC_API int GC_CALL GC_get_no_dls(void)
+{
+ return GC_no_dls;
+}
+
+GC_API void GC_CALL GC_set_non_gc_bytes(GC_word value)
+{
+ GC_non_gc_bytes = value;
+}
+
+GC_API GC_word GC_CALL GC_get_non_gc_bytes(void)
+{
+ return GC_non_gc_bytes;
+}
+
+GC_API void GC_CALL GC_set_free_space_divisor(GC_word value)
+{
+ GC_ASSERT(value > 0);
+ GC_free_space_divisor = value;
+}
+
+GC_API GC_word GC_CALL GC_get_free_space_divisor(void)
+{
+ return GC_free_space_divisor;
+}
+
+GC_API void GC_CALL GC_set_max_retries(GC_word value)
+{
+ GC_ASSERT(value != ~(GC_word)0);
+ GC_max_retries = value;
+}
+
+GC_API GC_word GC_CALL GC_get_max_retries(void)
+{
+ return GC_max_retries;
+}
+
+GC_API void GC_CALL GC_set_dont_precollect(int value)
+{
+ GC_ASSERT(value != -1);
+ /* value is of boolean type. */
+ GC_dont_precollect = value;
+}
+
+GC_API int GC_CALL GC_get_dont_precollect(void)
+{
+ return GC_dont_precollect;
+}
+
+GC_API void GC_CALL GC_set_full_freq(int value)
+{
+ GC_ASSERT(value >= 0);
+ GC_full_freq = value;
+}
+
+GC_API int GC_CALL GC_get_full_freq(void)
+{
+ return GC_full_freq;
+}
+
+GC_API void GC_CALL GC_set_time_limit(unsigned long value)
+{
+ GC_ASSERT(value != (unsigned long)-1L);
+ GC_time_limit = value;
+}
+
+GC_API unsigned long GC_CALL GC_get_time_limit(void)
+{
+ return GC_time_limit;
+}
+
+GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int value)
+{
+ GC_force_unmap_on_gcollect = (GC_bool)value;
+}
+
+GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void)
+{
+ return (int)GC_force_unmap_on_gcollect;
+}
diff --git a/boehm-gc/mkinstalldirs b/boehm-gc/mkinstalldirs
deleted file mode 100755
index f9c37afd1b8..00000000000
--- a/boehm-gc/mkinstalldirs
+++ /dev/null
@@ -1,101 +0,0 @@
-#! /bin/sh
-# mkinstalldirs --- make directory hierarchy
-# Author: Noah Friedman <friedman@prep.ai.mit.edu>
-# Created: 1993-05-16
-# Public domain
-
-# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $
-
-errstatus=0
-dirmode=""
-
-usage="\
-Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..."
-
-# process command line arguments
-while test $# -gt 0 ; do
- case "${1}" in
- -h | --help | --h* ) # -h for help
- echo "${usage}" 1>&2; exit 0 ;;
- -m ) # -m PERM arg
- shift
- test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; }
- dirmode="${1}"
- shift ;;
- -- ) shift; break ;; # stop option processing
- -* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option
- * ) break ;; # first non-opt arg
- esac
-done
-
-for file
-do
- if test -d "$file"; then
- shift
- else
- break
- fi
-done
-
-case $# in
-0) exit 0 ;;
-esac
-
-case $dirmode in
-'')
- if mkdir -p -- . 2>/dev/null; then
- echo "mkdir -p -- $*"
- exec mkdir -p -- "$@"
- fi ;;
-*)
- if mkdir -m "$dirmode" -p -- . 2>/dev/null; then
- echo "mkdir -m $dirmode -p -- $*"
- exec mkdir -m "$dirmode" -p -- "$@"
- fi ;;
-esac
-
-for file
-do
- set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
- shift
-
- pathcomp=
- for d
- do
- pathcomp="$pathcomp$d"
- case "$pathcomp" in
- -* ) pathcomp=./$pathcomp ;;
- esac
-
- if test ! -d "$pathcomp"; then
- echo "mkdir $pathcomp"
-
- mkdir "$pathcomp" || lasterr=$?
-
- if test ! -d "$pathcomp"; then
- errstatus=$lasterr
- else
- if test ! -z "$dirmode"; then
- echo "chmod $dirmode $pathcomp"
-
- lasterr=""
- chmod "$dirmode" "$pathcomp" || lasterr=$?
-
- if test ! -z "$lasterr"; then
- errstatus=$lasterr
- fi
- fi
- fi
- fi
-
- pathcomp="$pathcomp/"
- done
-done
-
-exit $errstatus
-
-# Local Variables:
-# mode: shell-script
-# sh-indentation: 3
-# End:
-# mkinstalldirs ends here
diff --git a/boehm-gc/new_hblk.c b/boehm-gc/new_hblk.c
index e5580e4ca21..e2992d445cd 100644
--- a/boehm-gc/new_hblk.c
+++ b/boehm-gc/new_hblk.c
@@ -11,253 +11,184 @@
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
- *
- * This file contains the functions:
- * ptr_t GC_build_flXXX(h, old_fl)
- * void GC_new_hblk(n)
*/
-/* Boehm, May 19, 1994 2:09 pm PDT */
-
-# include <stdio.h>
-# include "private/gc_priv.h"
+#include "private/gc_priv.h"
-#ifndef SMALL_CONFIG
/*
- * Build a free list for size 1 objects inside hblk h. Set the last link to
- * be ofl. Return a pointer tpo the first free list entry.
+ * This file contains the functions:
+ * ptr_t GC_build_flXXX(h, old_fl)
+ * void GC_new_hblk(size)
*/
-ptr_t GC_build_fl1(h, ofl)
-struct hblk *h;
-ptr_t ofl;
-{
- register word * p = h -> hb_body;
- register word * lim = (word *)(h + 1);
-
- p[0] = (word)ofl;
- p[1] = (word)(p);
- p[2] = (word)(p+1);
- p[3] = (word)(p+2);
- p += 4;
- for (; p < lim; p += 4) {
- p[0] = (word)(p-1);
- p[1] = (word)(p);
- p[2] = (word)(p+1);
- p[3] = (word)(p+2);
- };
- return((ptr_t)(p-1));
-}
-/* The same for size 2 cleared objects */
-ptr_t GC_build_fl_clear2(h, ofl)
-struct hblk *h;
-ptr_t ofl;
-{
- register word * p = h -> hb_body;
- register word * lim = (word *)(h + 1);
-
+#include <stdio.h>
+
+#ifndef SMALL_CONFIG
+ /* Build a free list for size 2 (words) cleared objects inside */
+ /* hblk h. Set the last link to be ofl. Return a pointer tpo the */
+ /* first free list entry. */
+ STATIC ptr_t GC_build_fl_clear2(struct hblk *h, ptr_t ofl)
+ {
+ word * p = (word *)(h -> hb_body);
+ word * lim = (word *)(h + 1);
+
p[0] = (word)ofl;
p[1] = 0;
p[2] = (word)p;
p[3] = 0;
p += 4;
- for (; p < lim; p += 4) {
+ for (; (word)p < (word)lim; p += 4) {
p[0] = (word)(p-2);
p[1] = 0;
p[2] = (word)p;
p[3] = 0;
};
return((ptr_t)(p-2));
-}
+ }
-/* The same for size 3 cleared objects */
-ptr_t GC_build_fl_clear3(h, ofl)
-struct hblk *h;
-ptr_t ofl;
-{
- register word * p = h -> hb_body;
- register word * lim = (word *)(h + 1) - 2;
-
- p[0] = (word)ofl;
- p[1] = 0;
- p[2] = 0;
- p += 3;
- for (; p < lim; p += 3) {
- p[0] = (word)(p-3);
- p[1] = 0;
- p[2] = 0;
- };
- return((ptr_t)(p-3));
-}
+ /* The same for size 4 cleared objects. */
+ STATIC ptr_t GC_build_fl_clear4(struct hblk *h, ptr_t ofl)
+ {
+ word * p = (word *)(h -> hb_body);
+ word * lim = (word *)(h + 1);
-/* The same for size 4 cleared objects */
-ptr_t GC_build_fl_clear4(h, ofl)
-struct hblk *h;
-ptr_t ofl;
-{
- register word * p = h -> hb_body;
- register word * lim = (word *)(h + 1);
-
p[0] = (word)ofl;
p[1] = 0;
p[2] = 0;
p[3] = 0;
p += 4;
- for (; p < lim; p += 4) {
- PREFETCH_FOR_WRITE((ptr_t)(p+64));
+ for (; (word)p < (word)lim; p += 4) {
+ PREFETCH_FOR_WRITE((ptr_t)(p+64));
p[0] = (word)(p-4);
p[1] = 0;
- CLEAR_DOUBLE(p+2);
+ CLEAR_DOUBLE(p+2);
};
return((ptr_t)(p-4));
-}
+ }
+
+ /* The same for size 2 uncleared objects. */
+ STATIC ptr_t GC_build_fl2(struct hblk *h, ptr_t ofl)
+ {
+ word * p = (word *)(h -> hb_body);
+ word * lim = (word *)(h + 1);
-/* The same for size 2 uncleared objects */
-ptr_t GC_build_fl2(h, ofl)
-struct hblk *h;
-ptr_t ofl;
-{
- register word * p = h -> hb_body;
- register word * lim = (word *)(h + 1);
-
p[0] = (word)ofl;
p[2] = (word)p;
p += 4;
- for (; p < lim; p += 4) {
+ for (; (word)p < (word)lim; p += 4) {
p[0] = (word)(p-2);
p[2] = (word)p;
};
return((ptr_t)(p-2));
-}
+ }
+
+ /* The same for size 4 uncleared objects. */
+ STATIC ptr_t GC_build_fl4(struct hblk *h, ptr_t ofl)
+ {
+ word * p = (word *)(h -> hb_body);
+ word * lim = (word *)(h + 1);
-/* The same for size 4 uncleared objects */
-ptr_t GC_build_fl4(h, ofl)
-struct hblk *h;
-ptr_t ofl;
-{
- register word * p = h -> hb_body;
- register word * lim = (word *)(h + 1);
-
p[0] = (word)ofl;
p[4] = (word)p;
p += 8;
- for (; p < lim; p += 8) {
- PREFETCH_FOR_WRITE((ptr_t)(p+64));
+ for (; (word)p < (word)lim; p += 8) {
+ PREFETCH_FOR_WRITE((ptr_t)(p+64));
p[0] = (word)(p-4);
p[4] = (word)p;
};
return((ptr_t)(p-4));
-}
-
+ }
#endif /* !SMALL_CONFIG */
-
-/* Build a free list for objects of size sz inside heap block h. */
-/* Clear objects inside h if clear is set. Add list to the end of */
-/* the free list we build. Return the new free list. */
-/* This could be called without the main GC lock, if we ensure that */
-/* there is no concurrent collection which might reclaim objects that */
-/* we have not yet allocated. */
-ptr_t GC_build_fl(h, sz, clear, list)
-struct hblk *h;
-word sz;
-GC_bool clear;
-ptr_t list;
+/* Build a free list for objects of size sz inside heap block h. */
+/* Clear objects inside h if clear is set. Add list to the end of */
+/* the free list we build. Return the new free list. */
+/* This could be called without the main GC lock, if we ensure that */
+/* there is no concurrent collection which might reclaim objects that */
+/* we have not yet allocated. */
+GC_INNER ptr_t GC_build_fl(struct hblk *h, size_t sz, GC_bool clear,
+ ptr_t list)
{
word *p, *prev;
- word *last_object; /* points to last object in new hblk */
+ word *last_object; /* points to last object in new hblk */
- /* Do a few prefetches here, just because its cheap. */
- /* If we were more serious about it, these should go inside */
- /* the loops. But write prefetches usually don't seem to */
- /* matter much. */
+ /* Do a few prefetches here, just because its cheap. */
+ /* If we were more serious about it, these should go inside */
+ /* the loops. But write prefetches usually don't seem to */
+ /* matter much. */
PREFETCH_FOR_WRITE((ptr_t)h);
PREFETCH_FOR_WRITE((ptr_t)h + 128);
PREFETCH_FOR_WRITE((ptr_t)h + 256);
PREFETCH_FOR_WRITE((ptr_t)h + 378);
- /* Handle small objects sizes more efficiently. For larger objects */
- /* the difference is less significant. */
-# ifndef SMALL_CONFIG
+# ifndef SMALL_CONFIG
+ /* Handle small objects sizes more efficiently. For larger objects */
+ /* the difference is less significant. */
switch (sz) {
- case 1: return GC_build_fl1(h, list);
case 2: if (clear) {
- return GC_build_fl_clear2(h, list);
- } else {
- return GC_build_fl2(h, list);
- }
- case 3: if (clear) {
- return GC_build_fl_clear3(h, list);
- } else {
- /* It's messy to do better than the default here. */
- break;
- }
+ return GC_build_fl_clear2(h, list);
+ } else {
+ return GC_build_fl2(h, list);
+ }
case 4: if (clear) {
- return GC_build_fl_clear4(h, list);
- } else {
- return GC_build_fl4(h, list);
- }
+ return GC_build_fl_clear4(h, list);
+ } else {
+ return GC_build_fl4(h, list);
+ }
default:
- break;
+ break;
}
-# endif /* !SMALL_CONFIG */
-
+# endif /* !SMALL_CONFIG */
+
/* Clear the page if necessary. */
if (clear) BZERO(h, HBLKSIZE);
-
+
/* Add objects to free list */
- p = &(h -> hb_body[sz]); /* second object in *h */
- prev = &(h -> hb_body[0]); /* One object behind p */
+ p = (word *)(h -> hb_body) + sz; /* second object in *h */
+ prev = (word *)(h -> hb_body); /* One object behind p */
last_object = (word *)((char *)h + HBLKSIZE);
last_object -= sz;
- /* Last place for last object to start */
+ /* Last place for last object to start */
/* make a list of all objects in *h with head as last object */
- while (p <= last_object) {
+ while ((word)p <= (word)last_object) {
/* current object's link points to last object */
obj_link(p) = (ptr_t)prev;
- prev = p;
- p += sz;
+ prev = p;
+ p += sz;
}
- p -= sz; /* p now points to last object */
+ p -= sz; /* p now points to last object */
- /*
- * put p (which is now head of list of objects in *h) as first
- * pointer in the appropriate free list for this size.
- */
- obj_link(h -> hb_body) = list;
- return ((ptr_t)p);
+ /* Put p (which is now head of list of objects in *h) as first */
+ /* pointer in the appropriate free list for this size. */
+ *(ptr_t *)h = list;
+ return ((ptr_t)p);
}
/*
- * Allocate a new heapblock for small objects of size n.
+ * Allocate a new heapblock for small objects of size gran granules.
* Add all of the heapblock's objects to the free list for objects
* of that size.
* Set all mark bits if objects are uncollectable.
* Will fail to do anything if we are out of memory.
*/
-void GC_new_hblk(sz, kind)
-register word sz;
-int kind;
+GC_INNER void GC_new_hblk(size_t gran, int kind)
{
- register struct hblk *h; /* the new heap block */
- register GC_bool clear = GC_obj_kinds[kind].ok_init;
+ struct hblk *h; /* the new heap block */
+ GC_bool clear = GC_obj_kinds[kind].ok_init;
+
+ GC_STATIC_ASSERT((sizeof (struct hblk)) == HBLKSIZE);
-# ifdef PRINTSTATS
- if ((sizeof (struct hblk)) > HBLKSIZE) {
- ABORT("HBLK SZ inconsistency");
- }
-# endif
if (GC_debugging_started) clear = TRUE;
/* Allocate a new heap block */
- h = GC_allochblk(sz, kind, 0);
+ h = GC_allochblk(GRANULES_TO_BYTES(gran), kind, 0);
if (h == 0) return;
/* Mark all objects if appropriate. */
if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(HDR(h));
/* Build the free list */
- GC_obj_kinds[kind].ok_freelist[sz] =
- GC_build_fl(h, sz, clear, GC_obj_kinds[kind].ok_freelist[sz]);
+ GC_obj_kinds[kind].ok_freelist[gran] =
+ GC_build_fl(h, GRANULES_TO_WORDS(gran), clear,
+ GC_obj_kinds[kind].ok_freelist[gran]);
}
-
diff --git a/boehm-gc/obj_map.c b/boehm-gc/obj_map.c
index d002d65b4dd..c935bf3f2ce 100644
--- a/boehm-gc/obj_map.c
+++ b/boehm-gc/obj_map.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991, 1992 by Xerox Corporation. All rights reserved.
* Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
@@ -12,136 +12,79 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-
+
+#include "private/gc_priv.h"
+
/* Routines for maintaining maps describing heap block
* layouts for various object sizes. Allows fast pointer validity checks
* and fast location of object start locations on machines (such as SPARC)
* with slow division.
*/
-
-# include "private/gc_priv.h"
-
-map_entry_type * GC_invalid_map = 0;
-
-/* Invalidate the object map associated with a block. Free blocks */
-/* are identified by invalid maps. */
-void GC_invalidate_map(hhdr)
-hdr *hhdr;
-{
- register int displ;
-
- if (GC_invalid_map == 0) {
- GC_invalid_map = (map_entry_type *)GC_scratch_alloc(MAP_SIZE);
- if (GC_invalid_map == 0) {
- GC_err_printf0(
- "Cant initialize GC_invalid_map: insufficient memory\n");
- EXIT();
- }
- for (displ = 0; displ < HBLKSIZE; displ++) {
- MAP_ENTRY(GC_invalid_map, displ) = OBJ_INVALID;
- }
- }
- hhdr -> hb_map = GC_invalid_map;
-}
/* Consider pointers that are offset bytes displaced from the beginning */
/* of an object to be valid. */
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_register_displacement(GC_word offset)
-# else
- void GC_register_displacement(offset)
- GC_word offset;
-# endif
+GC_API void GC_CALL GC_register_displacement(size_t offset)
{
DCL_LOCK_STATE;
-
- DISABLE_SIGNALS();
+
LOCK();
GC_register_displacement_inner(offset);
UNLOCK();
- ENABLE_SIGNALS();
}
-void GC_register_displacement_inner(offset)
-word offset;
+GC_INNER void GC_register_displacement_inner(size_t offset)
{
- register unsigned i;
- word map_entry = BYTES_TO_WORDS(offset);
-
if (offset >= VALID_OFFSET_SZ) {
ABORT("Bad argument to GC_register_displacement");
}
- if (map_entry > MAX_OFFSET) map_entry = OFFSET_TOO_BIG;
if (!GC_valid_offsets[offset]) {
GC_valid_offsets[offset] = TRUE;
GC_modws_valid_offsets[offset % sizeof(word)] = TRUE;
- if (!GC_all_interior_pointers) {
- for (i = 0; i <= MAXOBJSZ; i++) {
- if (GC_obj_map[i] != 0) {
- if (i == 0) {
- GC_obj_map[i][offset] = (map_entry_type)map_entry;
- } else {
- register unsigned j;
- register unsigned lb = WORDS_TO_BYTES(i);
-
- if (offset < lb) {
- for (j = offset; j < HBLKSIZE; j += lb) {
- GC_obj_map[i][j] = (map_entry_type)map_entry;
- }
- }
- }
- }
- }
- }
}
}
+#ifdef MARK_BIT_PER_GRANULE
+ /* Add a heap block map for objects of size granules to obj_map. */
+ /* Return FALSE on failure. */
+ /* A size of 0 granules is used for large objects. */
+ GC_INNER GC_bool GC_add_map_entry(size_t granules)
+ {
+ unsigned displ;
+ short * new_map;
-/* Add a heap block map for objects of size sz to obj_map. */
-/* Return FALSE on failure. */
-GC_bool GC_add_map_entry(sz)
-word sz;
-{
- register unsigned obj_start;
- register unsigned displ;
- register map_entry_type * new_map;
- word map_entry;
-
- if (sz > MAXOBJSZ) sz = 0;
- if (GC_obj_map[sz] != 0) {
+ if (granules > BYTES_TO_GRANULES(MAXOBJBYTES)) granules = 0;
+ if (GC_obj_map[granules] != 0) {
return(TRUE);
}
- new_map = (map_entry_type *)GC_scratch_alloc(MAP_SIZE);
+ new_map = (short *)GC_scratch_alloc(MAP_LEN * sizeof(short));
if (new_map == 0) return(FALSE);
-# ifdef PRINTSTATS
- GC_printf1("Adding block map for size %lu\n", (unsigned long)sz);
-# endif
- for (displ = 0; displ < HBLKSIZE; displ++) {
- MAP_ENTRY(new_map,displ) = OBJ_INVALID;
- }
- if (sz == 0) {
- for(displ = 0; displ <= HBLKSIZE; displ++) {
- if (OFFSET_VALID(displ)) {
- map_entry = BYTES_TO_WORDS(displ);
- if (map_entry > MAX_OFFSET) map_entry = OFFSET_TOO_BIG;
- MAP_ENTRY(new_map,displ) = (map_entry_type)map_entry;
- }
- }
+ GC_COND_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++) {
+ new_map[displ] = 1; /* Nonzero to get us out of marker fast path. */
+ }
} else {
- for (obj_start = 0;
- obj_start + WORDS_TO_BYTES(sz) <= HBLKSIZE;
- obj_start += WORDS_TO_BYTES(sz)) {
- for (displ = 0; displ < WORDS_TO_BYTES(sz); displ++) {
- if (OFFSET_VALID(displ)) {
- map_entry = BYTES_TO_WORDS(displ);
- if (map_entry > MAX_OFFSET) map_entry = OFFSET_TOO_BIG;
- MAP_ENTRY(new_map, obj_start + displ) =
- (map_entry_type)map_entry;
- }
- }
- }
+ for (displ = 0; displ < BYTES_TO_GRANULES(HBLKSIZE); displ++) {
+ new_map[displ] = (short)(displ % granules);
+ }
}
- GC_obj_map[sz] = new_map;
+ GC_obj_map[granules] = new_map;
return(TRUE);
+ }
+#endif /* MARK_BIT_PER_GRANULE */
+
+GC_INNER void GC_initialize_offsets(void)
+{
+ unsigned i;
+ if (GC_all_interior_pointers) {
+ for (i = 0; i < VALID_OFFSET_SZ; ++i)
+ GC_valid_offsets[i] = TRUE;
+ } else {
+ BZERO(GC_valid_offsets, sizeof(GC_valid_offsets));
+ for (i = 0; i < sizeof(word); ++i)
+ GC_modws_valid_offsets[i] = FALSE;
+ }
}
diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c
index 21d05635ab8..45d4a3102e8 100644
--- a/boehm-gc/os_dep.c
+++ b/boehm-gc/os_dep.c
@@ -14,99 +14,79 @@
* modified is included with the above copyright notice.
*/
-# include "private/gc_priv.h"
-
-# if defined(LINUX) && !defined(POWERPC)
-# include <linux/version.h>
-# if (LINUX_VERSION_CODE <= 0x10400)
- /* Ugly hack to get struct sigcontext_struct definition. Required */
- /* for some early 1.3.X releases. Will hopefully go away soon. */
- /* in some later Linux releases, asm/sigcontext.h may have to */
- /* be included instead. */
-# define __KERNEL__
-# include <asm/signal.h>
-# undef __KERNEL__
-# else
- /* Kernels prior to 2.1.1 defined struct sigcontext_struct instead of */
- /* struct sigcontext. libc6 (glibc2) uses "struct sigcontext" in */
- /* prototypes, so we have to include the top-level sigcontext.h to */
- /* make sure the former gets defined to be the latter if appropriate. */
-# include <features.h>
-# if 2 <= __GLIBC__
-# if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__
- /* glibc 2.1 no longer has sigcontext.h. But signal.h */
- /* has the right declaration for glibc 2.1. */
-# include <sigcontext.h>
-# endif /* 0 == __GLIBC_MINOR__ */
-# else /* not 2 <= __GLIBC__ */
- /* libc5 doesn't have <sigcontext.h>: go directly with the kernel */
- /* one. Check LINUX_VERSION_CODE to see which we should reference. */
-# include <asm/sigcontext.h>
-# endif /* 2 <= __GLIBC__ */
-# endif
-# endif
-# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
- && !defined(MSWINCE)
-# include <sys/types.h>
-# if !defined(MSWIN32) && !defined(SUNOS4)
-# include <unistd.h>
-# endif
-# endif
-
-# include <stdio.h>
-# if defined(MSWINCE)
-# define SIGSEGV 0 /* value is irrelevant */
+#include "private/gc_priv.h"
+
+#if defined(LINUX) && !defined(POWERPC)
+# include <linux/version.h>
+# if (LINUX_VERSION_CODE <= 0x10400)
+ /* Ugly hack to get struct sigcontext_struct definition. Required */
+ /* for some early 1.3.X releases. Will hopefully go away soon. */
+ /* in some later Linux releases, asm/sigcontext.h may have to */
+ /* be included instead. */
+# define __KERNEL__
+# include <asm/signal.h>
+# undef __KERNEL__
# else
-# include <signal.h>
-# endif
-
-/* Blatantly OS dependent routines, except for those that are related */
-/* to dynamic loading. */
-
-# if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)
-# define NEED_FIND_LIMIT
-# endif
-
-# if !defined(STACKBOTTOM) && defined(HEURISTIC2)
-# define NEED_FIND_LIMIT
-# endif
-
-# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)
-# define NEED_FIND_LIMIT
+ /* Kernels prior to 2.1.1 defined struct sigcontext_struct instead of */
+ /* struct sigcontext. libc6 (glibc2) uses "struct sigcontext" in */
+ /* prototypes, so we have to include the top-level sigcontext.h to */
+ /* make sure the former gets defined to be the latter if appropriate. */
+# include <features.h>
+# if 2 <= __GLIBC__
+# if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__
+ /* glibc 2.1 no longer has sigcontext.h. But signal.h */
+ /* has the right declaration for glibc 2.1. */
+# include <sigcontext.h>
+# endif /* 0 == __GLIBC_MINOR__ */
+# else /* not 2 <= __GLIBC__ */
+ /* libc5 doesn't have <sigcontext.h>: go directly with the kernel */
+ /* one. Check LINUX_VERSION_CODE to see which we should reference. */
+# include <asm/sigcontext.h>
+# endif /* 2 <= __GLIBC__ */
# endif
+#endif
-# if (defined(SVR4) || defined(AUX) || defined(DGUX) \
- || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
-# define NEED_FIND_LIMIT
+#if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
+ && !defined(MSWINCE) && !defined(__CC_ARM)
+# include <sys/types.h>
+# if !defined(MSWIN32)
+# include <unistd.h>
# endif
+#endif
-#if defined(FREEBSD) && defined(I386)
-# include <machine/trap.h>
-# if !defined(PCR)
-# define NEED_FIND_LIMIT
-# endif
+#include <stdio.h>
+#if defined(MSWINCE) || defined(SN_TARGET_PS3)
+# define SIGSEGV 0 /* value is irrelevant */
+#else
+# include <signal.h>
#endif
-#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \
- && !defined(NEED_FIND_LIMIT)
- /* Used by GC_init_netbsd_elf() below. */
-# define NEED_FIND_LIMIT
+#if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(NACL) \
+ || defined(SYMBIAN)
+# include <fcntl.h>
#endif
-#ifdef NEED_FIND_LIMIT
-# include <setjmp.h>
+#if defined(LINUX) || defined(LINUX_STACKBOTTOM)
+# include <ctype.h>
#endif
+/* Blatantly OS dependent routines, except for those that are related */
+/* to dynamic loading. */
+
#ifdef AMIGA
# define GC_AMIGA_DEF
-# include "AmigaOS.c"
+# include "extra/AmigaOS.c"
# undef GC_AMIGA_DEF
#endif
-#if defined(MSWIN32) || defined(MSWINCE)
-# define WIN32_LEAN_AND_MEAN
+#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
# define NOSERVICE
# include <windows.h>
+ /* It's not clear this is completely kosher under Cygwin. But it */
+ /* allows us to get a working GC_get_stack_base. */
#endif
#ifdef MACOS
@@ -117,9 +97,15 @@
# include <sys/uio.h>
# include <malloc.h> /* for locking */
#endif
-#if defined(USE_MMAP) || defined(USE_MUNMAP)
-# ifndef USE_MMAP
- --> USE_MUNMAP requires USE_MMAP
+
+#if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) || defined(IRIX5) \
+ || ((defined(USE_MMAP) || defined(USE_MUNMAP)) && !defined(USE_WINALLOC))
+# define MMAP_SUPPORTED
+#endif
+
+#if defined(MMAP_SUPPORTED) || defined(ADD_HEAP_GUARD_PAGES)
+# if defined(USE_MUNMAP) && !defined(USE_MMAP)
+# error "invalid config - USE_MUNMAP requires USE_MMAP"
# endif
# include <sys/types.h>
# include <sys/mman.h>
@@ -127,30 +113,14 @@
# include <errno.h>
#endif
-#ifdef UNIX_LIKE
-# include <fcntl.h>
-# if defined(SUNOS5SIGS) && !defined(FREEBSD)
-# include <sys/siginfo.h>
-# endif
- /* Define SETJMP and friends to be the version that restores */
- /* the signal mask. */
-# define SETJMP(env) sigsetjmp(env, 1)
-# define LONGJMP(env, val) siglongjmp(env, val)
-# define JMP_BUF sigjmp_buf
-#else
-# define SETJMP(env) setjmp(env)
-# define LONGJMP(env, val) longjmp(env, val)
-# define JMP_BUF jmp_buf
-#endif
-
#ifdef DARWIN
-/* for get_etext and friends */
-#include <mach-o/getsect.h>
+ /* for get_etext and friends */
+# include <mach-o/getsect.h>
#endif
#ifdef DJGPP
- /* Apparently necessary for djgpp 2.01. May cause problems with */
- /* other versions. */
+ /* Apparently necessary for djgpp 2.01. May cause problems with */
+ /* other versions. */
typedef long unsigned int caddr_t;
#endif
@@ -161,169 +131,319 @@
#endif
#if !defined(NO_EXECUTE_PERMISSION)
-# define OPT_PROT_EXEC PROT_EXEC
+ STATIC GC_bool GC_pages_executable = TRUE;
#else
-# define OPT_PROT_EXEC 0
+ STATIC GC_bool GC_pages_executable = FALSE;
#endif
+#define IGNORE_PAGES_EXECUTABLE 1
+ /* Undefined on GC_pages_executable real use. */
-#if defined(LINUX) && \
- (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) || !defined(SMALL_CONFIG))
-
-/* We need to parse /proc/self/maps, either to find dynamic libraries, */
-/* and/or to find the register backing store base (IA64). Do it once */
-/* here. */
+#ifdef NEED_PROC_MAPS
+/* We need to parse /proc/self/maps, either to find dynamic libraries, */
+/* and/or to find the register backing store base (IA64). Do it once */
+/* here. */
#define READ read
-/* Repeatedly perform a read call until the buffer is filled or */
-/* we encounter EOF. */
-ssize_t GC_repeat_read(int fd, char *buf, size_t count)
+/* Repeatedly perform a read call until the buffer is filled or */
+/* we encounter EOF. */
+STATIC ssize_t GC_repeat_read(int fd, char *buf, size_t count)
{
- ssize_t num_read = 0;
+ size_t num_read = 0;
ssize_t result;
-
+
+ ASSERT_CANCEL_DISABLED();
while (num_read < count) {
- result = READ(fd, buf + num_read, count - num_read);
- if (result < 0) return result;
- if (result == 0) break;
- num_read += result;
+ result = READ(fd, buf + num_read, count - num_read);
+ if (result < 0) return result;
+ if (result == 0) break;
+ num_read += result;
}
return num_read;
}
-/*
- * Apply fn to a buffer containing the contents of /proc/self/maps.
- * Return the result of fn or, if we failed, 0.
- * We currently do nothing to /proc/self/maps other than simply read
- * it. This code could be simplified if we could determine its size
- * ahead of time.
- */
+#ifdef THREADS
+ /* Determine the length of a file by incrementally reading it into a */
+ /* This would be silly to use on a file supporting lseek, but Linux */
+ /* /proc files usually do not. */
+ STATIC size_t GC_get_file_len(int f)
+ {
+ size_t total = 0;
+ ssize_t result;
+# define GET_FILE_LEN_BUF_SZ 500
+ char buf[GET_FILE_LEN_BUF_SZ];
+
+ do {
+ result = read(f, buf, GET_FILE_LEN_BUF_SZ);
+ if (result == -1) return 0;
+ total += result;
+ } while (result > 0);
+ return total;
+ }
-word GC_apply_to_maps(word (*fn)(char *))
+ STATIC size_t GC_get_maps_len(void)
+ {
+ int f = open("/proc/self/maps", O_RDONLY);
+ size_t result;
+ if (f < 0) return 0; /* treat missing file as empty */
+ result = GC_get_file_len(f);
+ close(f);
+ return result;
+ }
+#endif /* THREADS */
+
+/* Copy the contents of /proc/self/maps to a buffer in our address */
+/* space. Return the address of the buffer, or zero on failure. */
+/* This code could be simplified if we could determine its size ahead */
+/* of time. */
+GC_INNER char * GC_get_maps(void)
{
int f;
- int result;
- size_t maps_size = 4000; /* Initial guess. */
- static char init_buf[1];
- static char *maps_buf = init_buf;
+ ssize_t result;
+ static char *maps_buf = NULL;
static size_t maps_buf_sz = 1;
+ size_t maps_size, old_maps_size = 0;
+
+ /* The buffer is essentially static, so there must be a single client. */
+ GC_ASSERT(I_HOLD_LOCK());
+
+ /* Note that in the presence of threads, the maps file can */
+ /* essentially shrink asynchronously and unexpectedly as */
+ /* threads that we already think of as dead release their */
+ /* stacks. And there is no easy way to read the entire */
+ /* file atomically. This is arguably a misfeature of the */
+ /* /proc/.../maps interface. */
+
+ /* Since we don't believe the file can grow */
+ /* asynchronously, it should suffice to first determine */
+ /* the size (using lseek or read), and then to reread the */
+ /* file. If the size is inconsistent we have to retry. */
+ /* This only matters with threads enabled, and if we use */
+ /* this to locate roots (not the default). */
+
+# ifdef THREADS
+ /* Determine the initial size of /proc/self/maps. */
+ /* Note that lseek doesn't work, at least as of 2.6.15. */
+ maps_size = GC_get_maps_len();
+ if (0 == maps_size) return 0;
+# else
+ maps_size = 4000; /* Guess */
+# endif
- /* Read /proc/self/maps, growing maps_buf as necessary. */
- /* Note that we may not allocate conventionally, and */
- /* thus can't use stdio. */
- do {
- if (maps_size >= maps_buf_sz) {
- /* Grow only by powers of 2, since we leak "too small" buffers. */
- while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
- maps_buf = GC_scratch_alloc(maps_buf_sz);
- if (maps_buf == 0) return 0;
- }
- f = open("/proc/self/maps", O_RDONLY);
- if (-1 == f) return 0;
- maps_size = 0;
- do {
- result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);
- if (result <= 0) return 0;
- maps_size += result;
- } while (result == maps_buf_sz-1);
- close(f);
- } while (maps_size >= maps_buf_sz);
+ /* Read /proc/self/maps, growing maps_buf as necessary. */
+ /* Note that we may not allocate conventionally, and */
+ /* thus can't use stdio. */
+ do {
+ while (maps_size >= maps_buf_sz) {
+ /* Grow only by powers of 2, since we leak "too small" buffers.*/
+ while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
+ maps_buf = GC_scratch_alloc(maps_buf_sz);
+# ifdef THREADS
+ /* Recompute initial length, since we allocated. */
+ /* This can only happen a few times per program */
+ /* execution. */
+ maps_size = GC_get_maps_len();
+ if (0 == maps_size) return 0;
+# endif
+ if (maps_buf == 0) return 0;
+ }
+ GC_ASSERT(maps_buf_sz >= maps_size + 1);
+ f = open("/proc/self/maps", O_RDONLY);
+ if (-1 == f) return 0;
+# ifdef THREADS
+ old_maps_size = maps_size;
+# endif
+ maps_size = 0;
+ do {
+ result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);
+ if (result <= 0)
+ break;
+ maps_size += result;
+ } while ((size_t)result == maps_buf_sz-1);
+ close(f);
+ if (result <= 0)
+ return 0;
+# ifdef THREADS
+ if (maps_size > old_maps_size) {
+ GC_COND_LOG_PRINTF(
+ "Unexpected maps size growth from %lu to %lu\n",
+ (unsigned long)old_maps_size,
+ (unsigned long)maps_size);
+ ABORT("Unexpected asynchronous /proc/self/maps growth: "
+ "unregistered thread?");
+ }
+# endif
+ } while (maps_size >= maps_buf_sz || maps_size < old_maps_size);
+ /* In the single-threaded case, the second clause is false. */
maps_buf[maps_size] = '\0';
-
- /* Apply fn to result. */
- return fn(maps_buf);
-}
-
-#endif /* Need GC_apply_to_maps */
-
-#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64))
-//
-// GC_parse_map_entry parses an entry from /proc/self/maps so we can
-// locate all writable data segments that belong to shared libraries.
-// The format of one of these entries and the fields we care about
-// is as follows:
-// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
-// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
-// start end prot maj_dev
-// 0 9 18 32
-//
-// For 64 bit ABIs:
-// 0 17 34 56
-//
-// The parser is called with a pointer to the entry and the return value
-// is either NULL or is advanced to the next entry(the byte after the
-// trailing '\n'.)
-//
-#if CPP_WORDSZ == 32
-# define OFFSET_MAP_START 0
-# define OFFSET_MAP_END 9
-# define OFFSET_MAP_PROT 18
-# define OFFSET_MAP_MAJDEV 32
-# define ADDR_WIDTH 8
-#endif
-#if CPP_WORDSZ == 64
-# define OFFSET_MAP_START 0
-# define OFFSET_MAP_END 17
-# define OFFSET_MAP_PROT 34
-# define OFFSET_MAP_MAJDEV 56
-# define ADDR_WIDTH 16
-#endif
+ /* Apply fn to result. */
+ return maps_buf;
+}
/*
- * Assign various fields of the first line in buf_ptr to *start, *end,
- * *prot_buf and *maj_dev. Only *prot_buf may be set for unwritable maps.
+ * GC_parse_map_entry parses an entry from /proc/self/maps so we can
+ * locate all writable data segments that belong to shared libraries.
+ * The format of one of these entries and the fields we care about
+ * is as follows:
+ * XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
+ * ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
+ * start end prot maj_dev
+ *
+ * Note that since about august 2003 kernels, the columns no longer have
+ * fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets
+ * anywhere, which is safer anyway.
*/
-char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
- char *prot_buf, unsigned int *maj_dev)
-{
- int i;
- char *tok;
+
+/* Assign various fields of the first line in buf_ptr to (*start), */
+/* (*end), (*prot), (*maj_dev) and (*mapping_name). mapping_name may */
+/* be NULL. (*prot) and (*mapping_name) are assigned pointers into the */
+/* original buffer. */
+#if (defined(DYNAMIC_LOADING) && defined(USE_PROC_FOR_LIBRARIES)) \
+ || defined(IA64) || defined(INCLUDE_LINUX_THREAD_DESCR) \
+ || defined(REDIRECT_MALLOC)
+ GC_INNER char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
+ char **prot, unsigned int *maj_dev,
+ char **mapping_name)
+ {
+ char *start_start, *end_start, *maj_dev_start;
+ char *p;
+ char *endp;
if (buf_ptr == NULL || *buf_ptr == '\0') {
return NULL;
}
- memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4);
- /* do the protections first. */
- prot_buf[4] = '\0';
-
- if (prot_buf[1] == 'w') {/* we can skip all of this if it's not writable. */
-
- tok = buf_ptr;
- buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0';
- *start = strtoul(tok, NULL, 16);
-
- tok = buf_ptr+OFFSET_MAP_END;
- buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0';
- *end = strtoul(tok, NULL, 16);
+ p = buf_ptr;
+ while (isspace(*p)) ++p;
+ start_start = p;
+ GC_ASSERT(isxdigit(*start_start));
+ *start = (ptr_t)strtoul(start_start, &endp, 16); p = endp;
+ GC_ASSERT(*p=='-');
+
+ ++p;
+ end_start = p;
+ GC_ASSERT(isxdigit(*end_start));
+ *end = (ptr_t)strtoul(end_start, &endp, 16); p = endp;
+ GC_ASSERT(isspace(*p));
+
+ while (isspace(*p)) ++p;
+ GC_ASSERT(*p == 'r' || *p == '-');
+ *prot = p;
+ /* Skip past protection field to offset field */
+ while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
+ GC_ASSERT(isxdigit(*p));
+ /* Skip past offset field, which we ignore */
+ while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
+ maj_dev_start = p;
+ GC_ASSERT(isxdigit(*maj_dev_start));
+ *maj_dev = strtoul(maj_dev_start, NULL, 16);
+
+ if (mapping_name == 0) {
+ while (*p && *p++ != '\n');
+ } else {
+ while (*p && *p != '\n' && *p != '/' && *p != '[') p++;
+ *mapping_name = p;
+ while (*p && *p++ != '\n');
+ }
+ return p;
+ }
+#endif /* REDIRECT_MALLOC || DYNAMIC_LOADING || IA64 || ... */
+
+#if defined(IA64) || defined(INCLUDE_LINUX_THREAD_DESCR)
+ /* Try to read the backing store base from /proc/self/maps. */
+ /* Return the bounds of the writable mapping with a 0 major device, */
+ /* which includes the address passed as data. */
+ /* Return FALSE if there is no such mapping. */
+ GC_INNER GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp,
+ ptr_t *endp)
+ {
+ char *prot;
+ ptr_t my_start, my_end;
+ unsigned int maj_dev;
+ char *maps = GC_get_maps();
+ char *buf_ptr = maps;
- buf_ptr += OFFSET_MAP_MAJDEV;
- tok = buf_ptr;
- while (*buf_ptr != ':') buf_ptr++;
- *buf_ptr++ = '\0';
- *maj_dev = strtoul(tok, NULL, 16);
+ if (0 == maps) return(FALSE);
+ for (;;) {
+ buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
+ &prot, &maj_dev, 0);
+
+ if (buf_ptr == NULL) return FALSE;
+ if (prot[1] == 'w' && maj_dev == 0) {
+ if ((word)my_end > (word)addr && (word)my_start <= (word)addr) {
+ *startp = my_start;
+ *endp = my_end;
+ return TRUE;
+ }
+ }
}
+ return FALSE;
+ }
+#endif /* IA64 || INCLUDE_LINUX_THREAD_DESCR */
- while (*buf_ptr && *buf_ptr++ != '\n');
+#if defined(REDIRECT_MALLOC)
+ /* Find the text(code) mapping for the library whose name, after */
+ /* stripping the directory part, starts with nm. */
+ GC_INNER GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp)
+ {
+ size_t nm_len = strlen(nm);
+ char *prot;
+ char *map_path;
+ ptr_t my_start, my_end;
+ unsigned int maj_dev;
+ char *maps = GC_get_maps();
+ char *buf_ptr = maps;
+
+ if (0 == maps) return(FALSE);
+ for (;;) {
+ buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
+ &prot, &maj_dev, &map_path);
+
+ if (buf_ptr == NULL) return FALSE;
+ if (prot[0] == 'r' && prot[1] == '-' && prot[2] == 'x') {
+ 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 != '/' && (word)p >= (word)map_path) --p;
+ ++p;
+ if (strncmp(nm, p, nm_len) == 0) {
+ *startp = my_start;
+ *endp = my_end;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+ }
+#endif /* REDIRECT_MALLOC */
- return buf_ptr;
-}
+#ifdef IA64
+ static ptr_t backing_store_base_from_proc(void)
+ {
+ ptr_t my_start, my_end;
+ if (!GC_enclosing_mapping(GC_save_regs_in_stack(), &my_start, &my_end)) {
+ GC_COND_LOG_PRINTF("Failed to find backing store base from /proc\n");
+ return 0;
+ }
+ return my_start;
+ }
+#endif
-#endif /* Need to parse /proc/self/maps. */
+#endif /* NEED_PROC_MAPS */
#if defined(SEARCH_FOR_DATA_START)
- /* The I386 case can be handled without a search. The Alpha case */
- /* used to be handled differently as well, but the rules changed */
- /* for recent Linux versions. This seems to be the easiest way to */
- /* cover all versions. */
-
-# ifdef LINUX
- /* Some Linux distributions arrange to define __data_start. Some */
- /* define data_start as a weak symbol. The latter is technically */
- /* broken, since the user program may define data_start, in which */
- /* case we lose. Nonetheless, we try both, prefering __data_start. */
- /* We assume gcc-compatible pragmas. */
+ /* The I386 case can be handled without a search. The Alpha case */
+ /* used to be handled differently as well, but the rules changed */
+ /* for recent Linux versions. This seems to be the easiest way to */
+ /* cover all versions. */
+
+# if defined(LINUX) || defined(HURD)
+ /* Some Linux distributions arrange to define __data_start. Some */
+ /* define data_start as a weak symbol. The latter is technically */
+ /* broken, since the user program may define data_start, in which */
+ /* case we lose. Nonetheless, we try both, preferring __data_start.*/
+ /* We assume gcc-compatible pragmas. */
# pragma weak __data_start
extern int __data_start[];
# pragma weak data_start
@@ -331,73 +451,168 @@ char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
# endif /* LINUX */
extern int _end[];
- ptr_t GC_data_start;
+ ptr_t GC_data_start = NULL;
- void GC_init_linux_data_start()
- {
- extern ptr_t GC_find_limit();
+ ptr_t GC_find_limit(ptr_t, GC_bool);
-# ifdef LINUX
- /* Try the easy approaches first: */
+ GC_INNER void GC_init_linux_data_start(void)
+ {
+# if defined(LINUX) || defined(HURD)
+ /* Try the easy approaches first: */
if ((ptr_t)__data_start != 0) {
- GC_data_start = (ptr_t)(__data_start);
- return;
+ GC_data_start = (ptr_t)(__data_start);
+ return;
}
if ((ptr_t)data_start != 0) {
- GC_data_start = (ptr_t)(data_start);
- return;
+ GC_data_start = (ptr_t)(data_start);
+ return;
}
# endif /* LINUX */
+
+ if (GC_no_dls) {
+ /* Not needed, avoids the SIGSEGV caused by */
+ /* GC_find_limit which complicates debugging. */
+ GC_data_start = (ptr_t)_end; /* set data root size to 0 */
+ return;
+ }
+
GC_data_start = GC_find_limit((ptr_t)(_end), FALSE);
}
-#endif
+#endif /* SEARCH_FOR_DATA_START */
-# ifdef ECOS
+#ifdef ECOS
# ifndef ECOS_GC_MEMORY_SIZE
-# define ECOS_GC_MEMORY_SIZE (448 * 1024)
+# define ECOS_GC_MEMORY_SIZE (448 * 1024)
# endif /* ECOS_GC_MEMORY_SIZE */
-// setjmp() function, as described in ANSI para 7.6.1.1
-#undef SETJMP
-#define SETJMP( __env__ ) hal_setjmp( __env__ )
+ /* FIXME: This is a simple way of allocating memory which is */
+ /* compatible with ECOS early releases. Later releases use a more */
+ /* sophisticated means of allocating memory than this simple static */
+ /* allocator, but this method is at least bound to work. */
+ static char ecos_gc_memory[ECOS_GC_MEMORY_SIZE];
+ static char *ecos_gc_brk = ecos_gc_memory;
-// FIXME: This is a simple way of allocating memory which is
-// compatible with ECOS early releases. Later releases use a more
-// sophisticated means of allocating memory than this simple static
-// allocator, but this method is at least bound to work.
-static char memory[ECOS_GC_MEMORY_SIZE];
-static char *brk = memory;
+ static void *tiny_sbrk(ptrdiff_t increment)
+ {
+ void *p = ecos_gc_brk;
+ ecos_gc_brk += increment;
+ if ((word)ecos_gc_brk > (word)(ecos_gc_memory + sizeof(ecos_gc_memory))) {
+ ecos_gc_brk -= increment;
+ return NULL;
+ }
+ return p;
+ }
+# define sbrk tiny_sbrk
+#endif /* ECOS */
-static void *tiny_sbrk(ptrdiff_t increment)
-{
- void *p = brk;
+#if defined(NETBSD) && defined(__ELF__)
+ ptr_t GC_data_start = NULL;
+ ptr_t GC_find_limit(ptr_t, GC_bool);
- brk += increment;
+ extern char **environ;
- if (brk > memory + sizeof memory)
- {
- brk -= increment;
- return NULL;
+ GC_INNER void GC_init_netbsd_elf(void)
+ {
+ /* This may need to be environ, without the underscore, for */
+ /* some versions. */
+ GC_data_start = GC_find_limit((ptr_t)&environ, FALSE);
+ }
+#endif /* NETBSD */
+
+#ifdef OPENBSD
+ static struct sigaction old_segv_act;
+ STATIC sigjmp_buf GC_jmp_buf_openbsd;
+
+# ifdef THREADS
+# include <sys/syscall.h>
+ extern sigset_t __syscall(quad_t, ...);
+# endif
+
+ /* Don't use GC_find_limit() because siglongjmp() outside of the */
+ /* signal handler by-passes our userland pthreads lib, leaving */
+ /* SIGSEGV and SIGPROF masked. Instead, use this custom one that */
+ /* works-around the issues. */
+
+ STATIC void GC_fault_handler_openbsd(int sig GC_ATTR_UNUSED)
+ {
+ siglongjmp(GC_jmp_buf_openbsd, 1);
+ }
+
+ /* Return the first non-addressible location > p or bound. */
+ /* Requires the allocation lock. */
+ STATIC ptr_t GC_find_limit_openbsd(ptr_t p, ptr_t bound)
+ {
+ static volatile ptr_t result;
+ /* Safer if static, since otherwise it may not be */
+ /* preserved across the longjmp. Can safely be */
+ /* static since it's only called with the */
+ /* allocation lock held. */
+
+ struct sigaction act;
+ size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
+ GC_ASSERT(I_HOLD_LOCK());
+
+ act.sa_handler = GC_fault_handler_openbsd;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_NODEFER | SA_RESTART;
+ /* act.sa_restorer is deprecated and should not be initialized. */
+ sigaction(SIGSEGV, &act, &old_segv_act);
+
+ if (sigsetjmp(GC_jmp_buf_openbsd, 1) == 0) {
+ result = (ptr_t)((word)p & ~(pgsz-1));
+ for (;;) {
+ result += pgsz;
+ if ((word)result >= (word)bound) {
+ result = bound;
+ break;
+ }
+ GC_noop1((word)(*result));
+ }
}
- return p;
-}
-#define sbrk tiny_sbrk
-# endif /* ECOS */
+# ifdef THREADS
+ /* Due to the siglongjump we need to manually unmask SIGPROF. */
+ __syscall(SYS_sigprocmask, SIG_UNBLOCK, sigmask(SIGPROF));
+# endif
-#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
- ptr_t GC_data_start;
+ sigaction(SIGSEGV, &old_segv_act, 0);
+ return(result);
+ }
- void GC_init_netbsd_elf()
+ /* Return first addressable location > p or bound. */
+ /* Requires the allocation lock. */
+ STATIC ptr_t GC_skip_hole_openbsd(ptr_t p, ptr_t bound)
{
- extern ptr_t GC_find_limit();
- extern char **environ;
- /* This may need to be environ, without the underscore, for */
- /* some versions. */
- GC_data_start = GC_find_limit((ptr_t)&environ, FALSE);
+ static volatile ptr_t result;
+ static volatile int firstpass;
+
+ struct sigaction act;
+ size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
+ GC_ASSERT(I_HOLD_LOCK());
+
+ act.sa_handler = GC_fault_handler_openbsd;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_NODEFER | SA_RESTART;
+ /* act.sa_restorer is deprecated and should not be initialized. */
+ sigaction(SIGSEGV, &act, &old_segv_act);
+
+ firstpass = 1;
+ result = (ptr_t)((word)p & ~(pgsz-1));
+ if (sigsetjmp(GC_jmp_buf_openbsd, 1) != 0 || firstpass) {
+ firstpass = 0;
+ result += pgsz;
+ if ((word)result >= (word)bound) {
+ result = bound;
+ } else {
+ GC_noop1((word)(*result));
+ }
+ }
+
+ sigaction(SIGSEGV, &old_segv_act, 0);
+ return(result);
}
-#endif
+#endif /* OPENBSD */
# ifdef OS2
@@ -412,19 +627,19 @@ struct exe_hdr {
};
#define E_MAGIC(x) (x).magic_number
-#define EMAGIC 0x5A4D
+#define EMAGIC 0x5A4D
#define E_LFANEW(x) (x).new_exe_offset
struct e32_exe {
- unsigned char magic_number[2];
- unsigned char byte_order;
- unsigned char word_order;
+ unsigned char magic_number[2];
+ unsigned char byte_order;
+ unsigned char word_order;
unsigned long exe_format_level;
- unsigned short cpu;
+ unsigned short cpu;
unsigned short os;
unsigned long padding1[13];
unsigned long object_table_offset;
- unsigned long object_count;
+ unsigned long object_count;
unsigned long padding2[31];
};
@@ -442,11 +657,11 @@ struct e32_exe {
#define E32_OBJCNT(x) (x).object_count
struct o32_obj {
- unsigned long size;
+ unsigned long size;
unsigned long base;
- unsigned long flags;
+ unsigned long flags;
unsigned long pagemap;
- unsigned long mapsize;
+ unsigned long mapsize;
unsigned long reserved;
};
@@ -480,359 +695,299 @@ struct o32_obj {
# define INCL_DOSMEMMGR
# include <os2.h>
+# endif /* OS/2 */
-/* Disable and enable signals during nontrivial allocations */
-
-void GC_disable_signals(void)
-{
- ULONG nest;
-
- DosEnterMustComplete(&nest);
- if (nest != 1) ABORT("nested GC_disable_signals");
-}
-
-void GC_enable_signals(void)
-{
- ULONG nest;
-
- DosExitMustComplete(&nest);
- if (nest != 0) ABORT("GC_enable_signals");
-}
-
-
-# else
-
-# if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
- && !defined(MSWINCE) \
- && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) \
- && !defined(NOSYS) && !defined(ECOS)
-
-# if defined(sigmask) && !defined(UTS4) && !defined(HURD)
- /* Use the traditional BSD interface */
-# define SIGSET_T int
-# define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
-# define SIG_FILL(set) (set) = 0x7fffffff
- /* Setting the leading bit appears to provoke a bug in some */
- /* longjmp implementations. Most systems appear not to have */
- /* a signal 32. */
-# define SIGSETMASK(old, new) (old) = sigsetmask(new)
-# else
- /* Use POSIX/SYSV interface */
-# define SIGSET_T sigset_t
-# define SIG_DEL(set, signal) sigdelset(&(set), (signal))
-# define SIG_FILL(set) sigfillset(&set)
-# define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
-# endif
-
-static GC_bool mask_initialized = FALSE;
-
-static SIGSET_T new_mask;
-
-static SIGSET_T old_mask;
-
-static SIGSET_T dummy;
-
-#if defined(PRINTSTATS) && !defined(THREADS)
-# define CHECK_SIGNALS
- int GC_sig_disabled = 0;
-#endif
-
-void GC_disable_signals()
-{
- if (!mask_initialized) {
- SIG_FILL(new_mask);
-
- SIG_DEL(new_mask, SIGSEGV);
- SIG_DEL(new_mask, SIGILL);
- SIG_DEL(new_mask, SIGQUIT);
-# ifdef SIGBUS
- SIG_DEL(new_mask, SIGBUS);
-# endif
-# ifdef SIGIOT
- SIG_DEL(new_mask, SIGIOT);
-# endif
-# ifdef SIGEMT
- SIG_DEL(new_mask, SIGEMT);
-# endif
-# ifdef SIGTRAP
- SIG_DEL(new_mask, SIGTRAP);
-# endif
- mask_initialized = TRUE;
- }
-# ifdef CHECK_SIGNALS
- if (GC_sig_disabled != 0) ABORT("Nested disables");
- GC_sig_disabled++;
-# endif
- SIGSETMASK(old_mask,new_mask);
-}
-
-void GC_enable_signals()
-{
-# ifdef CHECK_SIGNALS
- if (GC_sig_disabled != 1) ABORT("Unmatched enable");
- GC_sig_disabled--;
-# endif
- SIGSETMASK(dummy,old_mask);
-}
-
-# endif /* !PCR */
+/* Find the page size */
+GC_INNER word GC_page_size = 0;
-# endif /*!OS/2 */
+#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+# ifndef VER_PLATFORM_WIN32_CE
+# define VER_PLATFORM_WIN32_CE 3
+# endif
-/* Ivan Demakov: simplest way (to me) */
-#if defined (DOS4GW)
- void GC_disable_signals() { }
- void GC_enable_signals() { }
-#endif
+# if defined(MSWINCE) && defined(THREADS)
+ GC_INNER GC_bool GC_dont_query_stack_min = FALSE;
+# endif
-/* Find the page size */
-word GC_page_size;
+ GC_INNER SYSTEM_INFO GC_sysinfo;
-# if defined(MSWIN32) || defined(MSWINCE)
- void GC_setpagesize()
+ GC_INNER void GC_setpagesize(void)
{
GetSystemInfo(&GC_sysinfo);
GC_page_size = GC_sysinfo.dwPageSize;
- }
-
-# else
-# if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP) \
- || defined(USE_MUNMAP)
- void GC_setpagesize()
- {
- GC_page_size = GETPAGESIZE();
- }
-# else
- /* It's acceptable to fake it. */
- void GC_setpagesize()
- {
- GC_page_size = HBLKSIZE;
- }
+# if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
+ {
+ OSVERSIONINFO verInfo;
+ /* Check the current WinCE version. */
+ verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if (!GetVersionEx(&verInfo))
+ ABORT("GetVersionEx failed");
+ if (verInfo.dwPlatformId == VER_PLATFORM_WIN32_CE &&
+ verInfo.dwMajorVersion < 6) {
+ /* Only the first 32 MB of address space belongs to the */
+ /* current process (unless WinCE 6.0+ or emulation). */
+ GC_sysinfo.lpMaximumApplicationAddress = (LPVOID)((word)32 << 20);
+# ifdef THREADS
+ /* On some old WinCE versions, it's observed that */
+ /* VirtualQuery calls don't work properly when used to */
+ /* get thread current stack committed minimum. */
+ if (verInfo.dwMajorVersion < 5)
+ GC_dont_query_stack_min = TRUE;
+# endif
+ }
+ }
# endif
-# endif
+ }
-/*
- * Find the base of the stack.
- * Used only in single-threaded environment.
- * With threads, GC_mark_roots needs to know how to do this.
- * Called with allocator lock held.
- */
-# if defined(MSWIN32) || defined(MSWINCE)
-# define is_writable(prot) ((prot) == PAGE_READWRITE \
- || (prot) == PAGE_WRITECOPY \
- || (prot) == PAGE_EXECUTE_READWRITE \
- || (prot) == PAGE_EXECUTE_WRITECOPY)
-/* Return the number of bytes that are writable starting at p. */
-/* The pointer p is assumed to be page aligned. */
-/* If base is not 0, *base becomes the beginning of the */
-/* allocation region containing p. */
-word GC_get_writable_length(ptr_t p, ptr_t *base)
-{
- MEMORY_BASIC_INFORMATION buf;
- word result;
- word protect;
-
- result = VirtualQuery(p, &buf, sizeof(buf));
- if (result != sizeof(buf)) ABORT("Weird VirtualQuery result");
- if (base != 0) *base = (ptr_t)(buf.AllocationBase);
- protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE));
- if (!is_writable(protect)) {
+# ifndef CYGWIN32
+# define is_writable(prot) ((prot) == PAGE_READWRITE \
+ || (prot) == PAGE_WRITECOPY \
+ || (prot) == PAGE_EXECUTE_READWRITE \
+ || (prot) == PAGE_EXECUTE_WRITECOPY)
+ /* Return the number of bytes that are writable starting at p. */
+ /* The pointer p is assumed to be page aligned. */
+ /* If base is not 0, *base becomes the beginning of the */
+ /* allocation region containing p. */
+ STATIC word GC_get_writable_length(ptr_t p, ptr_t *base)
+ {
+ MEMORY_BASIC_INFORMATION buf;
+ word result;
+ word protect;
+
+ result = VirtualQuery(p, &buf, sizeof(buf));
+ if (result != sizeof(buf)) ABORT("Weird VirtualQuery result");
+ if (base != 0) *base = (ptr_t)(buf.AllocationBase);
+ protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE));
+ if (!is_writable(protect)) {
return(0);
+ }
+ if (buf.State != MEM_COMMIT) return(0);
+ return(buf.RegionSize);
}
- if (buf.State != MEM_COMMIT) return(0);
- return(buf.RegionSize);
-}
-ptr_t GC_get_stack_base()
-{
- int dummy;
- ptr_t sp = (ptr_t)(&dummy);
- ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
- word size = GC_get_writable_length(trunc_sp, 0);
-
- return(trunc_sp + size);
-}
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
+ {
+ ptr_t trunc_sp = (ptr_t)((word)GC_approx_sp() & ~(GC_page_size - 1));
+ /* FIXME: This won't work if called from a deeply recursive */
+ /* client code (and the committed stack space has grown). */
+ word size = GC_get_writable_length(trunc_sp, 0);
+ GC_ASSERT(size != 0);
+ sb -> mem_base = trunc_sp + size;
+ return GC_SUCCESS;
+ }
+# else /* CYGWIN32 */
+ /* An alternate version for Cygwin (adapted from Dave Korn's */
+ /* gcc version of boehm-gc). */
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
+ {
+ void * _tlsbase;
+ __asm__ ("movl %%fs:4, %0"
+ : "=r" (_tlsbase));
+ sb -> mem_base = _tlsbase;
+ return GC_SUCCESS;
+ }
+# endif /* CYGWIN32 */
+# define HAVE_GET_STACK_BASE
-# endif /* MS Windows */
+#else /* !MSWIN32 */
+ GC_INNER void GC_setpagesize(void)
+ {
+# if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP)
+ GC_page_size = GETPAGESIZE();
+ if (!GC_page_size) ABORT("getpagesize failed");
+# else
+ /* It's acceptable to fake it. */
+ GC_page_size = HBLKSIZE;
+# endif
+ }
+#endif /* !MSWIN32 */
-# ifdef BEOS
+#ifdef BEOS
# include <kernel/OS.h>
-ptr_t GC_get_stack_base(){
- thread_info th;
- get_thread_info(find_thread(NULL),&th);
- return th.stack_end;
-}
-# endif /* BEOS */
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
+ {
+ thread_info th;
+ get_thread_info(find_thread(NULL),&th);
+ sb->mem_base = th.stack_end;
+ return GC_SUCCESS;
+ }
+# define HAVE_GET_STACK_BASE
+#endif /* BEOS */
-# ifdef OS2
-
-ptr_t GC_get_stack_base()
-{
- PTIB ptib;
+#ifdef OS2
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
+ {
+ PTIB ptib; /* thread information block */
PPIB ppib;
-
if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
- GC_err_printf0("DosGetInfoBlocks failed\n");
- ABORT("DosGetInfoBlocks failed\n");
+ ABORT("DosGetInfoBlocks failed");
}
- return((ptr_t)(ptib -> tib_pstacklimit));
-}
-
-# endif /* OS2 */
+ sb->mem_base = ptib->tib_pstacklimit;
+ return GC_SUCCESS;
+ }
+# define HAVE_GET_STACK_BASE
+#endif /* OS2 */
# ifdef AMIGA
# define GC_AMIGA_SB
-# include "AmigaOS.c"
+# include "extra/AmigaOS.c"
# undef GC_AMIGA_SB
# endif /* AMIGA */
# if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
-# ifdef __STDC__
- typedef void (*handler)(int);
-# else
- typedef void (*handler)();
-# endif
+ typedef void (*GC_fault_handler_t)(int);
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
- || defined(HURD) || defined(NETBSD)
- static struct sigaction old_segv_act;
-# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \
- || defined(HURD) || defined(NETBSD)
- static struct sigaction old_bus_act;
-# endif
-# else
- static handler old_segv_handler, old_bus_handler;
-# endif
-
-# ifdef __STDC__
- void GC_set_and_save_fault_handler(handler h)
+ || defined(HURD) || defined(NETBSD)
+ static struct sigaction old_segv_act;
+# if defined(_sigargs) /* !Irix6.x */ \
+ || defined(HURD) || defined(NETBSD)
+ static struct sigaction old_bus_act;
+# endif
# else
- void GC_set_and_save_fault_handler(h)
- handler h;
+ static GC_fault_handler_t old_segv_handler;
+# ifdef SIGBUS
+ static GC_fault_handler_t old_bus_handler;
+# endif
# endif
+
+ GC_INNER void GC_set_and_save_fault_handler(GC_fault_handler_t h)
{
-# if defined(SUNOS5SIGS) || defined(IRIX5) \
- || defined(OSF1) || defined(HURD) || defined(NETBSD)
- struct sigaction act;
-
- act.sa_handler = h;
-# if 0 /* Was necessary for Solaris 2.3 and very temporary */
- /* NetBSD bugs. */
- act.sa_flags = SA_RESTART | SA_NODEFER;
+# if defined(SUNOS5SIGS) || defined(IRIX5) \
+ || defined(OSF1) || defined(HURD) || defined(NETBSD)
+ struct sigaction act;
+
+ act.sa_handler = h;
+# ifdef SIGACTION_FLAGS_NODEFER_HACK
+ /* Was necessary for Solaris 2.3 and very temporary */
+ /* NetBSD bugs. */
+ act.sa_flags = SA_RESTART | SA_NODEFER;
# else
- act.sa_flags = SA_RESTART;
-# endif
-
- (void) sigemptyset(&act.sa_mask);
-# ifdef GC_IRIX_THREADS
- /* Older versions have a bug related to retrieving and */
- /* and setting a handler at the same time. */
- (void) sigaction(SIGSEGV, 0, &old_segv_act);
- (void) sigaction(SIGSEGV, &act, 0);
-# else
- (void) sigaction(SIGSEGV, &act, &old_segv_act);
-# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
- || defined(HPUX) || defined(HURD) || defined(NETBSD)
- /* Under Irix 5.x or HP/UX, we may get SIGBUS. */
- /* Pthreads doesn't exist under Irix 5.x, so we */
- /* don't have to worry in the threads case. */
- (void) sigaction(SIGBUS, &act, &old_bus_act);
-# endif
-# endif /* GC_IRIX_THREADS */
-# else
- old_segv_handler = signal(SIGSEGV, h);
-# ifdef SIGBUS
- old_bus_handler = signal(SIGBUS, h);
-# endif
-# endif
+ act.sa_flags = SA_RESTART;
+# endif
+
+ (void) sigemptyset(&act.sa_mask);
+ /* act.sa_restorer is deprecated and should not be initialized. */
+# ifdef GC_IRIX_THREADS
+ /* Older versions have a bug related to retrieving and */
+ /* and setting a handler at the same time. */
+ (void) sigaction(SIGSEGV, 0, &old_segv_act);
+ (void) sigaction(SIGSEGV, &act, 0);
+# else
+ (void) sigaction(SIGSEGV, &act, &old_segv_act);
+# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
+ || defined(HURD) || defined(NETBSD)
+ /* Under Irix 5.x or HP/UX, we may get SIGBUS. */
+ /* Pthreads doesn't exist under Irix 5.x, so we */
+ /* don't have to worry in the threads case. */
+ (void) sigaction(SIGBUS, &act, &old_bus_act);
+# endif
+# endif /* GC_IRIX_THREADS */
+# else
+ old_segv_handler = signal(SIGSEGV, h);
+# ifdef SIGBUS
+ old_bus_handler = signal(SIGBUS, h);
+# endif
+# endif
}
# endif /* NEED_FIND_LIMIT || UNIX_LIKE */
-# ifdef NEED_FIND_LIMIT
- /* Some tools to implement HEURISTIC2 */
-# define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */
- /* static */ JMP_BUF GC_jmp_buf;
-
- /*ARGSUSED*/
- void GC_fault_handler(sig)
- int sig;
+# if defined(NEED_FIND_LIMIT) \
+ || (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))
+ /* Some tools to implement HEURISTIC2 */
+# define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */
+
+ STATIC void GC_fault_handler(int sig GC_ATTR_UNUSED)
{
LONGJMP(GC_jmp_buf, 1);
}
- void GC_setup_temporary_fault_handler()
+ GC_INNER void GC_setup_temporary_fault_handler(void)
{
- GC_set_and_save_fault_handler(GC_fault_handler);
+ /* Handler is process-wide, so this should only happen in */
+ /* one thread at a time. */
+ GC_ASSERT(I_HOLD_LOCK());
+ GC_set_and_save_fault_handler(GC_fault_handler);
}
-
- void GC_reset_fault_handler()
+
+ GC_INNER void GC_reset_fault_handler(void)
{
# if defined(SUNOS5SIGS) || defined(IRIX5) \
- || defined(OSF1) || defined(HURD) || defined(NETBSD)
- (void) sigaction(SIGSEGV, &old_segv_act, 0);
-# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
- || defined(HPUX) || defined(HURD) || defined(NETBSD)
- (void) sigaction(SIGBUS, &old_bus_act, 0);
-# endif
+ || defined(OSF1) || defined(HURD) || defined(NETBSD)
+ (void) sigaction(SIGSEGV, &old_segv_act, 0);
+# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
+ || defined(HURD) || defined(NETBSD)
+ (void) sigaction(SIGBUS, &old_bus_act, 0);
+# endif
# else
- (void) signal(SIGSEGV, old_segv_handler);
-# ifdef SIGBUS
- (void) signal(SIGBUS, old_bus_handler);
-# endif
+ (void) signal(SIGSEGV, old_segv_handler);
+# ifdef SIGBUS
+ (void) signal(SIGBUS, old_bus_handler);
+# endif
# endif
}
- /* Return the first nonaddressible location > p (up) or */
- /* the smallest location q s.t. [q,p) is addressable (!up). */
- /* We assume that p (up) or p-1 (!up) is addressable. */
- ptr_t GC_find_limit(p, up)
- ptr_t p;
- GC_bool up;
+ /* Return the first non-addressable location > p (up) or */
+ /* the smallest location q s.t. [q,p) is addressable (!up). */
+ /* We assume that p (up) or p-1 (!up) is addressable. */
+ /* Requires allocation lock. */
+ STATIC ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound)
{
- static VOLATILE ptr_t result;
- /* Needs to be static, since otherwise it may not be */
- /* preserved across the longjmp. Can safely be */
- /* static since it's only called once, with the */
- /* allocation lock held. */
-
-
- GC_setup_temporary_fault_handler();
- if (SETJMP(GC_jmp_buf) == 0) {
- result = (ptr_t)(((word)(p))
- & ~(MIN_PAGE_SIZE-1));
- for (;;) {
- if (up) {
- result += MIN_PAGE_SIZE;
- } else {
- result -= MIN_PAGE_SIZE;
- }
- GC_noop1((word)(*result));
- }
- }
- GC_reset_fault_handler();
- if (!up) {
- result += MIN_PAGE_SIZE;
- }
- return(result);
+ static volatile ptr_t result;
+ /* Safer if static, since otherwise it may not be */
+ /* preserved across the longjmp. Can safely be */
+ /* static since it's only called with the */
+ /* allocation lock held. */
+
+ GC_ASSERT(I_HOLD_LOCK());
+ GC_setup_temporary_fault_handler();
+ if (SETJMP(GC_jmp_buf) == 0) {
+ result = (ptr_t)(((word)(p))
+ & ~(MIN_PAGE_SIZE-1));
+ for (;;) {
+ if (up) {
+ result += MIN_PAGE_SIZE;
+ if ((word)result >= (word)bound) {
+ result = bound;
+ break;
+ }
+ } else {
+ result -= MIN_PAGE_SIZE;
+ if ((word)result <= (word)bound) {
+ result = bound - MIN_PAGE_SIZE;
+ /* This is to compensate */
+ /* further result increment (we */
+ /* do not modify "up" variable */
+ /* since it might be clobbered */
+ /* by setjmp otherwise). */
+ break;
+ }
+ }
+ GC_noop1((word)(*result));
+ }
+ }
+ GC_reset_fault_handler();
+ if (!up) {
+ result += MIN_PAGE_SIZE;
+ }
+ return(result);
}
-# endif
-#if defined(ECOS) || defined(NOSYS)
- ptr_t GC_get_stack_base()
- {
- return STACKBOTTOM;
- }
-#endif
+ ptr_t GC_find_limit(ptr_t p, GC_bool up)
+ {
+ return GC_find_limit_with_bound(p, up, up ? (ptr_t)(word)(-1) : 0);
+ }
+# endif /* NEED_FIND_LIMIT || USE_PROC_FOR_LIBRARIES */
#ifdef HPUX_STACKBOTTOM
#include <sys/param.h>
#include <sys/pstat.h>
- ptr_t GC_get_register_stack_base(void)
+ GC_INNER ptr_t GC_get_register_stack_base(void)
{
struct pst_vm_status vm_status;
@@ -852,221 +1007,454 @@ ptr_t GC_get_stack_base()
#ifdef LINUX_STACKBOTTOM
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <ctype.h>
+# include <sys/types.h>
+# include <sys/stat.h>
-# define STAT_SKIP 27 /* Number of fields preceding startstack */
- /* field in /proc/self/stat */
+# define STAT_SKIP 27 /* Number of fields preceding startstack */
+ /* field in /proc/self/stat */
-# pragma weak __libc_stack_end
- extern ptr_t __libc_stack_end;
+# ifdef USE_LIBC_PRIVATES
+# pragma weak __libc_stack_end
+ extern ptr_t __libc_stack_end;
+# endif
# ifdef IA64
- /* Try to read the backing store base from /proc/self/maps. */
- /* We look for the writable mapping with a 0 major device, */
- /* which is as close to our frame as possible, but below it.*/
- static word backing_store_base_from_maps(char *maps)
- {
- char prot_buf[5];
- char *buf_ptr = maps;
- word start, end;
- unsigned int maj_dev;
- word current_best = 0;
- word dummy;
-
- for (;;) {
- buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
- if (buf_ptr == NULL) return current_best;
- if (prot_buf[1] == 'w' && maj_dev == 0) {
- if (end < (word)(&dummy) && start > current_best) current_best = start;
- }
- }
- return current_best;
- }
+# ifdef USE_LIBC_PRIVATES
+# pragma weak __libc_ia64_register_backing_store_base
+ extern ptr_t __libc_ia64_register_backing_store_base;
+# endif
- static word backing_store_base_from_proc(void)
+ GC_INNER ptr_t GC_get_register_stack_base(void)
{
- return GC_apply_to_maps(backing_store_base_from_maps);
- }
-
-# pragma weak __libc_ia64_register_backing_store_base
- extern ptr_t __libc_ia64_register_backing_store_base;
+ ptr_t result;
- ptr_t GC_get_register_stack_base(void)
- {
- if (0 != &__libc_ia64_register_backing_store_base
- && 0 != __libc_ia64_register_backing_store_base) {
- /* Glibc 2.2.4 has a bug such that for dynamically linked */
- /* executables __libc_ia64_register_backing_store_base is */
- /* defined but uninitialized during constructor calls. */
- /* Hence we check for both nonzero address and value. */
- return __libc_ia64_register_backing_store_base;
- } else {
- word result = backing_store_base_from_proc();
- if (0 == result) {
- /* Use dumb heuristics. Works only for default configuration. */
- result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
- result += BACKING_STORE_ALIGNMENT - 1;
- result &= ~(BACKING_STORE_ALIGNMENT - 1);
- /* Verify that it's at least readable. If not, we goofed. */
- GC_noop1(*(word *)result);
- }
- return (ptr_t)result;
+# ifdef USE_LIBC_PRIVATES
+ if (0 != &__libc_ia64_register_backing_store_base
+ && 0 != __libc_ia64_register_backing_store_base) {
+ /* Glibc 2.2.4 has a bug such that for dynamically linked */
+ /* executables __libc_ia64_register_backing_store_base is */
+ /* defined but uninitialized during constructor calls. */
+ /* Hence we check for both nonzero address and value. */
+ return __libc_ia64_register_backing_store_base;
+ }
+# endif
+ result = backing_store_base_from_proc();
+ if (0 == result) {
+ result = GC_find_limit(GC_save_regs_in_stack(), FALSE);
+ /* Now seems to work better than constant displacement */
+ /* heuristic used in 6.X versions. The latter seems to */
+ /* fail for 2.6 kernels. */
}
+ return result;
}
-# endif
+# endif /* IA64 */
- ptr_t GC_linux_stack_base(void)
+ STATIC ptr_t GC_linux_main_stack_base(void)
{
- /* We read the stack base value from /proc/self/stat. We do this */
+ /* We read the stack base value from /proc/self/stat. We do this */
/* using direct I/O system calls in order to avoid calling malloc */
- /* in case REDIRECT_MALLOC is defined. */
-# define STAT_BUF_SIZE 4096
-# define STAT_READ read
- /* Should probably call the real read, if read is wrapped. */
+ /* in case REDIRECT_MALLOC is defined. */
+# ifndef STAT_READ
+ /* Also defined in pthread_support.c. */
+# define STAT_BUF_SIZE 4096
+# define STAT_READ read
+# endif
+ /* Should probably call the real read, if read is wrapped. */
char stat_buf[STAT_BUF_SIZE];
int f;
- char c;
- word result = 0;
- size_t i, buf_offset = 0;
+ word result;
+ int i, buf_offset = 0, len;
- /* First try the easy way. This should work for glibc 2.2 */
+ /* First try the easy way. This should work for glibc 2.2 */
/* This fails in a prelinked ("prelink" command) executable */
- /* since the correct value of __libc_stack_end never */
- /* becomes visible to us. The second test works around */
- /* this. */
+ /* since the correct value of __libc_stack_end never */
+ /* becomes visible to us. The second test works around */
+ /* this. */
+# ifdef USE_LIBC_PRIVATES
if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
-# ifdef IA64
- /* Some versions of glibc set the address 16 bytes too */
- /* low while the initialization code is running. */
- if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
- return __libc_stack_end + 0x10;
- } /* Otherwise it's not safe to add 16 bytes and we fall */
- /* back to using /proc. */
-# else
- return __libc_stack_end;
-# endif
+# if defined(IA64)
+ /* Some versions of glibc set the address 16 bytes too */
+ /* low while the initialization code is running. */
+ if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
+ return __libc_stack_end + 0x10;
+ } /* Otherwise it's not safe to add 16 bytes and we fall */
+ /* back to using /proc. */
+# elif defined(SPARC)
+ /* Older versions of glibc for 64-bit Sparc do not set
+ * this variable correctly, it gets set to either zero
+ * or one.
+ */
+ if (__libc_stack_end != (ptr_t) (unsigned long)0x1)
+ return __libc_stack_end;
+# else
+ return __libc_stack_end;
+# endif
}
+# endif
f = open("/proc/self/stat", O_RDONLY);
- if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
- ABORT("Couldn't read /proc/self/stat");
- }
- c = stat_buf[buf_offset++];
- /* Skip the required number of fields. This number is hopefully */
- /* constant across all Linux implementations. */
- for (i = 0; i < STAT_SKIP; ++i) {
- while (isspace(c)) c = stat_buf[buf_offset++];
- while (!isspace(c)) c = stat_buf[buf_offset++];
+ if (f < 0)
+ ABORT("Couldn't read /proc/self/stat");
+ len = STAT_READ(f, stat_buf, STAT_BUF_SIZE);
+ close(f);
+
+ /* Skip the required number of fields. This number is hopefully */
+ /* constant across all Linux implementations. */
+ for (i = 0; i < STAT_SKIP; ++i) {
+ while (buf_offset < len && isspace(stat_buf[buf_offset++])) {
+ /* empty */
+ }
+ while (buf_offset < len && !isspace(stat_buf[buf_offset++])) {
+ /* empty */
}
- while (isspace(c)) c = stat_buf[buf_offset++];
- while (isdigit(c)) {
- result *= 10;
- result += c - '0';
- c = stat_buf[buf_offset++];
}
- close(f);
- if (result < 0x10000000) ABORT("Absurd stack bottom value");
+ /* Skip spaces. */
+ while (buf_offset < len && isspace(stat_buf[buf_offset])) {
+ buf_offset++;
+ }
+ /* Find the end of the number and cut the buffer there. */
+ for (i = 0; buf_offset + i < len; i++) {
+ if (!isdigit(stat_buf[buf_offset + i])) break;
+ }
+ if (buf_offset + i >= len) ABORT("Could not parse /proc/self/stat");
+ stat_buf[buf_offset + i] = '\0';
+
+ result = (word)STRTOULL(&stat_buf[buf_offset], NULL, 10);
+ if (result < 0x100000 || (result & (sizeof(word) - 1)) != 0)
+ ABORT("Absurd stack bottom value");
return (ptr_t)result;
}
-
#endif /* LINUX_STACKBOTTOM */
#ifdef FREEBSD_STACKBOTTOM
+ /* This uses an undocumented sysctl call, but at least one expert */
+ /* believes it will stay. */
-/* This uses an undocumented sysctl call, but at least one expert */
-/* believes it will stay. */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/sysctl.h>
+# include <unistd.h>
+# include <sys/types.h>
+# include <sys/sysctl.h>
- ptr_t GC_freebsd_stack_base(void)
+ STATIC ptr_t GC_freebsd_main_stack_base(void)
{
int nm[2] = {CTL_KERN, KERN_USRSTACK};
ptr_t base;
size_t len = sizeof(ptr_t);
int r = sysctl(nm, 2, &base, &len, NULL, 0);
-
- if (r) ABORT("Error getting stack base");
-
+ if (r) ABORT("Error getting main stack base");
return base;
}
-
#endif /* FREEBSD_STACKBOTTOM */
-#if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
- && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS)
+#if defined(ECOS) || defined(NOSYS)
+ ptr_t GC_get_main_stack_base(void)
+ {
+ return STACKBOTTOM;
+ }
+# define GET_MAIN_STACKBASE_SPECIAL
+#elif defined(SYMBIAN)
+ extern int GC_get_main_symbian_stack_base(void);
+ ptr_t GC_get_main_stack_base(void)
+ {
+ return (ptr_t)GC_get_main_symbian_stack_base();
+ }
+# define GET_MAIN_STACKBASE_SPECIAL
+#elif !defined(BEOS) && !defined(AMIGA) && !defined(OS2) \
+ && !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) \
+ && !defined(GC_OPENBSD_THREADS) \
+ && (!defined(GC_SOLARIS_THREADS) || defined(_STRICT_STDC))
+
+# if defined(LINUX) && defined(USE_GET_STACKBASE_FOR_MAIN)
+# include <pthread.h>
+# elif defined(DARWIN) && !defined(NO_PTHREAD_GET_STACKADDR_NP)
+ /* We could use pthread_get_stackaddr_np even in case of a */
+ /* single-threaded gclib (there is no -lpthread on Darwin). */
+# include <pthread.h>
+# undef STACKBOTTOM
+# define STACKBOTTOM (ptr_t)pthread_get_stackaddr_np(pthread_self())
+# endif
-ptr_t GC_get_stack_base()
-{
-# if defined(HEURISTIC1) || defined(HEURISTIC2) || \
- defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM)
- word dummy;
+ ptr_t GC_get_main_stack_base(void)
+ {
ptr_t result;
+# if defined(LINUX) && !defined(NACL) \
+ && (defined(USE_GET_STACKBASE_FOR_MAIN) \
+ || (defined(THREADS) && !defined(REDIRECT_MALLOC)))
+ pthread_attr_t attr;
+ void *stackaddr;
+ size_t size;
+
+ if (pthread_getattr_np(pthread_self(), &attr) == 0) {
+ if (pthread_attr_getstack(&attr, &stackaddr, &size) == 0
+ && stackaddr != NULL) {
+ pthread_attr_destroy(&attr);
+# ifdef STACK_GROWS_DOWN
+ stackaddr = (char *)stackaddr + size;
+# endif
+ return (ptr_t)stackaddr;
+ }
+ pthread_attr_destroy(&attr);
+ }
+ WARN("pthread_getattr_np or pthread_attr_getstack failed"
+ " for main thread\n", 0);
# endif
-
-# define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
-
# ifdef STACKBOTTOM
- return(STACKBOTTOM);
+ result = STACKBOTTOM;
# else
-# ifdef HEURISTIC1
-# ifdef STACK_GROWS_DOWN
- result = (ptr_t)((((word)(&dummy))
- + STACKBOTTOM_ALIGNMENT_M1)
- & ~STACKBOTTOM_ALIGNMENT_M1);
-# else
- result = (ptr_t)(((word)(&dummy))
- & ~STACKBOTTOM_ALIGNMENT_M1);
-# endif
-# endif /* HEURISTIC1 */
-# ifdef LINUX_STACKBOTTOM
- result = GC_linux_stack_base();
-# endif
-# ifdef FREEBSD_STACKBOTTOM
- result = GC_freebsd_stack_base();
-# endif
-# ifdef HEURISTIC2
-# ifdef STACK_GROWS_DOWN
- result = GC_find_limit((ptr_t)(&dummy), TRUE);
-# ifdef HEURISTIC2_LIMIT
- if (result > HEURISTIC2_LIMIT
- && (ptr_t)(&dummy) < HEURISTIC2_LIMIT) {
- result = HEURISTIC2_LIMIT;
- }
-# endif
-# else
- result = GC_find_limit((ptr_t)(&dummy), FALSE);
-# ifdef HEURISTIC2_LIMIT
- if (result < HEURISTIC2_LIMIT
- && (ptr_t)(&dummy) > HEURISTIC2_LIMIT) {
- result = HEURISTIC2_LIMIT;
- }
-# endif
-# endif
-
-# endif /* HEURISTIC2 */
-# ifdef STACK_GROWS_DOWN
- if (result == 0) result = (ptr_t)(signed_word)(-sizeof(ptr_t));
-# endif
- return(result);
-# endif /* STACKBOTTOM */
-}
+# define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
+# ifdef HEURISTIC1
+# ifdef STACK_GROWS_DOWN
+ result = (ptr_t)(((word)GC_approx_sp() + STACKBOTTOM_ALIGNMENT_M1)
+ & ~STACKBOTTOM_ALIGNMENT_M1);
+# else
+ result = (ptr_t)((word)GC_approx_sp() & ~STACKBOTTOM_ALIGNMENT_M1);
+# endif
+# endif /* HEURISTIC1 */
+# ifdef LINUX_STACKBOTTOM
+ result = GC_linux_main_stack_base();
+# endif
+# ifdef FREEBSD_STACKBOTTOM
+ result = GC_freebsd_main_stack_base();
+# endif
+# ifdef HEURISTIC2
+ {
+ ptr_t sp = GC_approx_sp();
+# ifdef STACK_GROWS_DOWN
+ result = GC_find_limit(sp, TRUE);
+# ifdef HEURISTIC2_LIMIT
+ if ((word)result > (word)HEURISTIC2_LIMIT
+ && (word)sp < (word)HEURISTIC2_LIMIT) {
+ result = HEURISTIC2_LIMIT;
+ }
+# endif
+# else
+ result = GC_find_limit(sp, FALSE);
+# ifdef HEURISTIC2_LIMIT
+ if ((word)result < (word)HEURISTIC2_LIMIT
+ && (word)sp > (word)HEURISTIC2_LIMIT) {
+ result = HEURISTIC2_LIMIT;
+ }
+# endif
+# endif
+ }
+# endif /* HEURISTIC2 */
+# ifdef STACK_GROWS_DOWN
+ if (result == 0)
+ result = (ptr_t)(signed_word)(-sizeof(ptr_t));
+# endif
+# endif
+ GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)result);
+ return(result);
+ }
+# define GET_MAIN_STACKBASE_SPECIAL
+#endif /* !AMIGA, !BEOS, !OPENBSD, !OS2, !Windows */
-# endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS, !NOSYS, !ECOS */
+#if (defined(GC_LINUX_THREADS) || defined(PLATFORM_ANDROID)) && !defined(NACL)
-/*
- * Register static data segment(s) as roots.
- * If more data segments are added later then they need to be registered
- * add that point (as we do with SunOS dynamic loading),
- * or GC_mark_roots needs to check for them (as we do with PCR).
- * Called with allocator lock held.
- */
+# include <pthread.h>
+ /* extern int pthread_getattr_np(pthread_t, pthread_attr_t *); */
+
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
+ {
+ pthread_attr_t attr;
+ size_t size;
+# ifdef IA64
+ DCL_LOCK_STATE;
+# endif
+
+ if (pthread_getattr_np(pthread_self(), &attr) != 0) {
+ WARN("pthread_getattr_np failed\n", 0);
+ return GC_UNIMPLEMENTED;
+ }
+ if (pthread_attr_getstack(&attr, &(b -> mem_base), &size) != 0) {
+ ABORT("pthread_attr_getstack failed");
+ }
+ pthread_attr_destroy(&attr);
+# ifdef STACK_GROWS_DOWN
+ b -> mem_base = (char *)(b -> mem_base) + size;
+# endif
+# ifdef IA64
+ /* We could try backing_store_base_from_proc, but that's safe */
+ /* only if no mappings are being asynchronously created. */
+ /* Subtracting the size from the stack base doesn't work for at */
+ /* least the main thread. */
+ LOCK();
+ {
+ IF_CANCEL(int cancel_state;)
+ ptr_t bsp;
+ ptr_t next_stack;
+
+ DISABLE_CANCEL(cancel_state);
+ bsp = GC_save_regs_in_stack();
+ next_stack = GC_greatest_stack_base_below(bsp);
+ if (0 == next_stack) {
+ b -> reg_base = GC_find_limit(bsp, FALSE);
+ } else {
+ /* Avoid walking backwards into preceding memory stack and */
+ /* growing it. */
+ b -> reg_base = GC_find_limit_with_bound(bsp, FALSE, next_stack);
+ }
+ RESTORE_CANCEL(cancel_state);
+ }
+ UNLOCK();
+# endif
+ return GC_SUCCESS;
+ }
+# define HAVE_GET_STACK_BASE
+#endif /* GC_LINUX_THREADS */
+
+#if defined(GC_DARWIN_THREADS) && !defined(NO_PTHREAD_GET_STACKADDR_NP)
+# include <pthread.h>
+
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
+ {
+ /* pthread_get_stackaddr_np() should return stack bottom (highest */
+ /* stack address plus 1). */
+ b->mem_base = pthread_get_stackaddr_np(pthread_self());
+ GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)b->mem_base);
+ return GC_SUCCESS;
+ }
+# define HAVE_GET_STACK_BASE
+#endif /* GC_DARWIN_THREADS */
+
+#ifdef GC_OPENBSD_THREADS
+# include <sys/signal.h>
+# include <pthread.h>
+# include <pthread_np.h>
+
+ /* Find the stack using pthread_stackseg_np(). */
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
+ {
+ stack_t stack;
+ if (pthread_stackseg_np(pthread_self(), &stack))
+ ABORT("pthread_stackseg_np(self) failed");
+ sb->mem_base = stack.ss_sp;
+ return GC_SUCCESS;
+ }
+# define HAVE_GET_STACK_BASE
+#endif /* GC_OPENBSD_THREADS */
+
+#if defined(GC_SOLARIS_THREADS) && !defined(_STRICT_STDC)
+
+# include <thread.h>
+# include <signal.h>
+# include <pthread.h>
+
+ /* These variables are used to cache ss_sp value for the primordial */
+ /* thread (it's better not to call thr_stksegment() twice for this */
+ /* thread - see JDK bug #4352906). */
+ static pthread_t stackbase_main_self = 0;
+ /* 0 means stackbase_main_ss_sp value is unset. */
+ static void *stackbase_main_ss_sp = NULL;
+
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
+ {
+ stack_t s;
+ pthread_t self = pthread_self();
+
+ if (self == stackbase_main_self)
+ {
+ /* If the client calls GC_get_stack_base() from the main thread */
+ /* then just return the cached value. */
+ b -> mem_base = stackbase_main_ss_sp;
+ GC_ASSERT(b -> mem_base != NULL);
+ return GC_SUCCESS;
+ }
+
+ if (thr_stksegment(&s)) {
+ /* According to the manual, the only failure error code returned */
+ /* is EAGAIN meaning "the information is not available due to the */
+ /* thread is not yet completely initialized or it is an internal */
+ /* thread" - this shouldn't happen here. */
+ ABORT("thr_stksegment failed");
+ }
+ /* s.ss_sp holds the pointer to the stack bottom. */
+ GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)s.ss_sp);
+
+ if (!stackbase_main_self && thr_main() != 0)
+ {
+ /* Cache the stack base value for the primordial thread (this */
+ /* is done during GC_init, so there is no race). */
+ stackbase_main_ss_sp = s.ss_sp;
+ stackbase_main_self = self;
+ }
+
+ b -> mem_base = s.ss_sp;
+ return GC_SUCCESS;
+ }
+# define HAVE_GET_STACK_BASE
+#endif /* GC_SOLARIS_THREADS */
+
+#ifdef GC_RTEMS_PTHREADS
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
+ {
+ sb->mem_base = rtems_get_stack_bottom();
+ return GC_SUCCESS;
+ }
+# define HAVE_GET_STACK_BASE
+#endif /* GC_RTEMS_PTHREADS */
+
+#ifndef HAVE_GET_STACK_BASE
+# ifdef NEED_FIND_LIMIT
+ /* Retrieve stack base. */
+ /* Using the GC_find_limit version is risky. */
+ /* On IA64, for example, there is no guard page between the */
+ /* stack of one thread and the register backing store of the */
+ /* next. Thus this is likely to identify way too large a */
+ /* "stack" and thus at least result in disastrous performance. */
+ /* FIXME - Implement better strategies here. */
+ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
+ {
+ IF_CANCEL(int cancel_state;)
+ DCL_LOCK_STATE;
+
+ LOCK();
+ DISABLE_CANCEL(cancel_state); /* May be unnecessary? */
+# ifdef STACK_GROWS_DOWN
+ b -> mem_base = GC_find_limit(GC_approx_sp(), TRUE);
+# ifdef IA64
+ b -> reg_base = GC_find_limit(GC_save_regs_in_stack(), FALSE);
+# endif
+# else
+ b -> mem_base = GC_find_limit(GC_approx_sp(), FALSE);
+# endif
+ RESTORE_CANCEL(cancel_state);
+ UNLOCK();
+ return GC_SUCCESS;
+ }
+# else
+ GC_API int GC_CALL GC_get_stack_base(
+ struct GC_stack_base *b GC_ATTR_UNUSED)
+ {
+# if defined(GET_MAIN_STACKBASE_SPECIAL) && !defined(THREADS) \
+ && !defined(IA64)
+ b->mem_base = GC_get_main_stack_base();
+ return GC_SUCCESS;
+# else
+ return GC_UNIMPLEMENTED;
+# endif
+ }
+# endif /* !NEED_FIND_LIMIT */
+#endif /* !HAVE_GET_STACK_BASE */
+
+#ifndef GET_MAIN_STACKBASE_SPECIAL
+ /* This is always called from the main thread. Default implementation. */
+ ptr_t GC_get_main_stack_base(void)
+ {
+ struct GC_stack_base sb;
+
+ if (GC_get_stack_base(&sb) != GC_SUCCESS)
+ ABORT("GC_get_stack_base failed");
+ GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)sb.mem_base);
+ return (ptr_t)sb.mem_base;
+ }
+#endif /* !GET_MAIN_STACKBASE_SPECIAL */
+/* Register static data segment(s) as roots. If more data segments are */
+/* added later then they need to be registered at that point (as we do */
+/* with SunOS dynamic loading), or GC_mark_roots needs to check for */
+/* them (as we do with PCR). Called with allocator lock held. */
# ifdef OS2
-void GC_register_data_segments()
+void GC_register_data_segments(void)
{
PTIB ptib;
PPIB ppib;
@@ -1074,153 +1462,256 @@ void GC_register_data_segments()
# define PBUFSIZ 512
UCHAR path[PBUFSIZ];
FILE * myexefile;
- struct exe_hdr hdrdos; /* MSDOS header. */
- struct e32_exe hdr386; /* Real header for my executable */
- struct o32_obj seg; /* Currrent segment */
+ struct exe_hdr hdrdos; /* MSDOS header. */
+ struct e32_exe hdr386; /* Real header for my executable */
+ struct o32_obj seg; /* Currrent segment */
int nsegs;
-
-
+
+
if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
- GC_err_printf0("DosGetInfoBlocks failed\n");
- ABORT("DosGetInfoBlocks failed\n");
+ ABORT("DosGetInfoBlocks failed");
}
module_handle = ppib -> pib_hmte;
if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
- GC_err_printf0("DosQueryModuleName failed\n");
- ABORT("DosGetInfoBlocks failed\n");
+ GC_err_printf("DosQueryModuleName failed\n");
+ ABORT("DosGetInfoBlocks failed");
}
myexefile = fopen(path, "rb");
if (myexefile == 0) {
- GC_err_puts("Couldn't open executable ");
- GC_err_puts(path); GC_err_puts("\n");
- ABORT("Failed to open executable\n");
+ GC_COND_LOG_PRINTF("Could not open executable %s\n", path);
+ ABORT("Failed to open executable");
}
- if (fread((char *)(&hdrdos), 1, sizeof hdrdos, myexefile) < sizeof hdrdos) {
- GC_err_puts("Couldn't read MSDOS header from ");
- GC_err_puts(path); GC_err_puts("\n");
+ if (fread((char *)(&hdrdos), 1, sizeof(hdrdos), myexefile)
+ < sizeof(hdrdos)) {
+ GC_COND_LOG_PRINTF("Could not read MSDOS header from %s\n", path);
ABORT("Couldn't read MSDOS header");
}
if (E_MAGIC(hdrdos) != EMAGIC) {
- GC_err_puts("Executable has wrong DOS magic number: ");
- GC_err_puts(path); GC_err_puts("\n");
+ GC_COND_LOG_PRINTF("Executable has wrong DOS magic number: %s\n",
+ path);
ABORT("Bad DOS magic number");
}
if (fseek(myexefile, E_LFANEW(hdrdos), SEEK_SET) != 0) {
- GC_err_puts("Seek to new header failed in ");
- GC_err_puts(path); GC_err_puts("\n");
+ GC_COND_LOG_PRINTF("Seek to new header failed in %s\n", path);
ABORT("Bad DOS magic number");
}
- if (fread((char *)(&hdr386), 1, sizeof hdr386, myexefile) < sizeof hdr386) {
- GC_err_puts("Couldn't read MSDOS header from ");
- GC_err_puts(path); GC_err_puts("\n");
+ if (fread((char *)(&hdr386), 1, sizeof(hdr386), myexefile)
+ < sizeof(hdr386)) {
+ GC_COND_LOG_PRINTF("Could not read MSDOS header from %s\n", path);
ABORT("Couldn't read OS/2 header");
}
if (E32_MAGIC1(hdr386) != E32MAGIC1 || E32_MAGIC2(hdr386) != E32MAGIC2) {
- GC_err_puts("Executable has wrong OS/2 magic number:");
- GC_err_puts(path); GC_err_puts("\n");
+ GC_COND_LOG_PRINTF("Executable has wrong OS/2 magic number: %s\n",
+ path);
ABORT("Bad OS/2 magic number");
}
- if ( E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) {
- GC_err_puts("Executable %s has wrong byte order: ");
- GC_err_puts(path); GC_err_puts("\n");
+ if (E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) {
+ GC_COND_LOG_PRINTF("Executable has wrong byte order: %s\n", path);
ABORT("Bad byte order");
}
- if ( E32_CPU(hdr386) == E32CPU286) {
- GC_err_puts("GC can't handle 80286 executables: ");
- GC_err_puts(path); GC_err_puts("\n");
- EXIT();
+ if (E32_CPU(hdr386) == E32CPU286) {
+ GC_COND_LOG_PRINTF("GC cannot handle 80286 executables: %s\n", path);
+ ABORT("Intel 80286 executables are unsupported");
}
if (fseek(myexefile, E_LFANEW(hdrdos) + E32_OBJTAB(hdr386),
- SEEK_SET) != 0) {
- GC_err_puts("Seek to object table failed: ");
- GC_err_puts(path); GC_err_puts("\n");
+ SEEK_SET) != 0) {
+ GC_COND_LOG_PRINTF("Seek to object table failed: %s\n", path);
ABORT("Seek to object table failed");
}
for (nsegs = E32_OBJCNT(hdr386); nsegs > 0; nsegs--) {
int flags;
- if (fread((char *)(&seg), 1, sizeof seg, myexefile) < sizeof seg) {
- GC_err_puts("Couldn't read obj table entry from ");
- GC_err_puts(path); GC_err_puts("\n");
+ if (fread((char *)(&seg), 1, sizeof(seg), myexefile) < sizeof(seg)) {
+ GC_COND_LOG_PRINTF("Could not read obj table entry from %s\n", path);
ABORT("Couldn't read obj table entry");
}
flags = O32_FLAGS(seg);
if (!(flags & OBJWRITE)) continue;
if (!(flags & OBJREAD)) continue;
if (flags & OBJINVALID) {
- GC_err_printf0("Object with invalid pages?\n");
+ GC_err_printf("Object with invalid pages?\n");
continue;
- }
- GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg), FALSE);
+ }
+ GC_add_roots_inner((ptr_t)O32_BASE(seg),
+ (ptr_t)(O32_BASE(seg)+O32_SIZE(seg)), FALSE);
}
}
# else /* !OS2 */
-# if defined(MSWIN32) || defined(MSWINCE)
+# if defined(GWW_VDB)
+# ifndef MEM_WRITE_WATCH
+# define MEM_WRITE_WATCH 0x200000
+# endif
+# ifndef WRITE_WATCH_FLAG_RESET
+# define WRITE_WATCH_FLAG_RESET 1
+# endif
+
+ /* Since we can't easily check whether ULONG_PTR and SIZE_T are */
+ /* defined in Win32 basetsd.h, we define own ULONG_PTR. */
+# define GC_ULONG_PTR word
+
+ typedef UINT (WINAPI * GetWriteWatch_type)(
+ DWORD, PVOID, GC_ULONG_PTR /* SIZE_T */,
+ PVOID *, GC_ULONG_PTR *, PULONG);
+ static GetWriteWatch_type GetWriteWatch_func;
+ static DWORD GetWriteWatch_alloc_flag;
+
+# define GC_GWW_AVAILABLE() (GetWriteWatch_func != NULL)
+
+ static void detect_GetWriteWatch(void)
+ {
+ static GC_bool done;
+ HMODULE hK32;
+ if (done)
+ return;
+
+# if defined(MPROTECT_VDB)
+ {
+ char * str = GETENV("GC_USE_GETWRITEWATCH");
+# if defined(GC_PREFER_MPROTECT_VDB)
+ if (str == NULL || (*str == '0' && *(str + 1) == '\0')) {
+ /* GC_USE_GETWRITEWATCH is unset or set to "0". */
+ done = TRUE; /* falling back to MPROTECT_VDB strategy. */
+ /* This should work as if GWW_VDB is undefined. */
+ return;
+ }
+# else
+ if (str != NULL && *str == '0' && *(str + 1) == '\0') {
+ /* GC_USE_GETWRITEWATCH is set "0". */
+ done = TRUE; /* falling back to MPROTECT_VDB strategy. */
+ return;
+ }
+# endif
+ }
+# endif
+
+ hK32 = GetModuleHandle(TEXT("kernel32.dll"));
+ if (hK32 != (HMODULE)0 &&
+ (GetWriteWatch_func = (GetWriteWatch_type)GetProcAddress(hK32,
+ "GetWriteWatch")) != NULL) {
+ /* Also check whether VirtualAlloc accepts MEM_WRITE_WATCH, */
+ /* as some versions of kernel32.dll have one but not the */
+ /* other, making the feature completely broken. */
+ void * page = VirtualAlloc(NULL, GC_page_size,
+ MEM_WRITE_WATCH | MEM_RESERVE,
+ PAGE_READWRITE);
+ if (page != NULL) {
+ PVOID pages[16];
+ GC_ULONG_PTR count = 16;
+ DWORD page_size;
+ /* Check that it actually works. In spite of some */
+ /* documentation it actually seems to exist on W2K. */
+ /* This test may be unnecessary, but ... */
+ if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
+ page, GC_page_size,
+ pages,
+ &count,
+ &page_size) != 0) {
+ /* GetWriteWatch always fails. */
+ GetWriteWatch_func = NULL;
+ } else {
+ GetWriteWatch_alloc_flag = MEM_WRITE_WATCH;
+ }
+ VirtualFree(page, GC_page_size, MEM_RELEASE);
+ } else {
+ /* GetWriteWatch will be useless. */
+ GetWriteWatch_func = NULL;
+ }
+ }
+# ifndef SMALL_CONFIG
+ if (GetWriteWatch_func == NULL) {
+ GC_COND_LOG_PRINTF("Did not find a usable GetWriteWatch()\n");
+ } else {
+ GC_COND_LOG_PRINTF("Using GetWriteWatch()\n");
+ }
+# endif
+ done = TRUE;
+ }
+
+# else
+# define GetWriteWatch_alloc_flag 0
+# endif /* !GWW_VDB */
+
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
# ifdef MSWIN32
- /* Unfortunately, we have to handle win32s very differently from NT, */
- /* Since VirtualQuery has very different semantics. In particular, */
- /* under win32s a VirtualQuery call on an unmapped page returns an */
- /* invalid result. Under NT, GC_register_data_segments is a noop and */
- /* all real work is done by GC_register_dynamic_libraries. Under */
- /* win32s, we cannot find the data segments associated with dll's. */
- /* We register the main data segment here. */
- GC_bool GC_no_win32_dlls = FALSE;
- /* This used to be set for gcc, to avoid dealing with */
- /* the structured exception handling issues. But we now have */
- /* assembly code to do that right. */
-
- void GC_init_win32()
+ /* Unfortunately, we have to handle win32s very differently from NT, */
+ /* Since VirtualQuery has very different semantics. In particular, */
+ /* under win32s a VirtualQuery call on an unmapped page returns an */
+ /* invalid result. Under NT, GC_register_data_segments is a no-op */
+ /* and all real work is done by GC_register_dynamic_libraries. Under */
+ /* win32s, we cannot find the data segments associated with dll's. */
+ /* We register the main data segment here. */
+ GC_INNER GC_bool GC_no_win32_dlls = FALSE;
+ /* This used to be set for gcc, to avoid dealing with */
+ /* the structured exception handling issues. But we now have */
+ /* assembly code to do that right. */
+
+ GC_INNER GC_bool GC_wnt = FALSE;
+ /* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */
+
+ GC_INNER void GC_init_win32(void)
{
- /* if we're running under win32s, assume that no DLLs will be loaded */
+ /* Set GC_wnt. If we're running under win32s, assume that no DLLs */
+ /* will be loaded. I doubt anyone still runs win32s, but... */
DWORD v = GetVersion();
- GC_no_win32_dlls |= ((v & 0x80000000) && (v & 0xff) <= 3);
+ GC_wnt = !(v & 0x80000000);
+ GC_no_win32_dlls |= ((!GC_wnt) && (v & 0xff) <= 3);
+# ifdef USE_MUNMAP
+ if (GC_no_win32_dlls) {
+ /* Turn off unmapping for safety (since may not work well with */
+ /* GlobalAlloc). */
+ GC_unmap_threshold = 0;
+ }
+# endif
}
- /* Return the smallest address a such that VirtualQuery */
- /* returns correct results for all addresses between a and start. */
- /* Assumes VirtualQuery returns correct information for start. */
- ptr_t GC_least_described_address(ptr_t start)
- {
+ /* Return the smallest address a such that VirtualQuery */
+ /* returns correct results for all addresses between a and start. */
+ /* Assumes VirtualQuery returns correct information for start. */
+ STATIC ptr_t GC_least_described_address(ptr_t start)
+ {
MEMORY_BASIC_INFORMATION buf;
- DWORD result;
+ size_t result;
LPVOID limit;
ptr_t p;
LPVOID q;
-
+
limit = GC_sysinfo.lpMinimumApplicationAddress;
p = (ptr_t)((word)start & ~(GC_page_size - 1));
for (;;) {
- q = (LPVOID)(p - GC_page_size);
- if ((ptr_t)q > (ptr_t)p /* underflow */ || q < limit) break;
- result = VirtualQuery(q, &buf, sizeof(buf));
- if (result != sizeof(buf) || buf.AllocationBase == 0) break;
- p = (ptr_t)(buf.AllocationBase);
+ q = (LPVOID)(p - GC_page_size);
+ if ((word)q > (word)p /* underflow */ || (word)q < (word)limit) break;
+ result = VirtualQuery(q, &buf, sizeof(buf));
+ if (result != sizeof(buf) || buf.AllocationBase == 0) break;
+ p = (ptr_t)(buf.AllocationBase);
}
- return(p);
+ return p;
}
-# endif
+# endif /* MSWIN32 */
# ifndef REDIRECT_MALLOC
- /* We maintain a linked list of AllocationBase values that we know */
+ /* We maintain a linked list of AllocationBase values that we know */
/* correspond to malloc heap sections. Currently this is only called */
- /* during a GC. But there is some hope that for long running */
- /* programs we will eventually see most heap sections. */
+ /* during a GC. But there is some hope that for long running */
+ /* programs we will eventually see most heap sections. */
+
+ /* In the long run, it would be more reliable to occasionally walk */
+ /* the malloc heap with HeapWalk on the default heap. But that */
+ /* apparently works only for NT-based Windows. */
- /* In the long run, it would be more reliable to occasionally walk */
- /* the malloc heap with HeapWalk on the default heap. But that */
- /* apparently works only for NT-based Windows. */
+ STATIC size_t GC_max_root_size = 100000; /* Appr. largest root size. */
- /* In the long run, a better data structure would also be nice ... */
- struct GC_malloc_heap_list {
+# ifdef USE_WINALLOC
+ /* In the long run, a better data structure would also be nice ... */
+ STATIC struct GC_malloc_heap_list {
void * allocation_base;
struct GC_malloc_heap_list *next;
} *GC_malloc_heap_l = 0;
- /* Is p the base of one of the malloc heap sections we already know */
- /* about? */
- GC_bool GC_is_malloc_heap_base(ptr_t p)
+ /* Is p the base of one of the malloc heap sections we already know */
+ /* about? */
+ STATIC GC_bool GC_is_malloc_heap_base(ptr_t p)
{
struct GC_malloc_heap_list *q = GC_malloc_heap_l;
@@ -1231,19 +1722,17 @@ void GC_register_data_segments()
return FALSE;
}
- void *GC_get_allocation_base(void *p)
+ STATIC void *GC_get_allocation_base(void *p)
{
MEMORY_BASIC_INFORMATION buf;
- DWORD result = VirtualQuery(p, &buf, sizeof(buf));
+ size_t result = VirtualQuery(p, &buf, sizeof(buf));
if (result != sizeof(buf)) {
ABORT("Weird VirtualQuery result");
}
return buf.AllocationBase;
}
- size_t GC_max_root_size = 100000; /* Appr. largest root size. */
-
- void GC_add_current_malloc_heap()
+ GC_INNER void GC_add_current_malloc_heap(void)
{
struct GC_malloc_heap_list *new_l =
malloc(sizeof(struct GC_malloc_heap_list));
@@ -1251,67 +1740,66 @@ void GC_register_data_segments()
if (new_l == 0) return;
if (GC_is_malloc_heap_base(candidate)) {
- /* Try a little harder to find malloc heap. */
- size_t req_size = 10000;
- do {
- void *p = malloc(req_size);
- if (0 == p) { free(new_l); return; }
- candidate = GC_get_allocation_base(p);
- free(p);
- req_size *= 2;
- } while (GC_is_malloc_heap_base(candidate)
- && req_size < GC_max_root_size/10 && req_size < 500000);
- if (GC_is_malloc_heap_base(candidate)) {
- free(new_l); return;
- }
+ /* Try a little harder to find malloc heap. */
+ size_t req_size = 10000;
+ do {
+ void *p = malloc(req_size);
+ if (0 == p) {
+ free(new_l);
+ return;
+ }
+ candidate = GC_get_allocation_base(p);
+ free(p);
+ req_size *= 2;
+ } while (GC_is_malloc_heap_base(candidate)
+ && req_size < GC_max_root_size/10 && req_size < 500000);
+ if (GC_is_malloc_heap_base(candidate)) {
+ free(new_l);
+ return;
+ }
}
-# ifdef CONDPRINT
- if (GC_print_stats)
- GC_printf1("Found new system malloc AllocationBase at 0x%lx\n",
- candidate);
-# endif
+ GC_COND_LOG_PRINTF("Found new system malloc AllocationBase at %p\n",
+ candidate);
new_l -> allocation_base = candidate;
new_l -> next = GC_malloc_heap_l;
GC_malloc_heap_l = new_l;
}
-# endif /* REDIRECT_MALLOC */
-
+# endif /* USE_WINALLOC */
+
+# endif /* !REDIRECT_MALLOC */
+
+ STATIC word GC_n_heap_bases = 0; /* See GC_heap_bases. */
+
/* Is p the start of either the malloc heap, or of one of our */
- /* heap sections? */
- GC_bool GC_is_heap_base (ptr_t p)
+ /* heap sections? */
+ GC_INNER GC_bool GC_is_heap_base(ptr_t p)
{
-
unsigned i;
-
# ifndef REDIRECT_MALLOC
- static word last_gc_no = -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;
+# ifdef USE_WINALLOC
+ if (GC_is_malloc_heap_base(p)) return TRUE;
+# endif
# endif
for (i = 0; i < GC_n_heap_bases; i++) {
if (GC_heap_bases[i] == p) return TRUE;
}
- return FALSE ;
+ return FALSE;
}
-# ifdef MSWIN32
- void GC_register_root_section(ptr_t static_root)
+#ifdef MSWIN32
+ STATIC void GC_register_root_section(ptr_t static_root)
{
MEMORY_BASIC_INFORMATION buf;
- DWORD result;
+ size_t result;
DWORD protect;
LPVOID p;
char * base;
char * limit, * new_limit;
-
+
if (!GC_no_win32_dlls) return;
p = base = limit = GC_least_described_address(static_root);
- while (p < GC_sysinfo.lpMaximumApplicationAddress) {
+ while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress) {
result = VirtualQuery(p, &buf, sizeof(buf));
if (result != sizeof(buf) || buf.AllocationBase == 0
|| GC_is_heap_base(buf.AllocationBase)) break;
@@ -1327,146 +1815,169 @@ void GC_register_data_segments()
limit = new_limit;
}
}
- if (p > (LPVOID)new_limit /* overflow */) break;
+ if ((word)p > (word)new_limit /* overflow */) break;
p = (LPVOID)new_limit;
}
if (base != limit) GC_add_roots_inner(base, limit, FALSE);
}
-#endif
-
- void GC_register_data_segments()
+#endif /* MSWIN32 */
+
+ void GC_register_data_segments(void)
{
-# ifdef MSWIN32
- static char dummy;
- GC_register_root_section((ptr_t)(&dummy));
-# endif
+# ifdef MSWIN32
+ GC_register_root_section((ptr_t)&GC_pages_executable);
+ /* any other GC global variable would fit too. */
+# endif
}
# else /* !OS2 && !Windows */
# if (defined(SVR4) || defined(AUX) || defined(DGUX) \
|| (defined(LINUX) && defined(SPARC))) && !defined(PCR)
-ptr_t GC_SysVGetDataStart(max_page_size, etext_addr)
-int max_page_size;
-int * etext_addr;
-{
+ ptr_t GC_SysVGetDataStart(size_t max_page_size, ptr_t etext_addr)
+ {
word text_end = ((word)(etext_addr) + sizeof(word) - 1)
- & ~(sizeof(word) - 1);
- /* etext rounded to word boundary */
+ & ~(sizeof(word) - 1);
+ /* etext rounded to word boundary */
word next_page = ((text_end + (word)max_page_size - 1)
- & ~((word)max_page_size - 1));
+ & ~((word)max_page_size - 1));
word page_offset = (text_end & ((word)max_page_size - 1));
- VOLATILE char * result = (char *)(next_page + page_offset);
- /* Note that this isnt equivalent to just adding */
- /* max_page_size to &etext if &etext is at a page boundary */
-
+ char * volatile result = (char *)(next_page + page_offset);
+ /* Note that this isn't equivalent to just adding */
+ /* max_page_size to &etext if &etext is at a page boundary */
+
GC_setup_temporary_fault_handler();
if (SETJMP(GC_jmp_buf) == 0) {
- /* Try writing to the address. */
- *result = *result;
+ /* Try writing to the address. */
+ *result = *result;
GC_reset_fault_handler();
} else {
GC_reset_fault_handler();
- /* We got here via a longjmp. The address is not readable. */
- /* This is known to happen under Solaris 2.4 + gcc, which place */
- /* string constants in the text segment, but after etext. */
- /* Use plan B. Note that we now know there is a gap between */
- /* text and data segments, so plan A bought us something. */
- result = (char *)GC_find_limit((ptr_t)(DATAEND), FALSE);
+ /* We got here via a longjmp. The address is not readable. */
+ /* This is known to happen under Solaris 2.4 + gcc, which place */
+ /* string constants in the text segment, but after etext. */
+ /* Use plan B. Note that we now know there is a gap between */
+ /* text and data segments, so plan A bought us something. */
+ result = (char *)GC_find_limit((ptr_t)(DATAEND), FALSE);
}
return((ptr_t)result);
-}
+ }
# endif
-# if defined(FREEBSD) && defined(I386) && !defined(PCR)
-/* Its unclear whether this should be identical to the above, or */
-/* whether it should apply to non-X86 architectures. */
-/* For now we don't assume that there is always an empty page after */
+# if defined(FREEBSD) && !defined(PCR) && (defined(I386) || defined(X86_64) \
+ || defined(powerpc) || defined(__powerpc__))
+
+/* Its unclear whether this should be identical to the above, or */
+/* whether it should apply to non-X86 architectures. */
+/* For now we don't assume that there is always an empty page after */
/* etext. But in some cases there actually seems to be slightly more. */
-/* This also deals with holes between read-only data and writable data. */
-ptr_t GC_FreeBSDGetDataStart(max_page_size, etext_addr)
-int max_page_size;
-int * etext_addr;
+/* This also deals with holes between read-only data and writable data. */
+ptr_t GC_FreeBSDGetDataStart(size_t max_page_size, ptr_t etext_addr)
{
word text_end = ((word)(etext_addr) + sizeof(word) - 1)
- & ~(sizeof(word) - 1);
- /* etext rounded to word boundary */
- VOLATILE word next_page = (text_end + (word)max_page_size - 1)
- & ~((word)max_page_size - 1);
- VOLATILE ptr_t result = (ptr_t)text_end;
+ & ~(sizeof(word) - 1);
+ /* etext rounded to word boundary */
+ volatile word next_page = (text_end + (word)max_page_size - 1)
+ & ~((word)max_page_size - 1);
+ volatile ptr_t result = (ptr_t)text_end;
GC_setup_temporary_fault_handler();
if (SETJMP(GC_jmp_buf) == 0) {
- /* Try reading at the address. */
- /* This should happen before there is another thread. */
- for (; next_page < (word)(DATAEND); next_page += (word)max_page_size)
- *(VOLATILE char *)next_page;
- GC_reset_fault_handler();
+ /* Try reading at the address. */
+ /* This should happen before there is another thread. */
+ for (; next_page < (word)(DATAEND); next_page += (word)max_page_size)
+ *(volatile char *)next_page;
+ GC_reset_fault_handler();
} else {
- GC_reset_fault_handler();
- /* As above, we go to plan B */
- result = GC_find_limit((ptr_t)(DATAEND), FALSE);
+ GC_reset_fault_handler();
+ /* As above, we go to plan B */
+ result = GC_find_limit((ptr_t)(DATAEND), FALSE);
}
return(result);
}
-# endif
+# endif /* FREEBSD */
#ifdef AMIGA
# define GC_AMIGA_DS
-# include "AmigaOS.c"
+# include "extra/AmigaOS.c"
# undef GC_AMIGA_DS
-#else /* !OS2 && !Windows && !AMIGA */
+#elif defined(OPENBSD)
+
+/* Depending on arch alignment, there can be multiple holes */
+/* between DATASTART and DATAEND. Scan in DATASTART .. DATAEND */
+/* and register each region. */
+void GC_register_data_segments(void)
+{
+ ptr_t region_start = DATASTART;
+ ptr_t region_end;
+
+ for (;;) {
+ region_end = GC_find_limit_openbsd(region_start, DATAEND);
+ GC_add_roots_inner(region_start, region_end, FALSE);
+ if ((word)region_end >= (word)(DATAEND))
+ break;
+ region_start = GC_skip_hole_openbsd(region_end, DATAEND);
+ }
+}
+
+# else /* !OS2 && !Windows && !AMIGA && !OPENBSD */
-void GC_register_data_segments()
+void GC_register_data_segments(void)
{
-# if !defined(PCR) && !defined(SRC_M3) && !defined(MACOS)
+# if !defined(PCR) && !defined(MACOS)
# if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
- /* As of Solaris 2.3, the Solaris threads implementation */
- /* allocates the data structure for the initial thread with */
- /* sbrk at process startup. It needs to be scanned, so that */
- /* we don't lose some malloc allocated data structures */
- /* hanging from it. We're on thin ice here ... */
- extern caddr_t sbrk();
-
- GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
+ /* As of Solaris 2.3, the Solaris threads implementation */
+ /* allocates the data structure for the initial thread with */
+ /* sbrk at process startup. It needs to be scanned, so that */
+ /* we don't lose some malloc allocated data structures */
+ /* hanging from it. We're on thin ice here ... */
+ extern caddr_t sbrk(int);
+
+ GC_ASSERT(DATASTART);
+ {
+ ptr_t p = (ptr_t)sbrk(0);
+ if ((word)(DATASTART) < (word)p)
+ GC_add_roots_inner(DATASTART, p, FALSE);
+ }
# else
- GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
+ GC_ASSERT(DATASTART);
+ GC_add_roots_inner(DATASTART, (ptr_t)(DATAEND), FALSE);
# if defined(DATASTART2)
- GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), FALSE);
+ GC_add_roots_inner(DATASTART2, (ptr_t)(DATAEND2), FALSE);
# endif
# endif
# endif
# if defined(MACOS)
{
# if defined(THINK_C)
- extern void* GC_MacGetDataStart(void);
- /* globals begin above stack and end at a5. */
- GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
- (ptr_t)LMGetCurrentA5(), FALSE);
+ extern void* GC_MacGetDataStart(void);
+ /* globals begin above stack and end at a5. */
+ GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
+ (ptr_t)LMGetCurrentA5(), FALSE);
# else
# if defined(__MWERKS__)
# if !__POWERPC__
- extern void* GC_MacGetDataStart(void);
- /* MATTHEW: Function to handle Far Globals (CW Pro 3) */
+ extern void* GC_MacGetDataStart(void);
+ /* MATTHEW: Function to handle Far Globals (CW Pro 3) */
# if __option(far_data)
- extern void* GC_MacGetDataEnd(void);
+ extern void* GC_MacGetDataEnd(void);
# endif
- /* globals begin above stack and end at a5. */
- GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
- (ptr_t)LMGetCurrentA5(), FALSE);
- /* MATTHEW: Handle Far Globals */
+ /* globals begin above stack and end at a5. */
+ GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
+ (ptr_t)LMGetCurrentA5(), FALSE);
+ /* MATTHEW: Handle Far Globals */
# if __option(far_data)
/* Far globals follow he QD globals: */
- GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
- (ptr_t)GC_MacGetDataEnd(), FALSE);
+ GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
+ (ptr_t)GC_MacGetDataEnd(), FALSE);
# endif
# else
- extern char __data_start__[], __data_end__[];
- GC_add_roots_inner((ptr_t)&__data_start__,
- (ptr_t)&__data_end__, FALSE);
+ extern char __data_start__[], __data_end__[];
+ GC_add_roots_inner((ptr_t)&__data_start__,
+ (ptr_t)&__data_end__, FALSE);
# endif /* __POWERPC__ */
# endif /* __MWERKS__ */
# endif /* !THINK_C */
@@ -1474,68 +1985,30 @@ void GC_register_data_segments()
# endif /* MACOS */
/* Dynamic libraries are added at every collection, since they may */
- /* change. */
+ /* change. */
}
-# endif /* ! AMIGA */
-# endif /* ! MSWIN32 && ! MSWINCE*/
-# endif /* ! OS2 */
+# endif /* !AMIGA */
+# endif /* !MSWIN32 && !MSWINCE */
+# endif /* !OS2 */
/*
* Auxiliary routines for obtaining memory from OS.
*/
# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
- && !defined(MSWIN32) && !defined(MSWINCE) \
- && !defined(MACOS) && !defined(DOS4GW)
+ && !defined(USE_WINALLOC) && !defined(MACOS) && !defined(DOS4GW) \
+ && !defined(NONSTOP) && !defined(SN_TARGET_PS3) && !defined(RTEMS) \
+ && !defined(__CC_ARM)
-# ifdef SUNOS4
- extern caddr_t sbrk();
-# endif
-# ifdef __STDC__
-# define SBRK_ARG_T ptrdiff_t
-# else
-# define SBRK_ARG_T int
-# endif
+# define SBRK_ARG_T ptrdiff_t
-
-# ifdef RS6000
-/* The compiler seems to generate speculative reads one past the end of */
-/* an allocated object. Hence we need to make sure that the page */
-/* following the last heap page is also mapped. */
-ptr_t GC_unix_get_mem(bytes)
-word bytes;
-{
- caddr_t cur_brk = (caddr_t)sbrk(0);
- caddr_t result;
- SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
- static caddr_t my_brk_val = 0;
-
- if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
- if (lsbs != 0) {
- if((caddr_t)(sbrk(GC_page_size - lsbs)) == (caddr_t)(-1)) return(0);
- }
- if (cur_brk == my_brk_val) {
- /* Use the extra block we allocated last time. */
- result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
- if (result == (caddr_t)(-1)) return(0);
- result -= GC_page_size;
- } else {
- result = (ptr_t)sbrk(GC_page_size + (SBRK_ARG_T)bytes);
- if (result == (caddr_t)(-1)) return(0);
- }
- my_brk_val = result + bytes + GC_page_size; /* Always page aligned */
- return((ptr_t)result);
-}
-
-#else /* Not RS6000 */
-
-#if defined(USE_MMAP) || defined(USE_MUNMAP)
+#if defined(MMAP_SUPPORTED)
#ifdef USE_MMAP_FIXED
# define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
- /* Seems to yield better performance on Solaris 2, but can */
- /* be unreliable if something is already mapped at the address. */
+ /* Seems to yield better performance on Solaris 2, but can */
+ /* be unreliable if something is already mapped at the address. */
#else
# define GC_MMAP_FLAGS MAP_PRIVATE
#endif
@@ -1550,19 +2023,17 @@ word bytes;
#else
static int zero_fd;
# define OPT_MAP_ANON 0
-#endif
-
-#endif /* defined(USE_MMAP) || defined(USE_MUNMAP) */
-
-#if defined(USE_MMAP)
-/* Tested only under Linux, IRIX5 and Solaris 2 */
+#endif
#ifndef HEAP_START
-# define HEAP_START 0
+# define HEAP_START ((ptr_t)0)
+#endif
+
+#ifdef SYMBIAN
+ extern char* GC_get_private_path_and_zero_file(void);
#endif
-ptr_t GC_unix_get_mem(bytes)
-word bytes;
+STATIC ptr_t GC_unix_mmap_get_mem(word bytes)
{
void *result;
static ptr_t last_addr = HEAP_START;
@@ -1570,63 +2041,122 @@ word bytes;
# ifndef USE_MMAP_ANON
static GC_bool initialized = FALSE;
- if (!initialized) {
- zero_fd = open("/dev/zero", O_RDONLY);
- fcntl(zero_fd, F_SETFD, FD_CLOEXEC);
- initialized = TRUE;
+ if (!EXPECT(initialized, TRUE)) {
+# ifdef SYMBIAN
+ char* path = GC_get_private_path_and_zero_file();
+ zero_fd = open(path, O_RDWR | O_CREAT, 0666);
+ free(path);
+# else
+ zero_fd = open("/dev/zero", O_RDONLY);
+# endif
+ if (zero_fd == -1)
+ ABORT("Could not open /dev/zero");
+
+ fcntl(zero_fd, F_SETFD, FD_CLOEXEC);
+ initialized = TRUE;
}
# endif
- if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg");
- result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
- GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0/* offset */);
+ if (bytes & (GC_page_size - 1)) ABORT("Bad GET_MEM arg");
+ result = mmap(last_addr, bytes, (PROT_READ | PROT_WRITE)
+ | (GC_pages_executable ? PROT_EXEC : 0),
+ GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0/* offset */);
+# undef IGNORE_PAGES_EXECUTABLE
+
if (result == MAP_FAILED) return(0);
last_addr = (ptr_t)result + bytes + GC_page_size - 1;
last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
# if !defined(LINUX)
if (last_addr == 0) {
- /* Oops. We got the end of the address space. This isn't */
- /* usable by arbitrary C code, since one-past-end pointers */
- /* don't work, so we discard it and try again. */
- munmap(result, (size_t)(-GC_page_size) - (size_t)result);
- /* Leave last page mapped, so we can't repeat. */
- return GC_unix_get_mem(bytes);
+ /* Oops. We got the end of the address space. This isn't */
+ /* usable by arbitrary C code, since one-past-end pointers */
+ /* don't work, so we discard it and try again. */
+ munmap(result, (size_t)(-GC_page_size) - (size_t)result);
+ /* Leave last page mapped, so we can't repeat. */
+ return GC_unix_mmap_get_mem(bytes);
}
# else
GC_ASSERT(last_addr != 0);
# endif
+ if (((word)result % HBLKSIZE) != 0)
+ ABORT(
+ "GC_unix_get_mem: Memory returned by mmap is not aligned to HBLKSIZE.");
return((ptr_t)result);
}
-#else /* Not RS6000, not USE_MMAP */
-ptr_t GC_unix_get_mem(bytes)
-word bytes;
+# endif /* MMAP_SUPPORTED */
+
+#if defined(USE_MMAP)
+ ptr_t GC_unix_get_mem(word bytes)
+ {
+ return GC_unix_mmap_get_mem(bytes);
+ }
+#else /* !USE_MMAP */
+
+STATIC ptr_t GC_unix_sbrk_get_mem(word bytes)
{
ptr_t result;
# ifdef IRIX5
- /* Bare sbrk isn't thread safe. Play by malloc rules. */
- /* The equivalent may be needed on other systems as well. */
+ /* Bare sbrk isn't thread safe. Play by malloc rules. */
+ /* The equivalent may be needed on other systems as well. */
__LOCK_MALLOC();
# endif
{
ptr_t cur_brk = (ptr_t)sbrk(0);
SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
-
- if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
+
+ if ((SBRK_ARG_T)bytes < 0) {
+ result = 0; /* too big */
+ goto out;
+ }
if (lsbs != 0) {
- if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) return(0);
+ if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) {
+ result = 0;
+ goto out;
+ }
}
+# ifdef ADD_HEAP_GUARD_PAGES
+ /* This is useful for catching severe memory overwrite problems that */
+ /* span heap sections. It shouldn't otherwise be turned on. */
+ {
+ ptr_t guard = (ptr_t)sbrk((SBRK_ARG_T)GC_page_size);
+ if (mprotect(guard, GC_page_size, PROT_NONE) != 0)
+ ABORT("ADD_HEAP_GUARD_PAGES: mprotect failed");
+ }
+# endif /* ADD_HEAP_GUARD_PAGES */
result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
if (result == (ptr_t)(-1)) result = 0;
}
+ out:
# ifdef IRIX5
__UNLOCK_MALLOC();
# endif
return(result);
}
-#endif /* Not USE_MMAP */
-#endif /* Not RS6000 */
+ptr_t GC_unix_get_mem(word bytes)
+{
+# if defined(MMAP_SUPPORTED)
+ /* By default, we try both sbrk and mmap, in that order. */
+ static GC_bool sbrk_failed = FALSE;
+ ptr_t result = 0;
+
+ if (!sbrk_failed) result = GC_unix_sbrk_get_mem(bytes);
+ if (0 == result) {
+ sbrk_failed = TRUE;
+ result = GC_unix_mmap_get_mem(bytes);
+ }
+ if (0 == result) {
+ /* Try sbrk again, in case sbrk memory became available. */
+ result = GC_unix_sbrk_get_mem(bytes);
+ }
+ return result;
+# else /* !MMAP_SUPPORTED */
+ return GC_unix_sbrk_get_mem(bytes);
+# endif
+}
+
+#endif /* !USE_MMAP */
# endif /* UN*X */
@@ -1636,23 +2166,75 @@ void * os2_alloc(size_t bytes)
{
void * result;
- if (DosAllocMem(&result, bytes, PAG_EXECUTE | PAG_READ |
- PAG_WRITE | PAG_COMMIT)
- != NO_ERROR) {
- return(0);
+ if (DosAllocMem(&result, bytes, (PAG_READ | PAG_WRITE | PAG_COMMIT)
+ | (GC_pages_executable ? PAG_EXECUTE : 0))
+ != NO_ERROR) {
+ return(0);
}
+ /* FIXME: What's the purpose of this recursion? (Probably, if */
+ /* DosAllocMem returns memory at 0 address then just retry once.) */
if (result == 0) return(os2_alloc(bytes));
return(result);
}
# endif /* OS2 */
+#ifdef MSWINCE
+ ptr_t GC_wince_get_mem(word bytes)
+ {
+ ptr_t result = 0; /* initialized to prevent warning. */
+ word i;
-# if defined(MSWIN32) || defined(MSWINCE)
-SYSTEM_INFO GC_sysinfo;
-# endif
+ /* Round up allocation size to multiple of page size */
+ bytes = (bytes + GC_page_size-1) & ~(GC_page_size-1);
-# ifdef MSWIN32
+ /* Try to find reserved, uncommitted pages */
+ for (i = 0; i < GC_n_heap_bases; i++) {
+ if (((word)(-(signed_word)GC_heap_lengths[i])
+ & (GC_sysinfo.dwAllocationGranularity-1))
+ >= bytes) {
+ result = GC_heap_bases[i] + GC_heap_lengths[i];
+ break;
+ }
+ }
+
+ if (i == GC_n_heap_bases) {
+ /* Reserve more pages */
+ word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
+ & ~(GC_sysinfo.dwAllocationGranularity-1);
+ /* If we ever support MPROTECT_VDB here, we will probably need to */
+ /* ensure that res_bytes is strictly > bytes, so that VirtualProtect */
+ /* never spans regions. It seems to be OK for a VirtualFree */
+ /* argument to span regions, so we should be OK for now. */
+ result = (ptr_t) VirtualAlloc(NULL, res_bytes,
+ MEM_RESERVE | MEM_TOP_DOWN,
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE :
+ PAGE_READWRITE);
+ if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
+ /* 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");
+ if (result == NULL) return NULL;
+ GC_heap_bases[GC_n_heap_bases] = result;
+ GC_heap_lengths[GC_n_heap_bases] = 0;
+ GC_n_heap_bases++;
+ }
+
+ /* Commit pages */
+ result = (ptr_t) VirtualAlloc(result, bytes, MEM_COMMIT,
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE :
+ PAGE_READWRITE);
+# undef IGNORE_PAGES_EXECUTABLE
+
+ if (result != NULL) {
+ if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
+ GC_heap_lengths[i] += bytes;
+ }
+
+ return(result);
+ }
+
+#elif defined(USE_WINALLOC) || defined(CYGWIN32)
# ifdef USE_GLOBAL_ALLOC
# define GLOBAL_ALLOC_TEST 1
@@ -1660,286 +2242,293 @@ SYSTEM_INFO GC_sysinfo;
# define GLOBAL_ALLOC_TEST GC_no_win32_dlls
# endif
-word GC_n_heap_bases = 0;
+# if defined(GC_USE_MEM_TOP_DOWN) && defined(USE_WINALLOC)
+ DWORD GC_mem_top_down = MEM_TOP_DOWN;
+ /* Use GC_USE_MEM_TOP_DOWN for better 64-bit */
+ /* testing. Otherwise all addresses tend to */
+ /* end up in first 4GB, hiding bugs. */
+# else
+# define GC_mem_top_down 0
+# endif /* !GC_USE_MEM_TOP_DOWN */
-ptr_t GC_win32_get_mem(bytes)
-word bytes;
-{
+ ptr_t GC_win32_get_mem(word bytes)
+ {
ptr_t result;
- if (GLOBAL_ALLOC_TEST) {
- /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE. */
- /* There are also unconfirmed rumors of other */
- /* problems, so we dodge the issue. */
+# ifndef USE_WINALLOC
+ result = GC_unix_get_mem(bytes);
+# else
+# ifdef MSWIN32
+ if (GLOBAL_ALLOC_TEST) {
+ /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE. */
+ /* There are also unconfirmed rumors of other */
+ /* problems, so we dodge the issue. */
result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
- result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));
- } else {
- /* VirtualProtect only works on regions returned by a */
- /* single VirtualAlloc call. Thus we allocate one */
- /* extra page, which will prevent merging of blocks */
- /* in separate regions, and eliminate any temptation */
- /* to call VirtualProtect on a range spanning regions. */
- /* This wastes a small amount of memory, and risks */
- /* increased fragmentation. But better alternatives */
- /* would require effort. */
- result = (ptr_t) VirtualAlloc(NULL, bytes + 1,
- MEM_COMMIT | MEM_RESERVE,
- PAGE_EXECUTE_READWRITE);
+ result = (ptr_t)(((word)result + HBLKSIZE - 1) & ~(HBLKSIZE-1));
+ } else
+# endif
+ /* else */ {
+ /* VirtualProtect only works on regions returned by a */
+ /* single VirtualAlloc call. Thus we allocate one */
+ /* extra page, which will prevent merging of blocks */
+ /* in separate regions, and eliminate any temptation */
+ /* to call VirtualProtect on a range spanning regions. */
+ /* This wastes a small amount of memory, and risks */
+ /* increased fragmentation. But better alternatives */
+ /* would require effort. */
+# ifdef MPROTECT_VDB
+ /* We can't check for GC_incremental here (because */
+ /* GC_enable_incremental() might be called some time */
+ /* later after the GC initialization). */
+# ifdef GWW_VDB
+# define VIRTUAL_ALLOC_PAD (GC_GWW_AVAILABLE() ? 0 : 1)
+# else
+# define VIRTUAL_ALLOC_PAD 1
+# endif
+# else
+# define VIRTUAL_ALLOC_PAD 0
+# endif
+ /* Pass the MEM_WRITE_WATCH only if GetWriteWatch-based */
+ /* VDBs are enabled and the GetWriteWatch function is */
+ /* available. Otherwise we waste resources or possibly */
+ /* cause VirtualAlloc to fail (observed in Windows 2000 */
+ /* SP2). */
+ result = (ptr_t) VirtualAlloc(NULL, bytes + VIRTUAL_ALLOC_PAD,
+ GetWriteWatch_alloc_flag
+ | (MEM_COMMIT | MEM_RESERVE)
+ | GC_mem_top_down,
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE :
+ PAGE_READWRITE);
+# undef IGNORE_PAGES_EXECUTABLE
}
+# endif /* USE_WINALLOC */
if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
- /* If I read the documentation correctly, this can */
- /* only happen if HBLKSIZE > 64k or not a power of 2. */
+ /* 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;
- return(result);
-}
+ if (0 != result) GC_heap_bases[GC_n_heap_bases++] = result;
+ return(result);
+ }
-void GC_win32_free_heap ()
-{
- if (GC_no_win32_dlls) {
- while (GC_n_heap_bases > 0) {
- GlobalFree (GC_heap_bases[--GC_n_heap_bases]);
- GC_heap_bases[GC_n_heap_bases] = 0;
- }
+ GC_API void GC_CALL GC_win32_free_heap(void)
+ {
+# ifndef CYGWIN32
+ if (GC_no_win32_dlls)
+# endif
+ {
+ while (GC_n_heap_bases-- > 0) {
+# ifdef CYGWIN32
+ /* FIXME: Is it ok to use non-GC free() here? */
+# else
+ GlobalFree(GC_heap_bases[GC_n_heap_bases]);
+# endif
+ GC_heap_bases[GC_n_heap_bases] = 0;
+ }
}
-}
-# endif
+ }
+#endif /* USE_WINALLOC || CYGWIN32 */
#ifdef AMIGA
# define GC_AMIGA_AM
-# include "AmigaOS.c"
+# include "extra/AmigaOS.c"
# undef GC_AMIGA_AM
#endif
-
-# ifdef MSWINCE
-word GC_n_heap_bases = 0;
-
-ptr_t GC_wince_get_mem(bytes)
-word bytes;
-{
- ptr_t result;
- word i;
-
- /* Round up allocation size to multiple of page size */
- bytes = (bytes + GC_page_size-1) & ~(GC_page_size-1);
-
- /* Try to find reserved, uncommitted pages */
- for (i = 0; i < GC_n_heap_bases; i++) {
- if (((word)(-(signed_word)GC_heap_lengths[i])
- & (GC_sysinfo.dwAllocationGranularity-1))
- >= bytes) {
- result = GC_heap_bases[i] + GC_heap_lengths[i];
- break;
- }
- }
-
- if (i == GC_n_heap_bases) {
- /* Reserve more pages */
- word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
- & ~(GC_sysinfo.dwAllocationGranularity-1);
- /* If we ever support MPROTECT_VDB here, we will probably need to */
- /* ensure that res_bytes is strictly > bytes, so that VirtualProtect */
- /* never spans regions. It seems to be OK for a VirtualFree argument */
- /* to span regions, so we should be OK for now. */
- result = (ptr_t) VirtualAlloc(NULL, res_bytes,
- MEM_RESERVE | MEM_TOP_DOWN,
- PAGE_EXECUTE_READWRITE);
- if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
- /* 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;
- GC_heap_lengths[GC_n_heap_bases] = 0;
- GC_n_heap_bases++;
- }
-
- /* Commit pages */
- result = (ptr_t) VirtualAlloc(result, bytes,
- MEM_COMMIT,
- PAGE_EXECUTE_READWRITE);
- if (result != NULL) {
- if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
- GC_heap_lengths[i] += bytes;
- }
-
- return(result);
-}
-# endif
-
#ifdef USE_MUNMAP
-/* For now, this only works on Win32/WinCE and some Unix-like */
-/* systems. If you have something else, don't define */
-/* USE_MUNMAP. */
-/* We assume ANSI C to support this feature. */
+/* For now, this only works on Win32/WinCE and some Unix-like */
+/* systems. If you have something else, don't define */
+/* USE_MUNMAP. */
#if !defined(MSWIN32) && !defined(MSWINCE)
-
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
+# include <unistd.h>
+# include <sys/mman.h>
+# include <sys/stat.h>
+# include <sys/types.h>
#endif
-/* Compute a page aligned starting address for the unmap */
-/* operation on a block of size bytes starting at start. */
-/* Return 0 if the block is too small to make this feasible. */
-ptr_t GC_unmap_start(ptr_t start, word bytes)
+/* Compute a page aligned starting address for the unmap */
+/* operation on a block of size bytes starting at start. */
+/* Return 0 if the block is too small to make this feasible. */
+STATIC ptr_t GC_unmap_start(ptr_t start, size_t bytes)
{
- ptr_t result = start;
+ ptr_t result;
/* Round start to next page boundary. */
- result += GC_page_size - 1;
- result = (ptr_t)((word)result & ~(GC_page_size - 1));
- if (result + GC_page_size > start + bytes) return 0;
+ result = (ptr_t)((word)(start + GC_page_size - 1) & ~(GC_page_size - 1));
+ if ((word)(result + GC_page_size) > (word)(start + bytes)) return 0;
return result;
}
-/* Compute end address for an unmap operation on the indicated */
-/* block. */
-ptr_t GC_unmap_end(ptr_t start, word bytes)
+/* Compute end address for an unmap operation on the indicated */
+/* block. */
+STATIC ptr_t GC_unmap_end(ptr_t start, size_t bytes)
{
- ptr_t end_addr = start + bytes;
- end_addr = (ptr_t)((word)end_addr & ~(GC_page_size - 1));
- return end_addr;
+ return (ptr_t)((word)(start + bytes) & ~(GC_page_size - 1));
}
-/* Under Win32/WinCE we commit (map) and decommit (unmap) */
-/* memory using VirtualAlloc and VirtualFree. These functions */
-/* work on individual allocations of virtual memory, made */
-/* previously using VirtualAlloc with the MEM_RESERVE flag. */
-/* The ranges we need to (de)commit may span several of these */
-/* allocations; therefore we use VirtualQuery to check */
-/* allocation lengths, and split up the range as necessary. */
-
-/* We assume that GC_remap is called on exactly the same range */
-/* as a previous call to GC_unmap. It is safe to consistently */
-/* round the endpoints in both places. */
-void GC_unmap(ptr_t start, word bytes)
+/* Under Win32/WinCE we commit (map) and decommit (unmap) */
+/* memory using VirtualAlloc and VirtualFree. These functions */
+/* work on individual allocations of virtual memory, made */
+/* previously using VirtualAlloc with the MEM_RESERVE flag. */
+/* The ranges we need to (de)commit may span several of these */
+/* allocations; therefore we use VirtualQuery to check */
+/* allocation lengths, and split up the range as necessary. */
+
+/* We assume that GC_remap is called on exactly the same range */
+/* as a previous call to GC_unmap. It is safe to consistently */
+/* round the endpoints in both places. */
+GC_INNER void GC_unmap(ptr_t start, size_t bytes)
{
ptr_t start_addr = GC_unmap_start(start, bytes);
ptr_t end_addr = GC_unmap_end(start, bytes);
word len = end_addr - start_addr;
+
if (0 == start_addr) return;
-# if defined(MSWIN32) || defined(MSWINCE)
+# ifdef USE_WINALLOC
while (len != 0) {
MEMORY_BASIC_INFORMATION mem_info;
- GC_word free_len;
- if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
- != sizeof(mem_info))
- ABORT("Weird VirtualQuery result");
- free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
- if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
- ABORT("VirtualFree failed");
- GC_unmapped_bytes += free_len;
- start_addr += free_len;
- len -= free_len;
+ GC_word free_len;
+
+ if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
+ != sizeof(mem_info))
+ ABORT("Weird VirtualQuery result");
+ free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
+ if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
+ ABORT("VirtualFree failed");
+ GC_unmapped_bytes += free_len;
+ start_addr += free_len;
+ len -= free_len;
}
# else
- /* We immediately remap it to prevent an intervening mmap from */
- /* accidentally grabbing the same address space. */
+ /* We immediately remap it to prevent an intervening mmap from */
+ /* accidentally grabbing the same address space. */
{
- void * result;
+ void * result;
+
result = mmap(start_addr, len, PROT_NONE,
- MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
- zero_fd, 0/* offset */);
- if (result != (void *)start_addr) ABORT("mmap(...PROT_NONE...) failed");
+ MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
+ zero_fd, 0/* offset */);
+ if (result != (void *)start_addr)
+ ABORT("mmap(PROT_NONE) failed");
}
GC_unmapped_bytes += len;
# endif
}
-
-void GC_remap(ptr_t start, word bytes)
+GC_INNER void GC_remap(ptr_t start, size_t bytes)
{
ptr_t start_addr = GC_unmap_start(start, bytes);
ptr_t end_addr = GC_unmap_end(start, bytes);
word len = end_addr - start_addr;
+ if (0 == start_addr) return;
-# if defined(MSWIN32) || defined(MSWINCE)
- ptr_t result;
-
- if (0 == start_addr) return;
+ /* FIXME: Handle out-of-memory correctly (at least for Win32) */
+# ifdef USE_WINALLOC
while (len != 0) {
MEMORY_BASIC_INFORMATION mem_info;
- GC_word alloc_len;
- if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
- != sizeof(mem_info))
- ABORT("Weird VirtualQuery result");
- alloc_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
- result = VirtualAlloc(start_addr, alloc_len,
- MEM_COMMIT,
- PAGE_EXECUTE_READWRITE);
- if (result != start_addr) {
- ABORT("VirtualAlloc remapping failed");
- }
- GC_unmapped_bytes -= alloc_len;
- start_addr += alloc_len;
- len -= alloc_len;
+ GC_word alloc_len;
+ ptr_t result;
+
+ if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
+ != sizeof(mem_info))
+ ABORT("Weird VirtualQuery result");
+ alloc_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
+ result = VirtualAlloc(start_addr, alloc_len, MEM_COMMIT,
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE :
+ PAGE_READWRITE);
+ if (result != start_addr) {
+ if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
+ GetLastError() == ERROR_OUTOFMEMORY) {
+ ABORT("Not enough memory to process remapping");
+ } else {
+ ABORT("VirtualAlloc remapping failed");
+ }
+ }
+ GC_unmapped_bytes -= alloc_len;
+ start_addr += alloc_len;
+ len -= alloc_len;
}
# else
/* It was already remapped with PROT_NONE. */
- int result;
-
- if (0 == start_addr) return;
- result = mprotect(start_addr, len,
- PROT_READ | PROT_WRITE | OPT_PROT_EXEC);
- if (result != 0) {
- GC_err_printf3(
- "Mprotect failed at 0x%lx (length %ld) with errno %ld\n",
- start_addr, len, errno);
- ABORT("Mprotect remapping failed");
+ {
+# ifdef NACL
+ /* NaCl does not expose mprotect, but mmap should work fine. */
+ void *mmap_result = mmap(start_addr, len, (PROT_READ | PROT_WRITE)
+ | (GC_pages_executable ? PROT_EXEC : 0),
+ MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
+ zero_fd, 0 /* offset */);
+ if (mmap_result != (void *)start_addr)
+ ABORT("mmap as mprotect failed");
+# else
+ if (mprotect(start_addr, len, (PROT_READ | PROT_WRITE)
+ | (GC_pages_executable ? PROT_EXEC : 0)) != 0) {
+ GC_COND_LOG_PRINTF("mprotect failed at %p (length %lu)"
+ " with errno %d\n",
+ start_addr, (unsigned long)len, errno);
+ ABORT("mprotect remapping failed");
+ }
+# endif /* !NACL */
}
+# undef IGNORE_PAGES_EXECUTABLE
GC_unmapped_bytes -= len;
# endif
}
-/* Two adjacent blocks have already been unmapped and are about to */
-/* be merged. Unmap the whole block. This typically requires */
-/* that we unmap a small section in the middle that was not previously */
-/* unmapped due to alignment constraints. */
-void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2)
+/* Two adjacent blocks have already been unmapped and are about to */
+/* be merged. Unmap the whole block. This typically requires */
+/* that we unmap a small section in the middle that was not previously */
+/* unmapped due to alignment constraints. */
+GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
+ size_t bytes2)
{
ptr_t start1_addr = GC_unmap_start(start1, bytes1);
ptr_t end1_addr = GC_unmap_end(start1, bytes1);
ptr_t start2_addr = GC_unmap_start(start2, bytes2);
- ptr_t end2_addr = GC_unmap_end(start2, bytes2);
ptr_t start_addr = end1_addr;
ptr_t end_addr = start2_addr;
- word len;
+ size_t len;
+
GC_ASSERT(start1 + bytes1 == start2);
if (0 == start1_addr) start_addr = GC_unmap_start(start1, bytes1 + bytes2);
if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);
if (0 == start_addr) return;
len = end_addr - start_addr;
-# if defined(MSWIN32) || defined(MSWINCE)
+# ifdef USE_WINALLOC
while (len != 0) {
MEMORY_BASIC_INFORMATION mem_info;
- GC_word free_len;
- if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
- != sizeof(mem_info))
- ABORT("Weird VirtualQuery result");
- free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
- if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
- ABORT("VirtualFree failed");
- GC_unmapped_bytes += free_len;
- start_addr += free_len;
- len -= free_len;
+ GC_word free_len;
+
+ if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
+ != sizeof(mem_info))
+ ABORT("Weird VirtualQuery result");
+ free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
+ if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
+ ABORT("VirtualFree failed");
+ GC_unmapped_bytes += free_len;
+ start_addr += free_len;
+ len -= free_len;
}
# else
- if (len != 0 && munmap(start_addr, len) != 0) ABORT("munmap failed");
+ if (len != 0) {
+ /* Immediately remap as above. */
+ void * result;
+ result = mmap(start_addr, len, PROT_NONE,
+ MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
+ zero_fd, 0/* offset */);
+ if (result != (void *)start_addr)
+ ABORT("mmap(PROT_NONE) failed");
+ }
GC_unmapped_bytes += len;
# endif
}
#endif /* USE_MUNMAP */
-/* Routine for pushing any additional roots. In THREADS */
-/* environment, this is also responsible for marking from */
-/* thread stacks. */
+/* Routine for pushing any additional roots. In THREADS */
+/* environment, this is also responsible for marking from */
+/* thread stacks. */
#ifndef THREADS
-void (*GC_push_other_roots)() = 0;
+ GC_push_other_roots_proc GC_push_other_roots = 0;
#else /* THREADS */
# ifdef PCR
@@ -1947,718 +2536,738 @@ PCR_ERes GC_push_thread_stack(PCR_Th_T *t, PCR_Any dummy)
{
struct PCR_ThCtl_TInfoRep info;
PCR_ERes result;
-
+
info.ti_stkLow = info.ti_stkHi = 0;
result = PCR_ThCtl_GetInfo(t, &info);
GC_push_all_stack((ptr_t)(info.ti_stkLow), (ptr_t)(info.ti_stkHi));
return(result);
}
-/* Push the contents of an old object. We treat this as stack */
-/* data only becasue that makes it robust against mark stack */
-/* overflow. */
+/* Push the contents of an old object. We treat this as stack */
+/* data only because that makes it robust against mark stack */
+/* overflow. */
PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any data)
{
GC_push_all_stack((ptr_t)p, (ptr_t)p + size);
return(PCR_ERes_okay);
}
+extern struct PCR_MM_ProcsRep * GC_old_allocator;
+ /* defined in pcr_interface.c. */
-void GC_default_push_other_roots GC_PROTO((void))
+STATIC void GC_CALLBACK GC_default_push_other_roots(void)
{
- /* Traverse data allocated by previous memory managers. */
- {
- extern struct PCR_MM_ProcsRep * GC_old_allocator;
-
- if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
- GC_push_old_obj, 0)
- != PCR_ERes_okay) {
- ABORT("Old object enumeration failed");
- }
- }
+ /* Traverse data allocated by previous memory managers. */
+ if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
+ GC_push_old_obj, 0)
+ != PCR_ERes_okay) {
+ ABORT("Old object enumeration failed");
+ }
/* Traverse all thread stacks. */
- if (PCR_ERes_IsErr(
+ if (PCR_ERes_IsErr(
PCR_ThCtl_ApplyToAllOtherThreads(GC_push_thread_stack,0))
- || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
- ABORT("Thread stack marking failed\n");
- }
+ || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
+ ABORT("Thread stack marking failed");
+ }
}
# endif /* PCR */
-# ifdef SRC_M3
+# if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
+ STATIC void GC_CALLBACK GC_default_push_other_roots(void)
+ {
+ GC_push_all_stacks();
+ }
+# endif /* GC_WIN32_THREADS || GC_PTHREADS */
-# ifdef ALL_INTERIOR_POINTERS
- --> misconfigured
-# endif
+# ifdef SN_TARGET_PS3
+ STATIC void GC_CALLBACK GC_default_push_other_roots(void)
+ {
+ ABORT("GC_default_push_other_roots is not implemented");
+ }
-void GC_push_thread_structures GC_PROTO((void))
-{
- /* Not our responsibibility. */
-}
+ void GC_push_thread_structures(void)
+ {
+ ABORT("GC_push_thread_structures is not implemented");
+ }
+# endif /* SN_TARGET_PS3 */
-extern void ThreadF__ProcessStacks();
+ GC_push_other_roots_proc GC_push_other_roots = GC_default_push_other_roots;
+#endif /* THREADS */
-void GC_push_thread_stack(start, stop)
-word start, stop;
+GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc fn)
{
- GC_push_all_stack((ptr_t)start, (ptr_t)stop + sizeof(word));
+ GC_push_other_roots = fn;
}
-/* Push routine with M3 specific calling convention. */
-GC_m3_push_root(dummy1, p, dummy2, dummy3)
-word *p;
-ptr_t dummy1, dummy2;
-int dummy3;
+GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
{
- word q = *p;
-
- GC_PUSH_ONE_STACK(q, p);
+ return GC_push_other_roots;
}
-/* M3 set equivalent to RTHeap.TracedRefTypes */
-typedef struct { int elts[1]; } RefTypeSet;
-RefTypeSet GC_TracedRefTypes = {{0x1}};
+/*
+ * Routines for accessing dirty bits on virtual pages.
+ * There are six ways to maintain this information:
+ * DEFAULT_VDB: A simple dummy implementation that treats every page
+ * as possibly dirty. This makes incremental collection
+ * useless, but the implementation is still correct.
+ * MANUAL_VDB: Stacks and static data are always considered dirty.
+ * Heap pages are considered dirty if GC_dirty(p) has been
+ * called on some pointer p pointing to somewhere inside
+ * an object on that page. A GC_dirty() call on a large
+ * object directly dirties only a single page, but for
+ * MANUAL_VDB we are careful to treat an object with a dirty
+ * page as completely dirty.
+ * In order to avoid races, an object must be marked dirty
+ * after it is written, and a reference to the object
+ * must be kept on a stack or in a register in the interim.
+ * With threads enabled, an object directly reachable from the
+ * stack at the time of a collection is treated as dirty.
+ * In single-threaded mode, it suffices to ensure that no
+ * collection can take place between the pointer assignment
+ * and the GC_dirty() call.
+ * PCR_VDB: Use PPCRs virtual dirty bit facility.
+ * PROC_VDB: Use the /proc facility for reading dirty bits. Only
+ * works under some SVR4 variants. Even then, it may be
+ * too slow to be entirely satisfactory. Requires reading
+ * dirty bits for entire address space. Implementations tend
+ * to assume that the client is a (slow) debugger.
+ * MPROTECT_VDB:Protect pages and then catch the faults to keep track of
+ * dirtied pages. The implementation (and implementability)
+ * is highly system dependent. This usually fails when system
+ * calls write to a protected page. We prevent the read system
+ * call from doing so. It is the clients responsibility to
+ * make sure that other system calls are similarly protected
+ * or write only to the stack.
+ * GWW_VDB: Use the Win32 GetWriteWatch functions, if available, to
+ * read dirty bits. In case it is not available (because we
+ * are running on Windows 95, Windows 2000 or earlier),
+ * MPROTECT_VDB may be defined as a fallback strategy.
+ */
+#ifndef GC_DISABLE_INCREMENTAL
+ GC_INNER GC_bool GC_dirty_maintained = FALSE;
+#endif
-void GC_default_push_other_roots GC_PROTO((void))
-{
- /* Use the M3 provided routine for finding static roots. */
- /* This is a bit dubious, since it presumes no C roots. */
- /* We handle the collector roots explicitly in GC_push_roots */
- RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);
- if (GC_words_allocd > 0) {
- ThreadF__ProcessStacks(GC_push_thread_stack);
- }
- /* Otherwise this isn't absolutely necessary, and we have */
- /* startup ordering problems. */
-}
+#if defined(PROC_VDB) || defined(GWW_VDB)
+ /* Add all pages in pht2 to pht1 */
+ STATIC void GC_or_pages(page_hash_table pht1, page_hash_table pht2)
+ {
+ register unsigned i;
+ for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
+ }
-# endif /* SRC_M3 */
+# ifdef MPROTECT_VDB
+ STATIC GC_bool GC_gww_page_was_dirty(struct hblk * h)
+# else
+ GC_INNER GC_bool GC_page_was_dirty(struct hblk * h)
+# endif
+ {
+ register word index;
+ if (HDR(h) == 0)
+ return TRUE;
+ index = PHT_HASH(h);
+ return get_pht_entry_from_index(GC_grungy_pages, index);
+ }
-# if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS) || \
- defined(GC_WIN32_THREADS)
+# if defined(CHECKSUMS) || defined(PROC_VDB)
+ /* Used only if GWW_VDB. */
+# ifdef MPROTECT_VDB
+ STATIC GC_bool GC_gww_page_was_ever_dirty(struct hblk * h)
+# else
+ GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h)
+# endif
+ {
+ register word index;
+ if (HDR(h) == 0)
+ return TRUE;
+ index = PHT_HASH(h);
+ return get_pht_entry_from_index(GC_written_pages, index);
+ }
+# endif /* CHECKSUMS || PROC_VDB */
-extern void GC_push_all_stacks();
+# ifndef MPROTECT_VDB
+ /* Ignore write hints. They don't help us here. */
+ GC_INNER void GC_remove_protection(struct hblk * h GC_ATTR_UNUSED,
+ word nblocks GC_ATTR_UNUSED,
+ GC_bool is_ptrfree GC_ATTR_UNUSED) {}
+# endif
-void GC_default_push_other_roots GC_PROTO((void))
-{
- GC_push_all_stacks();
-}
+#endif /* PROC_VDB || GWW_VDB */
-# endif /* GC_SOLARIS_THREADS || GC_PTHREADS */
+#ifdef GWW_VDB
-void (*GC_push_other_roots) GC_PROTO((void)) = GC_default_push_other_roots;
+# define GC_GWW_BUF_LEN (MAXHINCR * HBLKSIZE / 4096 /* X86 page size */)
+ /* Still susceptible to overflow, if there are very large allocations, */
+ /* and everything is dirty. */
+ static PVOID gww_buf[GC_GWW_BUF_LEN];
-#endif /* THREADS */
+# ifdef MPROTECT_VDB
+ GC_INNER GC_bool GC_gww_dirty_init(void)
+ {
+ detect_GetWriteWatch();
+ return GC_GWW_AVAILABLE();
+ }
+# else
+ GC_INNER void GC_dirty_init(void)
+ {
+ detect_GetWriteWatch();
+ GC_dirty_maintained = GC_GWW_AVAILABLE();
+ }
+# endif /* !MPROTECT_VDB */
-/*
- * Routines for accessing dirty bits on virtual pages.
- * We plan to eventually implement four strategies for doing so:
- * DEFAULT_VDB: A simple dummy implementation that treats every page
- * as possibly dirty. This makes incremental collection
- * useless, but the implementation is still correct.
- * PCR_VDB: Use PPCRs virtual dirty bit facility.
- * PROC_VDB: Use the /proc facility for reading dirty bits. Only
- * works under some SVR4 variants. Even then, it may be
- * too slow to be entirely satisfactory. Requires reading
- * dirty bits for entire address space. Implementations tend
- * to assume that the client is a (slow) debugger.
- * MPROTECT_VDB:Protect pages and then catch the faults to keep track of
- * dirtied pages. The implementation (and implementability)
- * is highly system dependent. This usually fails when system
- * calls write to a protected page. We prevent the read system
- * call from doing so. It is the clients responsibility to
- * make sure that other system calls are similarly protected
- * or write only to the stack.
- */
-GC_bool GC_dirty_maintained = FALSE;
+# ifdef MPROTECT_VDB
+ STATIC void GC_gww_read_dirty(void)
+# else
+ GC_INNER void GC_read_dirty(void)
+# endif
+ {
+ word i;
+
+ BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
+
+ for (i = 0; i != GC_n_heap_sects; ++i) {
+ GC_ULONG_PTR count;
+
+ do {
+ PVOID * pages, * pages_end;
+ DWORD page_size;
+
+ pages = gww_buf;
+ count = GC_GWW_BUF_LEN;
+ /* GetWriteWatch is documented as returning non-zero when it */
+ /* fails, but the documentation doesn't explicitly say why it */
+ /* would fail or what its behaviour will be if it fails. */
+ /* It does appear to fail, at least on recent W2K instances, if */
+ /* the underlying memory was not allocated with the appropriate */
+ /* flag. This is common if GC_enable_incremental is called */
+ /* shortly after GC initialization. To avoid modifying the */
+ /* interface, we silently work around such a failure, it only */
+ /* affects the initial (small) heap allocation. If there are */
+ /* more dirty pages than will fit in the buffer, this is not */
+ /* treated as a failure; we must check the page count in the */
+ /* loop condition. Since each partial call will reset the */
+ /* status of some pages, this should eventually terminate even */
+ /* in the overflow case. */
+ if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
+ GC_heap_sects[i].hs_start,
+ GC_heap_sects[i].hs_bytes,
+ pages,
+ &count,
+ &page_size) != 0) {
+ static int warn_count = 0;
+ unsigned j;
+ struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start;
+ static struct hblk *last_warned = 0;
+ size_t nblocks = divHBLKSZ(GC_heap_sects[i].hs_bytes);
+
+ if ( i != 0 && last_warned != start && warn_count++ < 5) {
+ last_warned = start;
+ WARN(
+ "GC_gww_read_dirty unexpectedly failed at %p: "
+ "Falling back to marking all pages dirty\n", start);
+ }
+ for (j = 0; j < nblocks; ++j) {
+ word hash = PHT_HASH(start + j);
+ set_pht_entry_from_index(GC_grungy_pages, hash);
+ }
+ count = 1; /* Done with this section. */
+ } else /* succeeded */ {
+ pages_end = pages + count;
+ while (pages != pages_end) {
+ struct hblk * h = (struct hblk *) *pages++;
+ struct hblk * h_end = (struct hblk *) ((char *) h + page_size);
+ do {
+ set_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
+ } while ((word)(++h) < (word)h_end);
+ }
+ }
+ } while (count == GC_GWW_BUF_LEN);
+ /* FIXME: It's unclear from Microsoft's documentation if this loop */
+ /* is useful. We suspect the call just fails if the buffer fills */
+ /* up. But that should still be handled correctly. */
+ }
-# ifdef DEFAULT_VDB
+ GC_or_pages(GC_written_pages, GC_grungy_pages);
+ }
+#endif /* GWW_VDB */
-/* All of the following assume the allocation lock is held, and */
-/* signals are disabled. */
+#ifdef DEFAULT_VDB
+ /* All of the following assume the allocation lock is held. */
-/* The client asserts that unallocated pages in the heap are never */
-/* written. */
+ /* The client asserts that unallocated pages in the heap are never */
+ /* written. */
-/* Initialize virtual dirty bit implementation. */
-void GC_dirty_init()
-{
-# ifdef PRINTSTATS
- GC_printf0("Initializing DEFAULT_VDB...\n");
-# endif
+ /* Initialize virtual dirty bit implementation. */
+ GC_INNER void GC_dirty_init(void)
+ {
+ GC_VERBOSE_LOG_PRINTF("Initializing DEFAULT_VDB...\n");
GC_dirty_maintained = TRUE;
-}
+ }
-/* Retrieve system dirty bits for heap to a local buffer. */
-/* Restore the systems notion of which pages are dirty. */
-void GC_read_dirty()
-{}
-
-/* Is the HBLKSIZE sized page at h marked dirty in the local buffer? */
-/* If the actual page size is different, this returns TRUE if any */
-/* of the pages overlapping h are dirty. This routine may err on the */
-/* side of labelling pages as dirty (and this implementation does). */
-/*ARGSUSED*/
-GC_bool GC_page_was_dirty(h)
-struct hblk *h;
-{
- return(TRUE);
-}
+ /* Retrieve system dirty bits for heap to a local buffer. */
+ /* Restore the systems notion of which pages are dirty. */
+ GC_INNER void GC_read_dirty(void) {}
-/*
- * The following two routines are typically less crucial. They matter
- * most with large dynamic libraries, or if we can't accurately identify
- * stacks, e.g. under Solaris 2.X. Otherwise the following default
- * versions are adequate.
- */
-
-/* Could any valid GC heap pointer ever have been written to this page? */
-/*ARGSUSED*/
-GC_bool GC_page_was_ever_dirty(h)
-struct hblk *h;
-{
+ /* Is the HBLKSIZE sized page at h marked dirty in the local buffer? */
+ /* If the actual page size is different, this returns TRUE if any */
+ /* of the pages overlapping h are dirty. This routine may err on the */
+ /* side of labeling pages as dirty (and this implementation does). */
+ GC_INNER GC_bool GC_page_was_dirty(struct hblk * h GC_ATTR_UNUSED)
+ {
return(TRUE);
-}
-
-/* Reset the n pages starting at h to "was never dirty" status. */
-void GC_is_fresh(h, n)
-struct hblk *h;
-word n;
-{
-}
+ }
-/* A call that: */
-/* I) hints that [h, h+nblocks) is about to be written. */
-/* II) guarantees that protection is removed. */
-/* (I) may speed up some dirty bit implementations. */
-/* (II) may be essential if we need to ensure that */
-/* pointer-free system call buffers in the heap are */
-/* not protected. */
-/*ARGSUSED*/
-void GC_remove_protection(h, nblocks, is_ptrfree)
-struct hblk *h;
-word nblocks;
-GC_bool is_ptrfree;
-{
-}
+ /* The following two routines are typically less crucial. */
+ /* They matter most with large dynamic libraries, or if we can't */
+ /* accurately identify stacks, e.g. under Solaris 2.X. Otherwise the */
+ /* following default versions are adequate. */
+# ifdef CHECKSUMS
+ /* Could any valid GC heap pointer ever have been written to this page? */
+ GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h GC_ATTR_UNUSED)
+ {
+ return(TRUE);
+ }
+# endif /* CHECKSUMS */
+
+ /* A call that: */
+ /* I) hints that [h, h+nblocks) is about to be written. */
+ /* II) guarantees that protection is removed. */
+ /* (I) may speed up some dirty bit implementations. */
+ /* (II) may be essential if we need to ensure that */
+ /* pointer-free system call buffers in the heap are */
+ /* not protected. */
+ GC_INNER void GC_remove_protection(struct hblk * h GC_ATTR_UNUSED,
+ word nblocks GC_ATTR_UNUSED,
+ GC_bool is_ptrfree GC_ATTR_UNUSED) {}
+#endif /* DEFAULT_VDB */
+
+#ifdef MANUAL_VDB
+ /* Initialize virtual dirty bit implementation. */
+ GC_INNER void GC_dirty_init(void)
+ {
+ GC_VERBOSE_LOG_PRINTF("Initializing MANUAL_VDB...\n");
+ /* GC_dirty_pages and GC_grungy_pages are already cleared. */
+ GC_dirty_maintained = TRUE;
+ }
-# endif /* DEFAULT_VDB */
+ /* Retrieve system dirty bits for heap to a local buffer. */
+ /* Restore the systems notion of which pages are dirty. */
+ GC_INNER void GC_read_dirty(void)
+ {
+ BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
+ (sizeof GC_dirty_pages));
+ BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
+ }
+ /* Is the HBLKSIZE sized page at h marked dirty in the local buffer? */
+ /* If the actual page size is different, this returns TRUE if any */
+ /* of the pages overlapping h are dirty. This routine may err on the */
+ /* side of labeling pages as dirty (and this implementation does). */
+ GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
+ {
+ register word index = PHT_HASH(h);
+ return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
+ }
-# ifdef MPROTECT_VDB
+# define async_set_pht_entry_from_index(db, index) \
+ set_pht_entry_from_index(db, index) /* for now */
-/*
- * See DEFAULT_VDB for interface descriptions.
- */
+ /* Mark the page containing p as dirty. Logically, this dirties the */
+ /* entire object. */
+ void GC_dirty(ptr_t p)
+ {
+ word index = PHT_HASH(p);
+ async_set_pht_entry_from_index(GC_dirty_pages, index);
+ }
-/*
- * This implementation maintains dirty bits itself by catching write
- * faults and keeping track of them. We assume nobody else catches
- * SIGBUS or SIGSEGV. We assume no write faults occur in system calls.
- * This means that clients must ensure that system calls don't write
- * to the write-protected heap. Probably the best way to do this is to
- * ensure that system calls write at most to POINTERFREE objects in the
- * heap, and do even that only if we are on a platform on which those
- * are not protected. Another alternative is to wrap system calls
- * (see example for read below), but the current implementation holds
- * a lock across blocking calls, making it problematic for multithreaded
- * applications.
- * We assume the page size is a multiple of HBLKSIZE.
- * We prefer them to be the same. We avoid protecting POINTERFREE
- * objects only if they are the same.
- */
+ GC_INNER void GC_remove_protection(struct hblk * h GC_ATTR_UNUSED,
+ word nblocks GC_ATTR_UNUSED,
+ GC_bool is_ptrfree GC_ATTR_UNUSED) {}
-# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(DARWIN)
+# ifdef CHECKSUMS
+ /* Could any valid GC heap pointer ever have been written to this page? */
+ GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h GC_ATTR_UNUSED)
+ {
+ /* FIXME - implement me. */
+ return(TRUE);
+ }
+# endif /* CHECKSUMS */
+
+#endif /* MANUAL_VDB */
+
+#ifdef MPROTECT_VDB
+ /* See DEFAULT_VDB for interface descriptions. */
+
+ /*
+ * This implementation maintains dirty bits itself by catching write
+ * faults and keeping track of them. We assume nobody else catches
+ * SIGBUS or SIGSEGV. We assume no write faults occur in system calls.
+ * This means that clients must ensure that system calls don't write
+ * to the write-protected heap. Probably the best way to do this is to
+ * ensure that system calls write at most to POINTERFREE objects in the
+ * heap, and do even that only if we are on a platform on which those
+ * are not protected. Another alternative is to wrap system calls
+ * (see example for read below), but the current implementation holds
+ * applications.
+ * We assume the page size is a multiple of HBLKSIZE.
+ * We prefer them to be the same. We avoid protecting POINTERFREE
+ * objects only if they are the same.
+ */
+# ifdef DARWIN
+ /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to
+ decrease the likelihood of some of the problems described below. */
+# include <mach/vm_map.h>
+ STATIC mach_port_t GC_task_self = 0;
+# define PROTECT(addr,len) \
+ if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
+ FALSE, VM_PROT_READ \
+ | (GC_pages_executable ? VM_PROT_EXECUTE : 0)) \
+ != KERN_SUCCESS) { \
+ ABORT("vm_protect(PROTECT) failed"); \
+ }
+# define UNPROTECT(addr,len) \
+ if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
+ FALSE, (VM_PROT_READ | VM_PROT_WRITE) \
+ | (GC_pages_executable ? VM_PROT_EXECUTE : 0)) \
+ != KERN_SUCCESS) { \
+ ABORT("vm_protect(UNPROTECT) failed"); \
+ }
+# elif !defined(USE_WINALLOC)
# include <sys/mman.h>
# include <signal.h>
# include <sys/syscall.h>
# define PROTECT(addr, len) \
- if (mprotect((caddr_t)(addr), (size_t)(len), \
- PROT_READ | OPT_PROT_EXEC) < 0) { \
- ABORT("mprotect failed"); \
- }
-# define UNPROTECT(addr, len) \
- if (mprotect((caddr_t)(addr), (size_t)(len), \
- PROT_WRITE | PROT_READ | OPT_PROT_EXEC ) < 0) { \
- ABORT("un-mprotect failed"); \
- }
-
-# else
-
-# ifdef DARWIN
- /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to
- decrease the likelihood of some of the problems described below. */
- #include <mach/vm_map.h>
- static mach_port_t GC_task_self;
- #define PROTECT(addr,len) \
- if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
- FALSE,VM_PROT_READ) != KERN_SUCCESS) { \
- ABORT("vm_portect failed"); \
+ if (mprotect((caddr_t)(addr), (size_t)(len), \
+ PROT_READ \
+ | (GC_pages_executable ? PROT_EXEC : 0)) < 0) { \
+ ABORT("mprotect failed"); \
}
- #define UNPROTECT(addr,len) \
- if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
- FALSE,VM_PROT_READ|VM_PROT_WRITE) != KERN_SUCCESS) { \
- ABORT("vm_portect failed"); \
+# define UNPROTECT(addr, len) \
+ if (mprotect((caddr_t)(addr), (size_t)(len), \
+ (PROT_READ | PROT_WRITE) \
+ | (GC_pages_executable ? PROT_EXEC : 0)) < 0) { \
+ ABORT(GC_pages_executable ? "un-mprotect executable page" \
+ " failed (probably disabled by OS)" : \
+ "un-mprotect failed"); \
}
-# else
-
+# undef IGNORE_PAGES_EXECUTABLE
+
+# else /* USE_WINALLOC */
# ifndef MSWINCE
# include <signal.h>
# endif
static DWORD protect_junk;
# define PROTECT(addr, len) \
- if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READ, \
- &protect_junk)) { \
- DWORD last_error = GetLastError(); \
- GC_printf1("Last error code: %lx\n", last_error); \
- ABORT("VirtualProtect failed"); \
- }
+ if (!VirtualProtect((addr), (len), \
+ GC_pages_executable ? PAGE_EXECUTE_READ : \
+ PAGE_READONLY, \
+ &protect_junk)) { \
+ GC_COND_LOG_PRINTF("Last error code: 0x%lx\n", \
+ (long)GetLastError()); \
+ ABORT("VirtualProtect failed"); \
+ }
# define UNPROTECT(addr, len) \
- if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READWRITE, \
- &protect_junk)) { \
- ABORT("un-VirtualProtect failed"); \
- }
-# endif /* !DARWIN */
-# endif /* MSWIN32 || MSWINCE || DARWIN */
-
-#if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS))
- typedef void (* SIG_PF)();
-#endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
-
-#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
- || defined(HURD)
-# ifdef __STDC__
- typedef void (* SIG_PF)(int);
-# else
- typedef void (* SIG_PF)();
-# endif
-#endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */
+ if (!VirtualProtect((addr), (len), \
+ GC_pages_executable ? PAGE_EXECUTE_READWRITE : \
+ PAGE_READWRITE, \
+ &protect_junk)) { \
+ ABORT("un-VirtualProtect failed"); \
+ }
+# endif /* USE_WINALLOC */
-#if defined(MSWIN32)
- typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
+# if defined(MSWIN32)
+ typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_HNDLR_PTR;
# undef SIG_DFL
-# define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)
-#endif
-#if defined(MSWINCE)
- typedef LONG (WINAPI *SIG_PF)(struct _EXCEPTION_POINTERS *);
+# define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER)((signed_word)-1)
+# elif defined(MSWINCE)
+ typedef LONG (WINAPI *SIG_HNDLR_PTR)(struct _EXCEPTION_POINTERS *);
# undef SIG_DFL
-# define SIG_DFL (SIG_PF) (-1)
-#endif
-
-#if defined(IRIX5) || defined(OSF1) || defined(HURD)
- typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
-#endif /* IRIX5 || OSF1 || HURD */
-
-#if defined(SUNOS5SIGS)
-# if defined(HPUX) || defined(FREEBSD)
-# define SIGINFO_T siginfo_t
+# define SIG_DFL (SIG_HNDLR_PTR) (-1)
+# elif defined(DARWIN)
+ typedef void (* SIG_HNDLR_PTR)();
# else
-# define SIGINFO_T struct siginfo
+ typedef void (* SIG_HNDLR_PTR)(int, siginfo_t *, void *);
+ typedef void (* PLAIN_HNDLR_PTR)(int);
# endif
-# ifdef __STDC__
- typedef void (* REAL_SIG_PF)(int, SIGINFO_T *, void *);
-# else
- typedef void (* REAL_SIG_PF)();
-# endif
-#endif /* SUNOS5SIGS */
-
-#if defined(LINUX)
-# if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
- typedef struct sigcontext s_c;
-# else /* glibc < 2.2 */
-# include <linux/version.h>
-# if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(ARM32)
- typedef struct sigcontext s_c;
-# else
- typedef struct sigcontext_struct s_c;
-# endif
-# endif /* glibc < 2.2 */
-# if defined(ALPHA) || defined(M68K)
- typedef void (* REAL_SIG_PF)(int, int, s_c *);
-# else
-# if defined(IA64) || defined(HP_PA) || defined(X86_64)
- typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *);
- /* FIXME: */
- /* According to SUSV3, the last argument should have type */
- /* void * or ucontext_t * */
-# else
- typedef void (* REAL_SIG_PF)(int, s_c);
-# endif
+
+# if defined(__GLIBC__)
+# if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
+# error glibc too old?
# endif
-# ifdef ALPHA
- /* Retrieve fault address from sigcontext structure by decoding */
- /* instruction. */
- char * get_fault_addr(s_c *sc) {
- unsigned instr;
- word faultaddr;
-
- instr = *((unsigned *)(sc->sc_pc));
- faultaddr = sc->sc_regs[(instr >> 16) & 0x1f];
- faultaddr += (word) (((int)instr << 16) >> 16);
- return (char *)faultaddr;
- }
-# endif /* !ALPHA */
-# endif /* LINUX */
+# endif
#ifndef DARWIN
-SIG_PF GC_old_bus_handler;
-SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
+ STATIC SIG_HNDLR_PTR GC_old_segv_handler = 0;
+ /* Also old MSWIN32 ACCESS_VIOLATION filter */
+# if !defined(MSWIN32) && !defined(MSWINCE)
+ STATIC SIG_HNDLR_PTR GC_old_bus_handler = 0;
+# if defined(FREEBSD) || defined(HURD) || defined(HPUX)
+ STATIC GC_bool GC_old_bus_handler_used_si = FALSE;
+# endif
+ STATIC GC_bool GC_old_segv_handler_used_si = FALSE;
+# endif /* !MSWIN32 */
#endif /* !DARWIN */
#if defined(THREADS)
-/* We need to lock around the bitmap update in the write fault handler */
-/* in order to avoid the risk of losing a bit. We do this with a */
-/* test-and-set spin lock if we know how to do that. Otherwise we */
-/* check whether we are already in the handler and use the dumb but */
-/* safe fallback algorithm of setting all bits in the word. */
-/* Contention should be very rare, so we do the minimum to handle it */
-/* correctly. */
-#ifdef GC_TEST_AND_SET_DEFINED
- static VOLATILE unsigned int fault_handler_lock = 0;
- void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
- while (GC_test_and_set(&fault_handler_lock)) {}
- /* Could also revert to set_pht_entry_from_index_safe if initial */
- /* GC_test_and_set fails. */
+/* We need to lock around the bitmap update in the write fault handler */
+/* in order to avoid the risk of losing a bit. We do this with a */
+/* test-and-set spin lock if we know how to do that. Otherwise we */
+/* check whether we are already in the handler and use the dumb but */
+/* safe fallback algorithm of setting all bits in the word. */
+/* Contention should be very rare, so we do the minimum to handle it */
+/* correctly. */
+#ifdef AO_HAVE_test_and_set_acquire
+ GC_INNER volatile AO_TS_t GC_fault_handler_lock = AO_TS_INITIALIZER;
+ static void async_set_pht_entry_from_index(volatile page_hash_table db,
+ size_t index)
+ {
+ while (AO_test_and_set_acquire(&GC_fault_handler_lock) == AO_TS_SET) {
+ /* empty */
+ }
+ /* Could also revert to set_pht_entry_from_index_safe if initial */
+ /* GC_test_and_set fails. */
set_pht_entry_from_index(db, index);
- GC_clear(&fault_handler_lock);
+ AO_CLEAR(&GC_fault_handler_lock);
}
-#else /* !GC_TEST_AND_SET_DEFINED */
- /* THIS IS INCORRECT! The dirty bit vector may be temporarily wrong, */
+#else /* !AO_HAVE_test_and_set_acquire */
+# error No test_and_set operation: Introduces a race.
+ /* THIS WOULD BE INCORRECT! */
+ /* The dirty bit vector may be temporarily wrong, */
/* just before we notice the conflict and correct it. We may end up */
- /* looking at it while it's wrong. But this requires contention */
- /* exactly when a GC is triggered, which seems far less likely to */
- /* fail than the old code, which had no reported failures. Thus we */
- /* leave it this way while we think of something better, or support */
- /* GC_test_and_set on the remaining platforms. */
- static VOLATILE word currently_updating = 0;
- void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
- unsigned int update_dummy;
- currently_updating = (word)(&update_dummy);
+ /* looking at it while it's wrong. But this requires contention */
+ /* exactly when a GC is triggered, which seems far less likely to */
+ /* fail than the old code, which had no reported failures. Thus we */
+ /* leave it this way while we think of something better, or support */
+ /* GC_test_and_set on the remaining platforms. */
+ static int * volatile currently_updating = 0;
+ static void async_set_pht_entry_from_index(volatile page_hash_table db,
+ size_t index)
+ {
+ int update_dummy;
+ currently_updating = &update_dummy;
set_pht_entry_from_index(db, index);
- /* If we get contention in the 10 or so instruction window here, */
- /* and we get stopped by a GC between the two updates, we lose! */
- if (currently_updating != (word)(&update_dummy)) {
- set_pht_entry_from_index_safe(db, index);
- /* We claim that if two threads concurrently try to update the */
- /* dirty bit vector, the first one to execute UPDATE_START */
- /* will see it changed when UPDATE_END is executed. (Note that */
- /* &update_dummy must differ in two distinct threads.) It */
- /* will then execute set_pht_entry_from_index_safe, thus */
- /* returning us to a safe state, though not soon enough. */
+ /* If we get contention in the 10 or so instruction window here, */
+ /* and we get stopped by a GC between the two updates, we lose! */
+ if (currently_updating != &update_dummy) {
+ set_pht_entry_from_index_safe(db, index);
+ /* We claim that if two threads concurrently try to update the */
+ /* dirty bit vector, the first one to execute UPDATE_START */
+ /* will see it changed when UPDATE_END is executed. (Note that */
+ /* &update_dummy must differ in two distinct threads.) It */
+ /* will then execute set_pht_entry_from_index_safe, thus */
+ /* returning us to a safe state, though not soon enough. */
}
}
-#endif /* !GC_TEST_AND_SET_DEFINED */
+#endif /* !AO_HAVE_test_and_set_acquire */
#else /* !THREADS */
# define async_set_pht_entry_from_index(db, index) \
- set_pht_entry_from_index(db, index)
+ set_pht_entry_from_index(db, index)
#endif /* !THREADS */
-/*ARGSUSED*/
-#if !defined(DARWIN)
-# if defined (SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS))
- void GC_write_fault_handler(sig, code, scp, addr)
- int sig, code;
- struct sigcontext *scp;
- char * addr;
-# ifdef SUNOS4
-# define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
-# define CODE_OK (FC_CODE(code) == FC_PROT \
- || (FC_CODE(code) == FC_OBJERR \
- && FC_ERRNO(code) == FC_PROT))
-# endif
-# ifdef FREEBSD
-# define SIG_OK (sig == SIGBUS)
-# define CODE_OK (code == BUS_PAGE_FAULT)
-# endif
-# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
+#ifdef CHECKSUMS
+ void GC_record_fault(struct hblk * h); /* from checksums.c */
+#endif
+
+#ifndef DARWIN
-# if defined(IRIX5) || defined(OSF1) || defined(HURD)
+# if !defined(MSWIN32) && !defined(MSWINCE)
# include <errno.h>
- void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
-# ifdef OSF1
+# if defined(FREEBSD) || defined(HURD) || defined(HPUX)
+# define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
+# else
# define SIG_OK (sig == SIGSEGV)
-# define CODE_OK (code == 2 /* experimentally determined */)
+ /* Catch SIGSEGV but ignore SIGBUS. */
# endif
-# ifdef IRIX5
-# define SIG_OK (sig == SIGSEGV)
-# define CODE_OK (code == EACCES)
+# if defined(FREEBSD)
+# ifndef SEGV_ACCERR
+# define SEGV_ACCERR 2
+# endif
+# define CODE_OK (si -> si_code == BUS_PAGE_FAULT \
+ || si -> si_code == SEGV_ACCERR)
+# elif defined(OSF1)
+# define CODE_OK (si -> si_code == 2 /* experimentally determined */)
+# elif defined(IRIX5)
+# define CODE_OK (si -> si_code == EACCES)
+# elif defined(HURD)
+# define CODE_OK TRUE
+# elif defined(LINUX)
+# define CODE_OK TRUE
+ /* Empirically c.trapno == 14, on IA32, but is that useful? */
+ /* Should probably consider alignment issues on other */
+ /* architectures. */
+# elif defined(HPUX)
+# define CODE_OK (si -> si_code == SEGV_ACCERR \
+ || si -> si_code == BUS_ADRERR \
+ || si -> si_code == BUS_UNKNOWN \
+ || si -> si_code == SEGV_UNKNOWN \
+ || si -> si_code == BUS_OBJERR)
+# elif defined(SUNOS5SIGS)
+# define CODE_OK (si -> si_code == SEGV_ACCERR)
# endif
-# ifdef HURD
-# define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
-# define CODE_OK TRUE
+# ifndef NO_GETCONTEXT
+# include <ucontext.h>
# endif
-# endif /* IRIX5 || OSF1 || HURD */
-
-# if defined(LINUX)
-# if defined(ALPHA) || defined(M68K)
- void GC_write_fault_handler(int sig, int code, s_c * sc)
+ STATIC void GC_write_fault_handler(int sig, siginfo_t *si, void *raw_sc)
+# else
+# define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode \
+ == STATUS_ACCESS_VIOLATION)
+# define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] \
+ == 1) /* Write fault */
+ STATIC LONG WINAPI GC_write_fault_handler(
+ struct _EXCEPTION_POINTERS *exc_info)
+# endif /* MSWIN32 || MSWINCE */
+ {
+# if !defined(MSWIN32) && !defined(MSWINCE)
+ char *addr = si -> si_addr;
# else
-# if defined(IA64) || defined(HP_PA) || defined(X86_64)
- void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp)
-# else
-# if defined(ARM32)
- void GC_write_fault_handler(int sig, int a2, int a3, int a4, s_c sc)
-# else
- void GC_write_fault_handler(int sig, s_c sc)
-# endif
-# endif
+ char * addr = (char *) (exc_info -> ExceptionRecord
+ -> ExceptionInformation[1]);
# endif
-# define SIG_OK (sig == SIGSEGV)
-# define CODE_OK TRUE
- /* Empirically c.trapno == 14, on IA32, but is that useful? */
- /* Should probably consider alignment issues on other */
- /* architectures. */
-# endif /* LINUX */
+ unsigned i;
-# if defined(SUNOS5SIGS)
-# ifdef __STDC__
- void GC_write_fault_handler(int sig, SIGINFO_T *scp, void * context)
-# else
- void GC_write_fault_handler(sig, scp, context)
- int sig;
- SIGINFO_T *scp;
- void * context;
-# endif
-# ifdef HPUX
-# define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
-# define CODE_OK (scp -> si_code == SEGV_ACCERR) \
- || (scp -> si_code == BUS_ADRERR) \
- || (scp -> si_code == BUS_UNKNOWN) \
- || (scp -> si_code == SEGV_UNKNOWN) \
- || (scp -> si_code == BUS_OBJERR)
-# else
-# ifdef FREEBSD
-# define SIG_OK (sig == SIGBUS)
-# define CODE_OK (scp -> si_code == BUS_PAGE_FAULT)
-# else
-# define SIG_OK (sig == SIGSEGV)
-# define CODE_OK (scp -> si_code == SEGV_ACCERR)
-# endif
-# endif
-# endif /* SUNOS5SIGS */
-
-# if defined(MSWIN32) || defined(MSWINCE)
- LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
-# define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
- STATUS_ACCESS_VIOLATION)
-# define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
- /* Write fault */
-# endif /* MSWIN32 || MSWINCE */
-{
- register unsigned i;
-# if defined(HURD)
- char *addr = (char *) code;
-# endif
-# ifdef IRIX5
- char * addr = (char *) (size_t) (scp -> sc_badvaddr);
-# endif
-# if defined(OSF1) && defined(ALPHA)
- char * addr = (char *) (scp -> sc_traparg_a0);
-# endif
-# ifdef SUNOS5SIGS
- char * addr = (char *) (scp -> si_addr);
-# endif
-# ifdef LINUX
-# if defined(I386)
- char * addr = (char *) (sc.cr2);
-# else
-# if defined(M68K)
- char * addr = NULL;
-
- struct sigcontext *scp = (struct sigcontext *)(sc);
-
- int format = (scp->sc_formatvec >> 12) & 0xf;
- unsigned long *framedata = (unsigned long *)(scp + 1);
- unsigned long ea;
-
- if (format == 0xa || format == 0xb) {
- /* 68020/030 */
- ea = framedata[2];
- } else if (format == 7) {
- /* 68040 */
- ea = framedata[3];
- if (framedata[1] & 0x08000000) {
- /* correct addr on misaligned access */
- ea = (ea+4095)&(~4095);
- }
- } else if (format == 4) {
- /* 68060 */
- ea = framedata[0];
- if (framedata[1] & 0x08000000) {
- /* correct addr on misaligned access */
- ea = (ea+4095)&(~4095);
- }
- }
- addr = (char *)ea;
-# else
-# ifdef ALPHA
- char * addr = get_fault_addr(sc);
-# else
-# if defined(IA64) || defined(HP_PA) || defined(X86_64)
- char * addr = si -> si_addr;
- /* I believe this is claimed to work on all platforms for */
- /* Linux 2.3.47 and later. Hopefully we don't have to */
- /* worry about earlier kernels on IA64. */
-# else
-# if defined(POWERPC)
- char * addr = (char *) (sc.regs->dar);
-# else
-# if defined(ARM32)
- char * addr = (char *)sc.fault_address;
-# else
- --> architecture not supported
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# if defined(MSWIN32) || defined(MSWINCE)
- char * addr = (char *) (exc_info -> ExceptionRecord
- -> ExceptionInformation[1]);
-# define sig SIGSEGV
-# endif
-
if (SIG_OK && CODE_OK) {
register struct hblk * h =
- (struct hblk *)((word)addr & ~(GC_page_size-1));
+ (struct hblk *)((word)addr & ~(GC_page_size-1));
GC_bool in_allocd_block;
-
-# ifdef SUNOS5SIGS
- /* Address is only within the correct physical page. */
- in_allocd_block = FALSE;
+# ifdef CHECKSUMS
+ GC_record_fault(h);
+# endif
+
+# ifdef SUNOS5SIGS
+ /* Address is only within the correct physical page. */
+ in_allocd_block = FALSE;
for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
if (HDR(h+i) != 0) {
in_allocd_block = TRUE;
+ break;
}
}
-# else
- in_allocd_block = (HDR(addr) != 0);
-# endif
+# else
+ in_allocd_block = (HDR(addr) != 0);
+# endif
if (!in_allocd_block) {
- /* FIXME - We should make sure that we invoke the */
- /* old handler with the appropriate calling */
- /* sequence, which often depends on SA_SIGINFO. */
-
- /* Heap blocks now begin and end on page boundaries */
- SIG_PF old_handler;
-
- if (sig == SIGSEGV) {
- old_handler = GC_old_segv_handler;
- } else {
- old_handler = GC_old_bus_handler;
- }
- if (old_handler == SIG_DFL) {
-# if !defined(MSWIN32) && !defined(MSWINCE)
- GC_err_printf1("Segfault at 0x%lx\n", addr);
+ /* FIXME - We should make sure that we invoke the */
+ /* old handler with the appropriate calling */
+ /* sequence, which often depends on SA_SIGINFO. */
+
+ /* Heap blocks now begin and end on page boundaries */
+ SIG_HNDLR_PTR old_handler;
+
+# if defined(MSWIN32) || defined(MSWINCE)
+ old_handler = GC_old_segv_handler;
+# else
+ GC_bool used_si;
+
+# if defined(FREEBSD) || defined(HURD) || defined(HPUX)
+ if (sig == SIGBUS) {
+ old_handler = GC_old_bus_handler;
+ used_si = GC_old_bus_handler_used_si;
+ } else
+# endif
+ /* else */ {
+ old_handler = GC_old_segv_handler;
+ used_si = GC_old_segv_handler_used_si;
+ }
+# endif
+
+ if (old_handler == (SIG_HNDLR_PTR)SIG_DFL) {
+# if !defined(MSWIN32) && !defined(MSWINCE)
+ GC_COND_LOG_PRINTF("Unexpected segfault at %p\n", addr);
ABORT("Unexpected bus error or segmentation fault");
-# else
- return(EXCEPTION_CONTINUE_SEARCH);
-# endif
+# else
+ return(EXCEPTION_CONTINUE_SEARCH);
+# endif
} else {
-# if defined (SUNOS4) \
- || (defined(FREEBSD) && !defined(SUNOS5SIGS))
- (*old_handler) (sig, code, scp, addr);
- return;
-# endif
-# if defined (SUNOS5SIGS)
- /*
- * FIXME: For FreeBSD, this code should check if the
- * old signal handler used the traditional BSD style and
- * if so call it using that style.
- */
- (*(REAL_SIG_PF)old_handler) (sig, scp, context);
- return;
-# endif
-# if defined (LINUX)
-# if defined(ALPHA) || defined(M68K)
- (*(REAL_SIG_PF)old_handler) (sig, code, sc);
-# else
-# if defined(IA64) || defined(HP_PA) || defined(X86_64)
- (*(REAL_SIG_PF)old_handler) (sig, si, scp);
-# else
- (*(REAL_SIG_PF)old_handler) (sig, sc);
-# endif
-# endif
- return;
-# endif
-# if defined (IRIX5) || defined(OSF1) || defined(HURD)
- (*(REAL_SIG_PF)old_handler) (sig, code, scp);
- return;
-# endif
-# ifdef MSWIN32
- return((*old_handler)(exc_info));
-# endif
+ /*
+ * FIXME: This code should probably check if the
+ * old signal handler used the traditional style and
+ * if so call it using that style.
+ */
+# if defined(MSWIN32) || defined(MSWINCE)
+ return((*old_handler)(exc_info));
+# else
+ if (used_si)
+ ((SIG_HNDLR_PTR)old_handler) (sig, si, raw_sc);
+ else
+ /* FIXME: should pass nonstandard args as well. */
+ ((PLAIN_HNDLR_PTR)old_handler) (sig);
+ return;
+# endif
}
}
UNPROTECT(h, GC_page_size);
- /* We need to make sure that no collection occurs between */
- /* the UNPROTECT and the setting of the dirty bit. Otherwise */
- /* a write by a third thread might go unnoticed. Reversing */
- /* the order is just as bad, since we would end up unprotecting */
- /* a page in a GC cycle during which it's not marked. */
- /* Currently we do this by disabling the thread stopping */
- /* signals while this handler is running. An alternative might */
- /* be to record the fact that we're about to unprotect, or */
- /* have just unprotected a page in the GC's thread structure, */
- /* and then to have the thread stopping code set the dirty */
- /* flag, if necessary. */
+ /* We need to make sure that no collection occurs between */
+ /* the UNPROTECT and the setting of the dirty bit. Otherwise */
+ /* a write by a third thread might go unnoticed. Reversing */
+ /* the order is just as bad, since we would end up unprotecting */
+ /* a page in a GC cycle during which it's not marked. */
+ /* Currently we do this by disabling the thread stopping */
+ /* signals while this handler is running. An alternative might */
+ /* be to record the fact that we're about to unprotect, or */
+ /* have just unprotected a page in the GC's thread structure, */
+ /* and then to have the thread stopping code set the dirty */
+ /* flag, if necessary. */
for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
- register int index = PHT_HASH(h+i);
-
+ size_t index = PHT_HASH(h+i);
+
async_set_pht_entry_from_index(GC_dirty_pages, index);
}
-# if defined(OSF1)
- /* These reset the signal handler each time by default. */
- signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
-# endif
- /* The write may not take place before dirty bits are read. */
- /* But then we'll fault again ... */
-# if defined(MSWIN32) || defined(MSWINCE)
- return(EXCEPTION_CONTINUE_EXECUTION);
-# else
- return;
-# endif
+ /* The write may not take place before dirty bits are read. */
+ /* But then we'll fault again ... */
+# if defined(MSWIN32) || defined(MSWINCE)
+ return(EXCEPTION_CONTINUE_EXECUTION);
+# else
+ return;
+# endif
}
-#if defined(MSWIN32) || defined(MSWINCE)
- return EXCEPTION_CONTINUE_SEARCH;
-#else
- GC_err_printf1("Segfault at 0x%lx\n", addr);
- ABORT("Unexpected bus error or segmentation fault");
-#endif
-}
+# if defined(MSWIN32) || defined(MSWINCE)
+ return EXCEPTION_CONTINUE_SEARCH;
+# else
+ GC_COND_LOG_PRINTF("Unexpected segfault at %p\n", addr);
+ ABORT("Unexpected bus error or segmentation fault");
+# endif
+ }
+
+# ifdef GC_WIN32_THREADS
+ GC_INNER void GC_set_write_fault_handler(void)
+ {
+ SetUnhandledExceptionFilter(GC_write_fault_handler);
+ }
+# endif
#endif /* !DARWIN */
-/*
- * We hold the allocation lock. We expect block h to be written
- * shortly. Ensure that all pages containing any part of the n hblks
- * starting at h are no longer protected. If is_ptrfree is false,
- * also ensure that they will subsequently appear to be dirty.
- */
-void GC_remove_protection(h, nblocks, is_ptrfree)
-struct hblk *h;
-word nblocks;
-GC_bool is_ptrfree;
+/* We hold the allocation lock. We expect block h to be written */
+/* shortly. Ensure that all pages containing any part of the n hblks */
+/* starting at h are no longer protected. If is_ptrfree is false, also */
+/* ensure that they will subsequently appear to be dirty. Not allowed */
+/* to call GC_printf (and the friends) here, see Win32 GC_stop_world() */
+/* for the information. */
+GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
+ GC_bool is_ptrfree)
{
struct hblk * h_trunc; /* Truncated to page boundary */
struct hblk * h_end; /* Page boundary following block end */
struct hblk * current;
- GC_bool found_clean;
-
+
+# if defined(GWW_VDB)
+ if (GC_GWW_AVAILABLE()) return;
+# endif
if (!GC_dirty_maintained) return;
h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
h_end = (struct hblk *)(((word)(h + nblocks) + GC_page_size-1)
- & ~(GC_page_size-1));
- found_clean = FALSE;
- for (current = h_trunc; current < h_end; ++current) {
- int index = PHT_HASH(current);
-
- if (!is_ptrfree || current < h || current >= h + nblocks) {
+ & ~(GC_page_size-1));
+ if (h_end == h_trunc + 1 &&
+ get_pht_entry_from_index(GC_dirty_pages, PHT_HASH(h_trunc))) {
+ /* already marked dirty, and hence unprotected. */
+ return;
+ }
+ for (current = h_trunc; (word)current < (word)h_end; ++current) {
+ size_t index = PHT_HASH(current);
+ if (!is_ptrfree || (word)current < (word)h
+ || (word)current >= (word)(h + nblocks)) {
async_set_pht_entry_from_index(GC_dirty_pages, index);
}
}
@@ -2666,210 +3275,197 @@ GC_bool is_ptrfree;
}
#if !defined(DARWIN)
-void GC_dirty_init()
-{
-# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
- defined(OSF1) || defined(HURD)
- struct sigaction act, oldact;
- /* We should probably specify SA_SIGINFO for Linux, and handle */
- /* the different architectures more uniformly. */
-# if defined(IRIX5) || defined(LINUX) && !defined(X86_64) \
- || defined(OSF1) || defined(HURD)
- act.sa_flags = SA_RESTART;
- act.sa_handler = (SIG_PF)GC_write_fault_handler;
-# else
- act.sa_flags = SA_RESTART | SA_SIGINFO;
- act.sa_sigaction = GC_write_fault_handler;
-# endif
+ GC_INNER void GC_dirty_init(void)
+ {
+# if !defined(MSWIN32) && !defined(MSWINCE)
+ struct sigaction act, oldact;
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ act.sa_sigaction = GC_write_fault_handler;
(void)sigemptyset(&act.sa_mask);
-# ifdef SIG_SUSPEND
- /* Arrange to postpone SIG_SUSPEND while we're in a write fault */
- /* handler. This effectively makes the handler atomic w.r.t. */
- /* stopping the world for GC. */
- (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
-# endif /* SIG_SUSPEND */
-# endif
-# ifdef PRINTSTATS
- GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
-# endif
+# if defined(THREADS) && !defined(GC_OPENBSD_THREADS) \
+ && !defined(GC_WIN32_THREADS) && !defined(NACL)
+ /* Arrange to postpone the signal while we are in a write fault */
+ /* handler. This effectively makes the handler atomic w.r.t. */
+ /* stopping the world for GC. */
+ (void)sigaddset(&act.sa_mask, GC_get_suspend_signal());
+# endif
+# endif /* !MSWIN32 */
+ GC_VERBOSE_LOG_PRINTF(
+ "Initializing mprotect virtual dirty bit implementation\n");
GC_dirty_maintained = TRUE;
if (GC_page_size % HBLKSIZE != 0) {
- GC_err_printf0("Page size not multiple of HBLKSIZE\n");
ABORT("Page size not multiple of HBLKSIZE");
}
-# if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS))
- GC_old_bus_handler = signal(SIGBUS, GC_write_fault_handler);
- if (GC_old_bus_handler == SIG_IGN) {
- GC_err_printf0("Previously ignored bus error!?");
- GC_old_bus_handler = SIG_DFL;
- }
- if (GC_old_bus_handler != SIG_DFL) {
-# ifdef PRINTSTATS
- GC_err_printf0("Replaced other SIGBUS handler\n");
-# endif
- }
-# endif
-# if defined(SUNOS4)
- GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
- if (GC_old_segv_handler == SIG_IGN) {
- GC_err_printf0("Previously ignored segmentation violation!?");
- GC_old_segv_handler = SIG_DFL;
- }
- if (GC_old_segv_handler != SIG_DFL) {
-# ifdef PRINTSTATS
- GC_err_printf0("Replaced other SIGSEGV handler\n");
-# endif
- }
-# endif
-# if (defined(SUNOS5SIGS) && !defined(FREEBSD)) || defined(IRIX5) \
- || defined(LINUX) || defined(OSF1) || defined(HURD)
- /* SUNOS5SIGS includes HPUX */
+# if !defined(MSWIN32) && !defined(MSWINCE)
+ /* act.sa_restorer is deprecated and should not be initialized. */
# if defined(GC_IRIX_THREADS)
- sigaction(SIGSEGV, 0, &oldact);
- sigaction(SIGSEGV, &act, 0);
-# else
- {
- int res = sigaction(SIGSEGV, &act, &oldact);
- if (res != 0) ABORT("Sigaction failed");
- }
-# endif
-# if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
- /* This is Irix 5.x, not 6.x. Irix 5.x does not have */
- /* sa_sigaction. */
- GC_old_segv_handler = oldact.sa_handler;
-# else /* Irix 6.x or SUNOS5SIGS or LINUX */
- if (oldact.sa_flags & SA_SIGINFO) {
- GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
- } else {
- GC_old_segv_handler = oldact.sa_handler;
+ sigaction(SIGSEGV, 0, &oldact);
+ sigaction(SIGSEGV, &act, 0);
+# else
+ {
+ int res = sigaction(SIGSEGV, &act, &oldact);
+ if (res != 0) ABORT("Sigaction failed");
}
# endif
- if (GC_old_segv_handler == SIG_IGN) {
- GC_err_printf0("Previously ignored segmentation violation!?");
- GC_old_segv_handler = SIG_DFL;
+ if (oldact.sa_flags & SA_SIGINFO) {
+ GC_old_segv_handler = oldact.sa_sigaction;
+ GC_old_segv_handler_used_si = TRUE;
+ } else {
+ GC_old_segv_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
+ GC_old_segv_handler_used_si = FALSE;
}
- if (GC_old_segv_handler != SIG_DFL) {
-# ifdef PRINTSTATS
- GC_err_printf0("Replaced other SIGSEGV handler\n");
-# endif
+ if (GC_old_segv_handler == (SIG_HNDLR_PTR)SIG_IGN) {
+ WARN("Previously ignored segmentation violation!?\n", 0);
+ GC_old_segv_handler = (SIG_HNDLR_PTR)SIG_DFL;
+ }
+ if (GC_old_segv_handler != (SIG_HNDLR_PTR)SIG_DFL) {
+ GC_VERBOSE_LOG_PRINTF("Replaced other SIGSEGV handler\n");
}
-# endif /* (SUNOS5SIGS && !FREEBSD) || IRIX5 || LINUX || OSF1 || HURD */
# if defined(HPUX) || defined(LINUX) || defined(HURD) \
- || (defined(FREEBSD) && defined(SUNOS5SIGS))
+ || (defined(FREEBSD) && defined(SUNOS5SIGS))
sigaction(SIGBUS, &act, &oldact);
- GC_old_bus_handler = oldact.sa_handler;
- if (GC_old_bus_handler == SIG_IGN) {
- GC_err_printf0("Previously ignored bus error!?");
- GC_old_bus_handler = SIG_DFL;
+ if ((oldact.sa_flags & SA_SIGINFO) != 0) {
+ GC_old_bus_handler = oldact.sa_sigaction;
+# if !defined(LINUX)
+ GC_old_bus_handler_used_si = TRUE;
+# endif
+ } else {
+ GC_old_bus_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
+# if !defined(LINUX)
+ GC_old_bus_handler_used_si = FALSE;
+# endif
}
- if (GC_old_bus_handler != SIG_DFL) {
-# ifdef PRINTSTATS
- GC_err_printf0("Replaced other SIGBUS handler\n");
+ if (GC_old_bus_handler == (SIG_HNDLR_PTR)SIG_IGN) {
+ WARN("Previously ignored bus error!?\n", 0);
+# if !defined(LINUX)
+ GC_old_bus_handler = (SIG_HNDLR_PTR)SIG_DFL;
+# else
+ /* GC_old_bus_handler is not used by GC_write_fault_handler. */
# endif
+ } else if (GC_old_bus_handler != (SIG_HNDLR_PTR)SIG_DFL) {
+ GC_VERBOSE_LOG_PRINTF("Replaced other SIGBUS handler\n");
}
# endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */
+# endif /* ! MS windows */
+# if defined(GWW_VDB)
+ if (GC_gww_dirty_init())
+ return;
+# endif
# if defined(MSWIN32)
GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
if (GC_old_segv_handler != NULL) {
-# ifdef PRINTSTATS
- GC_err_printf0("Replaced other UnhandledExceptionFilter\n");
-# endif
+ GC_COND_LOG_PRINTF("Replaced other UnhandledExceptionFilter\n");
} else {
GC_old_segv_handler = SIG_DFL;
}
+# elif defined(MSWINCE)
+ /* MPROTECT_VDB is unsupported for WinCE at present. */
+ /* FIXME: implement it (if possible). */
# endif
-}
+ }
#endif /* !DARWIN */
-int GC_incremental_protection_needs()
+GC_API int GC_CALL GC_incremental_protection_needs(void)
{
+ GC_ASSERT(GC_is_initialized);
+
if (GC_page_size == HBLKSIZE) {
- return GC_PROTECTS_POINTER_HEAP;
+ return GC_PROTECTS_POINTER_HEAP;
} else {
- return GC_PROTECTS_POINTER_HEAP | GC_PROTECTS_PTRFREE_HEAP;
+ return GC_PROTECTS_POINTER_HEAP | GC_PROTECTS_PTRFREE_HEAP;
}
}
-
#define HAVE_INCREMENTAL_PROTECTION_NEEDS
#define IS_PTRFREE(hhdr) ((hhdr)->hb_descr == 0)
-
#define PAGE_ALIGNED(x) !((word)(x) & (GC_page_size - 1))
-void GC_protect_heap()
+
+STATIC void GC_protect_heap(void)
{
ptr_t start;
- word len;
+ size_t len;
struct hblk * current;
struct hblk * current_start; /* Start of block to be protected. */
struct hblk * limit;
unsigned i;
- GC_bool protect_all =
- (0 != (GC_incremental_protection_needs() & GC_PROTECTS_PTRFREE_HEAP));
+ GC_bool protect_all =
+ (0 != (GC_incremental_protection_needs() & GC_PROTECTS_PTRFREE_HEAP));
for (i = 0; i < GC_n_heap_sects; i++) {
start = GC_heap_sects[i].hs_start;
len = GC_heap_sects[i].hs_bytes;
- if (protect_all) {
+ if (protect_all) {
PROTECT(start, len);
- } else {
- GC_ASSERT(PAGE_ALIGNED(len))
- GC_ASSERT(PAGE_ALIGNED(start))
- current_start = current = (struct hblk *)start;
- limit = (struct hblk *)(start + len);
- while (current < limit) {
+ } else {
+ GC_ASSERT(PAGE_ALIGNED(len));
+ GC_ASSERT(PAGE_ALIGNED(start));
+ current_start = current = (struct hblk *)start;
+ limit = (struct hblk *)(start + len);
+ while ((word)current < (word)limit) {
hdr * hhdr;
- word nhblks;
- GC_bool is_ptrfree;
-
- GC_ASSERT(PAGE_ALIGNED(current));
- GET_HDR(current, hhdr);
- if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
- /* This can happen only if we're at the beginning of a */
- /* heap segment, and a block spans heap segments. */
- /* We will handle that block as part of the preceding */
- /* segment. */
- GC_ASSERT(current_start == current);
- current_start = ++current;
- continue;
- }
- if (HBLK_IS_FREE(hhdr)) {
- GC_ASSERT(PAGE_ALIGNED(hhdr -> hb_sz));
- nhblks = divHBLKSZ(hhdr -> hb_sz);
- is_ptrfree = TRUE; /* dirty on alloc */
- } else {
- nhblks = OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
- is_ptrfree = IS_PTRFREE(hhdr);
- }
- if (is_ptrfree) {
- if (current_start < current) {
- PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
- }
- current_start = (current += nhblks);
- } else {
- current += nhblks;
- }
- }
- if (current_start < current) {
- PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
- }
- }
+ word nhblks;
+ GC_bool is_ptrfree;
+
+ GC_ASSERT(PAGE_ALIGNED(current));
+ GET_HDR(current, hhdr);
+ if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+ /* This can happen only if we're at the beginning of a */
+ /* heap segment, and a block spans heap segments. */
+ /* We will handle that block as part of the preceding */
+ /* segment. */
+ GC_ASSERT(current_start == current);
+ current_start = ++current;
+ continue;
+ }
+ if (HBLK_IS_FREE(hhdr)) {
+ GC_ASSERT(PAGE_ALIGNED(hhdr -> hb_sz));
+ nhblks = divHBLKSZ(hhdr -> hb_sz);
+ is_ptrfree = TRUE; /* dirty on alloc */
+ } else {
+ nhblks = OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
+ is_ptrfree = IS_PTRFREE(hhdr);
+ }
+ if (is_ptrfree) {
+ if ((word)current_start < (word)current) {
+ PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
+ }
+ current_start = (current += nhblks);
+ } else {
+ current += nhblks;
+ }
+ }
+ if ((word)current_start < (word)current) {
+ PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
+ }
+ }
}
}
-/* We assume that either the world is stopped or its OK to lose dirty */
-/* bits while this is happenning (as in GC_enable_incremental). */
-void GC_read_dirty()
+/* We assume that either the world is stopped or its OK to lose dirty */
+/* bits while this is happenning (as in GC_enable_incremental). */
+GC_INNER void GC_read_dirty(void)
{
+# if defined(GWW_VDB)
+ if (GC_GWW_AVAILABLE()) {
+ GC_gww_read_dirty();
+ return;
+ }
+# endif
BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
(sizeof GC_dirty_pages));
BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
GC_protect_heap();
}
-GC_bool GC_page_was_dirty(h)
-struct hblk * h;
+GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
{
- register word index = PHT_HASH(h);
-
+ register word index;
+
+# if defined(GWW_VDB)
+ if (GC_GWW_AVAILABLE())
+ return GC_gww_page_was_dirty(h);
+# endif
+
+ index = PHT_HASH(h);
return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
}
@@ -2881,33 +3477,34 @@ struct hblk * h;
* On other systems, SET_LOCK_HOLDER and friends must be suitably defined.
*/
-static GC_bool syscall_acquired_lock = FALSE; /* Protected by GC lock. */
-
-void GC_begin_syscall()
+#if 0
+static GC_bool syscall_acquired_lock = FALSE; /* Protected by GC lock. */
+
+void GC_begin_syscall(void)
{
+ /* FIXME: Resurrecting this code would require fixing the */
+ /* test, which can spuriously return TRUE. */
if (!I_HOLD_LOCK()) {
- LOCK();
- syscall_acquired_lock = TRUE;
+ LOCK();
+ syscall_acquired_lock = TRUE;
}
}
-void GC_end_syscall()
+void GC_end_syscall(void)
{
if (syscall_acquired_lock) {
- syscall_acquired_lock = FALSE;
- UNLOCK();
+ syscall_acquired_lock = FALSE;
+ UNLOCK();
}
}
-void GC_unprotect_range(addr, len)
-ptr_t addr;
-word len;
+void GC_unprotect_range(ptr_t addr, word len)
{
struct hblk * start_block;
struct hblk * end_block;
register struct hblk *h;
ptr_t obj_start;
-
+
if (!GC_dirty_maintained) return;
obj_start = GC_base(addr);
if (obj_start == 0) return;
@@ -2917,72 +3514,60 @@ word len;
start_block = (struct hblk *)((word)addr & ~(GC_page_size - 1));
end_block = (struct hblk *)((word)(addr + len - 1) & ~(GC_page_size - 1));
end_block += GC_page_size/HBLKSIZE - 1;
- for (h = start_block; h <= end_block; h++) {
+ for (h = start_block; (word)h <= (word)end_block; h++) {
register word index = PHT_HASH(h);
-
+
async_set_pht_entry_from_index(GC_dirty_pages, index);
}
UNPROTECT(start_block,
- ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
+ ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
}
-#if 0
-/* We no longer wrap read by default, since that was causing too many */
-/* problems. It is preferred that the client instead avoids writing */
-/* to the write-protected heap with a system call. */
+/* We no longer wrap read by default, since that was causing too many */
+/* problems. It is preferred that the client instead avoids writing */
+/* to the write-protected heap with a system call. */
/* This still serves as sample code if you do want to wrap system calls.*/
#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(GC_USE_LD_WRAP)
-/* Replacement for UNIX system call. */
-/* Other calls that write to the heap should be handled similarly. */
-/* Note that this doesn't work well for blocking reads: It will hold */
+/* Replacement for UNIX system call. */
+/* Other calls that write to the heap should be handled similarly. */
+/* Note that this doesn't work well for blocking reads: It will hold */
/* the allocation lock for the entire duration of the call. Multithreaded */
-/* clients should really ensure that it won't block, either by setting */
-/* the descriptor nonblocking, or by calling select or poll first, to */
-/* make sure that input is available. */
-/* Another, preferred alternative is to ensure that system calls never */
-/* write to the protected heap (see above). */
-# if defined(__STDC__) && !defined(SUNOS4)
-# include <unistd.h>
-# include <sys/uio.h>
- ssize_t read(int fd, void *buf, size_t nbyte)
-# else
-# ifndef LINT
- int read(fd, buf, nbyte)
-# else
- int GC_read(fd, buf, nbyte)
-# endif
- int fd;
- char *buf;
- int nbyte;
-# endif
+/* clients should really ensure that it won't block, either by setting */
+/* the descriptor nonblocking, or by calling select or poll first, to */
+/* make sure that input is available. */
+/* Another, preferred alternative is to ensure that system calls never */
+/* write to the protected heap (see above). */
+# include <unistd.h>
+# include <sys/uio.h>
+ssize_t read(int fd, void *buf, size_t nbyte)
{
int result;
-
+
GC_begin_syscall();
GC_unprotect_range(buf, (word)nbyte);
# if defined(IRIX5) || defined(GC_LINUX_THREADS)
- /* Indirect system call may not always be easily available. */
- /* We could call _read, but that would interfere with the */
- /* libpthread interception of read. */
- /* On Linux, we have to be careful with the linuxthreads */
- /* read interception. */
- {
- struct iovec iov;
-
- iov.iov_base = buf;
- iov.iov_len = nbyte;
- result = readv(fd, &iov, 1);
- }
+ /* Indirect system call may not always be easily available. */
+ /* We could call _read, but that would interfere with the */
+ /* libpthread interception of read. */
+ /* On Linux, we have to be careful with the linuxthreads */
+ /* read interception. */
+ {
+ struct iovec iov;
+
+ iov.iov_base = buf;
+ iov.iov_len = nbyte;
+ result = readv(fd, &iov, 1);
+ }
# else
-# if defined(HURD)
- result = __read(fd, buf, nbyte);
+# if defined(HURD)
+ result = __read(fd, buf, nbyte);
# else
- /* The two zero args at the end of this list are because one
- IA-64 syscall() implementation actually requires six args
- to be passed, even though they aren't always used. */
- result = syscall(SYS_read, fd, buf, nbyte, 0, 0);
+ /* The two zero args at the end of this list are because one
+ IA-64 syscall() implementation actually requires six args
+ to be passed, even though they aren't always used. */
+ result = syscall(SYS_read, fd, buf, nbyte, 0, 0);
# endif /* !HURD */
# endif
GC_end_syscall();
@@ -2991,376 +3576,253 @@ word len;
#endif /* !MSWIN32 && !MSWINCE && !GC_LINUX_THREADS */
#if defined(GC_USE_LD_WRAP) && !defined(THREADS)
- /* We use the GNU ld call wrapping facility. */
- /* This requires that the linker be invoked with "--wrap read". */
- /* This can be done by passing -Wl,"--wrap read" to gcc. */
- /* I'm not sure that this actually wraps whatever version of read */
- /* is called by stdio. That code also mentions __read. */
+ /* We use the GNU ld call wrapping facility. */
+ /* I'm not sure that this actually wraps whatever version of read */
+ /* is called by stdio. That code also mentions __read. */
# include <unistd.h>
ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
{
- int result;
+ int result;
- GC_begin_syscall();
- GC_unprotect_range(buf, (word)nbyte);
- result = __real_read(fd, buf, nbyte);
- GC_end_syscall();
- return(result);
+ GC_begin_syscall();
+ GC_unprotect_range(buf, (word)nbyte);
+ result = __real_read(fd, buf, nbyte);
+ GC_end_syscall();
+ return(result);
}
- /* We should probably also do this for __read, or whatever stdio */
- /* actually calls. */
+ /* We should probably also do this for __read, or whatever stdio */
+ /* actually calls. */
#endif
-
#endif /* 0 */
-/*ARGSUSED*/
-GC_bool GC_page_was_ever_dirty(h)
-struct hblk *h;
-{
- return(TRUE);
-}
-
-/* Reset the n pages starting at h to "was never dirty" status. */
-/*ARGSUSED*/
-void GC_is_fresh(h, n)
-struct hblk *h;
-word n;
-{
-}
+# ifdef CHECKSUMS
+ GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h GC_ATTR_UNUSED)
+ {
+# if defined(GWW_VDB)
+ if (GC_GWW_AVAILABLE())
+ return GC_gww_page_was_ever_dirty(h);
+# endif
+ return(TRUE);
+ }
+# endif /* CHECKSUMS */
-# endif /* MPROTECT_VDB */
+#endif /* MPROTECT_VDB */
-# ifdef PROC_VDB
+#ifdef PROC_VDB
+/* See DEFAULT_VDB for interface descriptions. */
-/*
- * See DEFAULT_VDB for interface descriptions.
- */
-
-/*
- * This implementaion assumes a Solaris 2.X like /proc pseudo-file-system
- * from which we can read page modified bits. This facility is far from
- * optimal (e.g. we would like to get the info for only some of the
- * address space), but it avoids intercepting system calls.
- */
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/signal.h>
-#include <sys/fault.h>
-#include <sys/syscall.h>
-#include <sys/procfs.h>
-#include <sys/stat.h>
-
-#define INITIAL_BUF_SZ 16384
-word GC_proc_buf_size = INITIAL_BUF_SZ;
-char *GC_proc_buf;
-
-#ifdef GC_SOLARIS_THREADS
-/* We don't have exact sp values for threads. So we count on */
-/* occasionally declaring stack pages to be fresh. Thus we */
-/* need a real implementation of GC_is_fresh. We can't clear */
-/* entries in GC_written_pages, since that would declare all */
-/* pages with the given hash address to be fresh. */
-# define MAX_FRESH_PAGES 8*1024 /* Must be power of 2 */
- struct hblk ** GC_fresh_pages; /* A direct mapped cache. */
- /* Collisions are dropped. */
-
-# define FRESH_PAGE_SLOT(h) (divHBLKSZ((word)(h)) & (MAX_FRESH_PAGES-1))
-# define ADD_FRESH_PAGE(h) \
- GC_fresh_pages[FRESH_PAGE_SLOT(h)] = (h)
-# define PAGE_IS_FRESH(h) \
- (GC_fresh_pages[FRESH_PAGE_SLOT(h)] == (h) && (h) != 0)
-#endif
+/* This implementation assumes a Solaris 2.X like /proc */
+/* pseudo-file-system from which we can read page modified bits. This */
+/* facility is far from optimal (e.g. we would like to get the info for */
+/* only some of the address space), but it avoids intercepting system */
+/* calls. */
-/* Add all pages in pht2 to pht1 */
-void GC_or_pages(pht1, pht2)
-page_hash_table pht1, pht2;
-{
- register int i;
-
- for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
-}
+# include <errno.h>
+# include <sys/types.h>
+# include <sys/signal.h>
+# include <sys/fault.h>
+# include <sys/syscall.h>
+# include <sys/procfs.h>
+# include <sys/stat.h>
-int GC_proc_fd;
+# define INITIAL_BUF_SZ 16384
+ STATIC word GC_proc_buf_size = INITIAL_BUF_SZ;
+ STATIC char *GC_proc_buf = NULL;
+ STATIC int GC_proc_fd = 0;
-void GC_dirty_init()
+GC_INNER void GC_dirty_init(void)
{
int fd;
char buf[30];
- GC_dirty_maintained = TRUE;
- if (GC_words_allocd != 0 || GC_words_allocd_before_gc != 0) {
- register int i;
-
- for (i = 0; i < PHT_SIZE; i++) GC_written_pages[i] = (word)(-1);
-# ifdef PRINTSTATS
- GC_printf1("Allocated words:%lu:all pages may have been written\n",
- (unsigned long)
- (GC_words_allocd + GC_words_allocd_before_gc));
-# endif
+ if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) {
+ memset(GC_written_pages, 0xff, sizeof(page_hash_table));
+ GC_VERBOSE_LOG_PRINTF(
+ "Allocated %lu bytes: all pages may have been written\n",
+ (unsigned long)(GC_bytes_allocd + GC_bytes_allocd_before_gc));
}
- sprintf(buf, "/proc/%d", getpid());
+
+ (void)snprintf(buf, sizeof(buf), "/proc/%ld", (long)getpid());
+ buf[sizeof(buf) - 1] = '\0';
fd = open(buf, O_RDONLY);
if (fd < 0) {
- ABORT("/proc open failed");
+ ABORT("/proc open failed");
}
GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
close(fd);
syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC);
if (GC_proc_fd < 0) {
- ABORT("/proc ioctl failed");
+ WARN("/proc ioctl(PIOCOPENPD) failed", 0);
+ return;
}
- GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
-# ifdef GC_SOLARIS_THREADS
- GC_fresh_pages = (struct hblk **)
- GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));
- if (GC_fresh_pages == 0) {
- GC_err_printf0("No space for fresh pages\n");
- EXIT();
- }
- BZERO(GC_fresh_pages, MAX_FRESH_PAGES * sizeof (struct hblk *));
-# endif
-}
-/* Ignore write hints. They don't help us here. */
-/*ARGSUSED*/
-void GC_remove_protection(h, nblocks, is_ptrfree)
-struct hblk *h;
-word nblocks;
-GC_bool is_ptrfree;
-{
+ GC_dirty_maintained = TRUE;
+ GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
+ if (GC_proc_buf == NULL)
+ ABORT("Insufficient space for /proc read");
}
-#ifdef GC_SOLARIS_THREADS
-# define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)
-#else
-# define READ(fd,buf,nbytes) read(fd, buf, nbytes)
-#endif
+# define READ read
-void GC_read_dirty()
+GC_INNER void GC_read_dirty(void)
{
- unsigned long ps, np;
int nmaps;
- ptr_t vaddr;
+ unsigned long npages;
+ unsigned pagesize;
+ ptr_t vaddr, limit;
struct prasmap * map;
char * bufp;
- ptr_t current_addr, limit;
int i;
-int dummy;
- BZERO(GC_grungy_pages, (sizeof GC_grungy_pages));
-
+ BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
bufp = GC_proc_buf;
if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
-# ifdef PRINTSTATS
- GC_printf1("/proc read failed: GC_proc_buf_size = %lu\n",
- GC_proc_buf_size);
-# endif
- {
- /* Retry with larger buffer. */
- word new_size = 2 * GC_proc_buf_size;
- char * new_buf = GC_scratch_alloc(new_size);
-
- if (new_buf != 0) {
- GC_proc_buf = bufp = new_buf;
- GC_proc_buf_size = new_size;
- }
- if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
- WARN("Insufficient space for /proc read\n", 0);
- /* Punt: */
- memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
- memset(GC_written_pages, 0xff, sizeof(page_hash_table));
-# ifdef GC_SOLARIS_THREADS
- BZERO(GC_fresh_pages,
- MAX_FRESH_PAGES * sizeof (struct hblk *));
-# endif
- return;
- }
+ /* Retry with larger buffer. */
+ word new_size = 2 * GC_proc_buf_size;
+ char *new_buf;
+
+ WARN("/proc read failed: GC_proc_buf_size = %" WARN_PRIdPTR "\n",
+ (signed_word)GC_proc_buf_size);
+ new_buf = GC_scratch_alloc(new_size);
+ if (new_buf != 0) {
+ GC_proc_buf = bufp = new_buf;
+ GC_proc_buf_size = new_size;
+ }
+ if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
+ WARN("Insufficient space for /proc read\n", 0);
+ /* Punt: */
+ memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
+ memset(GC_written_pages, 0xff, sizeof(page_hash_table));
+ return;
}
}
- /* Copy dirty bits into GC_grungy_pages */
- nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
- /* printf( "nmaps = %d, PG_REFERENCED = %d, PG_MODIFIED = %d\n",
- nmaps, PG_REFERENCED, PG_MODIFIED); */
- bufp = bufp + sizeof(struct prpageheader);
- for (i = 0; i < nmaps; i++) {
- map = (struct prasmap *)bufp;
- vaddr = (ptr_t)(map -> pr_vaddr);
- ps = map -> pr_pagesize;
- np = map -> pr_npage;
- /* printf("vaddr = 0x%X, ps = 0x%X, np = 0x%X\n", vaddr, ps, np); */
- limit = vaddr + ps * np;
- bufp += sizeof (struct prasmap);
- for (current_addr = vaddr;
- current_addr < limit; current_addr += ps){
- if ((*bufp++) & PG_MODIFIED) {
- register struct hblk * h = (struct hblk *) current_addr;
-
- while ((ptr_t)h < current_addr + ps) {
- register word index = PHT_HASH(h);
-
- set_pht_entry_from_index(GC_grungy_pages, index);
-# ifdef GC_SOLARIS_THREADS
- {
- register int slot = FRESH_PAGE_SLOT(h);
-
- if (GC_fresh_pages[slot] == h) {
- GC_fresh_pages[slot] = 0;
- }
- }
-# endif
- h++;
- }
- }
- }
- bufp += sizeof(long) - 1;
- bufp = (char *)((unsigned long)bufp & ~(sizeof(long)-1));
- }
- /* Update GC_written_pages. */
- GC_or_pages(GC_written_pages, GC_grungy_pages);
-# ifdef GC_SOLARIS_THREADS
- /* Make sure that old stacks are considered completely clean */
- /* unless written again. */
- GC_old_stacks_are_fresh();
-# endif
-}
-
-#undef READ
-
-GC_bool GC_page_was_dirty(h)
-struct hblk *h;
-{
- register word index = PHT_HASH(h);
- register GC_bool result;
-
- result = get_pht_entry_from_index(GC_grungy_pages, index);
-# ifdef GC_SOLARIS_THREADS
- if (result && PAGE_IS_FRESH(h)) result = FALSE;
- /* This happens only if page was declared fresh since */
- /* the read_dirty call, e.g. because it's in an unused */
- /* thread stack. It's OK to treat it as clean, in */
- /* that case. And it's consistent with */
- /* GC_page_was_ever_dirty. */
-# endif
- return(result);
-}
-GC_bool GC_page_was_ever_dirty(h)
-struct hblk *h;
-{
- register word index = PHT_HASH(h);
- register GC_bool result;
-
- result = get_pht_entry_from_index(GC_written_pages, index);
-# ifdef GC_SOLARIS_THREADS
- if (result && PAGE_IS_FRESH(h)) result = FALSE;
+ /* Copy dirty bits into GC_grungy_pages */
+ nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
+# ifdef DEBUG_DIRTY_BITS
+ GC_log_printf("Proc VDB read: pr_nmap= %u, pr_npage= %lu\n",
+ nmaps, ((struct prpageheader *)bufp)->pr_npage);
# endif
- return(result);
-}
-
-/* Caller holds allocation lock. */
-void GC_is_fresh(h, n)
-struct hblk *h;
-word n;
-{
+ bufp += sizeof(struct prpageheader);
+ for (i = 0; i < nmaps; i++) {
+ map = (struct prasmap *)bufp;
+ vaddr = (ptr_t)(map -> pr_vaddr);
+ npages = map -> pr_npage;
+ pagesize = map -> pr_pagesize;
+# ifdef DEBUG_DIRTY_BITS
+ GC_log_printf(
+ "pr_vaddr= %p, npage= %lu, mflags= 0x%x, pagesize= 0x%x\n",
+ vaddr, npages, map->pr_mflags, pagesize);
+# endif
- register word index;
-
-# ifdef GC_SOLARIS_THREADS
- register word i;
-
- if (GC_fresh_pages != 0) {
- for (i = 0; i < n; i++) {
- ADD_FRESH_PAGE(h + i);
+ bufp += sizeof(struct prasmap);
+ limit = vaddr + pagesize * npages;
+ for (; (word)vaddr < (word)limit; vaddr += pagesize) {
+ if ((*bufp++) & PG_MODIFIED) {
+ register struct hblk * h;
+ ptr_t next_vaddr = vaddr + pagesize;
+# ifdef DEBUG_DIRTY_BITS
+ GC_log_printf("dirty page at: %p\n", vaddr);
+# endif
+ for (h = (struct hblk *)vaddr;
+ (word)h < (word)next_vaddr; h++) {
+ register word index = PHT_HASH(h);
+ set_pht_entry_from_index(GC_grungy_pages, index);
+ }
+ }
}
- }
+ bufp = (char *)(((word)bufp + (sizeof(long)-1)) & ~(sizeof(long)-1));
+ }
+# ifdef DEBUG_DIRTY_BITS
+ GC_log_printf("Proc VDB read done.\n");
# endif
-}
-# endif /* PROC_VDB */
+ /* Update GC_written_pages. */
+ GC_or_pages(GC_written_pages, GC_grungy_pages);
+}
+# undef READ
+#endif /* PROC_VDB */
-# ifdef PCR_VDB
+#ifdef PCR_VDB
# include "vd/PCR_VD.h"
-# define NPAGES (32*1024) /* 128 MB */
+# define NPAGES (32*1024) /* 128 MB */
-PCR_VD_DB GC_grungy_bits[NPAGES];
+PCR_VD_DB GC_grungy_bits[NPAGES];
-ptr_t GC_vd_base; /* Address corresponding to GC_grungy_bits[0] */
- /* HBLKSIZE aligned. */
+STATIC ptr_t GC_vd_base = NULL;
+ /* Address corresponding to GC_grungy_bits[0] */
+ /* HBLKSIZE aligned. */
-void GC_dirty_init()
+GC_INNER void GC_dirty_init(void)
{
GC_dirty_maintained = TRUE;
/* For the time being, we assume the heap generally grows up */
GC_vd_base = GC_heap_sects[0].hs_start;
if (GC_vd_base == 0) {
- ABORT("Bad initial heap segment");
+ ABORT("Bad initial heap segment");
}
if (PCR_VD_Start(HBLKSIZE, GC_vd_base, NPAGES*HBLKSIZE)
- != PCR_ERes_okay) {
- ABORT("dirty bit initialization failed");
+ != PCR_ERes_okay) {
+ ABORT("Dirty bit initialization failed");
}
}
-void GC_read_dirty()
+GC_INNER void GC_read_dirty(void)
{
/* lazily enable dirty bits on newly added heap sects */
{
static int onhs = 0;
int nhs = GC_n_heap_sects;
- for( ; onhs < nhs; onhs++ ) {
+ for(; onhs < nhs; onhs++) {
PCR_VD_WriteProtectEnable(
GC_heap_sects[onhs].hs_start,
GC_heap_sects[onhs].hs_bytes );
}
}
-
if (PCR_VD_Clear(GC_vd_base, NPAGES*HBLKSIZE, GC_grungy_bits)
!= PCR_ERes_okay) {
- ABORT("dirty bit read failed");
+ ABORT("Dirty bit read failed");
}
}
-GC_bool GC_page_was_dirty(h)
-struct hblk *h;
+GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
{
- if((ptr_t)h < GC_vd_base || (ptr_t)h >= GC_vd_base + NPAGES*HBLKSIZE) {
- return(TRUE);
+ if ((word)h < (word)GC_vd_base
+ || (word)h >= (word)(GC_vd_base + NPAGES*HBLKSIZE)) {
+ return(TRUE);
}
return(GC_grungy_bits[h - (struct hblk *)GC_vd_base] & PCR_VD_DB_dirtyBit);
}
-/*ARGSUSED*/
-void GC_remove_protection(h, nblocks, is_ptrfree)
-struct hblk *h;
-word nblocks;
-GC_bool is_ptrfree;
+GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
+ GC_bool is_ptrfree GC_ATTR_UNUSED)
{
PCR_VD_WriteProtectDisable(h, nblocks*HBLKSIZE);
PCR_VD_WriteProtectEnable(h, nblocks*HBLKSIZE);
}
-# endif /* PCR_VDB */
+#endif /* PCR_VDB */
#if defined(MPROTECT_VDB) && defined(DARWIN)
-/* The following sources were used as a *reference* for this exception handling
- code:
+/* The following sources were used as a "reference" for this exception
+ handling code:
1. Apple's mach/xnu documentation
2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
- omnigroup's macosx-dev list.
- www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
+ omnigroup's macosx-dev list.
+ www.omnigroup.com/mailman/archive/macosx-dev/2000-June/014178.html
3. macosx-nat.c from Apple's GDB source code.
*/
-
+
/* The bug that caused all this trouble should now be fixed. This should
eventually be removed if all goes well. */
-/* define BROKEN_EXCEPTION_HANDLING */
-
+
+/* #define BROKEN_EXCEPTION_HANDLING */
+
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/thread_status.h>
@@ -3369,552 +3831,631 @@ GC_bool is_ptrfree;
#include <pthread.h>
/* These are not defined in any header, although they are documented */
-extern boolean_t exc_server(mach_msg_header_t *,mach_msg_header_t *);
-extern kern_return_t exception_raise(
- mach_port_t,mach_port_t,mach_port_t,
- exception_type_t,exception_data_t,mach_msg_type_number_t);
-extern kern_return_t exception_raise_state(
- mach_port_t,mach_port_t,mach_port_t,
- exception_type_t,exception_data_t,mach_msg_type_number_t,
- thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
- thread_state_t,mach_msg_type_number_t*);
-extern kern_return_t exception_raise_state_identity(
- mach_port_t,mach_port_t,mach_port_t,
- exception_type_t,exception_data_t,mach_msg_type_number_t,
- thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
- thread_state_t,mach_msg_type_number_t*);
+extern boolean_t
+exc_server(mach_msg_header_t *, mach_msg_header_t *);
+
+extern kern_return_t
+exception_raise(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
+ exception_data_t, mach_msg_type_number_t);
+
+extern kern_return_t
+exception_raise_state(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
+ exception_data_t, mach_msg_type_number_t,
+ thread_state_flavor_t*, thread_state_t,
+ mach_msg_type_number_t, thread_state_t,
+ mach_msg_type_number_t*);
+
+extern kern_return_t
+exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
+ exception_type_t, exception_data_t,
+ mach_msg_type_number_t, thread_state_flavor_t*,
+ thread_state_t, mach_msg_type_number_t,
+ thread_state_t, mach_msg_type_number_t*);
+
+GC_API_OSCALL kern_return_t
+catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
+ mach_port_t task, exception_type_t exception,
+ exception_data_t code, mach_msg_type_number_t code_count);
+
+/* These should never be called, but just in case... */
+GC_API_OSCALL kern_return_t
+catch_exception_raise_state(mach_port_name_t exception_port GC_ATTR_UNUSED,
+ int exception GC_ATTR_UNUSED, exception_data_t code GC_ATTR_UNUSED,
+ mach_msg_type_number_t codeCnt GC_ATTR_UNUSED, int flavor GC_ATTR_UNUSED,
+ thread_state_t old_state GC_ATTR_UNUSED, int old_stateCnt GC_ATTR_UNUSED,
+ thread_state_t new_state GC_ATTR_UNUSED, int new_stateCnt GC_ATTR_UNUSED)
+{
+ ABORT_RET("Unexpected catch_exception_raise_state invocation");
+ return(KERN_INVALID_ARGUMENT);
+}
+GC_API_OSCALL kern_return_t
+catch_exception_raise_state_identity(
+ mach_port_name_t exception_port GC_ATTR_UNUSED,
+ mach_port_t thread GC_ATTR_UNUSED, mach_port_t task GC_ATTR_UNUSED,
+ int exception GC_ATTR_UNUSED, exception_data_t code GC_ATTR_UNUSED,
+ mach_msg_type_number_t codeCnt GC_ATTR_UNUSED, int flavor GC_ATTR_UNUSED,
+ thread_state_t old_state GC_ATTR_UNUSED, int old_stateCnt GC_ATTR_UNUSED,
+ thread_state_t new_state GC_ATTR_UNUSED, int new_stateCnt GC_ATTR_UNUSED)
+{
+ ABORT_RET("Unexpected catch_exception_raise_state_identity invocation");
+ return(KERN_INVALID_ARGUMENT);
+}
#define MAX_EXCEPTION_PORTS 16
static struct {
- mach_msg_type_number_t count;
- exception_mask_t masks[MAX_EXCEPTION_PORTS];
- exception_handler_t ports[MAX_EXCEPTION_PORTS];
- exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
- thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
+ mach_msg_type_number_t count;
+ exception_mask_t masks[MAX_EXCEPTION_PORTS];
+ exception_handler_t ports[MAX_EXCEPTION_PORTS];
+ exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
+ thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
} GC_old_exc_ports;
-static struct {
- mach_port_t exception;
-#if defined(THREADS)
+STATIC struct {
+ void (*volatile os_callback[3])(void);
+ mach_port_t exception;
+# if defined(THREADS)
mach_port_t reply;
-#endif
-} GC_ports;
+# endif
+} GC_ports = {
+ {
+ /* This is to prevent stripping these routines as dead. */
+ (void (*)(void))catch_exception_raise,
+ (void (*)(void))catch_exception_raise_state,
+ (void (*)(void))catch_exception_raise_state_identity
+ },
+# ifdef THREADS
+ 0, /* for 'exception' */
+# endif
+ 0
+};
typedef struct {
mach_msg_header_t head;
} GC_msg_t;
typedef enum {
- GC_MP_NORMAL, GC_MP_DISCARDING, GC_MP_STOPPED
+ GC_MP_NORMAL,
+ GC_MP_DISCARDING,
+ GC_MP_STOPPED
} GC_mprotect_state_t;
-/* FIXME: 1 and 2 seem to be safe to use in the msgh_id field,
- but it isn't documented. Use the source and see if they
- should be ok. */
-#define ID_STOP 1
-#define ID_RESUME 2
-
-/* These values are only used on the reply port */
-#define ID_ACK 3
+#ifdef THREADS
+ /* FIXME: 1 and 2 seem to be safe to use in the msgh_id field, */
+ /* but it isn't documented. Use the source and see if they */
+ /* should be ok. */
+# define ID_STOP 1
+# define ID_RESUME 2
-#if defined(THREADS)
+ /* This value is only used on the reply port. */
+# define ID_ACK 3
-GC_mprotect_state_t GC_mprotect_state;
+ STATIC GC_mprotect_state_t GC_mprotect_state = 0;
-/* The following should ONLY be called when the world is stopped */
-static void GC_mprotect_thread_notify(mach_msg_id_t id) {
+ /* The following should ONLY be called when the world is stopped. */
+ STATIC void GC_mprotect_thread_notify(mach_msg_id_t id)
+ {
struct {
- GC_msg_t msg;
- mach_msg_trailer_t trailer;
+ GC_msg_t msg;
+ mach_msg_trailer_t trailer;
} buf;
mach_msg_return_t r;
+
/* remote, local */
- buf.msg.head.msgh_bits =
- MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+ buf.msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
buf.msg.head.msgh_size = sizeof(buf.msg);
buf.msg.head.msgh_remote_port = GC_ports.exception;
buf.msg.head.msgh_local_port = MACH_PORT_NULL;
buf.msg.head.msgh_id = id;
-
- r = mach_msg(
- &buf.msg.head,
- MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_LARGE,
- sizeof(buf.msg),
- sizeof(buf),
- GC_ports.reply,
- MACH_MSG_TIMEOUT_NONE,
- MACH_PORT_NULL);
- if(r != MACH_MSG_SUCCESS)
- ABORT("mach_msg failed in GC_mprotect_thread_notify");
- if(buf.msg.head.msgh_id != ID_ACK)
- ABORT("invalid ack in GC_mprotect_thread_notify");
-}
-/* Should only be called by the mprotect thread */
-static void GC_mprotect_thread_reply() {
+ r = mach_msg(&buf.msg.head, MACH_SEND_MSG | MACH_RCV_MSG | MACH_RCV_LARGE,
+ sizeof(buf.msg), sizeof(buf), GC_ports.reply,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (r != MACH_MSG_SUCCESS)
+ ABORT("mach_msg failed in GC_mprotect_thread_notify");
+ if (buf.msg.head.msgh_id != ID_ACK)
+ ABORT("Invalid ack in GC_mprotect_thread_notify");
+ }
+
+ /* Should only be called by the mprotect thread */
+ STATIC void GC_mprotect_thread_reply(void)
+ {
GC_msg_t msg;
mach_msg_return_t r;
/* remote, local */
- msg.head.msgh_bits =
- MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+
+ msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
msg.head.msgh_size = sizeof(msg);
msg.head.msgh_remote_port = GC_ports.reply;
msg.head.msgh_local_port = MACH_PORT_NULL;
msg.head.msgh_id = ID_ACK;
-
- r = mach_msg(
- &msg.head,
- MACH_SEND_MSG,
- sizeof(msg),
- 0,
- MACH_PORT_NULL,
- MACH_MSG_TIMEOUT_NONE,
- MACH_PORT_NULL);
- if(r != MACH_MSG_SUCCESS)
- ABORT("mach_msg failed in GC_mprotect_thread_reply");
-}
-void GC_mprotect_stop() {
+ r = mach_msg(&msg.head, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (r != MACH_MSG_SUCCESS)
+ ABORT("mach_msg failed in GC_mprotect_thread_reply");
+ }
+
+ GC_INNER void GC_mprotect_stop(void)
+ {
GC_mprotect_thread_notify(ID_STOP);
-}
-void GC_mprotect_resume() {
+ }
+
+ GC_INNER void GC_mprotect_resume(void)
+ {
GC_mprotect_thread_notify(ID_RESUME);
-}
+ }
-#else /* !THREADS */
-/* The compiler should optimize away any GC_mprotect_state computations */
-#define GC_mprotect_state GC_MP_NORMAL
-#endif
+# ifndef GC_NO_THREADS_DISCOVERY
+ GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread);
+# endif
-static void *GC_mprotect_thread(void *arg) {
- mach_msg_return_t r;
- /* These two structures contain some private kernel data. We don't need to
- access any of it so we don't bother defining a proper struct. The
- correct definitions are in the xnu source code. */
- struct {
- mach_msg_header_t head;
- char data[256];
- } reply;
- struct {
- mach_msg_header_t head;
- mach_msg_body_t msgh_body;
- char data[1024];
- } msg;
+#else
+ /* The compiler should optimize away any GC_mprotect_state computations */
+# define GC_mprotect_state GC_MP_NORMAL
+#endif /* !THREADS */
+
+STATIC void *GC_mprotect_thread(void *arg)
+{
+ mach_msg_return_t r;
+ /* These two structures contain some private kernel data. We don't */
+ /* need to access any of it so we don't bother defining a proper */
+ /* struct. The correct definitions are in the xnu source code. */
+ struct {
+ mach_msg_header_t head;
+ char data[256];
+ } reply;
+ struct {
+ mach_msg_header_t head;
+ mach_msg_body_t msgh_body;
+ char data[1024];
+ } msg;
+ mach_msg_id_t id;
- mach_msg_id_t id;
+ if ((word)arg == (word)-1) return 0; /* to make compiler happy */
+# if defined(THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
GC_darwin_register_mach_handler_thread(mach_thread_self());
-
- for(;;) {
- r = mach_msg(
- &msg.head,
- MACH_RCV_MSG|MACH_RCV_LARGE|
- (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
- 0,
- sizeof(msg),
- GC_ports.exception,
- GC_mprotect_state == GC_MP_DISCARDING ? 0 : MACH_MSG_TIMEOUT_NONE,
- MACH_PORT_NULL);
-
- id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
-
-#if defined(THREADS)
- if(GC_mprotect_state == GC_MP_DISCARDING) {
- if(r == MACH_RCV_TIMED_OUT) {
- GC_mprotect_state = GC_MP_STOPPED;
- GC_mprotect_thread_reply();
- continue;
- }
- if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
- ABORT("out of order mprotect thread request");
- }
-#endif
-
- if(r != MACH_MSG_SUCCESS) {
- GC_err_printf2("mach_msg failed with %d %s\n",
- (int)r,mach_error_string(r));
- ABORT("mach_msg failed");
+# endif
+
+ for(;;) {
+ r = mach_msg(&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE |
+ (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
+ 0, sizeof(msg), GC_ports.exception,
+ GC_mprotect_state == GC_MP_DISCARDING ? 0
+ : MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
+
+# if defined(THREADS)
+ if(GC_mprotect_state == GC_MP_DISCARDING) {
+ if(r == MACH_RCV_TIMED_OUT) {
+ GC_mprotect_state = GC_MP_STOPPED;
+ GC_mprotect_thread_reply();
+ continue;
}
-
- switch(id) {
-#if defined(THREADS)
- case ID_STOP:
- if(GC_mprotect_state != GC_MP_NORMAL)
- ABORT("Called mprotect_stop when state wasn't normal");
- GC_mprotect_state = GC_MP_DISCARDING;
- break;
- case ID_RESUME:
- if(GC_mprotect_state != GC_MP_STOPPED)
- ABORT("Called mprotect_resume when state wasn't stopped");
- GC_mprotect_state = GC_MP_NORMAL;
- GC_mprotect_thread_reply();
- break;
-#endif /* THREADS */
- default:
- /* Handle the message (calls catch_exception_raise) */
- if(!exc_server(&msg.head,&reply.head))
- ABORT("exc_server failed");
- /* Send the reply */
- r = mach_msg(
- &reply.head,
- MACH_SEND_MSG,
- reply.head.msgh_size,
- 0,
- MACH_PORT_NULL,
- MACH_MSG_TIMEOUT_NONE,
- MACH_PORT_NULL);
- if(r != MACH_MSG_SUCCESS) {
- /* This will fail if the thread dies, but the thread shouldn't
- die... */
- #ifdef BROKEN_EXCEPTION_HANDLING
- GC_err_printf2(
- "mach_msg failed with %d %s while sending exc reply\n",
- (int)r,mach_error_string(r));
- #else
- ABORT("mach_msg failed while sending exception reply");
- #endif
- }
- } /* switch */
- } /* for(;;) */
- /* NOT REACHED */
- return NULL;
+ if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
+ ABORT("Out of order mprotect thread request");
+ }
+# endif /* THREADS */
+
+ if (r != MACH_MSG_SUCCESS) {
+ GC_COND_LOG_PRINTF("mach_msg failed with code %d: %s\n", (int)r,
+ mach_error_string(r));
+ ABORT("mach_msg failed");
+ }
+
+ switch(id) {
+# if defined(THREADS)
+ case ID_STOP:
+ if(GC_mprotect_state != GC_MP_NORMAL)
+ ABORT("Called mprotect_stop when state wasn't normal");
+ GC_mprotect_state = GC_MP_DISCARDING;
+ break;
+ case ID_RESUME:
+ if(GC_mprotect_state != GC_MP_STOPPED)
+ ABORT("Called mprotect_resume when state wasn't stopped");
+ GC_mprotect_state = GC_MP_NORMAL;
+ GC_mprotect_thread_reply();
+ break;
+# endif /* THREADS */
+ default:
+ /* Handle the message (calls catch_exception_raise) */
+ if(!exc_server(&msg.head, &reply.head))
+ ABORT("exc_server failed");
+ /* Send the reply */
+ r = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0,
+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS) {
+ /* This will fail if the thread dies, but the thread */
+ /* shouldn't die... */
+# ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf("mach_msg failed with %d %s while sending "
+ "exc reply\n", (int)r, mach_error_string(r));
+# else
+ ABORT("mach_msg failed while sending exception reply");
+# endif
+ }
+ } /* switch */
+ } /* for(;;) */
}
/* All this SIGBUS code shouldn't be necessary. All protection faults should
- be going throught the mach exception handler. However, it seems a SIGBUS is
+ be going through the mach exception handler. However, it seems a SIGBUS is
occasionally sent for some unknown reason. Even more odd, it seems to be
meaningless and safe to ignore. */
#ifdef BROKEN_EXCEPTION_HANDLING
-typedef void (* SIG_PF)();
-static SIG_PF GC_old_bus_handler;
+ /* Updates to this aren't atomic, but the SIGBUS'es seem pretty rare. */
+ /* Even if this doesn't get updated property, it isn't really a problem. */
+ STATIC int GC_sigbus_count = 0;
-/* Updates to this aren't atomic, but the SIGBUSs seem pretty rare.
- Even if this doesn't get updated property, it isn't really a problem */
-static int GC_sigbus_count;
+ STATIC void GC_darwin_sigbus(int num, siginfo_t *sip, void *context)
+ {
+ if (num != SIGBUS)
+ ABORT("Got a non-sigbus signal in the sigbus handler");
-static void GC_darwin_sigbus(int num,siginfo_t *sip,void *context) {
- if(num != SIGBUS) ABORT("Got a non-sigbus signal in the sigbus handler");
-
/* Ugh... some seem safe to ignore, but too many in a row probably means
trouble. GC_sigbus_count is reset for each mach exception that is
handled */
- if(GC_sigbus_count >= 8) {
- ABORT("Got more than 8 SIGBUSs in a row!");
+ if (GC_sigbus_count >= 8) {
+ ABORT("Got more than 8 SIGBUSs in a row!");
} else {
- GC_sigbus_count++;
- GC_err_printf0("GC: WARNING: Ignoring SIGBUS.\n");
+ GC_sigbus_count++;
+ WARN("Ignoring SIGBUS.\n", 0);
}
-}
+ }
#endif /* BROKEN_EXCEPTION_HANDLING */
-void GC_dirty_init() {
- kern_return_t r;
- mach_port_t me;
- pthread_t thread;
- pthread_attr_t attr;
- exception_mask_t mask;
-
-# ifdef PRINTSTATS
- GC_printf0("Inititalizing mach/darwin mprotect virtual dirty bit "
- "implementation\n");
-# endif
-# ifdef BROKEN_EXCEPTION_HANDLING
- GC_err_printf0("GC: WARNING: Enabling workarounds for various darwin "
- "exception handling bugs.\n");
-# endif
- GC_dirty_maintained = TRUE;
- if (GC_page_size % HBLKSIZE != 0) {
- GC_err_printf0("Page size not multiple of HBLKSIZE\n");
- ABORT("Page size not multiple of HBLKSIZE");
+GC_INNER void GC_dirty_init(void)
+{
+ kern_return_t r;
+ mach_port_t me;
+ pthread_t thread;
+ pthread_attr_t attr;
+ exception_mask_t mask;
+
+# ifdef CAN_HANDLE_FORK
+ if (GC_handle_fork) {
+ /* To both support GC incremental mode and GC functions usage in */
+ /* the forked child, pthread_atfork should be used to install */
+ /* handlers that switch off GC_dirty_maintained in the child */
+ /* gracefully (unprotecting all pages and clearing */
+ /* GC_mach_handler_thread). For now, we just disable incremental */
+ /* mode if fork() handling is requested by the client. */
+ GC_COND_LOG_PRINTF("GC incremental mode disabled since fork()"
+ " handling requested\n");
+ return;
}
-
- GC_task_self = me = mach_task_self();
-
- r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.exception);
- if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (exception port)");
-
- r = mach_port_insert_right(me,GC_ports.exception,GC_ports.exception,
- MACH_MSG_TYPE_MAKE_SEND);
- if(r != KERN_SUCCESS)
- ABORT("mach_port_insert_right failed (exception port)");
-
- #if defined(THREADS)
- r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.reply);
- if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (reply port)");
- #endif
-
- /* The exceptions we want to catch */
- mask = EXC_MASK_BAD_ACCESS;
-
- r = task_get_exception_ports(
- me,
- mask,
- GC_old_exc_ports.masks,
- &GC_old_exc_ports.count,
- GC_old_exc_ports.ports,
- GC_old_exc_ports.behaviors,
- GC_old_exc_ports.flavors
- );
- if(r != KERN_SUCCESS) ABORT("task_get_exception_ports failed");
-
- r = task_set_exception_ports(
- me,
- mask,
- GC_ports.exception,
- EXCEPTION_DEFAULT,
- MACHINE_THREAD_STATE
- );
- if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed");
-
- if(pthread_attr_init(&attr) != 0) ABORT("pthread_attr_init failed");
- if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0)
- ABORT("pthread_attr_setdetachedstate failed");
-
-# undef pthread_create
- /* This will call the real pthread function, not our wrapper */
- if(pthread_create(&thread,&attr,GC_mprotect_thread,NULL) != 0)
- ABORT("pthread_create failed");
- pthread_attr_destroy(&attr);
-
- /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
- #ifdef BROKEN_EXCEPTION_HANDLING
+# endif
+
+ GC_VERBOSE_LOG_PRINTF("Initializing mach/darwin mprotect"
+ " virtual dirty bit implementation\n");
+# ifdef BROKEN_EXCEPTION_HANDLING
+ WARN("Enabling workarounds for various darwin "
+ "exception handling bugs.\n", 0);
+# endif
+ GC_dirty_maintained = TRUE;
+ if (GC_page_size % HBLKSIZE != 0) {
+ ABORT("Page size not multiple of HBLKSIZE");
+ }
+
+ GC_task_self = me = mach_task_self();
+
+ r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.exception);
+ if (r != KERN_SUCCESS)
+ ABORT("mach_port_allocate failed (exception port)");
+
+ r = mach_port_insert_right(me, GC_ports.exception, GC_ports.exception,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (r != KERN_SUCCESS)
+ ABORT("mach_port_insert_right failed (exception port)");
+
+# if defined(THREADS)
+ r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.reply);
+ if(r != KERN_SUCCESS)
+ ABORT("mach_port_allocate failed (reply port)");
+# endif
+
+ /* The exceptions we want to catch */
+ mask = EXC_MASK_BAD_ACCESS;
+
+ r = task_get_exception_ports(me, mask, GC_old_exc_ports.masks,
+ &GC_old_exc_ports.count, GC_old_exc_ports.ports,
+ GC_old_exc_ports.behaviors,
+ GC_old_exc_ports.flavors);
+ if (r != KERN_SUCCESS)
+ ABORT("task_get_exception_ports failed");
+
+ r = task_set_exception_ports(me, mask, GC_ports.exception, EXCEPTION_DEFAULT,
+ GC_MACH_THREAD_STATE);
+ if (r != KERN_SUCCESS)
+ ABORT("task_set_exception_ports failed");
+ if (pthread_attr_init(&attr) != 0)
+ ABORT("pthread_attr_init failed");
+ if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
+ ABORT("pthread_attr_setdetachedstate failed");
+
+# undef pthread_create
+ /* This will call the real pthread function, not our wrapper */
+ if (pthread_create(&thread, &attr, GC_mprotect_thread, NULL) != 0)
+ ABORT("pthread_create failed");
+ pthread_attr_destroy(&attr);
+
+ /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
+# ifdef BROKEN_EXCEPTION_HANDLING
{
- struct sigaction sa, oldsa;
- sa.sa_handler = (SIG_PF)GC_darwin_sigbus;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART|SA_SIGINFO;
- if(sigaction(SIGBUS,&sa,&oldsa) < 0) ABORT("sigaction");
- GC_old_bus_handler = (SIG_PF)oldsa.sa_handler;
- if (GC_old_bus_handler != SIG_DFL) {
-# ifdef PRINTSTATS
- GC_err_printf0("Replaced other SIGBUS handler\n");
-# endif
- }
+ struct sigaction sa, oldsa;
+ sa.sa_handler = (SIG_HNDLR_PTR)GC_darwin_sigbus;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART|SA_SIGINFO;
+ /* sa.sa_restorer is deprecated and should not be initialized. */
+ if (sigaction(SIGBUS, &sa, &oldsa) < 0)
+ ABORT("sigaction failed");
+ if ((SIG_HNDLR_PTR)oldsa.sa_handler != SIG_DFL) {
+ GC_VERBOSE_LOG_PRINTF("Replaced other SIGBUS handler\n");
+ }
}
- #endif /* BROKEN_EXCEPTION_HANDLING */
+# endif /* BROKEN_EXCEPTION_HANDLING */
}
-
-/* The source code for Apple's GDB was used as a reference for the exception
- forwarding code. This code is similar to be GDB code only because there is
- only one way to do it. */
-static kern_return_t GC_forward_exception(
- mach_port_t thread,
- mach_port_t task,
- exception_type_t exception,
- exception_data_t data,
- mach_msg_type_number_t data_count
-) {
- int i;
- kern_return_t r;
- mach_port_t port;
- exception_behavior_t behavior;
- thread_state_flavor_t flavor;
-
- thread_state_data_t thread_state;
- mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
-
- for(i=0;i<GC_old_exc_ports.count;i++)
- if(GC_old_exc_ports.masks[i] & (1 << exception))
- break;
- if(i==GC_old_exc_ports.count) ABORT("No handler for exception!");
-
- port = GC_old_exc_ports.ports[i];
- behavior = GC_old_exc_ports.behaviors[i];
- flavor = GC_old_exc_ports.flavors[i];
-
- if(behavior != EXCEPTION_DEFAULT) {
- r = thread_get_state(thread,flavor,thread_state,&thread_state_count);
- if(r != KERN_SUCCESS)
- ABORT("thread_get_state failed in forward_exception");
- }
-
- switch(behavior) {
- case EXCEPTION_DEFAULT:
- r = exception_raise(port,thread,task,exception,data,data_count);
- break;
- case EXCEPTION_STATE:
- r = exception_raise_state(port,thread,task,exception,data,
- data_count,&flavor,thread_state,thread_state_count,
- thread_state,&thread_state_count);
- break;
- case EXCEPTION_STATE_IDENTITY:
- r = exception_raise_state_identity(port,thread,task,exception,data,
- data_count,&flavor,thread_state,thread_state_count,
- thread_state,&thread_state_count);
- break;
- default:
- r = KERN_FAILURE; /* make gcc happy */
- ABORT("forward_exception: unknown behavior");
- break;
- }
-
- if(behavior != EXCEPTION_DEFAULT) {
- r = thread_set_state(thread,flavor,thread_state,thread_state_count);
- if(r != KERN_SUCCESS)
- ABORT("thread_set_state failed in forward_exception");
+
+/* The source code for Apple's GDB was used as a reference for the */
+/* exception forwarding code. This code is similar to be GDB code only */
+/* because there is only one way to do it. */
+STATIC kern_return_t GC_forward_exception(mach_port_t thread, mach_port_t task,
+ exception_type_t exception,
+ exception_data_t data,
+ mach_msg_type_number_t data_count)
+{
+ unsigned int i;
+ kern_return_t r;
+ mach_port_t port;
+ exception_behavior_t behavior;
+ thread_state_flavor_t flavor;
+
+ thread_state_data_t thread_state;
+ mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
+
+ for (i=0; i < GC_old_exc_ports.count; i++)
+ if (GC_old_exc_ports.masks[i] & (1 << exception))
+ break;
+ if (i == GC_old_exc_ports.count)
+ ABORT("No handler for exception!");
+
+ port = GC_old_exc_ports.ports[i];
+ behavior = GC_old_exc_ports.behaviors[i];
+ flavor = GC_old_exc_ports.flavors[i];
+
+ if (behavior == EXCEPTION_STATE || behavior == EXCEPTION_STATE_IDENTITY) {
+ r = thread_get_state(thread, flavor, thread_state, &thread_state_count);
+ if(r != KERN_SUCCESS)
+ ABORT("thread_get_state failed in forward_exception");
}
-
- return r;
+
+ switch(behavior) {
+ case EXCEPTION_STATE:
+ r = exception_raise_state(port, thread, task, exception, data, data_count,
+ &flavor, thread_state, thread_state_count,
+ thread_state, &thread_state_count);
+ break;
+ case EXCEPTION_STATE_IDENTITY:
+ r = exception_raise_state_identity(port, thread, task, exception, data,
+ data_count, &flavor, thread_state,
+ thread_state_count, thread_state,
+ &thread_state_count);
+ break;
+ /* case EXCEPTION_DEFAULT: */ /* default signal handlers */
+ default: /* user-supplied signal handlers */
+ r = exception_raise(port, thread, task, exception, data, data_count);
+ }
+
+ if (behavior == EXCEPTION_STATE || behavior == EXCEPTION_STATE_IDENTITY) {
+ r = thread_set_state(thread, flavor, thread_state, thread_state_count);
+ if (r != KERN_SUCCESS)
+ ABORT("thread_set_state failed in forward_exception");
+ }
+ return r;
}
-#define FWD() GC_forward_exception(thread,task,exception,code,code_count)
-
-/* This violates the namespace rules but there isn't anything that can be done
- about it. The exception handling stuff is hard coded to call this */
-kern_return_t
-catch_exception_raise(
- mach_port_t exception_port,mach_port_t thread,mach_port_t task,
- exception_type_t exception,exception_data_t code,
- mach_msg_type_number_t code_count
-) {
- kern_return_t r;
- char *addr;
- struct hblk *h;
- int i;
-#ifdef POWERPC
- thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
- mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
- ppc_exception_state_t exc_state;
+#define FWD() GC_forward_exception(thread, task, exception, code, code_count)
+
+#ifdef ARM32
+# define DARWIN_EXC_STATE ARM_EXCEPTION_STATE
+# define DARWIN_EXC_STATE_COUNT ARM_EXCEPTION_STATE_COUNT
+# define DARWIN_EXC_STATE_T arm_exception_state_t
+# define DARWIN_EXC_STATE_DAR THREAD_FLD(far)
+#elif defined(POWERPC)
+# if CPP_WORDSZ == 32
+# define DARWIN_EXC_STATE PPC_EXCEPTION_STATE
+# define DARWIN_EXC_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
+# define DARWIN_EXC_STATE_T ppc_exception_state_t
+# else
+# define DARWIN_EXC_STATE PPC_EXCEPTION_STATE64
+# define DARWIN_EXC_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT
+# define DARWIN_EXC_STATE_T ppc_exception_state64_t
+# endif
+# define DARWIN_EXC_STATE_DAR THREAD_FLD(dar)
+#elif defined(I386) || defined(X86_64)
+# if CPP_WORDSZ == 32
+# if defined(i386_EXCEPTION_STATE_COUNT) \
+ && !defined(x86_EXCEPTION_STATE32_COUNT)
+ /* Use old naming convention for 32-bit x86. */
+# define DARWIN_EXC_STATE i386_EXCEPTION_STATE
+# define DARWIN_EXC_STATE_COUNT i386_EXCEPTION_STATE_COUNT
+# define DARWIN_EXC_STATE_T i386_exception_state_t
+# else
+# define DARWIN_EXC_STATE x86_EXCEPTION_STATE32
+# define DARWIN_EXC_STATE_COUNT x86_EXCEPTION_STATE32_COUNT
+# define DARWIN_EXC_STATE_T x86_exception_state32_t
+# endif
+# else
+# define DARWIN_EXC_STATE x86_EXCEPTION_STATE64
+# define DARWIN_EXC_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
+# define DARWIN_EXC_STATE_T x86_exception_state64_t
+# endif
+# define DARWIN_EXC_STATE_DAR THREAD_FLD(faultvaddr)
#else
-# error FIXME for non-ppc darwin
+# error FIXME for non-arm/ppc/x86 darwin
#endif
-
- if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
- #ifdef DEBUG_EXCEPTION_HANDLING
- /* We aren't interested, pass it on to the old handler */
- GC_printf3("Exception: 0x%x Code: 0x%x 0x%x in catch....\n",
- exception,
- code_count > 0 ? code[0] : -1,
- code_count > 1 ? code[1] : -1);
- #endif
- return FWD();
- }
+/* This violates the namespace rules but there isn't anything that can */
+/* be done about it. The exception handling stuff is hard coded to */
+/* call this. catch_exception_raise, catch_exception_raise_state and */
+/* and catch_exception_raise_state_identity are called from OS. */
+GC_API_OSCALL kern_return_t
+catch_exception_raise(mach_port_t exception_port GC_ATTR_UNUSED,
+ mach_port_t thread, mach_port_t task GC_ATTR_UNUSED,
+ exception_type_t exception, exception_data_t code,
+ mach_msg_type_number_t code_count GC_ATTR_UNUSED)
+{
+ kern_return_t r;
+ char *addr;
+ struct hblk *h;
+ unsigned int i;
+ thread_state_flavor_t flavor = DARWIN_EXC_STATE;
+ mach_msg_type_number_t exc_state_count = DARWIN_EXC_STATE_COUNT;
+ DARWIN_EXC_STATE_T exc_state;
+
+ if (exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
+# ifdef DEBUG_EXCEPTION_HANDLING
+ /* We aren't interested, pass it on to the old handler */
+ GC_log_printf("Exception: 0x%x Code: 0x%x 0x%x in catch...\n",
+ exception, code_count > 0 ? code[0] : -1,
+ code_count > 1 ? code[1] : -1);
+# endif
+ return FWD();
+ }
- r = thread_get_state(thread,flavor,
- (natural_t*)&exc_state,&exc_state_count);
- if(r != KERN_SUCCESS) {
- /* The thread is supposed to be suspended while the exception handler
- is called. This shouldn't fail. */
- #ifdef BROKEN_EXCEPTION_HANDLING
- GC_err_printf0("thread_get_state failed in "
- "catch_exception_raise\n");
- return KERN_SUCCESS;
- #else
- ABORT("thread_get_state failed in catch_exception_raise");
- #endif
- }
-
- /* This is the address that caused the fault */
- addr = (char*) exc_state.dar;
-
- if((HDR(addr)) == 0) {
- /* Ugh... just like the SIGBUS problem above, it seems we get a bogus
- KERN_PROTECTION_FAILURE every once and a while. We wait till we get
- a bunch in a row before doing anything about it. If a "real" fault
- ever occurres it'll just keep faulting over and over and we'll hit
- the limit pretty quickly. */
- #ifdef BROKEN_EXCEPTION_HANDLING
- static char *last_fault;
- static int last_fault_count;
-
- if(addr != last_fault) {
- last_fault = addr;
- last_fault_count = 0;
- }
- if(++last_fault_count < 32) {
- if(last_fault_count == 1)
- GC_err_printf1(
- "GC: WARNING: Ignoring KERN_PROTECTION_FAILURE at %p\n",
- addr);
- return KERN_SUCCESS;
- }
-
- GC_err_printf1("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
- /* Can't pass it along to the signal handler because that is
- ignoring SIGBUS signals. We also shouldn't call ABORT here as
- signals don't always work too well from the exception handler. */
- GC_err_printf0("Aborting\n");
- exit(EXIT_FAILURE);
- #else /* BROKEN_EXCEPTION_HANDLING */
- /* Pass it along to the next exception handler
- (which should call SIGBUS/SIGSEGV) */
- return FWD();
- #endif /* !BROKEN_EXCEPTION_HANDLING */
- }
+ r = thread_get_state(thread, flavor, (natural_t*)&exc_state,
+ &exc_state_count);
+ if(r != KERN_SUCCESS) {
+ /* The thread is supposed to be suspended while the exception */
+ /* handler is called. This shouldn't fail. */
+# ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf("thread_get_state failed in catch_exception_raise\n");
+ return KERN_SUCCESS;
+# else
+ ABORT("thread_get_state failed in catch_exception_raise");
+# endif
+ }
- #ifdef BROKEN_EXCEPTION_HANDLING
- /* Reset the number of consecutive SIGBUSs */
- GC_sigbus_count = 0;
- #endif
-
- if(GC_mprotect_state == GC_MP_NORMAL) { /* common case */
- h = (struct hblk*)((word)addr & ~(GC_page_size-1));
- UNPROTECT(h, GC_page_size);
- for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
- register int index = PHT_HASH(h+i);
- async_set_pht_entry_from_index(GC_dirty_pages, index);
- }
- } else if(GC_mprotect_state == GC_MP_DISCARDING) {
- /* Lie to the thread for now. No sense UNPROTECT()ing the memory
- when we're just going to PROTECT() it again later. The thread
- will just fault again once it resumes */
- } else {
- /* Shouldn't happen, i don't think */
- GC_printf0("KERN_PROTECTION_FAILURE while world is stopped\n");
- return FWD();
+ /* This is the address that caused the fault */
+ addr = (char*) exc_state.DARWIN_EXC_STATE_DAR;
+ if (HDR(addr) == 0) {
+ /* Ugh... just like the SIGBUS problem above, it seems we get */
+ /* a bogus KERN_PROTECTION_FAILURE every once and a while. We wait */
+ /* till we get a bunch in a row before doing anything about it. */
+ /* If a "real" fault ever occurs it'll just keep faulting over and */
+ /* over and we'll hit the limit pretty quickly. */
+# ifdef BROKEN_EXCEPTION_HANDLING
+ static char *last_fault;
+ static int last_fault_count;
+
+ if(addr != last_fault) {
+ last_fault = addr;
+ last_fault_count = 0;
+ }
+ if(++last_fault_count < 32) {
+ if(last_fault_count == 1)
+ WARN("Ignoring KERN_PROTECTION_FAILURE at %p\n", addr);
+ return KERN_SUCCESS;
+ }
+
+ GC_err_printf(
+ "Unexpected KERN_PROTECTION_FAILURE at %p; aborting...\n", addr);
+ /* Can't pass it along to the signal handler because that is */
+ /* ignoring SIGBUS signals. We also shouldn't call ABORT here as */
+ /* signals don't always work too well from the exception handler. */
+ EXIT();
+# else /* BROKEN_EXCEPTION_HANDLING */
+ /* Pass it along to the next exception handler
+ (which should call SIGBUS/SIGSEGV) */
+ return FWD();
+# endif /* !BROKEN_EXCEPTION_HANDLING */
+ }
+
+# ifdef BROKEN_EXCEPTION_HANDLING
+ /* Reset the number of consecutive SIGBUSs */
+ GC_sigbus_count = 0;
+# endif
+
+ if (GC_mprotect_state == GC_MP_NORMAL) { /* common case */
+ h = (struct hblk*)((word)addr & ~(GC_page_size-1));
+ UNPROTECT(h, GC_page_size);
+ for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
+ register int index = PHT_HASH(h+i);
+ async_set_pht_entry_from_index(GC_dirty_pages, index);
}
- return KERN_SUCCESS;
+ } else if (GC_mprotect_state == GC_MP_DISCARDING) {
+ /* Lie to the thread for now. No sense UNPROTECT()ing the memory
+ when we're just going to PROTECT() it again later. The thread
+ will just fault again once it resumes */
+ } else {
+ /* Shouldn't happen, i don't think */
+ GC_err_printf("KERN_PROTECTION_FAILURE while world is stopped\n");
+ return FWD();
+ }
+ return KERN_SUCCESS;
}
#undef FWD
-/* These should never be called, but just in case... */
-kern_return_t catch_exception_raise_state(mach_port_name_t exception_port,
- int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
- int flavor, thread_state_t old_state, int old_stateCnt,
- thread_state_t new_state, int new_stateCnt)
-{
- ABORT("catch_exception_raise_state");
- return(KERN_INVALID_ARGUMENT);
-}
-kern_return_t catch_exception_raise_state_identity(
- mach_port_name_t exception_port, mach_port_t thread, mach_port_t task,
- int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
- int flavor, thread_state_t old_state, int old_stateCnt,
- thread_state_t new_state, int new_stateCnt)
-{
- ABORT("catch_exception_raise_state_identity");
- return(KERN_INVALID_ARGUMENT);
-}
-
+#ifndef NO_DESC_CATCH_EXCEPTION_RAISE
+ /* These symbols should have REFERENCED_DYNAMICALLY (0x10) bit set to */
+ /* let strip know they are not to be stripped. */
+ __asm__(".desc _catch_exception_raise, 0x10");
+ __asm__(".desc _catch_exception_raise_state, 0x10");
+ __asm__(".desc _catch_exception_raise_state_identity, 0x10");
+#endif
#endif /* DARWIN && MPROTECT_VDB */
-# ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
- int GC_incremental_protection_needs()
+#ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
+ GC_API int GC_CALL GC_incremental_protection_needs(void)
{
return GC_PROTECTS_NONE;
}
-# endif /* !HAVE_INCREMENTAL_PROTECTION_NEEDS */
+#endif /* !HAVE_INCREMENTAL_PROTECTION_NEEDS */
-/*
- * Call stack save code for debugging.
- * Should probably be in mach_dep.c, but that requires reorganization.
- */
+#ifdef ECOS
+ /* Undo sbrk() redirection. */
+# undef sbrk
+#endif
+
+/* If value is non-zero then allocate executable memory. */
+GC_API void GC_CALL GC_set_pages_executable(int value)
+{
+ GC_ASSERT(!GC_is_initialized);
+ /* Even if IGNORE_PAGES_EXECUTABLE is defined, GC_pages_executable is */
+ /* touched here to prevent a compiler warning. */
+ GC_pages_executable = (GC_bool)(value != 0);
+}
+
+/* Returns non-zero if the GC-allocated memory is executable. */
+/* GC_get_pages_executable is defined after all the places */
+/* where GC_get_pages_executable is undefined. */
+GC_API int GC_CALL GC_get_pages_executable(void)
+{
+# ifdef IGNORE_PAGES_EXECUTABLE
+ return 1; /* Always allocate executable memory. */
+# else
+ return (int)GC_pages_executable;
+# endif
+}
+
+/* Call stack save code for debugging. Should probably be in */
+/* mach_dep.c, but that requires reorganization. */
-/* I suspect the following works for most X86 *nix variants, so */
-/* long as the frame pointer is explicitly stored. In the case of gcc, */
-/* compiler flags (e.g. -fomit-frame-pointer) determine whether it is. */
+/* I suspect the following works for most X86 *nix variants, so */
+/* long as the frame pointer is explicitly stored. In the case of gcc, */
+/* compiler flags (e.g. -fomit-frame-pointer) determine whether it is. */
#if defined(I386) && defined(LINUX) && defined(SAVE_CALL_CHAIN)
# include <features.h>
struct frame {
- struct frame *fr_savfp;
- long fr_savpc;
- long fr_arg[NARGS]; /* All the arguments go here. */
+ struct frame *fr_savfp;
+ long fr_savpc;
+ long fr_arg[NARGS]; /* All the arguments go here. */
};
#endif
@@ -3923,39 +4464,33 @@ kern_return_t catch_exception_raise_state_identity(
# include <features.h>
struct frame {
- long fr_local[8];
- long fr_arg[6];
- struct frame *fr_savfp;
- long fr_savpc;
+ long fr_local[8];
+ long fr_arg[6];
+ struct frame *fr_savfp;
+ long fr_savpc;
# ifndef __arch64__
- char *fr_stret;
+ char *fr_stret;
# endif
- long fr_argd[6];
- long fr_argx[0];
+ long fr_argd[6];
+ long fr_argx[0];
};
+# elif defined (DRSNX)
+# include <sys/sparc/frame.h>
+# elif defined(OPENBSD)
+# include <frame.h>
+# elif defined(FREEBSD) || defined(NETBSD)
+# include <machine/frame.h>
# else
-# if defined(SUNOS4)
-# include <machine/frame.h>
-# else
-# if defined (DRSNX)
-# include <sys/sparc/frame.h>
-# else
-# if defined(OPENBSD) || defined(NETBSD)
-# include <frame.h>
-# else
-# include <sys/frame.h>
-# endif
-# endif
-# endif
+# include <sys/frame.h>
# endif
# if NARGS > 6
- --> We only know how to to get the first 6 arguments
+# error We only know how to get the first 6 arguments
# endif
#endif /* SPARC */
-#ifdef NEED_CALLINFO
-/* Fill in the pc and argument information for up to NFRAMES of my */
-/* callers. Ignore my frame and my callers frame. */
+#ifdef NEED_CALLINFO
+/* Fill in the pc and argument information for up to NFRAMES of my */
+/* callers. Ignore my frame and my callers frame. */
#ifdef LINUX
# include <unistd.h>
@@ -3964,7 +4499,11 @@ kern_return_t catch_exception_raise_state_identity(
#endif /* NEED_CALLINFO */
#if defined(GC_HAVE_BUILTIN_BACKTRACE)
-# include <execinfo.h>
+# ifdef _MSC_VER
+# include "private/msvc_dbg.h"
+# else
+# include <execinfo.h>
+# endif
#endif
#ifdef SAVE_CALL_CHAIN
@@ -3972,24 +4511,44 @@ kern_return_t catch_exception_raise_state_identity(
#if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
&& defined(GC_HAVE_BUILTIN_BACKTRACE)
-void GC_save_callers (info)
-struct callinfo info[NFRAMES];
+#ifdef REDIRECT_MALLOC
+ /* Deal with possible malloc calls in backtrace by omitting */
+ /* the infinitely recursing backtrace. */
+# ifdef THREADS
+ __thread /* If your compiler doesn't understand this */
+ /* you could use something like pthread_getspecific. */
+# endif
+ GC_in_save_callers = FALSE;
+#endif
+
+GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
{
void * tmp_info[NFRAMES + 1];
int npcs, i;
# define IGNORE_FRAMES 1
-
- /* We retrieve NFRAMES+1 pc values, but discard the first, since it */
- /* points to our own frame. */
- GC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
+
+ /* We retrieve NFRAMES+1 pc values, but discard the first, since it */
+ /* points to our own frame. */
+# ifdef REDIRECT_MALLOC
+ if (GC_in_save_callers) {
+ info[0].ci_pc = (word)(&GC_save_callers);
+ for (i = 1; i < NFRAMES; ++i) info[i].ci_pc = 0;
+ return;
+ }
+ GC_in_save_callers = TRUE;
+# endif
+ GC_STATIC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *));
for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0;
+# ifdef REDIRECT_MALLOC
+ GC_in_save_callers = FALSE;
+# endif
}
#else /* No builtin backtrace; do it ourselves */
-#if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC)
+#if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC)
# define FR_SAVFP fr_fp
# define FR_SAVPC fr_pc
#else
@@ -4003,8 +4562,7 @@ struct callinfo info[NFRAMES];
# define BIAS 0
#endif
-void GC_save_callers (info)
-struct callinfo info[NFRAMES];
+GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
{
struct frame *frame;
struct frame *fp;
@@ -4014,19 +4572,20 @@ struct callinfo info[NFRAMES];
asm("movl %%ebp,%0" : "=r"(frame));
fp = frame;
# else
- frame = (struct frame *) GC_save_regs_in_stack ();
+ frame = (struct frame *)GC_save_regs_in_stack();
fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
#endif
-
- for (; (!(fp HOTTER_THAN frame) && !(GC_stackbottom HOTTER_THAN (ptr_t)fp)
- && (nframes < NFRAMES));
+
+ for (; !((word)fp HOTTER_THAN (word)frame)
+ && !((word)GC_stackbottom HOTTER_THAN (word)fp)
+ && nframes < NFRAMES;
fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) {
register int i;
-
+
info[nframes].ci_pc = fp->FR_SAVPC;
# if NARGS > 0
for (i = 0; i < NARGS; i++) {
- info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
+ info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
}
# endif /* NARGS > 0 */
}
@@ -4040,148 +4599,153 @@ struct callinfo info[NFRAMES];
#ifdef NEED_CALLINFO
/* Print info to stderr. We do NOT hold the allocation lock */
-void GC_print_callers (info)
-struct callinfo info[NFRAMES];
+GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
{
- register int i;
+ int i;
static int reentry_count = 0;
GC_bool stop = FALSE;
+ DCL_LOCK_STATE;
- /* FIXME: This should probably use a different lock, so that we */
- /* become callable with or without the allocation lock. */
+ /* FIXME: This should probably use a different lock, so that we */
+ /* become callable with or without the allocation lock. */
LOCK();
++reentry_count;
UNLOCK();
-
+
# if NFRAMES == 1
- GC_err_printf0("\tCaller at allocation:\n");
+ GC_err_printf("\tCaller at allocation:\n");
# else
- GC_err_printf0("\tCall chain at allocation:\n");
+ GC_err_printf("\tCall chain at allocation:\n");
# endif
- for (i = 0; i < NFRAMES && !stop ; i++) {
- if (info[i].ci_pc == 0) break;
-# if NARGS > 0
- {
- int j;
-
- GC_err_printf0("\t\targs: ");
- for (j = 0; j < NARGS; j++) {
- if (j != 0) GC_err_printf0(", ");
- GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
- ~(info[i].ci_arg[j]));
- }
- GC_err_printf0("\n");
- }
-# endif
+ for (i = 0; i < NFRAMES && !stop; i++) {
+ if (info[i].ci_pc == 0) break;
+# if NARGS > 0
+ {
+ int j;
+
+ GC_err_printf("\t\targs: ");
+ for (j = 0; j < NARGS; j++) {
+ if (j != 0) GC_err_printf(", ");
+ GC_err_printf("%d (0x%X)", ~(info[i].ci_arg[j]),
+ ~(info[i].ci_arg[j]));
+ }
+ GC_err_printf("\n");
+ }
+# endif
if (reentry_count > 1) {
- /* We were called during an allocation during */
- /* a previous GC_print_callers call; punt. */
- GC_err_printf1("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
- continue;
- }
- {
-# ifdef LINUX
- FILE *pipe;
-# endif
-# if defined(GC_HAVE_BUILTIN_BACKTRACE) \
- && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
- char **sym_name =
- backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
- char *name = sym_name[0];
-# else
- char buf[40];
- char *name = buf;
- sprintf(buf, "##PC##= 0x%lx", info[i].ci_pc);
-# endif
-# if defined(LINUX) && !defined(SMALL_CONFIG)
- /* Try for a line number. */
- {
-# define EXE_SZ 100
- static char exe_name[EXE_SZ];
-# define CMD_SZ 200
- char cmd_buf[CMD_SZ];
-# define RESULT_SZ 200
- static char result_buf[RESULT_SZ];
- size_t result_len;
- char *old_preload;
-# define PRELOAD_SZ 200
- char preload_buf[PRELOAD_SZ];
- static GC_bool found_exe_name = FALSE;
- static GC_bool will_fail = FALSE;
- int ret_code;
- /* Try to get it via a hairy and expensive scheme. */
- /* First we get the name of the executable: */
- if (will_fail) goto out;
- if (!found_exe_name) {
- ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
- if (ret_code < 0 || ret_code >= EXE_SZ
- || exe_name[0] != '/') {
- will_fail = TRUE; /* Dont try again. */
- goto out;
- }
- exe_name[ret_code] = '\0';
- found_exe_name = TRUE;
- }
- /* Then we use popen to start addr2line -e <exe> <addr> */
- /* There are faster ways to do this, but hopefully this */
- /* isn't time critical. */
- sprintf(cmd_buf, "/usr/bin/addr2line -f -e %s 0x%lx", exe_name,
- (unsigned long)info[i].ci_pc);
- old_preload = getenv ("LD_PRELOAD");
- if (0 != old_preload) {
- if (strlen (old_preload) >= PRELOAD_SZ) {
- will_fail = TRUE;
- goto out;
- }
- strcpy (preload_buf, old_preload);
- unsetenv ("LD_PRELOAD");
- }
- pipe = popen(cmd_buf, "r");
- if (0 != old_preload
- && 0 != setenv ("LD_PRELOAD", preload_buf, 0)) {
- WARN("Failed to reset LD_PRELOAD\n", 0);
- }
- if (pipe == NULL
- || (result_len = fread(result_buf, 1, RESULT_SZ - 1, pipe))
- == 0) {
- if (pipe != NULL) pclose(pipe);
- will_fail = TRUE;
- goto out;
- }
- if (result_buf[result_len - 1] == '\n') --result_len;
- result_buf[result_len] = 0;
- if (result_buf[0] == '?'
- || result_buf[result_len-2] == ':'
- && result_buf[result_len-1] == '0') {
- pclose(pipe);
- goto out;
- }
- /* Get rid of embedded newline, if any. Test for "main" */
- {
- char * nl = strchr(result_buf, '\n');
- if (nl != NULL && nl < result_buf + result_len) {
- *nl = ':';
- }
- if (strncmp(result_buf, "main", nl - result_buf) == 0) {
- stop = TRUE;
- }
- }
- if (result_len < RESULT_SZ - 25) {
- /* Add in hex address */
- sprintf(result_buf + result_len, " [0x%lx]",
- (unsigned long)info[i].ci_pc);
- }
- name = result_buf;
- pclose(pipe);
- out:;
- }
-# endif /* LINUX */
- GC_err_printf1("\t\t%s\n", name);
-# if defined(GC_HAVE_BUILTIN_BACKTRACE) \
- && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
- free(sym_name); /* May call GC_free; that's OK */
+ /* We were called during an allocation during */
+ /* a previous GC_print_callers call; punt. */
+ GC_err_printf("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
+ continue;
+ }
+ {
+# if defined(GC_HAVE_BUILTIN_BACKTRACE) \
+ && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
+ char **sym_name =
+ backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
+ char *name = sym_name[0];
+# else
+ char buf[40];
+ char *name = buf;
+ (void)snprintf(buf, sizeof(buf), "##PC##= 0x%lx", info[i].ci_pc);
+ buf[sizeof(buf) - 1] = '\0';
# endif
- }
+# if defined(LINUX) && !defined(SMALL_CONFIG)
+ /* Try for a line number. */
+ {
+ FILE *pipe;
+# define EXE_SZ 100
+ static char exe_name[EXE_SZ];
+# define CMD_SZ 200
+ char cmd_buf[CMD_SZ];
+# define RESULT_SZ 200
+ static char result_buf[RESULT_SZ];
+ size_t result_len;
+ char *old_preload;
+# define PRELOAD_SZ 200
+ char preload_buf[PRELOAD_SZ];
+ static GC_bool found_exe_name = FALSE;
+ static GC_bool will_fail = FALSE;
+ int ret_code;
+ /* Try to get it via a hairy and expensive scheme. */
+ /* First we get the name of the executable: */
+ if (will_fail) goto out;
+ if (!found_exe_name) {
+ ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
+ if (ret_code < 0 || ret_code >= EXE_SZ
+ || exe_name[0] != '/') {
+ will_fail = TRUE; /* Don't try again. */
+ goto out;
+ }
+ exe_name[ret_code] = '\0';
+ found_exe_name = TRUE;
+ }
+ /* Then we use popen to start addr2line -e <exe> <addr> */
+ /* There are faster ways to do this, but hopefully this */
+ /* isn't time critical. */
+ (void)snprintf(cmd_buf, sizeof(cmd_buf),
+ "/usr/bin/addr2line -f -e %s 0x%lx",
+ exe_name, (unsigned long)info[i].ci_pc);
+ cmd_buf[sizeof(cmd_buf) - 1] = '\0';
+ old_preload = GETENV("LD_PRELOAD");
+ if (0 != old_preload) {
+ size_t old_len = strlen(old_preload);
+ if (old_len >= PRELOAD_SZ) {
+ will_fail = TRUE;
+ goto out;
+ }
+ BCOPY(old_preload, preload_buf, old_len + 1);
+ unsetenv ("LD_PRELOAD");
+ }
+ pipe = popen(cmd_buf, "r");
+ if (0 != old_preload
+ && 0 != setenv ("LD_PRELOAD", preload_buf, 0)) {
+ WARN("Failed to reset LD_PRELOAD\n", 0);
+ }
+ if (pipe == NULL
+ || (result_len = fread(result_buf, 1,
+ RESULT_SZ - 1, pipe)) == 0) {
+ if (pipe != NULL) pclose(pipe);
+ will_fail = TRUE;
+ goto out;
+ }
+ if (result_buf[result_len - 1] == '\n') --result_len;
+ result_buf[result_len] = 0;
+ if (result_buf[0] == '?'
+ || (result_buf[result_len-2] == ':'
+ && result_buf[result_len-1] == '0')) {
+ pclose(pipe);
+ goto out;
+ }
+ /* Get rid of embedded newline, if any. Test for "main" */
+ {
+ char * nl = strchr(result_buf, '\n');
+ if (nl != NULL
+ && (word)nl < (word)(result_buf + result_len)) {
+ *nl = ':';
+ }
+ if (strncmp(result_buf, "main", nl - result_buf) == 0) {
+ stop = TRUE;
+ }
+ }
+ if (result_len < RESULT_SZ - 25) {
+ /* Add in hex address */
+ (void)snprintf(&result_buf[result_len],
+ sizeof(result_buf) - result_len,
+ " [0x%lx]", (unsigned long)info[i].ci_pc);
+ result_buf[sizeof(result_buf) - 1] = '\0';
+ }
+ name = result_buf;
+ pclose(pipe);
+ out:;
+ }
+# endif /* LINUX */
+ GC_err_printf("\t\t%s\n", name);
+# if defined(GC_HAVE_BUILTIN_BACKTRACE) \
+ && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
+ free(sym_name); /* May call GC_free; that's OK */
+# endif
+ }
}
LOCK();
--reentry_count;
@@ -4190,26 +4754,16 @@ struct callinfo info[NFRAMES];
#endif /* NEED_CALLINFO */
-
-
#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
+ /* Dump /proc/self/maps to GC_stderr, to enable looking up names for */
+ /* addresses in FIND_LEAK output. */
+ void GC_print_address_map(void)
+ {
+ char *maps;
-/* Dump /proc/self/maps to GC_stderr, to enable looking up names for
- addresses in FIND_LEAK output. */
-
-static word dump_maps(char *maps)
-{
- GC_err_write(maps, strlen(maps));
- return 1;
-}
-
-void GC_print_address_map()
-{
- GC_err_printf0("---------- Begin address map ----------\n");
- GC_apply_to_maps(dump_maps);
- GC_err_printf0("---------- End address map ----------\n");
-}
-
-#endif
-
-
+ GC_err_printf("---------- Begin address map ----------\n");
+ maps = GC_get_maps();
+ GC_err_puts(maps != NULL ? maps : "Failed to get map!\n");
+ GC_err_printf("---------- End address map ----------\n");
+ }
+#endif /* LINUX && ELF */
diff --git a/boehm-gc/pc_excludes b/boehm-gc/pc_excludes
deleted file mode 100644
index 15c904551be..00000000000
--- a/boehm-gc/pc_excludes
+++ /dev/null
@@ -1,21 +0,0 @@
-solaris_threads.c
-solaris_pthreads.c
-irix_threads.c
-pcr_interface.c
-real_malloc.c
-mips_mach_dep.s
-rs6000_mach_dep.s
-alpha_mach_dep.s
-sparc_mach_dep.s
-PCR-Makefile
-setjmp_t.c
-callprocs
-doc/gc.man
-pc_excludes
-barrett_diagram
-include/gc_c++.h
-include/gc_inline.h
-doc/README.hp
-doc/README.rs6000
-doc/README.sgi
-
diff --git a/boehm-gc/pcr_interface.c b/boehm-gc/pcr_interface.c
index 7bf02a45c69..c6c868c3b94 100644
--- a/boehm-gc/pcr_interface.c
+++ b/boehm-gc/pcr_interface.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -41,7 +41,7 @@ void * GC_DebugAllocProc(size_t size, PCR_Bool ptrFree, PCR_Bool clear )
{
if (ptrFree) {
void * result = (void *)GC_debug_malloc_atomic(size, __FILE__,
- __LINE__);
+ __LINE__);
if (clear && result != 0) BZERO(result, size);
return(result);
} else {
@@ -65,28 +65,29 @@ typedef struct {
PCR_Any ed_client_data;
} enumerate_data;
-void GC_enumerate_block(h, ed)
-register struct hblk *h;
-enumerate_data * ed;
+void GC_enumerate_block(struct hblk *h; enumerate_data * ed)
{
register hdr * hhdr;
register int sz;
- word *p;
- word * lim;
-
+ ptr_t p;
+ ptr_t lim;
+ word descr;
+# error This code was updated without testing.
+# error and its precursor was clearly broken.
+
hhdr = HDR(h);
+ descr = hhdr -> hb_descr;
sz = hhdr -> hb_sz;
- if (sz >= 0 && ed -> ed_pointerfree
- || sz <= 0 && !(ed -> ed_pointerfree)) return;
- if (sz < 0) sz = -sz;
- lim = (word *)(h+1) - sz;
- p = (word *)h;
+ if (descr != 0 && ed -> ed_pointerfree
+ || descr == 0 && !(ed -> ed_pointerfree)) return;
+ lim = (ptr_t)(h+1) - sz;
+ p = (ptr_t)h;
do {
if (PCR_ERes_IsErr(ed -> ed_fail_code)) return;
ed -> ed_fail_code =
- (*(ed -> ed_proc))(p, WORDS_TO_BYTES(sz), ed -> ed_client_data);
+ (*(ed -> ed_proc))(p, sz, ed -> ed_client_data);
p+= sz;
- } while (p <= lim);
+ } while ((word)p <= (word)lim);
}
struct PCR_MM_ProcsRep * GC_old_allocator = 0;
@@ -98,7 +99,7 @@ PCR_ERes GC_EnumerateProc(
)
{
enumerate_data ed;
-
+
ed.ed_proc = proc;
ed.ed_pointerfree = ptrFree;
ed.ed_fail_code = PCR_ERes_okay;
@@ -107,8 +108,8 @@ PCR_ERes GC_EnumerateProc(
if (ed.ed_fail_code != PCR_ERes_okay) {
return(ed.ed_fail_code);
} else {
- /* Also enumerate objects allocated by my predecessors */
- return((*(GC_old_allocator->mmp_enumerate))(ptrFree, proc, data));
+ /* Also enumerate objects allocated by my predecessors */
+ return((*(GC_old_allocator->mmp_enumerate))(ptrFree, proc, data));
}
}
@@ -117,23 +118,23 @@ void GC_DummyFreeProc(void *p) {}
void GC_DummyShutdownProc(void) {}
struct PCR_MM_ProcsRep GC_Rep = {
- MY_MAGIC,
- GC_AllocProc,
- GC_ReallocProc,
- GC_DummyFreeProc, /* mmp_free */
- GC_FreeProc, /* mmp_unsafeFree */
- GC_EnumerateProc,
- GC_DummyShutdownProc /* mmp_shutdown */
+ MY_MAGIC,
+ GC_AllocProc,
+ GC_ReallocProc,
+ GC_DummyFreeProc, /* mmp_free */
+ GC_FreeProc, /* mmp_unsafeFree */
+ GC_EnumerateProc,
+ GC_DummyShutdownProc /* mmp_shutdown */
};
struct PCR_MM_ProcsRep GC_DebugRep = {
- MY_DEBUGMAGIC,
- GC_DebugAllocProc,
- GC_DebugReallocProc,
- GC_DummyFreeProc, /* mmp_free */
- GC_DebugFreeProc, /* mmp_unsafeFree */
- GC_EnumerateProc,
- GC_DummyShutdownProc /* mmp_shutdown */
+ MY_DEBUGMAGIC,
+ GC_DebugAllocProc,
+ GC_DebugReallocProc,
+ GC_DummyFreeProc, /* mmp_free */
+ GC_DebugFreeProc, /* mmp_unsafeFree */
+ GC_EnumerateProc,
+ GC_DummyShutdownProc /* mmp_shutdown */
};
GC_bool GC_use_debug = 0;
@@ -162,9 +163,9 @@ PCR_GC_Run(void)
* awful hack to test whether VD is implemented ...
*/
if( PCR_VD_Start( 0, NIL, 0) != PCR_ERes_FromErr(ENOSYS) ) {
- GC_enable_incremental();
- }
- }
+ GC_enable_incremental();
+ }
+ }
}
return PCR_ERes_okay;
}
diff --git a/boehm-gc/powerpc_macosx_mach_dep.s b/boehm-gc/powerpc_macosx_mach_dep.s
deleted file mode 100644
index 92f06286e73..00000000000
--- a/boehm-gc/powerpc_macosx_mach_dep.s
+++ /dev/null
@@ -1,95 +0,0 @@
-
-.text
-
- .set linkageArea,24
- .set params,4
- .set alignment,4
-
- .set spaceToSave,linkageArea+params+alignment
- .set spaceToSave8,spaceToSave+8
-
-; Mark from machine registers that are saved by C compiler
- .globl _GC_push_regs
-_GC_push_regs:
- ; PROLOG
- mflr r0 ; get return address
- stw r0,8(r1) ; save return address
- stwu r1,-spaceToSave(r1) ; skip over caller save area
- ;
- mr r3,r2 ; mark from r2. Well Im not really sure
- ; that this is necessary or even the right
- ; thing to do - at least it doesnt harm...
- ; According to Apples docs it points to
- ; the direct data area, whatever that is...
- bl L_GC_push_one$stub
- mr r3,r13 ; mark from r13-r31
- bl L_GC_push_one$stub
- mr r3,r14
- bl L_GC_push_one$stub
- mr r3,r15
- bl L_GC_push_one$stub
- mr r3,r16
- bl L_GC_push_one$stub
- mr r3,r17
- bl L_GC_push_one$stub
- mr r3,r18
- bl L_GC_push_one$stub
- mr r3,r19
- bl L_GC_push_one$stub
- mr r3,r20
- bl L_GC_push_one$stub
- mr r3,r21
- bl L_GC_push_one$stub
- mr r3,r22
- bl L_GC_push_one$stub
- mr r3,r23
- bl L_GC_push_one$stub
- mr r3,r24
- bl L_GC_push_one$stub
- mr r3,r25
- bl L_GC_push_one$stub
- mr r3,r26
- bl L_GC_push_one$stub
- mr r3,r27
- bl L_GC_push_one$stub
- mr r3,r28
- bl L_GC_push_one$stub
- mr r3,r29
- bl L_GC_push_one$stub
- mr r3,r30
- bl L_GC_push_one$stub
- mr r3,r31
- bl L_GC_push_one$stub
- ; EPILOG
- lwz r0,spaceToSave8(r1) ; get return address back
- mtlr r0 ; reset link register
- addic r1,r1,spaceToSave ; restore stack pointer
- blr
-
-.data
-.picsymbol_stub
-L_GC_push_one$stub:
- .indirect_symbol _GC_push_one
- mflr r0
- bcl 20,31,L0$_GC_push_one
-L0$_GC_push_one:
- mflr r11
- addis r11,r11,ha16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)
- mtlr r0
- lwz r12,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)(r11)
- mtctr r12
- addi r11,r11,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)
- bctr
-.data
-.lazy_symbol_pointer
-L_GC_push_one$lazy_ptr:
- .indirect_symbol _GC_push_one
- .long dyld_stub_binding_helper
-.non_lazy_symbol_pointer
-L_GC_push_one$non_lazy_ptr:
- .indirect_symbol _GC_push_one
- .long 0
-
-
-
-
diff --git a/boehm-gc/pthread_start.c b/boehm-gc/pthread_start.c
new file mode 100644
index 00000000000..776a368d29d
--- /dev/null
+++ b/boehm-gc/pthread_start.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2010 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* We want to make sure that GC_thread_exit_proc() is unconditionally */
+/* invoked, even if the client is not compiled with -fexceptions, but */
+/* the GC is. The workaround is to put GC_inner_start_routine() in its */
+/* own file (pthread_start.c), and undefine __EXCEPTIONS in the GCC */
+/* case at the top of the file. FIXME: it's still unclear whether this */
+/* will actually cause the exit handler to be invoked last when */
+/* thread_exit is called (and if -fexceptions is used). */
+#if defined(__GNUC__) && defined(__linux__)
+ /* We undefine __EXCEPTIONS to avoid using GCC __cleanup__ attribute. */
+ /* The current NPTL implementation of pthread_cleanup_push uses */
+ /* __cleanup__ attribute when __EXCEPTIONS is defined (-fexceptions). */
+ /* The stack unwinding and cleanup with __cleanup__ attributes work */
+ /* correctly when everything is compiled with -fexceptions, but it is */
+ /* not the requirement for this library clients to use -fexceptions */
+ /* everywhere. With __EXCEPTIONS undefined, the cleanup routines are */
+ /* registered with __pthread_register_cancel thus should work anyway. */
+# undef __EXCEPTIONS
+#endif
+
+#include "private/pthread_support.h"
+
+#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
+
+#include <pthread.h>
+#include <sched.h>
+
+/* Invoked from GC_start_routine(). */
+void * GC_CALLBACK GC_inner_start_routine(struct GC_stack_base *sb, void *arg)
+{
+ void * (*start)(void *);
+ void * start_arg;
+ void * result;
+ volatile GC_thread me =
+ GC_start_rtn_prepare_thread(&start, &start_arg, sb, arg);
+
+# ifndef NACL
+ pthread_cleanup_push(GC_thread_exit_proc, me);
+# endif
+ result = (*start)(start_arg);
+# ifdef DEBUG_THREADS
+ GC_log_printf("Finishing thread %p\n", (void *)pthread_self());
+# endif
+ me -> status = result;
+# ifndef NACL
+ pthread_cleanup_pop(1);
+ /* Cleanup acquires lock, ensuring that we can't exit while */
+ /* a collection that thinks we're alive is trying to stop us. */
+# endif
+ return result;
+}
+
+#endif /* GC_PTHREADS */
diff --git a/boehm-gc/pthread_stop_world.c b/boehm-gc/pthread_stop_world.c
new file mode 100644
index 00000000000..a06ffb71cc8
--- /dev/null
+++ b/boehm-gc/pthread_stop_world.c
@@ -0,0 +1,923 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#include "private/pthread_support.h"
+
+#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && \
+ !defined(GC_DARWIN_THREADS)
+
+#ifdef NACL
+
+#include <unistd.h>
+#include <sys/time.h>
+
+STATIC int GC_nacl_num_gc_threads = 0;
+STATIC __thread int GC_nacl_thread_idx = -1;
+STATIC int GC_nacl_park_threads_now = 0;
+STATIC pthread_t GC_nacl_thread_parker = -1;
+
+GC_INNER __thread GC_thread GC_nacl_gc_thread_self = NULL;
+
+int GC_nacl_thread_parked[MAX_NACL_GC_THREADS];
+int GC_nacl_thread_used[MAX_NACL_GC_THREADS];
+
+#elif defined(GC_OPENBSD_THREADS)
+
+# include <pthread_np.h>
+
+#else /* !GC_OPENBSD_THREADS && !NACL */
+
+#include <signal.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <unistd.h>
+#include "atomic_ops.h"
+
+/* It's safe to call original pthread_sigmask() here. */
+#undef pthread_sigmask
+
+#ifdef DEBUG_THREADS
+# ifndef NSIG
+# if defined(MAXSIG)
+# define NSIG (MAXSIG+1)
+# elif defined(_NSIG)
+# define NSIG _NSIG
+# elif defined(__SIGRTMAX)
+# define NSIG (__SIGRTMAX+1)
+# else
+ --> please fix it
+# endif
+# endif /* NSIG */
+
+ void GC_print_sig_mask(void)
+ {
+ sigset_t blocked;
+ int i;
+
+ if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
+ ABORT("pthread_sigmask failed");
+ for (i = 1; i < NSIG; i++) {
+ if (sigismember(&blocked, i))
+ GC_printf("Signal blocked: %d\n", i);
+ }
+ }
+#endif /* DEBUG_THREADS */
+
+/* Remove the signals that we want to allow in thread stopping */
+/* handler from a set. */
+STATIC void GC_remove_allowed_signals(sigset_t *set)
+{
+ if (sigdelset(set, SIGINT) != 0
+ || sigdelset(set, SIGQUIT) != 0
+ || sigdelset(set, SIGABRT) != 0
+ || sigdelset(set, SIGTERM) != 0) {
+ ABORT("sigdelset failed");
+ }
+
+# ifdef MPROTECT_VDB
+ /* Handlers write to the thread structure, which is in the heap, */
+ /* and hence can trigger a protection fault. */
+ if (sigdelset(set, SIGSEGV) != 0
+# ifdef SIGBUS
+ || sigdelset(set, SIGBUS) != 0
+# endif
+ ) {
+ ABORT("sigdelset failed");
+ }
+# endif
+}
+
+static sigset_t suspend_handler_mask;
+
+STATIC volatile AO_t GC_stop_count = 0;
+ /* Incremented at the beginning of GC_stop_world. */
+
+STATIC volatile AO_t GC_world_is_stopped = FALSE;
+ /* FALSE ==> it is safe for threads to restart, i.e. */
+ /* they will see another suspend signal before they */
+ /* are expected to stop (unless they have voluntarily */
+ /* stopped). */
+
+#ifdef GC_OSF1_THREADS
+ STATIC GC_bool GC_retry_signals = TRUE;
+#else
+ STATIC GC_bool GC_retry_signals = FALSE;
+#endif
+
+/*
+ * We use signals to stop threads during GC.
+ *
+ * Suspended threads wait in signal handler for SIG_THR_RESTART.
+ * That's more portable than semaphores or condition variables.
+ * (We do use sem_post from a signal handler, but that should be portable.)
+ *
+ * The thread suspension signal SIG_SUSPEND is now defined in gc_priv.h.
+ * Note that we can't just stop a thread; we need it to save its stack
+ * pointer(s) and acknowledge.
+ */
+
+#ifndef SIG_THR_RESTART
+# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) \
+ || defined(GC_NETBSD_THREADS)
+# ifdef _SIGRTMIN
+# define SIG_THR_RESTART _SIGRTMIN + 5
+# else
+# define SIG_THR_RESTART SIGRTMIN + 5
+# endif
+# else
+# define SIG_THR_RESTART SIGXCPU
+# endif
+#endif
+
+STATIC int GC_sig_suspend = SIG_SUSPEND;
+STATIC int GC_sig_thr_restart = SIG_THR_RESTART;
+
+GC_API void GC_CALL GC_set_suspend_signal(int sig)
+{
+ if (GC_is_initialized) return;
+
+ GC_sig_suspend = sig;
+}
+
+GC_API void GC_CALL GC_set_thr_restart_signal(int sig)
+{
+ if (GC_is_initialized) return;
+
+ GC_sig_thr_restart = sig;
+}
+
+GC_API int GC_CALL GC_get_suspend_signal(void)
+{
+ return GC_sig_suspend;
+}
+
+GC_API int GC_CALL GC_get_thr_restart_signal(void)
+{
+ return GC_sig_thr_restart;
+}
+
+#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+ /* Some targets (eg., Solaris) might require this to be called when */
+ /* doing thread registering from the thread destructor. */
+ GC_INNER void GC_unblock_gc_signals(void)
+ {
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, GC_sig_suspend);
+ sigaddset(&set, GC_sig_thr_restart);
+ if (pthread_sigmask(SIG_UNBLOCK, &set, NULL) != 0)
+ ABORT("pthread_sigmask failed");
+ }
+#endif /* GC_EXPLICIT_SIGNALS_UNBLOCK */
+
+STATIC sem_t GC_suspend_ack_sem;
+
+#ifdef GC_NETBSD_THREADS
+# define GC_NETBSD_THREADS_WORKAROUND
+ /* It seems to be necessary to wait until threads have restarted. */
+ /* But it is unclear why that is the case. */
+ STATIC sem_t GC_restart_ack_sem;
+#endif
+
+STATIC void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
+
+#ifdef SA_SIGINFO
+ STATIC void GC_suspend_handler(int sig, siginfo_t * info GC_ATTR_UNUSED,
+ void * context GC_ATTR_UNUSED)
+#else
+ STATIC void GC_suspend_handler(int sig)
+#endif
+{
+ int old_errno = errno;
+
+# if defined(IA64) || defined(HP_PA) || defined(M68K)
+ GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
+# else
+ /* We believe that in all other cases the full context is already */
+ /* in the signal handler frame. */
+# ifndef SA_SIGINFO
+ void *context = 0;
+# endif
+ GC_suspend_handler_inner((ptr_t)(word)sig, context);
+# endif
+ errno = old_errno;
+}
+
+STATIC void GC_suspend_handler_inner(ptr_t sig_arg,
+ void * context GC_ATTR_UNUSED)
+{
+ pthread_t self = pthread_self();
+ GC_thread me;
+ IF_CANCEL(int cancel_state;)
+ AO_t my_stop_count = AO_load(&GC_stop_count);
+
+ if ((signed_word)sig_arg != GC_sig_suspend)
+ ABORT("Bad signal in suspend_handler");
+
+ DISABLE_CANCEL(cancel_state);
+ /* pthread_setcancelstate is not defined to be async-signal-safe. */
+ /* But the glibc version appears to be in the absence of */
+ /* asynchronous cancellation. And since this signal handler */
+ /* to block on sigsuspend, which is both async-signal-safe */
+ /* and a cancellation point, there seems to be no obvious way */
+ /* out of it. In fact, it looks to me like an async-signal-safe */
+ /* cancellation point is inherently a problem, unless there is */
+ /* some way to disable cancellation in the handler. */
+# ifdef DEBUG_THREADS
+ GC_log_printf("Suspending %p\n", (void *)self);
+# endif
+
+ me = GC_lookup_thread(self);
+ /* The lookup here is safe, since I'm doing this on behalf */
+ /* of a thread which holds the allocation lock in order */
+ /* to stop the world. Thus concurrent modification of the */
+ /* data structure is impossible. */
+ if (me -> stop_info.last_stop_count == my_stop_count) {
+ /* Duplicate signal. OK if we are retrying. */
+ if (!GC_retry_signals) {
+ WARN("Duplicate suspend signal in thread %p\n", self);
+ }
+ RESTORE_CANCEL(cancel_state);
+ return;
+ }
+# ifdef SPARC
+ me -> stop_info.stack_ptr = GC_save_regs_in_stack();
+# else
+ me -> stop_info.stack_ptr = GC_approx_sp();
+# endif
+# ifdef IA64
+ me -> backing_store_ptr = GC_save_regs_in_stack();
+# endif
+
+ /* Tell the thread that wants to stop the world that this */
+ /* thread has been stopped. Note that sem_post() is */
+ /* the only async-signal-safe primitive in LinuxThreads. */
+ sem_post(&GC_suspend_ack_sem);
+ me -> stop_info.last_stop_count = my_stop_count;
+
+ /* Wait until that thread tells us to restart by sending */
+ /* this thread a GC_sig_thr_restart signal (should be masked */
+ /* at this point thus there is no race). */
+ /* We do not continue until we receive that signal, */
+ /* but we do not take that as authoritative. (We may be */
+ /* accidentally restarted by one of the user signals we */
+ /* don't block.) After we receive the signal, we use a */
+ /* primitive and expensive mechanism to wait until it's */
+ /* really safe to proceed. Under normal circumstances, */
+ /* this code should not be executed. */
+ do {
+ sigsuspend (&suspend_handler_mask);
+ } while (AO_load_acquire(&GC_world_is_stopped)
+ && AO_load(&GC_stop_count) == my_stop_count);
+ /* If the RESTART signal gets lost, we can still lose. That should */
+ /* be less likely than losing the SUSPEND signal, since we don't do */
+ /* much between the sem_post and sigsuspend. */
+ /* We'd need more handshaking to work around that. */
+ /* Simply dropping the sigsuspend call should be safe, but is */
+ /* unlikely to be efficient. */
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("Continuing %p\n", (void *)self);
+# endif
+ RESTORE_CANCEL(cancel_state);
+}
+
+STATIC void GC_restart_handler(int sig)
+{
+# if defined(DEBUG_THREADS) || defined(GC_NETBSD_THREADS_WORKAROUND)
+ int old_errno = errno; /* Preserve errno value. */
+# endif
+
+ if (sig != GC_sig_thr_restart)
+ ABORT("Bad signal in suspend_handler");
+
+# ifdef GC_NETBSD_THREADS_WORKAROUND
+ sem_post(&GC_restart_ack_sem);
+# endif
+
+ /*
+ ** Note: even if we don't do anything useful here,
+ ** it would still be necessary to have a signal handler,
+ ** rather than ignoring the signals, otherwise
+ ** the signals will not be delivered at all, and
+ ** will thus not interrupt the sigsuspend() above.
+ */
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("In GC_restart_handler for %p\n", (void *)pthread_self());
+# endif
+# if defined(DEBUG_THREADS) || defined(GC_NETBSD_THREADS_WORKAROUND)
+ errno = old_errno;
+# endif
+}
+
+#endif /* !GC_OPENBSD_THREADS && !NACL */
+
+#ifdef IA64
+# define IF_IA64(x) x
+#else
+# define IF_IA64(x)
+#endif
+/* We hold allocation lock. Should do exactly the right thing if the */
+/* world is stopped. Should not fail if it isn't. */
+GC_INNER void GC_push_all_stacks(void)
+{
+ GC_bool found_me = FALSE;
+ size_t nthreads = 0;
+ int i;
+ GC_thread p;
+ ptr_t lo, hi;
+ /* On IA64, we also need to scan the register backing store. */
+ IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
+ pthread_t self = pthread_self();
+ word total_size = 0;
+
+ if (!EXPECT(GC_thr_initialized, TRUE))
+ GC_thr_init();
+# ifdef DEBUG_THREADS
+ GC_log_printf("Pushing stacks from thread %p\n", (void *)self);
+# endif
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (p = GC_threads[i]; p != 0; p = p -> next) {
+ if (p -> flags & FINISHED) continue;
+ ++nthreads;
+ if (THREAD_EQUAL(p -> id, self)) {
+ GC_ASSERT(!p->thread_blocked);
+# ifdef SPARC
+ lo = (ptr_t)GC_save_regs_in_stack();
+# else
+ lo = GC_approx_sp();
+# endif
+ found_me = TRUE;
+ IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
+ } else {
+ lo = p -> stop_info.stack_ptr;
+ IF_IA64(bs_hi = p -> backing_store_ptr;)
+ }
+ if ((p -> flags & MAIN_THREAD) == 0) {
+ hi = p -> stack_end;
+ IF_IA64(bs_lo = p -> backing_store_end);
+ } else {
+ /* The original stack. */
+ hi = GC_stackbottom;
+ IF_IA64(bs_lo = BACKING_STORE_BASE;)
+ }
+# ifdef DEBUG_THREADS
+ GC_log_printf("Stack for thread %p = [%p,%p)\n",
+ (void *)p->id, lo, hi);
+# endif
+ if (0 == lo) ABORT("GC_push_all_stacks: sp not set!");
+ GC_push_all_stack_sections(lo, hi, p -> traced_stack_sect);
+# ifdef STACK_GROWS_UP
+ total_size += lo - hi;
+# else
+ total_size += hi - lo; /* lo <= hi */
+# endif
+# ifdef NACL
+ /* Push reg_storage as roots, this will cover the reg context. */
+ GC_push_all_stack((ptr_t)p -> stop_info.reg_storage,
+ (ptr_t)(p -> stop_info.reg_storage + NACL_GC_REG_STORAGE_SIZE));
+ total_size += NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t);
+# endif
+# ifdef IA64
+# ifdef DEBUG_THREADS
+ GC_log_printf("Reg stack for thread %p = [%p,%p)\n",
+ (void *)p->id, bs_lo, bs_hi);
+# endif
+ /* FIXME: This (if p->id==self) may add an unbounded number of */
+ /* entries, and hence overflow the mark stack, which is bad. */
+ GC_push_all_register_sections(bs_lo, bs_hi,
+ THREAD_EQUAL(p -> id, self),
+ p -> traced_stack_sect);
+ total_size += bs_hi - bs_lo; /* bs_lo <= bs_hi */
+# endif
+ }
+ }
+ GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks\n", (int)nthreads);
+ if (!found_me && !GC_in_thread_creation)
+ ABORT("Collecting from unknown thread");
+ GC_total_stacksize = total_size;
+}
+
+#ifdef DEBUG_THREADS
+ /* There seems to be a very rare thread stopping problem. To help us */
+ /* debug that, we save the ids of the stopping thread. */
+ pthread_t GC_stopping_thread;
+ int GC_stopping_pid = 0;
+#endif
+
+#ifdef PLATFORM_ANDROID
+ extern int tkill(pid_t tid, int sig); /* from sys/linux-unistd.h */
+
+ static int android_thread_kill(pid_t tid, int sig)
+ {
+ int ret;
+ int old_errno = errno;
+
+ ret = tkill(tid, sig);
+ if (ret < 0) {
+ ret = errno;
+ errno = old_errno;
+ }
+
+ return ret;
+ }
+#endif /* PLATFORM_ANDROID */
+
+/* We hold the allocation lock. Suspend all threads that might */
+/* still be running. Return the number of suspend signals that */
+/* were sent. */
+STATIC int GC_suspend_all(void)
+{
+ int n_live_threads = 0;
+ int i;
+
+# ifndef NACL
+ GC_thread p;
+# ifndef GC_OPENBSD_THREADS
+ int result;
+# endif
+ pthread_t self = pthread_self();
+
+# ifdef DEBUG_THREADS
+ GC_stopping_thread = self;
+ GC_stopping_pid = getpid();
+# endif
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (p = GC_threads[i]; p != 0; p = p -> next) {
+ if (!THREAD_EQUAL(p -> id, self)) {
+ if (p -> flags & FINISHED) continue;
+ if (p -> thread_blocked) /* Will wait */ continue;
+# ifndef GC_OPENBSD_THREADS
+ if (p -> stop_info.last_stop_count == GC_stop_count) continue;
+ n_live_threads++;
+# endif
+# ifdef DEBUG_THREADS
+ GC_log_printf("Sending suspend signal to %p\n", (void *)p->id);
+# endif
+
+# ifdef GC_OPENBSD_THREADS
+ {
+ stack_t stack;
+ if (pthread_suspend_np(p -> id) != 0)
+ ABORT("pthread_suspend_np failed");
+ if (pthread_stackseg_np(p->id, &stack))
+ ABORT("pthread_stackseg_np failed");
+ p -> stop_info.stack_ptr = (ptr_t)stack.ss_sp - stack.ss_size;
+ }
+# else
+# ifndef PLATFORM_ANDROID
+ result = pthread_kill(p -> id, GC_sig_suspend);
+# else
+ result = android_thread_kill(p -> kernel_id, GC_sig_suspend);
+# endif
+ switch(result) {
+ case ESRCH:
+ /* Not really there anymore. Possible? */
+ n_live_threads--;
+ break;
+ case 0:
+ break;
+ default:
+# ifdef DEBUG_THREADS
+ GC_log_printf("pthread_kill failed at suspend,"
+ " errcode=%d\n", result);
+# endif
+ ABORT("pthread_kill failed");
+ }
+# endif
+ }
+ }
+ }
+
+# else /* NACL */
+# ifndef NACL_PARK_WAIT_NANOSECONDS
+# define NACL_PARK_WAIT_NANOSECONDS (100 * 1000)
+# endif
+# define NANOS_PER_SECOND (1000UL * 1000 * 1000)
+ unsigned long num_sleeps = 0;
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("pthread_stop_world: num_threads %d\n",
+ GC_nacl_num_gc_threads - 1);
+# endif
+ GC_nacl_thread_parker = pthread_self();
+ GC_nacl_park_threads_now = 1;
+# ifdef DEBUG_THREADS
+ GC_stopping_thread = GC_nacl_thread_parker;
+ GC_stopping_pid = getpid();
+# endif
+
+ while (1) {
+ int num_threads_parked = 0;
+ struct timespec ts;
+ int num_used = 0;
+
+ /* Check the 'parked' flag for each thread the GC knows about. */
+ for (i = 0; i < MAX_NACL_GC_THREADS
+ && num_used < GC_nacl_num_gc_threads; i++) {
+ if (GC_nacl_thread_used[i] == 1) {
+ num_used++;
+ if (GC_nacl_thread_parked[i] == 1) {
+ num_threads_parked++;
+ }
+ }
+ }
+ /* -1 for the current thread. */
+ if (num_threads_parked >= GC_nacl_num_gc_threads - 1)
+ break;
+ ts.tv_sec = 0;
+ ts.tv_nsec = NACL_PARK_WAIT_NANOSECONDS;
+# ifdef DEBUG_THREADS
+ GC_log_printf("Sleep waiting for %d threads to park...\n",
+ GC_nacl_num_gc_threads - num_threads_parked - 1);
+# endif
+ /* This requires _POSIX_TIMERS feature. */
+ nanosleep(&ts, 0);
+ if (++num_sleeps > NANOS_PER_SECOND / NACL_PARK_WAIT_NANOSECONDS) {
+ WARN("GC appears stalled waiting for %" WARN_PRIdPTR
+ " threads to park...\n",
+ GC_nacl_num_gc_threads - num_threads_parked - 1);
+ num_sleeps = 0;
+ }
+ }
+# endif /* NACL */
+ return n_live_threads;
+}
+
+GC_INNER void GC_stop_world(void)
+{
+# if !defined(GC_OPENBSD_THREADS) && !defined(NACL)
+ int i;
+ int n_live_threads;
+ int code;
+# endif
+ GC_ASSERT(I_HOLD_LOCK());
+# ifdef DEBUG_THREADS
+ GC_log_printf("Stopping the world from %p\n", (void *)pthread_self());
+# endif
+
+ /* Make sure all free list construction has stopped before we start. */
+ /* No new construction can start, since free list construction is */
+ /* required to acquire and release the GC lock before it starts, */
+ /* and we have the lock. */
+# ifdef PARALLEL_MARK
+ if (GC_parallel) {
+ GC_acquire_mark_lock();
+ GC_ASSERT(GC_fl_builder_count == 0);
+ /* We should have previously waited for it to become zero. */
+ }
+# endif /* PARALLEL_MARK */
+
+# if defined(GC_OPENBSD_THREADS) || defined(NACL)
+ (void)GC_suspend_all();
+# else
+ AO_store(&GC_stop_count, GC_stop_count+1);
+ /* Only concurrent reads are possible. */
+ AO_store_release(&GC_world_is_stopped, TRUE);
+ n_live_threads = GC_suspend_all();
+
+ if (GC_retry_signals) {
+ unsigned long wait_usecs = 0; /* Total wait since retry. */
+# define WAIT_UNIT 3000
+# define RETRY_INTERVAL 100000
+ for (;;) {
+ int ack_count;
+
+ sem_getvalue(&GC_suspend_ack_sem, &ack_count);
+ if (ack_count == n_live_threads) break;
+ if (wait_usecs > RETRY_INTERVAL) {
+ int newly_sent = GC_suspend_all();
+
+ GC_COND_LOG_PRINTF("Resent %d signals after timeout\n", newly_sent);
+ sem_getvalue(&GC_suspend_ack_sem, &ack_count);
+ if (newly_sent < n_live_threads - ack_count) {
+ WARN("Lost some threads during GC_stop_world?!\n",0);
+ n_live_threads = ack_count + newly_sent;
+ }
+ wait_usecs = 0;
+ }
+ usleep(WAIT_UNIT);
+ wait_usecs += WAIT_UNIT;
+ }
+ }
+
+ for (i = 0; i < n_live_threads; i++) {
+ retry:
+ code = sem_wait(&GC_suspend_ack_sem);
+ if (0 != code) {
+ /* On Linux, sem_wait is documented to always return zero. */
+ /* But the documentation appears to be incorrect. */
+ if (errno == EINTR) {
+ /* Seems to happen with some versions of gdb. */
+ goto retry;
+ }
+ ABORT("sem_wait for handler failed");
+ }
+ }
+# endif
+
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_release_mark_lock();
+# endif
+# ifdef DEBUG_THREADS
+ GC_log_printf("World stopped from %p\n", (void *)pthread_self());
+ GC_stopping_thread = 0;
+# endif
+}
+
+#ifdef NACL
+# if defined(__x86_64__)
+# define NACL_STORE_REGS() \
+ do { \
+ __asm__ __volatile__ ("push %rbx"); \
+ __asm__ __volatile__ ("push %rbp"); \
+ __asm__ __volatile__ ("push %r12"); \
+ __asm__ __volatile__ ("push %r13"); \
+ __asm__ __volatile__ ("push %r14"); \
+ __asm__ __volatile__ ("push %r15"); \
+ __asm__ __volatile__ ("mov %%esp, %0" \
+ : "=m" (GC_nacl_gc_thread_self->stop_info.stack_ptr)); \
+ BCOPY(GC_nacl_gc_thread_self->stop_info.stack_ptr, \
+ GC_nacl_gc_thread_self->stop_info.reg_storage, \
+ NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t)); \
+ __asm__ __volatile__ ("naclasp $48, %r15"); \
+ } while (0)
+# elif defined(__i386__)
+# define NACL_STORE_REGS() \
+ do { \
+ __asm__ __volatile__ ("push %ebx"); \
+ __asm__ __volatile__ ("push %ebp"); \
+ __asm__ __volatile__ ("push %esi"); \
+ __asm__ __volatile__ ("push %edi"); \
+ __asm__ __volatile__ ("mov %%esp, %0" \
+ : "=m" (GC_nacl_gc_thread_self->stop_info.stack_ptr)); \
+ BCOPY(GC_nacl_gc_thread_self->stop_info.stack_ptr, \
+ GC_nacl_gc_thread_self->stop_info.reg_storage, \
+ NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t));\
+ __asm__ __volatile__ ("add $16, %esp"); \
+ } while (0)
+# else
+# error FIXME for non-amd64/x86 NaCl
+# endif
+
+ GC_API_OSCALL void nacl_pre_syscall_hook(void)
+ {
+ if (GC_nacl_thread_idx != -1) {
+ NACL_STORE_REGS();
+ GC_nacl_gc_thread_self->stop_info.stack_ptr = GC_approx_sp();
+ GC_nacl_thread_parked[GC_nacl_thread_idx] = 1;
+ }
+ }
+
+ GC_API_OSCALL void __nacl_suspend_thread_if_needed(void)
+ {
+ if (GC_nacl_park_threads_now) {
+ pthread_t self = pthread_self();
+
+ /* Don't try to park the thread parker. */
+ if (GC_nacl_thread_parker == self)
+ return;
+
+ /* This can happen when a thread is created outside of the GC */
+ /* system (wthread mostly). */
+ if (GC_nacl_thread_idx < 0)
+ return;
+
+ /* If it was already 'parked', we're returning from a syscall, */
+ /* so don't bother storing registers again, the GC has a set. */
+ if (!GC_nacl_thread_parked[GC_nacl_thread_idx]) {
+ NACL_STORE_REGS();
+ GC_nacl_gc_thread_self->stop_info.stack_ptr = GC_approx_sp();
+ }
+ GC_nacl_thread_parked[GC_nacl_thread_idx] = 1;
+ while (GC_nacl_park_threads_now) {
+ /* Just spin. */
+ }
+ GC_nacl_thread_parked[GC_nacl_thread_idx] = 0;
+
+ /* Clear out the reg storage for next suspend. */
+ BZERO(GC_nacl_gc_thread_self->stop_info.reg_storage,
+ NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t));
+ }
+ }
+
+ GC_API_OSCALL void nacl_post_syscall_hook(void)
+ {
+ /* Calling __nacl_suspend_thread_if_needed right away should */
+ /* guarantee we don't mutate the GC set. */
+ __nacl_suspend_thread_if_needed();
+ if (GC_nacl_thread_idx != -1) {
+ GC_nacl_thread_parked[GC_nacl_thread_idx] = 0;
+ }
+ }
+
+ STATIC GC_bool GC_nacl_thread_parking_inited = FALSE;
+ STATIC pthread_mutex_t GC_nacl_thread_alloc_lock = PTHREAD_MUTEX_INITIALIZER;
+
+ extern void nacl_register_gc_hooks(void (*pre)(void), void (*post)(void));
+
+ GC_INNER void GC_nacl_initialize_gc_thread(void)
+ {
+ int i;
+ nacl_register_gc_hooks(nacl_pre_syscall_hook, nacl_post_syscall_hook);
+ pthread_mutex_lock(&GC_nacl_thread_alloc_lock);
+ if (!EXPECT(GC_nacl_thread_parking_inited, TRUE)) {
+ BZERO(GC_nacl_thread_parked, sizeof(GC_nacl_thread_parked));
+ BZERO(GC_nacl_thread_used, sizeof(GC_nacl_thread_used));
+ GC_nacl_thread_parking_inited = TRUE;
+ }
+ GC_ASSERT(GC_nacl_num_gc_threads <= MAX_NACL_GC_THREADS);
+ for (i = 0; i < MAX_NACL_GC_THREADS; i++) {
+ if (GC_nacl_thread_used[i] == 0) {
+ GC_nacl_thread_used[i] = 1;
+ GC_nacl_thread_idx = i;
+ GC_nacl_num_gc_threads++;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&GC_nacl_thread_alloc_lock);
+ }
+
+ GC_INNER void GC_nacl_shutdown_gc_thread(void)
+ {
+ pthread_mutex_lock(&GC_nacl_thread_alloc_lock);
+ GC_ASSERT(GC_nacl_thread_idx >= 0);
+ GC_ASSERT(GC_nacl_thread_idx < MAX_NACL_GC_THREADS);
+ GC_ASSERT(GC_nacl_thread_used[GC_nacl_thread_idx] != 0);
+ GC_nacl_thread_used[GC_nacl_thread_idx] = 0;
+ GC_nacl_thread_idx = -1;
+ GC_nacl_num_gc_threads--;
+ pthread_mutex_unlock(&GC_nacl_thread_alloc_lock);
+ }
+#endif /* NACL */
+
+/* Caller holds allocation lock, and has held it continuously since */
+/* the world stopped. */
+GC_INNER void GC_start_world(void)
+{
+# ifndef NACL
+ pthread_t self = pthread_self();
+ register int i;
+ register GC_thread p;
+# ifndef GC_OPENBSD_THREADS
+ register int n_live_threads = 0;
+ register int result;
+# endif
+# ifdef GC_NETBSD_THREADS_WORKAROUND
+ int code;
+# endif
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("World starting\n");
+# endif
+
+# ifndef GC_OPENBSD_THREADS
+ AO_store(&GC_world_is_stopped, FALSE);
+# endif
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (p = GC_threads[i]; p != 0; p = p -> next) {
+ if (!THREAD_EQUAL(p -> id, self)) {
+ if (p -> flags & FINISHED) continue;
+ if (p -> thread_blocked) continue;
+# ifndef GC_OPENBSD_THREADS
+ n_live_threads++;
+# endif
+# ifdef DEBUG_THREADS
+ GC_log_printf("Sending restart signal to %p\n", (void *)p->id);
+# endif
+
+# ifdef GC_OPENBSD_THREADS
+ if (pthread_resume_np(p -> id) != 0)
+ ABORT("pthread_resume_np failed");
+# else
+# ifndef PLATFORM_ANDROID
+ result = pthread_kill(p -> id, GC_sig_thr_restart);
+# else
+ result = android_thread_kill(p -> kernel_id,
+ GC_sig_thr_restart);
+# endif
+ switch(result) {
+ case ESRCH:
+ /* Not really there anymore. Possible? */
+ n_live_threads--;
+ break;
+ case 0:
+ break;
+ default:
+# ifdef DEBUG_THREADS
+ GC_log_printf("pthread_kill failed at resume,"
+ " errcode=%d\n", result);
+# endif
+ ABORT("pthread_kill failed");
+ }
+# endif
+ }
+ }
+ }
+# ifdef GC_NETBSD_THREADS_WORKAROUND
+ for (i = 0; i < n_live_threads; i++) {
+ while (0 != (code = sem_wait(&GC_restart_ack_sem))) {
+ if (errno != EINTR) {
+ GC_COND_LOG_PRINTF("sem_wait() returned %d\n", code);
+ ABORT("sem_wait() for restart handler failed");
+ }
+ }
+ }
+# endif
+# ifdef DEBUG_THREADS
+ GC_log_printf("World started\n");
+# endif
+# else /* NACL */
+# ifdef DEBUG_THREADS
+ GC_log_printf("World starting...\n");
+# endif
+ GC_nacl_park_threads_now = 0;
+# endif
+}
+
+GC_INNER void GC_stop_init(void)
+{
+# if !defined(GC_OPENBSD_THREADS) && !defined(NACL)
+ struct sigaction act;
+
+ if (sem_init(&GC_suspend_ack_sem, GC_SEM_INIT_PSHARED, 0) != 0)
+ ABORT("sem_init failed");
+# ifdef GC_NETBSD_THREADS_WORKAROUND
+ if (sem_init(&GC_restart_ack_sem, GC_SEM_INIT_PSHARED, 0) != 0)
+ ABORT("sem_init failed");
+# endif
+
+# ifdef SA_RESTART
+ act.sa_flags = SA_RESTART
+# else
+ act.sa_flags = 0
+# endif
+# ifdef SA_SIGINFO
+ | SA_SIGINFO
+# endif
+ ;
+ if (sigfillset(&act.sa_mask) != 0) {
+ ABORT("sigfillset failed");
+ }
+# ifdef GC_RTEMS_PTHREADS
+ if(sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL) != 0) {
+ ABORT("sigprocmask failed");
+ }
+# endif
+ GC_remove_allowed_signals(&act.sa_mask);
+ /* GC_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
+ /* act.sa_restorer is deprecated and should not be initialized. */
+ if (sigaction(GC_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(GC_sig_thr_restart, &act, NULL) != 0) {
+ ABORT("Cannot set SIG_THR_RESTART handler");
+ }
+
+ /* Initialize suspend_handler_mask (excluding GC_sig_thr_restart). */
+ if (sigfillset(&suspend_handler_mask) != 0) ABORT("sigfillset failed");
+ GC_remove_allowed_signals(&suspend_handler_mask);
+ if (sigdelset(&suspend_handler_mask, GC_sig_thr_restart) != 0)
+ ABORT("sigdelset failed");
+
+ /* Check for GC_RETRY_SIGNALS. */
+ if (0 != GETENV("GC_RETRY_SIGNALS")) {
+ GC_retry_signals = TRUE;
+ }
+ if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
+ GC_retry_signals = FALSE;
+ }
+ if (GC_retry_signals) {
+ GC_COND_LOG_PRINTF("Will retry suspend signal if necessary\n");
+ }
+# endif /* !GC_OPENBSD_THREADS && !NACL */
+}
+
+#endif /* GC_PTHREADS && !GC_DARWIN_THREADS && !GC_WIN32_THREADS */
diff --git a/boehm-gc/pthread_support.c b/boehm-gc/pthread_support.c
new file mode 100644
index 00000000000..da24d10e6c5
--- /dev/null
+++ b/boehm-gc/pthread_support.c
@@ -0,0 +1,2048 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2005 by Hewlett-Packard Company. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#include "private/pthread_support.h"
+
+/*
+ * Support code originally for LinuxThreads, the clone()-based kernel
+ * thread package for Linux which is included in libc6.
+ *
+ * This code no doubt makes some assumptions beyond what is
+ * guaranteed by the pthread standard, though it now does
+ * very little of that. It now also supports NPTL, and many
+ * other Posix thread implementations. We are trying to merge
+ * all flavors of pthread support code into this file.
+ */
+
+/*
+ * Linux_threads.c now also includes some code to support HPUX and
+ * OSF1 (Compaq Tru64 Unix, really). The OSF1 support is based on Eric Benson's
+ * patch.
+ *
+ * Eric also suggested an alternate basis for a lock implementation in
+ * his code:
+ * + #elif defined(OSF1)
+ * + unsigned long GC_allocate_lock = 0;
+ * + msemaphore GC_allocate_semaphore;
+ * + # define GC_TRY_LOCK() \
+ * + ((msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) == 0) \
+ * + ? (GC_allocate_lock = 1) \
+ * + : 0)
+ * + # define GC_LOCK_TAKEN GC_allocate_lock
+ */
+
+#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
+
+# include <stdlib.h>
+# include <pthread.h>
+# include <sched.h>
+# include <time.h>
+# include <errno.h>
+# include <unistd.h>
+# if !defined(GC_RTEMS_PTHREADS)
+# include <sys/mman.h>
+# endif
+# include <sys/time.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <signal.h>
+
+# include "gc_inline.h"
+
+#if defined(GC_DARWIN_THREADS)
+# include "private/darwin_semaphore.h"
+#else
+# include <semaphore.h>
+#endif /* !GC_DARWIN_THREADS */
+
+#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
+# include <sys/sysctl.h>
+#endif /* GC_DARWIN_THREADS */
+
+#if defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS)
+# include <sys/param.h>
+# include <sys/sysctl.h>
+#endif /* GC_NETBSD_THREADS */
+
+/* Allocator lock definitions. */
+#if !defined(USE_SPIN_LOCK)
+ GC_INNER pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
+#endif
+GC_INNER unsigned long GC_lock_holder = NO_THREAD;
+ /* Used only for assertions, and to prevent */
+ /* recursive reentry in the system call wrapper. */
+
+#if defined(GC_DGUX386_THREADS)
+# include <sys/dg_sys_info.h>
+# include <sys/_int_psem.h>
+ /* sem_t is an uint in DG/UX */
+ typedef unsigned int sem_t;
+#endif /* GC_DGUX386_THREADS */
+
+/* Undefine macros used to redirect pthread primitives. */
+# undef pthread_create
+# ifndef GC_NO_PTHREAD_SIGMASK
+# undef pthread_sigmask
+# endif
+# ifndef GC_NO_PTHREAD_CANCEL
+# undef pthread_cancel
+# endif
+# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+# undef pthread_exit
+# endif
+# undef pthread_join
+# undef pthread_detach
+# if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
+ && !defined(_PTHREAD_USE_PTDNAM_)
+ /* Restore the original mangled names on Tru64 UNIX. */
+# define pthread_create __pthread_create
+# define pthread_join __pthread_join
+# define pthread_detach __pthread_detach
+# ifndef GC_NO_PTHREAD_CANCEL
+# define pthread_cancel __pthread_cancel
+# endif
+# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+# define pthread_exit __pthread_exit
+# endif
+# endif
+
+#ifdef GC_USE_LD_WRAP
+# define WRAP_FUNC(f) __wrap_##f
+# define REAL_FUNC(f) __real_##f
+ int REAL_FUNC(pthread_create)(pthread_t *,
+ GC_PTHREAD_CREATE_CONST pthread_attr_t *,
+ void *(*start_routine)(void *), void *);
+ int REAL_FUNC(pthread_join)(pthread_t, void **);
+ int REAL_FUNC(pthread_detach)(pthread_t);
+# ifndef GC_NO_PTHREAD_SIGMASK
+ int REAL_FUNC(pthread_sigmask)(int, const sigset_t *, sigset_t *);
+# endif
+# ifndef GC_NO_PTHREAD_CANCEL
+ int REAL_FUNC(pthread_cancel)(pthread_t);
+# endif
+# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+ void REAL_FUNC(pthread_exit)(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
+# endif
+#else
+# ifdef GC_USE_DLOPEN_WRAP
+# include <dlfcn.h>
+# define WRAP_FUNC(f) f
+# define REAL_FUNC(f) GC_real_##f
+ /* We define both GC_f and plain f to be the wrapped function. */
+ /* In that way plain calls work, as do calls from files that */
+ /* included gc.h, wich redefined f to GC_f. */
+ /* FIXME: Needs work for DARWIN and True64 (OSF1) */
+ typedef int (* GC_pthread_create_t)(pthread_t *,
+ GC_PTHREAD_CREATE_CONST pthread_attr_t *,
+ void * (*)(void *), void *);
+ static GC_pthread_create_t REAL_FUNC(pthread_create);
+# ifndef GC_NO_PTHREAD_SIGMASK
+ typedef int (* GC_pthread_sigmask_t)(int, const sigset_t *,
+ sigset_t *);
+ static GC_pthread_sigmask_t REAL_FUNC(pthread_sigmask);
+# endif
+ typedef int (* GC_pthread_join_t)(pthread_t, void **);
+ static GC_pthread_join_t REAL_FUNC(pthread_join);
+ typedef int (* GC_pthread_detach_t)(pthread_t);
+ static GC_pthread_detach_t REAL_FUNC(pthread_detach);
+# ifndef GC_NO_PTHREAD_CANCEL
+ typedef int (* GC_pthread_cancel_t)(pthread_t);
+ static GC_pthread_cancel_t REAL_FUNC(pthread_cancel);
+# endif
+# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+ typedef void (* GC_pthread_exit_t)(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
+ static GC_pthread_exit_t REAL_FUNC(pthread_exit);
+# endif
+# else
+# define WRAP_FUNC(f) GC_##f
+# if !defined(GC_DGUX386_THREADS)
+# define REAL_FUNC(f) f
+# else /* GC_DGUX386_THREADS */
+# define REAL_FUNC(f) __d10_##f
+# endif /* GC_DGUX386_THREADS */
+# endif
+#endif
+
+#if defined(GC_USE_LD_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 references to the GC_ symbols, to see the right symbols. */
+ GC_API int GC_pthread_create(pthread_t * t,
+ GC_PTHREAD_CREATE_CONST pthread_attr_t *a,
+ void * (* fn)(void *), void * arg)
+ {
+ return pthread_create(t, a, fn, arg);
+ }
+
+# ifndef GC_NO_PTHREAD_SIGMASK
+ GC_API int GC_pthread_sigmask(int how, const sigset_t *mask,
+ sigset_t *old)
+ {
+ return pthread_sigmask(how, mask, old);
+ }
+# endif /* !GC_NO_PTHREAD_SIGMASK */
+
+ GC_API int GC_pthread_join(pthread_t t, void **res)
+ {
+ return pthread_join(t, res);
+ }
+
+ GC_API int GC_pthread_detach(pthread_t t)
+ {
+ return pthread_detach(t);
+ }
+
+# ifndef GC_NO_PTHREAD_CANCEL
+ GC_API int GC_pthread_cancel(pthread_t t)
+ {
+ return pthread_cancel(t);
+ }
+# endif /* !GC_NO_PTHREAD_CANCEL */
+
+# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+ GC_API GC_PTHREAD_EXIT_ATTRIBUTE void GC_pthread_exit(void *retval)
+ {
+ pthread_exit(retval);
+ }
+# endif /* GC_PTHREAD_EXIT_ATTRIBUTE */
+#endif /* Linker-based interception. */
+
+#ifdef GC_USE_DLOPEN_WRAP
+ STATIC GC_bool GC_syms_initialized = FALSE;
+
+ STATIC void GC_init_real_syms(void)
+ {
+ void *dl_handle;
+
+ if (GC_syms_initialized) return;
+# ifdef RTLD_NEXT
+ dl_handle = RTLD_NEXT;
+# else
+ dl_handle = dlopen("libpthread.so.0", RTLD_LAZY);
+ if (NULL == dl_handle) {
+ dl_handle = dlopen("libpthread.so", RTLD_LAZY); /* without ".0" */
+ }
+ if (NULL == dl_handle) ABORT("Couldn't open libpthread");
+# endif
+ REAL_FUNC(pthread_create) = (GC_pthread_create_t)
+ dlsym(dl_handle, "pthread_create");
+# ifdef RTLD_NEXT
+ if (REAL_FUNC(pthread_create) == 0)
+ ABORT("pthread_create not found"
+ " (probably -lgc is specified after -lpthread)");
+# endif
+# ifndef GC_NO_PTHREAD_SIGMASK
+ REAL_FUNC(pthread_sigmask) = (GC_pthread_sigmask_t)
+ dlsym(dl_handle, "pthread_sigmask");
+# endif
+ REAL_FUNC(pthread_join) = (GC_pthread_join_t)
+ dlsym(dl_handle, "pthread_join");
+ REAL_FUNC(pthread_detach) = (GC_pthread_detach_t)
+ dlsym(dl_handle, "pthread_detach");
+# ifndef GC_NO_PTHREAD_CANCEL
+ REAL_FUNC(pthread_cancel) = (GC_pthread_cancel_t)
+ dlsym(dl_handle, "pthread_cancel");
+# endif
+# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+ REAL_FUNC(pthread_exit) = (GC_pthread_exit_t)
+ dlsym(dl_handle, "pthread_exit");
+# endif
+ GC_syms_initialized = TRUE;
+ }
+
+# define INIT_REAL_SYMS() if (!EXPECT(GC_syms_initialized, TRUE)) \
+ GC_init_real_syms()
+#else
+# define INIT_REAL_SYMS()
+#endif
+
+static GC_bool parallel_initialized = FALSE;
+
+GC_INNER GC_bool GC_need_to_lock = FALSE;
+
+STATIC int GC_nprocs = 1;
+ /* Number of processors. We may not have */
+ /* access to all of them, but this is as good */
+ /* a guess as any ... */
+
+#ifdef THREAD_LOCAL_ALLOC
+ /* We must explicitly mark ptrfree and gcj free lists, since the free */
+ /* list links wouldn't otherwise be found. We also set them in the */
+ /* normal free lists, since that involves touching less memory than */
+ /* if we scanned them normally. */
+ GC_INNER void GC_mark_thread_local_free_lists(void)
+ {
+ int i;
+ GC_thread p;
+
+ for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+ for (p = GC_threads[i]; 0 != p; p = p -> next) {
+ if (!(p -> flags & FINISHED))
+ GC_mark_thread_local_fls_for(&(p->tlfs));
+ }
+ }
+ }
+
+# if defined(GC_ASSERTIONS)
+ void GC_check_tls_for(GC_tlfs p);
+# if defined(USE_CUSTOM_SPECIFIC)
+ void GC_check_tsd_marks(tsd *key);
+# endif
+
+ /* Check that all thread-local free-lists are completely marked. */
+ /* Also check that thread-specific-data structures are marked. */
+ void GC_check_tls(void)
+ {
+ int i;
+ GC_thread p;
+
+ for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+ for (p = GC_threads[i]; 0 != p; p = p -> next) {
+ if (!(p -> flags & FINISHED))
+ GC_check_tls_for(&(p->tlfs));
+ }
+ }
+# if defined(USE_CUSTOM_SPECIFIC)
+ if (GC_thread_key != 0)
+ GC_check_tsd_marks(GC_thread_key);
+# endif
+ }
+# endif /* GC_ASSERTIONS */
+
+#endif /* THREAD_LOCAL_ALLOC */
+
+#ifdef PARALLEL_MARK
+
+# ifndef MAX_MARKERS
+# define MAX_MARKERS 16
+# endif
+
+static ptr_t marker_sp[MAX_MARKERS - 1] = {0};
+#ifdef IA64
+ static ptr_t marker_bsp[MAX_MARKERS - 1] = {0};
+#endif
+
+#if defined(GC_DARWIN_THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
+ static mach_port_t marker_mach_threads[MAX_MARKERS - 1] = {0};
+
+ /* Used only by GC_suspend_thread_list(). */
+ GC_INNER GC_bool GC_is_mach_marker(thread_act_t thread)
+ {
+ int i;
+ for (i = 0; i < GC_markers_m1; i++) {
+ if (marker_mach_threads[i] == thread)
+ return TRUE;
+ }
+ return FALSE;
+ }
+#endif /* GC_DARWIN_THREADS */
+
+STATIC void * GC_mark_thread(void * id)
+{
+ word my_mark_no = 0;
+ IF_CANCEL(int cancel_state;)
+
+ if ((word)id == (word)-1) return 0; /* to make compiler happy */
+ DISABLE_CANCEL(cancel_state);
+ /* Mark threads are not cancellable; they */
+ /* should be invisible to client. */
+ marker_sp[(word)id] = GC_approx_sp();
+# ifdef IA64
+ marker_bsp[(word)id] = GC_save_regs_in_stack();
+# endif
+# if defined(GC_DARWIN_THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
+ marker_mach_threads[(word)id] = mach_thread_self();
+# endif
+
+ for (;; ++my_mark_no) {
+ /* GC_mark_no is passed only to allow GC_help_marker to terminate */
+ /* promptly. This is important if it were called from the signal */
+ /* handler or from the GC lock acquisition code. Under Linux, it's */
+ /* not safe to call it from a signal handler, since it uses mutexes */
+ /* and condition variables. Since it is called only here, the */
+ /* argument is unnecessary. */
+ if (my_mark_no < GC_mark_no || my_mark_no > GC_mark_no + 2) {
+ /* resynchronize if we get far off, e.g. because GC_mark_no */
+ /* wrapped. */
+ my_mark_no = GC_mark_no;
+ }
+# ifdef DEBUG_THREADS
+ GC_log_printf("Starting mark helper for mark number %lu\n",
+ (unsigned long)my_mark_no);
+# endif
+ GC_help_marker(my_mark_no);
+ }
+}
+
+STATIC pthread_t GC_mark_threads[MAX_MARKERS];
+
+#ifdef CAN_HANDLE_FORK
+ static int available_markers_m1 = 0;
+# define start_mark_threads GC_start_mark_threads
+ GC_API void GC_CALL
+#else
+# define available_markers_m1 GC_markers_m1
+ static void
+#endif
+start_mark_threads(void)
+{
+ int i;
+ pthread_attr_t attr;
+
+ GC_ASSERT(I_DONT_HOLD_LOCK());
+# ifdef CAN_HANDLE_FORK
+ if (available_markers_m1 <= 0 || GC_parallel) return;
+ /* Skip if parallel markers disabled or already started. */
+# endif
+
+ INIT_REAL_SYMS(); /* for pthread_create */
+
+ if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
+ if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
+ ABORT("pthread_attr_setdetachstate failed");
+
+# if defined(HPUX) || defined(GC_DGUX386_THREADS)
+ /* Default stack size is usually too small: fix it. */
+ /* Otherwise marker threads or GC may run out of */
+ /* space. */
+# define MIN_STACK_SIZE (8*HBLKSIZE*sizeof(word))
+ {
+ size_t old_size;
+
+ if (pthread_attr_getstacksize(&attr, &old_size) != 0)
+ ABORT("pthread_attr_getstacksize failed");
+ if (old_size < MIN_STACK_SIZE) {
+ if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
+ ABORT("pthread_attr_setstacksize failed");
+ }
+ }
+# endif /* HPUX || GC_DGUX386_THREADS */
+ for (i = 0; i < available_markers_m1; ++i) {
+ if (0 != REAL_FUNC(pthread_create)(GC_mark_threads + i, &attr,
+ GC_mark_thread, (void *)(word)i)) {
+ WARN("Marker thread creation failed, errno = %" WARN_PRIdPTR "\n",
+ errno);
+ /* Don't try to create other marker threads. */
+ break;
+ }
+ }
+ GC_markers_m1 = i;
+ pthread_attr_destroy(&attr);
+ GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
+}
+
+#endif /* PARALLEL_MARK */
+
+GC_INNER GC_bool GC_thr_initialized = FALSE;
+
+GC_INNER volatile GC_thread GC_threads[THREAD_TABLE_SZ] = {0};
+
+void GC_push_thread_structures(void)
+{
+ GC_ASSERT(I_HOLD_LOCK());
+ GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_push_all((ptr_t)(&GC_thread_key),
+ (ptr_t)(&GC_thread_key) + sizeof(GC_thread_key));
+# endif
+}
+
+#ifdef DEBUG_THREADS
+ STATIC int GC_count_threads(void)
+ {
+ int i;
+ int count = 0;
+ GC_ASSERT(I_HOLD_LOCK());
+ for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+ GC_thread th = GC_threads[i];
+ while (th) {
+ if (!(th->flags & FINISHED))
+ ++count;
+ th = th->next;
+ }
+ }
+ return count;
+ }
+#endif /* DEBUG_THREADS */
+
+/* It may not be safe to allocate when we register the first thread. */
+static struct GC_Thread_Rep first_thread;
+
+/* Add a thread to GC_threads. We assume it wasn't already there. */
+/* Caller holds allocation lock. */
+STATIC GC_thread GC_new_thread(pthread_t id)
+{
+ int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
+ GC_thread result;
+ static GC_bool first_thread_used = FALSE;
+# ifdef DEBUG_THREADS
+ GC_log_printf("Creating thread %p\n", (void *)id);
+# endif
+
+ GC_ASSERT(I_HOLD_LOCK());
+ if (!EXPECT(first_thread_used, TRUE)) {
+ result = &first_thread;
+ first_thread_used = TRUE;
+ } else {
+ result = (struct GC_Thread_Rep *)
+ GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
+ if (result == 0) return(0);
+ }
+ result -> id = id;
+# ifdef PLATFORM_ANDROID
+ result -> kernel_id = gettid();
+# endif
+ result -> next = GC_threads[hv];
+ GC_threads[hv] = result;
+# ifdef NACL
+ GC_nacl_gc_thread_self = result;
+ GC_nacl_initialize_gc_thread();
+# endif
+ GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
+ return(result);
+}
+
+/* Delete a thread from GC_threads. We assume it is there. */
+/* (The code intentionally traps if it wasn't.) */
+/* It is safe to delete the main thread. */
+STATIC void GC_delete_thread(pthread_t id)
+{
+ int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
+ register GC_thread p = GC_threads[hv];
+ register GC_thread prev = 0;
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("Deleting thread %p, n_threads = %d\n",
+ (void *)id, GC_count_threads());
+# endif
+
+# ifdef NACL
+ GC_nacl_shutdown_gc_thread();
+ GC_nacl_gc_thread_self = NULL;
+# endif
+
+ GC_ASSERT(I_HOLD_LOCK());
+ while (!THREAD_EQUAL(p -> id, id)) {
+ prev = p;
+ p = p -> next;
+ }
+ if (prev == 0) {
+ GC_threads[hv] = p -> next;
+ } else {
+ prev -> next = p -> next;
+ }
+ if (p != &first_thread) {
+# ifdef GC_DARWIN_THREADS
+ mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
+# endif
+ GC_INTERNAL_FREE(p);
+ }
+}
+
+/* If a thread has been joined, but we have not yet */
+/* been notified, then there may be more than one thread */
+/* in the table with the same pthread id. */
+/* This is OK, but we need a way to delete a specific one. */
+STATIC void GC_delete_gc_thread(GC_thread t)
+{
+ pthread_t id = t -> id;
+ int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
+ register GC_thread p = GC_threads[hv];
+ register GC_thread prev = 0;
+
+ GC_ASSERT(I_HOLD_LOCK());
+ while (p != t) {
+ prev = p;
+ p = p -> next;
+ }
+ if (prev == 0) {
+ GC_threads[hv] = p -> next;
+ } else {
+ prev -> next = p -> next;
+ }
+# ifdef GC_DARWIN_THREADS
+ mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
+# endif
+ GC_INTERNAL_FREE(p);
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("Deleted thread %p, n_threads = %d\n",
+ (void *)id, GC_count_threads());
+# endif
+}
+
+/* Return a GC_thread corresponding to a given pthread_t. */
+/* Returns 0 if it's not there. */
+/* Caller holds allocation lock or otherwise inhibits */
+/* updates. */
+/* If there is more than one thread with the given id we */
+/* return the most recent one. */
+GC_INNER GC_thread GC_lookup_thread(pthread_t id)
+{
+ int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
+ register GC_thread p = GC_threads[hv];
+
+ while (p != 0 && !THREAD_EQUAL(p -> id, id)) p = p -> next;
+ return(p);
+}
+
+/* Called by GC_finalize() (in case of an allocation failure observed). */
+GC_INNER void GC_reset_finalizer_nested(void)
+{
+ GC_thread me = GC_lookup_thread(pthread_self());
+ me->finalizer_nested = 0;
+}
+
+/* Checks and updates the thread-local level of finalizers recursion. */
+/* Returns NULL if GC_invoke_finalizers() should not be called by the */
+/* collector (to minimize the risk of a deep finalizers recursion), */
+/* otherwise returns a pointer to the thread-local finalizer_nested. */
+/* Called by GC_notify_or_invoke_finalizers() only (the lock is held). */
+GC_INNER unsigned char *GC_check_finalizer_nested(void)
+{
+ GC_thread me = GC_lookup_thread(pthread_self());
+ unsigned nesting_level = me->finalizer_nested;
+ if (nesting_level) {
+ /* We are inside another GC_invoke_finalizers(). */
+ /* Skip some implicitly-called GC_invoke_finalizers() */
+ /* depending on the nesting (recursion) level. */
+ if (++me->finalizer_skipped < (1U << nesting_level)) return NULL;
+ me->finalizer_skipped = 0;
+ }
+ me->finalizer_nested = (unsigned char)(nesting_level + 1);
+ return &me->finalizer_nested;
+}
+
+#if defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)
+ /* This is called from thread-local GC_malloc(). */
+ GC_bool GC_is_thread_tsd_valid(void *tsd)
+ {
+ GC_thread me;
+ DCL_LOCK_STATE;
+
+ LOCK();
+ me = GC_lookup_thread(pthread_self());
+ UNLOCK();
+ return (word)tsd >= (word)(&me->tlfs)
+ && (word)tsd < (word)(&me->tlfs) + sizeof(me->tlfs);
+ }
+#endif /* GC_ASSERTIONS && THREAD_LOCAL_ALLOC */
+
+GC_API int GC_CALL GC_thread_is_registered(void)
+{
+ pthread_t self = pthread_self();
+ GC_thread me;
+ DCL_LOCK_STATE;
+
+ LOCK();
+ me = GC_lookup_thread(self);
+ UNLOCK();
+ return me != NULL;
+}
+
+#ifdef CAN_HANDLE_FORK
+/* Remove all entries from the GC_threads table, except the */
+/* one for the current thread. We need to do this in the child */
+/* process after a fork(), since only the current thread */
+/* survives in the child. */
+STATIC void GC_remove_all_threads_but_me(void)
+{
+ pthread_t self = pthread_self();
+ int hv;
+ GC_thread p, next, me;
+
+ for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
+ me = 0;
+ for (p = GC_threads[hv]; 0 != p; p = next) {
+ next = p -> next;
+ if (THREAD_EQUAL(p -> id, self)) {
+ me = p;
+ p -> next = 0;
+# ifdef GC_DARWIN_THREADS
+ /* Update thread Id after fork (it is ok to call */
+ /* GC_destroy_thread_local and GC_free_internal */
+ /* before update). */
+ me -> stop_info.mach_thread = mach_thread_self();
+# elif defined(PLATFORM_ANDROID)
+ me -> kernel_id = gettid();
+# endif
+# if defined(THREAD_LOCAL_ALLOC) && !defined(USE_CUSTOM_SPECIFIC)
+ /* Some TLS implementations might be not fork-friendly, so */
+ /* we re-assign thread-local pointer to 'tlfs' for safety */
+ /* instead of the assertion check (again, it is ok to call */
+ /* GC_destroy_thread_local and GC_free_internal before). */
+ if (GC_setspecific(GC_thread_key, &me->tlfs) != 0)
+ ABORT("GC_setspecific failed (in child)");
+# endif
+ } else {
+# ifdef THREAD_LOCAL_ALLOC
+ if (!(p -> flags & FINISHED)) {
+ GC_destroy_thread_local(&(p->tlfs));
+ GC_remove_specific(GC_thread_key);
+ }
+# endif
+ if (p != &first_thread) GC_INTERNAL_FREE(p);
+ }
+ }
+ GC_threads[hv] = me;
+ }
+}
+#endif /* CAN_HANDLE_FORK */
+
+#ifdef USE_PROC_FOR_LIBRARIES
+ GC_INNER GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
+ {
+ int i;
+ GC_thread p;
+
+ GC_ASSERT(I_HOLD_LOCK());
+# ifdef PARALLEL_MARK
+ for (i = 0; i < GC_markers_m1; ++i) {
+ if ((word)marker_sp[i] > (word)lo && (word)marker_sp[i] < (word)hi)
+ return TRUE;
+# ifdef IA64
+ if ((word)marker_bsp[i] > (word)lo
+ && (word)marker_bsp[i] < (word)hi)
+ return TRUE;
+# endif
+ }
+# endif
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (p = GC_threads[i]; p != 0; p = p -> next) {
+ if (0 != p -> stack_end) {
+# ifdef STACK_GROWS_UP
+ if ((word)p->stack_end >= (word)lo
+ && (word)p->stack_end < (word)hi)
+ return TRUE;
+# else /* STACK_GROWS_DOWN */
+ if ((word)p->stack_end > (word)lo
+ && (word)p->stack_end <= (word)hi)
+ return TRUE;
+# endif
+ }
+ }
+ }
+ return FALSE;
+ }
+#endif /* USE_PROC_FOR_LIBRARIES */
+
+#ifdef IA64
+ /* Find the largest stack_base smaller than bound. May be used */
+ /* to find the boundary between a register stack and adjacent */
+ /* immediately preceding memory stack. */
+ GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound)
+ {
+ int i;
+ GC_thread p;
+ ptr_t result = 0;
+
+ GC_ASSERT(I_HOLD_LOCK());
+# ifdef PARALLEL_MARK
+ for (i = 0; i < GC_markers_m1; ++i) {
+ if ((word)marker_sp[i] > (word)result
+ && (word)marker_sp[i] < (word)bound)
+ result = marker_sp[i];
+ }
+# endif
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (p = GC_threads[i]; p != 0; p = p -> next) {
+ if ((word)p->stack_end > (word)result
+ && (word)p->stack_end < (word)bound) {
+ result = p -> stack_end;
+ }
+ }
+ }
+ return result;
+ }
+#endif /* IA64 */
+
+#ifndef STAT_READ
+ /* Also defined in os_dep.c. */
+# define STAT_BUF_SIZE 4096
+# define STAT_READ read
+ /* If read is wrapped, this may need to be redefined to call */
+ /* the real one. */
+#endif
+
+#ifdef GC_HPUX_THREADS
+# define GC_get_nprocs() pthread_num_processors_np()
+
+#elif defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \
+ || defined(GC_SOLARIS_THREADS) || defined(GC_GNU_THREADS) \
+ || defined(PLATFORM_ANDROID) || defined(NACL)
+ GC_INLINE int GC_get_nprocs(void)
+ {
+ int nprocs = (int)sysconf(_SC_NPROCESSORS_ONLN);
+ return nprocs > 0 ? nprocs : 1; /* ignore error silently */
+ }
+
+#elif defined(GC_IRIX_THREADS)
+ GC_INLINE int GC_get_nprocs(void)
+ {
+ int nprocs = (int)sysconf(_SC_NPROC_ONLN);
+ return nprocs > 0 ? nprocs : 1; /* ignore error silently */
+ }
+
+#elif defined(GC_LINUX_THREADS) /* && !PLATFORM_ANDROID && !NACL */
+ /* Return the number of processors. */
+ STATIC int GC_get_nprocs(void)
+ {
+ /* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that */
+ /* appears to be buggy in many cases. */
+ /* We look for lines "cpu<n>" in /proc/stat. */
+ char stat_buf[STAT_BUF_SIZE];
+ int f;
+ int result, i, len;
+
+ f = open("/proc/stat", O_RDONLY);
+ if (f < 0) {
+ WARN("Couldn't read /proc/stat\n", 0);
+ return 1; /* assume an uniprocessor */
+ }
+ len = STAT_READ(f, stat_buf, STAT_BUF_SIZE);
+ close(f);
+
+ result = 1;
+ /* Some old kernels only have a single "cpu nnnn ..." */
+ /* entry in /proc/stat. We identify those as */
+ /* uniprocessors. */
+
+ for (i = 0; i < len - 100; ++i) {
+ if (stat_buf[i] == '\n' && stat_buf[i+1] == 'c'
+ && stat_buf[i+2] == 'p' && stat_buf[i+3] == 'u') {
+ int cpu_no = atoi(&stat_buf[i + 4]);
+ if (cpu_no >= result)
+ result = cpu_no + 1;
+ }
+ }
+ return result;
+ }
+
+#elif defined(GC_DGUX386_THREADS)
+ /* Return the number of processors, or i <= 0 if it can't be determined. */
+ STATIC int GC_get_nprocs(void)
+ {
+ int numCpus;
+ struct dg_sys_info_pm_info pm_sysinfo;
+ int status = 0;
+
+ status = dg_sys_info((long int *) &pm_sysinfo,
+ DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_CURRENT_VERSION);
+ if (status < 0)
+ /* set -1 for error */
+ numCpus = -1;
+ else
+ /* Active CPUs */
+ numCpus = pm_sysinfo.idle_vp_count;
+ return(numCpus);
+ }
+
+#elif defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) \
+ || defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS)
+ STATIC int GC_get_nprocs(void)
+ {
+ int mib[] = {CTL_HW,HW_NCPU};
+ int res;
+ size_t len = sizeof(res);
+
+ sysctl(mib, sizeof(mib)/sizeof(int), &res, &len, NULL, 0);
+ return res;
+ }
+
+#else
+ /* E.g., GC_RTEMS_PTHREADS */
+# define GC_get_nprocs() 1 /* not implemented */
+#endif /* !GC_LINUX_THREADS && !GC_DARWIN_THREADS && ... */
+
+#if defined(ARM32) && defined(GC_LINUX_THREADS) && !defined(NACL)
+ /* Some buggy Linux/arm kernels show only non-sleeping CPUs in */
+ /* /proc/stat (and /proc/cpuinfo), so another data system source is */
+ /* tried first. Result <= 0 on error. */
+ STATIC int GC_get_nprocs_present(void)
+ {
+ char stat_buf[16];
+ int f;
+ int len;
+
+ f = open("/sys/devices/system/cpu/present", O_RDONLY);
+ if (f < 0)
+ return -1; /* cannot open the file */
+
+ len = STAT_READ(f, stat_buf, sizeof(stat_buf));
+ close(f);
+
+ /* Recognized file format: "0\n" or "0-<max_cpu_id>\n" */
+ /* The file might probably contain a comma-separated list */
+ /* but we do not need to handle it (just silently ignore). */
+ if (len < 2 || stat_buf[0] != '0' || stat_buf[len - 1] != '\n') {
+ return 0; /* read error or unrecognized content */
+ } else if (len == 2) {
+ return 1; /* an uniprocessor */
+ } else if (stat_buf[1] != '-') {
+ return 0; /* unrecognized content */
+ }
+
+ stat_buf[len - 1] = '\0'; /* terminate the string */
+ return atoi(&stat_buf[2]) + 1; /* skip "0-" and parse max_cpu_num */
+ }
+#endif /* ARM32 && GC_LINUX_THREADS && !NACL */
+
+/* We hold the GC lock. Wait until an in-progress GC has finished. */
+/* Repeatedly RELEASES GC LOCK in order to wait. */
+/* If wait_for_all is true, then we exit with the GC lock held and no */
+/* collection in progress; otherwise we just wait for the current GC */
+/* to finish. */
+STATIC void GC_wait_for_gc_completion(GC_bool wait_for_all)
+{
+ DCL_LOCK_STATE;
+ GC_ASSERT(I_HOLD_LOCK());
+ ASSERT_CANCEL_DISABLED();
+ if (GC_incremental && GC_collection_in_progress()) {
+ word old_gc_no = GC_gc_no;
+
+ /* Make sure that no part of our stack is still on the mark stack, */
+ /* since it's about to be unmapped. */
+ while (GC_incremental && GC_collection_in_progress()
+ && (wait_for_all || old_gc_no == GC_gc_no)) {
+ ENTER_GC();
+ GC_in_thread_creation = TRUE;
+ GC_collect_a_little_inner(1);
+ GC_in_thread_creation = FALSE;
+ EXIT_GC();
+ UNLOCK();
+ sched_yield();
+ LOCK();
+ }
+ }
+}
+
+#ifdef CAN_HANDLE_FORK
+/* Procedures called before and after a fork. The goal here is to make */
+/* it safe to call GC_malloc() in a forked child. It's unclear that is */
+/* attainable, since the single UNIX spec seems to imply that one */
+/* should only call async-signal-safe functions, and we probably can't */
+/* quite guarantee that. But we give it our best shot. (That same */
+/* spec also implies that it's not safe to call the system malloc */
+/* between fork() and exec(). Thus we're doing no worse than it.) */
+
+IF_CANCEL(static int fork_cancel_state;)
+ /* protected by allocation lock. */
+
+/* Called before a fork() */
+static void fork_prepare_proc(void)
+{
+ /* Acquire all relevant locks, so that after releasing the locks */
+ /* the child will see a consistent state in which monitor */
+ /* invariants hold. Unfortunately, we can't acquire libc locks */
+ /* we might need, and there seems to be no guarantee that libc */
+ /* must install a suitable fork handler. */
+ /* Wait for an ongoing GC to finish, since we can't finish it in */
+ /* the (one remaining thread in) the child. */
+ LOCK();
+ DISABLE_CANCEL(fork_cancel_state);
+ /* Following waits may include cancellation points. */
+# if defined(PARALLEL_MARK)
+ if (GC_parallel)
+ GC_wait_for_reclaim();
+# endif
+ GC_wait_for_gc_completion(TRUE);
+# if defined(PARALLEL_MARK)
+ if (GC_parallel)
+ GC_acquire_mark_lock();
+# endif
+}
+
+/* Called in parent after a fork() (even if the latter failed). */
+static void fork_parent_proc(void)
+{
+# if defined(PARALLEL_MARK)
+ if (GC_parallel)
+ GC_release_mark_lock();
+# endif
+ RESTORE_CANCEL(fork_cancel_state);
+ UNLOCK();
+}
+
+/* Called in child after a fork() */
+static void fork_child_proc(void)
+{
+ /* Clean up the thread table, so that just our thread is left. */
+# if defined(PARALLEL_MARK)
+ if (GC_parallel)
+ GC_release_mark_lock();
+# endif
+ GC_remove_all_threads_but_me();
+# ifdef PARALLEL_MARK
+ /* Turn off parallel marking in the child, since we are probably */
+ /* just going to exec, and we would have to restart mark threads. */
+ GC_parallel = FALSE;
+# endif /* PARALLEL_MARK */
+ RESTORE_CANCEL(fork_cancel_state);
+ UNLOCK();
+}
+
+ /* Routines for fork handling by client (no-op if pthread_atfork works). */
+ GC_API void GC_CALL GC_atfork_prepare(void)
+ {
+# if defined(GC_DARWIN_THREADS) && defined(MPROTECT_VDB)
+ if (GC_dirty_maintained) {
+ GC_ASSERT(0 == GC_handle_fork);
+ ABORT("Unable to fork while mprotect_thread is running");
+ }
+# endif
+ if (GC_handle_fork <= 0)
+ fork_prepare_proc();
+ }
+
+ GC_API void GC_CALL GC_atfork_parent(void)
+ {
+ if (GC_handle_fork <= 0)
+ fork_parent_proc();
+ }
+
+ GC_API void GC_CALL GC_atfork_child(void)
+ {
+ if (GC_handle_fork <= 0)
+ fork_child_proc();
+ }
+#endif /* CAN_HANDLE_FORK */
+
+#ifdef INCLUDE_LINUX_THREAD_DESCR
+ __thread int GC_dummy_thread_local;
+ GC_INNER GC_bool GC_enclosing_mapping(ptr_t addr,
+ ptr_t *startp, ptr_t *endp);
+#endif
+
+/* We hold the allocation lock. */
+GC_INNER void GC_thr_init(void)
+{
+ if (GC_thr_initialized) return;
+ GC_thr_initialized = TRUE;
+
+ GC_ASSERT((word)&GC_threads % sizeof(word) == 0);
+# ifdef CAN_HANDLE_FORK
+ /* Prepare for forks if requested. */
+ if (GC_handle_fork) {
+# ifdef CAN_CALL_ATFORK
+ if (pthread_atfork(fork_prepare_proc, fork_parent_proc,
+ fork_child_proc) == 0) {
+ /* Handlers successfully registered. */
+ GC_handle_fork = 1;
+ } else
+# endif
+ /* else */ if (GC_handle_fork != -1)
+ ABORT("pthread_atfork failed");
+ }
+# endif
+# ifdef INCLUDE_LINUX_THREAD_DESCR
+ /* Explicitly register the region including the address */
+ /* of a thread local variable. This should include thread */
+ /* locals for the main thread, except for those allocated */
+ /* in response to dlopen calls. */
+ {
+ ptr_t thread_local_addr = (ptr_t)(&GC_dummy_thread_local);
+ ptr_t main_thread_start, main_thread_end;
+ if (!GC_enclosing_mapping(thread_local_addr, &main_thread_start,
+ &main_thread_end)) {
+ ABORT("Failed to find mapping for main thread thread locals");
+ } else {
+ /* main_thread_start and main_thread_end are initialized. */
+ GC_add_roots_inner(main_thread_start, main_thread_end, FALSE);
+ }
+ }
+# endif
+ /* Add the initial thread, so we can stop it. */
+ {
+ GC_thread t = GC_new_thread(pthread_self());
+ if (t == NULL)
+ ABORT("Failed to allocate memory for the initial thread");
+# ifdef GC_DARWIN_THREADS
+ t -> stop_info.mach_thread = mach_thread_self();
+# else
+ t -> stop_info.stack_ptr = GC_approx_sp();
+# endif
+ t -> flags = DETACHED | MAIN_THREAD;
+ }
+
+# ifndef GC_DARWIN_THREADS
+ GC_stop_init();
+# endif
+
+ /* Set GC_nprocs. */
+ {
+ char * nprocs_string = GETENV("GC_NPROCS");
+ GC_nprocs = -1;
+ if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string);
+ }
+ if (GC_nprocs <= 0
+# if defined(ARM32) && defined(GC_LINUX_THREADS) && !defined(NACL)
+ && (GC_nprocs = GC_get_nprocs_present()) <= 1
+ /* Workaround for some Linux/arm kernels */
+# endif
+ )
+ {
+ GC_nprocs = GC_get_nprocs();
+ }
+ if (GC_nprocs <= 0) {
+ WARN("GC_get_nprocs() returned %" WARN_PRIdPTR "\n", GC_nprocs);
+ GC_nprocs = 2; /* assume dual-core */
+# ifdef PARALLEL_MARK
+ available_markers_m1 = 0; /* but use only one marker */
+# endif
+ } else {
+# ifdef PARALLEL_MARK
+ {
+ char * markers_string = GETENV("GC_MARKERS");
+ int markers_m1;
+
+ if (markers_string != NULL) {
+ markers_m1 = atoi(markers_string) - 1;
+ if (markers_m1 >= MAX_MARKERS) {
+ WARN("Limiting number of mark threads\n", 0);
+ markers_m1 = MAX_MARKERS - 1;
+ }
+ } else {
+ markers_m1 = GC_nprocs - 1;
+# ifdef GC_MIN_MARKERS
+ /* This is primarily for targets without getenv(). */
+ if (markers_m1 < GC_MIN_MARKERS - 1)
+ markers_m1 = GC_MIN_MARKERS - 1;
+# endif
+ if (markers_m1 >= MAX_MARKERS)
+ markers_m1 = MAX_MARKERS - 1; /* silently limit the value */
+ }
+ available_markers_m1 = markers_m1;
+ }
+# endif
+ }
+ GC_COND_LOG_PRINTF("Number of processors = %d\n", GC_nprocs);
+# ifdef PARALLEL_MARK
+ if (available_markers_m1 <= 0) {
+ /* Disable parallel marking. */
+ GC_parallel = FALSE;
+ GC_COND_LOG_PRINTF(
+ "Single marker thread, turning off parallel marking\n");
+ } else {
+ /* Disable true incremental collection, but generational is OK. */
+ GC_time_limit = GC_TIME_UNLIMITED;
+ /* If we are using a parallel marker, actually start helper threads. */
+ start_mark_threads();
+ }
+# endif
+}
+
+/* Perform all initializations, including those that */
+/* may require allocation. */
+/* Called without allocation lock. */
+/* Must be called before a second thread is created. */
+/* Did we say it's called without the allocation lock? */
+GC_INNER void GC_init_parallel(void)
+{
+# if defined(THREAD_LOCAL_ALLOC)
+ DCL_LOCK_STATE;
+# endif
+ if (parallel_initialized) return;
+ parallel_initialized = TRUE;
+
+ /* GC_init() calls us back, so set flag first. */
+ if (!GC_is_initialized) GC_init();
+ /* Initialize thread local free lists if used. */
+# if defined(THREAD_LOCAL_ALLOC)
+ LOCK();
+ GC_init_thread_local(&(GC_lookup_thread(pthread_self())->tlfs));
+ UNLOCK();
+# endif
+}
+
+#ifndef GC_NO_PTHREAD_SIGMASK
+ GC_API int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set,
+ sigset_t *oset)
+ {
+ sigset_t fudged_set;
+ int sig_suspend;
+
+ INIT_REAL_SYMS();
+ if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
+ fudged_set = *set;
+ sig_suspend = GC_get_suspend_signal();
+ GC_ASSERT(sig_suspend >= 0);
+ sigdelset(&fudged_set, sig_suspend);
+ set = &fudged_set;
+ }
+ return(REAL_FUNC(pthread_sigmask)(how, set, oset));
+ }
+#endif /* !GC_NO_PTHREAD_SIGMASK */
+
+/* Wrapper for functions that are likely to block for an appreciable */
+/* length of time. */
+
+GC_INNER void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
+{
+ struct blocking_data * d = (struct blocking_data *) data;
+ pthread_t self = pthread_self();
+ GC_thread me;
+# if defined(SPARC) || defined(IA64)
+ ptr_t stack_ptr = GC_save_regs_in_stack();
+# endif
+# if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
+ GC_bool topOfStackUnset = FALSE;
+# endif
+ DCL_LOCK_STATE;
+
+ LOCK();
+ me = GC_lookup_thread(self);
+ GC_ASSERT(!(me -> thread_blocked));
+# ifdef SPARC
+ me -> stop_info.stack_ptr = stack_ptr;
+# else
+ me -> stop_info.stack_ptr = GC_approx_sp();
+# endif
+# if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
+ if (me -> topOfStack == NULL) {
+ /* GC_do_blocking_inner is not called recursively, */
+ /* so topOfStack should be computed now. */
+ topOfStackUnset = TRUE;
+ me -> topOfStack = GC_FindTopOfStack(0);
+ }
+# endif
+# ifdef IA64
+ me -> backing_store_ptr = stack_ptr;
+# endif
+ me -> thread_blocked = (unsigned char)TRUE;
+ /* Save context here if we want to support precise stack marking */
+ UNLOCK();
+ d -> client_data = (d -> fn)(d -> client_data);
+ LOCK(); /* This will block if the world is stopped. */
+ me -> thread_blocked = FALSE;
+# if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
+ if (topOfStackUnset)
+ me -> topOfStack = NULL; /* make topOfStack unset again */
+# endif
+ UNLOCK();
+}
+
+/* GC_call_with_gc_active() has the opposite to GC_do_blocking() */
+/* functionality. It might be called from a user function invoked by */
+/* GC_do_blocking() to temporarily back allow calling any GC function */
+/* and/or manipulating pointers to the garbage collected heap. */
+GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
+ void * client_data)
+{
+ struct GC_traced_stack_sect_s stacksect;
+ pthread_t self = pthread_self();
+ GC_thread me;
+ DCL_LOCK_STATE;
+
+ LOCK(); /* This will block if the world is stopped. */
+ me = GC_lookup_thread(self);
+
+ /* Adjust our stack base value (this could happen unless */
+ /* GC_get_stack_base() was used which returned GC_SUCCESS). */
+ if ((me -> flags & MAIN_THREAD) == 0) {
+ GC_ASSERT(me -> stack_end != NULL);
+ if ((word)me->stack_end HOTTER_THAN (word)(&stacksect))
+ me -> stack_end = (ptr_t)(&stacksect);
+ } else {
+ /* The original stack. */
+ if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect))
+ GC_stackbottom = (ptr_t)(&stacksect);
+ }
+
+ if (!me->thread_blocked) {
+ /* We are not inside GC_do_blocking() - do nothing more. */
+ UNLOCK();
+ return fn(client_data);
+ }
+
+ /* Setup new "stack section". */
+ stacksect.saved_stack_ptr = me -> stop_info.stack_ptr;
+# ifdef IA64
+ /* This is the same as in GC_call_with_stack_base(). */
+ stacksect.backing_store_end = GC_save_regs_in_stack();
+ /* Unnecessarily flushes register stack, */
+ /* but that probably doesn't hurt. */
+ stacksect.saved_backing_store_ptr = me -> backing_store_ptr;
+# endif
+ stacksect.prev = me -> traced_stack_sect;
+ me -> thread_blocked = FALSE;
+ me -> traced_stack_sect = &stacksect;
+
+ UNLOCK();
+ client_data = fn(client_data);
+ GC_ASSERT(me -> thread_blocked == FALSE);
+ GC_ASSERT(me -> traced_stack_sect == &stacksect);
+
+ /* Restore original "stack section". */
+ LOCK();
+ me -> traced_stack_sect = stacksect.prev;
+# ifdef IA64
+ me -> backing_store_ptr = stacksect.saved_backing_store_ptr;
+# endif
+ me -> thread_blocked = (unsigned char)TRUE;
+ me -> stop_info.stack_ptr = stacksect.saved_stack_ptr;
+ UNLOCK();
+
+ return client_data; /* result */
+}
+
+STATIC void GC_unregister_my_thread_inner(GC_thread me)
+{
+# ifdef DEBUG_THREADS
+ GC_log_printf(
+ "Unregistering thread %p, gc_thread = %p, n_threads = %d\n",
+ (void *)me->id, me, GC_count_threads());
+# endif
+ GC_ASSERT(!(me -> flags & FINISHED));
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
+ GC_destroy_thread_local(&(me->tlfs));
+# endif
+# if defined(GC_PTHREAD_EXIT_ATTRIBUTE) || !defined(GC_NO_PTHREAD_CANCEL)
+ /* Handle DISABLED_GC flag which is set by the */
+ /* intercepted pthread_cancel or pthread_exit. */
+ if ((me -> flags & DISABLED_GC) != 0) {
+ GC_dont_gc--;
+ }
+# endif
+ if (me -> flags & DETACHED) {
+ GC_delete_thread(pthread_self());
+ } else {
+ me -> flags |= FINISHED;
+ }
+# if defined(THREAD_LOCAL_ALLOC)
+ /* It is required to call remove_specific defined in specific.c. */
+ GC_remove_specific(GC_thread_key);
+# endif
+}
+
+GC_API int GC_CALL GC_unregister_my_thread(void)
+{
+ pthread_t self = pthread_self();
+ GC_thread me;
+ IF_CANCEL(int cancel_state;)
+ DCL_LOCK_STATE;
+
+ LOCK();
+ DISABLE_CANCEL(cancel_state);
+ /* Wait for any GC that may be marking from our stack to */
+ /* complete before we remove this thread. */
+ GC_wait_for_gc_completion(FALSE);
+ me = GC_lookup_thread(self);
+# ifdef DEBUG_THREADS
+ GC_log_printf(
+ "Called GC_unregister_my_thread on %p, gc_thread = %p\n",
+ (void *)self, me);
+# endif
+ GC_ASSERT(me->id == self);
+ GC_unregister_my_thread_inner(me);
+ RESTORE_CANCEL(cancel_state);
+ UNLOCK();
+ return GC_SUCCESS;
+}
+
+/* Called at thread exit. */
+/* Never called for main thread. That's OK, since it */
+/* results in at most a tiny one-time leak. And */
+/* linuxthreads doesn't reclaim the main threads */
+/* resources or id anyway. */
+GC_INNER void GC_thread_exit_proc(void *arg)
+{
+# ifdef DEBUG_THREADS
+ GC_log_printf("Called GC_thread_exit_proc on %p, gc_thread = %p\n",
+ (void *)((GC_thread)arg)->id, arg);
+# endif
+ IF_CANCEL(int cancel_state;)
+ DCL_LOCK_STATE;
+
+ LOCK();
+ DISABLE_CANCEL(cancel_state);
+ GC_wait_for_gc_completion(FALSE);
+ GC_unregister_my_thread_inner((GC_thread)arg);
+ RESTORE_CANCEL(cancel_state);
+ UNLOCK();
+}
+
+GC_API int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
+{
+ int result;
+ GC_thread t;
+ DCL_LOCK_STATE;
+
+ INIT_REAL_SYMS();
+ LOCK();
+ t = GC_lookup_thread(thread);
+ /* This is guaranteed to be the intended one, since the thread id */
+ /* can't have been recycled by pthreads. */
+ UNLOCK();
+ result = REAL_FUNC(pthread_join)(thread, retval);
+# if defined(GC_FREEBSD_THREADS)
+ /* On FreeBSD, the wrapped pthread_join() sometimes returns (what
+ appears to be) a spurious EINTR which caused the test and real code
+ to gratuitously fail. Having looked at system pthread library source
+ code, I see how this return code may be generated. In one path of
+ code, pthread_join() just returns the errno setting of the thread
+ being joined. This does not match the POSIX specification or the
+ local man pages thus I have taken the liberty to catch this one
+ spurious return value properly conditionalized on GC_FREEBSD_THREADS. */
+ if (result == EINTR) result = 0;
+# endif
+ if (result == 0) {
+ LOCK();
+ /* Here the pthread thread id may have been recycled. */
+ GC_ASSERT((t -> flags & FINISHED) != 0);
+ GC_delete_gc_thread(t);
+ UNLOCK();
+ }
+ return result;
+}
+
+GC_API int WRAP_FUNC(pthread_detach)(pthread_t thread)
+{
+ int result;
+ GC_thread t;
+ DCL_LOCK_STATE;
+
+ INIT_REAL_SYMS();
+ LOCK();
+ t = GC_lookup_thread(thread);
+ UNLOCK();
+ result = REAL_FUNC(pthread_detach)(thread);
+ if (result == 0) {
+ LOCK();
+ t -> flags |= DETACHED;
+ /* Here the pthread thread id may have been recycled. */
+ if ((t -> flags & FINISHED) != 0) {
+ GC_delete_gc_thread(t);
+ }
+ UNLOCK();
+ }
+ return result;
+}
+
+#ifndef GC_NO_PTHREAD_CANCEL
+ /* We should deal with the fact that apparently on Solaris and, */
+ /* probably, on some Linux we can't collect while a thread is */
+ /* exiting, since signals aren't handled properly. This currently */
+ /* gives rise to deadlocks. The only workaround seen is to intercept */
+ /* pthread_cancel() and pthread_exit(), and disable the collections */
+ /* until the thread exit handler is called. That's ugly, because we */
+ /* risk growing the heap unnecessarily. But it seems that we don't */
+ /* really have an option in that the process is not in a fully */
+ /* functional state while a thread is exiting. */
+ GC_API int WRAP_FUNC(pthread_cancel)(pthread_t thread)
+ {
+# ifdef CANCEL_SAFE
+ GC_thread t;
+ DCL_LOCK_STATE;
+# endif
+
+ INIT_REAL_SYMS();
+# ifdef CANCEL_SAFE
+ LOCK();
+ t = GC_lookup_thread(thread);
+ /* We test DISABLED_GC because pthread_exit could be called at */
+ /* the same time. (If t is NULL then pthread_cancel should */
+ /* return ESRCH.) */
+ if (t != NULL && (t -> flags & DISABLED_GC) == 0) {
+ t -> flags |= DISABLED_GC;
+ GC_dont_gc++;
+ }
+ UNLOCK();
+# endif
+ return REAL_FUNC(pthread_cancel)(thread);
+ }
+#endif /* !GC_NO_PTHREAD_CANCEL */
+
+#ifdef GC_PTHREAD_EXIT_ATTRIBUTE
+ GC_API GC_PTHREAD_EXIT_ATTRIBUTE void WRAP_FUNC(pthread_exit)(void *retval)
+ {
+ pthread_t self = pthread_self();
+ GC_thread me;
+ DCL_LOCK_STATE;
+
+ INIT_REAL_SYMS();
+ LOCK();
+ me = GC_lookup_thread(self);
+ /* We test DISABLED_GC because someone else could call */
+ /* pthread_cancel at the same time. */
+ if (me != 0 && (me -> flags & DISABLED_GC) == 0) {
+ me -> flags |= DISABLED_GC;
+ GC_dont_gc++;
+ }
+ UNLOCK();
+
+# ifdef NACL
+ /* Native Client doesn't support pthread cleanup functions, */
+ /* so cleanup the thread here. */
+ GC_thread_exit_proc(0);
+# endif
+
+ REAL_FUNC(pthread_exit)(retval);
+ }
+#endif /* GC_PTHREAD_EXIT_ATTRIBUTE */
+
+GC_INNER GC_bool GC_in_thread_creation = FALSE;
+ /* Protected by allocation lock. */
+
+GC_INLINE void GC_record_stack_base(GC_thread me,
+ const struct GC_stack_base *sb)
+{
+# ifndef GC_DARWIN_THREADS
+ me -> stop_info.stack_ptr = sb -> mem_base;
+# endif
+ me -> stack_end = sb -> mem_base;
+ if (me -> stack_end == NULL)
+ ABORT("Bad stack base in GC_register_my_thread");
+# ifdef IA64
+ me -> backing_store_end = sb -> reg_base;
+# endif
+}
+
+STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
+ pthread_t my_pthread)
+{
+ GC_thread me;
+
+ GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
+ me = GC_new_thread(my_pthread);
+ GC_in_thread_creation = FALSE;
+ if (me == 0)
+ ABORT("Failed to allocate memory for thread registering");
+# ifdef GC_DARWIN_THREADS
+ me -> stop_info.mach_thread = mach_thread_self();
+# endif
+ GC_record_stack_base(me, sb);
+# ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+ /* Since this could be executed from a detached thread */
+ /* destructor, our signals might already be blocked. */
+ GC_unblock_gc_signals();
+# endif
+ return me;
+}
+
+GC_API void GC_CALL GC_allow_register_threads(void)
+{
+ /* Check GC is initialized and the current thread is registered. */
+ GC_ASSERT(GC_lookup_thread(pthread_self()) != 0);
+
+ GC_need_to_lock = TRUE; /* We are multi-threaded now. */
+}
+
+GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
+{
+ pthread_t self = pthread_self();
+ GC_thread me;
+ DCL_LOCK_STATE;
+
+ if (GC_need_to_lock == FALSE)
+ ABORT("Threads explicit registering is not previously enabled");
+
+ LOCK();
+ me = GC_lookup_thread(self);
+ if (0 == me) {
+ me = GC_register_my_thread_inner(sb, self);
+ me -> flags |= DETACHED;
+ /* Treat as detached, since we do not need to worry about */
+ /* pointer results. */
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_init_thread_local(&(me->tlfs));
+# endif
+ UNLOCK();
+ return GC_SUCCESS;
+ } else if ((me -> flags & FINISHED) != 0) {
+ /* This code is executed when a thread is registered from the */
+ /* client thread key destructor. */
+ GC_record_stack_base(me, sb);
+ me -> flags &= ~FINISHED; /* but not DETACHED */
+# ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
+ /* Since this could be executed from a thread destructor, */
+ /* our signals might be blocked. */
+ GC_unblock_gc_signals();
+# endif
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_init_thread_local(&(me->tlfs));
+# endif
+ UNLOCK();
+ return GC_SUCCESS;
+ } else {
+ UNLOCK();
+ return GC_DUPLICATE;
+ }
+}
+
+struct start_info {
+ void *(*start_routine)(void *);
+ void *arg;
+ word flags;
+ sem_t registered; /* 1 ==> in our thread table, but */
+ /* parent hasn't yet noticed. */
+};
+
+/* Called from GC_inner_start_routine(). Defined in this file to */
+/* minimize the number of include files in pthread_start.c (because */
+/* sem_t and sem_post() are not used that file directly). */
+GC_INNER GC_thread GC_start_rtn_prepare_thread(void *(**pstart)(void *),
+ void **pstart_arg,
+ struct GC_stack_base *sb, void *arg)
+{
+ struct start_info * si = arg;
+ pthread_t self = pthread_self();
+ GC_thread me;
+ DCL_LOCK_STATE;
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("Starting thread %p, pid = %ld, sp = %p\n",
+ (void *)self, (long)getpid(), &arg);
+# endif
+ LOCK();
+ me = GC_register_my_thread_inner(sb, self);
+ me -> flags = si -> flags;
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_init_thread_local(&(me->tlfs));
+# endif
+ UNLOCK();
+ *pstart = si -> start_routine;
+# ifdef DEBUG_THREADS
+ GC_log_printf("start_routine = %p\n", (void *)(signed_word)(*pstart));
+# endif
+ *pstart_arg = si -> arg;
+ sem_post(&(si -> registered)); /* Last action on si. */
+ /* OK to deallocate. */
+ return me;
+}
+
+void * GC_CALLBACK GC_inner_start_routine(struct GC_stack_base *sb, void *arg);
+ /* defined in pthread_start.c */
+
+STATIC void * GC_start_routine(void * arg)
+{
+# ifdef INCLUDE_LINUX_THREAD_DESCR
+ struct GC_stack_base sb;
+
+# ifdef REDIRECT_MALLOC
+ /* GC_get_stack_base may call pthread_getattr_np, which can */
+ /* unfortunately call realloc, which may allocate from an */
+ /* unregistered thread. This is unpleasant, since it might */
+ /* force heap growth (or, even, heap overflow). */
+ GC_disable();
+# endif
+ if (GC_get_stack_base(&sb) != GC_SUCCESS)
+ ABORT("Failed to get thread stack base");
+# ifdef REDIRECT_MALLOC
+ GC_enable();
+# endif
+ return GC_inner_start_routine(&sb, arg);
+# else
+ return GC_call_with_stack_base(GC_inner_start_routine, arg);
+# endif
+}
+
+GC_API int WRAP_FUNC(pthread_create)(pthread_t *new_thread,
+ GC_PTHREAD_CREATE_CONST pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg)
+{
+ int result;
+ int detachstate;
+ word my_flags = 0;
+ struct start_info * si;
+ DCL_LOCK_STATE;
+ /* This is otherwise saved only in an area mmapped by the thread */
+ /* library, which isn't visible to the collector. */
+
+ /* We resist the temptation to muck with the stack size here, */
+ /* even if the default is unreasonably small. That's the client's */
+ /* responsibility. */
+
+ INIT_REAL_SYMS();
+ LOCK();
+ si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
+ NORMAL);
+ UNLOCK();
+ if (!EXPECT(parallel_initialized, TRUE))
+ GC_init_parallel();
+ if (EXPECT(0 == si, FALSE) &&
+ (si = (struct start_info *)
+ (*GC_get_oom_fn())(sizeof(struct start_info))) == 0)
+ return(ENOMEM);
+ if (sem_init(&(si -> registered), GC_SEM_INIT_PSHARED, 0) != 0)
+ ABORT("sem_init failed");
+
+ si -> start_routine = start_routine;
+ si -> arg = arg;
+ LOCK();
+ if (!EXPECT(GC_thr_initialized, TRUE))
+ GC_thr_init();
+# ifdef GC_ASSERTIONS
+ {
+ size_t stack_size = 0;
+ if (NULL != attr) {
+ pthread_attr_getstacksize(attr, &stack_size);
+ }
+ if (0 == stack_size) {
+ pthread_attr_t my_attr;
+
+ pthread_attr_init(&my_attr);
+ pthread_attr_getstacksize(&my_attr, &stack_size);
+ pthread_attr_destroy(&my_attr);
+ }
+ /* On Solaris 10, with default attr initialization, */
+ /* stack_size remains 0. Fudge it. */
+ if (0 == stack_size) {
+# ifndef SOLARIS
+ WARN("Failed to get stack size for assertion checking\n", 0);
+# endif
+ stack_size = 1000000;
+ }
+# ifdef PARALLEL_MARK
+ GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
+# else
+ /* FreeBSD-5.3/Alpha: default pthread stack is 64K, */
+ /* HBLKSIZE=8192, sizeof(word)=8 */
+ GC_ASSERT(stack_size >= 65536);
+# endif
+ /* Our threads may need to do some work for the GC. */
+ /* Ridiculously small threads won't work, and they */
+ /* probably wouldn't work anyway. */
+ }
+# endif
+ if (NULL == attr) {
+ detachstate = PTHREAD_CREATE_JOINABLE;
+ } else {
+ pthread_attr_getdetachstate(attr, &detachstate);
+ }
+ if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
+ si -> flags = my_flags;
+ UNLOCK();
+# ifdef DEBUG_THREADS
+ GC_log_printf("About to start new thread from thread %p\n",
+ (void *)pthread_self());
+# endif
+ GC_need_to_lock = TRUE;
+
+ result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
+
+ /* Wait until child has been added to the thread table. */
+ /* This also ensures that we hold onto si until the child is done */
+ /* with it. Thus it doesn't matter whether it is otherwise */
+ /* visible to the collector. */
+ if (0 == result) {
+ IF_CANCEL(int cancel_state;)
+
+# ifdef DEBUG_THREADS
+ if (new_thread)
+ GC_log_printf("Started thread %p\n", (void *)(*new_thread));
+# endif
+ DISABLE_CANCEL(cancel_state);
+ /* pthread_create is not a cancellation point. */
+ while (0 != sem_wait(&(si -> registered))) {
+ if (EINTR != errno) ABORT("sem_wait failed");
+ }
+ RESTORE_CANCEL(cancel_state);
+ }
+ sem_destroy(&(si -> registered));
+ LOCK();
+ GC_INTERNAL_FREE(si);
+ UNLOCK();
+
+ return(result);
+}
+
+#if defined(USE_SPIN_LOCK) || !defined(NO_PTHREAD_TRYLOCK)
+/* Spend a few cycles in a way that can't introduce contention with */
+/* other threads. */
+STATIC void GC_pause(void)
+{
+ int i;
+# if !defined(__GNUC__) || defined(__INTEL_COMPILER)
+ volatile word dummy = 0;
+# endif
+
+ for (i = 0; i < 10; ++i) {
+# if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+ __asm__ __volatile__ (" " : : : "memory");
+# else
+ /* Something that's unlikely to be optimized away. */
+ GC_noop1(++dummy);
+# endif
+ }
+}
+#endif
+
+#define SPIN_MAX 128 /* Maximum number of calls to GC_pause before */
+ /* give up. */
+
+GC_INNER volatile GC_bool GC_collecting = 0;
+ /* A hint that we're in the collector and */
+ /* holding the allocation lock for an */
+ /* extended period. */
+
+#if (!defined(USE_SPIN_LOCK) && !defined(NO_PTHREAD_TRYLOCK)) \
+ || defined(PARALLEL_MARK)
+/* If we don't want to use the below spinlock implementation, either */
+/* because we don't have a GC_test_and_set implementation, or because */
+/* we don't want to risk sleeping, we can still try spinning on */
+/* pthread_mutex_trylock for a while. This appears to be very */
+/* beneficial in many cases. */
+/* I suspect that under high contention this is nearly always better */
+/* than the spin lock. But it's a bit slower on a uniprocessor. */
+/* Hence we still default to the spin lock. */
+/* This is also used to acquire the mark lock for the parallel */
+/* marker. */
+
+/* Here we use a strict exponential backoff scheme. I don't know */
+/* whether that's better or worse than the above. We eventually */
+/* yield by calling pthread_mutex_lock(); it never makes sense to */
+/* explicitly sleep. */
+
+/* #define LOCK_STATS */
+/* Note that LOCK_STATS requires AO_HAVE_test_and_set. */
+#ifdef LOCK_STATS
+ volatile AO_t GC_spin_count = 0;
+ volatile AO_t GC_block_count = 0;
+ volatile AO_t GC_unlocked_count = 0;
+#endif
+
+STATIC void GC_generic_lock(pthread_mutex_t * lock)
+{
+#ifndef NO_PTHREAD_TRYLOCK
+ unsigned pause_length = 1;
+ unsigned i;
+
+ if (0 == pthread_mutex_trylock(lock)) {
+# ifdef LOCK_STATS
+ (void)AO_fetch_and_add1(&GC_unlocked_count);
+# endif
+ return;
+ }
+ for (; pause_length <= SPIN_MAX; pause_length <<= 1) {
+ for (i = 0; i < pause_length; ++i) {
+ GC_pause();
+ }
+ switch(pthread_mutex_trylock(lock)) {
+ case 0:
+# ifdef LOCK_STATS
+ (void)AO_fetch_and_add1(&GC_spin_count);
+# endif
+ return;
+ case EBUSY:
+ break;
+ default:
+ ABORT("Unexpected error from pthread_mutex_trylock");
+ }
+ }
+#endif /* !NO_PTHREAD_TRYLOCK */
+# ifdef LOCK_STATS
+ (void)AO_fetch_and_add1(&GC_block_count);
+# endif
+ pthread_mutex_lock(lock);
+}
+
+#endif /* !USE_SPIN_LOCK || ... */
+
+#if defined(USE_SPIN_LOCK)
+
+/* Reasonably fast spin locks. Basically the same implementation */
+/* as STL alloc.h. This isn't really the right way to do this. */
+/* but until the POSIX scheduling mess gets straightened out ... */
+
+GC_INNER volatile AO_TS_t GC_allocate_lock = AO_TS_INITIALIZER;
+
+GC_INNER void GC_lock(void)
+{
+# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
+# define high_spin_max SPIN_MAX /* spin cycles for multiprocessor */
+ static unsigned spin_max = low_spin_max;
+ unsigned my_spin_max;
+ static unsigned last_spins = 0;
+ unsigned my_last_spins;
+ unsigned i;
+
+ if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
+ return;
+ }
+ my_spin_max = spin_max;
+ my_last_spins = last_spins;
+ for (i = 0; i < my_spin_max; i++) {
+ if (GC_collecting || GC_nprocs == 1) goto yield;
+ if (i < my_last_spins/2) {
+ GC_pause();
+ continue;
+ }
+ if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
+ /*
+ * got it!
+ * Spinning worked. Thus we're probably not being scheduled
+ * against the other process with which we were contending.
+ * Thus it makes sense to spin longer the next time.
+ */
+ last_spins = i;
+ spin_max = high_spin_max;
+ return;
+ }
+ }
+ /* We are probably being scheduled against the other process. Sleep. */
+ spin_max = low_spin_max;
+yield:
+ for (i = 0;; ++i) {
+ if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
+ return;
+ }
+# define SLEEP_THRESHOLD 12
+ /* Under Linux very short sleeps tend to wait until */
+ /* the current time quantum expires. On old Linux */
+ /* kernels nanosleep(<= 2ms) just spins under Linux. */
+ /* (Under 2.4, this happens only for real-time */
+ /* processes.) We want to minimize both behaviors */
+ /* here. */
+ if (i < SLEEP_THRESHOLD) {
+ sched_yield();
+ } else {
+ struct timespec ts;
+
+ if (i > 24) i = 24;
+ /* Don't wait for more than about 15msecs, even */
+ /* under extreme contention. */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1 << i;
+ nanosleep(&ts, 0);
+ }
+ }
+}
+
+#else /* !USE_SPIN_LOCK */
+GC_INNER void GC_lock(void)
+{
+#ifndef NO_PTHREAD_TRYLOCK
+ if (1 == GC_nprocs || GC_collecting) {
+ pthread_mutex_lock(&GC_allocate_ml);
+ } else {
+ GC_generic_lock(&GC_allocate_ml);
+ }
+#else /* !NO_PTHREAD_TRYLOCK */
+ pthread_mutex_lock(&GC_allocate_ml);
+#endif /* !NO_PTHREAD_TRYLOCK */
+}
+
+#endif /* !USE_SPIN_LOCK */
+
+#ifdef PARALLEL_MARK
+
+#ifdef GC_ASSERTIONS
+ GC_INNER unsigned long GC_mark_lock_holder = NO_THREAD;
+#endif
+
+#ifdef GLIBC_2_1_MUTEX_HACK
+ /* Ugly workaround for a linux threads bug in the final versions */
+ /* of glibc2.1. Pthread_mutex_trylock sets the mutex owner */
+ /* field even when it fails to acquire the mutex. This causes */
+ /* pthread_cond_wait to die. Remove for glibc2.2. */
+ /* According to the man page, we should use */
+ /* PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, but that isn't actually */
+ /* defined. */
+ static pthread_mutex_t mark_mutex =
+ {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}};
+#else
+ static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
+
+GC_INNER void GC_acquire_mark_lock(void)
+{
+ GC_generic_lock(&mark_mutex);
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
+# endif
+}
+
+GC_INNER void GC_release_mark_lock(void)
+{
+ GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NO_THREAD;
+# endif
+ if (pthread_mutex_unlock(&mark_mutex) != 0) {
+ ABORT("pthread_mutex_unlock failed");
+ }
+}
+
+/* Collector must wait for a freelist builders for 2 reasons: */
+/* 1) Mark bits may still be getting examined without lock. */
+/* 2) Partial free lists referenced only by locals may not be scanned */
+/* correctly, e.g. if they contain "pointer-free" objects, since the */
+/* free-list link may be ignored. */
+STATIC void GC_wait_builder(void)
+{
+ GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
+ ASSERT_CANCEL_DISABLED();
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NO_THREAD;
+# endif
+ if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
+ ABORT("pthread_cond_wait failed");
+ }
+ GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
+# endif
+}
+
+GC_INNER void GC_wait_for_reclaim(void)
+{
+ GC_acquire_mark_lock();
+ while (GC_fl_builder_count > 0) {
+ GC_wait_builder();
+ }
+ GC_release_mark_lock();
+}
+
+GC_INNER void GC_notify_all_builder(void)
+{
+ GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
+ if (pthread_cond_broadcast(&builder_cv) != 0) {
+ ABORT("pthread_cond_broadcast failed");
+ }
+}
+
+static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
+
+GC_INNER void GC_wait_marker(void)
+{
+ GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
+ ASSERT_CANCEL_DISABLED();
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NO_THREAD;
+# endif
+ if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
+ ABORT("pthread_cond_wait failed");
+ }
+ GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
+# endif
+}
+
+GC_INNER void GC_notify_all_marker(void)
+{
+ if (pthread_cond_broadcast(&mark_cv) != 0) {
+ ABORT("pthread_cond_broadcast failed");
+ }
+}
+
+#endif /* PARALLEL_MARK */
+
+#endif /* GC_PTHREADS */
diff --git a/boehm-gc/ptr_chck.c b/boehm-gc/ptr_chck.c
index d83d730d343..eb1c45697f7 100644
--- a/boehm-gc/ptr_chck.c
+++ b/boehm-gc/ptr_chck.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -11,102 +11,88 @@
* modified is included with the above copyright notice.
*/
+#include "private/gc_pmark.h"
+
/*
* These are checking routines calls to which could be inserted by a
* preprocessor to validate C pointer arithmetic.
*/
-#include "private/gc_pmark.h"
-
-#ifdef __STDC__
-void GC_default_same_obj_print_proc(GC_PTR p, GC_PTR q)
-#else
-void GC_default_same_obj_print_proc (p, q)
-GC_PTR p, q;
-#endif
+STATIC void GC_CALLBACK GC_default_same_obj_print_proc(void * p, void * q)
{
- GC_err_printf2("0x%lx and 0x%lx are not in the same object\n",
- (unsigned long)p, (unsigned long)q);
+ GC_err_printf("%p and %p are not in the same object\n", p, q);
ABORT("GC_same_obj test failed");
}
-void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR, GC_PTR))
- = GC_default_same_obj_print_proc;
+void (GC_CALLBACK *GC_same_obj_print_proc) (void *, void *)
+ = GC_default_same_obj_print_proc;
-/* Check that p and q point to the same object. Call */
-/* *GC_same_obj_print_proc if they don't. */
-/* Returns the first argument. (Return value may be hard */
-/* to use,due to typing issues. But if we had a suitable */
-/* preprocessor ...) */
-/* Succeeds if neither p nor q points to the heap. */
-/* We assume this is performance critical. (It shouldn't */
-/* be called by production code, but this can easily make */
-/* debugging intolerably slow.) */
-#ifdef __STDC__
- GC_PTR GC_same_obj(register void *p, register void *q)
-#else
- GC_PTR GC_same_obj(p, q)
- register char *p, *q;
-#endif
+/* Check that p and q point to the same object. Call */
+/* *GC_same_obj_print_proc if they don't. */
+/* Returns the first argument. (Return value may be hard */
+/* to use,due to typing issues. But if we had a suitable */
+/* preprocessor ...) */
+/* Succeeds if neither p nor q points to the heap. */
+/* We assume this is performance critical. (It shouldn't */
+/* be called by production code, but this can easily make */
+/* debugging intolerably slow.) */
+GC_API void * GC_CALL GC_same_obj(void *p, void *q)
{
- register struct hblk *h;
- register hdr *hhdr;
- register ptr_t base, limit;
- register word sz;
-
- if (!GC_is_initialized) GC_init();
+ struct hblk *h;
+ hdr *hhdr;
+ ptr_t base, limit;
+ word sz;
+
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
hhdr = HDR((word)p);
if (hhdr == 0) {
- if (divHBLKSZ((word)p) != divHBLKSZ((word)q)
- && HDR((word)q) != 0) {
- goto fail;
- }
- return(p);
+ if (divHBLKSZ((word)p) != divHBLKSZ((word)q)
+ && HDR((word)q) != 0) {
+ goto fail;
+ }
+ return(p);
}
- /* If it's a pointer to the middle of a large object, move it */
- /* to the beginning. */
+ /* If it's a pointer to the middle of a large object, move it */
+ /* to the beginning. */
if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
- h = HBLKPTR(p) - (word)hhdr;
- hhdr = HDR(h);
- while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
- h = FORWARDED_ADDR(h, hhdr);
- hhdr = HDR(h);
- }
- limit = (ptr_t)((word *)h + hhdr -> hb_sz);
- if ((ptr_t)p >= limit || (ptr_t)q >= limit || (ptr_t)q < (ptr_t)h ) {
- goto fail;
- }
- return(p);
+ h = HBLKPTR(p) - (word)hhdr;
+ hhdr = HDR(h);
+ while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+ h = FORWARDED_ADDR(h, hhdr);
+ hhdr = HDR(h);
+ }
+ limit = (ptr_t)h + hhdr -> hb_sz;
+ if ((word)p >= (word)limit || (word)q >= (word)limit
+ || (word)q < (word)h) {
+ goto fail;
+ }
+ return(p);
}
- sz = WORDS_TO_BYTES(hhdr -> hb_sz);
+ sz = hhdr -> hb_sz;
if (sz > MAXOBJBYTES) {
base = (ptr_t)HBLKPTR(p);
limit = base + sz;
- if ((ptr_t)p >= limit) {
+ if ((word)p >= (word)limit) {
goto fail;
}
} else {
- register int map_entry;
- register int pdispl = HBLKDISPL(p);
-
- map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
- if (map_entry > CPP_MAX_OFFSET) {
- map_entry = BYTES_TO_WORDS(pdispl) % BYTES_TO_WORDS(sz);
- if (HBLKPTR(p) != HBLKPTR(q)) goto fail;
- /* W/o this check, we might miss an error if */
- /* q points to the first object on a page, and */
- /* points just before the page. */
- }
- base = (char *)((word)p & ~(WORDS_TO_BYTES(1) - 1));
- base -= WORDS_TO_BYTES(map_entry);
+ size_t offset;
+ size_t pdispl = HBLKDISPL(p);
+
+ offset = pdispl % sz;
+ if (HBLKPTR(p) != HBLKPTR(q)) goto fail;
+ /* W/o this check, we might miss an error if */
+ /* q points to the first object on a page, and */
+ /* points just before the page. */
+ base = (ptr_t)p - offset;
limit = base + sz;
}
- /* [base, limit) delimits the object containing p, if any. */
- /* If p is not inside a valid object, then either q is */
- /* also outside any valid object, or it is outside */
- /* [base, limit). */
- if ((ptr_t)q >= limit || (ptr_t)q < base) {
- goto fail;
+ /* [base, limit) delimits the object containing p, if any. */
+ /* If p is not inside a valid object, then either q is */
+ /* also outside any valid object, or it is outside */
+ /* [base, limit). */
+ if ((word)q >= (word)limit || (word)q < (word)base) {
+ goto fail;
}
return(p);
fail:
@@ -114,59 +100,49 @@ fail:
return(p);
}
-#ifdef __STDC__
-void GC_default_is_valid_displacement_print_proc (GC_PTR p)
-#else
-void GC_default_is_valid_displacement_print_proc (p)
-GC_PTR p;
-#endif
+STATIC void GC_CALLBACK GC_default_is_valid_displacement_print_proc (void *p)
{
- GC_err_printf1("0x%lx does not point to valid object displacement\n",
- (unsigned long)p);
+ GC_err_printf("%p does not point to valid object displacement\n", p);
ABORT("GC_is_valid_displacement test failed");
}
-void (*GC_is_valid_displacement_print_proc) GC_PROTO((GC_PTR)) =
- GC_default_is_valid_displacement_print_proc;
+void (GC_CALLBACK *GC_is_valid_displacement_print_proc)(void *) =
+ GC_default_is_valid_displacement_print_proc;
-/* Check that if p is a pointer to a heap page, then it points to */
-/* a valid displacement within a heap object. */
-/* Uninteresting with GC_all_interior_pointers. */
-/* Always returns its argument. */
-/* Note that we don't lock, since nothing relevant about the header */
-/* should change while we have a valid object pointer to the block. */
-#ifdef __STDC__
- void * GC_is_valid_displacement(void *p)
-#else
- char *GC_is_valid_displacement(p)
- char *p;
-#endif
+/* Check that if p is a pointer to a heap page, then it points to */
+/* a valid displacement within a heap object. */
+/* Uninteresting with GC_all_interior_pointers. */
+/* Always returns its argument. */
+/* Note that we don't lock, since nothing relevant about the header */
+/* should change while we have a valid object pointer to the block. */
+GC_API void * GC_CALL GC_is_valid_displacement(void *p)
{
- register hdr *hhdr;
- register word pdispl;
- register struct hblk *h;
- register map_entry_type map_entry;
- register word sz;
-
- if (!GC_is_initialized) GC_init();
+ hdr *hhdr;
+ word pdispl;
+ word offset;
+ struct hblk *h;
+ word sz;
+
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
hhdr = HDR((word)p);
if (hhdr == 0) return(p);
h = HBLKPTR(p);
if (GC_all_interior_pointers) {
- while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
- h = FORWARDED_ADDR(h, hhdr);
- hhdr = HDR(h);
- }
+ while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+ h = FORWARDED_ADDR(h, hhdr);
+ hhdr = HDR(h);
+ }
}
if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
- goto fail;
+ goto fail;
}
- sz = WORDS_TO_BYTES(hhdr -> hb_sz);
+ sz = hhdr -> hb_sz;
pdispl = HBLKDISPL(p);
- map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
- if (map_entry == OBJ_INVALID
- || sz > MAXOBJBYTES && (ptr_t)p >= (ptr_t)h + sz) {
- goto fail;
+ offset = pdispl % sz;
+ if ((sz > MAXOBJBYTES && (word)p >= (word)h + sz)
+ || !GC_valid_offsets[offset]
+ || (word)p - offset + sz > (word)(h + 1)) {
+ goto fail;
}
return(p);
fail:
@@ -174,63 +150,50 @@ fail:
return(p);
}
-#ifdef __STDC__
-void GC_default_is_visible_print_proc(GC_PTR p)
-#else
-void GC_default_is_visible_print_proc(p)
-GC_PTR p;
-#endif
+STATIC void GC_CALLBACK GC_default_is_visible_print_proc(void * p)
{
- GC_err_printf1("0x%lx is not a GC visible pointer location\n",
- (unsigned long)p);
+ GC_err_printf("%p is not a GC visible pointer location\n", p);
ABORT("GC_is_visible test failed");
}
-void (*GC_is_visible_print_proc) GC_PROTO((GC_PTR p)) =
- GC_default_is_visible_print_proc;
+void (GC_CALLBACK *GC_is_visible_print_proc)(void * p) =
+ GC_default_is_visible_print_proc;
+#ifndef THREADS
/* Could p be a stack address? */
-GC_bool GC_on_stack(p)
-ptr_t p;
-{
-# ifdef THREADS
- return(TRUE);
-# else
- int dummy;
-# ifdef STACK_GROWS_DOWN
- if ((ptr_t)p >= (ptr_t)(&dummy) && (ptr_t)p < GC_stackbottom ) {
- return(TRUE);
- }
-# else
- if ((ptr_t)p <= (ptr_t)(&dummy) && (ptr_t)p > GC_stackbottom ) {
- return(TRUE);
- }
-# endif
- return(FALSE);
-# endif
-}
-
-/* Check that p is visible */
-/* to the collector as a possibly pointer containing location. */
-/* If it isn't invoke *GC_is_visible_print_proc. */
-/* Returns the argument in all cases. May erroneously succeed */
-/* in hard cases. (This is intended for debugging use with */
-/* untyped allocations. The idea is that it should be possible, though */
-/* slow, to add such a call to all indirect pointer stores.) */
-/* Currently useless for multithreaded worlds. */
-#ifdef __STDC__
- void * GC_is_visible(void *p)
-#else
- char *GC_is_visible(p)
- char *p;
+ STATIC GC_bool GC_on_stack(ptr_t p)
+ {
+# ifdef STACK_GROWS_DOWN
+ if ((word)p >= (word)GC_approx_sp()
+ && (word)p < (word)GC_stackbottom) {
+ return(TRUE);
+ }
+# else
+ if ((word)p <= (word)GC_approx_sp()
+ && (word)p > (word)GC_stackbottom) {
+ return(TRUE);
+ }
+# endif
+ return(FALSE);
+ }
#endif
+
+/* Check that p is visible */
+/* to the collector as a possibly pointer containing location. */
+/* If it isn't invoke *GC_is_visible_print_proc. */
+/* Returns the argument in all cases. May erroneously succeed */
+/* in hard cases. (This is intended for debugging use with */
+/* untyped allocations. The idea is that it should be possible, though */
+/* slow, to add such a call to all indirect pointer stores.) */
+/* Currently useless for multithreaded worlds. */
+GC_API void * GC_CALL GC_is_visible(void *p)
{
- register hdr *hhdr;
-
+ hdr *hhdr;
+
if ((word)p & (ALIGNMENT - 1)) goto fail;
- if (!GC_is_initialized) GC_init();
+ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
# ifdef THREADS
- hhdr = HDR((word)p);
+ hhdr = HDR((word)p);
if (hhdr != 0 && GC_base(p) == 0) {
goto fail;
} else {
@@ -238,90 +201,79 @@ ptr_t p;
return(p);
}
# else
- /* Check stack first: */
- if (GC_on_stack(p)) return(p);
- hhdr = HDR((word)p);
- if (hhdr == 0) {
- GC_bool result;
-
- if (GC_is_static_root(p)) return(p);
- /* Else do it again correctly: */
-# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || \
- defined(MSWINCE) || defined(PCR)) \
- && !defined(SRC_M3)
- DISABLE_SIGNALS();
- GC_register_dynamic_libraries();
- result = GC_is_static_root(p);
- ENABLE_SIGNALS();
- if (result) return(p);
-# endif
- goto fail;
- } else {
- /* p points to the heap. */
- word descr;
- ptr_t base = GC_base(p); /* Should be manually inlined? */
-
- if (base == 0) goto fail;
- if (HBLKPTR(base) != HBLKPTR(p)) hhdr = HDR((word)p);
- descr = hhdr -> hb_descr;
+ /* Check stack first: */
+ if (GC_on_stack(p)) return(p);
+ hhdr = HDR((word)p);
+ if (hhdr == 0) {
+ if (GC_is_static_root(p)) return(p);
+ /* Else do it again correctly: */
+# if defined(DYNAMIC_LOADING) || defined(MSWIN32) \
+ || defined(MSWINCE) || defined(CYGWIN32) || defined(PCR)
+ GC_register_dynamic_libraries();
+ if (GC_is_static_root(p))
+ return(p);
+# endif
+ goto fail;
+ } else {
+ /* p points to the heap. */
+ word descr;
+ ptr_t base = GC_base(p); /* Should be manually inlined? */
+
+ if (base == 0) goto fail;
+ if (HBLKPTR(base) != HBLKPTR(p)) hhdr = HDR((word)p);
+ descr = hhdr -> hb_descr;
retry:
- switch(descr & GC_DS_TAGS) {
- case GC_DS_LENGTH:
- if ((word)((ptr_t)p - (ptr_t)base) > (word)descr) goto fail;
- break;
- case GC_DS_BITMAP:
- if ((ptr_t)p - (ptr_t)base
- >= WORDS_TO_BYTES(BITMAP_BITS)
- || ((word)p & (sizeof(word) - 1))) goto fail;
- if (!((1 << (WORDSZ - ((ptr_t)p - (ptr_t)base) - 1))
- & descr)) goto fail;
- break;
- case GC_DS_PROC:
- /* We could try to decipher this partially. */
- /* For now we just punt. */
- break;
- case GC_DS_PER_OBJECT:
- if ((signed_word)descr >= 0) {
- descr = *(word *)((ptr_t)base + (descr & ~GC_DS_TAGS));
- } else {
- ptr_t type_descr = *(ptr_t *)base;
- descr = *(word *)(type_descr
- - (descr - (GC_DS_PER_OBJECT
- - GC_INDIR_PER_OBJ_BIAS)));
- }
- goto retry;
- }
- return(p);
- }
+ switch(descr & GC_DS_TAGS) {
+ case GC_DS_LENGTH:
+ if ((word)p - (word)base > descr) goto fail;
+ break;
+ case GC_DS_BITMAP:
+ if ((word)p - (word)base >= WORDS_TO_BYTES(BITMAP_BITS)
+ || ((word)p & (sizeof(word) - 1))) goto fail;
+ if (!(((word)1 << (WORDSZ - ((ptr_t)p - (ptr_t)base) - 1))
+ & descr)) goto fail;
+ break;
+ case GC_DS_PROC:
+ /* We could try to decipher this partially. */
+ /* For now we just punt. */
+ break;
+ case GC_DS_PER_OBJECT:
+ if ((signed_word)descr >= 0) {
+ descr = *(word *)((ptr_t)base + (descr & ~GC_DS_TAGS));
+ } else {
+ ptr_t type_descr = *(ptr_t *)base;
+ descr = *(word *)(type_descr
+ - (descr - (word)(GC_DS_PER_OBJECT
+ - GC_INDIR_PER_OBJ_BIAS)));
+ }
+ goto retry;
+ }
+ return(p);
+ }
# endif
fail:
(*GC_is_visible_print_proc)((ptr_t)p);
return(p);
}
-
-GC_PTR GC_pre_incr (p, how_much)
-GC_PTR *p;
-size_t how_much;
+GC_API void * GC_CALL GC_pre_incr (void **p, ptrdiff_t how_much)
{
- GC_PTR initial = *p;
- GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
-
+ void * initial = *p;
+ void * result = GC_same_obj((void *)((ptr_t)initial + how_much), initial);
+
if (!GC_all_interior_pointers) {
- (void) GC_is_valid_displacement(result);
+ (void) GC_is_valid_displacement(result);
}
return (*p = result);
}
-GC_PTR GC_post_incr (p, how_much)
-GC_PTR *p;
-size_t how_much;
+GC_API void * GC_CALL GC_post_incr (void **p, ptrdiff_t how_much)
{
- GC_PTR initial = *p;
- GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
-
+ void * initial = *p;
+ void * result = GC_same_obj((void *)((ptr_t)initial + how_much), initial);
+
if (!GC_all_interior_pointers) {
- (void) GC_is_valid_displacement(result);
+ (void) GC_is_valid_displacement(result);
}
*p = result;
return(initial);
diff --git a/boehm-gc/real_malloc.c b/boehm-gc/real_malloc.c
index dece9fdc09c..145e73f3b4b 100644
--- a/boehm-gc/real_malloc.c
+++ b/boehm-gc/real_malloc.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
*
@@ -11,8 +11,10 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:04 pm PDT */
+# ifdef HAVE_CONFIG_H
+# include "config.h"
+# endif
# ifdef PCR
/*
@@ -23,14 +25,15 @@
# define PCR_NO_RENAME
# include <stdlib.h>
-# ifdef __STDC__
- char * real_malloc(size_t size)
-# else
- char * real_malloc()
- int size;
-# endif
+void * real_malloc(size_t size)
{
- return((char *)malloc(size));
+ return(malloc(size));
}
-#endif /* PCR */
+# else
+
+extern int GC_quiet;
+ /* ANSI C doesn't allow translation units to be empty. */
+ /* So we guarantee this one is nonempty. */
+
+#endif /* PCR */
diff --git a/boehm-gc/reclaim.c b/boehm-gc/reclaim.c
index 323d420fa40..285e1460b31 100644
--- a/boehm-gc/reclaim.c
+++ b/boehm-gc/reclaim.c
@@ -1,8 +1,8 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
- * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -14,700 +14,301 @@
* modified is included with the above copyright notice.
*/
-#include <stdio.h>
#include "private/gc_priv.h"
-signed_word GC_mem_found = 0;
- /* Number of words of memory reclaimed */
+#ifdef ENABLE_DISCLAIM
+# include "gc_disclaim.h"
+#endif
+
+#include <stdio.h>
+
+GC_INNER 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;
- /* Number of threads currently building free lists without */
- /* holding GC lock. It is not safe to collect if this is */
- /* nonzero. */
+#if defined(PARALLEL_MARK)
+ GC_INNER word GC_fl_builder_count = 0;
+ /* Number of threads currently building free lists without */
+ /* holding GC lock. It is not safe to collect if this is */
+ /* nonzero. */
#endif /* PARALLEL_MARK */
-/* We defer printing of leaked objects until we're done with the GC */
-/* cycle, since the routine for printing objects needs to run outside */
-/* the collector, e.g. without the allocation lock. */
-#define MAX_LEAKED 40
-ptr_t GC_leaked[MAX_LEAKED];
-unsigned GC_n_leaked = 0;
+/* We defer printing of leaked objects until we're done with the GC */
+/* cycle, since the routine for printing objects needs to run outside */
+/* the collector, e.g. without the allocation lock. */
+#ifndef MAX_LEAKED
+# define MAX_LEAKED 40
+#endif
+STATIC ptr_t GC_leaked[MAX_LEAKED] = { NULL };
+STATIC unsigned GC_n_leaked = 0;
+
+GC_INNER GC_bool GC_have_errors = FALSE;
-GC_bool GC_have_errors = FALSE;
+#if !defined(EAGER_SWEEP) && defined(ENABLE_DISCLAIM)
+ STATIC void GC_reclaim_unconditionally_marked(void);
+#endif
-void GC_add_leaked(leaked)
-ptr_t leaked;
+GC_INLINE void GC_add_leaked(ptr_t leaked)
{
+# ifndef SHORT_DBG_HDRS
+ if (GC_findleak_delay_free && !GC_check_leaked(leaked))
+ return;
+# endif
+
+ GC_have_errors = TRUE;
+ /* FIXME: Prevent adding an object while printing leaked ones. */
if (GC_n_leaked < MAX_LEAKED) {
- GC_have_errors = TRUE;
GC_leaked[GC_n_leaked++] = leaked;
/* Make sure it's not reclaimed this cycle */
- GC_set_mark_bit(leaked);
+ GC_set_mark_bit(leaked);
}
}
-static GC_bool printing_errors = FALSE;
-/* Print all objects on the list after printing any smashed objs. */
-/* Clear both lists. */
-void GC_print_all_errors ()
+/* Print all objects on the list after printing any smashed objects. */
+/* Clear both lists. Called without the allocation lock held. */
+GC_INNER void GC_print_all_errors(void)
{
+ static GC_bool printing_errors = FALSE;
+ GC_bool have_errors;
unsigned i;
+ DCL_LOCK_STATE;
LOCK();
if (printing_errors) {
- UNLOCK();
- return;
+ UNLOCK();
+ return;
}
+ have_errors = GC_have_errors;
printing_errors = TRUE;
UNLOCK();
- if (GC_debugging_started) GC_print_all_smashed();
+
+ if (GC_debugging_started) {
+ GC_print_all_smashed();
+ } else {
+ have_errors = FALSE;
+ }
+
+ if (GC_n_leaked > 0) {
+ GC_err_printf("Found %u leaked objects:\n", GC_n_leaked);
+ have_errors = TRUE;
+ }
for (i = 0; i < GC_n_leaked; ++i) {
- ptr_t p = GC_leaked[i];
- if (HDR(p) -> hb_obj_kind == PTRFREE) {
- GC_err_printf0("Leaked atomic object at ");
- } else {
- GC_err_printf0("Leaked composite object at ");
- }
- GC_print_heap_obj(p);
- GC_err_printf0("\n");
- GC_free(p);
- GC_leaked[i] = 0;
+ ptr_t p = GC_leaked[i];
+ GC_print_heap_obj(p);
+ GC_free(p);
+ GC_leaked[i] = 0;
}
GC_n_leaked = 0;
+
+ if (have_errors
+# ifndef GC_ABORT_ON_LEAK
+ && GETENV("GC_ABORT_ON_LEAK") != NULL
+# endif
+ ) {
+ ABORT("Leaked or smashed objects encountered");
+ }
+
printing_errors = FALSE;
}
-# define FOUND_FREE(hblk, word_no) \
- { \
- GC_add_leaked((ptr_t)hblk + WORDS_TO_BYTES(word_no)); \
- }
-
/*
* reclaim phase
*
*/
-
-/*
- * Test whether a block is completely empty, i.e. contains no marked
- * objects. This does not require the block to be in physical
- * memory.
- */
-
-GC_bool GC_block_empty(hhdr)
-register hdr * hhdr;
+/* Test whether a block is completely empty, i.e. contains no marked */
+/* objects. This does not require the block to be in physical memory. */
+GC_INNER GC_bool GC_block_empty(hdr *hhdr)
{
- /* We treat hb_marks as an array of words here, even if it is */
- /* actually an array of bytes. Since we only check for zero, there */
- /* are no endian-ness issues. */
- register word *p = (word *)(&(hhdr -> hb_marks[0]));
- register word * plim =
- (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ]));
- while (p < plim) {
- if (*p++) return(FALSE);
- }
- return(TRUE);
+ return (hhdr -> hb_n_marks == 0);
}
-/* The following functions sometimes return a DONT_KNOW value. */
-#define DONT_KNOW 2
-
-#ifdef SMALL_CONFIG
-# define GC_block_nearly_full1(hhdr, pat1) DONT_KNOW
-# define GC_block_nearly_full3(hhdr, pat1, pat2) DONT_KNOW
-# define GC_block_nearly_full(hhdr) DONT_KNOW
-#endif
-
-#if !defined(SMALL_CONFIG) && defined(USE_MARK_BYTES)
-
-# define GC_block_nearly_full1(hhdr, pat1) GC_block_nearly_full(hhdr)
-# define GC_block_nearly_full3(hhdr, pat1, pat2) GC_block_nearly_full(hhdr)
-
-
-GC_bool GC_block_nearly_full(hhdr)
-register hdr * hhdr;
+STATIC GC_bool GC_block_nearly_full(hdr *hhdr)
{
- /* We again treat hb_marks as an array of words, even though it */
- /* isn't. We first sum up all the words, resulting in a word */
- /* containing 4 or 8 separate partial sums. */
- /* We then sum the bytes in the word of partial sums. */
- /* This is still endian independant. This fails if the partial */
- /* sums can overflow. */
-# if (BYTES_TO_WORDS(MARK_BITS_SZ)) >= 256
- --> potential overflow; fix the code
-# endif
- register word *p = (word *)(&(hhdr -> hb_marks[0]));
- register word * plim =
- (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ]));
- word sum_vector = 0;
- unsigned sum;
- while (p < plim) {
- sum_vector += *p;
- ++p;
- }
- sum = 0;
- while (sum_vector > 0) {
- sum += sum_vector & 0xff;
- sum_vector >>= 8;
- }
- return (sum > BYTES_TO_WORDS(7*HBLKSIZE/8)/(hhdr -> hb_sz));
+ return (hhdr -> hb_n_marks > 7 * HBLK_OBJS(hhdr -> hb_sz)/8);
}
-#endif /* USE_MARK_BYTES */
-#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
+/* FIXME: This should perhaps again be specialized for USE_MARK_BYTES */
+/* and USE_MARK_BITS cases. */
/*
- * Test whether nearly all of the mark words consist of the same
- * repeating pattern.
- */
-#define FULL_THRESHOLD (MARK_BITS_SZ/16)
-
-GC_bool GC_block_nearly_full1(hhdr, pat1)
-hdr *hhdr;
-word pat1;
-{
- unsigned i;
- unsigned misses = 0;
- GC_ASSERT((MARK_BITS_SZ & 1) == 0);
- for (i = 0; i < MARK_BITS_SZ; ++i) {
- if ((hhdr -> hb_marks[i] | ~pat1) != ONES) {
- if (++misses > FULL_THRESHOLD) return FALSE;
- }
- }
- return TRUE;
-}
-
-/*
- * Test whether the same repeating 3 word pattern occurs in nearly
- * all the mark bit slots.
- * This is used as a heuristic, so we're a bit sloppy and ignore
- * the last one or two words.
- */
-GC_bool GC_block_nearly_full3(hhdr, pat1, pat2, pat3)
-hdr *hhdr;
-word pat1, pat2, pat3;
-{
- unsigned i;
- unsigned misses = 0;
-
- if (MARK_BITS_SZ < 4) {
- return DONT_KNOW;
- }
- for (i = 0; i < MARK_BITS_SZ - 2; i += 3) {
- if ((hhdr -> hb_marks[i] | ~pat1) != ONES) {
- if (++misses > FULL_THRESHOLD) return FALSE;
- }
- if ((hhdr -> hb_marks[i+1] | ~pat2) != ONES) {
- if (++misses > FULL_THRESHOLD) return FALSE;
- }
- if ((hhdr -> hb_marks[i+2] | ~pat3) != ONES) {
- if (++misses > FULL_THRESHOLD) return FALSE;
- }
- }
- return TRUE;
-}
-
-/* Check whether a small object block is nearly full by looking at only */
-/* the mark bits. */
-/* We manually precomputed the mark bit patterns that need to be */
-/* checked for, and we give up on the ones that are unlikely to occur, */
-/* or have period > 3. */
-/* This would be a lot easier with a mark bit per object instead of per */
-/* word, but that would rewuire computing object numbers in the mark */
-/* loop, which would require different data structures ... */
-GC_bool GC_block_nearly_full(hhdr)
-hdr *hhdr;
-{
- int sz = hhdr -> hb_sz;
-
-# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
- return DONT_KNOW; /* Shouldn't be used in any standard config. */
-# endif
-# if CPP_WORDSZ == 32
- switch(sz) {
- case 1:
- return GC_block_nearly_full1(hhdr, 0xffffffffl);
- case 2:
- return GC_block_nearly_full1(hhdr, 0x55555555l);
- case 4:
- return GC_block_nearly_full1(hhdr, 0x11111111l);
- case 6:
- return GC_block_nearly_full3(hhdr, 0x41041041l,
- 0x10410410l,
- 0x04104104l);
- case 8:
- return GC_block_nearly_full1(hhdr, 0x01010101l);
- case 12:
- return GC_block_nearly_full3(hhdr, 0x01001001l,
- 0x10010010l,
- 0x00100100l);
- case 16:
- return GC_block_nearly_full1(hhdr, 0x00010001l);
- case 32:
- return GC_block_nearly_full1(hhdr, 0x00000001l);
- default:
- return DONT_KNOW;
- }
-# endif
-# if CPP_WORDSZ == 64
- switch(sz) {
- case 1:
- return GC_block_nearly_full1(hhdr, 0xffffffffffffffffl);
- case 2:
- return GC_block_nearly_full1(hhdr, 0x5555555555555555l);
- case 4:
- return GC_block_nearly_full1(hhdr, 0x1111111111111111l);
- case 6:
- return GC_block_nearly_full3(hhdr, 0x1041041041041041l,
- 0x4104104104104104l,
- 0x0410410410410410l);
- case 8:
- return GC_block_nearly_full1(hhdr, 0x0101010101010101l);
- case 12:
- return GC_block_nearly_full3(hhdr, 0x1001001001001001l,
- 0x0100100100100100l,
- 0x0010010010010010l);
- case 16:
- return GC_block_nearly_full1(hhdr, 0x0001000100010001l);
- case 32:
- return GC_block_nearly_full1(hhdr, 0x0000000100000001l);
- default:
- return DONT_KNOW;
- }
-# endif
-}
-#endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
-
-/* We keep track of reclaimed memory if we are either asked to, or */
-/* we are using the parallel marker. In the latter case, we assume */
-/* that most allocation goes through GC_malloc_many for scalability. */
-/* GC_malloc_many needs the count anyway. */
-# if defined(GATHERSTATS) || defined(PARALLEL_MARK)
-# define INCR_WORDS(sz) n_words_found += (sz)
-# define COUNT_PARAM , count
-# define COUNT_ARG , count
-# define COUNT_DECL signed_word * count;
-# define NWORDS_DECL signed_word n_words_found = 0;
-# define COUNT_UPDATE *count += n_words_found;
-# define MEM_FOUND_ADDR , &GC_mem_found
-# else
-# define INCR_WORDS(sz)
-# define COUNT_PARAM
-# define COUNT_ARG
-# define COUNT_DECL
-# define NWORDS_DECL
-# define COUNT_UPDATE
-# define MEM_FOUND_ADDR
-# endif
-/*
* Restore unmarked small objects in h of size sz to the object
* free list. Returns the new list.
- * Clears unmarked objects.
+ * Clears unmarked objects. Sz is in bytes.
*/
-/*ARGSUSED*/
-ptr_t GC_reclaim_clear(hbp, hhdr, sz, list COUNT_PARAM)
-register struct hblk *hbp; /* ptr to current heap block */
-register hdr * hhdr;
-register ptr_t list;
-register word sz;
-COUNT_DECL
+STATIC ptr_t GC_reclaim_clear(struct hblk *hbp, hdr *hhdr, size_t sz,
+ ptr_t list, signed_word *count)
{
- register int word_no;
- register word *p, *q, *plim;
- NWORDS_DECL
-
+ word bit_no = 0;
+ word *p, *q, *plim;
+ signed_word n_bytes_found = 0;
+
GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp));
+ GC_ASSERT(sz == hhdr -> hb_sz);
+ GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0);
p = (word *)(hbp->hb_body);
- word_no = 0;
- plim = (word *)((((word)hbp) + HBLKSIZE)
- - WORDS_TO_BYTES(sz));
+ plim = (word *)(hbp->hb_body + HBLKSIZE - sz);
/* go through all words in block */
- while( p <= plim ) {
- if( mark_bit_from_hdr(hhdr, word_no) ) {
- p += sz;
- } else {
- INCR_WORDS(sz);
- /* object is available - put on list */
- obj_link(p) = list;
- list = ((ptr_t)p);
- /* Clear object, advance p to next object in the process */
- q = p + sz;
-# ifdef USE_MARK_BYTES
- GC_ASSERT(!(sz & 1)
- && !((word)p & (2 * sizeof(word) - 1)));
- p[1] = 0;
+ while ((word)p <= (word)plim) {
+ if (mark_bit_from_hdr(hhdr, bit_no)) {
+ p = (word *)((ptr_t)p + sz);
+ } else {
+ n_bytes_found += sz;
+ /* object is available - put on list */
+ obj_link(p) = list;
+ list = ((ptr_t)p);
+ /* Clear object, advance p to next object in the process */
+ q = (word *)((ptr_t)p + sz);
+# ifdef USE_MARK_BYTES
+ GC_ASSERT(!(sz & 1)
+ && !((word)p & (2 * sizeof(word) - 1)));
+ p[1] = 0;
p += 2;
- while (p < q) {
- CLEAR_DOUBLE(p);
- p += 2;
- }
-# else
+ while ((word)p < (word)q) {
+ CLEAR_DOUBLE(p);
+ p += 2;
+ }
+# else
p++; /* Skip link field */
- while (p < q) {
- *p++ = 0;
- }
-# endif
- }
- word_no += sz;
- }
- COUNT_UPDATE
- return(list);
-}
-
-#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
-
-/*
- * A special case for 2 word composite objects (e.g. cons cells):
- */
-/*ARGSUSED*/
-ptr_t GC_reclaim_clear2(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp; /* ptr to current heap block */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
-{
- register word * mark_word_addr = &(hhdr->hb_marks[0]);
- register word *p, *plim;
- register word mark_word;
- register int i;
- NWORDS_DECL
-# define DO_OBJ(start_displ) \
- if (!(mark_word & ((word)1 << start_displ))) { \
- p[start_displ] = (word)list; \
- list = (ptr_t)(p+start_displ); \
- p[start_displ+1] = 0; \
- INCR_WORDS(2); \
- }
-
- p = (word *)(hbp->hb_body);
- plim = (word *)(((word)hbp) + HBLKSIZE);
-
- /* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- for (i = 0; i < WORDSZ; i += 8) {
- DO_OBJ(0);
- DO_OBJ(2);
- DO_OBJ(4);
- DO_OBJ(6);
- p += 8;
- mark_word >>= 8;
- }
- }
- COUNT_UPDATE
- return(list);
-# undef DO_OBJ
-}
-
-/*
- * Another special case for 4 word composite objects:
- */
-/*ARGSUSED*/
-ptr_t GC_reclaim_clear4(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp; /* ptr to current heap block */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
-{
- register word * mark_word_addr = &(hhdr->hb_marks[0]);
- register word *p, *plim;
- register word mark_word;
- NWORDS_DECL
-# define DO_OBJ(start_displ) \
- if (!(mark_word & ((word)1 << start_displ))) { \
- p[start_displ] = (word)list; \
- list = (ptr_t)(p+start_displ); \
- p[start_displ+1] = 0; \
- CLEAR_DOUBLE(p + start_displ + 2); \
- INCR_WORDS(4); \
- }
-
- p = (word *)(hbp->hb_body);
- plim = (word *)(((word)hbp) + HBLKSIZE);
-
- /* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- DO_OBJ(0);
- DO_OBJ(4);
- DO_OBJ(8);
- DO_OBJ(12);
- DO_OBJ(16);
- DO_OBJ(20);
- DO_OBJ(24);
- DO_OBJ(28);
-# if CPP_WORDSZ == 64
- DO_OBJ(32);
- DO_OBJ(36);
- DO_OBJ(40);
- DO_OBJ(44);
- DO_OBJ(48);
- DO_OBJ(52);
- DO_OBJ(56);
- DO_OBJ(60);
-# endif
- p += WORDSZ;
- }
- COUNT_UPDATE
+ while ((word)p < (word)q) {
+ *p++ = 0;
+ }
+# endif
+ }
+ bit_no += MARK_BIT_OFFSET(sz);
+ }
+ *count += n_bytes_found;
return(list);
-# undef DO_OBJ
}
-#endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
-
/* The same thing, but don't clear objects: */
-/*ARGSUSED*/
-ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_PARAM)
-register struct hblk *hbp; /* ptr to current heap block */
-register hdr * hhdr;
-register ptr_t list;
-register word sz;
-COUNT_DECL
+STATIC ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, size_t sz,
+ ptr_t list, signed_word *count)
{
- register int word_no = 0;
- register word *p, *plim;
- NWORDS_DECL
-
- p = (word *)(hbp->hb_body);
- plim = (word *)((((word)hbp) + HBLKSIZE)
- - WORDS_TO_BYTES(sz));
+ word bit_no = 0;
+ word *p, *plim;
+ signed_word n_bytes_found = 0;
- /* go through all words in block */
- while( p <= plim ) {
- if( !mark_bit_from_hdr(hhdr, word_no) ) {
- INCR_WORDS(sz);
- /* object is available - put on list */
- obj_link(p) = list;
- list = ((ptr_t)p);
- }
- p += sz;
- word_no += sz;
- }
- COUNT_UPDATE
- return(list);
-}
-
-/* Don't really reclaim objects, just check for unmarked ones: */
-/*ARGSUSED*/
-void GC_reclaim_check(hbp, hhdr, sz)
-register struct hblk *hbp; /* ptr to current heap block */
-register hdr * hhdr;
-register word sz;
-{
- register int word_no = 0;
- register word *p, *plim;
-# ifdef GATHERSTATS
- register int n_words_found = 0;
-# endif
-
+ GC_ASSERT(sz == hhdr -> hb_sz);
p = (word *)(hbp->hb_body);
- plim = (word *)((((word)hbp) + HBLKSIZE)
- - WORDS_TO_BYTES(sz));
+ plim = (word *)((ptr_t)hbp + HBLKSIZE - sz);
/* go through all words in block */
- while( p <= plim ) {
- if( !mark_bit_from_hdr(hhdr, word_no) ) {
- FOUND_FREE(hbp, word_no);
- }
- p += sz;
- word_no += sz;
- }
-}
-
-#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
-/*
- * Another special case for 2 word atomic objects:
- */
-/*ARGSUSED*/
-ptr_t GC_reclaim_uninit2(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp; /* ptr to current heap block */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
-{
- register word * mark_word_addr = &(hhdr->hb_marks[0]);
- register word *p, *plim;
- register word mark_word;
- register int i;
- NWORDS_DECL
-# define DO_OBJ(start_displ) \
- if (!(mark_word & ((word)1 << start_displ))) { \
- p[start_displ] = (word)list; \
- list = (ptr_t)(p+start_displ); \
- INCR_WORDS(2); \
- }
-
- p = (word *)(hbp->hb_body);
- plim = (word *)(((word)hbp) + HBLKSIZE);
-
- /* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- for (i = 0; i < WORDSZ; i += 8) {
- DO_OBJ(0);
- DO_OBJ(2);
- DO_OBJ(4);
- DO_OBJ(6);
- p += 8;
- mark_word >>= 8;
- }
- }
- COUNT_UPDATE
+ while ((word)p <= (word)plim) {
+ if (!mark_bit_from_hdr(hhdr, bit_no)) {
+ n_bytes_found += sz;
+ /* object is available - put on list */
+ obj_link(p) = list;
+ list = ((ptr_t)p);
+ }
+ p = (word *)((ptr_t)p + sz);
+ bit_no += MARK_BIT_OFFSET(sz);
+ }
+ *count += n_bytes_found;
return(list);
-# undef DO_OBJ
}
-/*
- * Another special case for 4 word atomic objects:
- */
-/*ARGSUSED*/
-ptr_t GC_reclaim_uninit4(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp; /* ptr to current heap block */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
-{
- register word * mark_word_addr = &(hhdr->hb_marks[0]);
- register word *p, *plim;
- register word mark_word;
- NWORDS_DECL
-# define DO_OBJ(start_displ) \
- if (!(mark_word & ((word)1 << start_displ))) { \
- p[start_displ] = (word)list; \
- list = (ptr_t)(p+start_displ); \
- INCR_WORDS(4); \
- }
-
- p = (word *)(hbp->hb_body);
- plim = (word *)(((word)hbp) + HBLKSIZE);
-
- /* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- DO_OBJ(0);
- DO_OBJ(4);
- DO_OBJ(8);
- DO_OBJ(12);
- DO_OBJ(16);
- DO_OBJ(20);
- DO_OBJ(24);
- DO_OBJ(28);
-# if CPP_WORDSZ == 64
- DO_OBJ(32);
- DO_OBJ(36);
- DO_OBJ(40);
- DO_OBJ(44);
- DO_OBJ(48);
- DO_OBJ(52);
- DO_OBJ(56);
- DO_OBJ(60);
-# endif
- p += WORDSZ;
- }
- COUNT_UPDATE
- return(list);
-# undef DO_OBJ
-}
+#ifdef ENABLE_DISCLAIM
+ /* Call reclaim notifier for block's kind on each unmarked object in */
+ /* block, all within a pair of corresponding enter/leave callbacks. */
+ STATIC ptr_t GC_disclaim_and_reclaim(struct hblk *hbp, hdr *hhdr, size_t sz,
+ ptr_t list, signed_word *count)
+ {
+ int bit_no = 0;
+ word *p, *q, *plim;
+ signed_word n_bytes_found = 0;
+ struct obj_kind *ok = &GC_obj_kinds[hhdr->hb_obj_kind];
+ int (GC_CALLBACK *disclaim)(void *) = ok->ok_disclaim_proc;
+
+ GC_ASSERT(sz == hhdr -> hb_sz);
+ p = (word *)(hbp -> hb_body);
+ plim = (word *)((ptr_t)p + HBLKSIZE - sz);
+
+ while ((word)p <= (word)plim) {
+ int marked = mark_bit_from_hdr(hhdr, bit_no);
+ if (!marked && (*disclaim)(p)) {
+ hhdr -> hb_n_marks++;
+ marked = 1;
+ }
+ if (marked)
+ p = (word *)((ptr_t)p + sz);
+ else {
+ n_bytes_found += sz;
+ /* object is available - put on list */
+ obj_link(p) = list;
+ list = ((ptr_t)p);
+ /* Clear object, advance p to next object in the process */
+ q = (word *)((ptr_t)p + sz);
+# ifdef USE_MARK_BYTES
+ GC_ASSERT((sz & 1) == 0);
+ GC_ASSERT(((word)p & (2 * sizeof(word) - 1)) == 0);
+ p[1] = 0;
+ p += 2;
+ while ((word)p < (word)q) {
+ CLEAR_DOUBLE(p);
+ p += 2;
+ }
+# else
+ p++; /* Skip link field */
+ while ((word)p < (word)q) {
+ *p++ = 0;
+ }
+# endif
+ }
+ bit_no += MARK_BIT_OFFSET(sz);
+ }
+ *count += n_bytes_found;
+ return list;
+ }
+#endif /* ENABLE_DISCLAIM */
-/* Finally the one word case, which never requires any clearing: */
-/*ARGSUSED*/
-ptr_t GC_reclaim1(hbp, hhdr, list COUNT_PARAM)
-register struct hblk *hbp; /* ptr to current heap block */
-hdr * hhdr;
-register ptr_t list;
-COUNT_DECL
+/* Don't really reclaim objects, just check for unmarked ones: */
+STATIC void GC_reclaim_check(struct hblk *hbp, hdr *hhdr, word sz)
{
- register word * mark_word_addr = &(hhdr->hb_marks[0]);
- register word *p, *plim;
- register word mark_word;
- register int i;
- NWORDS_DECL
-# define DO_OBJ(start_displ) \
- if (!(mark_word & ((word)1 << start_displ))) { \
- p[start_displ] = (word)list; \
- list = (ptr_t)(p+start_displ); \
- INCR_WORDS(1); \
- }
-
- p = (word *)(hbp->hb_body);
- plim = (word *)(((word)hbp) + HBLKSIZE);
+ word bit_no;
+ ptr_t p, plim;
+ GC_ASSERT(sz == hhdr -> hb_sz);
/* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- for (i = 0; i < WORDSZ; i += 4) {
- DO_OBJ(0);
- DO_OBJ(1);
- DO_OBJ(2);
- DO_OBJ(3);
- p += 4;
- mark_word >>= 4;
- }
- }
- COUNT_UPDATE
- return(list);
-# undef DO_OBJ
+ p = hbp->hb_body;
+ plim = p + HBLKSIZE - sz;
+ for (bit_no = 0; (word)p <= (word)plim;
+ p += sz, bit_no += MARK_BIT_OFFSET(sz)) {
+ if (!mark_bit_from_hdr(hhdr, bit_no)) {
+ GC_add_leaked(p);
+ }
+ }
}
-#endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
-
/*
* Generic procedure to rebuild a free list in hbp.
* Also called directly from GC_malloc_many.
+ * Sz is now in bytes.
*/
-ptr_t GC_reclaim_generic(hbp, hhdr, sz, init, list COUNT_PARAM)
-struct hblk *hbp; /* ptr to current heap block */
-hdr * hhdr;
-GC_bool init;
-ptr_t list;
-word sz;
-COUNT_DECL
+GC_INNER ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
+ GC_bool init, ptr_t list,
+ signed_word *count)
{
- ptr_t result = list;
+ ptr_t result;
GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr);
- GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */);
- if (init) {
- switch(sz) {
-# if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
- case 1:
- /* We now issue the hint even if GC_nearly_full returned */
- /* DONT_KNOW. */
- result = GC_reclaim1(hbp, hhdr, list COUNT_ARG);
- break;
- case 2:
- result = GC_reclaim_clear2(hbp, hhdr, list COUNT_ARG);
- break;
- case 4:
- result = GC_reclaim_clear4(hbp, hhdr, list COUNT_ARG);
- break;
-# endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
- default:
- result = GC_reclaim_clear(hbp, hhdr, sz, list COUNT_ARG);
- break;
- }
+# ifndef GC_DISABLE_INCREMENTAL
+ GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */);
+# endif
+# ifdef ENABLE_DISCLAIM
+ if ((hhdr -> hb_flags & HAS_DISCLAIM) != 0) {
+ result = GC_disclaim_and_reclaim(hbp, hhdr, sz, list, count);
+ } else
+# endif
+ /* else */ if (init || GC_debugging_started) {
+ result = GC_reclaim_clear(hbp, hhdr, sz, list, count);
} else {
GC_ASSERT((hhdr)->hb_descr == 0 /* Pointer-free block */);
- switch(sz) {
-# if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
- case 1:
- result = GC_reclaim1(hbp, hhdr, list COUNT_ARG);
- break;
- case 2:
- result = GC_reclaim_uninit2(hbp, hhdr, list COUNT_ARG);
- break;
- case 4:
- result = GC_reclaim_uninit4(hbp, hhdr, list COUNT_ARG);
- break;
-# endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
- default:
- result = GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_ARG);
- break;
- }
- }
+ result = GC_reclaim_uninit(hbp, hhdr, sz, list, count);
+ }
if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr);
return result;
}
@@ -718,28 +319,45 @@ COUNT_DECL
* If entirely empty blocks are to be completely deallocated, then
* caller should perform that check.
*/
-void GC_reclaim_small_nonempty_block(hbp, report_if_found COUNT_PARAM)
-register struct hblk *hbp; /* ptr to current heap block */
-int report_if_found; /* Abort if a reclaimable object is found */
-COUNT_DECL
+STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp,
+ GC_bool report_if_found)
{
hdr *hhdr = HDR(hbp);
- word sz = hhdr -> hb_sz;
- int kind = hhdr -> hb_obj_kind;
- struct obj_kind * ok = &GC_obj_kinds[kind];
- ptr_t * flh = &(ok -> ok_freelist[sz]);
-
+ size_t sz = hhdr -> hb_sz;
+ struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
+ void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
+
hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
if (report_if_found) {
- GC_reclaim_check(hbp, hhdr, sz);
+ GC_reclaim_check(hbp, hhdr, sz);
} else {
- *flh = GC_reclaim_generic(hbp, hhdr, sz,
- (ok -> ok_init || GC_debugging_started),
- *flh MEM_FOUND_ADDR);
+ *flh = GC_reclaim_generic(hbp, hhdr, sz, ok -> ok_init,
+ *flh, &GC_bytes_found);
}
}
+#ifdef ENABLE_DISCLAIM
+ STATIC void GC_disclaim_and_reclaim_or_free_small_block(struct hblk *hbp)
+ {
+ hdr *hhdr = HDR(hbp);
+ size_t sz = hhdr -> hb_sz;
+ struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
+ void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
+ void *flh_next;
+
+ hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
+ flh_next = GC_reclaim_generic(hbp, hhdr, sz, ok -> ok_init,
+ *flh, &GC_bytes_found);
+ if (hhdr -> hb_n_marks)
+ *flh = flh_next;
+ else {
+ GC_bytes_found += HBLKSIZE;
+ GC_freehblk(hbp);
+ }
+ }
+#endif /* ENABLE_DISCLAIM */
+
/*
* Restore an unmarked large object or an entirely empty blocks of small objects
* to the heap block free list.
@@ -748,156 +366,215 @@ COUNT_DECL
* If report_if_found is TRUE, then process any block immediately, and
* simply report free objects; do not actually reclaim them.
*/
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_reclaim_block(register struct hblk *hbp, word report_if_found)
-# else
- void GC_reclaim_block(hbp, report_if_found)
- register struct hblk *hbp; /* ptr to current heap block */
- word report_if_found; /* Abort if a reclaimable object is found */
-# endif
+STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found)
{
- register hdr * hhdr;
- register word sz; /* size of objects in current block */
- register struct obj_kind * ok;
+ hdr * hhdr = HDR(hbp);
+ size_t sz = hhdr -> hb_sz; /* size of objects in current block */
+ struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
struct hblk ** rlh;
- hhdr = HDR(hbp);
- sz = hhdr -> hb_sz;
- ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
-
- if( sz > MAXOBJSZ ) { /* 1 big object */
+ if( sz > MAXOBJBYTES ) { /* 1 big object */
if( !mark_bit_from_hdr(hhdr, 0) ) {
- if (report_if_found) {
- FOUND_FREE(hbp, 0);
- } else {
- word blocks = OBJ_SZ_TO_BLOCKS(sz);
- if (blocks > 1) {
- GC_large_allocd_bytes -= blocks * HBLKSIZE;
- }
-# ifdef GATHERSTATS
- GC_mem_found += sz;
-# endif
- GC_freehblk(hbp);
- }
- }
+ if (report_if_found) {
+ GC_add_leaked((ptr_t)hbp);
+ } else {
+ size_t blocks;
+
+# ifdef ENABLE_DISCLAIM
+ if (EXPECT(hhdr->hb_flags & HAS_DISCLAIM, 0)) {
+ struct obj_kind *ok = &GC_obj_kinds[hhdr->hb_obj_kind];
+ if ((*ok->ok_disclaim_proc)(hbp)) {
+ /* Not disclaimed => resurrect the object. */
+ set_mark_bit_from_hdr(hhdr, 0);
+ goto in_use;
+ }
+ }
+# endif
+ blocks = OBJ_SZ_TO_BLOCKS(sz);
+ if (blocks > 1) {
+ GC_large_allocd_bytes -= blocks * HBLKSIZE;
+ }
+ GC_bytes_found += sz;
+ GC_freehblk(hbp);
+ }
+ } else {
+# ifdef ENABLE_DISCLAIM
+ in_use:
+# endif
+ if (hhdr -> hb_descr != 0) {
+ GC_composite_in_use += sz;
+ } else {
+ GC_atomic_in_use += sz;
+ }
+ }
} else {
GC_bool empty = GC_block_empty(hhdr);
+# ifdef PARALLEL_MARK
+ /* Count can be low or one too high because we sometimes */
+ /* have to ignore decrements. Objects can also potentially */
+ /* be repeatedly marked by each marker. */
+ /* Here we assume two markers, but this is extremely */
+ /* unlikely to fail spuriously with more. And if it does, it */
+ /* should be looked at. */
+ GC_ASSERT(hhdr -> hb_n_marks <= 2 * (HBLKSIZE/sz + 1) + 16);
+# else
+ GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE);
+# endif
if (report_if_found) {
- GC_reclaim_small_nonempty_block(hbp, (int)report_if_found
- MEM_FOUND_ADDR);
+ GC_reclaim_small_nonempty_block(hbp, TRUE /* report_if_found */);
} else if (empty) {
-# ifdef GATHERSTATS
- GC_mem_found += BYTES_TO_WORDS(HBLKSIZE);
-# endif
- GC_freehblk(hbp);
- } else if (TRUE != GC_block_nearly_full(hhdr)){
+# ifdef ENABLE_DISCLAIM
+ if ((hhdr -> hb_flags & HAS_DISCLAIM) != 0) {
+ GC_disclaim_and_reclaim_or_free_small_block(hbp);
+ } else
+# endif
+ /* else */ {
+ GC_bytes_found += HBLKSIZE;
+ GC_freehblk(hbp);
+ }
+ } else if (GC_find_leak || !GC_block_nearly_full(hhdr)) {
/* group of smaller objects, enqueue the real work */
- rlh = &(ok -> ok_reclaim_list[sz]);
+ rlh = &(ok -> ok_reclaim_list[BYTES_TO_GRANULES(sz)]);
hhdr -> hb_next = *rlh;
*rlh = hbp;
} /* else not worth salvaging. */
- /* We used to do the nearly_full check later, but we */
- /* already have the right cache context here. Also */
- /* doing it here avoids some silly lock contention in */
- /* GC_malloc_many. */
+ /* We used to do the nearly_full check later, but we */
+ /* already have the right cache context here. Also */
+ /* doing it here avoids some silly lock contention in */
+ /* GC_malloc_many. */
+
+ if (hhdr -> hb_descr != 0) {
+ GC_composite_in_use += sz * hhdr -> hb_n_marks;
+ } else {
+ GC_atomic_in_use += sz * hhdr -> hb_n_marks;
+ }
}
}
#if !defined(NO_DEBUGGING)
-/* Routines to gather and print heap block info */
-/* intended for debugging. Otherwise should be called */
-/* with lock. */
+/* Routines to gather and print heap block info */
+/* intended for debugging. Otherwise should be called */
+/* with lock. */
struct Print_stats
{
- size_t number_of_blocks;
- size_t total_bytes;
+ size_t number_of_blocks;
+ size_t total_bytes;
};
#ifdef USE_MARK_BYTES
-/* Return the number of set mark bits in the given header */
-int GC_n_set_marks(hhdr)
-hdr * hhdr;
+/* Return the number of set mark bits in the given header. */
+/* Remains externally visible as used by GNU GCJ currently. */
+int GC_n_set_marks(hdr *hhdr)
{
- register int result = 0;
- register int i;
-
- for (i = 0; i < MARK_BITS_SZ; i++) {
+ int result = 0;
+ int i;
+ size_t sz = hhdr -> hb_sz;
+ int offset = (int)MARK_BIT_OFFSET(sz);
+ int limit = (int)FINAL_MARK_BIT(sz);
+
+ for (i = 0; i < limit; i += offset) {
result += hhdr -> hb_marks[i];
}
+ GC_ASSERT(hhdr -> hb_marks[limit]);
return(result);
}
#else
-/* Number of set bits in a word. Not performance critical. */
-static int set_bits(n)
-word n;
+/* Number of set bits in a word. Not performance critical. */
+static int set_bits(word n)
{
- register word m = n;
- register int result = 0;
-
+ word m = n;
+ int result = 0;
+
while (m > 0) {
- if (m & 1) result++;
- m >>= 1;
+ if (m & 1) result++;
+ m >>= 1;
}
return(result);
}
-/* Return the number of set mark bits in the given header */
-int GC_n_set_marks(hhdr)
-hdr * hhdr;
+int GC_n_set_marks(hdr *hhdr)
{
- register int result = 0;
- register int i;
-
- for (i = 0; i < MARK_BITS_SZ; i++) {
+ int result = 0;
+ int i;
+ int n_mark_words;
+# ifdef MARK_BIT_PER_OBJ
+ int n_objs = (int)HBLK_OBJS(hhdr -> hb_sz);
+
+ if (0 == n_objs) n_objs = 1;
+ n_mark_words = divWORDSZ(n_objs + WORDSZ - 1);
+# else /* MARK_BIT_PER_GRANULE */
+ n_mark_words = MARK_BITS_SZ;
+# endif
+ for (i = 0; i < n_mark_words - 1; i++) {
result += set_bits(hhdr -> hb_marks[i]);
}
- return(result);
+# ifdef MARK_BIT_PER_OBJ
+ result += set_bits((hhdr -> hb_marks[n_mark_words - 1])
+ << (n_mark_words * WORDSZ - n_objs));
+# else
+ result += set_bits(hhdr -> hb_marks[n_mark_words - 1]);
+# endif
+ return(result - 1);
}
#endif /* !USE_MARK_BYTES */
-/*ARGSUSED*/
-# if defined(__STDC__) || defined(__cplusplus)
- void GC_print_block_descr(struct hblk *h, word dummy)
-# else
- void GC_print_block_descr(h, dummy)
- struct hblk *h;
- word dummy;
-# endif
+STATIC void GC_print_block_descr(struct hblk *h,
+ word /* struct PrintStats */ raw_ps)
{
- register hdr * hhdr = HDR(h);
- register size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz);
+ hdr * hhdr = HDR(h);
+ size_t bytes = hhdr -> hb_sz;
struct Print_stats *ps;
-
- GC_printf3("(%lu:%lu,%lu)", (unsigned long)(hhdr -> hb_obj_kind),
- (unsigned long)bytes,
- (unsigned long)(GC_n_set_marks(hhdr)));
+ unsigned n_marks = GC_n_set_marks(hhdr);
+
+ if (hhdr -> hb_n_marks != n_marks) {
+ GC_printf("(%u:%u,%u!=%u)\n", hhdr->hb_obj_kind, (unsigned)bytes,
+ (unsigned)hhdr->hb_n_marks, n_marks);
+ } else {
+ GC_printf("(%u:%u,%u)\n", hhdr->hb_obj_kind,
+ (unsigned)bytes, n_marks);
+ }
bytes += HBLKSIZE-1;
bytes &= ~(HBLKSIZE-1);
- ps = (struct Print_stats *)dummy;
+ ps = (struct Print_stats *)raw_ps;
ps->total_bytes += bytes;
ps->number_of_blocks++;
}
-void GC_print_block_list()
+void GC_print_block_list(void)
{
struct Print_stats pstats;
- GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n");
+ GC_printf("(kind(0=ptrfree,1=normal,2=unc.):size_in_bytes, #_marks_set)\n");
pstats.number_of_blocks = 0;
pstats.total_bytes = 0;
GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
- GC_printf2("\nblocks = %lu, bytes = %lu\n",
- (unsigned long)pstats.number_of_blocks,
- (unsigned long)pstats.total_bytes);
+ GC_printf("blocks= %lu, bytes= %lu\n",
+ (unsigned long)pstats.number_of_blocks,
+ (unsigned long)pstats.total_bytes);
+}
+
+/* Currently for debugger use only: */
+void GC_print_free_list(int kind, size_t sz_in_granules)
+{
+ struct obj_kind * ok = &GC_obj_kinds[kind];
+ ptr_t flh = ok -> ok_freelist[sz_in_granules];
+ int n;
+
+ for (n = 0; flh; n++) {
+ struct hblk *block = HBLKPTR(flh);
+ GC_printf("Free object in heap block %p [%d]: %p\n",
+ (void *)block, n, flh);
+ flh = obj_link(flh);
+ }
}
-#endif /* NO_DEBUGGING */
+#endif /* !NO_DEBUGGING */
/*
* Clear all obj_link pointers in the list of free objects *flp.
@@ -906,10 +583,9 @@ void GC_print_block_list()
* since may otherwise end up with dangling "descriptor" pointers.
* It may help for other pointer-containing objects.
*/
-void GC_clear_fl_links(flp)
-ptr_t *flp;
+STATIC void GC_clear_fl_links(void **flp)
{
- ptr_t next = *flp;
+ void *next = *flp;
while (0 != next) {
*flp = 0;
@@ -922,61 +598,60 @@ ptr_t *flp;
* Perform GC_reclaim_block on the entire heap, after first clearing
* small object free lists (if we are not just looking for leaks).
*/
-void GC_start_reclaim(report_if_found)
-int report_if_found; /* Abort if a GC_reclaimable object is found */
+GC_INNER void GC_start_reclaim(GC_bool report_if_found)
{
- int kind;
-
-# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
+ unsigned kind;
+
+# if defined(PARALLEL_MARK)
GC_ASSERT(0 == GC_fl_builder_count);
# endif
+ /* Reset in use counters. GC_reclaim_block recomputes them. */
+ GC_composite_in_use = 0;
+ GC_atomic_in_use = 0;
/* Clear reclaim- and free-lists */
for (kind = 0; kind < GC_n_kinds; kind++) {
- ptr_t *fop;
- ptr_t *lim;
- struct hblk ** rlp;
- struct hblk ** rlim;
+ void **fop;
+ void **lim;
struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
- GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0);
-
- if (rlist == 0) continue; /* This kind not used. */
+ GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0);
+
+ if (rlist == 0) continue; /* This kind not used. */
if (!report_if_found) {
- lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]);
- for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) {
- if (*fop != 0) {
- if (should_clobber) {
- GC_clear_fl_links(fop);
- } else {
- *fop = 0;
- }
- }
- }
- } /* otherwise free list objects are marked, */
- /* and its safe to leave them */
- rlim = rlist + MAXOBJSZ+1;
- for( rlp = rlist; rlp < rlim; rlp++ ) {
- *rlp = 0;
- }
+ lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJGRANULES+1]);
+ for (fop = GC_obj_kinds[kind].ok_freelist;
+ (word)fop < (word)lim; fop++) {
+ if (*fop != 0) {
+ if (should_clobber) {
+ GC_clear_fl_links(fop);
+ } else {
+ *fop = 0;
+ }
+ }
+ }
+ } /* otherwise free list objects are marked, */
+ /* and its safe to leave them */
+ BZERO(rlist, (MAXOBJGRANULES + 1) * sizeof(void *));
}
-
-# ifdef PRINTBLOCKS
- GC_printf0("GC_reclaim: current block sizes:\n");
- GC_print_block_list();
-# endif
+
/* Go through all heap blocks (in hblklist) and reclaim unmarked objects */
- /* or enqueue the block for later processing. */
+ /* or enqueue the block for later processing. */
GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found);
# ifdef EAGER_SWEEP
- /* This is a very stupid thing to do. We make it possible anyway, */
- /* so that you can convince yourself that it really is very stupid. */
+ /* This is a very stupid thing to do. We make it possible anyway, */
+ /* so that you can convince yourself that it really is very stupid. */
GC_reclaim_all((GC_stop_func)0, FALSE);
+# elif defined(ENABLE_DISCLAIM)
+ /* However, make sure to clear reclaimable objects of kinds with */
+ /* unconditional marking enabled before we do any significant */
+ /* marking work. */
+ GC_reclaim_unconditionally_marked();
# endif
-# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
+# if defined(PARALLEL_MARK)
GC_ASSERT(0 == GC_fl_builder_count);
# endif
-
+
}
/*
@@ -984,22 +659,20 @@ int report_if_found; /* Abort if a GC_reclaimable object is found */
* appropriate free list is nonempty, or there are no more blocks to
* sweep.
*/
-void GC_continue_reclaim(sz, kind)
-word sz; /* words */
-int kind;
+GC_INNER void GC_continue_reclaim(size_t sz /* granules */, int kind)
{
- register hdr * hhdr;
- register struct hblk * hbp;
- register struct obj_kind * ok = &(GC_obj_kinds[kind]);
+ hdr * hhdr;
+ struct hblk * hbp;
+ struct obj_kind * ok = &(GC_obj_kinds[kind]);
struct hblk ** rlh = ok -> ok_reclaim_list;
- ptr_t *flh = &(ok -> ok_freelist[sz]);
-
- if (rlh == 0) return; /* No blocks of this kind. */
+ void **flh = &(ok -> ok_freelist[sz]);
+
+ if (rlh == 0) return; /* No blocks of this kind. */
rlh += sz;
while ((hbp = *rlh) != 0) {
hhdr = HDR(hbp);
*rlh = hhdr -> hb_next;
- GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR);
+ GC_reclaim_small_nonempty_block(hbp, FALSE);
if (*flh != 0) break;
}
}
@@ -1009,53 +682,88 @@ int kind;
* Abort and return FALSE when/if (*stop_func)() returns TRUE.
* If this returns TRUE, then it's safe to restart the world
* with incorrectly cleared mark bits.
- * If ignore_old is TRUE, then reclaim only blocks that have been
+ * If ignore_old is TRUE, then reclaim only blocks that have been
* recently reclaimed, and discard the rest.
* Stop_func may be 0.
*/
-GC_bool GC_reclaim_all(stop_func, ignore_old)
-GC_stop_func stop_func;
-GC_bool ignore_old;
+GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
{
- register word sz;
- register int kind;
- register hdr * hhdr;
- register struct hblk * hbp;
- register struct obj_kind * ok;
+ word sz;
+ unsigned kind;
+ hdr * hhdr;
+ struct hblk * hbp;
+ struct obj_kind * ok;
struct hblk ** rlp;
struct hblk ** rlh;
-# ifdef PRINTTIMES
- CLOCK_TYPE start_time;
- CLOCK_TYPE done_time;
-
- GET_TIME(start_time);
+# ifndef SMALL_CONFIG
+ CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
+ CLOCK_TYPE done_time;
+
+ if (GC_print_stats == VERBOSE)
+ GET_TIME(start_time);
# endif
-
+
for (kind = 0; kind < GC_n_kinds; kind++) {
- ok = &(GC_obj_kinds[kind]);
- rlp = ok -> ok_reclaim_list;
- if (rlp == 0) continue;
- for (sz = 1; sz <= MAXOBJSZ; sz++) {
- rlh = rlp + sz;
- while ((hbp = *rlh) != 0) {
- if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
- return(FALSE);
- }
- hhdr = HDR(hbp);
- *rlh = hhdr -> hb_next;
- if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) {
- /* It's likely we'll need it this time, too */
- /* It's been touched recently, so this */
- /* shouldn't trigger paging. */
- GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR);
- }
+ ok = &(GC_obj_kinds[kind]);
+ rlp = ok -> ok_reclaim_list;
+ if (rlp == 0) continue;
+ for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
+ rlh = rlp + sz;
+ while ((hbp = *rlh) != 0) {
+ if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
+ return(FALSE);
+ }
+ hhdr = HDR(hbp);
+ *rlh = hhdr -> hb_next;
+ if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) {
+ /* It's likely we'll need it this time, too */
+ /* It's been touched recently, so this */
+ /* shouldn't trigger paging. */
+ GC_reclaim_small_nonempty_block(hbp, FALSE);
+ }
}
}
}
-# ifdef PRINTTIMES
- GET_TIME(done_time);
- GC_printf1("Disposing of reclaim lists took %lu msecs\n",
- MS_TIME_DIFF(done_time,start_time));
+# ifndef SMALL_CONFIG
+ if (GC_print_stats == VERBOSE) {
+ GET_TIME(done_time);
+ GC_verbose_log_printf("Disposing of reclaim lists took %lu msecs\n",
+ MS_TIME_DIFF(done_time,start_time));
+ }
# endif
return(TRUE);
}
+
+#if !defined(EAGER_SWEEP) && defined(ENABLE_DISCLAIM)
+/* We do an eager sweep on heap blocks where unconditional marking has */
+/* been enabled, so that any reclaimable objects have been reclaimed */
+/* before we start marking. This is a simplified GC_reclaim_all */
+/* restricted to kinds where ok_mark_unconditionally is true. */
+ STATIC void GC_reclaim_unconditionally_marked(void)
+ {
+ word sz;
+ unsigned kind;
+ hdr * hhdr;
+ struct hblk * hbp;
+ struct obj_kind * ok;
+ struct hblk ** rlp;
+ struct hblk ** rlh;
+
+ for (kind = 0; kind < GC_n_kinds; kind++) {
+ ok = &(GC_obj_kinds[kind]);
+ if (!ok->ok_mark_unconditionally)
+ continue;
+ rlp = ok->ok_reclaim_list;
+ if (rlp == 0)
+ continue;
+ for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
+ rlh = rlp + sz;
+ while ((hbp = *rlh) != 0) {
+ hhdr = HDR(hbp);
+ *rlh = hhdr->hb_next;
+ GC_reclaim_small_nonempty_block(hbp, FALSE);
+ }
+ }
+ }
+ }
+#endif /* !EAGER_SWEEP && ENABLE_DISCLAIM */
diff --git a/boehm-gc/rs6000_mach_dep.s b/boehm-gc/rs6000_mach_dep.s
deleted file mode 100644
index 12bf9a84d51..00000000000
--- a/boehm-gc/rs6000_mach_dep.s
+++ /dev/null
@@ -1,114 +0,0 @@
- .set r0,0
- .set r1,1
- .set r2,2
- .set r3,3
- .set r4,4
- .set r5,5
- .set r6,6
- .set r7,7
- .set r8,8
- .set r9,9
- .set r10,10
- .set r11,11
- .set r12,12
- .set r13,13
- .set r14,14
- .set r15,15
- .set r16,16
- .set r17,17
- .set r18,18
- .set r19,19
- .set r20,20
- .set r21,21
- .set r22,22
- .set r23,23
- .set r24,24
- .set r25,25
- .set r26,26
- .set r27,27
- .set r28,28
- .set r29,29
- .set r30,30
- .set r31,31
-
- .extern .GC_push_one
- # Mark from machine registers that are saved by C compiler
- .globl .GC_push_regs
-.csect .text[PR]
- .align 2
- .globl GC_push_regs
- .globl .GC_push_regs
-.csect GC_push_regs[DS]
-GC_push_regs:
- .long .GC_push_regs, TOC[tc0], 0
-.csect .text[PR]
-.GC_push_regs:
- stu r1,-64(r1) # reserve stack frame
- mflr r0 # save link register
- st r0,0x48(r1)
- oril r3,r2,0x0 # mark from r2
- bl .GC_push_one
- cror 15,15,15
- oril r3,r13,0x0 # mark from r13-r31
- bl .GC_push_one
- cror 15,15,15
- oril r3,r14,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r15,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r16,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r17,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r18,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r19,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r20,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r21,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r22,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r23,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r24,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r25,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r26,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r27,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r28,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r29,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r30,0x0
- bl .GC_push_one
- cror 15,15,15
- oril r3,r31,0x0
- bl .GC_push_one
- cror 15,15,15
- l r0,0x48(r1)
- mtlr r0
- ai r1,r1,64
- br
- .long 0
- .byte 0,0,0,0,0,0,0,0
diff --git a/boehm-gc/setjmp_t.c b/boehm-gc/setjmp_t.c
deleted file mode 100644
index 07686ef0808..00000000000
--- a/boehm-gc/setjmp_t.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-
-/* Check whether setjmp actually saves registers in jmp_buf. */
-/* If it doesn't, the generic mark_regs code won't work. */
-/* Compilers vary as to whether they will put x in a */
-/* (callee-save) register without -O. The code is */
-/* contrived such that any decent compiler should put x in */
-/* a callee-save register with -O. Thus it is is */
-/* recommended that this be run optimized. (If the machine */
-/* has no callee-save registers, then the generic code is */
-/* safe, but this will not be noticed by this piece of */
-/* code.) This test appears to be far from perfect. */
-#include <stdio.h>
-#include <setjmp.h>
-#include <string.h>
-#include "private/gcconfig.h"
-
-#ifdef OS2
-/* GETPAGESIZE() is set to getpagesize() by default, but that */
-/* doesn't really exist, and the collector doesn't need it. */
-#define INCL_DOSFILEMGR
-#define INCL_DOSMISC
-#define INCL_DOSERRORS
-#include <os2.h>
-
-int
-getpagesize()
-{
- ULONG result[1];
-
- if (DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE,
- (void *)result, sizeof(ULONG)) != NO_ERROR) {
- fprintf(stderr, "DosQuerySysInfo failed\n");
- result[0] = 4096;
- }
- return((int)(result[0]));
-}
-#endif
-
-struct {char a_a; char * a_b;} a;
-
-int * nested_sp()
-{
- int dummy;
-
- return(&dummy);
-}
-
-main()
-{
- int dummy;
- long ps = GETPAGESIZE();
- jmp_buf b;
- register int x = (int)strlen("a"); /* 1, slightly disguised */
- static int y = 0;
-
- printf("This appears to be a %s running %s\n", MACH_TYPE, OS_TYPE);
- if (nested_sp() < &dummy) {
- printf("Stack appears to grow down, which is the default.\n");
- printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
- ((unsigned long)(&dummy) + ps) & ~(ps-1));
- } else {
- printf("Stack appears to grow up.\n");
- printf("Define STACK_GROWS_UP in gc_private.h\n");
- printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
- ((unsigned long)(&dummy) + ps) & ~(ps-1));
- }
- printf("Note that this may vary between machines of ostensibly\n");
- printf("the same architecture (e.g. Sun 3/50s and 3/80s).\n");
- printf("On many machines the value is not fixed.\n");
- printf("A good guess for ALIGNMENT on this machine is %ld.\n",
- (unsigned long)(&(a.a_b))-(unsigned long)(&a));
-
- /* Encourage the compiler to keep x in a callee-save register */
- x = 2*x-1;
- printf("");
- x = 2*x-1;
- setjmp(b);
- if (y == 1) {
- if (x == 2) {
- printf("Generic mark_regs code probably wont work\n");
-# if defined(SPARC) || defined(RS6000) || defined(VAX) || defined(MIPS) || defined(M68K) || defined(I386) || defined(NS32K) || defined(RT)
- printf("Assembly code supplied\n");
-# else
- printf("Need assembly code\n");
-# endif
- } else if (x == 1) {
- printf("Generic mark_regs code may work\n");
- } else {
- printf("Very strange setjmp implementation\n");
- }
- }
- y++;
- x = 2;
- if (y == 1) longjmp(b,1);
- return(0);
-}
-
-int g(x)
-int x;
-{
- return(x);
-}
diff --git a/boehm-gc/solaris_pthreads.c b/boehm-gc/solaris_pthreads.c
deleted file mode 100644
index 1e43d0904f9..00000000000
--- a/boehm-gc/solaris_pthreads.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/*
- * Support code for Solaris threads. Provides functionality we wish Sun
- * had provided. Relies on some information we probably shouldn't rely on.
- * Modified by Peter C. for Solaris Posix Threads.
- */
-
-# if defined(GC_SOLARIS_PTHREADS) || defined(GC_THREADS)
-# include "private/gc_priv.h"
-# endif
-# if defined(GC_SOLARIS_PTHREADS)
-# include <pthread.h>
-# include <thread.h>
-# include <signal.h>
-# include <fcntl.h>
-# include <sys/types.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-# include <sys/resource.h>
-# include <sys/stat.h>
-# include <sys/syscall.h>
-# include <sys/procfs.h>
-# include <sys/lwp.h>
-# include <sys/reg.h>
-# define _CLASSIC_XOPEN_TYPES
-# include <unistd.h>
-# include <errno.h>
-# include "private/solaris_threads.h"
-# include <stdio.h>
-
-#undef pthread_join
-#undef pthread_create
-
-pthread_cond_t GC_prom_join_cv; /* Broadcast when any thread terminates */
-pthread_cond_t GC_create_cv; /* Signalled when a new undetached */
- /* thread starts. */
-
-extern GC_bool GC_multithreaded;
-
-/* We use the allocation lock to protect thread-related data structures. */
-
-/* We stop the world using /proc primitives. This makes some */
-/* minimal assumptions about the threads implementation. */
-/* We don't play by the rules, since the rules make this */
-/* impossible (as of Solaris 2.3). Also note that as of */
-/* Solaris 2.3 the various thread and lwp suspension */
-/* primitives failed to stop threads by the time the request */
-/* is completed. */
-
-
-
-int GC_pthread_join(pthread_t wait_for, void **status)
-{
- return GC_thr_join((thread_t)wait_for, NULL, status);
-}
-
-
-int
-GC_pthread_create(pthread_t *new_thread,
- const pthread_attr_t *attr_in,
- void * (*thread_execp)(void *), void *arg)
-{
- int result;
- GC_thread t;
- pthread_t my_new_thread;
- pthread_attr_t attr;
- word my_flags = 0;
- int flag;
- void * stack = 0;
- size_t stack_size = 0;
- int n;
- struct sched_param schedparam;
-
- (void)pthread_attr_init(&attr);
- if (attr_in != 0) {
- (void)pthread_attr_getstacksize(attr_in, &stack_size);
- (void)pthread_attr_getstackaddr(attr_in, &stack);
- }
-
- LOCK();
- if (!GC_is_initialized) {
- GC_init_inner();
- }
- GC_multithreaded++;
-
- if (stack == 0) {
- if (stack_size == 0)
- stack_size = 1048576;
- /* ^-- 1 MB (this was GC_min_stack_sz, but that
- * violates the pthread_create documentation which
- * says the default value if none is supplied is
- * 1MB) */
- else
- stack_size += thr_min_stack();
-
- stack = (void *)GC_stack_alloc(&stack_size);
- if (stack == 0) {
- GC_multithreaded--;
- UNLOCK();
- errno = ENOMEM;
- return -1;
- }
- } else {
- my_flags |= CLIENT_OWNS_STACK;
- }
- (void)pthread_attr_setstacksize(&attr, stack_size);
- (void)pthread_attr_setstackaddr(&attr, stack);
- if (attr_in != 0) {
- (void)pthread_attr_getscope(attr_in, &n);
- (void)pthread_attr_setscope(&attr, n);
- (void)pthread_attr_getschedparam(attr_in, &schedparam);
- (void)pthread_attr_setschedparam(&attr, &schedparam);
- (void)pthread_attr_getschedpolicy(attr_in, &n);
- (void)pthread_attr_setschedpolicy(&attr, n);
- (void)pthread_attr_getinheritsched(attr_in, &n);
- (void)pthread_attr_setinheritsched(&attr, n);
-
- (void)pthread_attr_getdetachstate(attr_in, &flag);
- if (flag == PTHREAD_CREATE_DETACHED) {
- my_flags |= DETACHED;
- }
- (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- }
- /*
- * thr_create can call malloc(), which if redirected will
- * attempt to acquire the allocation lock.
- * Unlock here to prevent deadlock.
- */
-
-
-#if 0
-#ifdef I386
- UNLOCK();
-#endif
-#endif
- result =
- pthread_create(&my_new_thread, &attr, thread_execp, arg);
-#if 0
-#ifdef I386
- LOCK();
-#endif
-#endif
- if (result == 0) {
- t = GC_new_thread(my_new_thread);
- t -> flags = my_flags;
- if (!(my_flags & DETACHED)) cond_init(&(t->join_cv), USYNC_THREAD, 0);
- t -> stack = stack;
- t -> stack_size = stack_size;
- if (new_thread != 0) *new_thread = my_new_thread;
- pthread_cond_signal(&GC_create_cv);
- } else {
- if (!(my_flags & CLIENT_OWNS_STACK)) {
- GC_stack_free(stack, stack_size);
- }
- GC_multithreaded--;
- }
- UNLOCK();
- pthread_attr_destroy(&attr);
- return(result);
-}
-
-# else
-
-#ifndef LINT
- int GC_no_sunOS_pthreads;
-#endif
-
-# endif /* GC_SOLARIS_PTHREADS */
-
diff --git a/boehm-gc/solaris_threads.c b/boehm-gc/solaris_threads.c
deleted file mode 100644
index 0a07690a27a..00000000000
--- a/boehm-gc/solaris_threads.c
+++ /dev/null
@@ -1,962 +0,0 @@
-/*
- * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/*
- * Support code for Solaris threads. Provides functionality we wish Sun
- * had provided. Relies on some information we probably shouldn't rely on.
- */
-/* Boehm, September 14, 1994 4:44 pm PDT */
-
-# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS) \
- || defined(GC_THREADS)
-# include "private/gc_priv.h"
-# endif
-
-# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS)
-# include "private/solaris_threads.h"
-# include <thread.h>
-# include <synch.h>
-# include <signal.h>
-# include <fcntl.h>
-# include <sys/types.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-# include <sys/resource.h>
-# include <sys/stat.h>
-# include <sys/syscall.h>
-# include <sys/procfs.h>
-# include <sys/lwp.h>
-# include <sys/reg.h>
-# define _CLASSIC_XOPEN_TYPES
-# include <unistd.h>
-# include <errno.h>
-
-#ifdef HANDLE_FORK
- --> Not yet supported. Try porting the code from linux_threads.c.
-#endif
-
-/*
- * This is the default size of the LWP arrays. If there are more LWPs
- * than this when a stop-the-world GC happens, set_max_lwps will be
- * called to cope.
- * This must be higher than the number of LWPs at startup time.
- * The threads library creates a thread early on, so the min. is 3
- */
-# define DEFAULT_MAX_LWPS 4
-
-#undef thr_join
-#undef thr_create
-#undef thr_suspend
-#undef thr_continue
-
-cond_t GC_prom_join_cv; /* Broadcast when any thread terminates */
-cond_t GC_create_cv; /* Signalled when a new undetached */
- /* thread starts. */
-
-
-#ifdef MMAP_STACKS
-static int GC_zfd;
-#endif /* MMAP_STACKS */
-
-/* We use the allocation lock to protect thread-related data structures. */
-
-/* We stop the world using /proc primitives. This makes some */
-/* minimal assumptions about the threads implementation. */
-/* We don't play by the rules, since the rules make this */
-/* impossible (as of Solaris 2.3). Also note that as of */
-/* Solaris 2.3 the various thread and lwp suspension */
-/* primitives failed to stop threads by the time the request */
-/* is completed. */
-
-
-static sigset_t old_mask;
-
-/* Sleep for n milliseconds, n < 1000 */
-void GC_msec_sleep(int n)
-{
- struct timespec ts;
-
- ts.tv_sec = 0;
- ts.tv_nsec = 1000000*n;
- if (syscall(SYS_nanosleep, &ts, 0) < 0) {
- ABORT("nanosleep failed");
- }
-}
-/* Turn off preemption; gross but effective. */
-/* Caller has allocation lock. */
-/* Actually this is not needed under Solaris 2.3 and */
-/* 2.4, but hopefully that'll change. */
-void preempt_off()
-{
- sigset_t set;
-
- (void)sigfillset(&set);
- sigdelset(&set, SIGABRT);
- syscall(SYS_sigprocmask, SIG_SETMASK, &set, &old_mask);
-}
-
-void preempt_on()
-{
- syscall(SYS_sigprocmask, SIG_SETMASK, &old_mask, NULL);
-}
-
-int GC_main_proc_fd = -1;
-
-
-struct lwp_cache_entry {
- lwpid_t lc_id;
- int lc_descr; /* /proc file descriptor. */
-} GC_lwp_cache_default[DEFAULT_MAX_LWPS];
-
-static int max_lwps = DEFAULT_MAX_LWPS;
-static struct lwp_cache_entry *GC_lwp_cache = GC_lwp_cache_default;
-
-static prgregset_t GC_lwp_registers_default[DEFAULT_MAX_LWPS];
-static prgregset_t *GC_lwp_registers = GC_lwp_registers_default;
-
-/* Return a file descriptor for the /proc entry corresponding */
-/* to the given lwp. The file descriptor may be stale if the */
-/* lwp exited and a new one was forked. */
-static int open_lwp(lwpid_t id)
-{
- int result;
- static int next_victim = 0;
- register int i;
-
- for (i = 0; i < max_lwps; i++) {
- if (GC_lwp_cache[i].lc_id == id) return(GC_lwp_cache[i].lc_descr);
- }
- result = syscall(SYS_ioctl, GC_main_proc_fd, PIOCOPENLWP, &id);
- /*
- * If PIOCOPENLWP fails, try closing fds in the cache until it succeeds.
- */
- if (result < 0 && errno == EMFILE) {
- for (i = 0; i < max_lwps; i++) {
- if (GC_lwp_cache[i].lc_id != 0) {
- (void)syscall(SYS_close, GC_lwp_cache[i].lc_descr);
- result = syscall(SYS_ioctl, GC_main_proc_fd, PIOCOPENLWP, &id);
- if (result >= 0 || (result < 0 && errno != EMFILE))
- break;
- }
- }
- }
- if (result < 0) {
- if (errno == EMFILE) {
- ABORT("Too many open files");
- }
- return(-1) /* exited? */;
- }
- if (GC_lwp_cache[next_victim].lc_id != 0)
- (void)syscall(SYS_close, GC_lwp_cache[next_victim].lc_descr);
- GC_lwp_cache[next_victim].lc_id = id;
- GC_lwp_cache[next_victim].lc_descr = result;
- if (++next_victim >= max_lwps)
- next_victim = 0;
- return(result);
-}
-
-static void uncache_lwp(lwpid_t id)
-{
- register int i;
-
- for (i = 0; i < max_lwps; i++) {
- if (GC_lwp_cache[i].lc_id == id) {
- (void)syscall(SYS_close, GC_lwp_cache[id].lc_descr);
- GC_lwp_cache[i].lc_id = 0;
- break;
- }
- }
-}
- /* Sequence of current lwp ids */
-static lwpid_t GC_current_ids_default[DEFAULT_MAX_LWPS + 1];
-static lwpid_t *GC_current_ids = GC_current_ids_default;
-
- /* Temporary used below (can be big if large number of LWPs) */
-static lwpid_t last_ids_default[DEFAULT_MAX_LWPS + 1];
-static lwpid_t *last_ids = last_ids_default;
-
-
-#define ROUNDUP(n) WORDS_TO_BYTES(ROUNDED_UP_WORDS(n))
-
-static void set_max_lwps(GC_word n)
-{
- char *mem;
- char *oldmem;
- int required_bytes = ROUNDUP(n * sizeof(struct lwp_cache_entry))
- + ROUNDUP(n * sizeof(prgregset_t))
- + ROUNDUP((n + 1) * sizeof(lwpid_t))
- + ROUNDUP((n + 1) * sizeof(lwpid_t));
-
- GC_expand_hp_inner(divHBLKSZ((word)required_bytes));
- oldmem = mem = GC_scratch_alloc(required_bytes);
- if (0 == mem) ABORT("No space for lwp data structures");
-
- /*
- * We can either flush the old lwp cache or copy it over. Do the latter.
- */
- memcpy(mem, GC_lwp_cache, max_lwps * sizeof(struct lwp_cache_entry));
- GC_lwp_cache = (struct lwp_cache_entry*)mem;
- mem += ROUNDUP(n * sizeof(struct lwp_cache_entry));
-
- BZERO(GC_lwp_registers, max_lwps * sizeof(GC_lwp_registers[0]));
- GC_lwp_registers = (prgregset_t *)mem;
- mem += ROUNDUP(n * sizeof(prgregset_t));
-
-
- GC_current_ids = (lwpid_t *)mem;
- mem += ROUNDUP((n + 1) * sizeof(lwpid_t));
-
- last_ids = (lwpid_t *)mem;
- mem += ROUNDUP((n + 1)* sizeof(lwpid_t));
-
- if (mem > oldmem + required_bytes)
- ABORT("set_max_lwps buffer overflow");
-
- max_lwps = n;
-}
-
-
-/* Stop all lwps in process. Assumes preemption is off. */
-/* Caller has allocation lock (and any other locks he may */
-/* need). */
-static void stop_all_lwps()
-{
- int lwp_fd;
- char buf[30];
- prstatus_t status;
- register int i;
- GC_bool changed;
- lwpid_t me = _lwp_self();
-
- if (GC_main_proc_fd == -1) {
- sprintf(buf, "/proc/%d", getpid());
- GC_main_proc_fd = syscall(SYS_open, buf, O_RDONLY);
- if (GC_main_proc_fd < 0) {
- if (errno == EMFILE)
- ABORT("/proc open failed: too many open files");
- GC_printf1("/proc open failed: errno %d", errno);
- abort();
- }
- }
- BZERO(GC_lwp_registers, sizeof (prgregset_t) * max_lwps);
- for (i = 0; i < max_lwps; i++)
- last_ids[i] = 0;
- for (;;) {
- if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0)
- ABORT("Main PIOCSTATUS failed");
- if (status.pr_nlwp < 1)
- ABORT("Invalid number of lwps returned by PIOCSTATUS");
- if (status.pr_nlwp >= max_lwps) {
- set_max_lwps(status.pr_nlwp*2 + 10);
- /*
- * The data in the old GC_current_ids and
- * GC_lwp_registers has been trashed. Cleaning out last_ids
- * will make sure every LWP gets re-examined.
- */
- for (i = 0; i < max_lwps; i++)
- last_ids[i] = 0;
- continue;
- }
- if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCLWPIDS, GC_current_ids) < 0)
- ABORT("PIOCLWPIDS failed");
- changed = FALSE;
- for (i = 0; GC_current_ids[i] != 0 && i < max_lwps; i++) {
- if (GC_current_ids[i] != last_ids[i]) {
- changed = TRUE;
- if (GC_current_ids[i] != me) {
- /* PIOCSTOP doesn't work without a writable */
- /* descriptor. And that makes the process */
- /* undebuggable. */
- if (_lwp_suspend(GC_current_ids[i]) < 0) {
- /* Could happen if the lwp exited */
- uncache_lwp(GC_current_ids[i]);
- GC_current_ids[i] = me; /* ignore */
- }
- }
- }
- }
- /*
- * In the unlikely event something does a fork between the
- * PIOCSTATUS and the PIOCLWPIDS.
- */
- if (i >= max_lwps)
- continue;
- /* All lwps in GC_current_ids != me have been suspended. Note */
- /* that _lwp_suspend is idempotent. */
- for (i = 0; GC_current_ids[i] != 0; i++) {
- if (GC_current_ids[i] != last_ids[i]) {
- if (GC_current_ids[i] != me) {
- lwp_fd = open_lwp(GC_current_ids[i]);
- if (lwp_fd == -1)
- {
- GC_current_ids[i] = me;
- continue;
- }
- /* LWP should be stopped. Empirically it sometimes */
- /* isn't, and more frequently the PR_STOPPED flag */
- /* is not set. Wait for PR_STOPPED. */
- if (syscall(SYS_ioctl, lwp_fd,
- PIOCSTATUS, &status) < 0) {
- /* Possible if the descriptor was stale, or */
- /* we encountered the 2.3 _lwp_suspend bug. */
- uncache_lwp(GC_current_ids[i]);
- GC_current_ids[i] = me; /* handle next time. */
- } else {
- while (!(status.pr_flags & PR_STOPPED)) {
- GC_msec_sleep(1);
- if (syscall(SYS_ioctl, lwp_fd,
- PIOCSTATUS, &status) < 0) {
- ABORT("Repeated PIOCSTATUS failed");
- }
- if (status.pr_flags & PR_STOPPED) break;
-
- GC_msec_sleep(20);
- if (syscall(SYS_ioctl, lwp_fd,
- PIOCSTATUS, &status) < 0) {
- ABORT("Repeated PIOCSTATUS failed");
- }
- }
- if (status.pr_who != GC_current_ids[i]) {
- /* can happen if thread was on death row */
- uncache_lwp(GC_current_ids[i]);
- GC_current_ids[i] = me; /* handle next time. */
- continue;
- }
- /* Save registers where collector can */
- /* find them. */
- BCOPY(status.pr_reg, GC_lwp_registers[i],
- sizeof (prgregset_t));
- }
- }
- }
- }
- if (!changed) break;
- for (i = 0; i < max_lwps; i++) last_ids[i] = GC_current_ids[i];
- }
-}
-
-/* Restart all lwps in process. Assumes preemption is off. */
-static void restart_all_lwps()
-{
- int lwp_fd;
- register int i;
- GC_bool changed;
- lwpid_t me = _lwp_self();
-# define PARANOID
-
- for (i = 0; GC_current_ids[i] != 0; i++) {
-# ifdef PARANOID
- if (GC_current_ids[i] != me) {
- int lwp_fd = open_lwp(GC_current_ids[i]);
- prstatus_t status;
-
- if (lwp_fd < 0) ABORT("open_lwp failed");
- if (syscall(SYS_ioctl, lwp_fd,
- PIOCSTATUS, &status) < 0) {
- ABORT("PIOCSTATUS failed in restart_all_lwps");
- }
- if (memcmp(status.pr_reg, GC_lwp_registers[i],
- sizeof (prgregset_t)) != 0) {
- int j;
-
- for(j = 0; j < NPRGREG; j++)
- {
- GC_printf3("%i: %x -> %x\n", j,
- GC_lwp_registers[i][j],
- status.pr_reg[j]);
- }
- ABORT("Register contents changed");
- }
- if (!status.pr_flags & PR_STOPPED) {
- ABORT("lwp no longer stopped");
- }
-#ifdef SPARC
- {
- gwindows_t windows;
- if (syscall(SYS_ioctl, lwp_fd,
- PIOCGWIN, &windows) < 0) {
- ABORT("PIOCSTATUS failed in restart_all_lwps");
- }
- if (windows.wbcnt > 0) ABORT("unsaved register windows");
- }
-#endif
- }
-# endif /* PARANOID */
- if (GC_current_ids[i] == me) continue;
- if (_lwp_continue(GC_current_ids[i]) < 0) {
- ABORT("Failed to restart lwp");
- }
- }
- if (i >= max_lwps) ABORT("Too many lwps");
-}
-
-GC_bool GC_multithreaded = 0;
-
-void GC_stop_world()
-{
- preempt_off();
- if (GC_multithreaded)
- stop_all_lwps();
-}
-
-void GC_start_world()
-{
- if (GC_multithreaded)
- restart_all_lwps();
- preempt_on();
-}
-
-void GC_thr_init(void);
-
-GC_bool GC_thr_initialized = FALSE;
-
-size_t GC_min_stack_sz;
-
-
-/*
- * stack_head is stored at the top of free stacks
- */
-struct stack_head {
- struct stack_head *next;
- ptr_t base;
- thread_t owner;
-};
-
-# define N_FREE_LISTS 25
-struct stack_head *GC_stack_free_lists[N_FREE_LISTS] = { 0 };
- /* GC_stack_free_lists[i] is free list for stacks of */
- /* size GC_min_stack_sz*2**i. */
- /* Free lists are linked through stack_head stored */ /* at top of stack. */
-
-/* Return a stack of size at least *stack_size. *stack_size is */
-/* replaced by the actual stack size. */
-/* Caller holds allocation lock. */
-ptr_t GC_stack_alloc(size_t * stack_size)
-{
- register size_t requested_sz = *stack_size;
- register size_t search_sz = GC_min_stack_sz;
- register int index = 0; /* = log2(search_sz/GC_min_stack_sz) */
- register ptr_t base;
- register struct stack_head *result;
-
- while (search_sz < requested_sz) {
- search_sz *= 2;
- index++;
- }
- if ((result = GC_stack_free_lists[index]) == 0
- && (result = GC_stack_free_lists[index+1]) != 0) {
- /* Try next size up. */
- search_sz *= 2; index++;
- }
- if (result != 0) {
- base = GC_stack_free_lists[index]->base;
- GC_stack_free_lists[index] = GC_stack_free_lists[index]->next;
- } else {
-#ifdef MMAP_STACKS
- base = (ptr_t)mmap(0, search_sz + GC_page_size,
- PROT_READ|PROT_WRITE, MAP_PRIVATE |MAP_NORESERVE,
- GC_zfd, 0);
- if (base == (ptr_t)-1)
- {
- *stack_size = 0;
- return NULL;
- }
-
- mprotect(base, GC_page_size, PROT_NONE);
- /* Should this use divHBLKSZ(search_sz + GC_page_size) ? -- cf */
- GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz));
- base += GC_page_size;
-
-#else
- base = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_size);
- if (base == NULL)
- {
- *stack_size = 0;
- return NULL;
- }
-
- base = (ptr_t)(((word)base + GC_page_size) & ~(GC_page_size - 1));
- /* Protect hottest page to detect overflow. */
-# ifdef SOLARIS23_MPROTECT_BUG_FIXED
- mprotect(base, GC_page_size, PROT_NONE);
-# endif
- GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz));
-
- base += GC_page_size;
-#endif
- }
- *stack_size = search_sz;
- return(base);
-}
-
-/* Caller holds allocationlock. */
-void GC_stack_free(ptr_t stack, size_t size)
-{
- register int index = 0;
- register size_t search_sz = GC_min_stack_sz;
- register struct stack_head *head;
-
-#ifdef MMAP_STACKS
- /* Zero pointers */
- mmap(stack, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_NORESERVE|MAP_FIXED,
- GC_zfd, 0);
-#endif
- while (search_sz < size) {
- search_sz *= 2;
- index++;
- }
- if (search_sz != size) ABORT("Bad stack size");
-
- head = (struct stack_head *)(stack + search_sz - sizeof(struct stack_head));
- head->next = GC_stack_free_lists[index];
- head->base = stack;
- GC_stack_free_lists[index] = head;
-}
-
-void GC_my_stack_limits();
-
-/* Notify virtual dirty bit implementation that known empty parts of */
-/* stacks do not contain useful data. */
-/* Caller holds allocation lock. */
-void GC_old_stacks_are_fresh()
-{
-/* No point in doing this for MMAP stacks - and pointers are zero'd out */
-/* by the mmap in GC_stack_free */
-#ifndef MMAP_STACKS
- register int i;
- register struct stack_head *s;
- register ptr_t p;
- register size_t sz;
- register struct hblk * h;
- int dummy;
-
- for (i = 0, sz= GC_min_stack_sz; i < N_FREE_LISTS;
- i++, sz *= 2) {
- for (s = GC_stack_free_lists[i]; s != 0; s = s->next) {
- p = s->base;
- h = (struct hblk *)(((word)p + HBLKSIZE-1) & ~(HBLKSIZE-1));
- if ((ptr_t)h == p) {
- GC_is_fresh((struct hblk *)p, divHBLKSZ(sz));
- } else {
- GC_is_fresh((struct hblk *)p, divHBLKSZ(sz) - 1);
- BZERO(p, (ptr_t)h - p);
- }
- }
- }
-#endif /* MMAP_STACKS */
- GC_my_stack_limits();
-}
-
-/* The set of all known threads. We intercept thread creation and */
-/* joins. We never actually create detached threads. We allocate all */
-/* new thread stacks ourselves. These allow us to maintain this */
-/* data structure. */
-
-# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
-volatile GC_thread GC_threads[THREAD_TABLE_SZ];
-
-void GC_push_thread_structures GC_PROTO((void))
-{
- GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
-}
-
-/* Add a thread to GC_threads. We assume it wasn't already there. */
-/* Caller holds allocation lock. */
-GC_thread GC_new_thread(thread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- GC_thread result;
- static struct GC_Thread_Rep first_thread;
- static GC_bool first_thread_used = FALSE;
-
- if (!first_thread_used) {
- result = &first_thread;
- first_thread_used = TRUE;
- /* Dont acquire allocation lock, since we may already hold it. */
- } else {
- result = (struct GC_Thread_Rep *)
- GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
- }
- if (result == 0) return(0);
- result -> id = id;
- result -> next = GC_threads[hv];
- GC_threads[hv] = result;
- /* result -> finished = 0; */
- (void) cond_init(&(result->join_cv), USYNC_THREAD, 0);
- return(result);
-}
-
-/* Delete a thread from GC_threads. We assume it is there. */
-/* (The code intentionally traps if it wasn't.) */
-/* Caller holds allocation lock. */
-void GC_delete_thread(thread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (p -> id != id) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
-}
-
-/* Return the GC_thread correpsonding to a given thread_t. */
-/* Returns 0 if it's not there. */
-/* Caller holds allocation lock. */
-GC_thread GC_lookup_thread(thread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
-
- while (p != 0 && p -> id != id) p = p -> next;
- return(p);
-}
-
-/* Solaris 2/Intel uses an initial stack size limit slightly bigger than the
- SPARC default of 8 MB. Account for this to warn only if the user has
- raised the limit beyond the default.
-
- This is identical to DFLSSIZ defined in <sys/vm_machparam.h>. This file
- is installed in /usr/platform/`uname -m`/include, which is not in the
- default include directory list, so copy the definition here. */
-#ifdef I386
-# define MAX_ORIG_STACK_SIZE (8 * 1024 * 1024 + ((USRSTACK) & 0x3FFFFF))
-#else
-# define MAX_ORIG_STACK_SIZE (8 * 1024 * 1024)
-#endif
-
-word GC_get_orig_stack_size() {
- struct rlimit rl;
- static int warned = 0;
- int result;
-
- if (getrlimit(RLIMIT_STACK, &rl) != 0) ABORT("getrlimit failed");
- result = (word)rl.rlim_cur & ~(HBLKSIZE-1);
- if (result > MAX_ORIG_STACK_SIZE) {
- if (!warned) {
- WARN("Large stack limit(%ld): only scanning 8 MB\n", result);
- warned = 1;
- }
- result = MAX_ORIG_STACK_SIZE;
- }
- return result;
-}
-
-/* Notify dirty bit implementation of unused parts of my stack. */
-/* Caller holds allocation lock. */
-void GC_my_stack_limits()
-{
- int dummy;
- register ptr_t hottest = (ptr_t)((word)(&dummy) & ~(HBLKSIZE-1));
- register GC_thread me = GC_lookup_thread(thr_self());
- register size_t stack_size = me -> stack_size;
- register ptr_t stack;
-
- if (stack_size == 0) {
- /* original thread */
- /* Empirically, what should be the stack page with lowest */
- /* address is actually inaccessible. */
- stack_size = GC_get_orig_stack_size() - GC_page_size;
- stack = GC_stackbottom - stack_size + GC_page_size;
- } else {
- stack = me -> stack;
- }
- if (stack > hottest || stack + stack_size < hottest) {
- ABORT("sp out of bounds");
- }
- GC_is_fresh((struct hblk *)stack, divHBLKSZ(hottest - stack));
-}
-
-
-/* We hold allocation lock. Should do exactly the right thing if the */
-/* world is stopped. Should not fail if it isn't. */
-void GC_push_all_stacks()
-{
- register int i;
- register GC_thread p;
- register ptr_t sp = GC_approx_sp();
- register ptr_t bottom, top;
- struct rlimit rl;
-
-# define PUSH(bottom,top) \
- if (GC_dirty_maintained) { \
- GC_push_selected((bottom), (top), GC_page_was_ever_dirty, \
- GC_push_all_stack); \
- } else { \
- GC_push_all_stack((bottom), (top)); \
- }
- GC_push_all_stack((ptr_t)GC_lwp_registers,
- (ptr_t)GC_lwp_registers
- + max_lwps * sizeof(GC_lwp_registers[0]));
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> stack_size != 0) {
- bottom = p -> stack;
- top = p -> stack + p -> stack_size;
- } else {
- /* The original stack. */
- bottom = GC_stackbottom - GC_get_orig_stack_size() + GC_page_size;
- top = GC_stackbottom;
- }
- if ((word)sp > (word)bottom && (word)sp < (word)top) bottom = sp;
- PUSH(bottom, top);
- }
- }
-}
-
-
-int GC_is_thread_stack(ptr_t addr)
-{
- register int i;
- register GC_thread p;
- register ptr_t bottom, top;
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> stack_size != 0) {
- if (p -> stack <= addr &&
- addr < p -> stack + p -> stack_size)
- return 1;
- }
- }
- }
- return 0;
-}
-
-/* The only thread that ever really performs a thr_join. */
-void * GC_thr_daemon(void * dummy)
-{
- void *status;
- thread_t departed;
- register GC_thread t;
- register int i;
- register int result;
-
- for(;;) {
- start:
- result = thr_join((thread_t)0, &departed, &status);
- LOCK();
- if (result != 0) {
- /* No more threads; wait for create. */
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (t = GC_threads[i]; t != 0; t = t -> next) {
- if (!(t -> flags & (DETACHED | FINISHED))) {
- UNLOCK();
- goto start; /* Thread started just before we */
- /* acquired the lock. */
- }
- }
- }
- cond_wait(&GC_create_cv, &GC_allocate_ml);
- UNLOCK();
- } else {
- t = GC_lookup_thread(departed);
- GC_multithreaded--;
- if (!(t -> flags & CLIENT_OWNS_STACK)) {
- GC_stack_free(t -> stack, t -> stack_size);
- }
- if (t -> flags & DETACHED) {
- GC_delete_thread(departed);
- } else {
- t -> status = status;
- t -> flags |= FINISHED;
- cond_signal(&(t -> join_cv));
- cond_broadcast(&GC_prom_join_cv);
- }
- UNLOCK();
- }
- }
-}
-
-/* We hold the allocation lock, or caller ensures that 2 instances */
-/* cannot be invoked concurrently. */
-void GC_thr_init(void)
-{
- GC_thread t;
- thread_t tid;
- int ret;
-
- if (GC_thr_initialized)
- return;
- GC_thr_initialized = TRUE;
- GC_min_stack_sz = ((thr_min_stack() + 32*1024 + HBLKSIZE-1)
- & ~(HBLKSIZE - 1));
-#ifdef MMAP_STACKS
- GC_zfd = open("/dev/zero", O_RDONLY);
- if (GC_zfd == -1)
- ABORT("Can't open /dev/zero");
-#endif /* MMAP_STACKS */
- cond_init(&GC_prom_join_cv, USYNC_THREAD, 0);
- cond_init(&GC_create_cv, USYNC_THREAD, 0);
- /* Add the initial thread, so we can stop it. */
- t = GC_new_thread(thr_self());
- t -> stack_size = 0;
- t -> flags = DETACHED | CLIENT_OWNS_STACK;
- ret = thr_create(0 /* stack */, 0 /* stack_size */, GC_thr_daemon,
- 0 /* arg */, THR_DETACHED | THR_DAEMON,
- &tid /* thread_id */);
- if (ret != 0) {
- GC_err_printf1("Thr_create returned %ld\n", ret);
- ABORT("Cant fork daemon");
- }
- thr_setprio(tid, 126);
-}
-
-/* We acquire the allocation lock to prevent races with */
-/* stopping/starting world. */
-/* This is no more correct than the underlying Solaris 2.X */
-/* implementation. Under 2.3 THIS IS BROKEN. */
-int GC_thr_suspend(thread_t target_thread)
-{
- GC_thread t;
- int result;
-
- LOCK();
- result = thr_suspend(target_thread);
- if (result == 0) {
- t = GC_lookup_thread(target_thread);
- if (t == 0) ABORT("thread unknown to GC");
- t -> flags |= SUSPNDED;
- }
- UNLOCK();
- return(result);
-}
-
-int GC_thr_continue(thread_t target_thread)
-{
- GC_thread t;
- int result;
-
- LOCK();
- result = thr_continue(target_thread);
- if (result == 0) {
- t = GC_lookup_thread(target_thread);
- if (t == 0) ABORT("thread unknown to GC");
- t -> flags &= ~SUSPNDED;
- }
- UNLOCK();
- return(result);
-}
-
-int GC_thr_join(thread_t wait_for, thread_t *departed, void **status)
-{
- register GC_thread t;
- int result = 0;
-
- LOCK();
- if (wait_for == 0) {
- register int i;
- register GC_bool thread_exists;
-
- for (;;) {
- thread_exists = FALSE;
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (t = GC_threads[i]; t != 0; t = t -> next) {
- if (!(t -> flags & DETACHED)) {
- if (t -> flags & FINISHED) {
- goto found;
- }
- thread_exists = TRUE;
- }
- }
- }
- if (!thread_exists) {
- result = ESRCH;
- goto out;
- }
- cond_wait(&GC_prom_join_cv, &GC_allocate_ml);
- }
- } else {
- t = GC_lookup_thread(wait_for);
- if (t == 0 || t -> flags & DETACHED) {
- result = ESRCH;
- goto out;
- }
- if (wait_for == thr_self()) {
- result = EDEADLK;
- goto out;
- }
- while (!(t -> flags & FINISHED)) {
- cond_wait(&(t -> join_cv), &GC_allocate_ml);
- }
-
- }
- found:
- if (status) *status = t -> status;
- if (departed) *departed = t -> id;
- cond_destroy(&(t -> join_cv));
- GC_delete_thread(t -> id);
- out:
- UNLOCK();
- return(result);
-}
-
-
-int
-GC_thr_create(void *stack_base, size_t stack_size,
- void *(*start_routine)(void *), void *arg, long flags,
- thread_t *new_thread)
-{
- int result;
- GC_thread t;
- thread_t my_new_thread;
- word my_flags = 0;
- void * stack = stack_base;
-
- LOCK();
- if (!GC_is_initialized) GC_init_inner();
- GC_multithreaded++;
- if (stack == 0) {
- if (stack_size == 0) stack_size = 1024*1024;
- stack = (void *)GC_stack_alloc(&stack_size);
- if (stack == 0) {
- GC_multithreaded--;
- UNLOCK();
- return(ENOMEM);
- }
- } else {
- my_flags |= CLIENT_OWNS_STACK;
- }
- if (flags & THR_DETACHED) my_flags |= DETACHED;
- if (flags & THR_SUSPENDED) my_flags |= SUSPNDED;
- result = thr_create(stack, stack_size, start_routine,
- arg, flags & ~THR_DETACHED, &my_new_thread);
- if (result == 0) {
- t = GC_new_thread(my_new_thread);
- t -> flags = my_flags;
- if (!(my_flags & DETACHED)) cond_init(&(t -> join_cv), USYNC_THREAD, 0);
- t -> stack = stack;
- t -> stack_size = stack_size;
- if (new_thread != 0) *new_thread = my_new_thread;
- cond_signal(&GC_create_cv);
- } else {
- GC_multithreaded--;
- if (!(my_flags & CLIENT_OWNS_STACK)) {
- GC_stack_free(stack, stack_size);
- }
- }
- UNLOCK();
- return(result);
-}
-
-# else /* !GC_SOLARIS_THREADS */
-
-#ifndef LINT
- int GC_no_sunOS_threads;
-#endif
-#endif
diff --git a/boehm-gc/specific.c b/boehm-gc/specific.c
index 2c40c2b44a2..20c78ade78f 100644
--- a/boehm-gc/specific.c
+++ b/boehm-gc/specific.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2000 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
@@ -11,117 +11,158 @@
* modified is included with the above copyright notice.
*/
-#if defined(GC_LINUX_THREADS)
+#include "private/thread_local_alloc.h"
+ /* To determine type of tsd impl. */
+ /* Includes private/specific.h */
+ /* if needed. */
-#include "private/gc_priv.h" /* For GC_compare_and_exchange, GC_memory_barrier */
-#include "private/specific.h"
+#if defined(USE_CUSTOM_SPECIFIC)
-static tse invalid_tse = {INVALID_QTID, 0, 0, INVALID_THREADID};
- /* A thread-specific data entry which will never */
- /* appear valid to a reader. Used to fill in empty */
- /* cache entries to avoid a check for 0. */
+static const tse invalid_tse = {INVALID_QTID, 0, 0, INVALID_THREADID};
+ /* A thread-specific data entry which will never */
+ /* appear valid to a reader. Used to fill in empty */
+ /* cache entries to avoid a check for 0. */
-int PREFIXED(key_create) (tsd ** key_ptr, void (* destructor)(void *)) {
+GC_INNER int GC_key_create_inner(tsd ** key_ptr)
+{
int i;
- tsd * result = (tsd *)MALLOC_CLEAR(sizeof (tsd));
+ tsd * result = (tsd *)MALLOC_CLEAR(sizeof(tsd));
/* A quick alignment check, since we need atomic stores */
- GC_ASSERT((unsigned long)(&invalid_tse.next) % sizeof(tse *) == 0);
+ GC_ASSERT((word)(&invalid_tse.next) % sizeof(tse *) == 0);
if (0 == result) return ENOMEM;
pthread_mutex_init(&(result -> lock), NULL);
for (i = 0; i < TS_CACHE_SIZE; ++i) {
- result -> cache[i] = &invalid_tse;
+ result -> cache[i] = (/* no const */ tse *)&invalid_tse;
}
# ifdef GC_ASSERTIONS
for (i = 0; i < TS_HASH_SIZE; ++i) {
- GC_ASSERT(result -> hash[i] == 0);
+ GC_ASSERT(result -> hash[i].p == 0);
}
# endif
*key_ptr = result;
return 0;
}
-int PREFIXED(setspecific) (tsd * key, void * value) {
+/* Called with the lock held. */
+GC_INNER int GC_setspecific(tsd * key, void * value)
+{
pthread_t self = pthread_self();
int hash_val = HASH(self);
- volatile tse * entry = (volatile tse *)MALLOC_CLEAR(sizeof (tse));
-
+ volatile tse * entry;
+
GC_ASSERT(self != INVALID_THREADID);
+ GC_dont_gc++; /* disable GC */
+ entry = (volatile tse *)MALLOC_CLEAR(sizeof(tse));
+ GC_dont_gc--;
if (0 == entry) return ENOMEM;
+
pthread_mutex_lock(&(key -> lock));
- /* Could easily check for an existing entry here. */
- entry -> next = key -> hash[hash_val];
+ /* Could easily check for an existing entry here. */
+ entry -> next = key->hash[hash_val].p;
entry -> thread = self;
entry -> value = value;
GC_ASSERT(entry -> qtid == INVALID_QTID);
- /* There can only be one writer at a time, but this needs to be */
- /* atomic with respect to concurrent readers. */
- *(volatile tse **)(key -> hash + hash_val) = entry;
+ /* There can only be one writer at a time, but this needs to be */
+ /* atomic with respect to concurrent readers. */
+ AO_store_release(&key->hash[hash_val].ao, (AO_t)entry);
pthread_mutex_unlock(&(key -> lock));
return 0;
}
-/* Remove thread-specific data for this thread. Should be called on */
-/* thread exit. */
-void PREFIXED(remove_specific) (tsd * key) {
+/* Remove thread-specific data for this thread. Should be called on */
+/* thread exit. */
+GC_INNER void GC_remove_specific(tsd * key)
+{
pthread_t self = pthread_self();
unsigned hash_val = HASH(self);
tse *entry;
- tse **link = key -> hash + hash_val;
+ tse **link = &key->hash[hash_val].p;
pthread_mutex_lock(&(key -> lock));
entry = *link;
while (entry != NULL && entry -> thread != self) {
- link = &(entry -> next);
- entry = *link;
+ link = &(entry -> next);
+ entry = *link;
}
- /* Invalidate qtid field, since qtids may be reused, and a later */
- /* cache lookup could otherwise find this entry. */
- entry -> qtid = INVALID_QTID;
+ /* Invalidate qtid field, since qtids may be reused, and a later */
+ /* cache lookup could otherwise find this entry. */
if (entry != NULL) {
- *link = entry -> next;
- /* Atomic! concurrent accesses still work. */
- /* They must, since readers don't lock. */
- /* We shouldn't need a volatile access here, */
- /* since both this and the preceding write */
- /* should become visible no later than */
- /* the pthread_mutex_unlock() call. */
+ entry -> qtid = INVALID_QTID;
+ *link = entry -> next;
+ /* Atomic! concurrent accesses still work. */
+ /* They must, since readers don't lock. */
+ /* We shouldn't need a volatile access here, */
+ /* since both this and the preceding write */
+ /* should become visible no later than */
+ /* the pthread_mutex_unlock() call. */
}
- /* If we wanted to deallocate the entry, we'd first have to clear */
- /* any cache entries pointing to it. That probably requires */
- /* additional synchronization, since we can't prevent a concurrent */
+ /* If we wanted to deallocate the entry, we'd first have to clear */
+ /* any cache entries pointing to it. That probably requires */
+ /* additional synchronization, since we can't prevent a concurrent */
/* cache lookup, which should still be examining deallocated memory.*/
- /* This can only happen if the concurrent access is from another */
- /* thread, and hence has missed the cache, but still... */
+ /* This can only happen if the concurrent access is from another */
+ /* thread, and hence has missed the cache, but still... */
- /* With GC, we're done, since the pointers from the cache will */
- /* be overwritten, all local pointers to the entries will be */
- /* dropped, and the entry will then be reclaimed. */
+ /* With GC, we're done, since the pointers from the cache will */
+ /* be overwritten, all local pointers to the entries will be */
+ /* dropped, and the entry will then be reclaimed. */
pthread_mutex_unlock(&(key -> lock));
}
-/* Note that even the slow path doesn't lock. */
-void * PREFIXED(slow_getspecific) (tsd * key, unsigned long qtid,
- tse * volatile * cache_ptr) {
+/* Note that even the slow path doesn't lock. */
+GC_INNER void * GC_slow_getspecific(tsd * key, word qtid,
+ tse * volatile * cache_ptr)
+{
pthread_t self = pthread_self();
unsigned hash_val = HASH(self);
- tse *entry = key -> hash[hash_val];
+ tse *entry = key->hash[hash_val].p;
GC_ASSERT(qtid != INVALID_QTID);
while (entry != NULL && entry -> thread != self) {
- entry = entry -> next;
- }
+ entry = entry -> next;
+ }
if (entry == NULL) return NULL;
- /* Set cache_entry. */
- entry -> qtid = qtid;
- /* It's safe to do this asynchronously. Either value */
- /* is safe, though may produce spurious misses. */
- /* We're replacing one qtid with another one for the */
- /* same thread. */
- *cache_ptr = entry;
- /* Again this is safe since pointer assignments are */
- /* presumed atomic, and either pointer is valid. */
+ /* Set cache_entry. */
+ entry -> qtid = (AO_t)qtid;
+ /* It's safe to do this asynchronously. Either value */
+ /* is safe, though may produce spurious misses. */
+ /* We're replacing one qtid with another one for the */
+ /* same thread. */
+ *cache_ptr = entry;
+ /* Again this is safe since pointer assignments are */
+ /* presumed atomic, and either pointer is valid. */
return entry -> value;
}
-#endif /* GC_LINUX_THREADS */
+#ifdef GC_ASSERTIONS
+ /* Check that that all elements of the data structure associated */
+ /* with key are marked. */
+ void GC_check_tsd_marks(tsd *key)
+ {
+ int i;
+ tse *p;
+
+ if (!GC_is_marked(GC_base(key))) {
+ ABORT("Unmarked thread-specific-data table");
+ }
+ for (i = 0; i < TS_HASH_SIZE; ++i) {
+ for (p = key->hash[i].p; p != 0; p = p -> next) {
+ if (!GC_is_marked(GC_base(p))) {
+ GC_err_printf("Thread-specific-data entry at %p not marked\n", p);
+ ABORT("Unmarked tse");
+ }
+ }
+ }
+ for (i = 0; i < TS_CACHE_SIZE; ++i) {
+ p = key -> cache[i];
+ if (p != &invalid_tse && !GC_is_marked(GC_base(p))) {
+ GC_err_printf("Cached thread-specific-data entry at %p not marked\n",
+ p);
+ ABORT("Unmarked cached tse");
+ }
+ }
+ }
+#endif /* GC_ASSERTIONS */
+
+#endif /* USE_CUSTOM_SPECIFIC */
diff --git a/boehm-gc/ia64_save_regs_in_stack.s b/boehm-gc/src/ia64_save_regs_in_stack.s
index 3b18c0841d0..2b81edfaab1 100644
--- a/boehm-gc/ia64_save_regs_in_stack.s
+++ b/boehm-gc/src/ia64_save_regs_in_stack.s
@@ -9,4 +9,3 @@ GC_save_regs_in_stack:
mov r8=ar.bsp
br.ret.sptk.few rp
.endp GC_save_regs_in_stack
-
diff --git a/boehm-gc/src/sparc_mach_dep.S b/boehm-gc/src/sparc_mach_dep.S
new file mode 100644
index 00000000000..d204dc43680
--- /dev/null
+++ b/boehm-gc/src/sparc_mach_dep.S
@@ -0,0 +1,61 @@
+! SPARCompiler 3.0 and later apparently no longer handles
+! asm outside functions. So we need a separate .s file
+! This is only set up for SunOS 5, not SunOS 4.
+! Assumes this is called before the stack contents are
+! examined.
+
+ .seg "text"
+ .globl GC_save_regs_in_stack
+GC_save_regs_in_stack:
+#if defined(__arch64__) || defined(__sparcv9)
+ save %sp,-128,%sp
+ flushw
+ ret
+ restore %sp,2047+128,%o0
+#else /* 32 bit SPARC */
+ ta 0x3 ! ST_FLUSH_WINDOWS
+ mov %sp,%o0
+ retl
+ nop
+#endif /* 32 bit SPARC */
+.GC_save_regs_in_stack_end:
+ .size GC_save_regs_in_stack,.GC_save_regs_in_stack_end-GC_save_regs_in_stack
+
+! GC_clear_stack_inner(arg, limit) clears stack area up to limit and
+! returns arg. Stack clearing is crucial on SPARC, so we supply
+! an assembly version that s more careful. Assumes limit is hotter
+! than sp, and limit is 8 byte aligned.
+ .globl GC_clear_stack_inner
+GC_clear_stack_inner:
+#if defined(__arch64__) || defined(__sparcv9)
+ mov %sp,%o2 ! Save sp
+ add %sp,2047-8,%o3 ! p = sp+bias-8
+ add %o1,-2047-192,%sp ! Move sp out of the way,
+ ! so that traps still work.
+ ! Includes some extra words
+ ! so we can be sloppy below.
+loop:
+ stx %g0,[%o3] ! *(long *)p = 0
+ cmp %o3,%o1
+ bgu,pt %xcc, loop ! if (p > limit) goto loop
+ add %o3,-8,%o3 ! p -= 8 (delay slot)
+ retl
+ mov %o2,%sp ! Restore sp., delay slot
+#else /* 32 bit SPARC */
+ mov %sp,%o2 ! Save sp
+ add %sp,-8,%o3 ! p = sp-8
+ clr %g1 ! [g0,g1] = 0
+ add %o1,-0x60,%sp ! Move sp out of the way,
+ ! so that traps still work.
+ ! Includes some extra words
+ ! so we can be sloppy below.
+loop:
+ std %g0,[%o3] ! *(long long *)p = 0
+ cmp %o3,%o1
+ bgu loop ! if (p > limit) goto loop
+ add %o3,-8,%o3 ! p -= 8 (delay slot)
+ retl
+ mov %o2,%sp ! Restore sp., delay slot
+#endif /* 32 bit SPARC */
+.GC_clear_stack_inner_end:
+ .size GC_clear_stack_inner,.GC_clear_stack_inner_end-GC_clear_stack_inner
diff --git a/boehm-gc/sparc_netbsd_mach_dep.s b/boehm-gc/src/sparc_netbsd_mach_dep.s
index bc3f1603735..14feb15eea1 100644
--- a/boehm-gc/sparc_netbsd_mach_dep.s
+++ b/boehm-gc/src/sparc_netbsd_mach_dep.s
@@ -15,7 +15,7 @@ _C_LABEL(GC_push_regs):
mov %sp,%o0
retl
nop
-
+
.globl _C_LABEL(GC_clear_stack_inner)
_C_LABEL(GC_clear_stack_inner):
mov %sp,%o2 ! Save sp
diff --git a/boehm-gc/sparc_sunos4_mach_dep.s b/boehm-gc/src/sparc_sunos4_mach_dep.s
index 41858073ef9..923f5eaa277 100644
--- a/boehm-gc/sparc_sunos4_mach_dep.s
+++ b/boehm-gc/src/sparc_sunos4_mach_dep.s
@@ -13,7 +13,7 @@ _GC_push_regs:
mov %sp,%o0
retl
nop
-
+
.globl _GC_clear_stack_inner
_GC_clear_stack_inner:
mov %sp,%o2 ! Save sp
@@ -30,9 +30,3 @@ loop:
add %o3,-8,%o3 ! p -= 8 (delay slot)
retl
mov %o2,%sp ! Restore sp., delay slot
-
-
-
-
-
-
diff --git a/boehm-gc/stubborn.c b/boehm-gc/stubborn.c
index bb137616fa8..82f113896f9 100644
--- a/boehm-gc/stubborn.c
+++ b/boehm-gc/stubborn.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
*
@@ -11,316 +11,46 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, July 31, 1995 5:02 pm PDT */
-
#include "private/gc_priv.h"
-# ifdef STUBBORN_ALLOC
-/* Stubborn object (hard to change, nearly immutable) allocation. */
-
-extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
-
-#define GENERAL_MALLOC(lb,k) \
- (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
-
-/* Data structure representing immutable objects that */
-/* are still being initialized. */
-/* This is a bit baroque in order to avoid acquiring */
-/* the lock twice for a typical allocation. */
-
-GC_PTR * GC_changing_list_start;
-
-void GC_push_stubborn_structures GC_PROTO((void))
-{
- GC_push_all((ptr_t)(&GC_changing_list_start),
- (ptr_t)(&GC_changing_list_start) + sizeof(GC_PTR *));
-}
-
-# ifdef THREADS
- VOLATILE GC_PTR * VOLATILE GC_changing_list_current;
-# else
- GC_PTR * GC_changing_list_current;
-# endif
- /* Points at last added element. Also (ab)used for */
- /* synchronization. Updates and reads are assumed atomic. */
-
-GC_PTR * GC_changing_list_limit;
- /* Points at the last word of the buffer, which is always 0 */
- /* All entries in (GC_changing_list_current, */
- /* GC_changing_list_limit] are 0 */
-
+#if defined(MANUAL_VDB)
-void GC_stubborn_init()
-{
-# define INIT_SIZE 10
+ /* Stubborn object (hard to change, nearly immutable) allocation. */
+ /* This interface is deprecated. We mostly emulate it using */
+ /* MANUAL_VDB. But that imposes the additional constraint that */
+ /* written, but not yet GC_dirty()ed objects must be referenced */
+ /* by a stack. */
- GC_changing_list_start = (GC_PTR *)
- GC_INTERNAL_MALLOC(
- (word)(INIT_SIZE * sizeof(GC_PTR)),
- PTRFREE);
- BZERO(GC_changing_list_start,
- INIT_SIZE * sizeof(GC_PTR));
- if (GC_changing_list_start == 0) {
- GC_err_printf0("Insufficient space to start up\n");
- ABORT("GC_stubborn_init: put of space");
- }
- GC_changing_list_current = GC_changing_list_start;
- GC_changing_list_limit = GC_changing_list_start + INIT_SIZE - 1;
- * GC_changing_list_limit = 0;
-}
+ void GC_dirty(ptr_t p);
-/* Compact and possibly grow GC_uninit_list. The old copy is */
-/* left alone. Lock must be held. */
-/* When called GC_changing_list_current == GC_changing_list_limit */
-/* which is one past the current element. */
-/* When we finish GC_changing_list_current again points one past last */
-/* element. */
-/* Invariant while this is running: GC_changing_list_current */
-/* points at a word containing 0. */
-/* Returns FALSE on failure. */
-GC_bool GC_compact_changing_list()
-{
- register GC_PTR *p, *q;
- register word count = 0;
- word old_size = (char **)GC_changing_list_limit
- - (char **)GC_changing_list_start+1;
- /* The casts are needed as a workaround for an Amiga bug */
- register word new_size = old_size;
- GC_PTR * new_list;
-
- for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
- if (*p != 0) count++;
- }
- if (2 * count > old_size) new_size = 2 * count;
- new_list = (GC_PTR *)
- GC_INTERNAL_MALLOC(
- new_size * sizeof(GC_PTR), PTRFREE);
- /* PTRFREE is a lie. But we don't want the collector to */
- /* consider these. We do want the list itself to be */
- /* collectable. */
- if (new_list == 0) return(FALSE);
- BZERO(new_list, new_size * sizeof(GC_PTR));
- q = new_list;
- for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
- if (*p != 0) *q++ = *p;
- }
- GC_changing_list_start = new_list;
- GC_changing_list_limit = new_list + new_size - 1;
- GC_changing_list_current = q;
- return(TRUE);
-}
-
-/* Add p to changing list. Clear p on failure. */
-# define ADD_CHANGING(p) \
- { \
- register struct hblk * h = HBLKPTR(p); \
- register word index = PHT_HASH(h); \
- \
- set_pht_entry_from_index(GC_changed_pages, index); \
- } \
- if (*GC_changing_list_current != 0 \
- && ++GC_changing_list_current == GC_changing_list_limit) { \
- if (!GC_compact_changing_list()) (p) = 0; \
- } \
- *GC_changing_list_current = p;
-
-void GC_change_stubborn(p)
-GC_PTR p;
-{
- DCL_LOCK_STATE;
-
- DISABLE_SIGNALS();
- LOCK();
- ADD_CHANGING(p);
- UNLOCK();
- ENABLE_SIGNALS();
-}
-
-void GC_end_stubborn_change(p)
-GC_PTR p;
-{
-# ifdef THREADS
- register VOLATILE GC_PTR * my_current = GC_changing_list_current;
-# else
- register GC_PTR * my_current = GC_changing_list_current;
-# endif
- register GC_bool tried_quick;
- DCL_LOCK_STATE;
-
- if (*my_current == p) {
- /* Hopefully the normal case. */
- /* Compaction could not have been running when we started. */
- *my_current = 0;
-# ifdef THREADS
- if (my_current == GC_changing_list_current) {
- /* Compaction can't have run in the interim. */
- /* We got away with the quick and dirty approach. */
- return;
- }
- tried_quick = TRUE;
-# else
- return;
-# endif
- } else {
- tried_quick = FALSE;
- }
- DISABLE_SIGNALS();
- LOCK();
- my_current = GC_changing_list_current;
- for (; my_current >= GC_changing_list_start; my_current--) {
- if (*my_current == p) {
- *my_current = 0;
- UNLOCK();
- ENABLE_SIGNALS();
- return;
- }
- }
- if (!tried_quick) {
- GC_err_printf1("Bad arg to GC_end_stubborn_change: 0x%lx\n",
- (unsigned long)p);
- ABORT("Bad arg to GC_end_stubborn_change");
- }
- UNLOCK();
- ENABLE_SIGNALS();
-}
-
-/* Allocate lb bytes of composite (pointerful) data */
-/* No pointer fields may be changed after a call to */
-/* GC_end_stubborn_change(p) where p is the value */
-/* returned by GC_malloc_stubborn. */
-# ifdef __STDC__
- GC_PTR GC_malloc_stubborn(size_t lb)
-# else
- GC_PTR GC_malloc_stubborn(lb)
- size_t lb;
-# endif
-{
-register ptr_t op;
-register ptr_t *opp;
-register word lw;
-ptr_t result;
-DCL_LOCK_STATE;
-
- if( SMALL_OBJ(lb) ) {
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_sobjfreelist[lw]);
- FASTLOCK();
- if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
- FASTUNLOCK();
- result = GC_generic_malloc((word)lb, STUBBORN);
- goto record;
- }
- *opp = obj_link(op);
- obj_link(op) = 0;
- GC_words_allocd += lw;
- result = (GC_PTR) op;
- ADD_CHANGING(result);
- FASTUNLOCK();
- return((GC_PTR)result);
- } else {
- result = (GC_PTR)
- GC_generic_malloc((word)lb, STUBBORN);
- }
-record:
- DISABLE_SIGNALS();
- LOCK();
- ADD_CHANGING(result);
- UNLOCK();
- ENABLE_SIGNALS();
- return((GC_PTR)GC_clear_stack(result));
-}
-
-
-/* Functions analogous to GC_read_dirty and GC_page_was_dirty. */
-/* Report pages on which stubborn objects were changed. */
-void GC_read_changed()
-{
- register GC_PTR * p = GC_changing_list_start;
- register GC_PTR q;
- register struct hblk * h;
- register word index;
-
- if (p == 0) /* initializing */ return;
- BCOPY(GC_changed_pages, GC_prev_changed_pages,
- (sizeof GC_changed_pages));
- BZERO(GC_changed_pages, (sizeof GC_changed_pages));
- for (; p <= GC_changing_list_current; p++) {
- if ((q = *p) != 0) {
- h = HBLKPTR(q);
- index = PHT_HASH(h);
- set_pht_entry_from_index(GC_changed_pages, index);
- }
- }
-}
+ GC_API void * GC_CALL GC_malloc_stubborn(size_t lb)
+ {
+ return(GC_malloc(lb));
+ }
-GC_bool GC_page_was_changed(h)
-struct hblk * h;
-{
- register word index = PHT_HASH(h);
-
- return(get_pht_entry_from_index(GC_prev_changed_pages, index));
-}
+ GC_API void GC_CALL GC_end_stubborn_change(const void *p)
+ {
+ GC_dirty((ptr_t)p);
+ }
-/* Remove unreachable entries from changed list. Should only be */
-/* called with mark bits consistent and lock held. */
-void GC_clean_changing_list()
-{
- register GC_PTR * p = GC_changing_list_start;
- register GC_PTR q;
- register ptr_t r;
- register unsigned long count = 0;
- register unsigned long dropped_count = 0;
-
- if (p == 0) /* initializing */ return;
- for (; p <= GC_changing_list_current; p++) {
- if ((q = *p) != 0) {
- count++;
- r = (ptr_t)GC_base(q);
- if (r == 0 || !GC_is_marked(r)) {
- *p = 0;
- dropped_count++;
- }
- }
- }
-# ifdef PRINTSTATS
- if (count > 0) {
- GC_printf2("%lu entries in changing list: reclaimed %lu\n",
- (unsigned long)count, (unsigned long)dropped_count);
- }
-# endif
-}
+ GC_API void GC_CALL GC_change_stubborn(const void *p GC_ATTR_UNUSED)
+ {
+ }
-#else /* !STUBBORN_ALLOC */
+#else /* !MANUAL_VDB */
-# ifdef __STDC__
- GC_PTR GC_malloc_stubborn(size_t lb)
-# else
- GC_PTR GC_malloc_stubborn(lb)
- size_t lb;
-# endif
-{
+ GC_API void * GC_CALL GC_malloc_stubborn(size_t lb)
+ {
return(GC_malloc(lb));
-}
-
-/*ARGSUSED*/
-void GC_end_stubborn_change(p)
-GC_PTR p;
-{
-}
+ }
-/*ARGSUSED*/
-void GC_change_stubborn(p)
-GC_PTR p;
-{
-}
+ GC_API void GC_CALL GC_end_stubborn_change(const void *p GC_ATTR_UNUSED)
+ {
+ }
-void GC_push_stubborn_structures GC_PROTO((void))
-{
-}
+ GC_API void GC_CALL GC_change_stubborn(const void *p GC_ATTR_UNUSED)
+ {
+ }
-#endif
+#endif /* !MANUAL_VDB */
diff --git a/boehm-gc/tests/CMakeLists.txt b/boehm-gc/tests/CMakeLists.txt
new file mode 100644
index 00000000000..0f4d455f620
--- /dev/null
+++ b/boehm-gc/tests/CMakeLists.txt
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+# Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+# Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+# Copyright (c) 2000-2010 by Hewlett-Packard Company. All rights reserved.
+##
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+##
+# Permission is hereby granted to use or copy this program
+# for any purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+##
+
+ADD_DEFINITIONS(-DGC_NOT_DLL)
+ADD_EXECUTABLE(gctest WIN32 test.c)
+TARGET_LINK_LIBRARIES(gctest gc-lib)
diff --git a/boehm-gc/tests/disclaim_bench.c b/boehm-gc/tests/disclaim_bench.c
new file mode 100644
index 00000000000..5159829ce92
--- /dev/null
+++ b/boehm-gc/tests/disclaim_bench.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2011 by Hewlett-Packard Company. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "private/gc_priv.h"
+
+#include "gc_disclaim.h"
+
+#define my_assert(e) \
+ if (!(e)) { \
+ fprintf(stderr, "Assertion failure, line %d: " #e "\n", __LINE__); \
+ exit(-1); \
+ }
+
+static int free_count = 0;
+
+struct testobj_s {
+ struct testobj_s *keep_link;
+ int i;
+};
+
+typedef struct testobj_s *testobj_t;
+
+void GC_CALLBACK testobj_finalize(void *obj, void *carg)
+{
+ ++*(int *)carg;
+ my_assert(((testobj_t)obj)->i++ == 109);
+}
+
+static const struct GC_finalizer_closure fclos = {
+ testobj_finalize,
+ &free_count
+};
+
+testobj_t testobj_new(int model)
+{
+ testobj_t obj;
+ switch (model) {
+ case 0:
+ obj = GC_MALLOC(sizeof(struct testobj_s));
+ if (obj != NULL)
+ GC_register_finalizer_no_order(obj, testobj_finalize,
+ &free_count, NULL, NULL);
+ break;
+ case 1:
+ obj = GC_finalized_malloc(sizeof(struct testobj_s), &fclos);
+ break;
+ case 2:
+ obj = GC_MALLOC(sizeof(struct testobj_s));
+ break;
+ default:
+ exit(-1);
+ }
+ if (obj == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(3);
+ }
+ my_assert(obj->i == 0 && obj->keep_link == NULL);
+ obj->i = 109;
+ return obj;
+}
+
+#define ALLOC_CNT (4*1024*1024)
+#define KEEP_CNT (32*1024)
+
+static char const *model_str[3] = {
+ "regular finalization",
+ "finalize on reclaim",
+ "no finalization"
+};
+
+int main(int argc, char **argv)
+{
+ int i;
+ int model, model_min, model_max;
+ testobj_t *keep_arr;
+
+ GC_INIT();
+ GC_init_finalized_malloc();
+
+ keep_arr = GC_MALLOC(sizeof(void *)*KEEP_CNT);
+
+ if (argc == 2 && strcmp(argv[1], "--help") == 0) {
+ fprintf(stderr,
+ "Usage: %s [FINALIZATION_MODEL]\n"
+ "\t0 -- original finalization\n"
+ "\t1 -- finalization on reclaim\n"
+ "\t2 -- no finalization\n", argv[0]);
+ return 1;
+ }
+ if (argc == 2) {
+ model_min = model_max = atoi(argv[1]);
+ if (model_min < 0 || model_max > 2)
+ exit(2);
+ }
+ else {
+ model_min = 0;
+ model_max = 2;
+ }
+
+ printf("\t\t\tfin. ratio time/s time/fin.\n");
+ for (model = model_min; model <= model_max; ++model) {
+ double t = 0.0;
+ free_count = 0;
+
+# ifdef CLOCK_TYPE
+ CLOCK_TYPE tI, tF;
+ GET_TIME(tI);
+# endif
+ for (i = 0; i < ALLOC_CNT; ++i) {
+ int k = rand() % KEEP_CNT;
+ keep_arr[k] = testobj_new(model);
+ }
+ GC_gcollect();
+# ifdef CLOCK_TYPE
+ GET_TIME(tF);
+ t = MS_TIME_DIFF(tF, tI)*1e-3;
+# endif
+
+ if (model < 2)
+ printf("%20s: %12.4lf %12lg %12lg\n", model_str[model],
+ free_count/(double)ALLOC_CNT, t, t/free_count);
+ else
+ printf("%20s: %12.4lf %12lg %12s\n",
+ model_str[model], 0.0, t, "N/A");
+ }
+ return 0;
+}
diff --git a/boehm-gc/tests/disclaim_test.c b/boehm-gc/tests/disclaim_test.c
new file mode 100644
index 00000000000..7bba6fb84d5
--- /dev/null
+++ b/boehm-gc/tests/disclaim_test.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2011 by Hewlett-Packard Company. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+
+/* Test that objects reachable from an object allocated with */
+/* GC_malloc_with_finalizer is not reclaimable before the finalizer */
+/* is called. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+ /* For GC_[P]THREADS */
+# include "config.h"
+#endif
+
+#include "gc_disclaim.h"
+
+#define my_assert(e) \
+ if (!(e)) { \
+ fprintf(stderr, "Assertion failure, line %d: " #e "\n", __LINE__); \
+ exit(-1); \
+ }
+
+int memeq(void *s, int c, size_t len)
+{
+ while (len--) {
+ if (*(char *)s != c)
+ return 0;
+ s = (char *)s + 1;
+ }
+ return 1;
+}
+
+void GC_CALLBACK misc_sizes_dct(void *obj, void *cd)
+{
+ unsigned log_size = *(unsigned char *)obj;
+ size_t size;
+
+ my_assert(log_size < sizeof(size_t) * 8);
+ my_assert(cd == NULL);
+ size = (size_t)1 << log_size;
+ my_assert(memeq((char *)obj + 1, 0x56, size - 1));
+}
+
+void test_misc_sizes(void)
+{
+ static const struct GC_finalizer_closure fc = { misc_sizes_dct, NULL };
+ int i;
+ for (i = 1; i <= 20; ++i) { /* Up to 1 MiB. */
+ void *p = GC_finalized_malloc((size_t)1 << i, &fc);
+ if (p == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(3);
+ }
+ my_assert(memeq(p, 0, (size_t)1 << i));
+ memset(p, 0x56, (size_t)1 << i);
+ *(unsigned char *)p = i;
+ }
+}
+
+typedef struct pair_s *pair_t;
+
+struct pair_s {
+ int is_valid;
+ int checksum;
+ pair_t car;
+ pair_t cdr;
+};
+
+void GC_CALLBACK pair_dct(void *obj, void *cd)
+{
+ pair_t p = obj;
+ int checksum;
+
+ /* Check that obj and its car and cdr are not trashed. */
+# ifdef DEBUG_DISCLAIM_DESTRUCT
+ printf("Destruct %p = (%p, %p)\n",
+ (void *)p, (void *)p->car, (void *)p->cdr);
+# endif
+ my_assert(GC_base(obj));
+ my_assert(p->is_valid);
+ my_assert(!p->car || p->car->is_valid);
+ my_assert(!p->cdr || p->cdr->is_valid);
+ checksum = 782;
+ if (p->car) checksum += p->car->checksum;
+ if (p->cdr) checksum += p->cdr->checksum;
+ my_assert(p->checksum == checksum);
+
+ /* Invalidate it. */
+ p->is_valid = 0;
+ p->checksum = 0;
+ p->car = cd;
+ p->cdr = NULL;
+}
+
+pair_t
+pair_new(pair_t car, pair_t cdr)
+{
+ pair_t p;
+ static const struct GC_finalizer_closure fc = { pair_dct, NULL };
+
+ p = GC_finalized_malloc(sizeof(struct pair_s), &fc);
+ if (p == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(3);
+ }
+ my_assert(memeq(p, 0, sizeof(struct pair_s)));
+ p->is_valid = 1;
+ p->checksum = 782 + (car? car->checksum : 0) + (cdr? cdr->checksum : 0);
+ p->car = car;
+ p->cdr = cdr;
+# ifdef DEBUG_DISCLAIM_DESTRUCT
+ printf("Construct %p = (%p, %p)\n",
+ (void *)p, (void *)p->car, (void *)p->cdr);
+# endif
+ return p;
+}
+
+void
+pair_check_rec(pair_t p)
+{
+ while (p) {
+ int checksum = 782;
+ if (p->car) checksum += p->car->checksum;
+ if (p->cdr) checksum += p->cdr->checksum;
+ my_assert(p->checksum == checksum);
+ if (rand() % 2)
+ p = p->car;
+ else
+ p = p->cdr;
+ }
+}
+
+#ifdef GC_PTHREADS
+# define THREAD_CNT 6
+# include <pthread.h>
+#else
+# define THREAD_CNT 1
+#endif
+
+#define POP_SIZE 1000
+#if THREAD_CNT > 1
+# define MUTATE_CNT 2000000/THREAD_CNT
+#else
+# define MUTATE_CNT 10000000
+#endif
+#define GROW_LIMIT 10000000
+
+void *test(void *data)
+{
+ int i;
+ pair_t pop[POP_SIZE];
+ memset(pop, 0, sizeof(pop));
+ for (i = 0; i < MUTATE_CNT; ++i) {
+ int t = rand() % POP_SIZE;
+ switch (rand() % (i > GROW_LIMIT? 5 : 3)) {
+ case 0: case 3:
+ if (pop[t])
+ pop[t] = pop[t]->car;
+ break;
+ case 1: case 4:
+ if (pop[t])
+ pop[t] = pop[t]->cdr;
+ break;
+ case 2:
+ pop[t] = pair_new(pop[rand() % POP_SIZE],
+ pop[rand() % POP_SIZE]);
+ break;
+ }
+ if (rand() % 8 == 1)
+ pair_check_rec(pop[rand() % POP_SIZE]);
+ }
+ return data;
+}
+
+int main(void)
+{
+#if THREAD_CNT > 1
+ pthread_t th[THREAD_CNT];
+ int i;
+#endif
+
+ GC_set_all_interior_pointers(0); /* for a stricter test */
+ GC_INIT();
+ GC_init_finalized_malloc();
+
+ test_misc_sizes();
+
+#if THREAD_CNT > 1
+ printf("Threaded disclaim test.\n");
+ for (i = 0; i < THREAD_CNT; ++i) {
+ int err = pthread_create(&th[i], NULL, test, NULL);
+ if (err) {
+ fprintf(stderr, "Failed to create thread # %d: %s\n", i,
+ strerror(err));
+ exit(1);
+ }
+ }
+ for (i = 0; i < THREAD_CNT; ++i) {
+ int err = pthread_join(th[i], NULL);
+ if (err) {
+ fprintf(stderr, "Failed to join thread # %d: %s\n", i,
+ strerror(err));
+ exit(69);
+ }
+ }
+#else
+ printf("Unthreaded disclaim test.\n");
+ test(NULL);
+#endif
+ return 0;
+}
diff --git a/boehm-gc/tests/huge_test.c b/boehm-gc/tests/huge_test.c
new file mode 100644
index 00000000000..bde9836d5a8
--- /dev/null
+++ b/boehm-gc/tests/huge_test.c
@@ -0,0 +1,52 @@
+
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+
+#ifndef GC_IGNORE_WARN
+ /* Ignore misleading "Out of Memory!" warning (which is printed on */
+ /* every GC_MALLOC(LONG_MAX) call) by defining this macro before */
+ /* "gc.h" inclusion. */
+# define GC_IGNORE_WARN
+#endif
+
+#include "gc.h"
+
+/*
+ * Check that very large allocation requests fail. "Success" would usually
+ * indicate that the size was somehow converted to a negative
+ * number. Clients shouldn't do this, but we should fail in the
+ * expected manner.
+ */
+
+int main(void)
+{
+ GC_INIT();
+
+ GC_set_max_heap_size(100*1024*1024);
+ /* Otherwise heap expansion aborts when deallocating large block. */
+ /* That's OK. We test this corner case mostly to make sure that */
+ /* it fails predictably. */
+ GC_expand_hp(1024*1024*5);
+ if (sizeof(long) == sizeof(void *)) {
+ void *r = GC_MALLOC(LONG_MAX-1024);
+ if (0 != r) {
+ fprintf(stderr,
+ "Size LONG_MAX-1024 allocation unexpectedly succeeded\n");
+ exit(1);
+ }
+ r = GC_MALLOC(LONG_MAX);
+ if (0 != r) {
+ fprintf(stderr,
+ "Size LONG_MAX allocation unexpectedly succeeded\n");
+ exit(1);
+ }
+ r = GC_MALLOC((size_t)LONG_MAX + 1024);
+ if (0 != r) {
+ fprintf(stderr,
+ "Size LONG_MAX+1024 allocation unexpectedly succeeded\n");
+ exit(1);
+ }
+ }
+ return 0;
+}
diff --git a/boehm-gc/tests/initsecondarythread.c b/boehm-gc/tests/initsecondarythread.c
new file mode 100644
index 00000000000..4a13ca95f55
--- /dev/null
+++ b/boehm-gc/tests/initsecondarythread.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 Ludovic Courtes
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* Make sure 'GC_INIT' can be called from threads other than the initial
+ * thread.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef GC_THREADS
+# define GC_THREADS
+#endif
+
+#define GC_NO_THREAD_REDIRECTS 1
+ /* Do not redirect thread creation and join calls. */
+
+#include "gc.h"
+
+#ifdef GC_PTHREADS
+# include <pthread.h>
+#else
+# include <windows.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef GC_PTHREADS
+ static void *thread(void *arg)
+#else
+ static DWORD WINAPI thread(LPVOID arg)
+#endif
+{
+ GC_INIT();
+ (void)GC_MALLOC(123);
+ (void)GC_MALLOC(12345);
+# ifdef GC_PTHREADS
+ return arg;
+# else
+ return (DWORD)(GC_word)arg;
+# endif
+}
+
+#include "private/gcconfig.h"
+
+int main(void)
+{
+# ifdef GC_PTHREADS
+ int code;
+ pthread_t t;
+# else
+ HANDLE t;
+ DWORD thread_id;
+# endif
+# if !(defined(BEOS) || defined(MSWIN32) || defined(MSWINCE) \
+ || defined(CYGWIN32) || defined(GC_OPENBSD_THREADS) \
+ || (defined(DARWIN) && !defined(NO_PTHREAD_GET_STACKADDR_NP)) \
+ || (defined(LINUX) && !defined(NACL)) \
+ || (defined(GC_SOLARIS_THREADS) && !defined(_STRICT_STDC)) \
+ || (!defined(STACKBOTTOM) && (defined(HEURISTIC1) \
+ || (!defined(LINUX_STACKBOTTOM) && !defined(FREEBSD_STACKBOTTOM)))))
+ /* GC_INIT() must be called from main thread only. */
+ GC_INIT();
+# endif
+# ifdef GC_PTHREADS
+ if ((code = pthread_create (&t, NULL, thread, NULL)) != 0) {
+ fprintf(stderr, "Thread creation failed %d\n", code);
+ return 1;
+ }
+ if ((code = pthread_join (t, NULL)) != 0) {
+ fprintf(stderr, "Thread join failed %d\n", code);
+ return 1;
+ }
+# else
+ t = CreateThread(NULL, 0, thread, 0, 0, &thread_id);
+ if (t == NULL) {
+ fprintf(stderr, "Thread creation failed %d\n", (int)GetLastError());
+ return 1;
+ }
+ if (WaitForSingleObject(t, INFINITE) != WAIT_OBJECT_0) {
+ fprintf(stderr, "Thread join failed %d\n", (int)GetLastError());
+ CloseHandle(t);
+ return 1;
+ }
+ CloseHandle(t);
+# endif
+ return 0;
+}
diff --git a/boehm-gc/tests/leak_test.c b/boehm-gc/tests/leak_test.c
index 421d0c6cd4a..ae0a9af3878 100644
--- a/boehm-gc/tests/leak_test.c
+++ b/boehm-gc/tests/leak_test.c
@@ -1,10 +1,13 @@
#include "leak_detector.h"
-main() {
+int main(void) {
int *p[10];
int i;
- GC_find_leak = 1; /* for new collect versions not compiled */
- /* with -DFIND_LEAK. */
+ GC_set_find_leak(1); /* for new collect versions not compiled */
+ /* with -DFIND_LEAK. */
+
+ GC_INIT(); /* Needed if thread-local allocation is enabled. */
+ /* FIXME: This is not ideal. */
for (i = 0; i < 10; ++i) {
p[i] = malloc(sizeof(int)+i);
}
@@ -18,4 +21,5 @@ main() {
CHECK_LEAKS();
CHECK_LEAKS();
CHECK_LEAKS();
-}
+ return 0;
+}
diff --git a/boehm-gc/tests/middle.c b/boehm-gc/tests/middle.c
new file mode 100644
index 00000000000..55686f759cc
--- /dev/null
+++ b/boehm-gc/tests/middle.c
@@ -0,0 +1,25 @@
+/*
+ * Test at the boundary between small and large objects.
+ * Inspired by a test case from Zoltan Varga.
+ */
+#include "gc.h"
+#include <stdio.h>
+
+int main (void)
+{
+ int i;
+
+ GC_set_all_interior_pointers(0);
+ GC_INIT();
+
+ for (i = 0; i < 20000; ++i) {
+ (void)GC_malloc_atomic(4096);
+ (void)GC_malloc(4096);
+ }
+ for (i = 0; i < 20000; ++i) {
+ (void)GC_malloc_atomic(2048);
+ (void)GC_malloc(2048);
+ }
+ printf("Final heap size is %lu\n", (unsigned long)GC_get_heap_size());
+ return 0;
+}
diff --git a/boehm-gc/tests/realloc_test.c b/boehm-gc/tests/realloc_test.c
new file mode 100644
index 00000000000..1c1668f27d0
--- /dev/null
+++ b/boehm-gc/tests/realloc_test.c
@@ -0,0 +1,34 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gc.h"
+
+#define COUNT 10000000
+
+int main(void) {
+ int i;
+ unsigned long last_heap_size = 0;
+
+ GC_INIT();
+
+ for (i = 0; i < COUNT; i++) {
+ int **p = GC_MALLOC(sizeof(int *));
+ int *q = GC_MALLOC_ATOMIC(sizeof(int));
+
+ if (p == 0 || *p != 0) {
+ fprintf(stderr, "GC_malloc returned garbage (or NULL)\n");
+ exit(1);
+ }
+
+ *p = GC_REALLOC(q, 2 * sizeof(int));
+
+ if (i % 10 == 0) {
+ unsigned long heap_size = (unsigned long)GC_get_heap_size();
+ if (heap_size != last_heap_size) {
+ printf("Heap size: %lu\n", heap_size);
+ last_heap_size = heap_size;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/boehm-gc/tests/smash_test.c b/boehm-gc/tests/smash_test.c
new file mode 100644
index 00000000000..0e8b1f08089
--- /dev/null
+++ b/boehm-gc/tests/smash_test.c
@@ -0,0 +1,28 @@
+/*
+ * Test that overwrite error detection works reasonably.
+ */
+#define GC_DEBUG
+#include "gc.h"
+
+#include <stdio.h>
+
+#define COUNT 7000
+#define SIZE 40
+
+char * A[COUNT];
+
+int main(void)
+{
+ int i;
+ char *p;
+
+ GC_INIT();
+
+ for (i = 0; i < COUNT; ++i) {
+ A[i] = p = GC_MALLOC(SIZE);
+
+ if (i%3000 == 0) GC_gcollect();
+ if (i%5678 == 0 && p != 0) p[SIZE + i/2000] = 42;
+ }
+ return 0;
+}
diff --git a/boehm-gc/tests/staticrootslib.c b/boehm-gc/tests/staticrootslib.c
new file mode 100644
index 00000000000..2a8fcd49cd5
--- /dev/null
+++ b/boehm-gc/tests/staticrootslib.c
@@ -0,0 +1,33 @@
+
+/* This test file is intended to be compiled into a DLL. */
+
+#include <stdio.h>
+
+#ifndef GC_DEBUG
+# define GC_DEBUG
+#endif
+
+#include "gc.h"
+
+struct treenode {
+ struct treenode *x;
+ struct treenode *y;
+} * root[10];
+
+struct treenode * libsrl_mktree(int i)
+{
+ struct treenode * r = GC_MALLOC(sizeof(struct treenode));
+ if (0 == i) return 0;
+ if (1 == i) r = GC_MALLOC_ATOMIC(sizeof(struct treenode));
+ if (r) {
+ r -> x = libsrl_mktree(i-1);
+ r -> y = libsrl_mktree(i-1);
+ }
+ return r;
+}
+
+void * libsrl_init(void)
+{
+ GC_INIT();
+ return GC_MALLOC(sizeof(struct treenode));
+}
diff --git a/boehm-gc/tests/staticrootstest.c b/boehm-gc/tests/staticrootstest.c
new file mode 100644
index 00000000000..5d5cb3ebb75
--- /dev/null
+++ b/boehm-gc/tests/staticrootstest.c
@@ -0,0 +1,79 @@
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef GC_DEBUG
+# define GC_DEBUG
+#endif
+
+#include "gc.h"
+#include "gc_backptr.h"
+
+#ifndef GC_VISIBILITY_HIDDEN_SET
+
+struct treenode {
+ struct treenode *x;
+ struct treenode *y;
+} * root[10];
+
+static char *staticroot = 0;
+
+extern struct treenode * libsrl_mktree(int i);
+extern void * libsrl_init(void);
+
+/*
+struct treenode * mktree(int i) {
+ struct treenode * r = GC_MALLOC(sizeof(struct treenode));
+ if (0 == i) return 0;
+ if (1 == i) r = GC_MALLOC_ATOMIC(sizeof(struct treenode));
+ r -> x = mktree(i-1);
+ r -> y = mktree(i-1);
+ return r;
+}*/
+
+int main(void)
+{
+ int i;
+ /*GC_INIT();
+ staticroot = GC_MALLOC(sizeof(struct treenode));*/
+ staticroot = libsrl_init();
+ if (NULL == staticroot) {
+ fprintf(stderr, "GC_malloc returned NULL\n");
+ return 2;
+ }
+ memset(staticroot, 0x42, sizeof(struct treenode));
+ GC_gcollect();
+ for (i = 0; i < 10; ++i) {
+ root[i] = libsrl_mktree(12);
+ GC_gcollect();
+ }
+ for (i = 0; i < (int)sizeof(struct treenode); ++i) {
+ if (staticroot[i] != 0x42) {
+ fprintf(stderr, "Memory check failed\n");
+ return -1;
+ }
+ }
+ for (i = 0; i < 10; ++i) {
+ root[i] = libsrl_mktree(12);
+ GC_gcollect();
+ }
+ for (i = 0; i < (int)sizeof(struct treenode); ++i) {
+ if (staticroot[i] != 0x42) {
+ fprintf(stderr, "Memory check failed\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+#else
+
+/* Skip since symbols defined in staticrootslib are not visible */
+
+int main(void)
+{
+ printf("staticrootstest skipped\n");
+ return 0;
+}
+
+#endif
diff --git a/boehm-gc/tests/subthread_create.c b/boehm-gc/tests/subthread_create.c
new file mode 100644
index 00000000000..9a7095b6dd3
--- /dev/null
+++ b/boehm-gc/tests/subthread_create.c
@@ -0,0 +1,145 @@
+
+#ifdef HAVE_CONFIG_H
+ /* For PARALLEL_MARK */
+# include "config.h"
+#endif
+
+#ifndef GC_THREADS
+# define GC_THREADS
+#endif
+#include "gc.h"
+
+#ifdef PARALLEL_MARK
+# define AO_REQUIRE_CAS
+#endif
+#include "atomic_ops.h"
+
+#include <stdio.h>
+
+#ifdef AO_HAVE_fetch_and_add
+
+#ifdef GC_PTHREADS
+# include <pthread.h>
+#else
+# include <windows.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef MAX_SUBTHREAD_DEPTH
+# define INITIAL_THREAD_COUNT 31
+# define MAX_ALIVE_THREAD_COUNT 55
+# define MAX_SUBTHREAD_DEPTH 7
+# define MAX_SUBTHREAD_COUNT 200
+#endif
+
+#ifndef DECAY_NUMER
+# define DECAY_NUMER 15
+# define DECAY_DENOM 16
+#endif
+
+volatile AO_t thread_created_cnt = 0;
+volatile AO_t thread_ended_cnt = 0;
+
+#ifdef GC_PTHREADS
+ void *entry(void *arg)
+#else
+ DWORD WINAPI entry(LPVOID arg)
+#endif
+{
+ int thread_num = AO_fetch_and_add(&thread_created_cnt, 1);
+ GC_word my_depth = (GC_word)arg + 1;
+
+ if (my_depth <= MAX_SUBTHREAD_DEPTH
+ && thread_num < MAX_SUBTHREAD_COUNT
+ && (thread_num % DECAY_DENOM) < DECAY_NUMER
+ && (int)(thread_num - AO_load(&thread_ended_cnt))
+ <= MAX_ALIVE_THREAD_COUNT) {
+# ifdef GC_PTHREADS
+ int err;
+ pthread_t th;
+ err = pthread_create(&th, NULL, entry, (void *)my_depth);
+ if (err) {
+ fprintf(stderr, "Thread #%d creation failed: %s", thread_num,
+ strerror(err));
+ exit(2);
+ }
+# else
+ HANDLE th;
+ DWORD thread_id;
+ th = CreateThread(NULL, 0, entry, (LPVOID)my_depth, 0, &thread_id);
+ if (th == NULL) {
+ fprintf(stderr, "Thread #%d creation failed: %d\n", thread_num,
+ (int)GetLastError());
+ exit(2);
+ }
+ CloseHandle(th);
+# endif
+ }
+
+ AO_fetch_and_add(&thread_ended_cnt, 1);
+ return 0;
+}
+
+int main(void)
+{
+ int i;
+# ifdef GC_PTHREADS
+ int err;
+ pthread_t th[INITIAL_THREAD_COUNT];
+# else
+ HANDLE th[INITIAL_THREAD_COUNT];
+# endif
+
+ GC_INIT();
+ for (i = 0; i < INITIAL_THREAD_COUNT; ++i) {
+# ifdef GC_PTHREADS
+ err = pthread_create(&th[i], NULL, entry, 0);
+ if (err) {
+ fprintf(stderr, "Thread creation failed: %s", strerror(err));
+ exit(1);
+ }
+# else
+ DWORD thread_id;
+ th[i] = CreateThread(NULL, 0, entry, 0, 0, &thread_id);
+ if (th[i] == NULL) {
+ fprintf(stderr, "Thread creation failed: %d\n",
+ (int)GetLastError());
+ exit(1);
+ }
+# endif
+ }
+
+ for (i = 0; i < INITIAL_THREAD_COUNT; ++i) {
+# ifdef GC_PTHREADS
+ void *res;
+ err = pthread_join(th[i], &res);
+ if (err) {
+ fprintf(stderr, "Failed to join thread: %s", strerror(err));
+ exit(1);
+ }
+# else
+ if (WaitForSingleObject(th[i], INFINITE) != WAIT_OBJECT_0) {
+ fprintf(stderr, "Failed to join thread: %d\n",
+ (int)GetLastError());
+ CloseHandle(th[i]);
+ exit(1);
+ }
+ CloseHandle(th[i]);
+# endif
+ }
+ printf("subthread_create: created %d threads (%d ended)\n",
+ (int)AO_load(&thread_created_cnt), (int)AO_load(&thread_ended_cnt));
+ return 0;
+}
+
+#else
+
+int main(void)
+{
+ printf("subthread_create test skipped\n");
+ return 0;
+}
+
+#endif /* !AO_HAVE_fetch_and_add */
diff --git a/boehm-gc/tests/test.c b/boehm-gc/tests/test.c
index e1676aadead..7309755b609 100644
--- a/boehm-gc/tests/test.c
+++ b/boehm-gc/tests/test.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
@@ -12,72 +12,143 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* An incomplete test for the garbage collector. */
-/* Some more obscure entry points are not tested at all. */
-/* This must be compiled with the same flags used to build the */
-/* GC. It uses GC internals to allow more precise results */
-/* checking for some of the tests. */
+/* An incomplete test for the garbage collector. */
+/* Some more obscure entry points are not tested at all. */
+/* This must be compiled with the same flags used to build the */
+/* GC. It uses GC internals to allow more precise results */
+/* checking for some of the tests. */
+
+# ifdef HAVE_CONFIG_H
+# include "config.h"
+# endif
# undef GC_BUILD
-#if defined(DBG_HDRS_ALL) || defined(MAKE_BACK_GRAPH)
+#if (defined(DBG_HDRS_ALL) || defined(MAKE_BACK_GRAPH)) && !defined(GC_DEBUG)
# define GC_DEBUG
#endif
+#include "gc.h"
+
+#ifndef NTHREADS /* Number of additional threads to fork. */
+# define NTHREADS 5 /* excludes main thread, which also runs a test. */
+ /* Not respected by PCR test. */
+#endif
+
# if defined(mips) && defined(SYSTYPE_BSD43)
/* MIPS RISCOS 4 */
# else
# include <stdlib.h>
# endif
# include <stdio.h>
-# ifdef _WIN32_WCE
+# if defined(_WIN32_WCE) && !defined(__GNUC__)
# include <winbase.h>
-# define assert ASSERT
+/* # define assert ASSERT */
# else
-# include <assert.h> /* Not normally used, but handy for debugging. */
+# include <assert.h> /* Not normally used, but handy for debugging. */
# endif
-# include <assert.h> /* Not normally used, but handy for debugging. */
-# include "gc.h"
+
# include "gc_typed.h"
-# ifdef THREAD_LOCAL_ALLOC
-# include "gc_local_alloc.h"
-# endif
-# include "private/gc_priv.h" /* For output, locking, MIN_WORDS, */
- /* and some statistics. */
-# include "private/gcconfig.h"
+# include "private/gc_priv.h" /* For output, locking, MIN_WORDS, */
+ /* some statistics and gcconfig.h. */
# if defined(MSWIN32) || defined(MSWINCE)
# include <windows.h>
# endif
+#ifdef GC_PRINT_VERBOSE_STATS
+# define print_stats VERBOSE
+# define INIT_PRINT_STATS /* empty */
+#else
+ /* Use own variable as GC_print_stats might not be exported. */
+ static int print_stats = 0;
+# ifdef GC_READ_ENV_FILE
+ /* GETENV uses GC internal function in this case. */
+# define INIT_PRINT_STATS /* empty */
+# else
+# define INIT_PRINT_STATS \
+ { \
+ if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) \
+ print_stats = VERBOSE; \
+ else if (0 != GETENV("GC_PRINT_STATS")) \
+ print_stats = 1; \
+ }
+# endif
+#endif /* !GC_PRINT_VERBOSE_STATS */
+
# ifdef PCR
# include "th/PCR_ThCrSec.h"
# include "th/PCR_Th.h"
-# undef GC_printf0
-# define GC_printf0 printf
-# undef GC_printf1
-# define GC_printf1 printf
-# endif
-
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-# include <thread.h>
-# include <synch.h>
+# define GC_printf printf
# endif
# if defined(GC_PTHREADS)
# include <pthread.h>
# endif
+# if (!defined(THREADS) || !defined(HANDLE_FORK) \
+ || (defined(DARWIN) && defined(MPROTECT_VDB) \
+ && !defined(NO_INCREMENTAL) && !defined(MAKE_BACK_GRAPH))) \
+ && !defined(NO_TEST_HANDLE_FORK) && !defined(TEST_HANDLE_FORK) \
+ && !defined(TEST_FORK_WITHOUT_ATFORK)
+# define NO_TEST_HANDLE_FORK
+# endif
+
+# ifndef NO_TEST_HANDLE_FORK
+# include <unistd.h>
+# ifdef HANDLE_FORK
+# define INIT_FORK_SUPPORT GC_set_handle_fork(1)
+ /* Causes abort in GC_init on pthread_atfork failure. */
+# elif !defined(TEST_FORK_WITHOUT_ATFORK)
+# define INIT_FORK_SUPPORT GC_set_handle_fork(-1)
+ /* Passing -1 implies fork() should be as well manually */
+ /* surrounded with GC_atfork_prepare/parent/child. */
+# endif
+# endif
+
+# ifndef INIT_FORK_SUPPORT
+# define INIT_FORK_SUPPORT /* empty */
+# endif
+
# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
static CRITICAL_SECTION incr_cs;
# endif
-#ifdef __STDC__
# include <stdarg.h>
+
+#ifndef GC_ALPHA_VERSION
+# define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
+#endif
+
+#define CHECH_GCLIB_VERSION \
+ if (GC_get_version() != ((GC_VERSION_MAJOR<<16) \
+ | (GC_VERSION_MINOR<<8) \
+ | GC_ALPHA_VERSION)) { \
+ GC_printf("libgc version mismatch\n"); \
+ exit(1); \
+ }
+
+/* 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) \
+ || defined(PLATFORM_ANDROID) || defined(THREAD_LOCAL_ALLOC) \
+ || (defined(MSWINCE) && !defined(GC_WINMAIN_REDIRECT))
+# define GC_OPT_INIT GC_INIT()
+#else
+# define GC_OPT_INIT /* empty */
#endif
+#define GC_COND_INIT() \
+ INIT_FORK_SUPPORT; GC_OPT_INIT; CHECH_GCLIB_VERSION; INIT_PRINT_STATS
+
+#define CHECK_OUT_OF_MEMORY(p) \
+ if ((p) == NULL) { \
+ GC_printf("Out of memory\n"); \
+ exit(1); \
+ }
-/* Allocation Statistics */
+/* Allocation Statistics. Incremented without synchronization. */
+/* FIXME: We should be using synchronization. */
int stubborn_count = 0;
int uncollectable_count = 0;
int collectable_count = 0;
@@ -86,19 +157,17 @@ int realloc_count = 0;
#if defined(GC_AMIGA_FASTALLOC) && defined(AMIGA)
- extern void GC_amiga_free_all_mem(void);
+ void GC_amiga_free_all_mem(void);
void Amiga_Fail(void){GC_amiga_free_all_mem();abort();}
# define FAIL (void)Amiga_Fail()
void *GC_amiga_gctest_malloc_explicitly_typed(size_t lb, GC_descr d){
void *ret=GC_malloc_explicitly_typed(lb,d);
if(ret==NULL){
- if(!GC_dont_gc){
- GC_gcollect();
- ret=GC_malloc_explicitly_typed(lb,d);
- }
+ GC_gcollect();
+ ret=GC_malloc_explicitly_typed(lb,d);
if(ret==NULL){
- GC_printf0("Out of memory, (typed allocations are not directly "
- "supported with the GC_AMIGA_FASTALLOC option.)\n");
+ GC_printf("Out of memory, (typed allocations are not directly "
+ "supported with the GC_AMIGA_FASTALLOC option.)\n");
FAIL;
}
}
@@ -107,40 +176,34 @@ int realloc_count = 0;
void *GC_amiga_gctest_calloc_explicitly_typed(size_t a,size_t lb, GC_descr d){
void *ret=GC_calloc_explicitly_typed(a,lb,d);
if(ret==NULL){
- if(!GC_dont_gc){
- GC_gcollect();
- ret=GC_calloc_explicitly_typed(a,lb,d);
- }
+ GC_gcollect();
+ ret=GC_calloc_explicitly_typed(a,lb,d);
if(ret==NULL){
- GC_printf0("Out of memory, (typed allocations are not directly "
- "supported with the GC_AMIGA_FASTALLOC option.)\n");
+ GC_printf("Out of memory, (typed allocations are not directly "
+ "supported with the GC_AMIGA_FASTALLOC option.)\n");
FAIL;
}
}
return ret;
}
-# define GC_malloc_explicitly_typed(a,b) GC_amiga_gctest_malloc_explicitly_typed(a,b)
-# define GC_calloc_explicitly_typed(a,b,c) GC_amiga_gctest_calloc_explicitly_typed(a,b,c)
+# define GC_malloc_explicitly_typed(a,b) GC_amiga_gctest_malloc_explicitly_typed(a,b)
+# define GC_calloc_explicitly_typed(a,b,c) GC_amiga_gctest_calloc_explicitly_typed(a,b,c)
#else /* !AMIGA_FASTALLOC */
-# ifdef PCR
+# if defined(PCR) || defined(LINT2)
# define FAIL (void)abort()
# else
-# ifdef MSWINCE
-# define FAIL DebugBreak()
-# else
-# define FAIL GC_abort("Test failed");
-# endif
+# define FAIL ABORT("Test failed")
# endif
#endif /* !AMIGA_FASTALLOC */
-/* AT_END may be defined to exercise the interior pointer test */
+/* AT_END may be defined to exercise the interior pointer test */
/* if the collector is configured with ALL_INTERIOR_POINTERS. */
-/* As it stands, this test should succeed with either */
-/* configuration. In the FIND_LEAK configuration, it should */
-/* find lots of leaks, since we free almost nothing. */
+/* As it stands, this test should succeed with either */
+/* configuration. In the FIND_LEAK configuration, it should */
+/* find lots of leaks, since we free almost nothing. */
struct SEXPR {
struct SEXPR * sexpr_car;
@@ -150,7 +213,8 @@ struct SEXPR {
typedef struct SEXPR * sexpr;
-# define INT_TO_SEXPR(x) ((sexpr)(unsigned long)(x))
+# define INT_TO_SEXPR(x) ((sexpr)(GC_word)(x))
+# define SEXPR_TO_INT(x) ((int)(GC_word)(x))
# undef nil
# define nil (INT_TO_SEXPR(0))
@@ -166,31 +230,26 @@ int extra_count = 0; /* Amount of space wasted in cons node */
# ifdef VERY_SMALL_CONFIG
# define cons small_cons
# else
-sexpr cons (x, y)
-sexpr x;
-sexpr y;
+sexpr cons (sexpr x, sexpr y)
{
- register sexpr r;
- register int *p;
- register int my_extra = extra_count;
-
+ sexpr r;
+ int *p;
+ int my_extra = extra_count;
+
stubborn_count++;
r = (sexpr) GC_MALLOC_STUBBORN(sizeof(struct SEXPR) + my_extra);
- if (r == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
+ CHECK_OUT_OF_MEMORY(r);
for (p = (int *)r;
- ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
- if (*p) {
- (void)GC_printf1("Found nonzero at 0x%lx - allocator is broken\n",
- (unsigned long)p);
- FAIL;
+ (word)p < (word)r + my_extra + sizeof(struct SEXPR); p++) {
+ if (*p) {
+ GC_printf("Found nonzero at %p - allocator is broken\n",
+ (void *)p);
+ FAIL;
}
- *p = 13;
+ *p = (int)((13 << 12) + ((p - (int *)r) & 0xfff));
}
# ifdef AT_END
- r = (sexpr)((char *)r + (my_extra & ~7));
+ r = (sexpr)((char *)r + (my_extra & ~7));
# endif
r -> sexpr_car = x;
r -> sexpr_cdr = y;
@@ -200,7 +259,7 @@ sexpr y;
} else {
extra_count = my_extra;
}
- GC_END_STUBBORN_CHANGE((char *)r);
+ GC_END_STUBBORN_CHANGE(r);
return(r);
}
# endif
@@ -210,150 +269,79 @@ sexpr y;
#include "gc_mark.h"
#include "gc_gcj.h"
-/* The following struct emulates the vtable in gcj. */
+/* The following struct emulates the vtable in gcj. */
/* This assumes the default value of MARK_DESCR_OFFSET. */
struct fake_vtable {
- void * dummy; /* class pointer in real gcj. */
- size_t descr;
+ void * dummy; /* class pointer in real gcj. */
+ GC_word descr;
};
struct fake_vtable gcj_class_struct1 = { 0, sizeof(struct SEXPR)
- + sizeof(struct fake_vtable *) };
- /* length based descriptor. */
+ + sizeof(struct fake_vtable *) };
+ /* length based descriptor. */
struct fake_vtable gcj_class_struct2 =
- { 0, (3l << (CPP_WORDSZ - 3)) | GC_DS_BITMAP};
- /* Bitmap based descriptor. */
+ { 0, ((GC_word)3 << (CPP_WORDSZ - 3)) | GC_DS_BITMAP};
+ /* Bitmap based descriptor. */
struct GC_ms_entry * fake_gcj_mark_proc(word * addr,
- struct GC_ms_entry *mark_stack_ptr,
- struct GC_ms_entry *mark_stack_limit,
- word env )
+ struct GC_ms_entry *mark_stack_ptr,
+ struct GC_ms_entry *mark_stack_limit,
+ word env )
{
sexpr x;
if (1 == env) {
- /* Object allocated with debug allocator. */
- addr = (word *)GC_USR_PTR_FROM_BASE(addr);
+ /* Object allocated with debug allocator. */
+ addr = (word *)GC_USR_PTR_FROM_BASE(addr);
}
x = (sexpr)(addr + 1); /* Skip the vtable pointer. */
mark_stack_ptr = GC_MARK_AND_PUSH(
- (GC_PTR)(x -> sexpr_cdr), mark_stack_ptr,
- mark_stack_limit, (GC_PTR *)&(x -> sexpr_cdr));
+ (void *)(x -> sexpr_cdr), mark_stack_ptr,
+ mark_stack_limit, (void * *)&(x -> sexpr_cdr));
mark_stack_ptr = GC_MARK_AND_PUSH(
- (GC_PTR)(x -> sexpr_car), mark_stack_ptr,
- mark_stack_limit, (GC_PTR *)&(x -> sexpr_car));
+ (void *)(x -> sexpr_car), mark_stack_ptr,
+ mark_stack_limit, (void * *)&(x -> sexpr_car));
return(mark_stack_ptr);
}
#endif /* GC_GCJ_SUPPORT */
-#ifdef THREAD_LOCAL_ALLOC
-#undef GC_REDIRECT_TO_LOCAL
-#include "gc_local_alloc.h"
-
-sexpr local_cons (x, y)
-sexpr x;
-sexpr y;
+sexpr small_cons (sexpr x, sexpr y)
{
- register sexpr r;
- register int *p;
- register int my_extra = extra_count;
- static int my_random = 0;
-
- collectable_count++;
- r = (sexpr) GC_LOCAL_MALLOC(sizeof(struct SEXPR) + my_extra);
-# ifdef GC_GCJ_SUPPORT
- if (collectable_count % 2 == 0) {
- r = (sexpr) GC_LOCAL_GCJ_MALLOC(sizeof(struct SEXPR) + sizeof(GC_word) + my_extra,
- &gcj_class_struct1);
- r = (sexpr) ((GC_word *)r + 1);
- }
-# endif
- if (r == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
- for (p = (int *)r;
- ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
- if (*p) {
- (void)GC_printf1("Found nonzero at 0x%lx (local) - allocator is broken\n",
- (unsigned long)p);
- FAIL;
- }
- *p = 13;
- }
- r -> sexpr_car = x;
- r -> sexpr_cdr = y;
- my_extra++;
- if ( my_extra >= 5000 || my_extra == 200 && ++my_random % 37 != 0) {
- extra_count = 0;
- } else {
- extra_count = my_extra;
- }
- return(r);
-}
-#endif /* THREAD_LOCAL_ALLOC */
+ sexpr r;
-sexpr small_cons (x, y)
-sexpr x;
-sexpr y;
-{
- register sexpr r;
-
collectable_count++;
r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
- if (r == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
+ CHECK_OUT_OF_MEMORY(r);
r -> sexpr_car = x;
r -> sexpr_cdr = y;
return(r);
}
-sexpr small_cons_uncollectable (x, y)
-sexpr x;
-sexpr y;
+sexpr small_cons_uncollectable (sexpr x, sexpr y)
{
- register sexpr r;
-
+ sexpr r;
+
uncollectable_count++;
r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
- if (r == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
+ CHECK_OUT_OF_MEMORY(r);
r -> sexpr_car = x;
- r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
+ r -> sexpr_cdr = (sexpr)(~(GC_word)y);
return(r);
}
#ifdef GC_GCJ_SUPPORT
-sexpr gcj_cons(x, y)
-sexpr x;
-sexpr y;
+sexpr gcj_cons(sexpr x, sexpr y)
{
GC_word * r;
sexpr result;
- static int count = 0;
-
- if (++count & 1) {
-# ifdef USE_MARK_BYTES
- r = (GC_word *) GC_GCJ_FAST_MALLOC(4, &gcj_class_struct1);
-# else
- r = (GC_word *) GC_GCJ_FAST_MALLOC(3, &gcj_class_struct1);
-# endif
- } else {
- r = (GC_word *) GC_GCJ_MALLOC(sizeof(struct SEXPR)
- + sizeof(struct fake_vtable*),
- &gcj_class_struct2);
- }
- if (r == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
+
+ r = (GC_word *) GC_GCJ_MALLOC(sizeof(struct SEXPR)
+ + sizeof(struct fake_vtable*),
+ &gcj_class_struct2);
+ CHECK_OUT_OF_MEMORY(r);
result = (sexpr)(r + 1);
result -> sexpr_car = x;
result -> sexpr_cdr = y;
@@ -362,8 +350,7 @@ sexpr y;
#endif
/* Return reverse(x) concatenated with y */
-sexpr reverse1(x, y)
-sexpr x, y;
+sexpr reverse1(sexpr x, sexpr y)
{
if (is_nil(x)) {
return(y);
@@ -372,8 +359,7 @@ sexpr x, y;
}
}
-sexpr reverse(x)
-sexpr x;
+sexpr reverse(sexpr x)
{
# ifdef TEST_WITH_SYSTEM_MALLOC
malloc(100000);
@@ -381,11 +367,10 @@ sexpr x;
return( reverse1(x, nil) );
}
-sexpr ints(low, up)
-int low, up;
+sexpr ints(int low, int up)
{
if (low > up) {
- return(nil);
+ return(nil);
} else {
return(small_cons(small_cons(INT_TO_SEXPR(low), nil), ints(low+1, up)));
}
@@ -393,8 +378,7 @@ int low, up;
#ifdef GC_GCJ_SUPPORT
/* Return reverse(x) concatenated with y */
-sexpr gcj_reverse1(x, y)
-sexpr x, y;
+sexpr gcj_reverse1(sexpr x, sexpr y)
{
if (is_nil(x)) {
return(y);
@@ -403,77 +387,43 @@ sexpr x, y;
}
}
-sexpr gcj_reverse(x)
-sexpr x;
+sexpr gcj_reverse(sexpr x)
{
return( gcj_reverse1(x, nil) );
}
-sexpr gcj_ints(low, up)
-int low, up;
+sexpr gcj_ints(int low, int up)
{
if (low > up) {
- return(nil);
+ return(nil);
} else {
return(gcj_cons(gcj_cons(INT_TO_SEXPR(low), nil), gcj_ints(low+1, up)));
}
}
#endif /* GC_GCJ_SUPPORT */
-#ifdef THREAD_LOCAL_ALLOC
-/* Return reverse(x) concatenated with y */
-sexpr local_reverse1(x, y)
-sexpr x, y;
-{
- if (is_nil(x)) {
- return(y);
- } else {
- return( local_reverse1(cdr(x), local_cons(car(x), y)) );
- }
-}
-
-sexpr local_reverse(x)
-sexpr x;
-{
- return( local_reverse1(x, nil) );
-}
-
-sexpr local_ints(low, up)
-int low, up;
-{
- if (low > up) {
- return(nil);
- } else {
- return(local_cons(local_cons(INT_TO_SEXPR(low), nil), local_ints(low+1, up)));
- }
-}
-#endif /* THREAD_LOCAL_ALLOC */
-
-/* To check uncollectable allocation we build lists with disguised cdr */
-/* pointers, and make sure they don't go away. */
-sexpr uncollectable_ints(low, up)
-int low, up;
+/* To check uncollectable allocation we build lists with disguised cdr */
+/* pointers, and make sure they don't go away. */
+sexpr uncollectable_ints(int low, int up)
{
if (low > up) {
- return(nil);
+ return(nil);
} else {
return(small_cons_uncollectable(small_cons(INT_TO_SEXPR(low), nil),
uncollectable_ints(low+1, up)));
}
}
-void check_ints(list, low, up)
-sexpr list;
-int low, up;
+void check_ints(sexpr list, int low, int up)
{
- if ((int)(GC_word)(car(car(list))) != low) {
- (void)GC_printf0(
+ if (SEXPR_TO_INT(car(car(list))) != low) {
+ GC_printf(
"List reversal produced incorrect list - collector is broken\n");
FAIL;
}
if (low == up) {
if (cdr(list) != nil) {
- (void)GC_printf0("List too long - collector is broken\n");
+ GC_printf("List too long - collector is broken\n");
FAIL;
}
} else {
@@ -481,40 +431,58 @@ int low, up;
}
}
-# define UNCOLLECTABLE_CDR(x) (sexpr)(~(unsigned long)(cdr(x)))
+# define UNCOLLECTABLE_CDR(x) (sexpr)(~(GC_word)(cdr(x)))
-void check_uncollectable_ints(list, low, up)
-sexpr list;
-int low, up;
+void check_uncollectable_ints(sexpr list, int low, int up)
{
- if ((int)(GC_word)(car(car(list))) != low) {
- (void)GC_printf0(
- "Uncollectable list corrupted - collector is broken\n");
+ if (SEXPR_TO_INT(car(car(list))) != low) {
+ GC_printf("Uncollectable list corrupted - collector is broken\n");
FAIL;
}
if (low == up) {
- if (UNCOLLECTABLE_CDR(list) != nil) {
- (void)GC_printf0("Uncollectable list too long - collector is broken\n");
- FAIL;
- }
+ if (UNCOLLECTABLE_CDR(list) != nil) {
+ GC_printf("Uncollectable list too long - collector is broken\n");
+ FAIL;
+ }
} else {
check_uncollectable_ints(UNCOLLECTABLE_CDR(list), low+1, up);
}
}
/* Not used, but useful for debugging: */
-void print_int_list(x)
-sexpr x;
+void print_int_list(sexpr x)
{
if (is_nil(x)) {
- (void)GC_printf0("NIL\n");
+ GC_printf("NIL\n");
} else {
- (void)GC_printf1("(%ld)", (long)(car(car(x))));
+ GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
if (!is_nil(cdr(x))) {
- (void)GC_printf0(", ");
- (void)print_int_list(cdr(x));
+ GC_printf(", ");
+ print_int_list(cdr(x));
} else {
- (void)GC_printf0("\n");
+ GC_printf("\n");
+ }
+ }
+}
+
+/* ditto: */
+void check_marks_int_list(sexpr x)
+{
+ if (!GC_is_marked(x))
+ GC_printf("[unm:%p]", (void *)x);
+ else
+ GC_printf("[mkd:%p]", (void *)x);
+ if (is_nil(x)) {
+ GC_printf("NIL\n");
+ } else {
+ if (!GC_is_marked(car(x)))
+ GC_printf("[unm car:%p]", (void *)car(x));
+ GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
+ if (!is_nil(cdr(x))) {
+ GC_printf(", ");
+ check_marks_int_list(cdr(x));
+ } else {
+ GC_printf("\n");
}
}
}
@@ -524,70 +492,65 @@ sexpr x;
*/
#ifdef THREADS
-# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
- DWORD __stdcall tiny_reverse_test(void * arg)
+# ifdef VERY_SMALL_CONFIG
+# define TINY_REVERSE_UPPER_VALUE 4
+# else
+# define TINY_REVERSE_UPPER_VALUE 10
+# endif
+
+# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
+ DWORD __stdcall tiny_reverse_test(void * arg GC_ATTR_UNUSED)
# else
- void * tiny_reverse_test(void * arg)
+ void * tiny_reverse_test(void * arg GC_ATTR_UNUSED)
# endif
{
int i;
for (i = 0; i < 5; ++i) {
- check_ints(reverse(reverse(ints(1,10))), 1, 10);
-# ifdef THREAD_LOCAL_ALLOC
- check_ints(local_reverse(local_reverse(local_ints(1,10))), 1, 10);
-# endif
+ check_ints(reverse(reverse(ints(1, TINY_REVERSE_UPPER_VALUE))),
+ 1, TINY_REVERSE_UPPER_VALUE);
}
return 0;
}
# if defined(GC_PTHREADS)
- void fork_a_thread()
+ void fork_a_thread(void)
{
pthread_t t;
int code;
if ((code = pthread_create(&t, 0, tiny_reverse_test, 0)) != 0) {
- (void)GC_printf1("Small thread creation failed %lu\n",
- (unsigned long)code);
- FAIL;
+ GC_printf("Small thread creation failed %d\n", code);
+ FAIL;
}
if ((code = pthread_join(t, 0)) != 0) {
- (void)GC_printf1("Small thread join failed %lu\n",
- (unsigned long)code);
+ GC_printf("Small thread join failed %d\n", code);
FAIL;
}
}
# elif defined(GC_WIN32_THREADS)
- void fork_a_thread()
+ void fork_a_thread(void)
{
- DWORD thread_id;
- HANDLE h;
- h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
+ DWORD thread_id;
+ HANDLE h;
+ h = GC_CreateThread((SECURITY_ATTRIBUTES *)NULL, (word)0,
+ tiny_reverse_test, NULL, (DWORD)0, &thread_id);
+ /* Explicitly specify types of the */
+ /* arguments to test the prototype. */
if (h == (HANDLE)NULL) {
- (void)GC_printf1("Small thread creation failed %lu\n",
- (unsigned long)GetLastError());
- FAIL;
+ GC_printf("Small thread creation failed %d\n",
+ (int)GetLastError());
+ FAIL;
+ }
+ if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
+ GC_printf("Small thread wait failed %d\n",
+ (int)GetLastError());
+ FAIL;
}
- if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
- (void)GC_printf1("Small thread wait failed %lu\n",
- (unsigned long)GetLastError());
- FAIL;
- }
}
-/* # elif defined(GC_SOLARIS_THREADS) */
-
-# else
-
-# define fork_a_thread()
-
# endif
-#else
-
-# define fork_a_thread()
-
-#endif
+#endif
/* Try to force a to be strangely aligned */
struct {
@@ -600,7 +563,7 @@ struct {
* Repeatedly reverse lists built out of very different sized cons cells.
* Check that we didn't lose anything.
*/
-void reverse_test()
+void *GC_CALLBACK reverse_test_inner(void *data)
{
int i;
sexpr b;
@@ -608,26 +571,28 @@ void reverse_test()
sexpr d;
sexpr e;
sexpr *f, *g, *h;
-# if defined(MSWIN32) || defined(MACOS)
+
+ if (data == 0) {
+ /* This stack frame is not guaranteed to be scanned. */
+ return GC_call_with_gc_active(reverse_test_inner, (void*)(word)1);
+ }
+
+# if /*defined(MSWIN32) ||*/ defined(MACOS)
/* Win32S only allows 128K stacks */
# define BIG 1000
+# elif defined(PCR)
+ /* PCR default stack is 100K. Stack frames are up to 120 bytes. */
+# define BIG 700
+# elif defined(MSWINCE) || defined(RTEMS)
+ /* WinCE only allows 64K stacks */
+# define BIG 500
+# elif defined(OSF1)
+ /* OSF has limited stack space by default, and large frames. */
+# define BIG 200
+# elif defined(__MACH__) && defined(__ppc64__)
+# define BIG 2500
# else
-# if defined PCR
- /* PCR default stack is 100K. Stack frames are up to 120 bytes. */
-# define BIG 700
-# else
-# if defined MSWINCE
- /* WinCE only allows 64K stacks */
-# define BIG 500
-# else
-# if defined(OSF1)
- /* OSF has limited stack space by default, and large frames. */
-# define BIG 200
-# else
-# define BIG 4500
-# endif
-# endif
-# endif
+# define BIG 4500
# endif
A.dummy = 17;
@@ -640,38 +605,38 @@ void reverse_test()
collectable_count++;
f = (sexpr *)GC_MALLOC(4 * sizeof(sexpr));
realloc_count++;
- f = (sexpr *)GC_REALLOC((GC_PTR)f, 6 * sizeof(sexpr));
+ f = (sexpr *)GC_REALLOC((void *)f, 6 * sizeof(sexpr));
+ CHECK_OUT_OF_MEMORY(f);
f[5] = ints(1,17);
collectable_count++;
g = (sexpr *)GC_MALLOC(513 * sizeof(sexpr));
realloc_count++;
- g = (sexpr *)GC_REALLOC((GC_PTR)g, 800 * sizeof(sexpr));
+ g = (sexpr *)GC_REALLOC((void *)g, 800 * sizeof(sexpr));
+ CHECK_OUT_OF_MEMORY(g);
g[799] = ints(1,18);
collectable_count++;
h = (sexpr *)GC_MALLOC(1025 * sizeof(sexpr));
realloc_count++;
- h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr));
+ h = (sexpr *)GC_REALLOC((void *)h, 2000 * sizeof(sexpr));
+ CHECK_OUT_OF_MEMORY(h);
# ifdef GC_GCJ_SUPPORT
h[1999] = gcj_ints(1,200);
- for (i = 0; i < 51; ++i)
+ for (i = 0; i < 51; ++i)
h[1999] = gcj_reverse(h[1999]);
/* Leave it as the reveresed list for now. */
# else
h[1999] = ints(1,200);
# endif
/* Try to force some collections and reuse of small list elements */
- for (i = 0; i < 10; i++) {
- (void)ints(1, BIG);
- }
+ for (i = 0; i < 10; i++) {
+ (void)ints(1, BIG);
+ }
/* Superficially test interior pointer recognition on stack */
- c = (sexpr)((char *)c + sizeof(char *));
- d = (sexpr)((char *)d + sizeof(char *));
+ c = (sexpr)((char *)c + sizeof(char *));
+ d = (sexpr)((char *)d + sizeof(char *));
+
+ GC_FREE((void *)e);
-# ifdef __STDC__
- GC_FREE((void *)e);
-# else
- GC_FREE((char *)e);
-# endif
check_ints(b,1,50);
check_ints(a,1,49);
for (i = 0; i < 50; i++) {
@@ -681,27 +646,29 @@ void reverse_test()
check_ints(b,1,50);
check_ints(a,1,49);
for (i = 0; i < 60; i++) {
- if (i % 10 == 0) fork_a_thread();
- /* This maintains the invariant that a always points to a list of */
- /* 49 integers. Thus this is thread safe without locks, */
- /* assuming atomic pointer assignments. */
+# if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
+ if (i % 10 == 0) fork_a_thread();
+# endif
+ /* This maintains the invariant that a always points to a list of */
+ /* 49 integers. Thus this is thread safe without locks, */
+ /* assuming atomic pointer assignments. */
a = reverse(reverse(a));
-# ifdef THREAD_LOCAL_ALLOC
- a = local_reverse(local_reverse(a));
-# endif
-# if !defined(AT_END) && !defined(THREADS)
- /* This is not thread safe, since realloc explicitly deallocates */
+# if !defined(AT_END) && !defined(THREADS)
+ /* This is not thread safe, since realloc explicitly deallocates */
if (i & 1) {
- a = (sexpr)GC_REALLOC((GC_PTR)a, 500);
+ a = (sexpr)GC_REALLOC((void *)a, 500);
} else {
- a = (sexpr)GC_REALLOC((GC_PTR)a, 8200);
+ a = (sexpr)GC_REALLOC((void *)a, 8200);
}
-# endif
+# endif
}
check_ints(a,1,49);
check_ints(b,1,50);
+
+ /* Restore c and d values. */
c = (sexpr)((char *)c - sizeof(char *));
d = (sexpr)((char *)d - sizeof(char *));
+
check_ints(c,1,BIG);
check_uncollectable_ints(d, 1, 100);
check_ints(f[5], 1,17);
@@ -711,9 +678,17 @@ void reverse_test()
# endif
check_ints(h[1999], 1,200);
# ifndef THREADS
- a = 0;
-# endif
- b = c = 0;
+ a = 0;
+# endif
+ *(sexpr volatile *)&b = 0;
+ *(sexpr volatile *)&c = 0;
+ return 0;
+}
+
+void reverse_test(void)
+{
+ /* Test GC_do_blocking/GC_call_with_gc_active. */
+ (void)GC_do_blocking(reverse_test_inner, 0);
}
#undef a
@@ -730,57 +705,40 @@ typedef struct treenode {
int finalizable_count = 0;
int finalized_count = 0;
-VOLATILE int dropped_something = 0;
+volatile int dropped_something = 0;
-# ifdef __STDC__
- void finalizer(void * obj, void * client_data)
-# else
- void finalizer(obj, client_data)
- char * obj;
- char * client_data;
-# endif
+void GC_CALLBACK finalizer(void * obj, void * client_data)
{
tn * t = (tn *)obj;
# ifdef PCR
PCR_ThCrSec_EnterSys();
# endif
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
- static mutex_t incr_lock;
- mutex_lock(&incr_lock);
-# endif
-# if defined(GC_PTHREADS)
+# if defined(GC_PTHREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock);
-# else
-# ifdef GC_WIN32_THREADS
- EnterCriticalSection(&incr_cs);
-# endif
+# elif defined(GC_WIN32_THREADS)
+ EnterCriticalSection(&incr_cs);
# endif
if ((int)(GC_word)client_data != t -> level) {
- (void)GC_printf0("Wrong finalization data - collector is broken\n");
+ GC_printf("Wrong finalization data - collector is broken\n");
FAIL;
}
finalized_count++;
- t -> level = -1; /* detect duplicate finalization immediately */
+ t -> level = -1; /* detect duplicate finalization immediately */
# ifdef PCR
PCR_ThCrSec_ExitSys();
# endif
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
- mutex_unlock(&incr_lock);
-# endif
# if defined(GC_PTHREADS)
pthread_mutex_unlock(&incr_lock);
-# else
-# ifdef GC_WIN32_THREADS
- LeaveCriticalSection(&incr_cs);
-# endif
+# elif defined(GC_WIN32_THREADS)
+ LeaveCriticalSection(&incr_cs);
# endif
}
size_t counter = 0;
-# define MAX_FINALIZED 8000
+# define MAX_FINALIZED (NTHREADS*4000)
# if !defined(MACOS)
GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0};
@@ -791,184 +749,136 @@ size_t counter = 0;
int live_indicators_count = 0;
-tn * mktree(n)
-int n;
+tn * mktree(int n)
{
-# ifdef THREAD_LOCAL_ALLOC
- tn * result = (tn *)GC_LOCAL_MALLOC(sizeof(tn));
-# else
- tn * result = (tn *)GC_MALLOC(sizeof(tn));
-# endif
-
+ tn * result = (tn *)GC_MALLOC(sizeof(tn));
+
collectable_count++;
-# ifdef THREAD_LOCAL_ALLOC
- /* Minimally exercise thread local allocation */
- {
- char * result = (char *)GC_LOCAL_MALLOC_ATOMIC(17);
- memset(result, 'a', 17);
- }
-# endif /* THREAD_LOCAL_ALLOC */
# if defined(MACOS)
- /* get around static data limitations. */
- if (!live_indicators)
- live_indicators =
- (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
- if (!live_indicators) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
+ /* get around static data limitations. */
+ if (!live_indicators) {
+ live_indicators =
+ (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
+ CHECK_OUT_OF_MEMORY(live_indicators);
}
# endif
if (n == 0) return(0);
- if (result == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
+ CHECK_OUT_OF_MEMORY(result);
result -> level = n;
result -> lchild = mktree(n-1);
result -> rchild = mktree(n-1);
if (counter++ % 17 == 0 && n >= 2) {
- tn * tmp = result -> lchild -> rchild;
-
+ tn * tmp;
+
+ CHECK_OUT_OF_MEMORY(result->lchild);
+ tmp = result -> lchild -> rchild;
+ CHECK_OUT_OF_MEMORY(result->rchild);
result -> lchild -> rchild = result -> rchild -> lchild;
result -> rchild -> lchild = tmp;
}
if (counter++ % 119 == 0) {
- int my_index;
-
+# ifndef GC_NO_FINALIZATION
+ int my_index;
+ void *new_link;
+# endif
+
{
-# ifdef PCR
- PCR_ThCrSec_EnterSys();
-# endif
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
- static mutex_t incr_lock;
- mutex_lock(&incr_lock);
-# endif
+# ifdef PCR
+ PCR_ThCrSec_EnterSys();
+# endif
# if defined(GC_PTHREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock);
-# else
-# ifdef GC_WIN32_THREADS
- EnterCriticalSection(&incr_cs);
-# endif
+# elif defined(GC_WIN32_THREADS)
+ EnterCriticalSection(&incr_cs);
# endif
- /* Losing a count here causes erroneous report of failure. */
+ /* Losing a count here causes erroneous report of failure. */
finalizable_count++;
- my_index = live_indicators_count++;
-# ifdef PCR
- PCR_ThCrSec_ExitSys();
-# endif
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
- mutex_unlock(&incr_lock);
-# endif
-# if defined(GC_PTHREADS)
- pthread_mutex_unlock(&incr_lock);
-# else
-# ifdef GC_WIN32_THREADS
- LeaveCriticalSection(&incr_cs);
-# endif
+# ifndef GC_NO_FINALIZATION
+ my_index = live_indicators_count++;
+# endif
+# ifdef PCR
+ PCR_ThCrSec_ExitSys();
# endif
- }
+# if defined(GC_PTHREADS)
+ pthread_mutex_unlock(&incr_lock);
+# elif defined(GC_WIN32_THREADS)
+ LeaveCriticalSection(&incr_cs);
+# endif
+ }
- GC_REGISTER_FINALIZER((GC_PTR)result, finalizer, (GC_PTR)(GC_word)n,
- (GC_finalization_proc *)0, (GC_PTR *)0);
+# ifndef GC_NO_FINALIZATION
+ GC_REGISTER_FINALIZER((void *)result, finalizer, (void *)(GC_word)n,
+ (GC_finalization_proc *)0, (void * *)0);
if (my_index >= MAX_FINALIZED) {
- GC_printf0("live_indicators overflowed\n");
- FAIL;
- }
+ GC_printf("live_indicators overflowed\n");
+ FAIL;
+ }
live_indicators[my_index] = 13;
if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
- (GC_PTR *)(&(live_indicators[my_index])),
- (GC_PTR)result) != 0) {
- GC_printf0("GC_general_register_disappearing_link failed\n");
- FAIL;
+ (void * *)(&(live_indicators[my_index])), result) != 0) {
+ GC_printf("GC_general_register_disappearing_link failed\n");
+ FAIL;
+ }
+ if (GC_move_disappearing_link((void **)(&(live_indicators[my_index])),
+ (void **)(&(live_indicators[my_index]))) != GC_SUCCESS) {
+ GC_printf("GC_move_disappearing_link(link,link) failed\n");
+ FAIL;
+ }
+ new_link = (void *)live_indicators[my_index];
+ if (GC_move_disappearing_link((void **)(&(live_indicators[my_index])),
+ &new_link) != GC_SUCCESS) {
+ GC_printf("GC_move_disappearing_link(new_link) failed\n");
+ FAIL;
+ }
+ if (GC_unregister_disappearing_link(&new_link) == 0) {
+ GC_printf("GC_unregister_disappearing_link failed\n");
+ FAIL;
}
- if (GC_unregister_disappearing_link(
- (GC_PTR *)
- (&(live_indicators[my_index]))) == 0) {
- GC_printf0("GC_unregister_disappearing_link failed\n");
- FAIL;
+ if (GC_move_disappearing_link((void **)(&(live_indicators[my_index])),
+ &new_link) != GC_NOT_FOUND) {
+ GC_printf("GC_move_disappearing_link(new_link) failed 2\n");
+ FAIL;
}
if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
- (GC_PTR *)(&(live_indicators[my_index])),
- (GC_PTR)result) != 0) {
- GC_printf0("GC_general_register_disappearing_link failed 2\n");
- FAIL;
+ (void * *)(&(live_indicators[my_index])), result) != 0) {
+ GC_printf("GC_general_register_disappearing_link failed 2\n");
+ FAIL;
}
+# endif
+ GC_reachable_here(result);
}
return(result);
}
-void chktree(t,n)
-tn *t;
-int n;
+void chktree(tn *t, int n)
{
if (n == 0 && t != 0) {
- (void)GC_printf0("Clobbered a leaf - collector is broken\n");
+ GC_printf("Clobbered a leaf - collector is broken\n");
FAIL;
}
if (n == 0) return;
if (t -> level != n) {
- (void)GC_printf1("Lost a node at level %lu - collector is broken\n",
- (unsigned long)n);
+ GC_printf("Lost a node at level %d - collector is broken\n", n);
FAIL;
}
if (counter++ % 373 == 0) {
- collectable_count++;
- (void) GC_MALLOC(counter%5001);
+ collectable_count++;
+ (void) GC_MALLOC(counter%5001);
}
chktree(t -> lchild, n-1);
if (counter++ % 73 == 0) {
- collectable_count++;
- (void) GC_MALLOC(counter%373);
- }
- chktree(t -> rchild, n-1);
-}
-
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-thread_key_t fl_key;
-
-void * alloc8bytes()
-{
-# if defined(SMALL_CONFIG) || defined(GC_DEBUG)
- collectable_count++;
- return(GC_MALLOC(8));
-# else
- void ** my_free_list_ptr;
- void * my_free_list;
-
- if (thr_getspecific(fl_key, (void **)(&my_free_list_ptr)) != 0) {
- (void)GC_printf0("thr_getspecific failed\n");
- FAIL;
- }
- if (my_free_list_ptr == 0) {
- uncollectable_count++;
- my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
- if (thr_setspecific(fl_key, my_free_list_ptr) != 0) {
- (void)GC_printf0("thr_setspecific failed\n");
- FAIL;
- }
- }
- my_free_list = *my_free_list_ptr;
- if (my_free_list == 0) {
collectable_count++;
- my_free_list = GC_malloc_many(8);
- if (my_free_list == 0) {
- (void)GC_printf0("alloc8bytes out of memory\n");
- FAIL;
- }
+ (void) GC_MALLOC(counter%373);
}
- *my_free_list_ptr = GC_NEXT(my_free_list);
- GC_NEXT(my_free_list) = 0;
- return(my_free_list);
-# endif
+ chktree(t -> rchild, n-1);
}
-#else
-# if defined(GC_PTHREADS)
+#if defined(GC_PTHREADS)
pthread_key_t fl_key;
-void * alloc8bytes()
+void * alloc8bytes(void)
{
# if defined(SMALL_CONFIG) || defined(GC_DEBUG)
collectable_count++;
@@ -976,23 +886,21 @@ void * alloc8bytes()
# else
void ** my_free_list_ptr;
void * my_free_list;
-
+
my_free_list_ptr = (void **)pthread_getspecific(fl_key);
if (my_free_list_ptr == 0) {
uncollectable_count++;
my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
+ CHECK_OUT_OF_MEMORY(my_free_list_ptr);
if (pthread_setspecific(fl_key, my_free_list_ptr) != 0) {
- (void)GC_printf0("pthread_setspecific failed\n");
- FAIL;
+ GC_printf("pthread_setspecific failed\n");
+ FAIL;
}
}
my_free_list = *my_free_list_ptr;
if (my_free_list == 0) {
my_free_list = GC_malloc_many(8);
- if (my_free_list == 0) {
- (void)GC_printf0("alloc8bytes out of memory\n");
- FAIL;
- }
+ CHECK_OUT_OF_MEMORY(my_free_list);
}
*my_free_list_ptr = GC_NEXT(my_free_list);
GC_NEXT(my_free_list) = 0;
@@ -1001,20 +909,18 @@ void * alloc8bytes()
# endif
}
-# else
+#else
# define alloc8bytes() GC_MALLOC_ATOMIC(8)
-# endif
#endif
-void alloc_small(n)
-int n;
+void alloc_small(int n)
{
- register int i;
-
+ int i;
+
for (i = 0; i < n; i += 8) {
atomic_count++;
if (alloc8bytes() == 0) {
- (void)GC_printf0("Out of memory\n");
+ GC_printf("Out of memory\n");
FAIL;
}
}
@@ -1033,23 +939,23 @@ int n;
# define TREE_HEIGHT 16
# endif
# endif
-void tree_test()
+void tree_test(void)
{
tn * root;
- register int i;
-
+ int i;
+
root = mktree(TREE_HEIGHT);
# ifndef VERY_SMALL_CONFIG
alloc_small(5000000);
# endif
chktree(root, TREE_HEIGHT);
if (finalized_count && ! dropped_something) {
- (void)GC_printf0("Premature finalization - collector is broken\n");
+ GC_printf("Premature finalization - collector is broken\n");
FAIL;
}
dropped_something = 1;
- GC_noop(root); /* Root needs to remain live until */
- /* dropped_something is set. */
+ GC_noop1((word)root); /* Root needs to remain live until */
+ /* dropped_something is set. */
root = mktree(TREE_HEIGHT);
chktree(root, TREE_HEIGHT);
for (i = TREE_HEIGHT; i >= 0; i--) {
@@ -1063,7 +969,7 @@ void tree_test()
unsigned n_tests = 0;
-GC_word bm_huge[10] = {
+const GC_word bm_huge[10] = {
0xffffffff,
0xffffffff,
0xffffffff,
@@ -1076,8 +982,8 @@ GC_word bm_huge[10] = {
0x00ffffff,
};
-/* A very simple test of explicitly typed allocation */
-void typed_test()
+/* A very simple test of explicitly typed allocation */
+void typed_test(void)
{
GC_word * old, * new;
GC_word bm3 = 0x3;
@@ -1085,63 +991,67 @@ void typed_test()
GC_word bm_large = 0xf7ff7fff;
GC_descr d1 = GC_make_descriptor(&bm3, 2);
GC_descr d2 = GC_make_descriptor(&bm2, 2);
-# ifndef LINT
- GC_descr dummy = GC_make_descriptor(&bm_large, 32);
-# endif
GC_descr d3 = GC_make_descriptor(&bm_large, 32);
GC_descr d4 = GC_make_descriptor(bm_huge, 320);
GC_word * x = (GC_word *)GC_malloc_explicitly_typed(2000, d4);
- register int i;
-
+ int i;
+
+# ifndef LINT
+ (void)GC_make_descriptor(&bm_large, 32);
+# endif
collectable_count++;
old = 0;
for (i = 0; i < 4000; i++) {
- collectable_count++;
+ collectable_count++;
new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1);
+ CHECK_OUT_OF_MEMORY(new);
if (0 != new[0] || 0 != new[1]) {
- GC_printf0("Bad initialization by GC_malloc_explicitly_typed\n");
- FAIL;
- }
+ GC_printf("Bad initialization by GC_malloc_explicitly_typed\n");
+ FAIL;
+ }
new[0] = 17;
new[1] = (GC_word)old;
old = new;
- collectable_count++;
+ collectable_count++;
new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d2);
+ CHECK_OUT_OF_MEMORY(new);
new[0] = 17;
new[1] = (GC_word)old;
old = new;
- collectable_count++;
+ collectable_count++;
new = (GC_word *) GC_malloc_explicitly_typed(33 * sizeof(GC_word), d3);
+ CHECK_OUT_OF_MEMORY(new);
new[0] = 17;
new[1] = (GC_word)old;
old = new;
- collectable_count++;
+ collectable_count++;
new = (GC_word *) GC_calloc_explicitly_typed(4, 2 * sizeof(GC_word),
- d1);
+ d1);
+ CHECK_OUT_OF_MEMORY(new);
new[0] = 17;
new[1] = (GC_word)old;
old = new;
- collectable_count++;
+ collectable_count++;
if (i & 0xff) {
new = (GC_word *) GC_calloc_explicitly_typed(7, 3 * sizeof(GC_word),
- d2);
+ d2);
} else {
new = (GC_word *) GC_calloc_explicitly_typed(1001,
- 3 * sizeof(GC_word),
- d2);
- if (0 != new[0] || 0 != new[1]) {
- GC_printf0("Bad initialization by GC_malloc_explicitly_typed\n");
- FAIL;
- }
+ 3 * sizeof(GC_word),
+ d2);
+ if (new && (0 != new[0] || 0 != new[1])) {
+ GC_printf("Bad initialization by GC_malloc_explicitly_typed\n");
+ FAIL;
+ }
}
+ CHECK_OUT_OF_MEMORY(new);
new[0] = 17;
new[1] = (GC_word)old;
old = new;
}
for (i = 0; i < 20000; i++) {
if (new[0] != 17) {
- (void)GC_printf1("typed alloc failed at %lu\n",
- (unsigned long)i);
+ GC_printf("typed alloc failed at %lu\n", (unsigned long)i);
FAIL;
}
new[0] = 0;
@@ -1149,403 +1059,536 @@ void typed_test()
new = (GC_word *)(old[1]);
}
GC_gcollect();
- GC_noop(x);
+ GC_noop1((word)x);
}
int fail_count = 0;
-#ifndef __STDC__
-/*ARGSUSED*/
-void fail_proc1(x)
-GC_PTR x;
+void GC_CALLBACK fail_proc1(void *x GC_ATTR_UNUSED)
{
fail_count++;
}
-#else
-
-/*ARGSUSED*/
-void fail_proc1(GC_PTR x)
-{
- fail_count++;
-}
-
static void uniq(void *p, ...) {
va_list a;
void *q[100];
int n = 0, i, j;
q[n++] = p;
va_start(a,p);
- for (;(q[n] = va_arg(a,void *));n++) ;
+ for (;(q[n] = va_arg(a,void *)) != NULL;n++) ;
va_end(a);
for (i=0; i<n; i++)
for (j=0; j<i; j++)
if (q[i] == q[j]) {
- GC_printf0(
- "Apparently failed to mark form some function arguments.\n"
+ GC_printf(
+ "Apparently failed to mark from some function arguments.\n"
"Perhaps GC_push_regs was configured incorrectly?\n"
);
- FAIL;
+ FAIL;
}
}
-#endif /* __STDC__ */
-
#ifdef THREADS
# define TEST_FAIL_COUNT(n) 1
-#else
+#else
# define TEST_FAIL_COUNT(n) (fail_count >= (n))
#endif
-void run_one_test()
+void * GC_CALLBACK inc_int_counter(void *pcounter)
{
- char *x;
-# ifdef LINT
- char *y = 0;
-# else
- char *y = (char *)(size_t)fail_proc1;
+ ++(*(int *)pcounter);
+ return NULL;
+}
+
+void run_one_test(void)
+{
+# ifndef DBG_HDRS_ALL
+ char *x;
+ char **z;
+# ifdef LINT
+ char *y = 0;
+# else
+ char *y = (char *)(GC_word)fail_proc1;
+# endif
+ CLOCK_TYPE typed_time;
# endif
- DCL_LOCK_STATE;
-
+ CLOCK_TYPE start_time;
+ CLOCK_TYPE reverse_time;
+ CLOCK_TYPE tree_time;
+ unsigned long time_diff;
+
# ifdef FIND_LEAK
- (void)GC_printf0(
- "This test program is not designed for leak detection mode\n");
- (void)GC_printf0("Expect lots of problems.\n");
+ GC_printf(
+ "This test program is not designed for leak detection mode\n");
+ GC_printf("Expect lots of problems\n");
# endif
GC_FREE(0);
+# ifdef THREADS
+ if (!GC_thread_is_registered()) {
+ GC_printf("Current thread is not registered with GC\n");
+ FAIL;
+ }
+# endif
# ifndef DBG_HDRS_ALL
collectable_count += 3;
- if (GC_size(GC_malloc(7)) != 8 &&
- GC_size(GC_malloc(7)) != MIN_WORDS * sizeof(GC_word)
- || GC_size(GC_malloc(15)) != 16) {
- (void)GC_printf0("GC_size produced unexpected results\n");
- FAIL;
+ if ((GC_size(GC_malloc(7)) != 8 &&
+ GC_size(GC_malloc(7)) != MIN_WORDS * sizeof(GC_word))
+ || GC_size(GC_malloc(15)) != 16) {
+ GC_printf("GC_size produced unexpected results\n");
+ FAIL;
}
collectable_count += 1;
if (GC_size(GC_malloc(0)) != MIN_WORDS * sizeof(GC_word)) {
- (void)GC_printf1("GC_malloc(0) failed: GC_size returns %ld\n",
- GC_size(GC_malloc(0)));
- FAIL;
+ GC_printf("GC_malloc(0) failed: GC_size returns %lu\n",
+ (unsigned long)GC_size(GC_malloc(0)));
+ FAIL;
}
collectable_count += 1;
if (GC_size(GC_malloc_uncollectable(0)) != MIN_WORDS * sizeof(GC_word)) {
- (void)GC_printf0("GC_malloc_uncollectable(0) failed\n");
- 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_printf0("GC_base(heap ptr) produced incorrect result\n");
- FAIL;
+ if (GC_base(GC_PTR_ADD(x, 13)) != x) {
+ GC_printf("GC_base(heap ptr) produced incorrect result\n");
+ FAIL;
+ }
+ if (!GC_is_heap_ptr(x)) {
+ GC_printf("GC_is_heap_ptr(heap_ptr) produced incorrect result\n");
+ FAIL;
+ }
+ if (GC_is_heap_ptr(&x)) {
+ GC_printf("GC_is_heap_ptr(&local_var) produced incorrect result\n");
+ FAIL;
+ }
+ if (GC_is_heap_ptr(&fail_count) || GC_is_heap_ptr(NULL)) {
+ GC_printf("GC_is_heap_ptr(&global_var) produced incorrect result\n");
+ FAIL;
+ }
+ (void)GC_PRE_INCR(x, 0);
+ (void)GC_POST_INCR(x);
+ (void)GC_POST_DECR(x);
+ if (GC_base(x) != x) {
+ GC_printf("Bad INCR/DECR result\n");
+ FAIL;
}
# ifndef PCR
if (GC_base(y) != 0) {
- (void)GC_printf0("GC_base(fn_ptr) produced incorrect result\n");
- FAIL;
+ GC_printf("GC_base(fn_ptr) produced incorrect result\n");
+ FAIL;
}
# endif
if (GC_same_obj(x+5, x) != x + 5) {
- (void)GC_printf0("GC_same_obj produced incorrect result\n");
- FAIL;
+ GC_printf("GC_same_obj produced incorrect result\n");
+ FAIL;
}
if (GC_is_visible(y) != y || GC_is_visible(x) != x) {
- (void)GC_printf0("GC_is_visible produced incorrect result\n");
- FAIL;
+ 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", (void *)(*z), (void *)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 */
- /* data segment, so there should have been no failures. */
- /* The same applies to IA64. Something similar seems to */
- /* be going on with NetBSD/M68K. */
- (void)GC_printf0("GC_is_visible produced wrong failure indication\n");
- FAIL;
-# endif
+# 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. */
+ GC_printf("GC_is_visible produced wrong failure indication\n");
+ FAIL;
+# endif
}
if (GC_is_valid_displacement(y) != y
|| GC_is_valid_displacement(x) != x
|| GC_is_valid_displacement(x + 3) != x + 3) {
- (void)GC_printf0(
- "GC_is_valid_displacement produced incorrect result\n");
- FAIL;
+ GC_printf("GC_is_valid_displacement produced incorrect result\n");
+ FAIL;
}
-# if defined(__STDC__) && !defined(MSWIN32) && !defined(MSWINCE)
- /* Harder to test under Windows without a gc.h declaration. */
{
- size_t i;
- extern void *GC_memalign();
-
- GC_malloc(17);
- for (i = sizeof(GC_word); i < 512; i *= 2) {
- GC_word result = (GC_word) GC_memalign(i, 17);
- if (result % i != 0 || result == 0 || *(int *)result != 0) FAIL;
- }
- }
-# endif
+ size_t i;
+
+ (void)GC_malloc(17);
+ for (i = sizeof(GC_word); i < 512; i *= 2) {
+ GC_word result = (GC_word) GC_memalign(i, 17);
+ if (result % i != 0 || result == 0 || *(int *)result != 0) FAIL;
+ }
+ }
# ifndef ALL_INTERIOR_POINTERS
# if defined(RS6000) || defined(POWERPC)
- if (!TEST_FAIL_COUNT(1)) {
+ if (!TEST_FAIL_COUNT(1))
# else
- if (GC_all_interior_pointers && !TEST_FAIL_COUNT(1)
- || !GC_all_interior_pointers && !TEST_FAIL_COUNT(2)) {
+ if (!TEST_FAIL_COUNT(GC_get_all_interior_pointers() ? 1 : 2))
# endif
- (void)GC_printf0("GC_is_valid_displacement produced wrong failure indication\n");
- FAIL;
+ {
+ GC_printf(
+ "GC_is_valid_displacement produced wrong failure indication\n");
+ FAIL;
}
# endif
# endif /* DBG_HDRS_ALL */
/* Test floating point alignment */
- collectable_count += 2;
- *(double *)GC_MALLOC(sizeof(double)) = 1.0;
- *(double *)GC_MALLOC(sizeof(double)) = 1.0;
+ collectable_count += 2;
+ {
+ double *dp = GC_MALLOC(sizeof(double));
+ CHECK_OUT_OF_MEMORY(dp);
+ *dp = 1.0;
+ dp = GC_MALLOC(sizeof(double));
+ CHECK_OUT_OF_MEMORY(dp);
+ *dp = 1.0;
+ }
+ /* Test size 0 allocation a bit more */
+ {
+ size_t i;
+ for (i = 0; i < 10000; ++i) {
+ (void)GC_MALLOC(0);
+ GC_FREE(GC_MALLOC(0));
+ (void)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);
+ GC_init_gcj_malloc(0, (void *)(GC_word)fake_gcj_mark_proc);
# endif
- /* Make sure that fn arguments are visible to the collector. */
-# ifdef __STDC__
+ /* Make sure that fn arguments are visible to the collector. */
uniq(
GC_malloc(12), GC_malloc(12), GC_malloc(12),
(GC_gcollect(),GC_malloc(12)),
GC_malloc(12), GC_malloc(12), GC_malloc(12),
- (GC_gcollect(),GC_malloc(12)),
+ (GC_gcollect(),GC_malloc(12)),
GC_malloc(12), GC_malloc(12), GC_malloc(12),
- (GC_gcollect(),GC_malloc(12)),
+ (GC_gcollect(),GC_malloc(12)),
GC_malloc(12), GC_malloc(12), GC_malloc(12),
- (GC_gcollect(),GC_malloc(12)),
+ (GC_gcollect(),GC_malloc(12)),
GC_malloc(12), GC_malloc(12), GC_malloc(12),
- (GC_gcollect(),GC_malloc(12)),
+ (GC_gcollect(),GC_malloc(12)),
(void *)0);
+ /* GC_malloc(0) must return NULL or something we can deallocate. */
+ GC_free(GC_malloc(0));
+ GC_free(GC_malloc_atomic(0));
+ GC_free(GC_malloc(0));
+ GC_free(GC_malloc_atomic(0));
+# ifndef NO_TEST_HANDLE_FORK
+ GC_atfork_prepare();
+ if (fork() != 0) {
+ GC_atfork_parent();
+ if (print_stats)
+ GC_log_printf("Forked child process (or failed)\n");
+ } else {
+ GC_atfork_child();
+ if (print_stats)
+ GC_log_printf("Started a child process\n");
+# ifdef THREADS
+# ifdef PARALLEL_MARK
+ GC_gcollect(); /* no parallel markers */
+# endif
+ GC_start_mark_threads();
+# endif
+ GC_gcollect();
+# ifdef THREADS
+ tiny_reverse_test(0);
+ GC_gcollect();
+# endif
+ if (print_stats)
+ GC_log_printf("Finished a child process\n");
+ exit(0);
+ }
# endif
/* Repeated list reversal test. */
- reverse_test();
-# ifdef PRINTSTATS
- GC_printf0("-------------Finished reverse_test\n");
-# endif
+ GET_TIME(start_time);
+ reverse_test();
+ if (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, (void *)&start_time);
+ }
# ifndef DBG_HDRS_ALL
typed_test();
-# ifdef PRINTSTATS
- GC_printf0("-------------Finished typed_test\n");
-# endif
+ if (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, (void *)&start_time);
+ }
# endif /* DBG_HDRS_ALL */
tree_test();
- LOCK();
- n_tests++;
- UNLOCK();
-# if defined(THREADS) && defined(HANDLE_FORK)
- if (fork() == 0) {
- GC_gcollect();
- tiny_reverse_test(0);
- GC_gcollect();
- GC_printf0("Finished a child process\n");
- exit(0);
+ if (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, (void *)&start_time);
+ }
+ /* Run reverse_test a second time, so we hopefully notice corruption. */
+ reverse_test();
+ if (print_stats) {
+ GET_TIME(reverse_time);
+ time_diff = MS_TIME_DIFF(reverse_time, start_time);
+ GC_log_printf(
+ "-------------Finished second reverse_test at time %u (%p)\n",
+ (unsigned)time_diff, (void *)&start_time);
}
-# endif
- /* GC_printf1("Finished %x\n", pthread_self()); */
+ /* GC_allocate_ml and GC_need_to_lock are no longer exported, and */
+ /* AO_fetch_and_add1() may be unavailable to update a counter. */
+ (void)GC_call_with_alloc_lock(inc_int_counter, &n_tests);
+ if (print_stats)
+ GC_log_printf("Finished %p\n", (void *)&start_time);
}
-void check_heap_stats()
+#define NUMBER_ROUND_UP(v, bound) ((((v) + (bound) - 1) / (bound)) * (bound))
+
+void check_heap_stats(void)
{
- unsigned long max_heap_sz;
- register int i;
- int still_live;
- int late_finalize_count = 0;
-
+ size_t max_heap_sz;
+ int i;
+# ifndef GC_NO_FINALIZATION
+ int still_live;
+# ifdef FINALIZE_ON_DEMAND
+ int late_finalize_count = 0;
+# endif
+# endif
+
# ifdef VERY_SMALL_CONFIG
- /* these are something of a guess */
- if (sizeof(char *) > 4) {
+ /* The upper bounds are a guess, which has been empirically */
+ /* adjusted. On low end uniprocessors with incremental GC */
+ /* these may be particularly dubious, since empirically the */
+ /* heap tends to grow largely as a result of the GC not */
+ /* getting enough cycles. */
+# if CPP_WORDSZ == 64
max_heap_sz = 4500000;
- } else {
- max_heap_sz = 2800000;
- }
+# else
+ max_heap_sz = 2800000;
+# endif
# else
- if (sizeof(char *) > 4) {
- max_heap_sz = 19000000;
- } else {
- max_heap_sz = 11000000;
- }
+# if CPP_WORDSZ == 64
+ max_heap_sz = 23000000;
+# else
+ max_heap_sz = 16000000;
+# endif
# endif
# ifdef GC_DEBUG
- max_heap_sz *= 2;
+ max_heap_sz *= 2;
# ifdef SAVE_CALL_CHAIN
- max_heap_sz *= 3;
+ max_heap_sz *= 3;
# ifdef SAVE_CALL_COUNT
- max_heap_sz += max_heap_sz * SAVE_CALL_COUNT/4;
-# endif
+ max_heap_sz += max_heap_sz * SAVE_CALL_COUNT/4;
+# endif
# endif
# endif
- /* Garbage collect repeatedly so that all inaccessible objects */
- /* can be finalized. */
+ max_heap_sz *= n_tests;
+# if defined(USE_MMAP) || defined(MSWIN32)
+ max_heap_sz = NUMBER_ROUND_UP(max_heap_sz, 4 * 1024 * 1024);
+# endif
+ /* Garbage collect repeatedly so that all inaccessible objects */
+ /* can be finalized. */
while (GC_collect_a_little()) { }
for (i = 0; i < 16; i++) {
GC_gcollect();
- late_finalize_count += GC_invoke_finalizers();
+# ifndef GC_NO_FINALIZATION
+# ifdef FINALIZE_ON_DEMAND
+ late_finalize_count +=
+# endif
+ GC_invoke_finalizers();
+# endif
}
- (void)GC_printf1("Completed %lu tests\n", (unsigned long)n_tests);
- (void)GC_printf1("Allocated %lu collectable objects\n", (unsigned long)collectable_count);
- (void)GC_printf1("Allocated %lu uncollectable objects\n", (unsigned long)uncollectable_count);
- (void)GC_printf1("Allocated %lu atomic objects\n", (unsigned long)atomic_count);
- (void)GC_printf1("Allocated %lu stubborn objects\n", (unsigned long)stubborn_count);
- (void)GC_printf2("Finalized %lu/%lu objects - ",
- (unsigned long)finalized_count,
- (unsigned long)finalizable_count);
-# ifdef FINALIZE_ON_DEMAND
- if (finalized_count != late_finalize_count) {
- (void)GC_printf0("Demand finalization error\n");
- FAIL;
- }
-# endif
- if (finalized_count > finalizable_count
- || finalized_count < finalizable_count/2) {
- (void)GC_printf0("finalization is probably broken\n");
+ if (print_stats) {
+ struct GC_stack_base sb;
+ int res = GC_get_stack_base(&sb);
+
+ if (res == GC_SUCCESS) {
+ GC_log_printf("Primordial thread stack bottom: %p\n", sb.mem_base);
+ } else if (res == GC_UNIMPLEMENTED) {
+ GC_log_printf("GC_get_stack_base() unimplemented\n");
+ } else {
+ GC_printf("GC_get_stack_base() failed: %d\n", res);
+ FAIL;
+ }
+ }
+ GC_printf("Completed %u tests\n", n_tests);
+ GC_printf("Allocated %d collectable objects\n", collectable_count);
+ GC_printf("Allocated %d uncollectable objects\n",
+ uncollectable_count);
+ GC_printf("Allocated %d atomic objects\n", atomic_count);
+ GC_printf("Allocated %d stubborn objects\n", stubborn_count);
+ GC_printf("Finalized %d/%d objects - ",
+ finalized_count, finalizable_count);
+# ifndef GC_NO_FINALIZATION
+# ifdef FINALIZE_ON_DEMAND
+ if (finalized_count != late_finalize_count) {
+ GC_printf("Demand finalization error\n");
+ FAIL;
+ }
+# endif
+ if (finalized_count > finalizable_count
+ || finalized_count < finalizable_count/2) {
+ GC_printf("finalization is probably broken\n");
FAIL;
- } else {
- (void)GC_printf0("finalization is probably ok\n");
- }
- still_live = 0;
- for (i = 0; i < MAX_FINALIZED; i++) {
- if (live_indicators[i] != 0) {
- still_live++;
- }
- }
- i = finalizable_count - finalized_count - still_live;
- if (0 != i) {
- (void)GC_printf2
- ("%lu disappearing links remain and %ld more objects were not finalized\n",
- (unsigned long) still_live, (long)i);
+ } else {
+ GC_printf("finalization is probably ok\n");
+ }
+ still_live = 0;
+ for (i = 0; i < MAX_FINALIZED; i++) {
+ if (live_indicators[i] != 0) {
+ still_live++;
+ }
+ }
+ i = finalizable_count - finalized_count - still_live;
+ if (0 != i) {
+ GC_printf("%d disappearing links remain and %d more objects "
+ "were not finalized\n", still_live, i);
if (i > 10) {
- GC_printf0("\tVery suspicious!\n");
- } else {
- GC_printf0("\tSlightly suspicious, but probably OK.\n");
- }
- }
- (void)GC_printf1("Total number of bytes allocated is %lu\n",
- (unsigned long)
- WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc));
- (void)GC_printf1("Final heap size is %lu bytes\n",
- (unsigned long)GC_get_heap_size());
- if (WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc)
+ GC_printf("\tVery suspicious!\n");
+ } else {
+ GC_printf("\tSlightly suspicious, but probably OK\n");
+ }
+ }
+# endif
+ GC_printf("Total number of bytes allocated is %lu\n",
+ (unsigned long)GC_get_total_bytes());
+ GC_printf("Final heap size is %lu bytes\n",
+ (unsigned long)GC_get_heap_size());
+ if (GC_get_total_bytes() < n_tests *
# ifdef VERY_SMALL_CONFIG
- < 2700000*n_tests) {
+ 2700000
# else
- < 33500000*n_tests) {
+ 33500000
# endif
- (void)GC_printf0("Incorrect execution - missed some allocations\n");
- FAIL;
+ ) {
+ GC_printf("Incorrect execution - missed some allocations\n");
+ FAIL;
}
- if (GC_get_heap_size() > max_heap_sz*n_tests) {
- (void)GC_printf0("Unexpected heap growth - collector may be broken\n");
+ if (GC_get_heap_size() + GC_get_unmapped_bytes() > max_heap_sz) {
+ GC_printf("Unexpected heap growth - collector may be broken"
+ " (heapsize: %lu, expected: %lu)\n",
+ (unsigned long)(GC_get_heap_size() + GC_get_unmapped_bytes()),
+ (unsigned long)max_heap_sz);
FAIL;
}
- (void)GC_printf0("Collector appears to work\n");
+
+# ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
+ /* Get global counters (just to check the functions work). */
+ GC_get_heap_usage_safe(NULL, NULL, NULL, NULL, NULL);
+ {
+ struct GC_prof_stats_s stats;
+ (void)GC_get_prof_stats(&stats, sizeof(stats));
+# ifdef THREADS
+ (void)GC_get_prof_stats_unsafe(&stats, sizeof(stats));
+# endif
+ }
+# endif
+
+# ifdef THREADS
+ GC_unregister_my_thread(); /* just to check it works (for main) */
+# endif
+ GC_printf("Completed %u collections", (unsigned)GC_get_gc_no());
+# ifdef PARALLEL_MARK
+ GC_printf(" (using %d marker threads)", GC_get_parallel() + 1);
+# endif
+ GC_printf("\n" "Collector appears to work\n");
}
#if defined(MACOS)
void SetMinimumStack(long minSize)
{
- long newApplLimit;
-
- if (minSize > LMGetDefltStack())
- {
- newApplLimit = (long) GetApplLimit()
- - (minSize - LMGetDefltStack());
- SetApplLimit((Ptr) newApplLimit);
- MaxApplZone();
- }
+ long newApplLimit;
+
+ if (minSize > LMGetDefltStack())
+ {
+ newApplLimit = (long) GetApplLimit()
+ - (minSize - LMGetDefltStack());
+ SetApplLimit((Ptr) newApplLimit);
+ MaxApplZone();
+ }
}
#define cMinStackSpace (512L * 1024L)
#endif
-#ifdef __STDC__
- void warn_proc(char *msg, GC_word p)
-#else
- void warn_proc(msg, p)
- char *msg;
- GC_word p;
-#endif
+void GC_CALLBACK warn_proc(char *msg, GC_word p)
{
- GC_printf1(msg, (unsigned long)p);
+ GC_printf(msg, (unsigned long)p);
/*FAIL;*/
}
+#if defined(MSWINCE) && defined(UNDER_CE)
+# define WINMAIN_LPTSTR LPWSTR
+#else
+# define WINMAIN_LPTSTR LPSTR
+#endif
-#if !defined(PCR) && !defined(GC_SOLARIS_THREADS) \
- && !defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) \
+#if !defined(PCR) && !defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) \
|| defined(LINT)
-#if defined(MSWIN32) && !defined(__MINGW32__)
- int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPTSTR cmd, int n)
+#if defined(MSWIN32) && !defined(__MINGW32__) || defined(MSWINCE)
+ int APIENTRY WinMain(HINSTANCE instance GC_ATTR_UNUSED,
+ HINSTANCE prev GC_ATTR_UNUSED,
+ WINMAIN_LPTSTR cmd GC_ATTR_UNUSED,
+ int n GC_ATTR_UNUSED)
+#elif defined(RTEMS)
+# include <bsp.h>
+# define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+# define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+# define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+# define CONFIGURE_MAXIMUM_TASKS 1
+# define CONFIGURE_INIT
+# define CONFIGURE_INIT_TASK_STACK_SIZE (64*1024)
+# include <rtems/confdefs.h>
+ rtems_task Init(rtems_task_argument ignord)
#else
- int main()
+ int main(void)
#endif
{
-# if defined(DJGPP)
- int dummy;
-# endif
n_tests = 0;
-
-# if defined(DJGPP)
- /* No good way to determine stack base from library; do it */
- /* manually on this platform. */
- GC_stackbottom = (GC_PTR)(&dummy);
-# endif
# if defined(MACOS)
- /* Make sure we have lots and lots of stack space. */
- SetMinimumStack(cMinStackSpace);
- /* Cheat and let stdio initialize toolbox for us. */
- printf("Testing GC Macintosh port.\n");
+ /* Make sure we have lots and lots of stack space. */
+ SetMinimumStack(cMinStackSpace);
+ /* 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);
-# if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
- && !defined(MAKE_BACK_GRAPH)
+ 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_printf0("Switched to incremental mode\n");
+ GC_printf("Switched to incremental mode\n");
# if defined(MPROTECT_VDB)
- (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
+ GC_printf("Emulating dirty bits with mprotect/signals\n");
# else
# ifdef PROC_VDB
- (void)GC_printf0("Reading dirty bits from /proc\n");
+ GC_printf("Reading dirty bits from /proc\n");
+# elif defined(GWW_VDB)
+ GC_printf("Using GetWriteWatch-based implementation\n");
# else
- (void)GC_printf0("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);
-# endif
-# ifdef LINT
- /* Entry points we should be testing, but aren't. */
- /* Some can be tested by defining GC_DEBUG at the top of this file */
- /* This is a bit SunOS4 specific. */
- GC_noop(GC_expand_hp, GC_add_roots, GC_clear_roots,
- GC_register_disappearing_link,
- GC_register_finalizer_ignore_self,
- GC_debug_register_displacement,
- GC_print_obj, GC_debug_change_stubborn,
- GC_debug_end_stubborn_change, GC_debug_malloc_uncollectable,
- GC_debug_free, GC_debug_realloc, GC_generic_malloc_words_small,
- GC_init, GC_make_closure, GC_debug_invoke_finalizer,
- GC_page_was_ever_dirty, GC_is_fresh,
- GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page,
- GC_set_max_heap_size, GC_get_bytes_since_gc,
- GC_get_total_bytes, GC_pre_incr, GC_post_incr);
+ fflush(stdout);
# endif
# ifdef MSWIN32
GC_win32_free_heap();
# endif
- return(0);
+# ifdef RTEMS
+ exit(0);
+# else
+ return(0);
+# endif
}
# endif
-#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
+#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
-DWORD __stdcall thr_run_one_test(void *arg)
+DWORD __stdcall thr_run_one_test(void * arg GC_ATTR_UNUSED)
{
run_one_test();
return 0;
@@ -1555,16 +1598,18 @@ DWORD __stdcall thr_run_one_test(void *arg)
HANDLE win_created_h;
HWND win_handle;
-LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam,
+ LPARAM lParam)
{
LRESULT ret = 0;
switch (uMsg) {
case WM_HIBERNATE:
- GC_printf0("Received WM_HIBERNATE, calling GC_gcollect\n");
- GC_gcollect();
+ GC_printf("Received WM_HIBERNATE, calling GC_gcollect\n");
+ /* Force "unmap as much memory as possible" mode. */
+ GC_gcollect_and_unmap();
break;
case WM_CLOSE:
- GC_printf0("Received WM_CLOSE, closing window\n");
+ GC_printf("Received WM_CLOSE, closing window\n");
DestroyWindow(hwnd);
break;
case WM_DESTROY:
@@ -1577,7 +1622,7 @@ LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return ret;
}
-DWORD __stdcall thr_window(void *arg)
+DWORD __stdcall thr_window(void * arg GC_ATTR_UNUSED)
{
WNDCLASS win_class = {
CS_NOCLOSE,
@@ -1589,7 +1634,7 @@ DWORD __stdcall thr_window(void *arg)
NULL,
(HBRUSH)(COLOR_APPWORKSPACE+1),
NULL,
- L"GCtestWindow"
+ TEXT("GCtestWindow")
};
MSG msg;
@@ -1598,8 +1643,8 @@ DWORD __stdcall thr_window(void *arg)
win_handle = CreateWindowEx(
0,
- L"GCtestWindow",
- L"GCtest",
+ TEXT("GCtestWindow"),
+ TEXT("GCtest"),
0,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
@@ -1624,61 +1669,65 @@ DWORD __stdcall thr_window(void *arg)
}
#endif
-#define NTEST 2
-
-# ifdef MSWINCE
-int APIENTRY GC_WinMain(HINSTANCE instance, HINSTANCE prev, LPWSTR cmd, int n)
-# else
-int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
-# endif
+int APIENTRY WinMain(HINSTANCE instance GC_ATTR_UNUSED,
+ HINSTANCE prev GC_ATTR_UNUSED,
+ WINMAIN_LPTSTR cmd GC_ATTR_UNUSED,
+ int n GC_ATTR_UNUSED)
{
-# if NTEST > 0
- HANDLE h[NTEST];
+# if NTHREADS > 0
+ HANDLE h[NTHREADS];
int i;
# endif
# ifdef MSWINCE
HANDLE win_thr_h;
# endif
DWORD thread_id;
-# if 0
+# if defined(GC_DLL) && !defined(GC_NO_THREADS_DISCOVERY) \
+ && !defined(MSWINCE) && !defined(THREAD_LOCAL_ALLOC) \
+ && !defined(PARALLEL_MARK)
+ GC_use_threads_discovery();
+ /* Test with implicit thread registration if possible. */
+ GC_printf("Using DllMain to track threads\n");
+# endif
+ GC_COND_INIT();
+# if !defined(MAKE_BACK_GRAPH) && !defined(NO_INCREMENTAL)
GC_enable_incremental();
# endif
- GC_init();
InitializeCriticalSection(&incr_cs);
- (void) GC_set_warn_proc(warn_proc);
+ GC_set_warn_proc(warn_proc);
# ifdef MSWINCE
win_created_h = CreateEvent(NULL, FALSE, FALSE, NULL);
if (win_created_h == (HANDLE)NULL) {
- (void)GC_printf1("Event creation failed %lu\n", (unsigned long)GetLastError());
+ GC_printf("Event creation failed %d\n", (int)GetLastError());
FAIL;
}
win_thr_h = GC_CreateThread(NULL, 0, thr_window, 0, 0, &thread_id);
if (win_thr_h == (HANDLE)NULL) {
- (void)GC_printf1("Thread creation failed %lu\n", (unsigned long)GetLastError());
+ GC_printf("Thread creation failed %d\n", (int)GetLastError());
FAIL;
}
if (WaitForSingleObject(win_created_h, INFINITE) != WAIT_OBJECT_0)
FAIL;
CloseHandle(win_created_h);
# endif
-# if NTEST > 0
- for (i = 0; i < NTEST; i++) {
+# if NTHREADS > 0
+ for (i = 0; i < NTHREADS; i++) {
h[i] = GC_CreateThread(NULL, 0, thr_run_one_test, 0, 0, &thread_id);
if (h[i] == (HANDLE)NULL) {
- (void)GC_printf1("Thread creation failed %lu\n", (unsigned long)GetLastError());
+ GC_printf("Thread creation failed %d\n", (int)GetLastError());
FAIL;
}
}
-# endif /* NTEST > 0 */
+# endif /* NTHREADS > 0 */
run_one_test();
-# if NTEST > 0
- for (i = 0; i < NTEST; i++) {
+# if NTHREADS > 0
+ for (i = 0; i < NTHREADS; i++) {
if (WaitForSingleObject(h[i], INFINITE) != WAIT_OBJECT_0) {
- (void)GC_printf1("Thread wait failed %lu\n", (unsigned long)GetLastError());
+ GC_printf("Thread wait failed %d\n", (int)GetLastError());
FAIL;
}
}
-# endif /* NTEST > 0 */
+# endif /* NTHREADS > 0 */
# ifdef MSWINCE
PostMessage(win_handle, WM_CLOSE, 0, 0);
if (WaitForSingleObject(win_thr_h, INFINITE) != WAIT_OBJECT_0)
@@ -1692,7 +1741,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
#ifdef PCR
-test()
+int test(void)
{
PCR_Th_T * th1;
PCR_Th_T * th2;
@@ -1700,25 +1749,25 @@ test()
n_tests = 0;
/* GC_enable_incremental(); */
- (void) GC_set_warn_proc(warn_proc);
+ GC_set_warn_proc(warn_proc);
th1 = PCR_Th_Fork(run_one_test, 0);
th2 = PCR_Th_Fork(run_one_test, 0);
run_one_test();
if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
!= PCR_ERes_okay || code != 0) {
- (void)GC_printf0("Thread 1 failed\n");
+ GC_printf("Thread 1 failed\n");
}
if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
!= PCR_ERes_okay || code != 0) {
- (void)GC_printf0("Thread 2 failed\n");
+ GC_printf("Thread 2 failed\n");
}
check_heap_stats();
return(0);
}
#endif
-#if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS)
-void * thr_run_one_test(void * arg)
+#if defined(GC_PTHREADS)
+void * thr_run_one_test(void * arg GC_ATTR_UNUSED)
{
run_one_test();
return(0);
@@ -1728,119 +1777,83 @@ void * thr_run_one_test(void * arg)
# define GC_free GC_debug_free
#endif
-#if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
-main()
-{
- thread_t th1;
- thread_t th2;
- int code;
-
- n_tests = 0;
- GC_INIT(); /* Only needed if gc is dynamic library. */
-# ifndef MAKE_BACK_GRAPH
- GC_enable_incremental();
-# endif
- (void) GC_set_warn_proc(warn_proc);
- if (thr_keycreate(&fl_key, GC_free) != 0) {
- (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
- FAIL;
- }
- if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, 0, &th1)) != 0) {
- (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
- FAIL;
- }
- if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, THR_NEW_LWP, &th2)) != 0) {
- (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
- FAIL;
- }
- run_one_test();
- if ((code = thr_join(th1, 0, 0)) != 0) {
- (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
- FAIL;
- }
- if (thr_join(th2, 0, 0) != 0) {
- (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
- FAIL;
- }
- check_heap_stats();
- (void)fflush(stdout);
- return(0);
-}
-#else /* pthreads */
-
-#ifndef GC_PTHREADS
- --> bad news
-#endif
-
-main()
+int main(void)
{
- pthread_t th1;
- pthread_t th2;
+ pthread_t th[NTHREADS];
pthread_attr_t attr;
int code;
-
+ int i;
# ifdef GC_IRIX_THREADS
- /* Force a larger stack to be preallocated */
- /* Since the initial cant always grow later. */
- *((volatile char *)&code - 1024*1024) = 0; /* Require 1 Mb */
+ /* Force a larger stack to be preallocated */
+ /* Since the initial can't always grow later. */
+ *((volatile char *)&code - 1024*1024) = 0; /* Require 1 MB */
# endif /* GC_IRIX_THREADS */
# if defined(GC_HPUX_THREADS)
- /* Default stack size is too small, especially with the 64 bit ABI */
- /* Increase it. */
- if (pthread_default_stacksize_np(1024*1024, 0) != 0) {
- (void)GC_printf0("pthread_default_stacksize_np failed.\n");
- }
-# endif /* GC_HPUX_THREADS */
- GC_INIT();
+ /* Default stack size is too small, especially with the 64 bit ABI */
+ /* Increase it. */
+ if (pthread_default_stacksize_np(1024*1024, 0) != 0) {
+ GC_printf("pthread_default_stacksize_np failed\n");
+ }
+# endif /* GC_HPUX_THREADS */
+# ifdef PTW32_STATIC_LIB
+ pthread_win32_process_attach_np ();
+ pthread_win32_thread_attach_np ();
+# endif
+# if defined(GC_DARWIN_THREADS) && !defined(GC_NO_THREADS_DISCOVERY) \
+ && !defined(DARWIN_DONT_PARSE_STACK) && !defined(THREAD_LOCAL_ALLOC)
+ /* Test with the Darwin implicit thread registration. */
+ GC_use_threads_discovery();
+ GC_printf("Using Darwin task-threads-based world stop and push\n");
+# endif
+ GC_COND_INIT();
pthread_attr_init(&attr);
# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
- || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
- pthread_attr_setstacksize(&attr, 1000000);
+ || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS) \
+ || defined(GC_OPENBSD_THREADS)
+ pthread_attr_setstacksize(&attr, 1000000);
# endif
n_tests = 0;
-# if (defined(MPROTECT_VDB)) \
- && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) \
- && !defined(MAKE_BACK_GRAPH)
- GC_enable_incremental();
- (void) GC_printf0("Switched to incremental mode\n");
+# if (defined(MPROTECT_VDB)) && !defined(REDIRECT_MALLOC) \
+ && !defined(MAKE_BACK_GRAPH) && !defined(USE_PROC_FOR_LIBRARIES) \
+ && !defined(NO_INCREMENTAL)
+ GC_enable_incremental();
+ GC_printf("Switched to incremental mode\n");
# if defined(MPROTECT_VDB)
- (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
+ GC_printf("Emulating dirty bits with mprotect/signals\n");
# else
# ifdef PROC_VDB
- (void)GC_printf0("Reading dirty bits from /proc\n");
+ GC_printf("Reading dirty bits from /proc\n");
# else
- (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
+ GC_printf("Using DEFAULT_VDB dirty bit implementation\n");
# endif
# endif
# endif
- (void) GC_set_warn_proc(warn_proc);
+ GC_set_warn_proc(warn_proc);
if ((code = pthread_key_create(&fl_key, 0)) != 0) {
- (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
- FAIL;
- }
- if ((code = pthread_create(&th1, &attr, thr_run_one_test, 0)) != 0) {
- (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
- FAIL;
- }
- if ((code = pthread_create(&th2, &attr, thr_run_one_test, 0)) != 0) {
- (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
- FAIL;
+ GC_printf("Key creation failed %d\n", code);
+ FAIL;
}
- run_one_test();
- if ((code = pthread_join(th1, 0)) != 0) {
- (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
+ for (i = 0; i < NTHREADS; ++i) {
+ if ((code = pthread_create(th+i, &attr, thr_run_one_test, 0)) != 0) {
+ GC_printf("Thread %d creation failed %d\n", i, code);
FAIL;
+ }
}
- if (pthread_join(th2, 0) != 0) {
- (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
+ run_one_test();
+ for (i = 0; i < NTHREADS; ++i) {
+ if ((code = pthread_join(th[i], 0)) != 0) {
+ GC_printf("Thread %d failed %d\n", i, code);
FAIL;
+ }
}
check_heap_stats();
(void)fflush(stdout);
pthread_attr_destroy(&attr);
- GC_printf1("Completed %d collections\n", GC_gc_no);
+# ifdef PTW32_STATIC_LIB
+ pthread_win32_thread_detach_np ();
+ pthread_win32_process_detach_np ();
+# endif
return(0);
}
#endif /* GC_PTHREADS */
-#endif /* GC_SOLARIS_THREADS || GC_PTHREADS */
diff --git a/boehm-gc/tests/test_cpp.cc b/boehm-gc/tests/test_cpp.cc
index 6661e411927..dd11b92791b 100644
--- a/boehm-gc/tests/test_cpp.cc
+++ b/boehm-gc/tests/test_cpp.cc
@@ -1,17 +1,15 @@
/****************************************************************************
Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
+
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
+
Permission is hereby granted to use or copy this program for any
purpose, provided the above notices are retained on all copies.
Permission to modify the code and to distribute modified code is
granted, provided the above notices are retained, and a notice that
the code was modified is included with the above copyright notice.
****************************************************************************
-Last modified on Mon Jul 10 21:06:03 PDT 1995 by ellis
- modified on December 20, 1994 7:27 pm PST by boehm
usage: test_cpp number-of-iterations
@@ -24,49 +22,70 @@ few minutes to complete.
***************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#undef GC_BUILD
+
#include "gc_cpp.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#define USE_STD_ALLOCATOR
-#ifdef USE_STD_ALLOCATOR
-# include "gc_allocator.h"
-#elif __GNUC__
-# include "new_gc_alloc.h"
+
+#ifndef DONT_USE_STD_ALLOCATOR
+# include "gc_allocator.h"
#else
-# include "gc_alloc.h"
+ /* Note: This works only for ancient STL versions. */
+# include "new_gc_alloc.h"
#endif
+
extern "C" {
-#include "private/gc_priv.h"
+# include "private/gcconfig.h"
+
+# ifndef GC_API_PRIV
+# define GC_API_PRIV GC_API
+# endif
+ GC_API_PRIV void GC_printf(const char * format, ...);
+ /* Use GC private output to reach the same log file. */
+ /* Don't include gc_priv.h, since that may include Windows system */
+ /* header files that don't take kindly to this context. */
}
+
#ifdef MSWIN32
-# include <windows.h>
+# include <windows.h>
#endif
+
#ifdef GC_NAME_CONFLICT
-# define USE_GC UseGC
- struct foo * GC;
+# define USE_GC GC_NS_QUALIFY(UseGC)
+ struct foo * GC;
#else
-# define USE_GC GC
+# define USE_GC GC_NS_QUALIFY(GC)
#endif
-
#define my_assert( e ) \
if (! (e)) { \
- GC_printf1( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
+ GC_printf( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
__LINE__ ); \
exit( 1 ); }
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# define ATTR_UNUSED __attribute__((__unused__))
+#else
+# define ATTR_UNUSED /* empty */
+#endif
class A {public:
/* An uncollectable class. */
A( int iArg ): i( iArg ) {}
void Test( int iArg ) {
- my_assert( i == iArg );}
+ my_assert( i == iArg );}
int i;};
-class B: public gc, public A {public:
+class B: public GC_NS_QUALIFY(gc), public A { public:
/* A collectable class. */
B( int j ): A( j ) {}
@@ -79,7 +98,7 @@ class B: public gc, public A {public:
int B::deleting = 0;
-class C: public gc_cleanup, public A {public:
+class C: public GC_NS_QUALIFY(gc_cleanup), public A { public:
/* A collectable class with cleanup and virtual multiple inheritance. */
C( int levelArg ): A( levelArg ), level( levelArg ) {
@@ -92,7 +111,7 @@ class C: public gc_cleanup, public A {public:
~C() {
this->A::Test( level );
nFreed++;
- my_assert( level == 0 ?
+ my_assert( level == 0 ?
left == 0 && right == 0 :
level == left->level + 1 && level == right->level + 1 );
left = right = 0;
@@ -110,7 +129,7 @@ int C::nFreed = 0;
int C::nAllocated = 0;
-class D: public gc {public:
+class D: public GC_NS_QUALIFY(gc) { public:
/* A collectable class with a static member function to be used as
an explicit clean-up function supplied to ::new. */
@@ -119,10 +138,10 @@ class D: public gc {public:
static void CleanUp( void* obj, void* data ) {
D* self = (D*) obj;
nFreed++;
- my_assert( self->i == (int) (long) data );}
+ my_assert( self->i == (int) (GC_word) data );}
static void Test() {
my_assert( nFreed >= .8 * nAllocated );}
-
+
int i;
static int nFreed;
static int nAllocated;};
@@ -131,7 +150,7 @@ int D::nFreed = 0;
int D::nAllocated = 0;
-class E: public gc_cleanup {public:
+class E: public GC_NS_QUALIFY(gc_cleanup) { public:
/* A collectable class with clean-up for use by F. */
E() {
@@ -141,10 +160,10 @@ class E: public gc_cleanup {public:
static int nFreed;
static int nAllocated;};
-
+
int E::nFreed = 0;
int E::nAllocated = 0;
-
+
class F: public E {public:
/* A collectable class with clean-up, a base with clean-up, and a
@@ -157,104 +176,113 @@ class F: public E {public:
static void Test() {
my_assert( nFreed >= .8 * nAllocated );
my_assert( 2 * nFreed == E::nFreed );}
-
+
E e;
static int nFreed;
static int nAllocated;};
-
+
int F::nFreed = 0;
int F::nAllocated = 0;
-
-long Disguise( void* p ) {
- return ~ (long) p;}
-void* Undisguise( long i ) {
- return (void*) ~ i;}
+GC_word Disguise( void* p ) {
+ return ~ (GC_word) p;}
+void* Undisguise( GC_word i ) {
+ return (void*) ~ i;}
#ifdef MSWIN32
-int APIENTRY WinMain(
- HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int cmdShow )
+int APIENTRY WinMain( HINSTANCE instance ATTR_UNUSED,
+ HINSTANCE prev ATTR_UNUSED, LPSTR cmd, int cmdShow ATTR_UNUSED )
{
- int argc;
+ int argc = 0;
char* argv[ 3 ];
- for (argc = 1; argc < sizeof( argv ) / sizeof( argv[ 0 ] ); argc++) {
+ if (cmd != 0)
+ for (argc = 1; argc < (int)(sizeof(argv) / sizeof(argv[0])); argc++) {
argv[ argc ] = strtok( argc == 1 ? cmd : 0, " \t" );
if (0 == argv[ argc ]) break;}
-
+#elif defined(MACOS)
+ int main() {
+ char* argv_[] = {"test_cpp", "10"}; // MacOS doesn't have a commandline
+ argv = argv_;
+ argc = sizeof(argv_)/sizeof(argv_[0]);
#else
-# ifdef MACOS
- int main() {
-# else
- int main( int argc, char* argv[] ) {
-# endif
+ int main( int argc, char* argv[] ) {
#endif
- GC_INIT();
+ GC_set_all_interior_pointers(1);
+ /* needed due to C++ multiple inheritance used */
+
+ GC_INIT();
-# if defined(MACOS) // MacOS
- char* argv_[] = {"test_cpp", "10"}; // doesn't
- argv = argv_; // have a
- argc = sizeof(argv_)/sizeof(argv_[0]); // commandline
-# endif
int i, iters, n;
-# ifdef USE_STD_ALLOCATOR
+# ifndef DONT_USE_STD_ALLOCATOR
int *x = gc_allocator<int>().allocate(1);
+ int *xio;
+ xio = gc_allocator_ignore_off_page<int>().allocate(1);
+ (void)xio;
int **xptr = traceable_allocator<int *>().allocate(1);
-# else
-# ifdef __GNUC__
- int *x = (int *)gc_alloc::allocate(sizeof(int));
-# else
- int *x = (int *)alloc::allocate(sizeof(int));
-# endif
+# else
+ int *x = (int *)gc_alloc::allocate(sizeof(int));
# endif
*x = 29;
-# ifdef USE_STD_ALLOCATOR
+# ifndef DONT_USE_STD_ALLOCATOR
+ if (!xptr) {
+ fprintf(stderr, "Out of memory!\n");
+ exit(3);
+ }
*xptr = x;
x = 0;
# endif
if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
- GC_printf0( "usage: test_cpp number-of-iterations\nAssuming 10 iters\n" );
+ GC_printf( "usage: test_cpp number-of-iterations\nAssuming 10 iters\n" );
n = 10;}
-
+
for (iters = 1; iters <= n; iters++) {
- GC_printf1( "Starting iteration %d\n", iters );
+ GC_printf( "Starting iteration %d\n", iters );
/* Allocate some uncollectable As and disguise their pointers.
Later we'll check to see if the objects are still there. We're
checking to make sure these objects really are uncollectable. */
- long as[ 1000 ];
- long bs[ 1000 ];
+ GC_word as[ 1000 ];
+ GC_word bs[ 1000 ];
for (i = 0; i < 1000; i++) {
- as[ i ] = Disguise( new (NoGC) A( i ) );
- bs[ i ] = Disguise( new (NoGC) B( i ) );}
+ as[ i ] = Disguise( new (GC_NS_QUALIFY(NoGC)) A(i) );
+ bs[ i ] = Disguise( new (GC_NS_QUALIFY(NoGC)) B(i) ); }
/* Allocate a fair number of finalizable Cs, Ds, and Fs.
Later we'll check to make sure they've gone away. */
for (i = 0; i < 1000; i++) {
C* c = new C( 2 );
C c1( 2 ); /* stack allocation should work too */
- D* d = ::new (USE_GC, D::CleanUp, (void*)(long)i) D( i );
- F* f = new F;
+ D* d;
+ F* f;
+ d = ::new (USE_GC, D::CleanUp, (void*)(GC_word)i) D( i );
+ (void)d;
+ f = new F;
+ (void)f;
if (0 == i % 10) delete c;}
/* Allocate a very large number of collectable As and Bs and
drop the references to them immediately, forcing many
collections. */
for (i = 0; i < 1000000; i++) {
- A* a = new (USE_GC) A( i );
- B* b = new B( i );
+ A* a;
+ a = new (USE_GC) A( i );
+ (void)a;
+ B* b;
+ b = new B( i );
+ (void)b;
b = new (USE_GC) B( i );
if (0 == i % 10) {
B::Deleting( 1 );
delete b;
B::Deleting( 0 );}
-# ifdef FINALIZE_ON_DEMAND
- GC_invoke_finalizers();
-# endif
- }
+# ifdef FINALIZE_ON_DEMAND
+ GC_invoke_finalizers();
+# endif
+ }
/* Make sure the uncollectable As and Bs are still there. */
for (i = 0; i < 1000; i++) {
@@ -266,11 +294,10 @@ int APIENTRY WinMain(
B::Deleting( 1 );
delete b;
B::Deleting( 0 );
-# ifdef FINALIZE_ON_DEMAND
- GC_invoke_finalizers();
-# endif
-
- }
+# ifdef FINALIZE_ON_DEMAND
+ GC_invoke_finalizers();
+# endif
+ }
/* Make sure most of the finalizable Cs, Ds, and Fs have
gone away. */
@@ -278,11 +305,10 @@ int APIENTRY WinMain(
D::Test();
F::Test();}
-# ifdef USE_STD_ALLOCATOR
+# ifndef DONT_USE_STD_ALLOCATOR
x = *xptr;
# endif
my_assert (29 == x[0]);
- GC_printf0( "The test appears to have succeeded.\n" );
- return( 0 );}
-
-
+ GC_printf( "The test appears to have succeeded.\n" );
+ return( 0 );
+}
diff --git a/boehm-gc/tests/tests.am b/boehm-gc/tests/tests.am
new file mode 100644
index 00000000000..9864bb46a81
--- /dev/null
+++ b/boehm-gc/tests/tests.am
@@ -0,0 +1,104 @@
+#
+# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+#
+# Permission is hereby granted to use or copy this program
+# for any purpose, provided the above notices are retained on all copies.
+# Permission to modify the code and to distribute modified code is granted,
+# provided the above notices are retained, and a notice that the code was
+# modified is included with the above copyright notice.
+
+# Common libs to _LDADD for all tests.
+test_ldadd = $(top_builddir)/libgc.la $(EXTRA_TEST_LIBS)
+
+TESTS += gctest$(EXEEXT)
+check_PROGRAMS += gctest
+gctest_SOURCES = tests/test.c
+gctest_LDADD = $(test_ldadd)
+gctest_DEPENDENCIES = $(top_builddir)/libgc.la
+
+TESTS += leaktest$(EXEEXT)
+check_PROGRAMS += leaktest
+leaktest_SOURCES = tests/leak_test.c
+leaktest_LDADD = $(test_ldadd)
+
+TESTS += middletest$(EXEEXT)
+check_PROGRAMS += middletest
+middletest_SOURCES = tests/middle.c
+middletest_LDADD = $(test_ldadd)
+
+TESTS += 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 += realloc_test$(EXEEXT)
+check_PROGRAMS += realloc_test
+realloc_test_SOURCES = tests/realloc_test.c
+realloc_test_LDADD = $(test_ldadd)
+
+TESTS += staticrootstest$(EXEEXT)
+check_PROGRAMS += staticrootstest
+staticrootstest_SOURCES = tests/staticrootstest.c
+staticrootstest_LDADD = $(test_ldadd) libstaticrootslib.la
+check_LTLIBRARIES += libstaticrootslib.la
+libstaticrootslib_la_SOURCES = tests/staticrootslib.c
+libstaticrootslib_la_LIBADD = $(test_ldadd)
+libstaticrootslib_la_LDFLAGS = -version-info 1:3:0 -no-undefined -rpath /nowhere
+libstaticrootslib_la_DEPENDENCIES = $(top_builddir)/libgc.la
+
+if KEEP_BACK_PTRS
+TESTS += tracetest$(EXEEXT)
+check_PROGRAMS += tracetest
+tracetest_SOURCES = tests/trace_test.c
+tracetest_LDADD = $(test_ldadd)
+endif
+
+if THREADS
+TESTS += threadleaktest$(EXEEXT)
+check_PROGRAMS += threadleaktest
+threadleaktest_SOURCES = tests/thread_leak_test.c
+threadleaktest_LDADD = $(test_ldadd)
+
+TESTS += threadkey_test$(EXEEXT)
+check_PROGRAMS += threadkey_test
+threadkey_test_SOURCES = tests/threadkey_test.c
+threadkey_test_LDADD = $(test_ldadd)
+
+TESTS += subthread_create$(EXEEXT)
+check_PROGRAMS += subthread_create
+subthread_create_SOURCES = tests/subthread_create.c
+subthread_create_LDADD = $(test_ldadd)
+
+TESTS += initsecondarythread$(EXEEXT)
+check_PROGRAMS += initsecondarythread
+initsecondarythread_SOURCES = tests/initsecondarythread.c
+initsecondarythread_LDADD = $(test_ldadd)
+endif
+
+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) $(CXXLIBS)
+else
+test_cpp_LDADD = libgccpp.la $(test_ldadd) $(CXXLIBS)
+endif
+endif
+
+if ENABLE_DISCLAIM
+TESTS += disclaim_test
+check_PROGRAMS += disclaim_test
+disclaim_test_SOURCES = tests/disclaim_test.c
+disclaim_test_LDADD = $(test_ldadd)
+TESTS += disclaim_bench
+check_PROGRAMS += disclaim_bench
+disclaim_bench_SOURCES = tests/disclaim_bench.c
+disclaim_bench_LDADD = $(test_ldadd)
+endif
diff --git a/boehm-gc/tests/thread_leak_test.c b/boehm-gc/tests/thread_leak_test.c
index 1174705e45e..845de00ecd9 100644
--- a/boehm-gc/tests/thread_leak_test.c
+++ b/boehm-gc/tests/thread_leak_test.c
@@ -1,13 +1,30 @@
-#define GC_LINUX_THREADS
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef GC_THREADS
+# define GC_THREADS
+#endif
+
#include "leak_detector.h"
-#include <pthread.h>
+
+#ifdef GC_PTHREADS
+# include <pthread.h>
+#else
+# include <windows.h>
+#endif
+
#include <stdio.h>
-void * test(void * arg) {
+#ifdef GC_PTHREADS
+ void * test(void * arg)
+#else
+ DWORD WINAPI test(LPVOID arg)
+#endif
+{
int *p[10];
int i;
- GC_find_leak = 1; /* for new collect versions not compiled */
- /* with -DFIND_LEAK. */
for (i = 0; i < 10; ++i) {
p[i] = malloc(sizeof(int)+i);
}
@@ -15,26 +32,57 @@ void * test(void * arg) {
for (i = 1; i < 10; ++i) {
free(p[i]);
}
-}
+# ifdef GC_PTHREADS
+ return arg;
+# else
+ return (DWORD)(GC_word)arg;
+# endif
+}
#define NTHREADS 5
-main() {
+int main(void) {
int i;
- pthread_t t[NTHREADS];
+# ifdef GC_PTHREADS
+ pthread_t t[NTHREADS];
+# else
+ HANDLE t[NTHREADS];
+ DWORD thread_id;
+# endif
int code;
+ GC_set_find_leak(1); /* for new collect versions not compiled */
+ /* with -DFIND_LEAK. */
+ GC_INIT();
+
for (i = 0; i < NTHREADS; ++i) {
- if ((code = pthread_create(t + i, 0, test, 0)) != 0) {
- printf("Thread creation failed %d\n", code);
+# ifdef GC_PTHREADS
+ code = pthread_create(t + i, 0, test, 0);
+# else
+ t[i] = CreateThread(NULL, 0, test, 0, 0, &thread_id);
+ code = t[i] != NULL ? 0 : (int)GetLastError();
+# endif
+ if (code != 0) {
+ fprintf(stderr, "Thread creation failed %d\n", code);
+ exit(2);
}
}
+
for (i = 0; i < NTHREADS; ++i) {
- if ((code = pthread_join(t[i], 0)) != 0) {
- printf("Thread join failed %lu\n", code);
+# ifdef GC_PTHREADS
+ code = pthread_join(t[i], 0);
+# else
+ code = WaitForSingleObject(t[i], INFINITE) == WAIT_OBJECT_0 ? 0 :
+ (int)GetLastError();
+# endif
+ if (code != 0) {
+ fprintf(stderr, "Thread join failed %d\n", code);
+ exit(2);
}
}
+
CHECK_LEAKS();
CHECK_LEAKS();
CHECK_LEAKS();
+ return 0;
}
diff --git a/boehm-gc/tests/threadkey_test.c b/boehm-gc/tests/threadkey_test.c
new file mode 100644
index 00000000000..f87530e3323
--- /dev/null
+++ b/boehm-gc/tests/threadkey_test.c
@@ -0,0 +1,100 @@
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef GC_THREADS
+# define GC_THREADS
+#endif
+
+#define GC_NO_THREAD_REDIRECTS 1
+
+#include "gc.h"
+
+#if (!defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
+ || defined(__native_client__)) && !defined(SKIP_THREADKEY_TEST)
+ /* FIXME: Skip this test on Solaris for now. The test may fail on */
+ /* other targets as well. Currently, tested only on Linux, Cygwin */
+ /* and Darwin. */
+# define SKIP_THREADKEY_TEST
+#endif
+
+#ifdef SKIP_THREADKEY_TEST
+
+#include <stdio.h>
+
+int main (void)
+{
+ printf("threadkey_test skipped\n");
+ return 0;
+}
+
+#else
+
+#include <pthread.h>
+
+pthread_key_t key;
+
+#ifdef GC_SOLARIS_THREADS
+ /* pthread_once_t key_once = { PTHREAD_ONCE_INIT }; */
+#else
+ pthread_once_t key_once = PTHREAD_ONCE_INIT;
+#endif
+
+void * entry (void *arg)
+{
+ pthread_setspecific(key,
+ (void *)GC_HIDE_POINTER(GC_STRDUP("hello, world")));
+ return arg;
+}
+
+void * GC_CALLBACK on_thread_exit_inner (struct GC_stack_base * sb, void * arg)
+{
+ int res = GC_register_my_thread (sb);
+ pthread_t t;
+ int creation_res; /* Used to suppress a warning about */
+ /* unchecked pthread_create() result. */
+
+ creation_res = GC_pthread_create (&t, NULL, entry, NULL);
+ if (res == GC_SUCCESS)
+ GC_unregister_my_thread ();
+
+ return arg ? (void*)(GC_word)creation_res : 0;
+}
+
+void on_thread_exit (void *v)
+{
+ GC_call_with_stack_base (on_thread_exit_inner, v);
+}
+
+void make_key (void)
+{
+ pthread_key_create (&key, on_thread_exit);
+}
+
+#ifndef LIMIT
+# define LIMIT 30
+#endif
+
+int main (void)
+{
+ int i;
+ GC_INIT ();
+
+# ifdef GC_SOLARIS_THREADS
+ pthread_key_create (&key, on_thread_exit);
+# else
+ pthread_once (&key_once, make_key);
+# endif
+ for (i = 0; i < LIMIT; i++) {
+ pthread_t t;
+ void *res;
+ if (GC_pthread_create (&t, NULL, entry, NULL) == 0
+ && (i & 1) != 0) {
+ (void)GC_pthread_join(t, &res);
+ }
+ }
+ return 0;
+}
+
+#endif /* !SKIP_THREADKEY_TEST */
diff --git a/boehm-gc/tests/trace_test.c b/boehm-gc/tests/trace_test.c
index 870e38723a8..79c353f71a6 100644
--- a/boehm-gc/tests/trace_test.c
+++ b/boehm-gc/tests/trace_test.c
@@ -1,6 +1,12 @@
#include <stdio.h>
-#define GC_DEBUG
+#include <stdlib.h>
+
+#ifndef GC_DEBUG
+# define GC_DEBUG
+#endif
+
#include "gc.h"
+#include "gc_backptr.h"
struct treenode {
struct treenode *x;
@@ -11,14 +17,19 @@ struct treenode * mktree(int i) {
struct treenode * r = GC_MALLOC(sizeof(struct treenode));
if (0 == i) return 0;
if (1 == i) r = GC_MALLOC_ATOMIC(sizeof(struct treenode));
+ if (r == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
r -> x = mktree(i-1);
r -> y = mktree(i-1);
return r;
}
-main()
+int main(void)
{
int i;
+ GC_INIT();
for (i = 0; i < 10; ++i) {
root[i] = mktree(12);
}
@@ -26,4 +37,5 @@ main()
GC_generate_random_backtrace();
GC_generate_random_backtrace();
GC_generate_random_backtrace();
+ return 0;
}
diff --git a/boehm-gc/thread_local_alloc.c b/boehm-gc/thread_local_alloc.c
new file mode 100644
index 00000000000..e4fdc854dde
--- /dev/null
+++ b/boehm-gc/thread_local_alloc.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2000-2005 by Hewlett-Packard Company. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#include "private/gc_priv.h"
+
+#if defined(THREAD_LOCAL_ALLOC)
+
+#ifndef THREADS
+# error "invalid config - THREAD_LOCAL_ALLOC requires GC_THREADS"
+#endif
+
+#include "private/thread_local_alloc.h"
+
+#include <stdlib.h>
+
+#if defined(USE_COMPILER_TLS)
+ __thread
+#elif defined(USE_WIN32_COMPILER_TLS)
+ __declspec(thread)
+#endif
+GC_key_t GC_thread_key;
+
+static GC_bool keys_initialized;
+
+#ifdef ENABLE_DISCLAIM
+ GC_INNER ptr_t * GC_finalized_objfreelist = NULL;
+ /* This variable is declared here to prevent linking of */
+ /* fnlz_mlc module unless the client uses the latter one. */
+#endif
+
+/* Return a single nonempty freelist fl to the global one pointed to */
+/* by gfl. */
+
+static void return_single_freelist(void *fl, void **gfl)
+{
+ void *q, **qptr;
+
+ if (*gfl == 0) {
+ *gfl = fl;
+ } else {
+ GC_ASSERT(GC_size(fl) == GC_size(*gfl));
+ /* Concatenate: */
+ qptr = &(obj_link(fl));
+ while ((word)(q = *qptr) >= HBLKSIZE)
+ qptr = &(obj_link(q));
+ GC_ASSERT(0 == q);
+ *qptr = *gfl;
+ *gfl = fl;
+ }
+}
+
+/* Recover the contents of the freelist array fl into the global one gfl.*/
+/* We hold the allocator lock. */
+static void return_freelists(void **fl, void **gfl)
+{
+ int i;
+
+ for (i = 1; i < TINY_FREELISTS; ++i) {
+ if ((word)(fl[i]) >= HBLKSIZE) {
+ return_single_freelist(fl[i], gfl+i);
+ }
+ /* Clear fl[i], since the thread structure may hang around. */
+ /* Do it in a way that is likely to trap if we access it. */
+ fl[i] = (ptr_t)HBLKSIZE;
+ }
+ /* The 0 granule freelist really contains 1 granule objects. */
+# ifdef GC_GCJ_SUPPORT
+ if (fl[0] == ERROR_FL) return;
+# endif
+ if ((word)(fl[0]) >= HBLKSIZE) {
+ return_single_freelist(fl[0], gfl+1);
+ }
+}
+
+/* Each thread structure must be initialized. */
+/* This call must be made from the new thread. */
+GC_INNER void GC_init_thread_local(GC_tlfs p)
+{
+ int i;
+
+ GC_ASSERT(I_HOLD_LOCK());
+ if (!EXPECT(keys_initialized, TRUE)) {
+ GC_ASSERT((word)&GC_thread_key % sizeof(word) == 0);
+ if (0 != GC_key_create(&GC_thread_key, 0)) {
+ ABORT("Failed to create key for local allocator");
+ }
+ keys_initialized = TRUE;
+ }
+ if (0 != GC_setspecific(GC_thread_key, p)) {
+ ABORT("Failed to set thread specific allocation pointers");
+ }
+ for (i = 1; i < TINY_FREELISTS; ++i) {
+ p -> ptrfree_freelists[i] = (void *)(word)1;
+ p -> normal_freelists[i] = (void *)(word)1;
+# ifdef GC_GCJ_SUPPORT
+ p -> gcj_freelists[i] = (void *)(word)1;
+# endif
+# ifdef ENABLE_DISCLAIM
+ p -> finalized_freelists[i] = (void *)(word)1;
+# endif
+ }
+ /* Set up the size 0 free lists. */
+ /* We now handle most of them like regular free lists, to ensure */
+ /* That explicit deallocation works. However, allocation of a */
+ /* size 0 "gcj" object is always an error. */
+ p -> ptrfree_freelists[0] = (void *)(word)1;
+ p -> normal_freelists[0] = (void *)(word)1;
+# ifdef GC_GCJ_SUPPORT
+ p -> gcj_freelists[0] = ERROR_FL;
+# endif
+# ifdef ENABLE_DISCLAIM
+ p -> finalized_freelists[0] = (void *)(word)1;
+# endif
+}
+
+/* We hold the allocator lock. */
+GC_INNER void GC_destroy_thread_local(GC_tlfs p)
+{
+ /* We currently only do this from the thread itself or from */
+ /* the fork handler for a child process. */
+ return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
+ return_freelists(p -> normal_freelists, GC_objfreelist);
+# ifdef GC_GCJ_SUPPORT
+ return_freelists(p -> gcj_freelists, (void **)GC_gcjobjfreelist);
+# endif
+# ifdef ENABLE_DISCLAIM
+ return_freelists(p -> finalized_freelists,
+ (void **)GC_finalized_objfreelist);
+# endif
+}
+
+#ifdef GC_ASSERTIONS
+ /* Defined in pthread_support.c or win32_threads.c. */
+ GC_bool GC_is_thread_tsd_valid(void *tsd);
+#endif
+
+GC_API void * GC_CALL GC_malloc(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, FALSE)) {
+ /* 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_COMPILER_TLS) && !defined(USE_WIN32_COMPILER_TLS)
+ if (EXPECT(0 == tsd, FALSE)) {
+ return GC_core_malloc(bytes);
+ }
+# endif
+ GC_ASSERT(GC_is_initialized);
+
+ GC_ASSERT(GC_is_thread_tsd_valid(tsd));
+
+ 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_log_printf("GC_malloc(%lu) = %p, GC: %lu\n",
+ (unsigned long)bytes, result, (unsigned long)GC_gc_no);
+# endif
+ return result;
+}
+
+GC_API void * GC_CALL 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, FALSE)) {
+ /* We haven't yet run GC_init_parallel. That means */
+ /* we also aren't locking, so this is fairly cheap. */
+ return GC_core_malloc_atomic(bytes);
+ }
+ tsd = GC_getspecific(k);
+# else
+ tsd = GC_getspecific(GC_thread_key);
+# endif
+# if !defined(USE_COMPILER_TLS) && !defined(USE_WIN32_COMPILER_TLS)
+ if (EXPECT(0 == tsd, FALSE)) {
+ return GC_core_malloc_atomic(bytes);
+ }
+# endif
+ GC_ASSERT(GC_is_initialized);
+ tiny_fl = ((GC_tlfs)tsd) -> ptrfree_freelists;
+ GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES, PTRFREE,
+ GC_core_malloc_atomic(bytes), (void)0 /* no init */);
+ return result;
+}
+
+#ifdef GC_GCJ_SUPPORT
+
+# include "atomic_ops.h" /* for AO_compiler_barrier() */
+
+# include "include/gc_gcj.h"
+
+/* Gcj-style allocation without locks is extremely tricky. The */
+/* fundamental issue is that we may end up marking a free list, which */
+/* has freelist links instead of "vtable" pointers. That is usually */
+/* OK, since the next object on the free list will be cleared, and */
+/* will thus be interpreted as containing a zero descriptor. That's */
+/* fine if the object has not yet been initialized. But there are */
+/* interesting potential races. */
+/* In the case of incremental collection, this seems hopeless, since */
+/* the marker may run asynchronously, and may pick up the pointer to */
+/* the next freelist entry (which it thinks is a vtable pointer), get */
+/* suspended for a while, and then see an allocated object instead */
+/* of the vtable. This may be avoidable with either a handshake with */
+/* the collector or, probably more easily, by moving the free list */
+/* links to the second word of each object. The latter isn't a */
+/* universal win, since on architecture like Itanium, nonzero offsets */
+/* are not necessarily free. And there may be cache fill order issues. */
+/* For now, we punt with incremental GC. This probably means that */
+/* incremental GC should be enabled before we fork a second thread. */
+/* Unlike the other thread local allocation calls, we assume that the */
+/* collector has been explicitly initialized. */
+GC_API void * GC_CALL GC_gcj_malloc(size_t bytes,
+ void * ptr_to_struct_containing_descr)
+{
+ if (EXPECT(GC_incremental, FALSE)) {
+ return GC_core_gcj_malloc(bytes, ptr_to_struct_containing_descr);
+ } else {
+ size_t granules = ROUNDED_UP_GRANULES(bytes);
+ void *result;
+ void **tiny_fl = ((GC_tlfs)GC_getspecific(GC_thread_key))
+ -> gcj_freelists;
+ GC_ASSERT(GC_gcj_malloc_initialized);
+ GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
+ GC_gcj_kind,
+ GC_core_gcj_malloc(bytes,
+ ptr_to_struct_containing_descr),
+ {AO_compiler_barrier();
+ *(void **)result = ptr_to_struct_containing_descr;});
+ /* This forces the initialization of the "method ptr". */
+ /* This is necessary to ensure some very subtle properties */
+ /* required if a GC is run in the middle of such an allocation. */
+ /* Here we implicitly also assume atomicity for the free list. */
+ /* and method pointer assignments. */
+ /* We must update the freelist before we store the pointer. */
+ /* Otherwise a GC at this point would see a corrupted */
+ /* free list. */
+ /* A real memory barrier is not needed, since the */
+ /* action of stopping this thread will cause prior writes */
+ /* to complete. */
+ /* We assert that any concurrent marker will stop us. */
+ /* Thus it is impossible for a mark procedure to see the */
+ /* allocation of the next object, but to see this object */
+ /* still containing a free list pointer. Otherwise the */
+ /* marker, by misinterpreting the freelist link as a vtable */
+ /* pointer, might find a random "mark descriptor" in the next */
+ /* object. */
+ return result;
+ }
+}
+
+#endif /* GC_GCJ_SUPPORT */
+
+/* The thread support layer must arrange to mark thread-local */
+/* free lists explicitly, since the link field is often */
+/* invisible to the marker. It knows how to find all threads; */
+/* we take care of an individual thread freelist structure. */
+GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p)
+{
+ ptr_t q;
+ int j;
+
+ for (j = 0; j < TINY_FREELISTS; ++j) {
+ q = p -> ptrfree_freelists[j];
+ if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
+ q = p -> normal_freelists[j];
+ if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
+# ifdef GC_GCJ_SUPPORT
+ if (j > 0) {
+ q = p -> gcj_freelists[j];
+ if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
+ }
+# endif /* GC_GCJ_SUPPORT */
+# ifdef ENABLE_DISCLAIM
+ q = p -> finalized_freelists[j];
+ if ((word)q > HBLKSIZE)
+ GC_set_fl_marks(q);
+# endif
+ }
+}
+
+#if defined(GC_ASSERTIONS)
+ /* Check that all thread-local free-lists in p are completely marked. */
+ void GC_check_tls_for(GC_tlfs p)
+ {
+ int j;
+
+ for (j = 1; j < TINY_FREELISTS; ++j) {
+ GC_check_fl_marks(&p->ptrfree_freelists[j]);
+ GC_check_fl_marks(&p->normal_freelists[j]);
+# ifdef GC_GCJ_SUPPORT
+ GC_check_fl_marks(&p->gcj_freelists[j]);
+# endif
+# ifdef ENABLE_DISCLAIM
+ GC_check_fl_marks(&p->finalized_freelists[j]);
+# endif
+ }
+ }
+#endif /* GC_ASSERTIONS */
+
+#endif /* THREAD_LOCAL_ALLOC */
diff --git a/boehm-gc/threadlibs.c b/boehm-gc/threadlibs.c
deleted file mode 100644
index 264b7240cbe..00000000000
--- a/boehm-gc/threadlibs.c
+++ /dev/null
@@ -1,37 +0,0 @@
-# include "gc_config_macros.h"
-# include "private/gcconfig.h"
-# include <stdio.h>
-
-int main()
-{
-# if defined(GC_USE_LD_WRAP)
- printf("-Wl,--wrap -Wl,dlopen "
- "-Wl,--wrap -Wl,pthread_create -Wl,--wrap -Wl,pthread_join "
- "-Wl,--wrap -Wl,pthread_detach "
- "-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
-# endif
-# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
- || defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \
- || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
- printf("-lpthread\n");
-# endif
-# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
- printf("-lpthread -lrt\n");
-# endif
-# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
- printf("-lthread -ldl\n");
-# endif
-# if defined(GC_WIN32_THREADS) && defined(CYGWIN32)
- printf("-lpthread\n");
-# endif
-# if defined(GC_OSF1_THREADS)
- printf("-pthread -lrt"); /* DOB: must be -pthread, not -lpthread */
-# endif
- /* You need GCC 3.0.3 to build this one! */
- /* DG/UX native gcc doesnt know what "-pthread" is */
-# if defined(GC_DGUX386_THREADS)
- printf("-ldl -pthread\n");
-# endif
- return 0;
-}
-
diff --git a/boehm-gc/tools/add_gc_prefix.c b/boehm-gc/tools/add_gc_prefix.c
new file mode 100644
index 00000000000..8369d689daf
--- /dev/null
+++ b/boehm-gc/tools/add_gc_prefix.c
@@ -0,0 +1,21 @@
+# include <stdio.h>
+# include <gc.h>
+
+#ifndef GC_ALPHA_VERSION
+# define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
+#endif
+
+int main(int argc, char ** argv)
+{
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (GC_ALPHA_VERSION == GC_NOT_ALPHA) {
+ printf("gc%d.%d/%s ", GC_VERSION_MAJOR, GC_VERSION_MINOR, argv[i]);
+ } else {
+ printf("gc%d.%dalpha%d/%s ", GC_VERSION_MAJOR,
+ GC_VERSION_MINOR, GC_ALPHA_VERSION, argv[i]);
+ }
+ }
+ return(0);
+}
diff --git a/boehm-gc/callprocs b/boehm-gc/tools/callprocs.sh
index a8793f0b728..a8793f0b728 100755
--- a/boehm-gc/callprocs
+++ b/boehm-gc/tools/callprocs.sh
diff --git a/boehm-gc/tools/gcname.c b/boehm-gc/tools/gcname.c
new file mode 100644
index 00000000000..74be553c977
--- /dev/null
+++ b/boehm-gc/tools/gcname.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <gc.h>
+
+#ifndef GC_ALPHA_VERSION
+# define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
+#endif
+
+int main(void)
+{
+ if (GC_ALPHA_VERSION == GC_NOT_ALPHA) {
+ printf("gc%d.%d", GC_VERSION_MAJOR, GC_VERSION_MINOR);
+ } else {
+ printf("gc%d.%dalpha%d", GC_VERSION_MAJOR,
+ GC_VERSION_MINOR, GC_ALPHA_VERSION);
+ }
+ return 0;
+}
diff --git a/boehm-gc/if_mach.c b/boehm-gc/tools/if_mach.c
index 3dcccf21f5a..94053a66662 100644
--- a/boehm-gc/if_mach.c
+++ b/boehm-gc/tools/if_mach.c
@@ -1,14 +1,11 @@
/* Conditionally execute a command based on machine and OS from gcconfig.h */
-# include "private/gcconfig.h"
+# include "private/gc_priv.h"
# include <stdio.h>
# include <string.h>
# include <unistd.h>
-int main(argc, argv, envp)
-int argc;
-char ** argv;
-char ** envp;
+int main(int argc, char **argv)
{
if (argc < 4) goto Usage;
if (strcmp(MACH_TYPE, argv[1]) != 0) return(0);
@@ -18,11 +15,10 @@ char ** envp;
fflush(stdout);
execvp(argv[3], argv+3);
perror("Couldn't execute");
-
+
Usage:
fprintf(stderr, "Usage: %s mach_type os_type command\n", argv[0]);
fprintf(stderr, "Currently mach_type = %s, os_type = %s\n",
- MACH_TYPE, OS_TYPE);
+ MACH_TYPE, OS_TYPE);
return(1);
}
-
diff --git a/boehm-gc/if_not_there.c b/boehm-gc/tools/if_not_there.c
index 8691e925920..c0f095d058c 100644
--- a/boehm-gc/if_not_there.c
+++ b/boehm-gc/tools/if_not_there.c
@@ -1,6 +1,7 @@
/* Conditionally execute a command based if the file argv[1] doesn't exist */
-/* Except for execvp, we stick to ANSI C. */
-# include "private/gcconfig.h"
+/* Except for execvp, we stick to ANSI C. */
+
+# include "private/gc_priv.h"
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
@@ -8,10 +9,7 @@
#include <dirent.h>
#endif /* __DJGPP__ */
-int main(argc, argv, envp)
-int argc;
-char ** argv;
-char ** envp;
+int main(int argc, char **argv)
{
FILE * f;
#ifdef __DJGPP__
@@ -25,17 +23,16 @@ char ** envp;
}
#ifdef __DJGPP__
if ((d = opendir(argv[1])) != 0) {
- closedir(d);
- return(0);
+ closedir(d);
+ return(0);
}
#endif
printf("^^^^Starting command^^^^\n");
fflush(stdout);
execvp(argv[2], argv+2);
exit(1);
-
+
Usage:
fprintf(stderr, "Usage: %s file_name command\n", argv[0]);
return(1);
}
-
diff --git a/boehm-gc/tools/setjmp_t.c b/boehm-gc/tools/setjmp_t.c
new file mode 100644
index 00000000000..1d9a1ad0a8d
--- /dev/null
+++ b/boehm-gc/tools/setjmp_t.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* Check whether setjmp actually saves registers in jmp_buf. */
+/* If it doesn't, the generic mark_regs code won't work. */
+/* Compilers vary as to whether they will put x in a */
+/* (callee-save) register without -O. The code is */
+/* contrived such that any decent compiler should put x in */
+/* a callee-save register with -O. Thus it is */
+/* recommended that this be run optimized. (If the machine */
+/* has no callee-save registers, then the generic code is */
+/* safe, but this will not be noticed by this piece of */
+/* code.) This test appears to be far from perfect. */
+#include <stdio.h>
+#include <setjmp.h>
+#include <string.h>
+#include "private/gc_priv.h"
+
+#ifdef OS2
+/* GETPAGESIZE() is set to getpagesize() by default, but that */
+/* doesn't really exist, and the collector doesn't need it. */
+#define INCL_DOSFILEMGR
+#define INCL_DOSMISC
+#define INCL_DOSERRORS
+#include <os2.h>
+
+int getpagesize(void)
+{
+ ULONG result[1];
+
+ if (DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE,
+ (void *)result, sizeof(ULONG)) != NO_ERROR) {
+ fprintf(stderr, "DosQuerySysInfo failed\n");
+ result[0] = 4096;
+ }
+ return((int)(result[0]));
+}
+#elif defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
+# include <windows.h>
+ int getpagesize(void)
+ {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ return sysinfo.dwPageSize;
+ }
+#endif
+
+struct {
+ char a_a;
+ char * a_b;
+} a;
+
+int * nested_sp(void)
+{
+ volatile word sp;
+ sp = (word)(&sp);
+ return (int *)sp;
+}
+
+int main(void)
+{
+ volatile word sp;
+ long ps = GETPAGESIZE();
+ jmp_buf b;
+ register int x = (int)strlen("a"); /* 1, slightly disguised */
+ static int y = 0;
+
+ sp = (word)(&sp);
+ printf("This appears to be a %s running %s\n", MACH_TYPE, OS_TYPE);
+ if ((word)nested_sp() < sp) {
+ printf("Stack appears to grow down, which is the default.\n");
+ printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
+ ((unsigned long)sp + ps) & ~(ps-1));
+ } else {
+ printf("Stack appears to grow up.\n");
+ printf("Define STACK_GROWS_UP in gc_private.h\n");
+ printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
+ ((unsigned long)sp + ps) & ~(ps-1));
+ }
+ printf("Note that this may vary between machines of ostensibly\n");
+ printf("the same architecture (e.g. Sun 3/50s and 3/80s).\n");
+ printf("On many machines the value is not fixed.\n");
+ printf("A good guess for ALIGNMENT on this machine is %ld.\n",
+ (unsigned long)((word)(&(a.a_b)) - (word)(&a)));
+
+ printf("The following is a very dubious test of one root marking"
+ " strategy.\n");
+ printf("Results may not be accurate/useful:\n");
+ /* Encourage the compiler to keep x in a callee-save register */
+ x = 2*x-1;
+ printf("\n");
+ x = 2*x-1;
+ setjmp(b);
+ if (y == 1) {
+ if (x == 2) {
+ printf("Setjmp-based generic mark_regs code probably wont work.\n");
+ printf("But we rarely try that anymore. If you have getcontect()\n");
+ printf("this probably doesn't matter.\n");
+ } else if (x == 1) {
+ printf("Setjmp-based register marking code may work.\n");
+ } else {
+ printf("Very strange setjmp implementation.\n");
+ }
+ }
+ y++;
+ x = 2;
+ if (y == 1) longjmp(b,1);
+ printf("Some GC internal configuration stuff: \n");
+ printf("\tWORDSZ = %lu, ALIGNMENT = %d, GC_GRANULE_BYTES = %d\n",
+ (unsigned long)WORDSZ, ALIGNMENT, GC_GRANULE_BYTES);
+ printf("\tUsing one mark ");
+# if defined(USE_MARK_BYTES)
+ printf("byte");
+# else
+ printf("bit");
+# endif
+ printf(" per ");
+# if defined(MARK_BIT_PER_OBJ)
+ printf("object.\n");
+# elif defined(MARK_BIT_PER_GRANULE)
+ printf("granule.\n");
+# endif
+# ifdef THREAD_LOCAL_ALLOC
+ printf("Thread local allocation enabled.\n");
+# endif
+# ifdef PARALLEL_MARK
+ printf("Parallel marking enabled.\n");
+# endif
+ return(0);
+}
+
+int g(int x)
+{
+ return(x);
+}
diff --git a/boehm-gc/tools/threadlibs.c b/boehm-gc/tools/threadlibs.c
new file mode 100644
index 00000000000..a97f91b8fc9
--- /dev/null
+++ b/boehm-gc/tools/threadlibs.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2010 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+# include "private/gc_priv.h"
+
+# include <stdio.h>
+
+int main(void)
+{
+# if defined(GC_USE_LD_WRAP)
+ printf("-Wl,--wrap -Wl,dlopen "
+ "-Wl,--wrap -Wl,pthread_create -Wl,--wrap -Wl,pthread_join "
+ "-Wl,--wrap -Wl,pthread_detach -Wl,--wrap -Wl,pthread_sigmask "
+ "-Wl,--wrap -Wl,pthread_exit -Wl,--wrap -Wl,pthread_cancel\n");
+# endif
+# if (defined(GC_LINUX_THREADS) && !defined(PLATFORM_ANDROID)) \
+ || defined(GC_IRIX_THREADS) || defined(GC_DARWIN_THREADS) \
+ || defined(GC_AIX_THREADS) || defined(GC_GNU_THREADS)
+# ifdef GC_USE_DLOPEN_WRAP
+ printf("-ldl ");
+# endif
+ printf("-lpthread\n");
+# endif
+# if defined(GC_OPENBSD_THREADS)
+ printf("-pthread\n");
+# endif
+# if defined(GC_FREEBSD_THREADS)
+# ifdef GC_USE_DLOPEN_WRAP
+ printf("-ldl ");
+# endif
+# if (__FREEBSD_version >= 500000)
+ printf("-lpthread\n");
+# else
+ printf("-pthread\n");
+# endif
+# endif
+# if defined(GC_NETBSD_THREADS)
+ printf("-lpthread -lrt\n");
+# endif
+
+# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
+ printf("-lpthread -lrt\n");
+# endif
+# if defined(GC_SOLARIS_THREADS)
+ printf("-lthread -lposix4\n");
+ /* Is this right for recent versions? */
+# endif
+# if defined(GC_WIN32_THREADS) && defined(CYGWIN32)
+ printf("-lpthread\n");
+# endif
+# if defined(GC_WIN32_PTHREADS)
+# ifdef PTW32_STATIC_LIB
+ /* assume suffix s for static version of the win32 pthread library */
+ printf("-lpthreadGC2s -lws2_32\n");
+# else
+ printf("-lpthreadGC2\n");
+# endif
+# endif
+# if defined(GC_OSF1_THREADS)
+ printf("-pthread -lrt"); /* DOB: must be -pthread, not -lpthread */
+# endif
+ /* You need GCC 3.0.3 to build this one! */
+ /* DG/UX native gcc doesn't know what "-pthread" is */
+# if defined(GC_DGUX386_THREADS)
+ printf("-ldl -pthread\n");
+# endif
+ return 0;
+}
diff --git a/boehm-gc/typd_mlc.c b/boehm-gc/typd_mlc.c
index 373257cd260..e1d3b2ab709 100644
--- a/boehm-gc/typd_mlc.c
+++ b/boehm-gc/typd_mlc.c
@@ -13,6 +13,7 @@
*
*/
+#include "private/gc_pmark.h"
/*
* Some simple primitives for allocation with explicit type information.
@@ -28,7 +29,7 @@
* must trace the complex_descriptor.
*
* Note that descriptors inside objects may appear cleared, if we encounter a
- * false refrence to an object on a free list. In the GC_descr case, this
+ * false reference to an object on a free list. In the GC_descr case, this
* is OK, since a 0 descriptor corresponds to examining no fields.
* In the complex_descriptor case, we explicitly check for that case.
*
@@ -36,109 +37,115 @@
* since they are not accessible through the current interface.
*/
-#include "private/gc_pmark.h"
#include "gc_typed.h"
-# define TYPD_EXTRA_BYTES (sizeof(word) - EXTRA_BYTES)
+#define TYPD_EXTRA_BYTES (sizeof(word) - EXTRA_BYTES)
-GC_bool GC_explicit_typing_initialized = FALSE;
+STATIC GC_bool GC_explicit_typing_initialized = FALSE;
-int GC_explicit_kind; /* Object kind for objects with indirect */
- /* (possibly extended) descriptors. */
+STATIC int GC_explicit_kind = 0;
+ /* Object kind for objects with indirect */
+ /* (possibly extended) descriptors. */
-int GC_array_kind; /* Object kind for objects with complex */
- /* descriptors and GC_array_mark_proc. */
+STATIC int GC_array_kind = 0;
+ /* Object kind for objects with complex */
+ /* descriptors and GC_array_mark_proc. */
-/* Extended descriptors. GC_typed_mark_proc understands these. */
-/* These are used for simple objects that are larger than what */
-/* can be described by a BITMAP_BITS sized bitmap. */
+/* Extended descriptors. GC_typed_mark_proc understands these. */
+/* These are used for simple objects that are larger than what */
+/* can be described by a BITMAP_BITS sized bitmap. */
typedef struct {
- word ed_bitmap; /* lsb corresponds to first word. */
- GC_bool ed_continued; /* next entry is continuation. */
+ word ed_bitmap; /* lsb corresponds to first word. */
+ GC_bool ed_continued; /* next entry is continuation. */
} ext_descr;
-/* Array descriptors. GC_array_mark_proc understands these. */
-/* We may eventually need to add provisions for headers and */
+/* Array descriptors. GC_array_mark_proc understands these. */
+/* We may eventually need to add provisions for headers and */
/* trailers. Hence we provide for tree structured descriptors, */
-/* though we don't really use them currently. */
+/* though we don't really use them currently. */
typedef union ComplexDescriptor {
- struct LeafDescriptor { /* Describes simple array */
+ struct LeafDescriptor { /* Describes simple array */
word ld_tag;
-# define LEAF_TAG 1
- word ld_size; /* bytes per element */
- /* multiple of ALIGNMENT */
- word ld_nelements; /* Number of elements. */
- GC_descr ld_descriptor; /* A simple length, bitmap, */
- /* or procedure descriptor. */
+# define LEAF_TAG 1
+ size_t ld_size; /* bytes per element */
+ /* multiple of ALIGNMENT */
+ size_t ld_nelements; /* Number of elements. */
+ GC_descr ld_descriptor; /* A simple length, bitmap, */
+ /* or procedure descriptor. */
} ld;
struct ComplexArrayDescriptor {
word ad_tag;
-# define ARRAY_TAG 2
- word ad_nelements;
- union ComplexDescriptor * ad_element_descr;
+# define ARRAY_TAG 2
+ size_t ad_nelements;
+ union ComplexDescriptor * ad_element_descr;
} ad;
struct SequenceDescriptor {
word sd_tag;
-# define SEQUENCE_TAG 3
- union ComplexDescriptor * sd_first;
- union ComplexDescriptor * sd_second;
+# define SEQUENCE_TAG 3
+ union ComplexDescriptor * sd_first;
+ union ComplexDescriptor * sd_second;
} sd;
} complex_descriptor;
#define TAG ld.ld_tag
-ext_descr * GC_ext_descriptors; /* Points to array of extended */
- /* descriptors. */
+STATIC ext_descr * GC_ext_descriptors = NULL;
+ /* Points to array of extended */
+ /* descriptors. */
-word GC_ed_size = 0; /* Current size of above arrays. */
-# define ED_INITIAL_SIZE 100;
+STATIC size_t GC_ed_size = 0; /* Current size of above arrays. */
+#define ED_INITIAL_SIZE 100
-word GC_avail_descr = 0; /* Next available slot. */
+STATIC 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 int GC_typed_mark_proc_index = 0; /* Indices of my mark */
+STATIC int GC_array_mark_proc_index = 0; /* procedures. */
-/* Add a multiword bitmap to GC_ext_descriptors arrays. Return */
-/* starting index. */
-/* Returns -1 on failure. */
-/* Caller does not hold allocation lock. */
-signed_word GC_add_ext_descriptor(bm, nbits)
-GC_bitmap bm;
-word nbits;
+STATIC void GC_push_typed_structures_proc(void)
{
- register size_t nwords = divWORDSZ(nbits + WORDSZ-1);
- register signed_word result;
- register word i;
- register word last_part;
- register int extra_bits;
+ 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. */
+/* Caller does not hold allocation lock. */
+STATIC signed_word GC_add_ext_descriptor(const GC_word * bm, word nbits)
+{
+ size_t nwords = divWORDSZ(nbits + WORDSZ-1);
+ signed_word result;
+ size_t i;
+ word last_part;
+ size_t extra_bits;
DCL_LOCK_STATE;
- DISABLE_SIGNALS();
LOCK();
while (GC_avail_descr + nwords >= GC_ed_size) {
- ext_descr * new;
- size_t new_size;
- word ed_size = GC_ed_size;
-
- UNLOCK();
- ENABLE_SIGNALS();
- if (ed_size == 0) {
- new_size = ED_INITIAL_SIZE;
- } else {
- new_size = 2 * ed_size;
- if (new_size > MAX_ENV) return(-1);
- }
- new = (ext_descr *) GC_malloc_atomic(new_size * sizeof(ext_descr));
- if (new == 0) return(-1);
- DISABLE_SIGNALS();
+ ext_descr * new;
+ size_t new_size;
+ word ed_size = GC_ed_size;
+
+ if (ed_size == 0) {
+ GC_ASSERT((word)&GC_ext_descriptors % sizeof(word) == 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);
+ }
+ new = (ext_descr *) GC_malloc_atomic(new_size * sizeof(ext_descr));
+ if (new == 0) return(-1);
LOCK();
if (ed_size == GC_ed_size) {
if (GC_avail_descr != 0) {
- BCOPY(GC_ext_descriptors, new,
- GC_avail_descr * sizeof(ext_descr));
- }
- GC_ed_size = new_size;
- GC_ext_descriptors = new;
- } /* else another thread already resized it in the meantime */
+ BCOPY(GC_ext_descriptors, new,
+ GC_avail_descr * sizeof(ext_descr));
+ }
+ GC_ed_size = new_size;
+ GC_ext_descriptors = new;
+ } /* else another thread already resized it in the meantime */
}
result = GC_avail_descr;
for (i = 0; i < nwords-1; i++) {
@@ -154,21 +161,18 @@ word nbits;
GC_ext_descriptors[result + i].ed_continued = FALSE;
GC_avail_descr += nwords;
UNLOCK();
- ENABLE_SIGNALS();
return(result);
}
-/* Table of bitmap descriptors for n word long all pointer objects. */
-GC_descr GC_bm_table[WORDSZ/2];
-
-/* Return a descriptor for the concatenation of 2 nwords long objects, */
-/* each of which is described by descriptor. */
-/* The result is known to be short enough to fit into a bitmap */
-/* descriptor. */
-/* Descriptor is a GC_DS_LENGTH or GC_DS_BITMAP descriptor. */
-GC_descr GC_double_descr(descriptor, nwords)
-register GC_descr descriptor;
-register word nwords;
+/* Table of bitmap descriptors for n word long all pointer objects. */
+STATIC GC_descr GC_bm_table[WORDSZ/2];
+
+/* Return a descriptor for the concatenation of 2 nwords long objects, */
+/* each of which is described by descriptor. */
+/* The result is known to be short enough to fit into a bitmap */
+/* descriptor. */
+/* Descriptor is a GC_DS_LENGTH or GC_DS_BITMAP descriptor. */
+STATIC GC_descr GC_double_descr(GC_descr descriptor, word nwords)
{
if ((descriptor & GC_DS_TAGS) == GC_DS_LENGTH) {
descriptor = GC_bm_table[BYTES_TO_WORDS((word)descriptor)];
@@ -177,44 +181,42 @@ register word nwords;
return(descriptor);
}
-complex_descriptor * GC_make_sequence_descriptor();
+STATIC complex_descriptor *
+GC_make_sequence_descriptor(complex_descriptor *first,
+ complex_descriptor *second);
-/* Build a descriptor for an array with nelements elements, */
-/* each of which can be described by a simple descriptor. */
-/* We try to optimize some common cases. */
+/* Build a descriptor for an array with nelements elements, */
+/* each of which can be described by a simple descriptor. */
+/* We try to optimize some common cases. */
/* If the result is COMPLEX, then a complex_descr* is returned */
-/* in *complex_d. */
-/* If the result is LEAF, then we built a LeafDescriptor in */
-/* the structure pointed to by leaf. */
-/* The tag in the leaf structure is not set. */
-/* If the result is SIMPLE, then a GC_descr */
-/* is returned in *simple_d. */
-/* If the result is NO_MEM, then */
-/* we failed to allocate the descriptor. */
-/* The implementation knows that GC_DS_LENGTH is 0. */
-/* *leaf, *complex_d, and *simple_d may be used as temporaries */
-/* during the construction. */
-# define COMPLEX 2
-# define LEAF 1
-# define SIMPLE 0
-# define NO_MEM (-1)
-int GC_make_array_descriptor(nelements, size, descriptor,
- simple_d, complex_d, leaf)
-word size;
-word nelements;
-GC_descr descriptor;
-GC_descr *simple_d;
-complex_descriptor **complex_d;
-struct LeafDescriptor * leaf;
+/* in *complex_d. */
+/* If the result is LEAF, then we built a LeafDescriptor in */
+/* the structure pointed to by leaf. */
+/* The tag in the leaf structure is not set. */
+/* If the result is SIMPLE, then a GC_descr */
+/* is returned in *simple_d. */
+/* If the result is NO_MEM, then */
+/* we failed to allocate the descriptor. */
+/* The implementation knows that GC_DS_LENGTH is 0. */
+/* *leaf, *complex_d, and *simple_d may be used as temporaries */
+/* during the construction. */
+#define COMPLEX 2
+#define LEAF 1
+#define SIMPLE 0
+#define NO_MEM (-1)
+STATIC int GC_make_array_descriptor(size_t nelements, size_t size,
+ GC_descr descriptor, GC_descr *simple_d,
+ complex_descriptor **complex_d,
+ struct LeafDescriptor * leaf)
{
# define OPT_THRESHOLD 50
- /* For larger arrays, we try to combine descriptors of adjacent */
- /* descriptors to speed up marking, and to reduce the amount */
- /* of space needed on the mark stack. */
+ /* For larger arrays, we try to combine descriptors of adjacent */
+ /* descriptors to speed up marking, and to reduce the amount */
+ /* of space needed on the mark stack. */
if ((descriptor & GC_DS_TAGS) == GC_DS_LENGTH) {
- if ((word)descriptor == size) {
- *simple_d = nelements * descriptor;
- return(SIMPLE);
+ if (descriptor == (GC_descr)size) {
+ *simple_d = nelements * descriptor;
+ return(SIMPLE);
} else if ((word)descriptor == 0) {
*simple_d = (GC_descr)0;
return(SIMPLE);
@@ -231,20 +233,20 @@ struct LeafDescriptor * leaf;
}
}
} else if (size <= BITMAP_BITS/2
- && (descriptor & GC_DS_TAGS) != GC_DS_PROC
- && (size & (sizeof(word)-1)) == 0) {
- int result =
+ && (descriptor & GC_DS_TAGS) != GC_DS_PROC
+ && (size & (sizeof(word)-1)) == 0) {
+ int result =
GC_make_array_descriptor(nelements/2, 2*size,
- GC_double_descr(descriptor,
- BYTES_TO_WORDS(size)),
- simple_d, complex_d, leaf);
+ GC_double_descr(descriptor,
+ BYTES_TO_WORDS(size)),
+ simple_d, complex_d, leaf);
if ((nelements & 1) == 0) {
return(result);
} else {
struct LeafDescriptor * one_element =
(struct LeafDescriptor *)
- GC_malloc_atomic(sizeof(struct LeafDescriptor));
-
+ GC_malloc_atomic(sizeof(struct LeafDescriptor));
+
if (result == NO_MEM || one_element == 0) return(NO_MEM);
one_element -> ld_tag = LEAF_TAG;
one_element -> ld_size = size;
@@ -255,61 +257,60 @@ struct LeafDescriptor * leaf;
{
struct LeafDescriptor * beginning =
(struct LeafDescriptor *)
- GC_malloc_atomic(sizeof(struct LeafDescriptor));
+ GC_malloc_atomic(sizeof(struct LeafDescriptor));
if (beginning == 0) return(NO_MEM);
beginning -> ld_tag = LEAF_TAG;
beginning -> ld_size = size;
beginning -> ld_nelements = 1;
beginning -> ld_descriptor = *simple_d;
*complex_d = GC_make_sequence_descriptor(
- (complex_descriptor *)beginning,
- (complex_descriptor *)one_element);
+ (complex_descriptor *)beginning,
+ (complex_descriptor *)one_element);
break;
}
case LEAF:
{
struct LeafDescriptor * beginning =
(struct LeafDescriptor *)
- GC_malloc_atomic(sizeof(struct LeafDescriptor));
+ GC_malloc_atomic(sizeof(struct LeafDescriptor));
if (beginning == 0) return(NO_MEM);
beginning -> ld_tag = LEAF_TAG;
beginning -> ld_size = leaf -> ld_size;
beginning -> ld_nelements = leaf -> ld_nelements;
beginning -> ld_descriptor = leaf -> ld_descriptor;
*complex_d = GC_make_sequence_descriptor(
- (complex_descriptor *)beginning,
- (complex_descriptor *)one_element);
+ (complex_descriptor *)beginning,
+ (complex_descriptor *)one_element);
break;
}
case COMPLEX:
*complex_d = GC_make_sequence_descriptor(
- *complex_d,
- (complex_descriptor *)one_element);
+ *complex_d,
+ (complex_descriptor *)one_element);
break;
}
return(COMPLEX);
}
}
- {
- leaf -> ld_size = size;
- leaf -> ld_nelements = nelements;
- leaf -> ld_descriptor = descriptor;
- return(LEAF);
- }
+
+ leaf -> ld_size = size;
+ leaf -> ld_nelements = nelements;
+ leaf -> ld_descriptor = descriptor;
+ return(LEAF);
}
-complex_descriptor * GC_make_sequence_descriptor(first, second)
-complex_descriptor * first;
-complex_descriptor * second;
+STATIC complex_descriptor *
+GC_make_sequence_descriptor(complex_descriptor *first,
+ complex_descriptor *second)
{
struct SequenceDescriptor * result =
(struct SequenceDescriptor *)
- GC_malloc(sizeof(struct SequenceDescriptor));
- /* Can't result in overly conservative marking, since tags are */
- /* very small integers. Probably faster than maintaining type */
- /* info. */
+ GC_malloc(sizeof(struct SequenceDescriptor));
+ /* Can't result in overly conservative marking, since tags are */
+ /* very small integers. Probably faster than maintaining type */
+ /* info. */
if (result != 0) {
- result -> sd_tag = SEQUENCE_TAG;
+ result -> sd_tag = SEQUENCE_TAG;
result -> sd_first = first;
result -> sd_second = second;
}
@@ -317,134 +318,111 @@ complex_descriptor * second;
}
#ifdef UNDEFINED
-complex_descriptor * GC_make_complex_array_descriptor(nelements, descr)
-word nelements;
-complex_descriptor * descr;
-{
+ complex_descriptor * GC_make_complex_array_descriptor(word nelements,
+ complex_descriptor *descr)
+ {
struct ComplexArrayDescriptor * result =
(struct ComplexArrayDescriptor *)
- GC_malloc(sizeof(struct ComplexArrayDescriptor));
-
+ GC_malloc(sizeof(struct ComplexArrayDescriptor));
+
if (result != 0) {
- result -> ad_tag = ARRAY_TAG;
+ result -> ad_tag = ARRAY_TAG;
result -> ad_nelements = nelements;
result -> ad_element_descr = descr;
}
return((complex_descriptor *)result);
-}
+ }
#endif
-ptr_t * GC_eobjfreelist;
+STATIC ptr_t * GC_eobjfreelist = NULL;
-ptr_t * GC_arobjfreelist;
+STATIC ptr_t * GC_arobjfreelist = NULL;
-mse * GC_typed_mark_proc GC_PROTO((register word * addr,
- register mse * mark_stack_ptr,
- mse * mark_stack_limit,
- word env));
+STATIC mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
+ mse * mark_stack_limit, word env);
-mse * GC_array_mark_proc GC_PROTO((register word * addr,
- register mse * mark_stack_ptr,
- mse * mark_stack_limit,
- word env));
+STATIC mse * GC_array_mark_proc(word * addr, mse * mark_stack_ptr,
+ mse * mark_stack_limit, word env);
/* Caller does not hold allocation lock. */
-void GC_init_explicit_typing()
+STATIC void GC_init_explicit_typing(void)
{
- register int i;
+ register unsigned i;
DCL_LOCK_STATE;
-
-# ifdef PRINTSTATS
- if (sizeof(struct LeafDescriptor) % sizeof(word) != 0)
- ABORT("Bad leaf descriptor size");
-# endif
- DISABLE_SIGNALS();
+ GC_STATIC_ASSERT(sizeof(struct LeafDescriptor) % sizeof(word) == 0);
LOCK();
if (GC_explicit_typing_initialized) {
UNLOCK();
- ENABLE_SIGNALS();
return;
}
GC_explicit_typing_initialized = TRUE;
/* Set up object kind with simple indirect descriptor. */
GC_eobjfreelist = (ptr_t *)GC_new_free_list_inner();
GC_explicit_kind = GC_new_kind_inner(
- (void **)GC_eobjfreelist,
- (((word)WORDS_TO_BYTES(-1)) | GC_DS_PER_OBJECT),
- TRUE, TRUE);
- /* Descriptors are in the last word of the object. */
+ (void **)GC_eobjfreelist,
+ (WORDS_TO_BYTES((word)-1) | GC_DS_PER_OBJECT),
+ TRUE, TRUE);
+ /* Descriptors are in the last word of the object. */
GC_typed_mark_proc_index = GC_new_proc_inner(GC_typed_mark_proc);
/* Set up object kind with array descriptor. */
GC_arobjfreelist = (ptr_t *)GC_new_free_list_inner();
GC_array_mark_proc_index = GC_new_proc_inner(GC_array_mark_proc);
GC_array_kind = GC_new_kind_inner(
- (void **)GC_arobjfreelist,
- GC_MAKE_PROC(GC_array_mark_proc_index, 0),
- FALSE, TRUE);
+ (void **)GC_arobjfreelist,
+ GC_MAKE_PROC(GC_array_mark_proc_index, 0),
+ FALSE, TRUE);
for (i = 0; i < WORDSZ/2; i++) {
- GC_descr d = (((word)(-1)) >> (WORDSZ - i)) << (WORDSZ - i);
- d |= GC_DS_BITMAP;
- GC_bm_table[i] = d;
+ GC_bm_table[i] = (((word)-1) << (WORDSZ - i)) | GC_DS_BITMAP;
}
UNLOCK();
- ENABLE_SIGNALS();
}
-# if defined(__STDC__) || defined(__cplusplus)
- mse * GC_typed_mark_proc(register word * addr,
- register mse * mark_stack_ptr,
- mse * mark_stack_limit,
- word env)
-# else
- mse * GC_typed_mark_proc(addr, mark_stack_ptr, mark_stack_limit, env)
- register word * addr;
- register mse * mark_stack_ptr;
- mse * mark_stack_limit;
- word env;
-# endif
+STATIC mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
+ mse * mark_stack_limit, word env)
{
- register word bm = GC_ext_descriptors[env].ed_bitmap;
- register word * current_p = addr;
- register word current;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
-
+ word bm = GC_ext_descriptors[env].ed_bitmap;
+ word * current_p = addr;
+ word current;
+ ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
+ ptr_t least_ha = GC_least_plausible_heap_addr;
+ DECLARE_HDR_CACHE;
+
+ INIT_HDR_CACHE;
for (; bm != 0; bm >>= 1, current_p++) {
- if (bm & 1) {
- current = *current_p;
- FIXUP_POINTER(current);
- if ((ptr_t)current >= least_ha && (ptr_t)current <= greatest_ha) {
- PUSH_CONTENTS((ptr_t)current, mark_stack_ptr,
- mark_stack_limit, current_p, exit1);
- }
- }
+ if (bm & 1) {
+ current = *current_p;
+ FIXUP_POINTER(current);
+ if (current >= (word)least_ha && current <= (word)greatest_ha) {
+ PUSH_CONTENTS((ptr_t)current, mark_stack_ptr,
+ mark_stack_limit, (ptr_t)current_p, exit1);
+ }
+ }
}
if (GC_ext_descriptors[env].ed_continued) {
- /* Push an entry with the rest of the descriptor back onto the */
- /* stack. Thus we never do too much work at once. Note that */
- /* we also can't overflow the mark stack unless we actually */
- /* mark something. */
+ /* Push an entry with the rest of the descriptor back onto the */
+ /* stack. Thus we never do too much work at once. Note that */
+ /* we also can't overflow the mark stack unless we actually */
+ /* mark something. */
mark_stack_ptr++;
- if (mark_stack_ptr >= mark_stack_limit) {
+ if ((word)mark_stack_ptr >= (word)mark_stack_limit) {
mark_stack_ptr = GC_signal_mark_stack_overflow(mark_stack_ptr);
}
- mark_stack_ptr -> mse_start = addr + WORDSZ;
- mark_stack_ptr -> mse_descr =
- GC_MAKE_PROC(GC_typed_mark_proc_index, env+1);
+ mark_stack_ptr -> mse_start = (ptr_t)(addr + WORDSZ);
+ mark_stack_ptr -> mse_descr.w =
+ GC_MAKE_PROC(GC_typed_mark_proc_index, env + 1);
}
return(mark_stack_ptr);
}
-/* Return the size of the object described by d. It would be faster to */
-/* store this directly, or to compute it as part of */
-/* GC_push_complex_descriptor, but hopefully it doesn't matter. */
-word GC_descr_obj_size(d)
-register complex_descriptor *d;
+/* Return the size of the object described by d. It would be faster to */
+/* store this directly, or to compute it as part of */
+/* GC_push_complex_descriptor, but hopefully it doesn't matter. */
+STATIC word GC_descr_obj_size(complex_descriptor *d)
{
switch(d -> TAG) {
case LEAF_TAG:
- return(d -> ld.ld_nelements * d -> ld.ld_size);
+ return(d -> ld.ld_nelements * d -> ld.ld_size);
case ARRAY_TAG:
return(d -> ad.ad_nelements
* GC_descr_obj_size(d -> ad.ad_element_descr));
@@ -452,36 +430,33 @@ register complex_descriptor *d;
return(GC_descr_obj_size(d -> sd.sd_first)
+ GC_descr_obj_size(d -> sd.sd_second));
default:
- ABORT("Bad complex descriptor");
- /*NOTREACHED*/ return 0; /*NOTREACHED*/
+ ABORT_RET("Bad complex descriptor");
+ return 0;
}
}
-/* Push descriptors for the object at addr with complex descriptor d */
-/* onto the mark stack. Return 0 if the mark stack overflowed. */
-mse * GC_push_complex_descriptor(addr, d, msp, msl)
-word * addr;
-register complex_descriptor *d;
-register mse * msp;
-mse * msl;
+/* Push descriptors for the object at addr with complex descriptor d */
+/* onto the mark stack. Return 0 if the mark stack overflowed. */
+STATIC mse * GC_push_complex_descriptor(word *addr, complex_descriptor *d,
+ mse *msp, mse *msl)
{
register ptr_t current = (ptr_t) addr;
register word nelements;
register word sz;
register word i;
-
+
switch(d -> TAG) {
case LEAF_TAG:
{
register GC_descr descr = d -> ld.ld_descriptor;
-
+
nelements = d -> ld.ld_nelements;
if (msl - msp <= (ptrdiff_t)nelements) return(0);
sz = d -> ld.ld_size;
for (i = 0; i < nelements; i++) {
msp++;
- msp -> mse_start = (word *)current;
- msp -> mse_descr = descr;
+ msp -> mse_start = current;
+ msp -> mse_descr.w = descr;
current += sz;
}
return(msp);
@@ -489,12 +464,12 @@ mse * msl;
case ARRAY_TAG:
{
register complex_descriptor *descr = d -> ad.ad_element_descr;
-
+
nelements = d -> ad.ad_nelements;
sz = GC_descr_obj_size(descr);
for (i = 0; i < nelements; i++) {
msp = GC_push_complex_descriptor((word *)current, descr,
- msp, msl);
+ msp, msl);
if (msp == 0) return(0);
current += sz;
}
@@ -504,306 +479,257 @@ mse * msl;
{
sz = GC_descr_obj_size(d -> sd.sd_first);
msp = GC_push_complex_descriptor((word *)current, d -> sd.sd_first,
- msp, msl);
+ msp, msl);
if (msp == 0) return(0);
current += sz;
msp = GC_push_complex_descriptor((word *)current, d -> sd.sd_second,
- msp, msl);
+ msp, msl);
return(msp);
}
default:
- ABORT("Bad complex descriptor");
- /*NOTREACHED*/ return 0; /*NOTREACHED*/
+ ABORT_RET("Bad complex descriptor");
+ return 0;
}
}
-/*ARGSUSED*/
-# if defined(__STDC__) || defined(__cplusplus)
- mse * GC_array_mark_proc(register word * addr,
- register mse * mark_stack_ptr,
- mse * mark_stack_limit,
- word env)
-# else
- mse * GC_array_mark_proc(addr, mark_stack_ptr, mark_stack_limit, env)
- register word * addr;
- register mse * mark_stack_ptr;
- mse * mark_stack_limit;
- word env;
-# endif
+STATIC mse * GC_array_mark_proc(word * addr, mse * mark_stack_ptr,
+ mse * mark_stack_limit,
+ word env GC_ATTR_UNUSED)
{
- register hdr * hhdr = HDR(addr);
- register word sz = hhdr -> hb_sz;
- register complex_descriptor * descr = (complex_descriptor *)(addr[sz-1]);
+ hdr * hhdr = HDR(addr);
+ size_t sz = hhdr -> hb_sz;
+ size_t nwords = BYTES_TO_WORDS(sz);
+ complex_descriptor * descr = (complex_descriptor *)(addr[nwords-1]);
mse * orig_mark_stack_ptr = mark_stack_ptr;
mse * new_mark_stack_ptr;
-
+
if (descr == 0) {
- /* Found a reference to a free list entry. Ignore it. */
- return(orig_mark_stack_ptr);
+ /* Found a reference to a free list entry. Ignore it. */
+ return(orig_mark_stack_ptr);
}
- /* In use counts were already updated when array descriptor was */
- /* pushed. Here we only replace it by subobject descriptors, so */
- /* no update is necessary. */
+ /* In use counts were already updated when array descriptor was */
+ /* pushed. Here we only replace it by subobject descriptors, so */
+ /* no update is necessary. */
new_mark_stack_ptr = GC_push_complex_descriptor(addr, descr,
- mark_stack_ptr,
- mark_stack_limit-1);
+ mark_stack_ptr,
+ mark_stack_limit-1);
if (new_mark_stack_ptr == 0) {
- /* Doesn't fit. Conservatively push the whole array as a unit */
- /* and request a mark stack expansion. */
- /* This cannot cause a mark stack overflow, since it replaces */
- /* the original array entry. */
- GC_mark_stack_too_small = TRUE;
- new_mark_stack_ptr = orig_mark_stack_ptr + 1;
- new_mark_stack_ptr -> mse_start = addr;
- new_mark_stack_ptr -> mse_descr = WORDS_TO_BYTES(sz) | GC_DS_LENGTH;
+ /* Doesn't fit. Conservatively push the whole array as a unit */
+ /* and request a mark stack expansion. */
+ /* This cannot cause a mark stack overflow, since it replaces */
+ /* the original array entry. */
+ GC_mark_stack_too_small = TRUE;
+ new_mark_stack_ptr = orig_mark_stack_ptr + 1;
+ new_mark_stack_ptr -> mse_start = (ptr_t)addr;
+ new_mark_stack_ptr -> mse_descr.w = sz | GC_DS_LENGTH;
} else {
/* Push descriptor itself */
new_mark_stack_ptr++;
- new_mark_stack_ptr -> mse_start = addr + sz - 1;
- new_mark_stack_ptr -> mse_descr = sizeof(word) | GC_DS_LENGTH;
+ new_mark_stack_ptr -> mse_start = (ptr_t)(addr + nwords - 1);
+ new_mark_stack_ptr -> mse_descr.w = sizeof(word) | GC_DS_LENGTH;
}
- return(new_mark_stack_ptr);
+ return new_mark_stack_ptr;
}
-#if defined(__STDC__) || defined(__cplusplus)
- GC_descr GC_make_descriptor(GC_bitmap bm, size_t len)
-#else
- GC_descr GC_make_descriptor(bm, len)
- GC_bitmap bm;
- size_t len;
-#endif
+GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * bm, size_t len)
{
- register signed_word last_set_bit = len - 1;
- register word result;
- register int i;
+ signed_word last_set_bit = len - 1;
+ GC_descr result;
+ signed_word i;
# define HIGH_BIT (((word)1) << (WORDSZ - 1))
-
- if (!GC_explicit_typing_initialized) GC_init_explicit_typing();
- while (last_set_bit >= 0 && !GC_get_bit(bm, last_set_bit)) last_set_bit --;
+
+ if (!EXPECT(GC_explicit_typing_initialized, TRUE))
+ GC_init_explicit_typing();
+
+ while (last_set_bit >= 0 && !GC_get_bit(bm, last_set_bit))
+ last_set_bit--;
if (last_set_bit < 0) return(0 /* no pointers */);
# if ALIGNMENT == CPP_WORDSZ/8
{
register GC_bool all_bits_set = TRUE;
for (i = 0; i < last_set_bit; i++) {
- if (!GC_get_bit(bm, i)) {
- all_bits_set = FALSE;
- break;
- }
+ if (!GC_get_bit(bm, i)) {
+ all_bits_set = FALSE;
+ break;
+ }
}
if (all_bits_set) {
- /* An initial section contains all pointers. Use length descriptor. */
- return(WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
+ /* An initial section contains all pointers. Use length descriptor. */
+ return (WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
}
}
# endif
- if (last_set_bit < BITMAP_BITS) {
- /* Hopefully the common case. */
- /* Build bitmap descriptor (with bits reversed) */
- result = HIGH_BIT;
- for (i = last_set_bit - 1; i >= 0; i--) {
- result >>= 1;
- if (GC_get_bit(bm, i)) result |= HIGH_BIT;
- }
- result |= GC_DS_BITMAP;
- return(result);
+ if ((word)last_set_bit < BITMAP_BITS) {
+ /* Hopefully the common case. */
+ /* Build bitmap descriptor (with bits reversed) */
+ result = HIGH_BIT;
+ for (i = last_set_bit - 1; i >= 0; i--) {
+ result >>= 1;
+ if (GC_get_bit(bm, i)) result |= HIGH_BIT;
+ }
+ result |= GC_DS_BITMAP;
+ return(result);
} else {
- signed_word index;
-
- index = GC_add_ext_descriptor(bm, (word)last_set_bit+1);
- if (index == -1) return(WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
- /* Out of memory: use conservative */
- /* approximation. */
- result = GC_MAKE_PROC(GC_typed_mark_proc_index, (word)index);
- return(result);
+ signed_word index;
+
+ index = GC_add_ext_descriptor(bm, (word)last_set_bit+1);
+ if (index == -1) return(WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
+ /* Out of memory: use conservative */
+ /* approximation. */
+ result = GC_MAKE_PROC(GC_typed_mark_proc_index, (word)index);
+ return result;
}
}
-ptr_t GC_clear_stack();
-
-#define GENERAL_MALLOC(lb,k) \
- (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
-
-#define GENERAL_MALLOC_IOP(lb,k) \
- (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page(lb, k))
-
-#if defined(__STDC__) || defined(__cplusplus)
- void * GC_malloc_explicitly_typed(size_t lb, GC_descr d)
-#else
- char * GC_malloc_explicitly_typed(lb, d)
- size_t lb;
- GC_descr d;
-#endif
+GC_API void * GC_CALL GC_malloc_explicitly_typed(size_t lb, GC_descr d)
{
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-DCL_LOCK_STATE;
+ ptr_t op;
+ ptr_t * opp;
+ size_t lg;
+ DCL_LOCK_STATE;
lb += TYPD_EXTRA_BYTES;
- if( SMALL_OBJ(lb) ) {
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_eobjfreelist[lw]);
- FASTLOCK();
- if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
- FASTUNLOCK();
+ if(SMALL_OBJ(lb)) {
+ GC_DBG_COLLECT_AT_MALLOC(lb);
+ lg = GC_size_map[lb];
+ opp = &(GC_eobjfreelist[lg]);
+ LOCK();
+ op = *opp;
+ if (EXPECT(0 == op, FALSE)) {
+ UNLOCK();
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
- if (0 == op) return 0;
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb]; /* May have been uninitialized. */
-# endif
+ if (0 == op) return 0;
+ lg = GC_size_map[lb]; /* May have been uninitialized. */
} else {
*opp = obj_link(op);
- obj_link(op) = 0;
- GC_words_allocd += lw;
- FASTUNLOCK();
+ obj_link(op) = 0;
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+ UNLOCK();
}
+ ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
} else {
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
- if (op != NULL)
- lw = BYTES_TO_WORDS(GC_size(op));
+ if (op != NULL) {
+ lg = BYTES_TO_GRANULES(GC_size(op));
+ ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
+ }
}
- if (op != NULL)
- ((word *)op)[lw - 1] = d;
- return((GC_PTR) op);
+ return((void *) op);
}
-#if defined(__STDC__) || defined(__cplusplus)
- void * GC_malloc_explicitly_typed_ignore_off_page(size_t lb, GC_descr d)
-#else
- char * GC_malloc_explicitly_typed_ignore_off_page(lb, d)
- size_t lb;
- GC_descr d;
-#endif
+GC_API void * GC_CALL GC_malloc_explicitly_typed_ignore_off_page(size_t lb,
+ GC_descr d)
{
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-DCL_LOCK_STATE;
+ ptr_t op;
+ ptr_t * opp;
+ size_t lg;
+ DCL_LOCK_STATE;
lb += TYPD_EXTRA_BYTES;
if( SMALL_OBJ(lb) ) {
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_eobjfreelist[lw]);
- FASTLOCK();
- if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
- FASTUNLOCK();
+ GC_DBG_COLLECT_AT_MALLOC(lb);
+ lg = GC_size_map[lb];
+ opp = &(GC_eobjfreelist[lg]);
+ LOCK();
+ op = *opp;
+ if (EXPECT(0 == op, FALSE)) {
+ UNLOCK();
op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb]; /* May have been uninitialized. */
-# endif
+ if (0 == op) return 0;
+ lg = GC_size_map[lb]; /* May have been uninitialized. */
} else {
*opp = obj_link(op);
- obj_link(op) = 0;
- GC_words_allocd += lw;
- FASTUNLOCK();
+ obj_link(op) = 0;
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+ UNLOCK();
}
+ ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
} else {
op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
- if (op != NULL)
- lw = BYTES_TO_WORDS(GC_size(op));
+ if (op != NULL) {
+ lg = BYTES_TO_WORDS(GC_size(op));
+ ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
+ }
}
- if (op != NULL)
- ((word *)op)[lw - 1] = d;
- return((GC_PTR) op);
+ return((void *) op);
}
-#if defined(__STDC__) || defined(__cplusplus)
- void * GC_calloc_explicitly_typed(size_t n,
- size_t lb,
- GC_descr d)
-#else
- char * GC_calloc_explicitly_typed(n, lb, d)
- size_t n;
- size_t lb;
- GC_descr d;
-#endif
+GC_API void * GC_CALL GC_calloc_explicitly_typed(size_t n, size_t lb,
+ GC_descr d)
{
-register ptr_t op;
-register ptr_t * opp;
-register word lw;
-GC_descr simple_descr;
-complex_descriptor *complex_descr;
-register int descr_type;
-struct LeafDescriptor leaf;
-DCL_LOCK_STATE;
+ ptr_t op;
+ ptr_t * opp;
+ size_t lg;
+ GC_descr simple_descr;
+ complex_descriptor *complex_descr;
+ register int descr_type;
+ struct LeafDescriptor leaf;
+ DCL_LOCK_STATE;
descr_type = GC_make_array_descriptor((word)n, (word)lb, d,
- &simple_descr, &complex_descr, &leaf);
+ &simple_descr, &complex_descr, &leaf);
switch(descr_type) {
- case NO_MEM: return(0);
- case SIMPLE: return(GC_malloc_explicitly_typed(n*lb, simple_descr));
- case LEAF:
- lb *= n;
- lb += sizeof(struct LeafDescriptor) + TYPD_EXTRA_BYTES;
- break;
- case COMPLEX:
- lb *= n;
- lb += TYPD_EXTRA_BYTES;
- break;
+ case NO_MEM: return(0);
+ case SIMPLE: return(GC_malloc_explicitly_typed(n*lb, simple_descr));
+ case LEAF:
+ lb *= n;
+ lb += sizeof(struct LeafDescriptor) + TYPD_EXTRA_BYTES;
+ break;
+ case COMPLEX:
+ lb *= n;
+ lb += TYPD_EXTRA_BYTES;
+ break;
}
if( SMALL_OBJ(lb) ) {
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb];
-# else
- lw = ALIGNED_WORDS(lb);
-# endif
- opp = &(GC_arobjfreelist[lw]);
- FASTLOCK();
- if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
- FASTUNLOCK();
+ lg = GC_size_map[lb];
+ opp = &(GC_arobjfreelist[lg]);
+ LOCK();
+ op = *opp;
+ if (EXPECT(0 == op, FALSE)) {
+ UNLOCK();
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_array_kind);
- if (0 == op) return(0);
-# ifdef MERGE_SIZES
- lw = GC_size_map[lb]; /* May have been uninitialized. */
-# endif
+ if (0 == op) return(0);
+ lg = GC_size_map[lb]; /* May have been uninitialized. */
} else {
*opp = obj_link(op);
- obj_link(op) = 0;
- GC_words_allocd += lw;
- FASTUNLOCK();
+ obj_link(op) = 0;
+ GC_bytes_allocd += GRANULES_TO_BYTES(lg);
+ UNLOCK();
}
} else {
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_array_kind);
if (0 == op) return(0);
- lw = BYTES_TO_WORDS(GC_size(op));
+ lg = BYTES_TO_GRANULES(GC_size(op));
}
if (descr_type == LEAF) {
/* Set up the descriptor inside the object itself. */
- VOLATILE struct LeafDescriptor * lp =
+ volatile struct LeafDescriptor * lp =
(struct LeafDescriptor *)
((word *)op
- + lw - (BYTES_TO_WORDS(sizeof(struct LeafDescriptor)) + 1));
-
+ + GRANULES_TO_WORDS(lg)
+ - (BYTES_TO_WORDS(sizeof(struct LeafDescriptor)) + 1));
+
lp -> ld_tag = LEAF_TAG;
lp -> ld_size = leaf.ld_size;
lp -> ld_nelements = leaf.ld_nelements;
lp -> ld_descriptor = leaf.ld_descriptor;
- ((VOLATILE word *)op)[lw - 1] = (word)lp;
+ ((volatile word *)op)[GRANULES_TO_WORDS(lg) - 1] = (word)lp;
} else {
- extern unsigned GC_finalization_failures;
- unsigned ff = GC_finalization_failures;
-
+# ifndef GC_NO_FINALIZATION
+ size_t lw = GRANULES_TO_WORDS(lg);
+
((word *)op)[lw - 1] = (word)complex_descr;
- /* Make sure the descriptor is cleared once there is any danger */
- /* it may have been collected. */
- (void)
- GC_general_register_disappearing_link((GC_PTR *)
- ((word *)op+lw-1),
- (GC_PTR) op);
- if (ff != GC_finalization_failures) {
- /* Couldn't register it due to lack of memory. Punt. */
- /* This will probably fail too, but gives the recovery code */
- /* a chance. */
- return(GC_malloc(n*lb));
- }
+ /* Make sure the descriptor is cleared once there is any danger */
+ /* it may have been collected. */
+ if (GC_general_register_disappearing_link((void * *)((word *)op+lw-1),
+ op) == GC_NO_MEMORY)
+# endif
+ {
+ /* Couldn't register it due to lack of memory. Punt. */
+ /* This will probably fail too, but gives the recovery code */
+ /* a chance. */
+ return(GC_malloc(n*lb));
+ }
}
- return((GC_PTR) op);
+ return((void *) op);
}
diff --git a/boehm-gc/version.h b/boehm-gc/version.h
deleted file mode 100644
index 93000c34e16..00000000000
--- a/boehm-gc/version.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* The version here should match that in configure/configure.in */
-/* Eventually this one may become unnecessary. For now we need */
-/* it to keep the old-style build process working. */
-#define GC_TMP_VERSION_MAJOR 6
-#define GC_TMP_VERSION_MINOR 3
-#define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA
-
-#ifndef GC_NOT_ALPHA
-# define GC_NOT_ALPHA 0xff
-#endif
-
-#if defined(GC_VERSION_MAJOR)
-# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR || \
- GC_TMP_VERSION_MINOR != GC_VERSION_MINOR || \
- defined(GC_ALPHA_VERSION) != (GC_TMP_ALPHA_VERSION != GC_NOT_ALPHA) || \
- defined(GC_ALPHA_VERSION) && GC_TMP_ALPHA_VERSION != GC_ALPHA_VERSION
-# error Inconsistent version info. Check README, version.h, and configure.in.
-# endif
-#else
-# define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
-# define GC_VERSION_MINOR GC_TMP_VERSION_MINOR
-# define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
-#endif
-
-
-#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 */
diff --git a/boehm-gc/win32_threads.c b/boehm-gc/win32_threads.c
index d2e97dee7d0..92b34f6f5f1 100644
--- a/boehm-gc/win32_threads.c
+++ b/boehm-gc/win32_threads.c
@@ -1,794 +1,2945 @@
-#if defined(GC_WIN32_THREADS)
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
+ * Copyright (c) 2000-2008 by Hewlett-Packard Development Company.
+ * All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
#include "private/gc_priv.h"
+
+#if defined(GC_WIN32_THREADS)
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+#endif
+#define NOSERVICE
#include <windows.h>
-#ifdef CYGWIN32
-# include <errno.h>
+#ifdef THREAD_LOCAL_ALLOC
+# include "private/thread_local_alloc.h"
+#endif /* THREAD_LOCAL_ALLOC */
+
+/* Allocation lock declarations. */
+#if !defined(USE_PTHREAD_LOCKS)
+ GC_INNER CRITICAL_SECTION GC_allocate_ml;
+ GC_INNER DWORD GC_lock_holder = NO_THREAD;
+ /* Thread id for current holder of allocation lock */
+#else
+ GC_INNER pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
+ GC_INNER unsigned long GC_lock_holder = NO_THREAD;
+#endif
+
+#undef CreateThread
+#undef ExitThread
+#undef _beginthreadex
+#undef _endthreadex
+
+#ifdef GC_PTHREADS
+# include <errno.h> /* for EAGAIN */
/* Cygwin-specific forward decls */
-# undef pthread_create
-# undef pthread_sigmask
-# undef pthread_join
-# undef dlopen
+# undef pthread_create
+# undef pthread_join
+# undef pthread_detach
+
+# ifndef GC_NO_PTHREAD_SIGMASK
+# undef pthread_sigmask
+# endif
-# define DEBUG_CYGWIN_THREADS 0
+ STATIC void * GC_pthread_start(void * arg);
+ STATIC void GC_thread_exit_proc(void *arg);
- void * GC_start_routine(void * arg);
- void GC_thread_exit_proc(void *arg);
+# include <pthread.h>
+# ifdef CAN_CALL_ATFORK
+# include <unistd.h>
+# endif
+
+#else
+
+# ifdef MSWINCE
+ /* Force DONT_USE_SIGNALANDWAIT implementation of PARALLEL_MARK */
+ /* for WinCE (since Win32 SignalObjectAndWait() is missing). */
+# ifndef DONT_USE_SIGNALANDWAIT
+# define DONT_USE_SIGNALANDWAIT
+# endif
+# else
+# include <process.h> /* For _beginthreadex, _endthreadex */
+# include <errno.h> /* for errno, EAGAIN */
+# endif
#endif
-/* The type of the first argument to InterlockedExchange. */
-/* Documented to be LONG volatile *, but at least gcc likes */
-/* this better. */
+/* DllMain-based thread registration is currently incompatible */
+/* with thread-local allocation, pthreads and WinCE. */
+#if (defined(GC_DLL) || defined(GC_INSIDE_DLL)) \
+ && !defined(GC_NO_THREADS_DISCOVERY) && !defined(MSWINCE) \
+ && !defined(THREAD_LOCAL_ALLOC) && !defined(GC_PTHREADS)
+# include "atomic_ops.h"
+
+ /* This code operates in two distinct modes, depending on */
+ /* the setting of GC_win32_dll_threads. */
+ /* If GC_win32_dll_threads is set, all threads in the process */
+ /* are implicitly registered with the GC by DllMain. */
+ /* No explicit registration is required, and attempts at */
+ /* explicit registration are ignored. This mode is */
+ /* very different from the Posix operation of the collector. */
+ /* In this mode access to the thread table is lock-free. */
+ /* Hence there is a static limit on the number of threads. */
+
+# ifdef GC_DISCOVER_TASK_THREADS
+ /* GC_DISCOVER_TASK_THREADS should be used if DllMain-based */
+ /* thread registration is required but it is impossible to */
+ /* call GC_use_threads_discovery before other GC routines. */
+# define GC_win32_dll_threads TRUE
+# else
+ STATIC GC_bool GC_win32_dll_threads = FALSE;
+ /* GC_win32_dll_threads must be set (if needed) at the */
+ /* application initialization time, i.e. before any */
+ /* collector or thread calls. We make it a "dynamic" */
+ /* option only to avoid multiple library versions. */
+# endif
+
+#else
+ /* If GC_win32_dll_threads is FALSE (or the collector is */
+ /* built without GC_DLL defined), things operate in a way */
+ /* that is very similar to Posix platforms, and new threads */
+ /* must be registered with the collector, e.g. by using */
+ /* preprocessor-based interception of the thread primitives. */
+ /* In this case, we use a real data structure for the thread */
+ /* table. Note that there is no equivalent of linker-based */
+ /* call interception, since we don't have ELF-like */
+ /* facilities. The Windows analog appears to be "API */
+ /* hooking", which really seems to be a standard way to */
+ /* do minor binary rewriting (?). I'd prefer not to have */
+ /* the basic collector rely on such facilities, but an */
+ /* optional package that intercepts thread calls this way */
+ /* would probably be nice. */
+# ifndef GC_NO_THREADS_DISCOVERY
+# define GC_NO_THREADS_DISCOVERY
+# endif
+# define GC_win32_dll_threads FALSE
+# undef MAX_THREADS
+# define MAX_THREADS 1 /* dll_thread_table[] is always empty. */
+#endif /* GC_NO_THREADS_DISCOVERY */
+
+/* We have two versions of the thread table. Which one */
+/* we us depends on whether or not GC_win32_dll_threads */
+/* is set. Note that before initialization, we don't */
+/* add any entries to either table, even if DllMain is */
+/* called. The main thread will be added on */
+/* initialization. */
+
+/* The type of the first argument to InterlockedExchange. */
+/* Documented to be LONG volatile *, but at least gcc likes */
+/* this better. */
typedef LONG * IE_t;
-#ifndef MAX_THREADS
-# define MAX_THREADS 256
- /* FIXME: */
- /* Things may get quite slow for large numbers of threads, */
- /* since we look them up with sequential search. */
-#endif
+STATIC GC_bool GC_thr_initialized = FALSE;
-GC_bool GC_thr_initialized = FALSE;
+GC_INNER GC_bool GC_need_to_lock = FALSE;
-DWORD GC_main_thread = 0;
+static GC_bool parallel_initialized = FALSE;
-struct GC_thread_Rep {
- LONG in_use; /* Updated without lock. */
- /* We assert that unused */
- /* entries have invalid ids of */
- /* zero and zero stack fields. */
+/* GC_use_threads_discovery() is currently incompatible with pthreads */
+/* and WinCE. It might be possible to get DllMain-based thread */
+/* registration to work with Cygwin, but if you try it then you are on */
+/* your own. */
+GC_API void GC_CALL GC_use_threads_discovery(void)
+{
+# ifdef GC_NO_THREADS_DISCOVERY
+ ABORT("GC DllMain-based thread registration unsupported");
+# else
+ /* Turn on GC_win32_dll_threads. */
+ GC_ASSERT(!parallel_initialized);
+# ifndef GC_DISCOVER_TASK_THREADS
+ GC_win32_dll_threads = TRUE;
+# endif
+ GC_init_parallel();
+# endif
+}
+
+STATIC DWORD GC_main_thread = 0;
+
+#define ADDR_LIMIT ((ptr_t)(word)-1)
+
+struct GC_Thread_Rep {
+ union {
+# ifndef GC_NO_THREADS_DISCOVERY
+ volatile AO_t in_use;
+ /* Updated without lock. */
+ /* We assert that unused */
+ /* entries have invalid ids of */
+ /* zero and zero stack fields. */
+ /* Used only with GC_win32_dll_threads. */
+# endif
+ struct GC_Thread_Rep * next;
+ /* Hash table link without */
+ /* GC_win32_dll_threads. */
+ /* More recently allocated threads */
+ /* with a given pthread id come */
+ /* first. (All but the first are */
+ /* guaranteed to be dead, but we may */
+ /* not yet have registered the join.) */
+ } tm; /* table_management */
DWORD id;
- HANDLE handle;
- ptr_t stack_base; /* The cold end of the stack. */
- /* 0 ==> entry not valid. */
- /* !in_use ==> stack_base == 0 */
- GC_bool suspended;
-
-# ifdef CYGWIN32
- void *status; /* hold exit value until join in case it's a pointer */
+
+# ifdef MSWINCE
+ /* According to MSDN specs for WinCE targets: */
+ /* - DuplicateHandle() is not applicable to thread handles; and */
+ /* - the value returned by GetCurrentThreadId() could be used as */
+ /* a "real" thread handle (for SuspendThread(), ResumeThread() and */
+ /* GetThreadContext()). */
+# define THREAD_HANDLE(t) (HANDLE)(word)(t)->id
+# else
+ HANDLE handle;
+# define THREAD_HANDLE(t) (t)->handle
+# endif
+
+ ptr_t stack_base; /* The cold end of the stack. */
+ /* 0 ==> entry not valid. */
+ /* !in_use ==> stack_base == 0 */
+ ptr_t last_stack_min; /* Last known minimum (hottest) address */
+ /* in stack or ADDR_LIMIT if unset */
+# ifdef IA64
+ ptr_t backing_store_end;
+ ptr_t backing_store_ptr;
+# endif
+
+ ptr_t thread_blocked_sp; /* Protected by GC lock. */
+ /* NULL value means thread unblocked. */
+ /* If set to non-NULL, thread will */
+ /* acquire GC lock before doing any */
+ /* pointer manipulations. Thus it does */
+ /* not need to stop this thread. */
+
+ struct GC_traced_stack_sect_s *traced_stack_sect;
+ /* Points to the "stack section" data */
+ /* held in stack by the innermost */
+ /* GC_call_with_gc_active() of this */
+ /* thread. May be NULL. */
+
+ unsigned short finalizer_skipped;
+ unsigned char finalizer_nested;
+ /* Used by GC_check_finalizer_nested() */
+ /* to minimize the level of recursion */
+ /* when a client finalizer allocates */
+ /* memory (initially both are 0). */
+
+ unsigned char suspended; /* really of GC_bool type */
+
+# ifdef GC_PTHREADS
+ unsigned char flags; /* Protected by GC lock. */
+# define FINISHED 1 /* Thread has exited. */
+# define DETACHED 2 /* Thread is intended to be detached. */
+# define KNOWN_FINISHED(t) (((t) -> flags) & FINISHED)
pthread_t pthread_id;
- short flags; /* Protected by GC lock. */
-# define FINISHED 1 /* Thread has exited. */
-# define DETACHED 2 /* Thread is intended to be detached. */
+ void *status; /* hold exit value until join in case it's a pointer */
+# else
+# define KNOWN_FINISHED(t) 0
+# endif
+
+# ifdef THREAD_LOCAL_ALLOC
+ struct thread_local_freelists tlfs;
# endif
};
-typedef volatile struct GC_thread_Rep * GC_thread;
+typedef struct GC_Thread_Rep * GC_thread;
+typedef volatile struct GC_Thread_Rep * GC_vthread;
+
+#ifndef GC_NO_THREADS_DISCOVERY
+ /* We assumed that volatile ==> memory ordering, at least among */
+ /* volatiles. This code should consistently use atomic_ops. */
+ STATIC volatile GC_bool GC_please_stop = FALSE;
+#elif defined(GC_ASSERTIONS)
+ STATIC GC_bool GC_please_stop = FALSE;
+#endif
/*
- * We generally assume that volatile ==> memory ordering, at least among
- * volatiles.
+ * We track thread attachments while the world is supposed to be stopped.
+ * Unfortunately, we can't stop them from starting, since blocking in
+ * DllMain seems to cause the world to deadlock. Thus we have to recover
+ * If we notice this in the middle of marking.
*/
-volatile GC_bool GC_please_stop = FALSE;
+#ifndef GC_NO_THREADS_DISCOVERY
+ STATIC volatile AO_t GC_attached_thread = FALSE;
+#endif
-volatile struct GC_thread_Rep thread_table[MAX_THREADS];
+#if !defined(__GNUC__)
+ /* Return TRUE if an thread was attached since we last asked or */
+ /* since GC_attached_thread was explicitly reset. */
+ GC_bool GC_started_thread_while_stopped(void)
+ {
+# ifndef GC_NO_THREADS_DISCOVERY
+ if (GC_win32_dll_threads) {
+# ifdef AO_HAVE_compare_and_swap_release
+ if (AO_compare_and_swap_release(&GC_attached_thread, TRUE,
+ FALSE /* stored */))
+ return TRUE;
+# else
+ AO_nop_full(); /* Prior heap reads need to complete earlier. */
+ if (AO_load(&GC_attached_thread)) {
+ AO_store(&GC_attached_thread, FALSE);
+ return TRUE;
+ }
+# endif
+ }
+# endif
+ return FALSE;
+ }
+#endif /* !__GNUC__ */
+
+/* Thread table used if GC_win32_dll_threads is set. */
+/* This is a fixed size array. */
+/* Since we use runtime conditionals, both versions */
+/* are always defined. */
+# ifndef MAX_THREADS
+# define MAX_THREADS 512
+# endif
-volatile LONG GC_max_thread_index = 0; /* Largest index in thread_table */
- /* that was ever used. */
+/* Things may get quite slow for large numbers of threads, */
+/* since we look them up with sequential search. */
+volatile struct GC_Thread_Rep dll_thread_table[MAX_THREADS];
-extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
+STATIC volatile LONG GC_max_thread_index = 0;
+ /* Largest index in dll_thread_table */
+ /* that was ever used. */
-/*
- * This may be called from DllMain, and hence operates under unusual
- * constraints.
- */
-static GC_thread GC_new_thread(void) {
- int i;
- /* It appears to be unsafe to acquire a lock here, since this */
- /* code is apparently not preeemptible on some systems. */
- /* (This is based on complaints, not on Microsoft's official */
- /* documentation, which says this should perform "only simple */
- /* initialization tasks".) */
- /* Hence we make do with nonblocking synchronization. */
-
- /* The following should be a noop according to the win32 */
- /* documentation. There is empirical evidence that it */
- /* isn't. - HB */
+/* And now the version used if GC_win32_dll_threads is not set. */
+/* This is a chained hash table, with much of the code borrowed */
+/* From the Posix implementation. */
+#ifndef THREAD_TABLE_SZ
+# define THREAD_TABLE_SZ 256 /* Power of 2 (for speed). */
+#endif
+#define THREAD_TABLE_INDEX(id) (((word)(id) >> 2) % THREAD_TABLE_SZ)
+STATIC GC_thread GC_threads[THREAD_TABLE_SZ];
+
+/* It may not be safe to allocate when we register the first thread. */
+/* Thus we allocated one statically. It does not contain any field we */
+/* need to push ("next" and "status" fields are unused). */
+static struct GC_Thread_Rep first_thread;
+static GC_bool first_thread_used = FALSE;
+
+/* Add a thread to GC_threads. We assume it wasn't already there. */
+/* Caller holds allocation lock. */
+/* Unlike the pthreads version, the id field is set by the caller. */
+STATIC GC_thread GC_new_thread(DWORD id)
+{
+ word hv = THREAD_TABLE_INDEX(id);
+ GC_thread result;
+
+ GC_ASSERT(I_HOLD_LOCK());
+ if (!EXPECT(first_thread_used, TRUE)) {
+ result = &first_thread;
+ first_thread_used = TRUE;
+ } else {
+ GC_ASSERT(!GC_win32_dll_threads);
+ result = (struct GC_Thread_Rep *)
+ GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
+ /* result can be NULL */
+ if (result == 0) return(0);
+ }
+ /* result -> id = id; Done by caller. */
+ result -> tm.next = GC_threads[hv];
+ GC_threads[hv] = result;
+# ifdef GC_PTHREADS
+ GC_ASSERT(result -> flags == 0);
+# endif
+ GC_ASSERT(result -> thread_blocked_sp == NULL);
+ return(result);
+}
+
+STATIC GC_bool GC_in_thread_creation = FALSE;
+ /* Protected by allocation lock. */
+
+GC_INLINE void GC_record_stack_base(GC_vthread me,
+ const struct GC_stack_base *sb)
+{
+ me -> stack_base = sb -> mem_base;
+# ifdef IA64
+ me -> backing_store_end = sb -> reg_base;
+# endif
+ if (me -> stack_base == NULL)
+ ABORT("Bad stack base in GC_register_my_thread");
+}
+
+/* This may be called from DllMain, and hence operates under unusual */
+/* constraints. In particular, it must be lock-free if */
+/* GC_win32_dll_threads is set. Always called from the thread being */
+/* added. If GC_win32_dll_threads is not set, we already hold the */
+/* allocation lock except possibly during single-threaded startup code. */
+STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
+ DWORD thread_id)
+{
+ GC_vthread me;
+
+ /* The following should be a no-op according to the win32 */
+ /* documentation. There is empirical evidence that it */
+ /* isn't. - HB */
# if defined(MPROTECT_VDB)
- if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
-# endif
- /* cast away volatile qualifier */
- for (i = 0; InterlockedExchange((IE_t)&thread_table[i].in_use,1) != 0; i++) {
- /* Compare-and-swap would make this cleaner, but that's not */
- /* supported before Windows 98 and NT 4.0. In Windows 2000, */
- /* InterlockedExchange is supposed to be replaced by */
- /* InterlockedExchangePointer, but that's not really what I */
- /* want here. */
- if (i == MAX_THREADS - 1)
- ABORT("too many threads");
- }
- /* Update GC_max_thread_index if necessary. The following is safe, */
- /* and unlike CompareExchange-based solutions seems to work on all */
- /* Windows95 and later platforms. */
- /* Unfortunately, GC_max_thread_index may be temporarily out of */
- /* bounds, so readers have to compensate. */
- while (i > GC_max_thread_index) {
- InterlockedIncrement((IE_t)&GC_max_thread_index);
- }
- if (GC_max_thread_index >= MAX_THREADS) {
- /* We overshot due to simultaneous increments. */
- /* Setting it to MAX_THREADS-1 is always safe. */
- GC_max_thread_index = MAX_THREADS - 1;
- }
-
-# ifdef CYGWIN32
- thread_table[i].pthread_id = pthread_self();
-# endif
- if (!DuplicateHandle(GetCurrentProcess(),
- GetCurrentThread(),
- GetCurrentProcess(),
- (HANDLE*)&thread_table[i].handle,
- 0,
- 0,
- DUPLICATE_SAME_ACCESS)) {
- DWORD last_error = GetLastError();
- GC_printf1("Last error code: %lx\n", last_error);
- ABORT("DuplicateHandle failed");
- }
- thread_table[i].stack_base = GC_get_stack_base();
- /* Up until this point, GC_push_all_stacks considers this thread */
- /* invalid. */
- if (thread_table[i].stack_base == NULL)
- ABORT("Failed to find stack base in GC_new_thread");
- /* Up until this point, this entry is viewed as reserved but invalid */
- /* by GC_delete_thread. */
- thread_table[i].id = GetCurrentThreadId();
- /* If this thread is being created while we are trying to stop */
- /* the world, wait here. Hopefully this can't happen on any */
- /* systems that don't allow us to block here. */
- while (GC_please_stop) Sleep(20);
- return thread_table + i;
+ if (GC_incremental
+# ifdef GWW_VDB
+ && !GC_gww_dirty_init()
+# endif
+ )
+ GC_set_write_fault_handler();
+# endif
+
+# ifndef GC_NO_THREADS_DISCOVERY
+ if (GC_win32_dll_threads) {
+ int i;
+ /* It appears to be unsafe to acquire a lock here, since this */
+ /* code is apparently not preemptible on some systems. */
+ /* (This is based on complaints, not on Microsoft's official */
+ /* documentation, which says this should perform "only simple */
+ /* initialization tasks".) */
+ /* Hence we make do with nonblocking synchronization. */
+ /* It has been claimed that DllMain is really only executed with */
+ /* a particular system lock held, and thus careful use of locking */
+ /* around code that doesn't call back into the system libraries */
+ /* might be OK. But this hasn't been tested across all win32 */
+ /* variants. */
+ /* cast away volatile qualifier */
+ for (i = 0;
+ InterlockedExchange((void*)&dll_thread_table[i].tm.in_use, 1) != 0;
+ i++) {
+ /* Compare-and-swap would make this cleaner, but that's not */
+ /* supported before Windows 98 and NT 4.0. In Windows 2000, */
+ /* InterlockedExchange is supposed to be replaced by */
+ /* InterlockedExchangePointer, but that's not really what I */
+ /* want here. */
+ /* FIXME: We should eventually declare Win95 dead and use AO_ */
+ /* primitives here. */
+ if (i == MAX_THREADS - 1)
+ ABORT("Too many threads");
+ }
+ /* Update GC_max_thread_index if necessary. The following is */
+ /* safe, and unlike CompareExchange-based solutions seems to work */
+ /* on all Windows95 and later platforms. */
+ /* Unfortunately, GC_max_thread_index may be temporarily out of */
+ /* bounds, so readers have to compensate. */
+ while (i > GC_max_thread_index) {
+ InterlockedIncrement((IE_t)&GC_max_thread_index);
+ }
+ if (GC_max_thread_index >= MAX_THREADS) {
+ /* We overshot due to simultaneous increments. */
+ /* Setting it to MAX_THREADS-1 is always safe. */
+ GC_max_thread_index = MAX_THREADS - 1;
+ }
+ me = dll_thread_table + i;
+ } else
+# endif
+ /* else */ /* Not using DllMain */ {
+ GC_ASSERT(I_HOLD_LOCK());
+ GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
+ me = GC_new_thread(thread_id);
+ GC_in_thread_creation = FALSE;
+ if (me == 0)
+ ABORT("Failed to allocate memory for thread registering");
+ }
+# ifdef GC_PTHREADS
+ /* me can be NULL -> segfault */
+ me -> pthread_id = pthread_self();
+# endif
+# ifndef MSWINCE
+ /* GetCurrentThread() returns a pseudohandle (a const value). */
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(),
+ (HANDLE*)&(me -> handle),
+ 0 /* dwDesiredAccess */, FALSE /* bInheritHandle */,
+ DUPLICATE_SAME_ACCESS)) {
+ GC_COND_LOG_PRINTF("DuplicateHandle failed with error code: %d\n",
+ (int)GetLastError());
+ ABORT("DuplicateHandle failed");
+ }
+# endif
+ me -> last_stack_min = ADDR_LIMIT;
+ GC_record_stack_base(me, sb);
+ /* Up until this point, GC_push_all_stacks considers this thread */
+ /* invalid. */
+ /* Up until this point, this entry is viewed as reserved but invalid */
+ /* by GC_delete_thread. */
+ me -> id = thread_id;
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
+# endif
+# ifndef GC_NO_THREADS_DISCOVERY
+ if (GC_win32_dll_threads) {
+ if (GC_please_stop) {
+ AO_store(&GC_attached_thread, TRUE);
+ AO_nop_full(); /* Later updates must become visible after this. */
+ }
+ /* We'd like to wait here, but can't, since waiting in DllMain */
+ /* provokes deadlocks. */
+ /* Thus we force marking to be restarted instead. */
+ } else
+# endif
+ /* else */ {
+ GC_ASSERT(!GC_please_stop);
+ /* Otherwise both we and the thread stopping code would be */
+ /* holding the allocation lock. */
+ }
+ return (GC_thread)(me);
}
/*
* GC_max_thread_index may temporarily be larger than MAX_THREADS.
* To avoid subscript errors, we check on access.
*/
-#ifdef __GNUC__
-__inline__
-#endif
-LONG GC_get_max_thread_index()
+GC_INLINE LONG GC_get_max_thread_index(void)
{
LONG my_max = GC_max_thread_index;
-
- if (my_max >= MAX_THREADS) return MAX_THREADS-1;
+ if (my_max >= MAX_THREADS) return MAX_THREADS - 1;
return my_max;
}
-/* This is intended to be lock-free, though that */
-/* assumes that the CloseHandle becomes visible before the */
-/* in_use assignment. */
-static void GC_delete_gc_thread(GC_thread thr)
+/* Return the GC_thread corresponding to a thread id. May be called */
+/* without a lock, but should be called in contexts in which the */
+/* requested thread cannot be asynchronously deleted, e.g. from the */
+/* thread itself. */
+/* This version assumes that either GC_win32_dll_threads is set, or */
+/* we hold the allocator lock. */
+/* Also used (for assertion checking only) from thread_local_alloc.c. */
+STATIC GC_thread GC_lookup_thread_inner(DWORD thread_id)
{
- CloseHandle(thr->handle);
- /* cast away volatile qualifier */
- thr->stack_base = 0;
- thr->id = 0;
-# ifdef CYGWIN32
- thr->pthread_id = 0;
-# endif /* CYGWIN32 */
- thr->in_use = FALSE;
+# ifndef GC_NO_THREADS_DISCOVERY
+ if (GC_win32_dll_threads) {
+ int i;
+ LONG my_max = GC_get_max_thread_index();
+ for (i = 0; i <= my_max &&
+ (!AO_load_acquire(&dll_thread_table[i].tm.in_use)
+ || dll_thread_table[i].id != thread_id);
+ /* Must still be in_use, since nobody else can store our */
+ /* thread_id. */
+ i++) {
+ /* empty */
+ }
+ return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
+ } else
+# endif
+ /* else */ {
+ word hv = THREAD_TABLE_INDEX(thread_id);
+ register GC_thread p = GC_threads[hv];
+
+ GC_ASSERT(I_HOLD_LOCK());
+ while (p != 0 && p -> id != thread_id) p = p -> tm.next;
+ return(p);
+ }
}
-static void GC_delete_thread(DWORD thread_id) {
- int i;
- LONG my_max = GC_get_max_thread_index();
-
- for (i = 0;
- i <= my_max &&
- (!thread_table[i].in_use || thread_table[i].id != thread_id);
- /* Must still be in_use, since nobody else can store our thread_id. */
- i++) {}
- if (i > my_max) {
- WARN("Removing nonexisiting thread %ld\n", (GC_word)thread_id);
- } else {
- GC_delete_gc_thread(thread_table+i);
+#ifdef LINT2
+# define CHECK_LOOKUP_MY_THREAD(me) \
+ if (!(me)) ABORT("GC_lookup_thread_inner(GetCurrentThreadId) failed")
+#else
+# define CHECK_LOOKUP_MY_THREAD(me) /* empty */
+#endif
+
+/* Called by GC_finalize() (in case of an allocation failure observed). */
+/* GC_reset_finalizer_nested() is the same as in pthread_support.c. */
+GC_INNER void GC_reset_finalizer_nested(void)
+{
+ GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
+ CHECK_LOOKUP_MY_THREAD(me);
+ me->finalizer_nested = 0;
+}
+
+/* Checks and updates the thread-local level of finalizers recursion. */
+/* Returns NULL if GC_invoke_finalizers() should not be called by the */
+/* collector (to minimize the risk of a deep finalizers recursion), */
+/* otherwise returns a pointer to the thread-local finalizer_nested. */
+/* Called by GC_notify_or_invoke_finalizers() only (the lock is held). */
+/* GC_check_finalizer_nested() is the same as in pthread_support.c. */
+GC_INNER unsigned char *GC_check_finalizer_nested(void)
+{
+ GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
+ unsigned nesting_level;
+ CHECK_LOOKUP_MY_THREAD(me);
+ nesting_level = me->finalizer_nested;
+ if (nesting_level) {
+ /* We are inside another GC_invoke_finalizers(). */
+ /* Skip some implicitly-called GC_invoke_finalizers() */
+ /* depending on the nesting (recursion) level. */
+ if (++me->finalizer_skipped < (1U << nesting_level)) return NULL;
+ me->finalizer_skipped = 0;
}
+ me->finalizer_nested = (unsigned char)(nesting_level + 1);
+ return &me->finalizer_nested;
}
+#if defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)
+ /* This is called from thread-local GC_malloc(). */
+ GC_bool GC_is_thread_tsd_valid(void *tsd)
+ {
+ GC_thread me;
+ DCL_LOCK_STATE;
-#ifdef CYGWIN32
+ LOCK();
+ me = GC_lookup_thread_inner(GetCurrentThreadId());
+ UNLOCK();
+ return (word)tsd >= (word)(&me->tlfs)
+ && (word)tsd < (word)(&me->tlfs) + sizeof(me->tlfs);
+ }
+#endif /* GC_ASSERTIONS && THREAD_LOCAL_ALLOC */
-/* Return a GC_thread corresponding to a given pthread_t. */
-/* Returns 0 if it's not there. */
-/* We assume that this is only called for pthread ids that */
-/* have not yet terminated or are still joinable. */
-static GC_thread GC_lookup_thread(pthread_t id)
+GC_API int GC_CALL GC_thread_is_registered(void)
{
- int i;
- LONG my_max = GC_get_max_thread_index();
-
- for (i = 0;
- i <= my_max &&
- (!thread_table[i].in_use || thread_table[i].pthread_id != id
- || !thread_table[i].in_use);
- /* Must still be in_use, since nobody else can store our thread_id. */
- i++);
- if (i > my_max) return 0;
- return thread_table + i;
+ DWORD thread_id = GetCurrentThreadId();
+ GC_thread me;
+ DCL_LOCK_STATE;
+
+ LOCK();
+ me = GC_lookup_thread_inner(thread_id);
+ UNLOCK();
+ return me != NULL;
}
-#endif /* CYGWIN32 */
+/* Make sure thread descriptor t is not protected by the VDB */
+/* implementation. */
+/* Used to prevent write faults when the world is (partially) stopped, */
+/* since it may have been stopped with a system lock held, and that */
+/* lock may be required for fault handling. */
+#if defined(MPROTECT_VDB)
+# define UNPROTECT_THREAD(t) \
+ if (!GC_win32_dll_threads && GC_dirty_maintained \
+ && t != &first_thread) { \
+ GC_ASSERT(SMALL_OBJ(GC_size(t))); \
+ GC_remove_protection(HBLKPTR(t), 1, FALSE); \
+ }
+#else
+# define UNPROTECT_THREAD(t)
+#endif
-void GC_push_thread_structures GC_PROTO((void))
+#ifdef CYGWIN32
+# define GC_PTHREAD_PTRVAL(pthread_id) pthread_id
+#elif defined(GC_WIN32_PTHREADS)
+# define GC_PTHREAD_PTRVAL(pthread_id) pthread_id.p
+#endif
+
+/* If a thread has been joined, but we have not yet */
+/* been notified, then there may be more than one thread */
+/* in the table with the same win32 id. */
+/* This is OK, but we need a way to delete a specific one. */
+/* Assumes we hold the allocation lock unless */
+/* GC_win32_dll_threads is set. Does not actually free */
+/* GC_thread entry (only unlinks it). */
+/* If GC_win32_dll_threads is set it should be called from the */
+/* thread being deleted. */
+STATIC void GC_delete_gc_thread_no_free(GC_vthread t)
{
- /* Unlike the other threads implementations, the thread table here */
- /* contains no pointers to the collectable heap. Thus we have */
- /* no private structures we need to preserve. */
-# ifdef CYGWIN32
- { int i; /* pthreads may keep a pointer in the thread exit value */
- LONG my_max = GC_get_max_thread_index();
+# ifndef MSWINCE
+ CloseHandle(t->handle);
+# endif
+# ifndef GC_NO_THREADS_DISCOVERY
+ 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 asynchronous changes to (*t) are possible. */
+ /* It's not allowed to call GC_printf (and the friends) here, */
+ /* see GC_stop_world() for the information. */
+ t -> stack_base = 0;
+ t -> id = 0;
+ AO_store_release(&t->tm.in_use, FALSE);
+ } else
+# endif
+ /* else */ {
+ DWORD id = ((GC_thread)t) -> id;
+ /* Cast away volatile qualifier, since we have lock. */
+ word hv = THREAD_TABLE_INDEX(id);
+ register GC_thread p = GC_threads[hv];
+ register GC_thread prev = 0;
+
+ GC_ASSERT(I_HOLD_LOCK());
+ while (p != (GC_thread)t) {
+ prev = p;
+ p = p -> tm.next;
+ }
+ if (prev == 0) {
+ GC_threads[hv] = p -> tm.next;
+ } else {
+ prev -> tm.next = p -> tm.next;
+ }
+ }
+}
- for (i = 0; i <= my_max; i++)
- if (thread_table[i].in_use)
- GC_push_all((ptr_t)&(thread_table[i].status),
- (ptr_t)(&(thread_table[i].status)+1));
+/* Delete a thread from GC_threads. We assume it is there. */
+/* (The code intentionally traps if it wasn't.) Assumes we */
+/* hold the allocation lock unless GC_win32_dll_threads is set. */
+/* If GC_win32_dll_threads is set then it should be called from */
+/* the thread being deleted. It is also safe to delete the */
+/* main thread (unless GC_win32_dll_threads). */
+STATIC void GC_delete_thread(DWORD id)
+{
+ if (GC_win32_dll_threads) {
+ GC_vthread t = GC_lookup_thread_inner(id);
+
+ if (0 == t) {
+ WARN("Removing nonexistent thread, id = %" WARN_PRIdPTR "\n", id);
+ } else {
+ GC_delete_gc_thread_no_free(t);
+ }
+ } else {
+ word hv = THREAD_TABLE_INDEX(id);
+ register GC_thread p = GC_threads[hv];
+ register GC_thread prev = 0;
+
+ GC_ASSERT(I_HOLD_LOCK());
+ while (p -> id != id) {
+ prev = p;
+ p = p -> tm.next;
+ }
+# ifndef MSWINCE
+ CloseHandle(p->handle);
+# endif
+ if (prev == 0) {
+ GC_threads[hv] = p -> tm.next;
+ } else {
+ prev -> tm.next = p -> tm.next;
+ }
+ if (p != &first_thread) {
+ GC_INTERNAL_FREE(p);
+ }
}
+}
+
+GC_API void GC_CALL GC_allow_register_threads(void)
+{
+ /* Check GC is initialized and the current thread is registered. */
+ GC_ASSERT(GC_lookup_thread_inner(GetCurrentThreadId()) != 0);
+
+# if !defined(GC_NO_THREADS_DISCOVERY) && !defined(PARALLEL_MARK)
+ /* GC_init() doesn't call GC_init_parallel() in this case. */
+ parallel_initialized = TRUE;
# endif
+ GC_need_to_lock = TRUE; /* We are multi-threaded now. */
}
-void GC_stop_world()
+GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
{
+ GC_thread me;
DWORD thread_id = GetCurrentThreadId();
- int i;
+ DCL_LOCK_STATE;
+
+ if (GC_need_to_lock == FALSE)
+ ABORT("Threads explicit registering is not previously enabled");
+
+ /* We lock here, since we want to wait for an ongoing GC. */
+ LOCK();
+ me = GC_lookup_thread_inner(thread_id);
+ if (me == 0) {
+# ifdef GC_PTHREADS
+ me = GC_register_my_thread_inner(sb, thread_id);
+ me -> flags |= DETACHED;
+ /* Treat as detached, since we do not need to worry about */
+ /* pointer results. */
+# else
+ GC_register_my_thread_inner(sb, thread_id);
+# endif
+ UNLOCK();
+ return GC_SUCCESS;
+ } else
+# ifdef GC_PTHREADS
+ /* else */ if ((me -> flags & FINISHED) != 0) {
+ GC_record_stack_base(me, sb);
+ me -> flags &= ~FINISHED; /* but not DETACHED */
+# ifdef THREAD_LOCAL_ALLOC
+ GC_init_thread_local((GC_tlfs)(&me->tlfs));
+# endif
+ UNLOCK();
+ return GC_SUCCESS;
+ } else
+# endif
+ /* else */ {
+ UNLOCK();
+ return GC_DUPLICATE;
+ }
+}
- if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
+/* Similar to that in pthread_support.c. */
+STATIC void GC_wait_for_gc_completion(GC_bool wait_for_all)
+{
+ GC_ASSERT(I_HOLD_LOCK());
+ if (GC_incremental && GC_collection_in_progress()) {
+ word old_gc_no = GC_gc_no;
+
+ /* Make sure that no part of our stack is still on the mark stack, */
+ /* since it's about to be unmapped. */
+ do {
+ ENTER_GC();
+ GC_in_thread_creation = TRUE;
+ GC_collect_a_little_inner(1);
+ GC_in_thread_creation = FALSE;
+ EXIT_GC();
- GC_please_stop = TRUE;
- for (i = 0; i <= GC_get_max_thread_index(); i++)
- if (thread_table[i].stack_base != 0
- && thread_table[i].id != thread_id) {
-# ifdef MSWINCE
- /* SuspendThread will fail if thread is running kernel code */
- while (SuspendThread(thread_table[i].handle) == (DWORD)-1)
- Sleep(10);
-# else
- /* Apparently the Windows 95 GetOpenFileName call creates */
- /* a thread that does not properly get cleaned up, and */
- /* SuspendThread on its descriptor may provoke a crash. */
- /* This reduces the probability of that event, though it still */
- /* appears there's a race here. */
- DWORD exitCode;
- if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
- exitCode != STILL_ACTIVE) {
- thread_table[i].stack_base = 0; /* prevent stack from being pushed */
-# ifndef CYGWIN32
- /* this breaks pthread_join on Cygwin, which is guaranteed to */
- /* only see user pthreads */
- thread_table[i].in_use = FALSE;
- CloseHandle(thread_table[i].handle);
-# endif
- continue;
- }
- if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
- ABORT("SuspendThread failed");
-# endif
- thread_table[i].suspended = TRUE;
- }
+ UNLOCK();
+ Sleep(0); /* yield */
+ LOCK();
+ } while (GC_incremental && GC_collection_in_progress()
+ && (wait_for_all || old_gc_no == GC_gc_no));
+ }
}
-void GC_start_world()
+GC_API int GC_CALL GC_unregister_my_thread(void)
{
- DWORD thread_id = GetCurrentThreadId();
- int i;
- LONG my_max = GC_get_max_thread_index();
+ DCL_LOCK_STATE;
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("Unregistering thread 0x%lx\n", (long)GetCurrentThreadId());
+# endif
- for (i = 0; i <= my_max; i++)
- if (thread_table[i].stack_base != 0 && thread_table[i].suspended
- && thread_table[i].id != thread_id) {
- if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
- ABORT("ResumeThread failed");
- thread_table[i].suspended = FALSE;
+ if (GC_win32_dll_threads) {
+# if defined(THREAD_LOCAL_ALLOC)
+ /* Can't happen: see GC_use_threads_discovery(). */
+ GC_ASSERT(FALSE);
+# else
+ /* FIXME: Should we just ignore this? */
+ GC_delete_thread(GetCurrentThreadId());
+# endif
+ } else {
+# if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
+ GC_thread me;
+# endif
+ DWORD thread_id = GetCurrentThreadId();
+
+ LOCK();
+ GC_wait_for_gc_completion(FALSE);
+# if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
+ me = GC_lookup_thread_inner(thread_id);
+ CHECK_LOOKUP_MY_THREAD(me);
+ GC_ASSERT(!KNOWN_FINISHED(me));
+# endif
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
+ GC_destroy_thread_local(&(me->tlfs));
+# endif
+# ifdef GC_PTHREADS
+ if ((me -> flags & DETACHED) == 0) {
+ me -> flags |= FINISHED;
+ } else
+# endif
+ /* else */ {
+ GC_delete_thread(thread_id);
}
- GC_please_stop = FALSE;
+# if defined(THREAD_LOCAL_ALLOC)
+ /* It is required to call remove_specific defined in specific.c. */
+ GC_remove_specific(GC_thread_key);
+# endif
+ UNLOCK();
+ }
+ return GC_SUCCESS;
}
-# ifdef _MSC_VER
-# pragma warning(disable:4715)
+/* Wrapper for functions that are likely to block for an appreciable */
+/* length of time. */
+
+/* GC_do_blocking_inner() is nearly the same as in pthread_support.c */
+GC_INNER void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
+{
+ struct blocking_data * d = (struct blocking_data *) data;
+ DWORD thread_id = GetCurrentThreadId();
+ GC_thread me;
+# ifdef IA64
+ ptr_t stack_ptr = GC_save_regs_in_stack();
# endif
-ptr_t GC_current_stackbottom()
+ DCL_LOCK_STATE;
+
+ LOCK();
+ me = GC_lookup_thread_inner(thread_id);
+ CHECK_LOOKUP_MY_THREAD(me);
+ GC_ASSERT(me -> thread_blocked_sp == NULL);
+# ifdef IA64
+ me -> backing_store_ptr = stack_ptr;
+# endif
+ me -> thread_blocked_sp = (ptr_t) &d; /* save approx. sp */
+ /* Save context here if we want to support precise stack marking */
+ UNLOCK();
+ d -> client_data = (d -> fn)(d -> client_data);
+ LOCK(); /* This will block if the world is stopped. */
+ me -> thread_blocked_sp = NULL;
+ UNLOCK();
+}
+
+/* GC_call_with_gc_active() has the opposite to GC_do_blocking() */
+/* functionality. It might be called from a user function invoked by */
+/* GC_do_blocking() to temporarily back allow calling any GC function */
+/* and/or manipulating pointers to the garbage collected heap. */
+GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
+ void * client_data)
{
+ struct GC_traced_stack_sect_s stacksect;
DWORD thread_id = GetCurrentThreadId();
- int i;
- LONG my_max = GC_get_max_thread_index();
+ GC_thread me;
+ DCL_LOCK_STATE;
+
+ LOCK(); /* This will block if the world is stopped. */
+ me = GC_lookup_thread_inner(thread_id);
+ CHECK_LOOKUP_MY_THREAD(me);
+ /* Adjust our stack base value (this could happen unless */
+ /* GC_get_stack_base() was used which returned GC_SUCCESS). */
+ GC_ASSERT(me -> stack_base != NULL);
+ if ((word)me->stack_base < (word)(&stacksect))
+ me -> stack_base = (ptr_t)(&stacksect);
+
+ if (me -> thread_blocked_sp == NULL) {
+ /* We are not inside GC_do_blocking() - do nothing more. */
+ UNLOCK();
+ return fn(client_data);
+ }
+
+ /* Setup new "stack section". */
+ stacksect.saved_stack_ptr = me -> thread_blocked_sp;
+# ifdef IA64
+ /* This is the same as in GC_call_with_stack_base(). */
+ stacksect.backing_store_end = GC_save_regs_in_stack();
+ /* Unnecessarily flushes register stack, */
+ /* but that probably doesn't hurt. */
+ stacksect.saved_backing_store_ptr = me -> backing_store_ptr;
+# endif
+ stacksect.prev = me -> traced_stack_sect;
+ me -> thread_blocked_sp = NULL;
+ me -> traced_stack_sect = &stacksect;
+
+ UNLOCK();
+ client_data = fn(client_data);
+ GC_ASSERT(me -> thread_blocked_sp == NULL);
+ GC_ASSERT(me -> traced_stack_sect == &stacksect);
+
+ /* Restore original "stack section". */
+ LOCK();
+ me -> traced_stack_sect = stacksect.prev;
+# ifdef IA64
+ me -> backing_store_ptr = stacksect.saved_backing_store_ptr;
+# endif
+ me -> thread_blocked_sp = stacksect.saved_stack_ptr;
+ UNLOCK();
- for (i = 0; i <= my_max; i++)
- if (thread_table[i].stack_base && thread_table[i].id == thread_id)
- return thread_table[i].stack_base;
- ABORT("no thread table entry for current thread");
+ return client_data; /* result */
}
-# ifdef _MSC_VER
-# pragma warning(default:4715)
+
+#ifdef GC_PTHREADS
+
+ /* A quick-and-dirty cache of the mapping between pthread_t */
+ /* and win32 thread id. */
+# define PTHREAD_MAP_SIZE 512
+ DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE] = {0};
+# define PTHREAD_MAP_INDEX(pthread_id) \
+ ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)
+ /* It appears pthread_t is really a pointer type ... */
+# define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \
+ (GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)] = (win32_id))
+# define GET_PTHREAD_MAP_CACHE(pthread_id) \
+ GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)]
+
+ /* Return a GC_thread corresponding to a given pthread_t. */
+ /* Returns 0 if it's not there. */
+ /* We assume that this is only called for pthread ids that */
+ /* have not yet terminated or are still joinable, and */
+ /* cannot be concurrently terminated. */
+ /* Assumes we do NOT hold the allocation lock. */
+ STATIC GC_thread GC_lookup_pthread(pthread_t id)
+ {
+# ifndef GC_NO_THREADS_DISCOVERY
+ if (GC_win32_dll_threads) {
+ int i;
+ LONG my_max = GC_get_max_thread_index();
+
+ for (i = 0; i <= my_max &&
+ (!AO_load_acquire(&dll_thread_table[i].tm.in_use)
+ || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));
+ /* Must still be in_use, since nobody else can */
+ /* store our thread_id. */
+ i++) {
+ /* empty */
+ }
+ return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
+ } else
+# endif
+ /* else */ {
+ /* We first try the cache. If that fails, we use a very slow */
+ /* approach. */
+ word hv_guess = THREAD_TABLE_INDEX(GET_PTHREAD_MAP_CACHE(id));
+ int hv;
+ GC_thread p;
+ DCL_LOCK_STATE;
+
+ LOCK();
+ for (p = GC_threads[hv_guess]; 0 != p; p = p -> tm.next) {
+ if (THREAD_EQUAL(p -> pthread_id, id))
+ goto foundit;
+ }
+ for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
+ for (p = GC_threads[hv]; 0 != p; p = p -> tm.next) {
+ if (THREAD_EQUAL(p -> pthread_id, id))
+ goto foundit;
+ }
+ }
+ p = 0;
+ foundit:
+ UNLOCK();
+ return p;
+ }
+ }
+
+#endif /* GC_PTHREADS */
+
+#ifdef CAN_HANDLE_FORK
+ /* Similar to that in pthread_support.c but also rehashes the table */
+ /* since hash map key (thread_id) differs from that in the parent. */
+ STATIC void GC_remove_all_threads_but_me(void)
+ {
+ int hv;
+ GC_thread p, next, me = NULL;
+ DWORD thread_id;
+ pthread_t pthread_id = pthread_self(); /* same as in parent */
+
+ GC_ASSERT(!GC_win32_dll_threads);
+ for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
+ for (p = GC_threads[hv]; 0 != p; p = next) {
+ next = p -> tm.next;
+ if (THREAD_EQUAL(p -> pthread_id, pthread_id)) {
+ GC_ASSERT(me == NULL);
+ me = p;
+ p -> tm.next = 0;
+ } else {
+# ifdef THREAD_LOCAL_ALLOC
+ if ((p -> flags & FINISHED) == 0) {
+ GC_destroy_thread_local(&p->tlfs);
+ GC_remove_specific(GC_thread_key);
+ }
+# endif
+ if (&first_thread != p)
+ GC_INTERNAL_FREE(p);
+ }
+ }
+ GC_threads[hv] = NULL;
+ }
+
+ /* Put "me" back to GC_threads. */
+ GC_ASSERT(me != NULL);
+ thread_id = GetCurrentThreadId(); /* differs from that in parent */
+ GC_threads[THREAD_TABLE_INDEX(thread_id)] = me;
+
+ /* Update Win32 thread Id and handle. */
+ me -> id = thread_id;
+# ifndef MSWINCE
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), (HANDLE *)&me->handle,
+ 0 /* dwDesiredAccess */, FALSE /* bInheritHandle */,
+ DUPLICATE_SAME_ACCESS))
+ ABORT("DuplicateHandle failed");
+# endif
+
+# if defined(THREAD_LOCAL_ALLOC) && !defined(USE_CUSTOM_SPECIFIC)
+ /* For Cygwin, we need to re-assign thread-local pointer to */
+ /* 'tlfs' (it is ok to call GC_destroy_thread_local and */
+ /* GC_free_internal before this action). */
+ if (GC_setspecific(GC_thread_key, &me->tlfs) != 0)
+ ABORT("GC_setspecific failed (in child)");
+# endif
+ }
+
+ static void fork_prepare_proc(void)
+ {
+ LOCK();
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_wait_for_reclaim();
+# endif
+ GC_wait_for_gc_completion(TRUE);
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_acquire_mark_lock();
+# endif
+ }
+
+ static void fork_parent_proc(void)
+ {
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_release_mark_lock();
+# endif
+ UNLOCK();
+ }
+
+ static void fork_child_proc(void)
+ {
+# ifdef PARALLEL_MARK
+ if (GC_parallel) {
+ GC_release_mark_lock();
+ GC_parallel = FALSE; /* or GC_markers_m1 = 0 */
+ /* Turn off parallel marking in the child, since we are */
+ /* probably just going to exec, and we would have to */
+ /* restart mark threads. */
+ }
+# endif
+ GC_remove_all_threads_but_me();
+ UNLOCK();
+ }
+
+ /* Routines for fork handling by client (no-op if pthread_atfork works). */
+ GC_API void GC_CALL GC_atfork_prepare(void)
+ {
+ if (GC_handle_fork <= 0)
+ fork_prepare_proc();
+ }
+
+ GC_API void GC_CALL GC_atfork_parent(void)
+ {
+ if (GC_handle_fork <= 0)
+ fork_parent_proc();
+ }
+
+ GC_API void GC_CALL GC_atfork_child(void)
+ {
+ if (GC_handle_fork <= 0)
+ fork_child_proc();
+ }
+#endif /* CAN_HANDLE_FORK */
+
+void GC_push_thread_structures(void)
+{
+ GC_ASSERT(I_HOLD_LOCK());
+# ifndef GC_NO_THREADS_DISCOVERY
+ if (GC_win32_dll_threads) {
+ /* Unlike the other threads implementations, the thread table */
+ /* here contains no pointers to the collectible heap (note also */
+ /* that GC_PTHREADS is incompatible with DllMain-based thread */
+ /* registration). Thus we have no private structures we need */
+ /* to preserve. */
+ } else
+# endif
+ /* else */ {
+ GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
+ }
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_push_all((ptr_t)(&GC_thread_key),
+ (ptr_t)(&GC_thread_key) + sizeof(GC_thread_key));
+ /* Just in case we ever use our own TLS implementation. */
+# endif
+}
+
+/* Suspend the given thread, if it's still active. */
+STATIC void GC_suspend(GC_thread t)
+{
+# ifndef MSWINCE
+ /* Apparently the Windows 95 GetOpenFileName call creates */
+ /* a thread that does not properly get cleaned up, and */
+ /* SuspendThread on its descriptor may provoke a crash. */
+ /* This reduces the probability of that event, though it still */
+ /* appears there's a race here. */
+ DWORD exitCode;
+# endif
+ UNPROTECT_THREAD(t);
+# ifndef MSWINCE
+ if (GetExitCodeThread(t -> handle, &exitCode) &&
+ exitCode != STILL_ACTIVE) {
+# ifdef GC_PTHREADS
+ t -> stack_base = 0; /* prevent stack from being pushed */
+# else
+ /* this breaks pthread_join on Cygwin, which is guaranteed to */
+ /* only see user pthreads */
+ GC_ASSERT(GC_win32_dll_threads);
+ GC_delete_gc_thread_no_free(t);
+# endif
+ return;
+ }
+# endif
+# if defined(MPROTECT_VDB)
+ /* Acquire the spin lock we use to update dirty bits. */
+ /* Threads shouldn't get stopped holding it. But we may */
+ /* acquire and release it in the UNPROTECT_THREAD call. */
+ while (AO_test_and_set_acquire(&GC_fault_handler_lock) == AO_TS_SET) {
+ /* empty */
+ }
# endif
# ifdef MSWINCE
- /* The VirtualQuery calls below won't work properly on WinCE, but */
- /* since each stack is restricted to an aligned 64K region of */
- /* virtual memory we can just take the next lowest multiple of 64K. */
-# define GC_get_stack_min(s) \
- ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))
+ /* SuspendThread() will fail if thread is running kernel code. */
+ while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1)
+ Sleep(10); /* in millis */
# else
- static ptr_t GC_get_stack_min(ptr_t s)
- {
- ptr_t bottom;
- MEMORY_BASIC_INFORMATION info;
- VirtualQuery(s, &info, sizeof(info));
- do {
- bottom = info.BaseAddress;
- VirtualQuery(bottom - 1, &info, sizeof(info));
- } while ((info.Protect & PAGE_READWRITE)
- && !(info.Protect & PAGE_GUARD));
- return(bottom);
- }
+ if (SuspendThread(t -> handle) == (DWORD)-1)
+ ABORT("SuspendThread failed");
+# endif /* !MSWINCE */
+ t -> suspended = (unsigned char)TRUE;
+# if defined(MPROTECT_VDB)
+ AO_CLEAR(&GC_fault_handler_lock);
# endif
+}
-void GC_push_all_stacks()
+#if defined(GC_ASSERTIONS) && !defined(CYGWIN32)
+ GC_INNER GC_bool GC_write_disabled = FALSE;
+ /* TRUE only if GC_stop_world() acquired GC_write_cs. */
+#endif
+
+GC_INNER void GC_stop_world(void)
{
DWORD thread_id = GetCurrentThreadId();
- GC_bool found_me = FALSE;
+
+ if (!GC_thr_initialized)
+ ABORT("GC_stop_world() called before GC_thr_init()");
+ GC_ASSERT(I_HOLD_LOCK());
+
+ /* This code is the same as in pthread_stop_world.c */
+# ifdef PARALLEL_MARK
+ if (GC_parallel) {
+ GC_acquire_mark_lock();
+ GC_ASSERT(GC_fl_builder_count == 0);
+ /* We should have previously waited for it to become zero. */
+ }
+# endif /* PARALLEL_MARK */
+
+# if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
+ GC_please_stop = TRUE;
+# endif
+# ifndef CYGWIN32
+ GC_ASSERT(!GC_write_disabled);
+ EnterCriticalSection(&GC_write_cs);
+ /* It's not allowed to call GC_printf() (and friends) here down to */
+ /* LeaveCriticalSection (same applies recursively to GC_suspend, */
+ /* GC_delete_gc_thread_no_free, GC_get_max_thread_index, GC_size */
+ /* and GC_remove_protection). */
+# ifdef GC_ASSERTIONS
+ GC_write_disabled = TRUE;
+# endif
+# endif
+# ifndef GC_NO_THREADS_DISCOVERY
+ if (GC_win32_dll_threads) {
+ int i;
+ int my_max;
+ /* Any threads being created during this loop will end up setting */
+ /* GC_attached_thread when they start. This will force marking */
+ /* to restart. This is not ideal, but hopefully correct. */
+ AO_store(&GC_attached_thread, FALSE);
+ my_max = (int)GC_get_max_thread_index();
+ for (i = 0; i <= my_max; i++) {
+ GC_vthread t = dll_thread_table + i;
+ if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
+ && t -> id != thread_id) {
+ GC_suspend((GC_thread)t);
+ }
+ }
+ } else
+# endif
+ /* else */ {
+ GC_thread t;
+ int i;
+
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
+ if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
+ && !KNOWN_FINISHED(t) && t -> id != thread_id) {
+ GC_suspend(t);
+ }
+ }
+ }
+ }
+# ifndef CYGWIN32
+# ifdef GC_ASSERTIONS
+ GC_write_disabled = FALSE;
+# endif
+ LeaveCriticalSection(&GC_write_cs);
+# endif
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_release_mark_lock();
+# endif
+}
+
+GC_INNER void GC_start_world(void)
+{
+# ifdef GC_ASSERTIONS
+ DWORD thread_id = GetCurrentThreadId();
+# endif
int i;
- int dummy;
+
+ GC_ASSERT(I_HOLD_LOCK());
+ if (GC_win32_dll_threads) {
+ LONG my_max = GC_get_max_thread_index();
+ for (i = 0; i <= my_max; i++) {
+ GC_thread t = (GC_thread)(dll_thread_table + i);
+ if (t -> suspended) {
+ GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
+ if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
+ ABORT("ResumeThread failed");
+ t -> suspended = FALSE;
+ }
+ }
+ } else {
+ GC_thread t;
+ int i;
+
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
+ if (t -> suspended) {
+ GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
+ if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
+ ABORT("ResumeThread failed");
+ UNPROTECT_THREAD(t);
+ t -> suspended = FALSE;
+ }
+ }
+ }
+ }
+# if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
+ GC_please_stop = FALSE;
+# endif
+}
+
+#ifdef MSWINCE
+ /* The VirtualQuery calls below won't work properly on some old WinCE */
+ /* versions, but since each stack is restricted to an aligned 64 KiB */
+ /* region of virtual memory we can just take the next lowest multiple */
+ /* of 64 KiB. The result of this macro must not be used as its */
+ /* argument later and must not be used as the lower bound for sp */
+ /* check (since the stack may be bigger than 64 KiB). */
+# define GC_wince_evaluate_stack_min(s) \
+ (ptr_t)(((word)(s) - 1) & ~(word)0xFFFF)
+#elif defined(GC_ASSERTIONS)
+# define GC_dont_query_stack_min FALSE
+#endif
+
+/* A cache holding the results of the recent VirtualQuery call. */
+/* Protected by the allocation lock. */
+static ptr_t last_address = 0;
+static MEMORY_BASIC_INFORMATION last_info;
+
+/* Probe stack memory region (starting at "s") to find out its */
+/* lowest address (i.e. stack top). */
+/* S must be a mapped address inside the region, NOT the first */
+/* unmapped address. */
+STATIC ptr_t GC_get_stack_min(ptr_t s)
+{
+ ptr_t bottom;
+
+ GC_ASSERT(I_HOLD_LOCK());
+ if (s != last_address) {
+ VirtualQuery(s, &last_info, sizeof(last_info));
+ last_address = s;
+ }
+ do {
+ bottom = last_info.BaseAddress;
+ VirtualQuery(bottom - 1, &last_info, sizeof(last_info));
+ last_address = bottom - 1;
+ } while ((last_info.Protect & PAGE_READWRITE)
+ && !(last_info.Protect & PAGE_GUARD));
+ return(bottom);
+}
+
+/* Return true if the page at s has protections appropriate */
+/* for a stack page. */
+static GC_bool may_be_in_stack(ptr_t s)
+{
+ GC_ASSERT(I_HOLD_LOCK());
+ if (s != last_address) {
+ VirtualQuery(s, &last_info, sizeof(last_info));
+ last_address = s;
+ }
+ return (last_info.Protect & PAGE_READWRITE)
+ && !(last_info.Protect & PAGE_GUARD);
+}
+
+STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
+{
ptr_t sp, stack_min;
- GC_thread thread;
- LONG my_max = GC_get_max_thread_index();
-
- for (i = 0; i <= my_max; i++) {
- thread = thread_table + i;
- if (thread -> in_use && thread -> stack_base) {
- if (thread -> id == thread_id) {
- sp = (ptr_t) &dummy;
- found_me = TRUE;
+
+ struct GC_traced_stack_sect_s *traced_stack_sect =
+ thread -> traced_stack_sect;
+ if (thread -> id == me) {
+ GC_ASSERT(thread -> thread_blocked_sp == NULL);
+ sp = GC_approx_sp();
+ } else if ((sp = thread -> thread_blocked_sp) == NULL) {
+ /* Use saved sp value for blocked threads. */
+ /* For unblocked threads call GetThreadContext(). */
+ CONTEXT context;
+ context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
+ if (!GetThreadContext(THREAD_HANDLE(thread), &context))
+ ABORT("GetThreadContext failed");
+
+ /* Push all registers that might point into the heap. Frame */
+ /* pointer registers are included in case client code was */
+ /* compiled with the 'omit frame pointer' optimisation. */
+# define PUSH1(reg) GC_push_one((word)context.reg)
+# define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2)
+# define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4)
+# if defined(I386)
+ PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
+ sp = (ptr_t)context.Esp;
+# elif defined(X86_64)
+ PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
+ PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
+ sp = (ptr_t)context.Rsp;
+# elif defined(ARM32)
+ PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11);
+ PUSH1(R12);
+ sp = (ptr_t)context.Sp;
+# elif defined(SHx)
+ PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
+ PUSH2(R12,R13), PUSH1(R14);
+ sp = (ptr_t)context.R15;
+# elif defined(MIPS)
+ PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
+ PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
+ PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
+ PUSH4(IntT9,IntK0,IntK1,IntS8);
+ sp = (ptr_t)context.IntSp;
+# elif defined(PPC)
+ PUSH4(Gpr0, Gpr3, Gpr4, Gpr5), PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
+ PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
+ PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
+ PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
+ sp = (ptr_t)context.Gpr1;
+# elif defined(ALPHA)
+ PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
+ PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
+ PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
+ PUSH4(IntT10,IntT11,IntT12,IntAt);
+ sp = (ptr_t)context.IntSp;
+# else
+# error "architecture is not supported"
+# endif
+ } /* ! current thread */
+
+ /* Set stack_min to the lowest address in the thread stack, */
+ /* or to an address in the thread stack no larger than sp, */
+ /* taking advantage of the old value to avoid slow traversals */
+ /* of large stacks. */
+ if (thread -> last_stack_min == ADDR_LIMIT) {
+# ifdef MSWINCE
+ if (GC_dont_query_stack_min) {
+ stack_min = GC_wince_evaluate_stack_min(traced_stack_sect != NULL ?
+ (ptr_t)traced_stack_sect : thread -> stack_base);
+ /* Keep last_stack_min value unmodified. */
+ } else
+# endif
+ /* else */ {
+ stack_min = GC_get_stack_min(traced_stack_sect != NULL ?
+ (ptr_t)traced_stack_sect : thread -> stack_base);
+ UNPROTECT_THREAD(thread);
+ thread -> last_stack_min = stack_min;
+ }
+ } else {
+ /* First, adjust the latest known minimum stack address if we */
+ /* are inside GC_call_with_gc_active(). */
+ if (traced_stack_sect != NULL &&
+ (word)thread->last_stack_min > (word)traced_stack_sect) {
+ UNPROTECT_THREAD(thread);
+ thread -> last_stack_min = (ptr_t)traced_stack_sect;
+ }
+
+ if ((word)sp < (word)thread->stack_base
+ && (word)sp >= (word)thread->last_stack_min) {
+ stack_min = sp;
+ } else {
+ /* In the current thread it is always safe to use sp value. */
+ if (may_be_in_stack(thread -> id == me &&
+ (word)sp < (word)thread->last_stack_min ?
+ sp : thread -> last_stack_min)) {
+ stack_min = last_info.BaseAddress;
+ /* Do not probe rest of the stack if sp is correct. */
+ if ((word)sp < (word)stack_min
+ || (word)sp >= (word)thread->stack_base)
+ stack_min = GC_get_stack_min(thread -> last_stack_min);
} else {
- CONTEXT context;
- context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
- if (!GetThreadContext(thread_table[i].handle, &context))
- ABORT("GetThreadContext failed");
-
- /* Push all registers that might point into the heap. Frame */
- /* pointer registers are included in case client code was */
- /* compiled with the 'omit frame pointer' optimisation. */
-# define PUSH1(reg) GC_push_one((word)context.reg)
-# define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2)
-# define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4)
-# if defined(I386)
- PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
- sp = (ptr_t)context.Esp;
-# elif defined(ARM32)
- PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12);
- sp = (ptr_t)context.Sp;
-# elif defined(SHx)
- PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
- PUSH2(R12,R13), PUSH1(R14);
- sp = (ptr_t)context.R15;
-# elif defined(MIPS)
- PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
- PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
- PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
- PUSH4(IntT9,IntK0,IntK1,IntS8);
- sp = (ptr_t)context.IntSp;
-# elif defined(PPC)
- PUSH4(Gpr0, Gpr3, Gpr4, Gpr5), PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
- PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
- PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
- PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
- sp = (ptr_t)context.Gpr1;
-# elif defined(ALPHA)
- PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
- PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
- PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
- PUSH4(IntT10,IntT11,IntT12,IntAt);
- sp = (ptr_t)context.IntSp;
-# else
-# error "architecture is not supported"
-# endif
+ /* Stack shrunk? Is this possible? */
+ stack_min = GC_get_stack_min(thread -> stack_base);
}
+ UNPROTECT_THREAD(thread);
+ thread -> last_stack_min = stack_min;
+ }
+ }
- stack_min = GC_get_stack_min(thread->stack_base);
+ GC_ASSERT(GC_dont_query_stack_min
+ || stack_min == GC_get_stack_min(thread -> stack_base)
+ || ((word)sp >= (word)stack_min
+ && (word)stack_min < (word)thread->stack_base
+ && (word)stack_min
+ > (word)GC_get_stack_min(thread -> stack_base)));
+
+ if ((word)sp >= (word)stack_min && (word)sp < (word)thread->stack_base) {
+# ifdef DEBUG_THREADS
+ GC_log_printf("Pushing stack for 0x%x from sp %p to %p from 0x%x\n",
+ (int)thread -> id, sp, thread -> stack_base, (int)me);
+# endif
+ GC_push_all_stack_sections(sp, thread->stack_base, traced_stack_sect);
+ } else {
+ /* If not current thread then it is possible for sp to point to */
+ /* the guarded (untouched yet) page just below the current */
+ /* stack_min of the thread. */
+ if (thread -> id == me || (word)sp >= (word)thread->stack_base
+ || (word)(sp + GC_page_size) < (word)stack_min)
+ WARN("Thread stack pointer %p out of range, pushing everything\n",
+ sp);
+# ifdef DEBUG_THREADS
+ GC_log_printf("Pushing stack for 0x%x from (min) %p to %p from 0x%x\n",
+ (int)thread->id, stack_min, thread->stack_base, (int)me);
+# endif
+ /* Push everything - ignore "traced stack section" data. */
+ GC_push_all_stack(stack_min, thread->stack_base);
+ }
+ return thread->stack_base - sp; /* stack grows down */
+}
+
+GC_INNER void GC_push_all_stacks(void)
+{
+ DWORD thread_id = GetCurrentThreadId();
+ GC_bool found_me = FALSE;
+# ifndef SMALL_CONFIG
+ unsigned nthreads = 0;
+# endif
+ word total_size = 0;
+# ifndef GC_NO_THREADS_DISCOVERY
+ if (GC_win32_dll_threads) {
+ int i;
+ LONG my_max = GC_get_max_thread_index();
- if (sp >= stack_min && sp < thread->stack_base)
- GC_push_all_stack(sp, thread->stack_base);
- else {
- WARN("Thread stack pointer 0x%lx out of range, pushing everything\n",
- (unsigned long)sp);
- GC_push_all_stack(stack_min, thread->stack_base);
+ for (i = 0; i <= my_max; i++) {
+ GC_thread t = (GC_thread)(dll_thread_table + i);
+ if (t -> tm.in_use && t -> stack_base) {
+# ifndef SMALL_CONFIG
+ ++nthreads;
+# endif
+ total_size += GC_push_stack_for(t, thread_id);
+ if (t -> id == thread_id) found_me = TRUE;
+ }
+ }
+ } else
+# endif
+ /* else */ {
+ int i;
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ GC_thread t;
+ for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
+ if (!KNOWN_FINISHED(t) && t -> stack_base) {
+# ifndef SMALL_CONFIG
+ ++nthreads;
+# endif
+ total_size += GC_push_stack_for(t, thread_id);
+ if (t -> id == thread_id) found_me = TRUE;
+ }
}
}
}
- if (!found_me) ABORT("Collecting from unknown thread.");
+# ifndef SMALL_CONFIG
+ GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks%s\n", nthreads,
+ GC_win32_dll_threads ?
+ " based on DllMain thread tracking" : "");
+# endif
+ if (!found_me && !GC_in_thread_creation)
+ ABORT("Collecting from unknown thread");
+ GC_total_stacksize = total_size;
}
-void GC_get_next_stack(char *start, char **lo, char **hi)
+#ifdef PARALLEL_MARK
+
+# ifndef MAX_MARKERS
+# define MAX_MARKERS 16
+# endif
+
+ static ptr_t marker_sp[MAX_MARKERS - 1]; /* The cold end of the stack */
+ /* for markers. */
+# ifdef IA64
+ static ptr_t marker_bsp[MAX_MARKERS - 1];
+# endif
+
+ static ptr_t marker_last_stack_min[MAX_MARKERS - 1];
+ /* Last known minimum (hottest) address */
+ /* in stack (or ADDR_LIMIT if unset) */
+ /* for markers. */
+
+#endif /* PARALLEL_MARK */
+
+/* Find stack with the lowest address which overlaps the */
+/* interval [start, limit). */
+/* Return stack bounds in *lo and *hi. If no such stack */
+/* is found, both *hi and *lo will be set to an address */
+/* higher than limit. */
+GC_INNER void GC_get_next_stack(char *start, char *limit,
+ char **lo, char **hi)
{
- int i;
-# define ADDR_LIMIT (char *)(-1L)
- char * current_min = ADDR_LIMIT;
+ int i;
+ char * current_min = ADDR_LIMIT; /* Least in-range stack base */
+ ptr_t *plast_stack_min = NULL; /* Address of last_stack_min */
+ /* field for thread corresponding */
+ /* to current_min. */
+ GC_thread thread = NULL; /* Either NULL or points to the */
+ /* thread's hash table entry */
+ /* containing *plast_stack_min. */
+
+ /* First set current_min, ignoring limit. */
+ if (GC_win32_dll_threads) {
LONG my_max = GC_get_max_thread_index();
-
+
for (i = 0; i <= my_max; i++) {
- char * s = (char *)thread_table[i].stack_base;
+ ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
- if (0 != s && s > start && s < current_min) {
- current_min = s;
- }
+ if ((word)s > (word)start && (word)s < (word)current_min) {
+ /* Update address of last_stack_min. */
+ plast_stack_min = (ptr_t * /* no volatile */)
+ &dll_thread_table[i].last_stack_min;
+ current_min = s;
+ }
}
- *hi = current_min;
- if (current_min == ADDR_LIMIT) {
- *lo = ADDR_LIMIT;
- return;
+ } else {
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ GC_thread t;
+
+ for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
+ ptr_t s = t -> stack_base;
+
+ if ((word)s > (word)start && (word)s < (word)current_min) {
+ /* Update address of last_stack_min. */
+ plast_stack_min = &t -> last_stack_min;
+ thread = t; /* Remember current thread to unprotect. */
+ current_min = s;
+ }
+ }
}
+# ifdef PARALLEL_MARK
+ for (i = 0; i < GC_markers_m1; ++i) {
+ ptr_t s = marker_sp[i];
+# ifdef IA64
+ /* FIXME: not implemented */
+# endif
+ if ((word)s > (word)start && (word)s < (word)current_min) {
+ GC_ASSERT(marker_last_stack_min[i] != NULL);
+ plast_stack_min = &marker_last_stack_min[i];
+ current_min = s;
+ thread = NULL; /* Not a thread's hash table entry. */
+ }
+ }
+# endif
+ }
+
+ *hi = current_min;
+ if (current_min == ADDR_LIMIT) {
+ *lo = ADDR_LIMIT;
+ return;
+ }
+
+ GC_ASSERT((word)current_min > (word)start && plast_stack_min != NULL);
+# ifdef MSWINCE
+ if (GC_dont_query_stack_min) {
+ *lo = GC_wince_evaluate_stack_min(current_min);
+ /* Keep last_stack_min value unmodified. */
+ return;
+ }
+# endif
+
+ if ((word)current_min > (word)limit && !may_be_in_stack(limit)) {
+ /* Skip the rest since the memory region at limit address is */
+ /* not a stack (so the lowest address of the found stack would */
+ /* be above the limit value anyway). */
+ *lo = ADDR_LIMIT;
+ return;
+ }
+
+ /* Get the minimum address of the found stack by probing its memory */
+ /* region starting from the recent known minimum (if set). */
+ if (*plast_stack_min == ADDR_LIMIT
+ || !may_be_in_stack(*plast_stack_min)) {
+ /* Unsafe to start from last_stack_min value. */
*lo = GC_get_stack_min(current_min);
- if (*lo < start) *lo = start;
+ } else {
+ /* Use the recent value to optimize search for min address. */
+ *lo = GC_get_stack_min(*plast_stack_min);
+ }
+
+ /* Remember current stack_min value. */
+ if (thread != NULL) {
+ UNPROTECT_THREAD(thread);
+ }
+ *plast_stack_min = *lo;
}
-#if !defined(CYGWIN32)
+#ifdef PARALLEL_MARK
-#if !defined(MSWINCE) && defined(GC_DLL)
+# if defined(GC_PTHREADS) && !defined(GC_PTHREADS_PARAMARK)
+ /* Use pthread-based parallel mark implementation. */
+# define GC_PTHREADS_PARAMARK
+# endif
-/* We register threads from DllMain */
+# if !defined(GC_PTHREADS_PARAMARK) && defined(DONT_USE_SIGNALANDWAIT)
+ STATIC HANDLE GC_marker_cv[MAX_MARKERS - 1] = {0};
+ /* Events with manual reset (one for each */
+ /* mark helper). */
-GC_API HANDLE WINAPI GC_CreateThread(
- LPSECURITY_ATTRIBUTES lpThreadAttributes,
- DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
- LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
-{
- return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
- lpParameter, dwCreationFlags, lpThreadId);
-}
+ STATIC DWORD GC_marker_Id[MAX_MARKERS - 1] = {0};
+ /* This table is used for mapping helper */
+ /* threads ID to mark helper index (linear */
+ /* search is used since the mapping contains */
+ /* only a few entries). */
+# endif
-#else /* defined(MSWINCE) || !defined(GC_DLL)) */
+ /* GC_mark_thread() is the same as in pthread_support.c */
+# ifdef GC_PTHREADS_PARAMARK
+ STATIC void * GC_mark_thread(void * id)
+# else
+# ifdef MSWINCE
+ STATIC DWORD WINAPI GC_mark_thread(LPVOID id)
+# else
+ STATIC unsigned __stdcall GC_mark_thread(void * id)
+# endif
+# endif
+ {
+ word my_mark_no = 0;
-/* We have no DllMain to take care of new threads. Thus we */
-/* must properly intercept thread creation. */
+ if ((word)id == (word)-1) return 0; /* to make compiler happy */
+ marker_sp[(word)id] = GC_approx_sp();
+# ifdef IA64
+ marker_bsp[(word)id] = GC_save_regs_in_stack();
+# endif
+# if !defined(GC_PTHREADS_PARAMARK) && defined(DONT_USE_SIGNALANDWAIT)
+ GC_marker_Id[(word)id] = GetCurrentThreadId();
+# endif
+
+ for (;; ++my_mark_no) {
+ if (my_mark_no - GC_mark_no > (word)2) {
+ /* resynchronize if we get far off, e.g. because GC_mark_no */
+ /* wrapped. */
+ my_mark_no = GC_mark_no;
+ }
+# ifdef DEBUG_THREADS
+ GC_log_printf("Starting mark helper for mark number %lu\n",
+ (unsigned long)my_mark_no);
+# endif
+ GC_help_marker(my_mark_no);
+ }
+ }
+
+# ifdef GC_ASSERTIONS
+ GC_INNER unsigned long GC_mark_lock_holder = NO_THREAD;
+# endif
+
+ /* GC_mark_threads[] is unused here unlike that in pthread_support.c */
+
+# ifndef CAN_HANDLE_FORK
+# define available_markers_m1 GC_markers_m1
+# endif
+
+# ifdef GC_PTHREADS_PARAMARK
+# include <pthread.h>
+
+# ifndef NUMERIC_THREAD_ID
+# define NUMERIC_THREAD_ID(id) (unsigned long)GC_PTHREAD_PTRVAL(id)
+# endif
+
+ /* start_mark_threads is the same as in pthread_support.c except */
+ /* for thread stack that is assumed to be large enough. */
+# ifdef CAN_HANDLE_FORK
+ static int available_markers_m1 = 0;
+# define start_mark_threads GC_start_mark_threads
+ GC_API void GC_CALL
+# else
+ static void
+# endif
+ start_mark_threads(void)
+ {
+ int i;
+ pthread_attr_t attr;
+ pthread_t new_thread;
+
+ GC_ASSERT(I_DONT_HOLD_LOCK());
+# ifdef CAN_HANDLE_FORK
+ if (available_markers_m1 <= 0 || GC_parallel) return;
+ /* Skip if parallel markers disabled or already started. */
+# endif
-typedef struct {
+ if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
+ if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
+ ABORT("pthread_attr_setdetachstate failed");
+
+ for (i = 0; i < available_markers_m1; ++i) {
+ marker_last_stack_min[i] = ADDR_LIMIT;
+ if (0 != pthread_create(&new_thread, &attr,
+ GC_mark_thread, (void *)(word)i)) {
+ WARN("Marker thread creation failed.\n", 0);
+ /* Don't try to create other marker threads. */
+ break;
+ }
+ }
+ GC_markers_m1 = i;
+ pthread_attr_destroy(&attr);
+ GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
+ }
+
+ static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+ static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
+
+ /* GC_acquire/release_mark_lock(), GC_wait_builder/marker(), */
+ /* GC_wait_for_reclaim(), GC_notify_all_builder/marker() are the same */
+ /* as in pthread_support.c except that GC_generic_lock() is not used. */
+
+# ifdef LOCK_STATS
+ volatile AO_t GC_block_count = 0;
+# endif
+
+ GC_INNER void GC_acquire_mark_lock(void)
+ {
+ if (pthread_mutex_lock(&mark_mutex) != 0) {
+ ABORT("pthread_mutex_lock failed");
+ }
+# ifdef LOCK_STATS
+ (void)AO_fetch_and_add1(&GC_block_count);
+# endif
+ /* GC_generic_lock(&mark_mutex); */
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
+# endif
+ }
+
+ GC_INNER void GC_release_mark_lock(void)
+ {
+ GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NO_THREAD;
+# endif
+ if (pthread_mutex_unlock(&mark_mutex) != 0) {
+ ABORT("pthread_mutex_unlock failed");
+ }
+ }
+
+ /* Collector must wait for a freelist builders for 2 reasons: */
+ /* 1) Mark bits may still be getting examined without lock. */
+ /* 2) Partial free lists referenced only by locals may not be */
+ /* scanned correctly, e.g. if they contain "pointer-free" objects, */
+ /* since the free-list link may be ignored. */
+ STATIC void GC_wait_builder(void)
+ {
+ GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NO_THREAD;
+# endif
+ if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
+ ABORT("pthread_cond_wait failed");
+ }
+ GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
+# endif
+ }
+
+ GC_INNER void GC_wait_for_reclaim(void)
+ {
+ GC_acquire_mark_lock();
+ while (GC_fl_builder_count > 0) {
+ GC_wait_builder();
+ }
+ GC_release_mark_lock();
+ }
+
+ GC_INNER void GC_notify_all_builder(void)
+ {
+ GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
+ if (pthread_cond_broadcast(&builder_cv) != 0) {
+ ABORT("pthread_cond_broadcast failed");
+ }
+ }
+
+ static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
+
+ GC_INNER void GC_wait_marker(void)
+ {
+ GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NO_THREAD;
+# endif
+ if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
+ ABORT("pthread_cond_wait failed");
+ }
+ GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
+# endif
+ }
+
+ GC_INNER void GC_notify_all_marker(void)
+ {
+ if (pthread_cond_broadcast(&mark_cv) != 0) {
+ ABORT("pthread_cond_broadcast failed");
+ }
+ }
+
+# else /* ! GC_PTHREADS_PARAMARK */
+
+# ifndef MARK_THREAD_STACK_SIZE
+# define MARK_THREAD_STACK_SIZE 0 /* default value */
+# endif
+
+ /* mark_mutex_event, builder_cv, mark_cv are initialized in GC_thr_init */
+ static HANDLE mark_mutex_event = (HANDLE)0; /* Event with auto-reset. */
+ static HANDLE builder_cv = (HANDLE)0; /* Event with manual reset. */
+ static HANDLE mark_cv = (HANDLE)0; /* Event with manual reset. */
+
+ static void start_mark_threads(void)
+ {
+ int i;
+# ifdef MSWINCE
+ HANDLE handle;
+ DWORD thread_id;
+# else
+ GC_uintptr_t handle;
+ unsigned thread_id;
+# endif
+
+# ifdef DONT_USE_SIGNALANDWAIT
+ /* Initialize GC_marker_cv[] fully before starting the */
+ /* first helper thread. */
+ for (i = 0; i < GC_markers_m1; ++i) {
+ if ((GC_marker_cv[i] = CreateEvent(NULL /* attrs */,
+ TRUE /* isManualReset */,
+ FALSE /* initialState */,
+ NULL /* name (A/W) */)) == (HANDLE)0)
+ ABORT("CreateEvent failed");
+ }
+# endif
+
+ for (i = 0; i < GC_markers_m1; ++i) {
+ marker_last_stack_min[i] = ADDR_LIMIT;
+# ifdef MSWINCE
+ /* There is no _beginthreadex() in WinCE. */
+ handle = CreateThread(NULL /* lpsa */,
+ MARK_THREAD_STACK_SIZE /* ignored */,
+ GC_mark_thread, (LPVOID)(word)i,
+ 0 /* fdwCreate */, &thread_id);
+ if (handle == NULL) {
+ WARN("Marker thread creation failed\n", 0);
+ /* The most probable failure reason is "not enough memory". */
+ /* Don't try to create other marker threads. */
+ break;
+ } else {
+ /* It's safe to detach the thread. */
+ CloseHandle(handle);
+ }
+# else
+ handle = _beginthreadex(NULL /* security_attr */,
+ MARK_THREAD_STACK_SIZE, GC_mark_thread,
+ (void *)(word)i, 0 /* flags */, &thread_id);
+ if (!handle || handle == (GC_uintptr_t)-1L) {
+ WARN("Marker thread creation failed\n", 0);
+ /* Don't try to create other marker threads. */
+ break;
+ } else {/* We may detach the thread (if handle is of HANDLE type) */
+ /* CloseHandle((HANDLE)handle); */
+ }
+# endif
+ }
+
+ /* Adjust GC_markers_m1 (and free unused resources) if failed. */
+# ifdef DONT_USE_SIGNALANDWAIT
+ while (GC_markers_m1 > i) {
+ GC_markers_m1--;
+ CloseHandle(GC_marker_cv[GC_markers_m1]);
+ }
+# else
+ GC_markers_m1 = i;
+# endif
+ GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
+ if (i == 0) {
+ CloseHandle(mark_cv);
+ CloseHandle(builder_cv);
+ CloseHandle(mark_mutex_event);
+ }
+ }
+
+# ifdef DONT_USE_SIGNALANDWAIT
+ STATIC /* volatile */ LONG GC_mark_mutex_state = 0;
+ /* Mutex state: 0 - unlocked, */
+ /* 1 - locked and no other waiters, */
+ /* -1 - locked and waiters may exist. */
+ /* Accessed by InterlockedExchange(). */
+# else
+ STATIC volatile AO_t GC_mark_mutex_waitcnt = 0;
+ /* Number of waiters + 1; 0 - unlocked. */
+# endif
+
+ /* #define LOCK_STATS */
+# ifdef LOCK_STATS
+ volatile AO_t GC_block_count = 0;
+ volatile AO_t GC_unlocked_count = 0;
+# endif
+
+ GC_INNER void GC_acquire_mark_lock(void)
+ {
+# ifdef DONT_USE_SIGNALANDWAIT
+ if (InterlockedExchange(&GC_mark_mutex_state, 1 /* locked */) != 0)
+# else
+ if (AO_fetch_and_add1_acquire(&GC_mark_mutex_waitcnt) != 0)
+# endif
+ {
+# ifdef LOCK_STATS
+ (void)AO_fetch_and_add1(&GC_block_count);
+# endif
+# ifdef DONT_USE_SIGNALANDWAIT
+ /* Repeatedly reset the state and wait until acquire the lock. */
+ while (InterlockedExchange(&GC_mark_mutex_state,
+ -1 /* locked_and_has_waiters */) != 0)
+# endif
+ {
+ if (WaitForSingleObject(mark_mutex_event, INFINITE) == WAIT_FAILED)
+ ABORT("WaitForSingleObject failed");
+ }
+ }
+# ifdef LOCK_STATS
+ else {
+ (void)AO_fetch_and_add1(&GC_unlocked_count);
+ }
+# endif
+
+ GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = (unsigned long)GetCurrentThreadId();
+# endif
+ }
+
+ GC_INNER void GC_release_mark_lock(void)
+ {
+ GC_ASSERT(GC_mark_lock_holder == (unsigned long)GetCurrentThreadId());
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NO_THREAD;
+# endif
+# ifdef DONT_USE_SIGNALANDWAIT
+ if (InterlockedExchange(&GC_mark_mutex_state, 0 /* unlocked */) < 0)
+# else
+ GC_ASSERT(AO_load(&GC_mark_mutex_waitcnt) != 0);
+ if (AO_fetch_and_sub1_release(&GC_mark_mutex_waitcnt) > 1)
+# endif
+ {
+ /* wake a waiter */
+ if (SetEvent(mark_mutex_event) == FALSE)
+ ABORT("SetEvent failed");
+ }
+ }
+
+ /* In GC_wait_for_reclaim/GC_notify_all_builder() we emulate POSIX */
+ /* cond_wait/cond_broadcast() primitives with WinAPI Event object */
+ /* (working in "manual reset" mode). This works here because */
+ /* GC_notify_all_builder() is always called holding lock on */
+ /* mark_mutex and the checked condition (GC_fl_builder_count == 0) */
+ /* is the only one for which broadcasting on builder_cv is performed. */
+
+ GC_INNER void GC_wait_for_reclaim(void)
+ {
+ GC_ASSERT(builder_cv != 0);
+ for (;;) {
+ GC_acquire_mark_lock();
+ if (GC_fl_builder_count == 0)
+ break;
+ if (ResetEvent(builder_cv) == FALSE)
+ ABORT("ResetEvent failed");
+ GC_release_mark_lock();
+ if (WaitForSingleObject(builder_cv, INFINITE) == WAIT_FAILED)
+ ABORT("WaitForSingleObject failed");
+ }
+ GC_release_mark_lock();
+ }
+
+ GC_INNER void GC_notify_all_builder(void)
+ {
+ GC_ASSERT(GC_mark_lock_holder == (unsigned long)GetCurrentThreadId());
+ GC_ASSERT(builder_cv != 0);
+ GC_ASSERT(GC_fl_builder_count == 0);
+ if (SetEvent(builder_cv) == FALSE)
+ ABORT("SetEvent failed");
+ }
+
+# ifdef DONT_USE_SIGNALANDWAIT
+
+ /* mark_cv is used (for waiting) by a non-helper thread. */
+
+ GC_INNER void GC_wait_marker(void)
+ {
+ HANDLE event = mark_cv;
+ DWORD thread_id = GetCurrentThreadId();
+ int i = GC_markers_m1;
+
+ while (i-- > 0) {
+ if (GC_marker_Id[i] == thread_id) {
+ event = GC_marker_cv[i];
+ break;
+ }
+ }
+
+ if (ResetEvent(event) == FALSE)
+ ABORT("ResetEvent failed");
+ GC_release_mark_lock();
+ if (WaitForSingleObject(event, INFINITE) == WAIT_FAILED)
+ ABORT("WaitForSingleObject failed");
+ GC_acquire_mark_lock();
+ }
+
+ GC_INNER void GC_notify_all_marker(void)
+ {
+ DWORD thread_id = GetCurrentThreadId();
+ int i = GC_markers_m1;
+
+ while (i-- > 0) {
+ /* Notify every marker ignoring self (for efficiency). */
+ if (SetEvent(GC_marker_Id[i] != thread_id ? GC_marker_cv[i] :
+ mark_cv) == FALSE)
+ ABORT("SetEvent failed");
+ }
+ }
+
+# else /* DONT_USE_SIGNALANDWAIT */
+
+ /* For GC_wait_marker/GC_notify_all_marker() the above technique */
+ /* does not work because they are used with different checked */
+ /* conditions in different places (and, in addition, notifying is */
+ /* done after leaving critical section) and this could result in */
+ /* a signal loosing between checking for a particular condition */
+ /* and calling WaitForSingleObject. So, we use PulseEvent() and */
+ /* NT SignalObjectAndWait() (which atomically sets mutex event to */
+ /* signaled state and starts waiting on condvar). A special */
+ /* case here is GC_mark_mutex_waitcnt == 1 (i.e. nobody waits for */
+ /* mark lock at this moment) - we don't change it (otherwise we */
+ /* may loose a signal sent between decrementing */
+ /* GC_mark_mutex_waitcnt and calling WaitForSingleObject()). */
+
+# ifdef MSWINCE
+ /* SignalObjectAndWait() is missing in WinCE (for now), so you */
+ /* should supply its emulation (externally) to use this code. */
+ WINBASEAPI DWORD WINAPI SignalObjectAndWait(HANDLE, HANDLE, DWORD,
+ BOOL);
+# define signalObjectAndWait_func SignalObjectAndWait
+# else
+ typedef DWORD (WINAPI * SignalObjectAndWait_type)(HANDLE, HANDLE,
+ DWORD, BOOL);
+ static SignalObjectAndWait_type signalObjectAndWait_func = 0;
+# endif
+
+ GC_INNER void GC_wait_marker(void)
+ {
+ /* Here we assume that GC_wait_marker() is always called */
+ /* from a while(check_cond) loop. */
+ AO_t waitcnt;
+ GC_ASSERT(mark_cv != 0);
+
+ /* We inline GC_release_mark_lock() to have atomic */
+ /* unlock-and-wait action here. */
+ GC_ASSERT(GC_mark_lock_holder == (unsigned long)GetCurrentThreadId());
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = NO_THREAD;
+# endif
+
+ if ((waitcnt = AO_load(&GC_mark_mutex_waitcnt)) > 1) {
+ (void)AO_fetch_and_sub1_release(&GC_mark_mutex_waitcnt);
+ } else {
+ GC_ASSERT(AO_load(&GC_mark_mutex_waitcnt) != 0);
+ }
+
+ /* The state of mark_cv is non-signaled here. */
+ if (signalObjectAndWait_func(mark_mutex_event /* hObjectToSignal */,
+ mark_cv /* hObjectToWaitOn */,
+ INFINITE /* timeout */,
+ FALSE /* isAlertable */) == WAIT_FAILED)
+ ABORT("SignalObjectAndWait failed");
+ /* The state of mark_cv is non-signaled here again. */
+
+ if (waitcnt > 1) {
+ GC_acquire_mark_lock();
+ } else {
+ GC_ASSERT(GC_mark_mutex_waitcnt != 0);
+ /* Acquire mark lock */
+ if (WaitForSingleObject(mark_mutex_event, INFINITE) == WAIT_FAILED)
+ ABORT("WaitForSingleObject failed");
+ GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
+# ifdef GC_ASSERTIONS
+ GC_mark_lock_holder = (unsigned long)GetCurrentThreadId();
+# endif
+ }
+ }
+
+ GC_INNER void GC_notify_all_marker(void)
+ {
+ GC_ASSERT(mark_cv != 0);
+ if (PulseEvent(mark_cv) == FALSE)
+ ABORT("PulseEvent failed");
+ }
+
+# endif /* !DONT_USE_SIGNALANDWAIT */
+
+# endif /* ! GC_PTHREADS_PARAMARK */
+
+#endif /* PARALLEL_MARK */
+
+ /* We have no DllMain to take care of new threads. Thus we */
+ /* must properly intercept thread creation. */
+
+ typedef struct {
LPTHREAD_START_ROUTINE start;
LPVOID param;
-} thread_args;
+ } thread_args;
-static DWORD WINAPI thread_start(LPVOID arg);
+ STATIC void * GC_CALLBACK GC_win32_start_inner(struct GC_stack_base *sb,
+ void *arg)
+ {
+ void * ret;
+ LPTHREAD_START_ROUTINE start = ((thread_args *)arg)->start;
+ LPVOID param = ((thread_args *)arg)->param;
-GC_API HANDLE WINAPI GC_CreateThread(
- LPSECURITY_ATTRIBUTES lpThreadAttributes,
- DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
- LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
-{
- HANDLE thread_h = NULL;
+ GC_register_my_thread(sb); /* This waits for an in-progress GC. */
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread 0x%lx starting...\n", (long)GetCurrentThreadId());
+# endif
+
+ GC_free(arg);
+
+ /* Clear the thread entry even if we exit with an exception. */
+ /* This is probably pointless, since an uncaught exception is */
+ /* supposed to result in the process being killed. */
+# ifndef __GNUC__
+ __try
+# endif
+ {
+ ret = (void *)(word)(*start)(param);
+ }
+# ifndef __GNUC__
+ __finally
+# endif
+ {
+ GC_unregister_my_thread();
+ }
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread 0x%lx returned from start routine\n",
+ (long)GetCurrentThreadId());
+# endif
+ return ret;
+ }
+
+ STATIC DWORD WINAPI GC_win32_start(LPVOID arg)
+ {
+ return (DWORD)(word)GC_call_with_stack_base(GC_win32_start_inner, arg);
+ }
+ GC_API HANDLE WINAPI GC_CreateThread(
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ GC_WIN32_SIZE_T dwStackSize,
+ LPTHREAD_START_ROUTINE lpStartAddress,
+ LPVOID lpParameter, DWORD dwCreationFlags,
+ LPDWORD lpThreadId)
+ {
+ HANDLE thread_h;
thread_args *args;
- if (!GC_is_initialized) GC_init();
- /* make sure GC is initialized (i.e. main thread is attached) */
-
- args = GC_malloc_uncollectable(sizeof(thread_args));
- /* Handed off to and deallocated by child thread. */
- if (0 == args) {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ if (!EXPECT(parallel_initialized, TRUE))
+ GC_init_parallel();
+ /* make sure GC is initialized (i.e. main thread is */
+ /* attached, tls initialized). */
+
+# ifdef DEBUG_THREADS
+ GC_log_printf("About to create a thread from 0x%lx\n",
+ (long)GetCurrentThreadId());
+# endif
+ if (GC_win32_dll_threads) {
+ return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
+ lpParameter, dwCreationFlags, lpThreadId);
+ } else {
+ args = GC_malloc_uncollectable(sizeof(thread_args));
+ /* Handed off to and deallocated by child thread. */
+ if (0 == args) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
+ }
+
+ /* set up thread arguments */
+ args -> start = lpStartAddress;
+ args -> param = lpParameter;
+
+ GC_need_to_lock = TRUE;
+ thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start,
+ args, dwCreationFlags, lpThreadId);
+ if (thread_h == 0) GC_free(args);
+ return thread_h;
}
+ }
- /* set up thread arguments */
- args -> start = lpStartAddress;
- args -> param = lpParameter;
+ GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(DWORD dwExitCode)
+ {
+ GC_unregister_my_thread();
+ ExitThread(dwExitCode);
+ }
- thread_h = CreateThread(lpThreadAttributes,
- dwStackSize, thread_start,
- args, dwCreationFlags,
- lpThreadId);
+# if !defined(MSWINCE) && !defined(CYGWIN32)
- return thread_h;
-}
+ GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
+ void *security, unsigned stack_size,
+ unsigned (__stdcall *start_address)(void *),
+ void *arglist, unsigned initflag,
+ unsigned *thrdaddr)
+ {
+ GC_uintptr_t thread_h;
+ thread_args *args;
+
+ if (!EXPECT(parallel_initialized, TRUE))
+ GC_init_parallel();
+ /* make sure GC is initialized (i.e. main thread is */
+ /* attached, tls initialized). */
+# ifdef DEBUG_THREADS
+ GC_log_printf("About to create a thread from 0x%lx\n",
+ (long)GetCurrentThreadId());
+# endif
-static DWORD WINAPI thread_start(LPVOID arg)
-{
- DWORD ret = 0;
- thread_args *args = (thread_args *)arg;
-
- GC_new_thread();
-
- /* Clear the thread entry even if we exit with an exception. */
- /* This is probably pointless, since an uncaught exception is */
- /* supposed to result in the process being killed. */
-#ifndef __GNUC__
- __try {
-#endif /* __GNUC__ */
- ret = args->start (args->param);
-#ifndef __GNUC__
- } __finally {
-#endif /* __GNUC__ */
- GC_free(args);
- GC_delete_thread(GetCurrentThreadId());
-#ifndef __GNUC__
- }
-#endif /* __GNUC__ */
+ if (GC_win32_dll_threads) {
+ return _beginthreadex(security, stack_size, start_address,
+ arglist, initflag, thrdaddr);
+ } else {
+ args = GC_malloc_uncollectable(sizeof(thread_args));
+ /* Handed off to and deallocated by child thread. */
+ if (0 == args) {
+ /* MSDN docs say _beginthreadex() returns 0 on error and sets */
+ /* errno to either EAGAIN (too many threads) or EINVAL (the */
+ /* argument is invalid or the stack size is incorrect), so we */
+ /* set errno to EAGAIN on "not enough memory". */
+ errno = EAGAIN;
+ return 0;
+ }
+
+ /* set up thread arguments */
+ args -> start = (LPTHREAD_START_ROUTINE)start_address;
+ args -> param = arglist;
+
+ GC_need_to_lock = TRUE;
+ thread_h = _beginthreadex(security, stack_size,
+ (unsigned (__stdcall *)(void *))GC_win32_start,
+ args, initflag, thrdaddr);
+ if (thread_h == 0) GC_free(args);
+ return thread_h;
+ }
+ }
- return ret;
-}
-#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
+ GC_API void GC_CALL GC_endthreadex(unsigned retval)
+ {
+ GC_unregister_my_thread();
+ _endthreadex(retval);
+ }
-#endif /* !CYGWIN32 */
+# endif /* !MSWINCE && !CYGWIN32 */
-#ifdef MSWINCE
+#ifdef GC_WINMAIN_REDIRECT
+ /* This might be useful on WinCE. Shouldn't be used with GC_DLL. */
-typedef struct {
+# if defined(MSWINCE) && defined(UNDER_CE)
+# define WINMAIN_LPTSTR LPWSTR
+# else
+# define WINMAIN_LPTSTR LPSTR
+# endif
+
+ /* This is defined in gc.h. */
+# undef WinMain
+
+ /* Defined outside GC by an application. */
+ int WINAPI GC_WinMain(HINSTANCE, HINSTANCE, WINMAIN_LPTSTR, int);
+
+ typedef struct {
HINSTANCE hInstance;
HINSTANCE hPrevInstance;
- LPWSTR lpCmdLine;
+ WINMAIN_LPTSTR lpCmdLine;
int nShowCmd;
-} main_thread_args;
+ } main_thread_args;
-DWORD WINAPI main_thread_start(LPVOID arg);
+ static DWORD WINAPI main_thread_start(LPVOID arg)
+ {
+ main_thread_args * args = (main_thread_args *) arg;
+ return (DWORD)GC_WinMain(args->hInstance, args->hPrevInstance,
+ args->lpCmdLine, args->nShowCmd);
+ }
-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
- LPWSTR lpCmdLine, int nShowCmd)
-{
+ STATIC void * GC_waitForSingleObjectInfinite(void * handle)
+ {
+ return (void *)(word)WaitForSingleObject((HANDLE)handle, INFINITE);
+ }
+
+# ifndef WINMAIN_THREAD_STACK_SIZE
+# define WINMAIN_THREAD_STACK_SIZE 0 /* default value */
+# endif
+
+ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ WINMAIN_LPTSTR lpCmdLine, int nShowCmd)
+ {
DWORD exit_code = 1;
main_thread_args args = {
- hInstance, hPrevInstance, lpCmdLine, nShowCmd
+ hInstance, hPrevInstance, lpCmdLine, nShowCmd
};
HANDLE thread_h;
DWORD thread_id;
/* initialize everything */
- GC_init();
+ GC_INIT();
/* start the main thread */
- thread_h = GC_CreateThread(
- NULL, 0, main_thread_start, &args, 0, &thread_id);
-
- if (thread_h != NULL)
- {
- WaitForSingleObject (thread_h, INFINITE);
- GetExitCodeThread (thread_h, &exit_code);
- CloseHandle (thread_h);
+ thread_h = GC_CreateThread(NULL /* lpsa */,
+ WINMAIN_THREAD_STACK_SIZE /* ignored on WinCE */,
+ main_thread_start, &args, 0 /* fdwCreate */,
+ &thread_id);
+
+ if (thread_h != NULL) {
+ if ((DWORD)(word)GC_do_blocking(GC_waitForSingleObjectInfinite,
+ (void *)thread_h) == WAIT_FAILED)
+ ABORT("WaitForSingleObject(main_thread) failed");
+ GetExitCodeThread (thread_h, &exit_code);
+ CloseHandle (thread_h);
+ } else {
+ ABORT("GC_CreateThread(main_thread) failed");
}
- GC_deinit();
- DeleteCriticalSection(&GC_allocate_ml);
-
+# ifdef MSWINCE
+ GC_deinit();
+ DeleteCriticalSection(&GC_allocate_ml);
+# endif
return (int) exit_code;
-}
+ }
-DWORD WINAPI main_thread_start(LPVOID arg)
+#endif /* GC_WINMAIN_REDIRECT */
+
+/* Called by GC_init() - we hold the allocation lock. */
+GC_INNER void GC_thr_init(void)
{
- main_thread_args * args = (main_thread_args *) arg;
+ struct GC_stack_base sb;
+# ifdef GC_ASSERTIONS
+ int sb_result;
+# endif
- return (DWORD) GC_WinMain (args->hInstance, args->hPrevInstance,
- args->lpCmdLine, args->nShowCmd);
-}
+ GC_ASSERT(I_HOLD_LOCK());
+ if (GC_thr_initialized) return;
+
+ GC_ASSERT((word)&GC_threads % sizeof(word) == 0);
+ GC_main_thread = GetCurrentThreadId();
+ GC_thr_initialized = TRUE;
+
+# ifdef CAN_HANDLE_FORK
+ /* Prepare for forks if requested. */
+ if (GC_handle_fork) {
+# ifdef CAN_CALL_ATFORK
+ if (pthread_atfork(fork_prepare_proc, fork_parent_proc,
+ fork_child_proc) == 0) {
+ /* Handlers successfully registered. */
+ GC_handle_fork = 1;
+ } else
+# endif
+ /* else */ if (GC_handle_fork != -1)
+ ABORT("pthread_atfork failed");
+ }
+# endif
+
+ /* Add the initial thread, so we can stop it. */
+# ifdef GC_ASSERTIONS
+ sb_result =
+# endif
+ GC_get_stack_base(&sb);
+ GC_ASSERT(sb_result == GC_SUCCESS);
+
+# if defined(PARALLEL_MARK)
+ {
+ char * markers_string = GETENV("GC_MARKERS");
+ int markers_m1;
+
+ if (markers_string != NULL) {
+ markers_m1 = atoi(markers_string) - 1;
+ if (markers_m1 >= MAX_MARKERS) {
+ WARN("Limiting number of mark threads\n", 0);
+ markers_m1 = MAX_MARKERS - 1;
+ }
+ } else {
+# ifdef MSWINCE
+ /* There is no GetProcessAffinityMask() in WinCE. */
+ /* GC_sysinfo is already initialized. */
+ markers_m1 = (int)GC_sysinfo.dwNumberOfProcessors - 1;
+# else
+# ifdef _WIN64
+ DWORD_PTR procMask = 0;
+ DWORD_PTR sysMask;
+# else
+ DWORD procMask = 0;
+ DWORD sysMask;
+# endif
+ int ncpu = 0;
+ if (GetProcessAffinityMask(GetCurrentProcess(),
+ (void *)&procMask, (void *)&sysMask)
+ && procMask) {
+ do {
+ ncpu++;
+ } while ((procMask &= procMask - 1) != 0);
+ }
+ markers_m1 = ncpu - 1;
+# endif
+# ifdef GC_MIN_MARKERS
+ /* This is primarily for testing on systems without getenv(). */
+ if (markers_m1 < GC_MIN_MARKERS - 1)
+ markers_m1 = GC_MIN_MARKERS - 1;
+# endif
+ if (markers_m1 >= MAX_MARKERS)
+ markers_m1 = MAX_MARKERS - 1; /* silently limit the value */
+ }
+ available_markers_m1 = markers_m1;
+ }
-# else /* !MSWINCE */
+ /* Check whether parallel mode could be enabled. */
+ {
+# if !defined(GC_PTHREADS_PARAMARK) && !defined(MSWINCE) \
+ && !defined(DONT_USE_SIGNALANDWAIT)
+ HMODULE hK32;
+ /* SignalObjectAndWait() API call works only under NT. */
+# endif
+ if (GC_win32_dll_threads || available_markers_m1 <= 0
+# if !defined(GC_PTHREADS_PARAMARK) && !defined(MSWINCE) \
+ && !defined(DONT_USE_SIGNALANDWAIT)
+ || GC_wnt == FALSE
+ || (hK32 = GetModuleHandle(TEXT("kernel32.dll"))) == (HMODULE)0
+ || (signalObjectAndWait_func = (SignalObjectAndWait_type)
+ GetProcAddress(hK32, "SignalObjectAndWait")) == 0
+# endif
+ ) {
+ /* Disable parallel marking. */
+ GC_parallel = FALSE;
+ GC_COND_LOG_PRINTF(
+ "Single marker thread, turning off parallel marking\n");
+ } else {
+# ifndef GC_PTHREADS_PARAMARK
+ /* Initialize Win32 event objects for parallel marking. */
+ mark_mutex_event = CreateEvent(NULL /* attrs */,
+ FALSE /* isManualReset */,
+ FALSE /* initialState */, NULL /* name */);
+ builder_cv = CreateEvent(NULL /* attrs */,
+ TRUE /* isManualReset */,
+ FALSE /* initialState */, NULL /* name */);
+ mark_cv = CreateEvent(NULL /* attrs */, TRUE /* isManualReset */,
+ FALSE /* initialState */, NULL /* name */);
+ if (mark_mutex_event == (HANDLE)0 || builder_cv == (HANDLE)0
+ || mark_cv == (HANDLE)0)
+ ABORT("CreateEvent failed");
+# endif
+ /* Disable true incremental collection, but generational is OK. */
+ GC_time_limit = GC_TIME_UNLIMITED;
+ }
+ }
+# endif /* PARALLEL_MARK */
-/* Called by GC_init() - we hold the allocation lock. */
-void GC_thr_init() {
- if (GC_thr_initialized) return;
- GC_main_thread = GetCurrentThreadId();
- GC_thr_initialized = TRUE;
+ GC_ASSERT(0 == GC_lookup_thread_inner(GC_main_thread));
+ GC_register_my_thread_inner(&sb, GC_main_thread);
- /* Add the initial thread, so we can stop it. */
- GC_new_thread();
+# ifdef PARALLEL_MARK
+# ifndef CAN_HANDLE_FORK
+ if (GC_parallel)
+# endif
+ {
+ /* If we are using a parallel marker, actually start helper threads. */
+ start_mark_threads();
+ }
+# endif
}
-#ifdef CYGWIN32
+#ifdef GC_PTHREADS
-struct start_info {
+ struct start_info {
void *(*start_routine)(void *);
void *arg;
GC_bool detached;
-};
+ };
-int GC_pthread_join(pthread_t pthread_id, void **retval) {
+ GC_API int GC_pthread_join(pthread_t pthread_id, void **retval)
+ {
int result;
- int i;
- GC_thread me;
-
-# if DEBUG_CYGWIN_THREADS
- GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",
- (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
+ GC_thread t;
+ DCL_LOCK_STATE;
+
+ GC_ASSERT(!GC_win32_dll_threads);
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%lx) is joining thread %p\n",
+ GC_PTHREAD_PTRVAL(pthread_self()),
+ (long)GetCurrentThreadId(), GC_PTHREAD_PTRVAL(pthread_id));
# endif
/* Thread being joined might not have registered itself yet. */
- /* After the join,thread id may have been recycled. */
- /* FIXME: It would be better if this worked more like */
- /* pthread_support.c. */
-
- while ((me = GC_lookup_thread(pthread_id)) == 0) Sleep(10);
+ /* After the join,thread id may have been recycled. */
+ /* FIXME: It would be better if this worked more like */
+ /* pthread_support.c. */
+# ifndef GC_WIN32_PTHREADS
+ while ((t = GC_lookup_pthread(pthread_id)) == 0)
+ Sleep(10);
+# endif
result = pthread_join(pthread_id, retval);
- GC_delete_gc_thread(me);
-
-# if DEBUG_CYGWIN_THREADS
- GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
- (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
+# ifdef GC_WIN32_PTHREADS
+ /* win32_pthreads id are unique */
+ t = GC_lookup_pthread(pthread_id);
+ if (NULL == t) ABORT("Thread not registered");
# endif
+ LOCK();
+ GC_delete_gc_thread_no_free(t);
+ GC_INTERNAL_FREE(t);
+ UNLOCK();
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%lx) completed join with thread %p\n",
+ GC_PTHREAD_PTRVAL(pthread_self()),
+ (long)GetCurrentThreadId(), GC_PTHREAD_PTRVAL(pthread_id));
+# endif
return result;
-}
+ }
-/* Cygwin-pthreads calls CreateThread internally, but it's not
- * easily interceptible by us..
- * so intercept pthread_create instead
- */
-int
-GC_pthread_create(pthread_t *new_thread,
- const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg) {
+ /* Cygwin-pthreads calls CreateThread internally, but it's not easily */
+ /* interceptible by us..., so intercept pthread_create instead. */
+ GC_API int GC_pthread_create(pthread_t *new_thread,
+ GC_PTHREAD_CREATE_CONST pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg)
+ {
int result;
struct start_info * si;
- if (!GC_is_initialized) GC_init();
- /* make sure GC is initialized (i.e. main thread is attached) */
-
- /* This is otherwise saved only in an area mmapped by the thread */
- /* library, which isn't visible to the collector. */
- si = GC_malloc_uncollectable(sizeof(struct start_info));
- if (0 == si) return(EAGAIN);
-
- si -> start_routine = start_routine;
- si -> arg = arg;
- if (attr != 0 &&
- pthread_attr_getdetachstate(attr, &si->detached)
- == PTHREAD_CREATE_DETACHED) {
- si->detached = TRUE;
- }
-
-# if DEBUG_CYGWIN_THREADS
- GC_printf2("About to create a thread from 0x%x(0x%x)\n",
- (int)pthread_self(), GetCurrentThreadId);
-# endif
- result = pthread_create(new_thread, attr, GC_start_routine, si);
+ if (!EXPECT(parallel_initialized, TRUE))
+ GC_init_parallel();
+ /* make sure GC is initialized (i.e. main thread is attached) */
+ GC_ASSERT(!GC_win32_dll_threads);
+
+ /* This is otherwise saved only in an area mmapped by the thread */
+ /* library, which isn't visible to the collector. */
+ si = GC_malloc_uncollectable(sizeof(struct start_info));
+ if (0 == si) return(EAGAIN);
+
+ si -> start_routine = start_routine;
+ si -> arg = arg;
+ if (attr != 0 &&
+ pthread_attr_getdetachstate(attr, &si->detached)
+ == PTHREAD_CREATE_DETACHED) {
+ si->detached = TRUE;
+ }
- if (result) { /* failure */
- GC_free(si);
- }
+# ifdef DEBUG_THREADS
+ GC_log_printf("About to create a thread from %p(0x%lx)\n",
+ GC_PTHREAD_PTRVAL(pthread_self()),
+ (long)GetCurrentThreadId());
+# endif
+ GC_need_to_lock = TRUE;
+ result = pthread_create(new_thread, attr, GC_pthread_start, si);
- return(result);
-}
+ if (result) { /* failure */
+ GC_free(si);
+ }
+ return(result);
+ }
-void * GC_start_routine(void * arg)
-{
+ STATIC void * GC_CALLBACK GC_pthread_start_inner(struct GC_stack_base *sb,
+ void * arg)
+ {
struct start_info * si = arg;
void * result;
void *(*start)(void *);
void *start_arg;
- pthread_t pthread_id;
+ DWORD thread_id = GetCurrentThreadId();
+ pthread_t pthread_id = pthread_self();
GC_thread me;
- GC_bool detached;
- int i;
+ DCL_LOCK_STATE;
-# if DEBUG_CYGWIN_THREADS
- GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(),
- GetCurrentThreadId());
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%x) starting...\n",
+ GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
# endif
- /* If a GC occurs before the thread is registered, that GC will */
+ GC_ASSERT(!GC_win32_dll_threads);
+ /* If a GC occurs before the thread is registered, that GC will */
/* ignore this thread. That's fine, since it will block trying to */
- /* acquire the allocation lock, and won't yet hold interesting */
- /* pointers. */
+ /* acquire the allocation lock, and won't yet hold interesting */
+ /* pointers. */
LOCK();
- /* We register the thread here instead of in the parent, so that */
+ /* We register the thread here instead of in the parent, so that */
/* we don't need to hold the allocation lock during pthread_create. */
- me = GC_new_thread();
+ me = GC_register_my_thread_inner(sb, thread_id);
+ SET_PTHREAD_MAP_CACHE(pthread_id, thread_id);
+ me -> pthread_id = pthread_id;
+ if (si->detached) me -> flags |= DETACHED;
UNLOCK();
start = si -> start_routine;
start_arg = si -> arg;
- if (si-> detached) me -> flags |= DETACHED;
- me -> pthread_id = pthread_id = pthread_self();
GC_free(si); /* was allocated uncollectable */
pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
result = (*start)(start_arg);
me -> status = result;
- pthread_cleanup_pop(0);
+ pthread_cleanup_pop(1);
-# if DEBUG_CYGWIN_THREADS
- GC_printf2("thread 0x%x(0x%x) returned from start routine.\n",
- (int)pthread_self(),GetCurrentThreadId());
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%x) returned from start routine\n",
+ GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
# endif
-
return(result);
-}
+ }
-void GC_thread_exit_proc(void *arg)
-{
+ STATIC void * GC_pthread_start(void * arg)
+ {
+ return GC_call_with_stack_base(GC_pthread_start_inner, arg);
+ }
+
+ STATIC void GC_thread_exit_proc(void *arg)
+ {
GC_thread me = (GC_thread)arg;
- int i;
+ DCL_LOCK_STATE;
-# if DEBUG_CYGWIN_THREADS
- GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
- (int)pthread_self(),GetCurrentThreadId());
+ GC_ASSERT(!GC_win32_dll_threads);
+# ifdef DEBUG_THREADS
+ GC_log_printf("thread %p(0x%lx) called pthread_exit()\n",
+ GC_PTHREAD_PTRVAL(pthread_self()),
+ (long)GetCurrentThreadId());
# endif
LOCK();
+ GC_wait_for_gc_completion(FALSE);
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
+ GC_destroy_thread_local(&(me->tlfs));
+# endif
if (me -> flags & DETACHED) {
GC_delete_thread(GetCurrentThreadId());
} else {
/* deallocate it as part of join */
me -> flags |= FINISHED;
}
+# if defined(THREAD_LOCAL_ALLOC)
+ /* It is required to call remove_specific defined in specific.c. */
+ GC_remove_specific(GC_thread_key);
+# endif
UNLOCK();
-}
+ }
-/* nothing required here... */
-int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
- return pthread_sigmask(how, set, oset);
-}
+# ifndef GC_NO_PTHREAD_SIGMASK
+ /* Win32 pthread does not support sigmask. */
+ /* So, nothing required here... */
+ GC_API int GC_pthread_sigmask(int how, const sigset_t *set,
+ sigset_t *oset)
+ {
+ return pthread_sigmask(how, set, oset);
+ }
+# endif /* !GC_NO_PTHREAD_SIGMASK */
-int GC_pthread_detach(pthread_t thread)
-{
+ GC_API int GC_pthread_detach(pthread_t thread)
+ {
int result;
- GC_thread thread_gc_id;
-
+ GC_thread t;
+ DCL_LOCK_STATE;
+
+ GC_ASSERT(!GC_win32_dll_threads);
LOCK();
- thread_gc_id = GC_lookup_thread(thread);
+ t = GC_lookup_pthread(thread);
UNLOCK();
result = pthread_detach(thread);
if (result == 0) {
+ if (NULL == t) ABORT("Thread not registered");
LOCK();
- thread_gc_id -> flags |= DETACHED;
+ t -> flags |= DETACHED;
/* Here the pthread thread id may have been recycled. */
- if (thread_gc_id -> flags & FINISHED) {
- GC_delete_gc_thread(thread_gc_id);
+ if ((t -> flags & FINISHED) != 0) {
+ GC_delete_gc_thread_no_free(t);
+ GC_INTERNAL_FREE(t);
}
UNLOCK();
}
return result;
-}
+ }
-#else /* !CYGWIN32 */
+#elif !defined(GC_NO_THREADS_DISCOVERY)
+ /* We avoid acquiring locks here, since this doesn't seem to be */
+ /* preemptible. This may run with an uninitialized collector, in */
+ /* which case we don't do much. This implies that no threads other */
+ /* than the main one should be created with an uninitialized */
+ /* collector. (The alternative of initializing the collector here */
+ /* seems dangerous, since DllMain is limited in what it can do.) */
+
+# ifdef GC_INSIDE_DLL
+ /* Export only if needed by client. */
+ GC_API
+# else
+# define GC_DllMain DllMain
+# endif
+ BOOL WINAPI GC_DllMain(HINSTANCE inst GC_ATTR_UNUSED, ULONG reason,
+ LPVOID reserved GC_ATTR_UNUSED)
+ {
+ DWORD thread_id;
+ static int entry_count = 0;
+
+ if (!GC_win32_dll_threads && parallel_initialized) return TRUE;
+
+ switch (reason) {
+ case DLL_THREAD_ATTACH:
+# ifdef PARALLEL_MARK
+ /* Don't register marker threads. */
+ if (GC_parallel) {
+ /* We could reach here only if parallel_initialized == FALSE. */
+ break;
+ }
+# endif
+ GC_ASSERT(entry_count == 0 || parallel_initialized);
+ ++entry_count; /* and fall through: */
+ case DLL_PROCESS_ATTACH:
+ /* This may run with the collector uninitialized. */
+ thread_id = GetCurrentThreadId();
+ if (parallel_initialized && GC_main_thread != thread_id) {
+# ifdef PARALLEL_MARK
+ ABORT("Cannot initialize parallel marker from DllMain");
+# else
+ struct GC_stack_base sb;
+ /* Don't lock here. */
+# ifdef GC_ASSERTIONS
+ int sb_result =
+# endif
+ GC_get_stack_base(&sb);
+ GC_ASSERT(sb_result == GC_SUCCESS);
+ GC_register_my_thread_inner(&sb, thread_id);
+# endif
+ } /* o.w. we already did it during GC_thr_init, called by GC_init */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* We are hopefully running in the context of the exiting thread. */
+ GC_ASSERT(parallel_initialized);
+ if (GC_win32_dll_threads) {
+ GC_delete_thread(GetCurrentThreadId());
+ }
+ break;
+
+ case DLL_PROCESS_DETACH:
+ if (GC_win32_dll_threads) {
+ int i;
+ int my_max = (int)GC_get_max_thread_index();
+
+ for (i = 0; i <= my_max; ++i) {
+ if (AO_load(&(dll_thread_table[i].tm.in_use)))
+ GC_delete_gc_thread_no_free(&dll_thread_table[i]);
+ }
+ GC_deinit();
+ DeleteCriticalSection(&GC_allocate_ml);
+ }
+ break;
+ }
+ return TRUE;
+ }
+#endif /* !GC_NO_THREADS_DISCOVERY && !GC_PTHREADS */
-/*
- * We avoid acquiring locks here, since this doesn't seem to be preemptable.
- * Pontus Rydin suggests wrapping the thread start routine instead.
- */
-#ifdef GC_DLL
-BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
+/* Perform all initializations, including those that */
+/* may require allocation. */
+/* Called without allocation lock. */
+/* Must be called before a second thread is created. */
+GC_INNER void GC_init_parallel(void)
{
- switch (reason) {
- case DLL_PROCESS_ATTACH:
- GC_init(); /* Force initialization before thread attach. */
- /* fall through */
- case DLL_THREAD_ATTACH:
- GC_ASSERT(GC_thr_initialized);
- if (GC_main_thread != GetCurrentThreadId()) {
- GC_new_thread();
- } /* o.w. we already did it during GC_thr_init(), called by GC_init() */
- break;
-
- case DLL_THREAD_DETACH:
- GC_delete_thread(GetCurrentThreadId());
- break;
-
- case DLL_PROCESS_DETACH:
- {
- int i;
+# if defined(THREAD_LOCAL_ALLOC)
+ GC_thread me;
+ DCL_LOCK_STATE;
+# endif
- LOCK();
- for (i = 0; i <= GC_get_max_thread_index(); ++i)
- {
- if (thread_table[i].in_use)
- GC_delete_gc_thread(thread_table + i);
- }
- UNLOCK();
+ if (parallel_initialized) return;
+ parallel_initialized = TRUE;
+ /* GC_init() calls us back, so set flag first. */
+
+ if (!GC_is_initialized) GC_init();
+ if (GC_win32_dll_threads) {
+ GC_need_to_lock = TRUE;
+ /* Cannot intercept thread creation. Hence we don't know if */
+ /* other threads exist. However, client is not allowed to */
+ /* create other threads before collector initialization. */
+ /* Thus it's OK not to lock before this. */
+ }
+ /* Initialize thread local free lists if used. */
+# if defined(THREAD_LOCAL_ALLOC)
+ LOCK();
+ me = GC_lookup_thread_inner(GetCurrentThreadId());
+ CHECK_LOOKUP_MY_THREAD(me);
+ GC_init_thread_local(&me->tlfs);
+ UNLOCK();
+# endif
+}
- GC_deinit();
- DeleteCriticalSection(&GC_allocate_ml);
- }
- break;
+#if defined(USE_PTHREAD_LOCKS)
+ /* Support for pthread locking code. */
+ /* Pthread_mutex_try_lock may not win here, */
+ /* due to builtin support for spinning first? */
+
+ GC_INNER volatile GC_bool GC_collecting = 0;
+ /* A hint that we're in the collector and */
+ /* holding the allocation lock for an */
+ /* extended period. */
+ GC_INNER void GC_lock(void)
+ {
+ pthread_mutex_lock(&GC_allocate_ml);
}
- return TRUE;
-}
-#endif /* GC_DLL */
-#endif /* !CYGWIN32 */
+#endif /* USE_PTHREAD_LOCKS */
-# endif /* !MSWINCE */
+#if defined(THREAD_LOCAL_ALLOC)
+
+ /* Add thread-local allocation support. VC++ uses __declspec(thread). */
+
+ /* We must explicitly mark ptrfree and gcj free lists, since the free */
+ /* list links wouldn't otherwise be found. We also set them in the */
+ /* normal free lists, since that involves touching less memory than if */
+ /* we scanned them normally. */
+ GC_INNER void GC_mark_thread_local_free_lists(void)
+ {
+ int i;
+ GC_thread p;
+
+ for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+ for (p = GC_threads[i]; 0 != p; p = p -> tm.next) {
+ if (!KNOWN_FINISHED(p)) {
+# ifdef DEBUG_THREADS
+ GC_log_printf("Marking thread locals for 0x%x\n", (int)p -> id);
+# endif
+ GC_mark_thread_local_fls_for(&(p->tlfs));
+ }
+ }
+ }
+ }
+
+# if defined(GC_ASSERTIONS)
+ void GC_check_tls_for(GC_tlfs p);
+# if defined(USE_CUSTOM_SPECIFIC)
+ void GC_check_tsd_marks(tsd *key);
+# endif
+ /* Check that all thread-local free-lists are completely marked. */
+ /* also check that thread-specific-data structures are marked. */
+ void GC_check_tls(void)
+ {
+ int i;
+ GC_thread p;
+
+ for (i = 0; i < THREAD_TABLE_SZ; ++i) {
+ for (p = GC_threads[i]; 0 != p; p = p -> tm.next) {
+ if (!KNOWN_FINISHED(p))
+ GC_check_tls_for(&(p->tlfs));
+ }
+ }
+# if defined(USE_CUSTOM_SPECIFIC)
+ if (GC_thread_key != 0)
+ GC_check_tsd_marks(GC_thread_key);
+# endif
+ }
+# endif /* GC_ASSERTIONS */
+
+#endif /* THREAD_LOCAL_ALLOC ... */
+
+# ifndef GC_NO_THREAD_REDIRECTS
+ /* Restore thread calls redirection. */
+# define CreateThread GC_CreateThread
+# define ExitThread GC_ExitThread
+# undef _beginthreadex
+# define _beginthreadex GC_beginthreadex
+# undef _endthreadex
+# define _endthreadex GC_endthreadex
+# endif /* !GC_NO_THREAD_REDIRECTS */
#endif /* GC_WIN32_THREADS */
diff --git a/boehm-gc/windows-untested/README b/boehm-gc/windows-untested/README
new file mode 100644
index 00000000000..0de3ce74fa3
--- /dev/null
+++ b/boehm-gc/windows-untested/README
@@ -0,0 +1,4 @@
+gc.def should probably be removed completely.
+
+I removed an apparently erroneous line for GC_CreateThread. Unfortunately
+gc.def is referenced in various other places I cannot easily edit. -HB
diff --git a/boehm-gc/windows-untested/gc.def b/boehm-gc/windows-untested/gc.def
new file mode 100644
index 00000000000..2853518fedf
--- /dev/null
+++ b/boehm-gc/windows-untested/gc.def
@@ -0,0 +1,2 @@
+EXPORTS
+ GC_version DATA
diff --git a/boehm-gc/windows-untested/gc.rc b/boehm-gc/windows-untested/gc.rc
new file mode 100644
index 00000000000..7de7af49769
--- /dev/null
+++ b/boehm-gc/windows-untested/gc.rc
@@ -0,0 +1 @@
+#include "gc.ver"
diff --git a/boehm-gc/windows-untested/gc.ver b/boehm-gc/windows-untested/gc.ver
new file mode 100644
index 00000000000..e91c7b6847e
--- /dev/null
+++ b/boehm-gc/windows-untested/gc.ver
@@ -0,0 +1,86 @@
+#include <winres.h>
+#include <winver.h>
+
+#include "../include/../version.h"
+
+#if GC_ALPHA_VERSION != GC_NOT_ALPHA
+#define _BETA 1
+#endif
+
+#define GC_VERSION_MICRO GC_ALPHA_VERSION
+#define GC_VERSION_REVISION 0
+
+#define GC_VERSION ((GC_VERSION_MAJOR) * 100 + GC_VERSION_MINOR)
+#define GC_FULL_VERSION ((GC_VERSION) * 10000 + GC_VERSION_MICRO)
+
+#ifndef __T
+# ifdef UNICODE
+# define __T(x) L ## x
+# else
+# define __T(x) x
+# endif
+#endif
+
+#define PP_TSTR(x) __T(#x)
+#define PP_EVAL_TSTR(x) PP_TSTR(x)
+
+#define GC_VERSION_STR PP_EVAL_TSTR(GC_VERSION_MAJOR) __T(".") PP_EVAL_TSTR(GC_VERSION_MINOR)
+#define GC_FULL_VERSION_STR PP_EVAL_TSTR(GC_VERSION_MAJOR) __T(".") PP_EVAL_TSTR(GC_VERSION_MINOR) __T(".") PP_EVAL_TSTR(GC_VERSION_MICRO) __T(".") PP_EVAL_TSTR(GC_VERSION_REVISION)
+#define GC_FULL_VERSION_CSV GC_VERSION_MAJOR, GC_VERSION_MINOR, GC_VERSION_MICRO, GC_VERSION_REVISION
+
+#ifdef _DEBUG
+#define VER_DEBUG VS_FF_DEBUG
+#else
+#define VER_DEBUG 0
+#endif
+
+#ifdef _BETA
+#define VER_PRERELEASE VS_FF_PRERELEASE
+#else
+#define VER_PRERELEASE 0
+#endif
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION GC_FULL_VERSION_CSV
+ PRODUCTVERSION GC_FULL_VERSION_CSV
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VER_DEBUG | VER_PRERELEASE
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0"
+ BEGIN
+ VALUE "CompanyName", "\
+Hans-J. Boehm, \
+Alan J. Demers, \
+Xerox Corporation, \
+Silicon Graphics, \
+and Hewlett-Packard Company. \
+\0"
+ VALUE "LegalCopyright", "\
+Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers. \
+Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. \
+Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. \
+Copyright (c) 1999-2004 by Hewlett-Packard. All rights reserved. \
+\0"
+
+ VALUE "OriginalFilename", "GC.DLL\0"
+ VALUE "InternalName", "GC\0"
+ VALUE "FileDescription", "Conservative Garbage Collector for C and C++\0"
+ VALUE "FileVersion", GC_FULL_VERSION_STR
+
+ VALUE "ProductName", "Conservative Garbage Collector for C and C++\0"
+ VALUE "ProductVersion", GC_FULL_VERSION_STR
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/boehm-gc/windows-untested/stdafx.c b/boehm-gc/windows-untested/stdafx.c
new file mode 100644
index 00000000000..fd4f341c7b2
--- /dev/null
+++ b/boehm-gc/windows-untested/stdafx.c
@@ -0,0 +1 @@
+#include "stdafx.h"
diff --git a/boehm-gc/windows-untested/stdafx.h b/boehm-gc/windows-untested/stdafx.h
new file mode 100644
index 00000000000..7f5dcf1c31d
--- /dev/null
+++ b/boehm-gc/windows-untested/stdafx.h
@@ -0,0 +1,15 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#pragma warning(error: 4013) // function undefined; assuming extern returning int
+
+#ifdef _MT
+# define GC_THREADS 1
+#endif
+
+#ifdef _DEBUG
+# define GC_DEBUG
+#endif
+
+#define SAVE_CALL_CHAIN
+#define SAVE_CALL_COUNT 8
diff --git a/boehm-gc/windows-untested/vc60/all.dsp b/boehm-gc/windows-untested/vc60/all.dsp
new file mode 100644
index 00000000000..b195df6d6e6
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/all.dsp
@@ -0,0 +1,63 @@
+# Microsoft Developer Studio Project File - Name="all" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Generic Project" 0x010a
+
+CFG=all - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "all.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "all.mak" CFG="all - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "all - Win32 Release" (based on "Win32 (x86) Generic Project")
+!MESSAGE "all - Win32 Debug" (based on "Win32 (x86) Generic Project")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+MTL=midl.exe
+
+!IF "$(CFG)" == "all - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Release"
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "all - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Debug"
+# PROP Target_Dir ""
+
+!ENDIF
+
+# Begin Target
+
+# Name "all - Win32 Release"
+# Name "all - Win32 Debug"
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/gc.dsp b/boehm-gc/windows-untested/vc60/gc.dsp
new file mode 100644
index 00000000000..b3169eb7dcf
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/gc.dsp
@@ -0,0 +1,332 @@
+# Microsoft Developer Studio Project File - Name="gc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=gc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "gc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "gc.mak" CFG="gc - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "gc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "gc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "gc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Release\gc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GC_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /I "..\..\include" /FI"stdafx.h" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "GC_BUILD" /D "GC_DLL" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /Yu"stdafx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /i "..\..\include" /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /base:"0x37C30000" /subsystem:console /dll /debug /machine:I386 /out:"..\..\..\bin/gc60.dll" /implib:"..\..\..\lib/gc.lib" /opt:ref /release
+# SUBTRACT LINK32 /pdb:none
+# Begin Special Build Tool
+OutDir=.\..\..\..\bin
+SOURCE="$(InputPath)"
+PostBuild_Cmds=del $(OutDir)\..\lib\gc.exp
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "gc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Debug\gc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GC_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /FI"stdafx.h" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "GC_BUILD" /D "GC_DLL" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /i "..\..\include" /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"..\..\..\bin/gcd.bsc"
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /base:"0x37C30000" /subsystem:console /dll /incremental:no /debug /machine:I386 /out:"..\..\..\bin/gc60d.dll" /implib:"..\..\..\lib/gcd.lib" /pdbtype:sept
+# SUBTRACT LINK32 /pdb:none
+# Begin Special Build Tool
+OutDir=.\..\..\..\bin
+SOURCE="$(InputPath)"
+PostBuild_Cmds=del $(OutDir)\..\lib\gcd.exp
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "gc - Win32 Release"
+# Name "gc - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "c;cpp;cc;cxx;tcc;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\allchblk.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\alloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\backgraph.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\blacklst.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\checksums.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\dbg_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\gcj_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\fnlz_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\dyn_load.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\finalize.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\headers.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mach_dep.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\malloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mallocx.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mark.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mark_rts.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\msvc_dbg.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\new_hblk.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\obj_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\os_dep.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ptr_chck.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\reclaim.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\stdafx.c
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\stubborn.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\typd_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\win32_threads.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hh;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\include\gc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_allocator.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_backptr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_config_macros.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_cpp.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_gcj.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\private\gc_hdrs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_inl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_inline.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\private\gc_locks.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_mark.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_disclaim.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\private\gc_pmark.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\private\gc_priv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_pthread_redirects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_typed.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\private\gcconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\javaxfc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\leak_detector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\msvc_dbg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\new_gc_alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\stdafx.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\version.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\weakpointer.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=..\gc.def
+# End Source File
+# Begin Source File
+
+SOURCE=..\gc.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\gc.ver
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/gc.dsw b/boehm-gc/windows-untested/vc60/gc.dsw
new file mode 100644
index 00000000000..c0f26184d8a
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/gc.dsw
@@ -0,0 +1,194 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "all"=".\all.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name gc
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libgc
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libgcmt
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "gc"=".\gc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libgc"=".\libgc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libgcmt"=".\libgcmt.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "test"=".\test.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name test_gc
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name test_libgc
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name test_libgcmt
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name test_leak_gc
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name test_leak_libgc
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name test_leak_libgcmt
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_gc"=".\test_gc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name gc
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_leak_gc"=".\test_leak_gc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name gc
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_leak_libgc"=".\test_leak_libgc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libgc
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_leak_libgcmt"=".\test_leak_libgcmt.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libgcmt
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_libgc"=".\test_libgc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libgc
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "test_libgcmt"=".\test_libgcmt.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libgcmt
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/boehm-gc/windows-untested/vc60/libgc.dsp b/boehm-gc/windows-untested/vc60/libgc.dsp
new file mode 100644
index 00000000000..40cb4d65619
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/libgc.dsp
@@ -0,0 +1,269 @@
+# Microsoft Developer Studio Project File - Name="libgc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libgc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libgc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libgc.mak" CFG="libgc - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libgc - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libgc - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libgc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\lib"
+# PROP Intermediate_Dir "..\..\..\obj\Release\libgc"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Zi /O2 /I "..\..\include" /FI"stdafx.h" /D "NDEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /D "GC_BUILD" /Yu"stdafx.h" /Fd"..\..\..\lib\libgc.pdb" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# Begin Special Build Tool
+OutDir=.\..\..\..\lib
+TargetName=libgc
+SOURCE="$(InputPath)"
+PostBuild_Cmds=del $(OutDir)\$(TargetName).idb
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "libgc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\lib"
+# PROP Intermediate_Dir "..\..\..\obj\Debug\libgc"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /GX /Zi /Od /I "..\..\include" /FI"stdafx.h" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /D "GC_BUILD" /Yu"stdafx.h" /Fd"..\..\..\lib\libgcd.pdb" /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"..\..\..\lib/libgcd.bsc"
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\..\..\lib\libgcd.lib"
+# Begin Special Build Tool
+OutDir=.\..\..\..\lib
+TargetName=libgcd
+SOURCE="$(InputPath)"
+PostBuild_Cmds=del $(OutDir)\$(TargetName).idb
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libgc - Win32 Release"
+# Name "libgc - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "c;cpp;cc;cxx;tcc;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\allchblk.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\alloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\backgraph.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\blacklst.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\checksums.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\dbg_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\gcj_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\fnlz_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\dyn_load.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\finalize.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\headers.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mach_dep.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\malloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mallocx.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mark.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mark_rts.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\msvc_dbg.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\new_hblk.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\obj_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\os_dep.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ptr_chck.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\reclaim.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\stdafx.c
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\stubborn.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\typd_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\win32_threads.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hh;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\include\gc_allocator.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_backptr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_cpp.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_gcj.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_inl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_inline.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\gc_pthread_redirects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\javaxfc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\leak_detector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\msvc_dbg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\new_gc_alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\stdafx.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\version.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\weakpointer.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/libgcmt.dsp b/boehm-gc/windows-untested/vc60/libgcmt.dsp
new file mode 100644
index 00000000000..14b6fbe2007
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/libgcmt.dsp
@@ -0,0 +1,225 @@
+# Microsoft Developer Studio Project File - Name="libgcmt" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libgcmt - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libgcmt.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libgcmt.mak" CFG="libgcmt - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libgcmt - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libgcmt - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libgcmt - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\lib"
+# PROP Intermediate_Dir "..\..\..\obj\Release\libgcmt"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "..\..\include" /FI"stdafx.h" /D "NDEBUG" /D "_LIB" /D "GC_BUILD" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /Yu"stdafx.h" /Fd"..\..\..\lib\libgcmt.pdb" /Zl /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# Begin Special Build Tool
+OutDir=.\..\..\..\lib
+TargetName=libgcmt
+SOURCE="$(InputPath)"
+PostBuild_Cmds=del $(OutDir)\$(TargetName).idb
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "libgcmt - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\lib"
+# PROP Intermediate_Dir "..\..\..\obj\Debug\libgcmt"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /GX /Zi /Od /I "..\..\include" /FI"stdafx.h" /D "_DEBUG" /D "_LIB" /D "GC_BUILD" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /Yu"stdafx.h" /Fd"..\..\..\lib\libgcmtd.pdb" /Zl /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"..\..\..\lib/libgcmtd.bsc"
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo /out:"..\..\..\lib\libgcmtd.lib"
+# Begin Special Build Tool
+OutDir=.\..\..\..\lib
+TargetName=libgcmtd
+SOURCE="$(InputPath)"
+PostBuild_Cmds=del $(OutDir)\$(TargetName).idb
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "libgcmt - Win32 Release"
+# Name "libgcmt - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "c;cpp;cc;cxx;tcc;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\allchblk.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\alloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\backgraph.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\blacklst.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\checksums.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\dbg_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\gcj_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\fnlz_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\dyn_load.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\finalize.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\headers.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mach_dep.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\malloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mallocx.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mark.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\mark_rts.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\msvc_dbg.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\new_hblk.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\obj_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\os_dep.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ptr_chck.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\reclaim.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\stdafx.c
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\stubborn.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\typd_mlc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\win32_threads.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hh;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\msvc_dbg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\stdafx.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\version.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/test.dsp b/boehm-gc/windows-untested/vc60/test.dsp
new file mode 100644
index 00000000000..3648da48ad5
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/test.dsp
@@ -0,0 +1,63 @@
+# Microsoft Developer Studio Project File - Name="test" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Generic Project" 0x010a
+
+CFG=test - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test.mak" CFG="test - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test - Win32 Release" (based on "Win32 (x86) Generic Project")
+!MESSAGE "test - Win32 Debug" (based on "Win32 (x86) Generic Project")
+!MESSAGE
+
+# Begin Project
+# PROP testowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+MTL=midl.exe
+
+!IF "$(CFG)" == "test - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Release"
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "test - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Debug"
+# PROP Target_Dir ""
+
+!ENDIF
+
+# Begin Target
+
+# Name "test - Win32 Release"
+# Name "test - Win32 Debug"
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/test_gc.dsp b/boehm-gc/windows-untested/vc60/test_gc.dsp
new file mode 100644
index 00000000000..a9225631205
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/test_gc.dsp
@@ -0,0 +1,93 @@
+# Microsoft Developer Studio Project File - Name="test_gc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_gc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_gc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_gc.mak" CFG="test_gc - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_gc - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_gc - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_gc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Release\test_gc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /I "..\..\include" /D "NDEBUG" /D "_CONSOLE" /D "GC_DLL" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /debug /machine:I386 /release /opt:ref
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "test_gc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Debug\test_gc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "_DEBUG" /D "_CONSOLE" /D "GC_DLL" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /YX /FD /GZ /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"..\..\..\bin/test_gcd.bsc"
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /incremental:no /debug /machine:I386 /out:"..\..\..\bin/test_gcd.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_gc - Win32 Release"
+# Name "test_gc - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\tests\test.c
+# End Source File
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/test_leak_gc.dsp b/boehm-gc/windows-untested/vc60/test_leak_gc.dsp
new file mode 100644
index 00000000000..273c27d8442
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/test_leak_gc.dsp
@@ -0,0 +1,93 @@
+# Microsoft Developer Studio Project File - Name="test_leak_gc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_leak_gc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_leak_gc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_leak_gc.mak" CFG="test_leak_gc - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_leak_gc - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_leak_gc - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_leak_gc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Release\test_leak_gc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /I "..\..\include" /D "NDEBUG" /D "_CONSOLE" /D "GC_DLL" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /debug /machine:I386 /release /opt:ref
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "test_leak_gc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Debug\test_leak_gc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "_DEBUG" /D "_CONSOLE" /D "GC_DLL" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /YX /FD /GZ /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"..\..\..\bin/test_leak_gcd.bsc"
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /incremental:no /debug /machine:I386 /out:"..\..\..\bin/test_leak_gcd.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_leak_gc - Win32 Release"
+# Name "test_leak_gc - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\tests\leak_test.c
+# End Source File
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/test_leak_libgc.dsp b/boehm-gc/windows-untested/vc60/test_leak_libgc.dsp
new file mode 100644
index 00000000000..2d92257155d
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/test_leak_libgc.dsp
@@ -0,0 +1,93 @@
+# Microsoft Developer Studio Project File - Name="test_leak_libgc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_leak_libgc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_leak_libgc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_leak_libgc.mak" CFG="test_leak_libgc - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_leak_libgc - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_leak_libgc - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_leak_libgc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Release\test_leak_libgc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Zi /O2 /I "..\..\include" /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /debug /machine:I386 /release /opt:ref
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "test_leak_libgc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Debug\test_leak_libgc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"..\..\..\bin/test_leak_libgcd.bsc"
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /incremental:no /debug /machine:I386 /out:"..\..\..\bin/test_leak_libgcd.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_leak_libgc - Win32 Release"
+# Name "test_leak_libgc - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\tests\leak_test.c
+# End Source File
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/test_leak_libgcmt.dsp b/boehm-gc/windows-untested/vc60/test_leak_libgcmt.dsp
new file mode 100644
index 00000000000..42f97899ee1
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/test_leak_libgcmt.dsp
@@ -0,0 +1,93 @@
+# Microsoft Developer Studio Project File - Name="test_leak_libgcmt" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_leak_libgcmt - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_leak_libgcmt.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_leak_libgcmt.mak" CFG="test_leak_libgcmt - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_leak_libgcmt - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_leak_libgcmt - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_leak_libgcmt - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Release\test_leak_libgcmt"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "..\..\include" /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /debug /machine:I386 /release /opt:ref
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "test_leak_libgcmt - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Debug\test_leak_libgcmt"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /YX /FD /GZ /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"..\..\..\bin/test_leak_libgcmtd.bsc"
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /incremental:no /debug /machine:I386 /out:"..\..\..\bin/test_leak_libgcmtd.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_leak_libgcmt - Win32 Release"
+# Name "test_leak_libgcmt - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\tests\leak_test.c
+# End Source File
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/test_libgc.dsp b/boehm-gc/windows-untested/vc60/test_libgc.dsp
new file mode 100644
index 00000000000..d7fa50aab32
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/test_libgc.dsp
@@ -0,0 +1,93 @@
+# Microsoft Developer Studio Project File - Name="test_libgc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_libgc - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_libgc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_libgc.mak" CFG="test_libgc - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_libgc - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_libgc - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_libgc - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Release\test_libgc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Zi /O2 /I "..\..\include" /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /debug /machine:I386 /release /opt:ref
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "test_libgc - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Debug\test_libgc"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"..\..\..\bin/test_libgcd.bsc"
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /incremental:no /debug /machine:I386 /out:"..\..\..\bin/test_libgcd.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_libgc - Win32 Release"
+# Name "test_libgc - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\tests\test.c
+# End Source File
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/test_libgcmt.dsp b/boehm-gc/windows-untested/vc60/test_libgcmt.dsp
new file mode 100644
index 00000000000..6f81a3466aa
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/test_libgcmt.dsp
@@ -0,0 +1,93 @@
+# Microsoft Developer Studio Project File - Name="test_libgcmt" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=test_libgcmt - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "test_libgcmt.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "test_libgcmt.mak" CFG="test_libgcmt - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "test_libgcmt - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "test_libgcmt - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "test_libgcmt - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Release\test_libgcmt"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /I "..\..\include" /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /debug /machine:I386 /release /opt:ref
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "test_libgcmt - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\..\..\bin"
+# PROP Intermediate_Dir "..\..\..\obj\Debug\test_libgcmt"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /D "GC_THREADS" /YX /FD /GZ /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo /o"..\..\..\bin/test_libgcmtd.bsc"
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /incremental:no /debug /machine:I386 /out:"..\..\..\bin/test_libgcmtd.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "test_libgcmt - Win32 Release"
+# Name "test_libgcmt - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\tests\test.c
+# End Source File
+# End Target
+# End Project
diff --git a/boehm-gc/windows-untested/vc60/vc60crlf.cmd b/boehm-gc/windows-untested/vc60/vc60crlf.cmd
new file mode 100755
index 00000000000..28ec5360c14
--- /dev/null
+++ b/boehm-gc/windows-untested/vc60/vc60crlf.cmd
@@ -0,0 +1,15 @@
+@echo off
+rem This script will convert Unix-style line endings into Windows format.
+
+for %%P in (*.ds?) do call :fixline %%P
+goto :eof
+
+:fixline
+@echo on
+if exist "%~1.new" del "%~1.new"
+for /f %%S in (%1) do (
+ echo %%S>>"%~1.new"
+)
+ren %1 "%~1.bak"
+ren "%~1.new" %1
+goto :eof
diff --git a/boehm-gc/windows-untested/vc70/all.vcproj b/boehm-gc/windows-untested/vc70/all.vcproj
new file mode 100644
index 00000000000..512e9a0621e
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/all.vcproj
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="all"
+ SccProjectName=""
+ SccLocalPath=""
+ Keyword="MakeFileProj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug"
+ ConfigurationType="10"
+ UseOfMFC="0">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release"
+ ConfigurationType="10"
+ UseOfMFC="0">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/gc.sln b/boehm-gc/windows-untested/vc70/gc.sln
new file mode 100644
index 00000000000..aaa1be64e54
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/gc.sln
@@ -0,0 +1,96 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "all", "all.vcproj", "{CED9D953-AC1A-4795-9853-6D60857509EE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gc", "gc.vcproj", "{D7ADAD9A-14FF-4C93-9BF1-ACD03FB6A2FA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgc", "libgc.vcproj", "{F80C47A7-2B2D-4BA9-BEED-AAFA7541650D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgcmt", "libgcmt.vcproj", "{39802D97-BEF7-499D-8570-294AEA39ED7D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{997208FE-7A7D-435A-945A-C61C57D8070C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_gc", "test_gc.vcproj", "{D1F56655-8C27-4320-9436-2A11729A337B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_leak_gc", "test_leak_gc.vcproj", "{6E545988-1AE7-41FB-A981-D256A84F4C3A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_leak_libgc", "test_leak_libgc.vcproj", "{A561AE5C-33FE-4DBC-A4D4-52B7F196D20F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_leak_libgcmt", "test_leak_libgcmt.vcproj", "{92046CBF-2EF9-408D-B997-8445E945D687}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libgc", "test_libgc.vcproj", "{8CFE55AA-676C-4B5A-B133-390B4BF02AB8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libgcmt", "test_libgcmt.vcproj", "{8C63DB39-DBF4-49D3-A908-172ADA21753B}"
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ ConfigName.0 = Debug
+ ConfigName.1 = Release
+ EndGlobalSection
+ GlobalSection(ProjectDependencies) = postSolution
+ {CED9D953-AC1A-4795-9853-6D60857509EE}.0 = {39802D97-BEF7-499D-8570-294AEA39ED7D}
+ {CED9D953-AC1A-4795-9853-6D60857509EE}.1 = {F80C47A7-2B2D-4BA9-BEED-AAFA7541650D}
+ {CED9D953-AC1A-4795-9853-6D60857509EE}.2 = {D7ADAD9A-14FF-4C93-9BF1-ACD03FB6A2FA}
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.0 = {92046CBF-2EF9-408D-B997-8445E945D687}
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.1 = {A561AE5C-33FE-4DBC-A4D4-52B7F196D20F}
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.2 = {6E545988-1AE7-41FB-A981-D256A84F4C3A}
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.3 = {8C63DB39-DBF4-49D3-A908-172ADA21753B}
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.4 = {8CFE55AA-676C-4B5A-B133-390B4BF02AB8}
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.5 = {D1F56655-8C27-4320-9436-2A11729A337B}
+ {D1F56655-8C27-4320-9436-2A11729A337B}.0 = {D7ADAD9A-14FF-4C93-9BF1-ACD03FB6A2FA}
+ {6E545988-1AE7-41FB-A981-D256A84F4C3A}.0 = {D7ADAD9A-14FF-4C93-9BF1-ACD03FB6A2FA}
+ {A561AE5C-33FE-4DBC-A4D4-52B7F196D20F}.0 = {F80C47A7-2B2D-4BA9-BEED-AAFA7541650D}
+ {92046CBF-2EF9-408D-B997-8445E945D687}.0 = {39802D97-BEF7-499D-8570-294AEA39ED7D}
+ {8CFE55AA-676C-4B5A-B133-390B4BF02AB8}.0 = {F80C47A7-2B2D-4BA9-BEED-AAFA7541650D}
+ {8C63DB39-DBF4-49D3-A908-172ADA21753B}.0 = {39802D97-BEF7-499D-8570-294AEA39ED7D}
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {CED9D953-AC1A-4795-9853-6D60857509EE}.Debug.ActiveCfg = Debug|Win32
+ {CED9D953-AC1A-4795-9853-6D60857509EE}.Debug.Build.0 = Debug|Win32
+ {CED9D953-AC1A-4795-9853-6D60857509EE}.Release.ActiveCfg = Release|Win32
+ {CED9D953-AC1A-4795-9853-6D60857509EE}.Release.Build.0 = Release|Win32
+ {D7ADAD9A-14FF-4C93-9BF1-ACD03FB6A2FA}.Debug.ActiveCfg = Debug|Win32
+ {D7ADAD9A-14FF-4C93-9BF1-ACD03FB6A2FA}.Debug.Build.0 = Debug|Win32
+ {D7ADAD9A-14FF-4C93-9BF1-ACD03FB6A2FA}.Release.ActiveCfg = Release|Win32
+ {D7ADAD9A-14FF-4C93-9BF1-ACD03FB6A2FA}.Release.Build.0 = Release|Win32
+ {F80C47A7-2B2D-4BA9-BEED-AAFA7541650D}.Debug.ActiveCfg = Debug|Win32
+ {F80C47A7-2B2D-4BA9-BEED-AAFA7541650D}.Debug.Build.0 = Debug|Win32
+ {F80C47A7-2B2D-4BA9-BEED-AAFA7541650D}.Release.ActiveCfg = Release|Win32
+ {F80C47A7-2B2D-4BA9-BEED-AAFA7541650D}.Release.Build.0 = Release|Win32
+ {39802D97-BEF7-499D-8570-294AEA39ED7D}.Debug.ActiveCfg = Debug|Win32
+ {39802D97-BEF7-499D-8570-294AEA39ED7D}.Debug.Build.0 = Debug|Win32
+ {39802D97-BEF7-499D-8570-294AEA39ED7D}.Release.ActiveCfg = Release|Win32
+ {39802D97-BEF7-499D-8570-294AEA39ED7D}.Release.Build.0 = Release|Win32
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.Debug.ActiveCfg = Debug|Win32
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.Debug.Build.0 = Debug|Win32
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.Release.ActiveCfg = Release|Win32
+ {997208FE-7A7D-435A-945A-C61C57D8070C}.Release.Build.0 = Release|Win32
+ {D1F56655-8C27-4320-9436-2A11729A337B}.Debug.ActiveCfg = Debug|Win32
+ {D1F56655-8C27-4320-9436-2A11729A337B}.Debug.Build.0 = Debug|Win32
+ {D1F56655-8C27-4320-9436-2A11729A337B}.Release.ActiveCfg = Release|Win32
+ {D1F56655-8C27-4320-9436-2A11729A337B}.Release.Build.0 = Release|Win32
+ {6E545988-1AE7-41FB-A981-D256A84F4C3A}.Debug.ActiveCfg = Debug|Win32
+ {6E545988-1AE7-41FB-A981-D256A84F4C3A}.Debug.Build.0 = Debug|Win32
+ {6E545988-1AE7-41FB-A981-D256A84F4C3A}.Release.ActiveCfg = Release|Win32
+ {6E545988-1AE7-41FB-A981-D256A84F4C3A}.Release.Build.0 = Release|Win32
+ {A561AE5C-33FE-4DBC-A4D4-52B7F196D20F}.Debug.ActiveCfg = Debug|Win32
+ {A561AE5C-33FE-4DBC-A4D4-52B7F196D20F}.Debug.Build.0 = Debug|Win32
+ {A561AE5C-33FE-4DBC-A4D4-52B7F196D20F}.Release.ActiveCfg = Release|Win32
+ {A561AE5C-33FE-4DBC-A4D4-52B7F196D20F}.Release.Build.0 = Release|Win32
+ {92046CBF-2EF9-408D-B997-8445E945D687}.Debug.ActiveCfg = Debug|Win32
+ {92046CBF-2EF9-408D-B997-8445E945D687}.Debug.Build.0 = Debug|Win32
+ {92046CBF-2EF9-408D-B997-8445E945D687}.Release.ActiveCfg = Release|Win32
+ {92046CBF-2EF9-408D-B997-8445E945D687}.Release.Build.0 = Release|Win32
+ {8CFE55AA-676C-4B5A-B133-390B4BF02AB8}.Debug.ActiveCfg = Debug|Win32
+ {8CFE55AA-676C-4B5A-B133-390B4BF02AB8}.Debug.Build.0 = Debug|Win32
+ {8CFE55AA-676C-4B5A-B133-390B4BF02AB8}.Release.ActiveCfg = Release|Win32
+ {8CFE55AA-676C-4B5A-B133-390B4BF02AB8}.Release.Build.0 = Release|Win32
+ {8C63DB39-DBF4-49D3-A908-172ADA21753B}.Debug.ActiveCfg = Debug|Win32
+ {8C63DB39-DBF4-49D3-A908-172ADA21753B}.Debug.Build.0 = Debug|Win32
+ {8C63DB39-DBF4-49D3-A908-172ADA21753B}.Release.ActiveCfg = Release|Win32
+ {8C63DB39-DBF4-49D3-A908-172ADA21753B}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/boehm-gc/windows-untested/vc70/gc.vcproj b/boehm-gc/windows-untested/vc70/gc.vcproj
new file mode 100644
index 00000000000..c143e76b833
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/gc.vcproj
@@ -0,0 +1,347 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="gc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\gc"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\gc/gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\gc/"
+ ObjectFile=".\..\..\..\obj\Release\gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile="..\..\..\bin/gc70.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile="..\gc.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/gc70.pdb"
+ SubSystem="1"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"
+ BaseAddress="0x37C30000"
+ ImportLibrary="..\..\..\lib/gc.lib"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\..\..\..\bin/gc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del $(OutDir)\..\lib\gc.exp"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories="..\..\include"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\gc"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\gc/gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\gc/"
+ ObjectFile=".\..\..\..\obj\Debug\gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile="..\..\..\bin/gc70d.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile="..\gc.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/gc70d.pdb"
+ SubSystem="1"
+ BaseAddress="0x37C30000"
+ ImportLibrary="..\..\..\lib/gcd.lib"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\..\..\..\bin/gc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del $(OutDir)\..\lib\gcd.exp"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories="..\..\include"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="c;cpp;cc;cxx;tcc;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="..\..\allchblk.c">
+ </File>
+ <File
+ RelativePath="..\..\alloc.c">
+ </File>
+ <File
+ RelativePath="..\..\backgraph.c">
+ </File>
+ <File
+ RelativePath="..\..\blacklst.c">
+ </File>
+ <File
+ RelativePath="..\..\checksums.c">
+ </File>
+ <File
+ RelativePath="..\..\dbg_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\gcj_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\fnlz_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\dyn_load.c">
+ </File>
+ <File
+ RelativePath="..\..\finalize.c">
+ </File>
+ <File
+ RelativePath="..\..\headers.c">
+ </File>
+ <File
+ RelativePath="..\..\mach_dep.c">
+ </File>
+ <File
+ RelativePath="..\..\malloc.c">
+ </File>
+ <File
+ RelativePath="..\..\mallocx.c">
+ </File>
+ <File
+ RelativePath="..\..\mark.c">
+ </File>
+ <File
+ RelativePath="..\..\mark_rts.c">
+ </File>
+ <File
+ RelativePath="..\..\misc.c">
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.c">
+ </File>
+ <File
+ RelativePath="..\..\new_hblk.c">
+ </File>
+ <File
+ RelativePath="..\..\obj_map.c">
+ </File>
+ <File
+ RelativePath="..\..\os_dep.c">
+ </File>
+ <File
+ RelativePath="..\..\ptr_chck.c">
+ </File>
+ <File
+ RelativePath="..\..\reclaim.c">
+ </File>
+ <File
+ RelativePath="..\stdafx.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\stubborn.c">
+ </File>
+ <File
+ RelativePath="..\..\typd_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\win32_threads.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hh;hpp;hxx;hm;inl">
+ <File
+ RelativePath="..\..\include\gc.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_allocator.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_backptr.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_config_macros.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_cpp.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_gcj.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gc_hdrs.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_inl.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_inline.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gc_locks.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_mark.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_disclaim.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gc_pmark.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gc_priv.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_pthread_redirects.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_typed.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gcconfig.h">
+ </File>
+ <File
+ RelativePath="..\..\include\javaxfc.h">
+ </File>
+ <File
+ RelativePath="..\..\include\leak_detector.h">
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.h">
+ </File>
+ <File
+ RelativePath="..\..\include\new_gc_alloc.h">
+ </File>
+ <File
+ RelativePath="..\stdafx.h">
+ </File>
+ <File
+ RelativePath="..\..\version.h">
+ </File>
+ <File
+ RelativePath="..\..\include\weakpointer.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ <File
+ RelativePath="..\gc.def">
+ </File>
+ <File
+ RelativePath="..\gc.rc">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories="..\..\include"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories="..\..\include"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\gc.ver">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/libgc.vcproj b/boehm-gc/windows-untested/vc70/libgc.vcproj
new file mode 100644
index 00000000000..10deed7c303
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/libgc.vcproj
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="libgc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\lib"
+ IntermediateDirectory=".\..\..\..\obj\Debug\libgc"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG,_LIB,WIN32,GC_BUILD"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\libgc/libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\libgc/"
+ ObjectFile=".\..\..\..\obj\Debug\libgc/"
+ ProgramDataBaseFileName="..\..\..\lib\libgcd.pdb"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\..\..\lib\libgcd.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del $(OutDir)\$(TargetName).idb"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\lib"
+ IntermediateDirectory=".\..\..\..\obj\Release\libgc"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG,_LIB,WIN32,GC_BUILD"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\libgc/libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\libgc/"
+ ObjectFile=".\..\..\..\obj\Release\libgc/"
+ ProgramDataBaseFileName="..\..\..\lib\libgc.pdb"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\..\..\..\lib\libgc.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del $(OutDir)\$(TargetName).idb"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="c;cpp;cc;cxx;tcc;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="..\..\allchblk.c">
+ </File>
+ <File
+ RelativePath="..\..\alloc.c">
+ </File>
+ <File
+ RelativePath="..\..\backgraph.c">
+ </File>
+ <File
+ RelativePath="..\..\blacklst.c">
+ </File>
+ <File
+ RelativePath="..\..\checksums.c">
+ </File>
+ <File
+ RelativePath="..\..\dbg_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\gcj_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\fnlz_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\dyn_load.c">
+ </File>
+ <File
+ RelativePath="..\..\finalize.c">
+ </File>
+ <File
+ RelativePath="..\..\headers.c">
+ </File>
+ <File
+ RelativePath="..\..\mach_dep.c">
+ </File>
+ <File
+ RelativePath="..\..\malloc.c">
+ </File>
+ <File
+ RelativePath="..\..\mallocx.c">
+ </File>
+ <File
+ RelativePath="..\..\mark.c">
+ </File>
+ <File
+ RelativePath="..\..\mark_rts.c">
+ </File>
+ <File
+ RelativePath="..\..\misc.c">
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.c">
+ </File>
+ <File
+ RelativePath="..\..\new_hblk.c">
+ </File>
+ <File
+ RelativePath="..\..\obj_map.c">
+ </File>
+ <File
+ RelativePath="..\..\os_dep.c">
+ </File>
+ <File
+ RelativePath="..\..\ptr_chck.c">
+ </File>
+ <File
+ RelativePath="..\..\reclaim.c">
+ </File>
+ <File
+ RelativePath="..\stdafx.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\stubborn.c">
+ </File>
+ <File
+ RelativePath="..\..\typd_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\win32_threads.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hh;hpp;hxx;hm;inl">
+ <File
+ RelativePath="..\..\include\gc_allocator.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_backptr.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_cpp.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_gcj.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_inl.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_inline.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_pthread_redirects.h">
+ </File>
+ <File
+ RelativePath="..\..\include\javaxfc.h">
+ </File>
+ <File
+ RelativePath="..\..\include\leak_detector.h">
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.h">
+ </File>
+ <File
+ RelativePath="..\..\include\new_gc_alloc.h">
+ </File>
+ <File
+ RelativePath="..\stdafx.h">
+ </File>
+ <File
+ RelativePath="..\..\version.h">
+ </File>
+ <File
+ RelativePath="..\..\include\weakpointer.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/libgcmt.vcproj b/boehm-gc/windows-untested/vc70/libgcmt.vcproj
new file mode 100644
index 00000000000..446180de870
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/libgcmt.vcproj
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="libgcmt"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\lib"
+ IntermediateDirectory=".\..\..\..\obj\Release\libgcmt"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG,_LIB,GC_BUILD,WIN32,GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\libgcmt/libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\libgcmt/"
+ ObjectFile=".\..\..\..\obj\Release\libgcmt/"
+ ProgramDataBaseFileName="..\..\..\lib\libgcmt.pdb"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\..\..\..\lib\libgcmt.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del $(OutDir)\$(TargetName).idb"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\lib"
+ IntermediateDirectory=".\..\..\..\obj\Debug\libgcmt"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG,_LIB,GC_BUILD,WIN32,GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\libgcmt/libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\libgcmt/"
+ ObjectFile=".\..\..\..\obj\Debug\libgcmt/"
+ ProgramDataBaseFileName="..\..\..\lib\libgcmtd.pdb"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\..\..\lib\libgcmtd.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del $(OutDir)\$(TargetName).idb"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="c;cpp;cc;cxx;tcc;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="..\..\allchblk.c">
+ </File>
+ <File
+ RelativePath="..\..\alloc.c">
+ </File>
+ <File
+ RelativePath="..\..\backgraph.c">
+ </File>
+ <File
+ RelativePath="..\..\blacklst.c">
+ </File>
+ <File
+ RelativePath="..\..\checksums.c">
+ </File>
+ <File
+ RelativePath="..\..\dbg_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\gcj_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\fnlz_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\dyn_load.c">
+ </File>
+ <File
+ RelativePath="..\..\finalize.c">
+ </File>
+ <File
+ RelativePath="..\..\headers.c">
+ </File>
+ <File
+ RelativePath="..\..\mach_dep.c">
+ </File>
+ <File
+ RelativePath="..\..\malloc.c">
+ </File>
+ <File
+ RelativePath="..\..\mallocx.c">
+ </File>
+ <File
+ RelativePath="..\..\mark.c">
+ </File>
+ <File
+ RelativePath="..\..\mark_rts.c">
+ </File>
+ <File
+ RelativePath="..\..\misc.c">
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.c">
+ </File>
+ <File
+ RelativePath="..\..\new_hblk.c">
+ </File>
+ <File
+ RelativePath="..\..\obj_map.c">
+ </File>
+ <File
+ RelativePath="..\..\os_dep.c">
+ </File>
+ <File
+ RelativePath="..\..\ptr_chck.c">
+ </File>
+ <File
+ RelativePath="..\..\reclaim.c">
+ </File>
+ <File
+ RelativePath="..\stdafx.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\stubborn.c">
+ </File>
+ <File
+ RelativePath="..\..\typd_mlc.c">
+ </File>
+ <File
+ RelativePath="..\..\win32_threads.c">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hh;hpp;hxx;hm;inl">
+ <File
+ RelativePath="..\..\msvc_dbg.h">
+ </File>
+ <File
+ RelativePath="..\stdafx.h">
+ </File>
+ <File
+ RelativePath="..\..\version.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/test.vcproj b/boehm-gc/windows-untested/vc70/test.vcproj
new file mode 100644
index 00000000000..4b6170ddd45
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/test.vcproj
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="test"
+ SccProjectName=""
+ SccLocalPath=""
+ Keyword="MakeFileProj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug"
+ ConfigurationType="10"
+ UseOfMFC="0">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release"
+ ConfigurationType="10"
+ UseOfMFC="0">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/test_gc.vcproj b/boehm-gc/windows-untested/vc70/test_gc.vcproj
new file mode 100644
index 00000000000..8802cf6d9a2
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/test_gc.vcproj
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="test_gc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_gc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG,_CONSOLE,GC_DLL,WIN32,GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_gc/test_gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_gc/"
+ ObjectFile=".\..\..\..\obj\Release\test_gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile=".\..\..\..\bin/test_gc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_gc.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_gc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_gc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG,_CONSOLE,GC_DLL,WIN32,GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_gc/test_gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_gc/"
+ ObjectFile=".\..\..\..\obj\Debug\test_gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile="..\..\..\bin/test_gcd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_gcd.pdb"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_gc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <File
+ RelativePath="..\..\tests\test.c">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/test_leak_gc.vcproj b/boehm-gc/windows-untested/vc70/test_leak_gc.vcproj
new file mode 100644
index 00000000000..4b12168ee3e
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/test_leak_gc.vcproj
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="test_leak_gc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_leak_gc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG,_CONSOLE,GC_DLL,WIN32,GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_leak_gc/test_leak_gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_leak_gc/"
+ ObjectFile=".\..\..\..\obj\Release\test_leak_gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_leak_gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile=".\..\..\..\bin/test_leak_gc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_gc.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_gc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_leak_gc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG,_CONSOLE,GC_DLL,WIN32,GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_leak_gc/test_leak_gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_leak_gc/"
+ ObjectFile=".\..\..\..\obj\Debug\test_leak_gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_leak_gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile="..\..\..\bin/test_leak_gcd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_gcd.pdb"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_gc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <File
+ RelativePath="..\..\tests\leak_test.c">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/test_leak_libgc.vcproj b/boehm-gc/windows-untested/vc70/test_leak_libgc.vcproj
new file mode 100644
index 00000000000..05a1be4e592
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/test_leak_libgc.vcproj
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="test_leak_libgc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_leak_libgc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG,_CONSOLE,WIN32"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_leak_libgc/test_leak_libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_leak_libgc/"
+ ObjectFile=".\..\..\..\obj\Debug\test_leak_libgc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_leak_libgc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile="..\..\..\bin/test_leak_libgcd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_libgcd.pdb"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_libgc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_leak_libgc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG,_CONSOLE,WIN32"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_leak_libgc/test_leak_libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_leak_libgc/"
+ ObjectFile=".\..\..\..\obj\Release\test_leak_libgc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_leak_libgc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile=".\..\..\..\bin/test_leak_libgc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_libgc.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_libgc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <File
+ RelativePath="..\..\tests\leak_test.c">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/test_leak_libgcmt.vcproj b/boehm-gc/windows-untested/vc70/test_leak_libgcmt.vcproj
new file mode 100644
index 00000000000..8f4f8bd7820
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/test_leak_libgcmt.vcproj
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="test_leak_libgcmt"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_leak_libgcmt"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG,_CONSOLE,WIN32,GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_leak_libgcmt/test_leak_libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_leak_libgcmt/"
+ ObjectFile=".\..\..\..\obj\Release\test_leak_libgcmt/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_leak_libgcmt/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile=".\..\..\..\bin/test_leak_libgcmt.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_libgcmt.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_libgcmt.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_leak_libgcmt"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG,_CONSOLE,WIN32,GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_leak_libgcmt/test_leak_libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_leak_libgcmt/"
+ ObjectFile=".\..\..\..\obj\Debug\test_leak_libgcmt/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_leak_libgcmt/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile="..\..\..\bin/test_leak_libgcmtd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_libgcmtd.pdb"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_libgcmt.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <File
+ RelativePath="..\..\tests\leak_test.c">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/test_libgc.vcproj b/boehm-gc/windows-untested/vc70/test_libgc.vcproj
new file mode 100644
index 00000000000..110c39621b0
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/test_libgc.vcproj
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="test_libgc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_libgc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG,_CONSOLE,WIN32"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_libgc/test_libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_libgc/"
+ ObjectFile=".\..\..\..\obj\Debug\test_libgc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_libgc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile="..\..\..\bin/test_libgcd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_libgcd.pdb"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_libgc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_libgc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG,_CONSOLE,WIN32"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_libgc/test_libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_libgc/"
+ ObjectFile=".\..\..\..\obj\Release\test_libgc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_libgc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile=".\..\..\..\bin/test_libgc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_libgc.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_libgc.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <File
+ RelativePath="..\..\tests\test.c">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc70/test_libgcmt.vcproj b/boehm-gc/windows-untested/vc70/test_libgcmt.vcproj
new file mode 100644
index 00000000000..1353cdf02be
--- /dev/null
+++ b/boehm-gc/windows-untested/vc70/test_libgcmt.vcproj
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding = "windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="test_libgcmt"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_libgcmt"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG,_CONSOLE,WIN32,GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_libgcmt/test_libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_libgcmt/"
+ ObjectFile=".\..\..\..\obj\Release\test_libgcmt/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_libgcmt/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile=".\..\..\..\bin/test_libgcmt.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_libgcmt.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_libgcmt.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_libgcmt"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG,_CONSOLE,WIN32,GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_libgcmt/test_libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_libgcmt/"
+ ObjectFile=".\..\..\..\obj\Debug\test_libgcmt/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_libgcmt/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ OutputFile="..\..\..\bin/test_libgcmtd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_libgcmtd.pdb"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_libgcmt.tlb"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <File
+ RelativePath="..\..\tests\test.c">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/all.vcproj b/boehm-gc/windows-untested/vc71/all.vcproj
new file mode 100644
index 00000000000..2f4d7ae529e
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/all.vcproj
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="all"
+ SccProjectName=""
+ SccLocalPath=""
+ Keyword="MakeFileProj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug"
+ ConfigurationType="10"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/all.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release"
+ ConfigurationType="10"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/all.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/gc.sln b/boehm-gc/windows-untested/vc71/gc.sln
new file mode 100644
index 00000000000..fa1acc8d6a3
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/gc.sln
@@ -0,0 +1,116 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "all", "all.vcproj", "{684E465A-3944-4BA0-BA8D-52A064B43A5D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16} = {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16}
+ {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0} = {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0}
+ {93622AAF-633A-4D02-B023-674D4CDA266B} = {93622AAF-633A-4D02-B023-674D4CDA266B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gc", "gc.vcproj", "{93622AAF-633A-4D02-B023-674D4CDA266B}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgc", "libgc.vcproj", "{1C32FB8B-6F91-4190-9F05-CE1E772BB5E0}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgcmt", "libgcmt.vcproj", "{EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{1891ADD8-C39B-494B-B69D-D64F76729E5A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {8A595901-33E6-4959-A8E9-6DACC2D57330} = {8A595901-33E6-4959-A8E9-6DACC2D57330}
+ {EB1D2ECA-926D-4B6E-BF65-B429C713381C} = {EB1D2ECA-926D-4B6E-BF65-B429C713381C}
+ {500B7CE2-FD16-42C5-B738-1406C13A68B4} = {500B7CE2-FD16-42C5-B738-1406C13A68B4}
+ {9551B5E4-94A5-4B04-ACA1-9FB28DFD28AA} = {9551B5E4-94A5-4B04-ACA1-9FB28DFD28AA}
+ {B0F6C137-5153-48E3-ABED-6C02D3912EDA} = {B0F6C137-5153-48E3-ABED-6C02D3912EDA}
+ {1911057C-30C3-41CE-AF9E-232AEB37BCD3} = {1911057C-30C3-41CE-AF9E-232AEB37BCD3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_gc", "test_gc.vcproj", "{1911057C-30C3-41CE-AF9E-232AEB37BCD3}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93622AAF-633A-4D02-B023-674D4CDA266B} = {93622AAF-633A-4D02-B023-674D4CDA266B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_leak_gc", "test_leak_gc.vcproj", "{500B7CE2-FD16-42C5-B738-1406C13A68B4}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93622AAF-633A-4D02-B023-674D4CDA266B} = {93622AAF-633A-4D02-B023-674D4CDA266B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_leak_libgc", "test_leak_libgc.vcproj", "{EB1D2ECA-926D-4B6E-BF65-B429C713381C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0} = {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_leak_libgcmt", "test_leak_libgcmt.vcproj", "{8A595901-33E6-4959-A8E9-6DACC2D57330}"
+ ProjectSection(ProjectDependencies) = postProject
+ {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16} = {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libgc", "test_libgc.vcproj", "{B0F6C137-5153-48E3-ABED-6C02D3912EDA}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0} = {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libgcmt", "test_libgcmt.vcproj", "{9551B5E4-94A5-4B04-ACA1-9FB28DFD28AA}"
+ ProjectSection(ProjectDependencies) = postProject
+ {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16} = {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {684E465A-3944-4BA0-BA8D-52A064B43A5D}.Debug.ActiveCfg = Debug|Win32
+ {684E465A-3944-4BA0-BA8D-52A064B43A5D}.Debug.Build.0 = Debug|Win32
+ {684E465A-3944-4BA0-BA8D-52A064B43A5D}.Release.ActiveCfg = Release|Win32
+ {684E465A-3944-4BA0-BA8D-52A064B43A5D}.Release.Build.0 = Release|Win32
+ {93622AAF-633A-4D02-B023-674D4CDA266B}.Debug.ActiveCfg = Debug|Win32
+ {93622AAF-633A-4D02-B023-674D4CDA266B}.Debug.Build.0 = Debug|Win32
+ {93622AAF-633A-4D02-B023-674D4CDA266B}.Release.ActiveCfg = Release|Win32
+ {93622AAF-633A-4D02-B023-674D4CDA266B}.Release.Build.0 = Release|Win32
+ {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0}.Debug.ActiveCfg = Debug|Win32
+ {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0}.Debug.Build.0 = Debug|Win32
+ {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0}.Release.ActiveCfg = Release|Win32
+ {1C32FB8B-6F91-4190-9F05-CE1E772BB5E0}.Release.Build.0 = Release|Win32
+ {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16}.Debug.ActiveCfg = Debug|Win32
+ {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16}.Debug.Build.0 = Debug|Win32
+ {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16}.Release.ActiveCfg = Release|Win32
+ {EDA8C8B6-2538-4F1E-9C9A-F5C4FAF1EC16}.Release.Build.0 = Release|Win32
+ {1891ADD8-C39B-494B-B69D-D64F76729E5A}.Debug.ActiveCfg = Debug|Win32
+ {1891ADD8-C39B-494B-B69D-D64F76729E5A}.Debug.Build.0 = Debug|Win32
+ {1891ADD8-C39B-494B-B69D-D64F76729E5A}.Release.ActiveCfg = Release|Win32
+ {1891ADD8-C39B-494B-B69D-D64F76729E5A}.Release.Build.0 = Release|Win32
+ {1911057C-30C3-41CE-AF9E-232AEB37BCD3}.Debug.ActiveCfg = Debug|Win32
+ {1911057C-30C3-41CE-AF9E-232AEB37BCD3}.Debug.Build.0 = Debug|Win32
+ {1911057C-30C3-41CE-AF9E-232AEB37BCD3}.Release.ActiveCfg = Release|Win32
+ {1911057C-30C3-41CE-AF9E-232AEB37BCD3}.Release.Build.0 = Release|Win32
+ {500B7CE2-FD16-42C5-B738-1406C13A68B4}.Debug.ActiveCfg = Debug|Win32
+ {500B7CE2-FD16-42C5-B738-1406C13A68B4}.Debug.Build.0 = Debug|Win32
+ {500B7CE2-FD16-42C5-B738-1406C13A68B4}.Release.ActiveCfg = Release|Win32
+ {500B7CE2-FD16-42C5-B738-1406C13A68B4}.Release.Build.0 = Release|Win32
+ {EB1D2ECA-926D-4B6E-BF65-B429C713381C}.Debug.ActiveCfg = Debug|Win32
+ {EB1D2ECA-926D-4B6E-BF65-B429C713381C}.Debug.Build.0 = Debug|Win32
+ {EB1D2ECA-926D-4B6E-BF65-B429C713381C}.Release.ActiveCfg = Release|Win32
+ {EB1D2ECA-926D-4B6E-BF65-B429C713381C}.Release.Build.0 = Release|Win32
+ {8A595901-33E6-4959-A8E9-6DACC2D57330}.Debug.ActiveCfg = Debug|Win32
+ {8A595901-33E6-4959-A8E9-6DACC2D57330}.Debug.Build.0 = Debug|Win32
+ {8A595901-33E6-4959-A8E9-6DACC2D57330}.Release.ActiveCfg = Release|Win32
+ {8A595901-33E6-4959-A8E9-6DACC2D57330}.Release.Build.0 = Release|Win32
+ {B0F6C137-5153-48E3-ABED-6C02D3912EDA}.Debug.ActiveCfg = Debug|Win32
+ {B0F6C137-5153-48E3-ABED-6C02D3912EDA}.Debug.Build.0 = Debug|Win32
+ {B0F6C137-5153-48E3-ABED-6C02D3912EDA}.Release.ActiveCfg = Release|Win32
+ {B0F6C137-5153-48E3-ABED-6C02D3912EDA}.Release.Build.0 = Release|Win32
+ {9551B5E4-94A5-4B04-ACA1-9FB28DFD28AA}.Debug.ActiveCfg = Debug|Win32
+ {9551B5E4-94A5-4B04-ACA1-9FB28DFD28AA}.Debug.Build.0 = Debug|Win32
+ {9551B5E4-94A5-4B04-ACA1-9FB28DFD28AA}.Release.ActiveCfg = Release|Win32
+ {9551B5E4-94A5-4B04-ACA1-9FB28DFD28AA}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/boehm-gc/windows-untested/vc71/gc.vcproj b/boehm-gc/windows-untested/vc71/gc.vcproj
new file mode 100644
index 00000000000..d33e9a3a0b0
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/gc.vcproj
@@ -0,0 +1,869 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\gc"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\gc/gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\gc/"
+ ObjectFile=".\..\..\..\obj\Release\gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\..\bin/gc71.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile="..\gc.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/gc71.pdb"
+ SubSystem="1"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"
+ BaseAddress="0x37C30000"
+ ImportLibrary="..\..\..\lib/gc.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\..\..\..\bin/gc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del &quot;$(OutDir)&quot;\..\lib\gc.exp"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories="..\..\include"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\gc"
+ ConfigurationType="2"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\gc/gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\gc/"
+ ObjectFile=".\..\..\..\obj\Debug\gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\..\bin/gc71d.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ ModuleDefinitionFile="..\gc.def"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/gc71d.pdb"
+ SubSystem="1"
+ BaseAddress="0x37C30000"
+ ImportLibrary="..\..\..\lib/gcd.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\..\..\..\bin/gc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del &quot;$(OutDir)&quot;\..\lib\gcd.exp"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories="..\..\include"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="c;cpp;cc;cxx;tcc;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="..\..\allchblk.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\alloc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\backgraph.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\blacklst.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\checksums.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\dbg_mlc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\gcj_mlc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\fnlz_mlc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\dyn_load.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\finalize.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\headers.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mach_dep.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\malloc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mallocx.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mark.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mark_rts.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\misc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\new_hblk.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\obj_map.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\os_dep.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\ptr_chck.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\reclaim.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\stdafx.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ UsePrecompiledHeader="1"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\stubborn.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\typd_mlc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\win32_threads.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="NDEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="_DEBUG;_WINDOWS;_USRDLL;GC_BUILD;GC_DLL;WIN32;_MBCS;GC_THREADS;$(NoInherit)"
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hh;hpp;hxx;hm;inl">
+ <File
+ RelativePath="..\..\include\gc.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_allocator.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_backptr.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_config_macros.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_cpp.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_gcj.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gc_hdrs.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_inl.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_inline.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gc_locks.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_mark.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_disclaim.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gc_pmark.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gc_priv.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_pthread_redirects.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_typed.h">
+ </File>
+ <File
+ RelativePath="..\..\include\private\gcconfig.h">
+ </File>
+ <File
+ RelativePath="..\..\include\javaxfc.h">
+ </File>
+ <File
+ RelativePath="..\..\include\leak_detector.h">
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.h">
+ </File>
+ <File
+ RelativePath="..\..\include\new_gc_alloc.h">
+ </File>
+ <File
+ RelativePath="..\stdafx.h">
+ </File>
+ <File
+ RelativePath="..\..\version.h">
+ </File>
+ <File
+ RelativePath="..\..\include\weakpointer.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ <File
+ RelativePath="..\gc.def">
+ </File>
+ <File
+ RelativePath="..\gc.rc">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ AdditionalIncludeDirectories="..\..\include"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ AdditionalIncludeDirectories="..\..\include"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\gc.ver">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/libgc.vcproj b/boehm-gc/windows-untested/vc71/libgc.vcproj
new file mode 100644
index 00000000000..6c5bfdce44a
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/libgc.vcproj
@@ -0,0 +1,776 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="libgc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\lib"
+ IntermediateDirectory=".\..\..\..\obj\Release\libgc"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_LIB;WIN32;GC_BUILD"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\libgc/libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\libgc/"
+ ObjectFile=".\..\..\..\obj\Release\libgc/"
+ ProgramDataBaseFileName="..\..\..\lib\libgc.pdb"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\..\..\..\lib\libgc.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del &quot;$(OutDir)&quot;\&quot;$(TargetName)&quot;.idb"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\lib"
+ IntermediateDirectory=".\..\..\..\obj\Debug\libgc"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_LIB;WIN32;GC_BUILD"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\libgc/libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\libgc/"
+ ObjectFile=".\..\..\..\obj\Debug\libgc/"
+ ProgramDataBaseFileName="..\..\..\lib\libgcd.pdb"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\..\..\lib\libgcd.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del &quot;$(OutDir)&quot;\&quot;$(TargetName)&quot;.idb"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="c;cpp;cc;cxx;tcc;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="..\..\allchblk.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\alloc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\backgraph.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\blacklst.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\checksums.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\dbg_mlc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\gcj_mlc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\fnlz_mlc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\dyn_load.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\finalize.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\headers.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mach_dep.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\malloc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mallocx.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mark.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mark_rts.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\misc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\new_hblk.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\obj_map.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\os_dep.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\ptr_chck.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\reclaim.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\stdafx.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\stubborn.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\typd_mlc.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\win32_threads.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hh;hpp;hxx;hm;inl">
+ <File
+ RelativePath="..\..\include\gc_allocator.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_backptr.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_cpp.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_gcj.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_inl.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_inline.h">
+ </File>
+ <File
+ RelativePath="..\..\include\gc_pthread_redirects.h">
+ </File>
+ <File
+ RelativePath="..\..\include\javaxfc.h">
+ </File>
+ <File
+ RelativePath="..\..\include\leak_detector.h">
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.h">
+ </File>
+ <File
+ RelativePath="..\..\include\new_gc_alloc.h">
+ </File>
+ <File
+ RelativePath="..\stdafx.h">
+ </File>
+ <File
+ RelativePath="..\..\version.h">
+ </File>
+ <File
+ RelativePath="..\..\include\weakpointer.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/libgcmt.vcproj b/boehm-gc/windows-untested/vc71/libgcmt.vcproj
new file mode 100644
index 00000000000..96c526becb2
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/libgcmt.vcproj
@@ -0,0 +1,743 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="libgcmt"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\lib"
+ IntermediateDirectory=".\..\..\..\obj\Debug\libgcmt"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_LIB;GC_BUILD;WIN32;GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\libgcmt/libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\libgcmt/"
+ ObjectFile=".\..\..\..\obj\Debug\libgcmt/"
+ ProgramDataBaseFileName="..\..\..\lib\libgcmtd.pdb"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\..\..\lib\libgcmtd.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del &quot;$(OutDir)&quot;\&quot;$(TargetName)&quot;.idb"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\lib"
+ IntermediateDirectory=".\..\..\..\obj\Release\libgcmt"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_LIB;GC_BUILD;WIN32;GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\libgcmt/libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\libgcmt/"
+ ObjectFile=".\..\..\..\obj\Release\libgcmt/"
+ ProgramDataBaseFileName="..\..\..\lib\libgcmt.pdb"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ ForcedIncludeFiles="stdafx.h"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\..\..\..\lib\libgcmt.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="del &quot;$(OutDir)&quot;\&quot;$(TargetName)&quot;.idb"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="c;cpp;cc;cxx;tcc;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="..\..\allchblk.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\alloc.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\backgraph.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\blacklst.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\checksums.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\dbg_mlc.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\gcj_mlc.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\fnlz_mlc.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\dyn_load.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\finalize.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\headers.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mach_dep.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\malloc.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mallocx.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mark.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mark_rts.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\misc.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\msvc_dbg.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\new_hblk.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\obj_map.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\os_dep.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\ptr_chck.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\reclaim.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\stdafx.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="1"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\stubborn.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\typd_mlc.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\win32_threads.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ ForcedIncludeFiles=""/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hh;hpp;hxx;hm;inl">
+ <File
+ RelativePath="..\..\msvc_dbg.h">
+ </File>
+ <File
+ RelativePath="..\stdafx.h">
+ </File>
+ <File
+ RelativePath="..\..\version.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/test.vcproj b/boehm-gc/windows-untested/vc71/test.vcproj
new file mode 100644
index 00000000000..41681979f93
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/test.vcproj
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="test"
+ SccProjectName=""
+ SccLocalPath=""
+ Keyword="MakeFileProj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release"
+ ConfigurationType="10"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug"
+ ConfigurationType="10"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/test_gc.vcproj b/boehm-gc/windows-untested/vc71/test_gc.vcproj
new file mode 100644
index 00000000000..d477d70a62d
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/test_gc.vcproj
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="test_gc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_gc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE;GC_DLL;WIN32;GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_gc/test_gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_gc/"
+ ObjectFile=".\..\..\..\obj\Release\test_gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\..\..\..\bin/test_gc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_gc.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_gc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_gc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE;GC_DLL;WIN32;GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_gc/test_gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_gc/"
+ ObjectFile=".\..\..\..\obj\Debug\test_gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\..\bin/test_gcd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_gcd.pdb"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_gc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\tests\test.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/test_leak_gc.vcproj b/boehm-gc/windows-untested/vc71/test_leak_gc.vcproj
new file mode 100644
index 00000000000..b6c980cf76c
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/test_leak_gc.vcproj
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="test_leak_gc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_leak_gc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE;GC_DLL;WIN32;GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_leak_gc/test_leak_gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_leak_gc/"
+ ObjectFile=".\..\..\..\obj\Release\test_leak_gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_leak_gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\..\..\..\bin/test_leak_gc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_gc.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_gc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_leak_gc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE;GC_DLL;WIN32;GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_leak_gc/test_leak_gc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_leak_gc/"
+ ObjectFile=".\..\..\..\obj\Debug\test_leak_gc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_leak_gc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\..\bin/test_leak_gcd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_gcd.pdb"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_gc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\tests\leak_test.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/test_leak_libgc.vcproj b/boehm-gc/windows-untested/vc71/test_leak_libgc.vcproj
new file mode 100644
index 00000000000..0486f1ef645
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/test_leak_libgc.vcproj
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="test_leak_libgc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_leak_libgc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE;WIN32"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_leak_libgc/test_leak_libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_leak_libgc/"
+ ObjectFile=".\..\..\..\obj\Release\test_leak_libgc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_leak_libgc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\..\..\..\bin/test_leak_libgc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_libgc.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_libgc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_leak_libgc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE;WIN32"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_leak_libgc/test_leak_libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_leak_libgc/"
+ ObjectFile=".\..\..\..\obj\Debug\test_leak_libgc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_leak_libgc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\..\bin/test_leak_libgcd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_libgcd.pdb"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_libgc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\tests\leak_test.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/test_leak_libgcmt.vcproj b/boehm-gc/windows-untested/vc71/test_leak_libgcmt.vcproj
new file mode 100644
index 00000000000..297464d4399
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/test_leak_libgcmt.vcproj
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="test_leak_libgcmt"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_leak_libgcmt"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE;WIN32;GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_leak_libgcmt/test_leak_libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_leak_libgcmt/"
+ ObjectFile=".\..\..\..\obj\Release\test_leak_libgcmt/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_leak_libgcmt/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\..\..\..\bin/test_leak_libgcmt.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_libgcmt.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_libgcmt.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_leak_libgcmt"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE;WIN32;GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_leak_libgcmt/test_leak_libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_leak_libgcmt/"
+ ObjectFile=".\..\..\..\obj\Debug\test_leak_libgcmt/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_leak_libgcmt/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\..\bin/test_leak_libgcmtd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_leak_libgcmtd.pdb"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_leak_libgcmt.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\tests\leak_test.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/test_libgc.vcproj b/boehm-gc/windows-untested/vc71/test_libgc.vcproj
new file mode 100644
index 00000000000..93d35f46df9
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/test_libgc.vcproj
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="test_libgc"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_libgc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE;WIN32"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_libgc/test_libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_libgc/"
+ ObjectFile=".\..\..\..\obj\Release\test_libgc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_libgc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\..\..\..\bin/test_libgc.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_libgc.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_libgc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_libgc"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE;WIN32"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_libgc/test_libgc.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_libgc/"
+ ObjectFile=".\..\..\..\obj\Debug\test_libgc/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_libgc/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\..\bin/test_libgcd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_libgcd.pdb"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_libgc.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\tests\test.c">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/boehm-gc/windows-untested/vc71/test_libgcmt.vcproj b/boehm-gc/windows-untested/vc71/test_libgcmt.vcproj
new file mode 100644
index 00000000000..276aed5b1b2
--- /dev/null
+++ b/boehm-gc/windows-untested/vc71/test_libgcmt.vcproj
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="test_libgcmt"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Debug\test_libgcmt"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="_DEBUG;_CONSOLE;WIN32;GC_THREADS"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\..\..\..\obj\Debug\test_libgcmt/test_libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Debug\test_libgcmt/"
+ ObjectFile=".\..\..\..\obj\Debug\test_libgcmt/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Debug\test_libgcmt/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\..\bin/test_libgcmtd.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_libgcmtd.pdb"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_libgcmt.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\..\bin"
+ IntermediateDirectory=".\..\..\..\obj\Release\test_libgcmt"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include"
+ PreprocessorDefinitions="NDEBUG;_CONSOLE;WIN32;GC_THREADS"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ PrecompiledHeaderFile=".\..\..\..\obj\Release\test_libgcmt/test_libgcmt.pch"
+ AssemblerListingLocation=".\..\..\..\obj\Release\test_libgcmt/"
+ ObjectFile=".\..\..\..\obj\Release\test_libgcmt/"
+ ProgramDataBaseFileName=".\..\..\..\obj\Release\test_libgcmt/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\..\..\..\bin/test_libgcmt.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\..\..\..\bin/test_libgcmt.pdb"
+ OptimizeReferences="2"
+ SetChecksum="TRUE"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\..\..\..\bin/test_libgcmt.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\..\tests\test.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>