mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-03-15 09:20:23 -07:00
bdwgc: Update library to version 7.6.8.
libatomic_ops is updated accordingly to version 7.6.6.
Fixes build failures on android.
This commit is contained in:
parent
089d30260c
commit
736f50b864
268 changed files with 50728 additions and 14692 deletions
|
|
@ -51,6 +51,7 @@
|
|||
passed empty environment is used
|
||||
- compiler: when gcc fails ecl prints the failing command output
|
||||
- ASDF has been updated to 3.1.8.8
|
||||
- The Boehm-Demers-Weiser garbage collector has been updated to version 7.6.8
|
||||
- package local nicknames has been implemented (after SBCL)
|
||||
- hash table extensions are documented in newdoc
|
||||
- various cleanups performed in the compiler
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ This is an attempt to acknowledge contributions to the garbage collector.
|
|||
Early contributions also mentioned (duplicated) in ChangeLog file; details of
|
||||
later ones should be in "git log".
|
||||
|
||||
Currently maintained by Ivan Maidanski.
|
||||
|
||||
HISTORY -
|
||||
|
||||
Early versions of this collector were developed as a part of research
|
||||
|
|
@ -21,11 +23,14 @@ Other contributors (my apologies for any omissions):
|
|||
Adam Megacz <adam@megac.com>
|
||||
Adnan Ali
|
||||
Adrian Bunk <bunk@fs.tum.de>
|
||||
Adrian Pop <adrian.pop@liu.se>
|
||||
Akira Tagoh <tagoh@redhat.com>
|
||||
Alain Novak <alain.novak@hermes.si>
|
||||
Alan Dosser <dosser@src.dec.com>
|
||||
Alan J. Demers <ademers@cs.cornell.edu>
|
||||
Aleksey Demakov <ademakov@gmail.com>
|
||||
Alessandro Bruni <alessandro.bruni@gmail.com>
|
||||
Alex Ronne Petersen <alexrp@xamarin.com>
|
||||
Alexander Belchenko <bialix@ukr.net>
|
||||
Alexander Gavrilov <angavrilov@gmail.com>
|
||||
Alexander Herz <alexander.herz@mytum.de>
|
||||
|
|
@ -36,10 +41,11 @@ Alistair G. Crooks <agc@uts.amdahl.com>
|
|||
Allan Hsu <allan@counterpop.net>
|
||||
Andre Leiradella <andre@leiradella.com>
|
||||
Andreas Jaeger <aj@suse.de>
|
||||
Andreas Tobler <a.tobler@schweiz.org>
|
||||
Andreas Tobler <andreastt@gmail.com>
|
||||
Andrei Polushin <polushin@gmail.com>
|
||||
Andrej Cedilnik <acedil1@csee.umbc.edu>
|
||||
Andrew Begel <abegel@eecs.berkeley.edu>
|
||||
Andrew Buss <abuss@ucsd.edu>
|
||||
Andrew Gray <andrew.gray@anu.edu.au>
|
||||
Andrew Haley <aph@redhat.com>
|
||||
Andrew Horton <andrew.j.horton@gmail.com>
|
||||
|
|
@ -47,6 +53,7 @@ Andrew McKinlay <mckinlay@axonsoft.com>
|
|||
Andrew Pinski <pinskia@physics.uc.edu>
|
||||
Andrew Stitcher <astitcher@redhat.com>
|
||||
Andrew Stone <andrew@stone.com>
|
||||
Andy Li <andy@onthewings.net>
|
||||
Andy Wingo <wingo@pobox.com>
|
||||
Anselm Baird-Smith <Anselm.BairdSmith@inria.fr>
|
||||
Anthony Green <green@redhat.com>
|
||||
|
|
@ -63,6 +70,7 @@ Ben Hutchings <ben@decadentplace.org.uk>
|
|||
Ben Maurer <benm@mono-cvs.ximian.com>
|
||||
Benjamin Lerman <Benjamin.Lerman@ambre.net>
|
||||
Bernd Edlinger <bernd.edlinger@hotmail.de>
|
||||
Bernd Kuhls <bernd.kuhls@t-online.de>
|
||||
Bernie Solomon <bernard@mono-cvs.ximian.com>
|
||||
Bill Janssen <janssen@parc.xerox.com>
|
||||
Bo Thorsen <bo@berlioz.suse.de>
|
||||
|
|
@ -80,11 +88,14 @@ Bruce Mitchener <bruce.mitchener@gmail.com>
|
|||
Bruno Haible <bruno@clisp.org>
|
||||
Bryce McKinlay <mckinlay@redhat.com>
|
||||
Burkhard Linke <blinke@cebitec.uni-bielefeld.de>
|
||||
Calvin Hill <calvin@hakobaito.co.uk>
|
||||
Carlos J. Puga Medina <cpm@fbsd.es>
|
||||
Cesar Eduardo Barros <cesarb@nitnet.com.br>
|
||||
Charles Fiterman <cef@geode.geodesic.com>
|
||||
Charles Mills <boson@cyberspace.org>
|
||||
Chris Dodd <chrisd@reservoir.com>
|
||||
Chris Lingard <chris@highludworth.freeserve.co.uk>
|
||||
Chris Metcalf <cmetcalf@mellanox.com>
|
||||
Christian Joensson <christian.joensson@gmail.com>
|
||||
Christian Limpach <chris@pin.lu>
|
||||
Christian Thalinger <twisti@complang.tuwien.ac.at>
|
||||
|
|
@ -115,6 +126,8 @@ David Mossberger
|
|||
David Peroutka <djp@volny.cz>
|
||||
David Pickens <dsp@rci.rutgers.edu>
|
||||
David Stes <stes@d5e02b1d.kabel.telenet.be>
|
||||
David Terei <d@davidterei.com>
|
||||
David Van Horn <dvanhorn@ccs.neu.edu>
|
||||
Davide Angelocola <davide.angelocola@tiscali.it>
|
||||
Dick Porter <dick@acm.org>
|
||||
Dietmar Planitzer <dave.pl@ping.at>
|
||||
|
|
@ -124,33 +137,39 @@ Djamel Magri <djamel.magri@googlemail.com>
|
|||
Doug Kaufman <dkaufman@rahul.net>
|
||||
Doug Moen <doug@moens.org>
|
||||
Douglas Steel <doug@wg.icl.co.uk>
|
||||
Eli Barzilay <eli@racket-lang.org>
|
||||
Elijah Taylor <elijahtaylor@google.com>
|
||||
Elvenlord Elrond <elrond@samba-tng.org>
|
||||
Emmanual Stumpf
|
||||
Eric Benson <eb@kaleida.com>
|
||||
Eric Holk <eric.holk@gmail.com>
|
||||
Erik M. Bray <erik.bray@lri.fr>
|
||||
Fabian Thylman
|
||||
Fergus Henderson <fjh@cs.mu.oz.au>
|
||||
Franklin Chen <chen@adi.com>
|
||||
Fred Gilham <gilham@csl.sri.com>
|
||||
Fred Stearns
|
||||
Friedrich Dominicus <friedrichdominicus@googlemail.com>
|
||||
Gabor Drescher <gabor.drescher@cs.fau.de>
|
||||
Gary Leavens <leavens@eecs.ucf.edu>
|
||||
Geoff Norton <grompf@sublimeintervention.com>
|
||||
George Talbot <Gtalbot@ansarisbio.com>
|
||||
Gerard A Allan
|
||||
Glauco Masotti <glauco.masotti@libero.it>
|
||||
Grzegorz Jakacki <jakacki@acm.org>
|
||||
Gustavo Giraldez <ggiraldez@manas.com.ar>
|
||||
Gustavo Rodriguez-Rivera <grr@cs.purdue.edu>
|
||||
H.J. Lu <hjl.tools@gmail.com>
|
||||
Hamayama <hamay1010@gmail.com>
|
||||
Hannes Mehnert <hannes@mehnert.org>
|
||||
Hanno Boeck <hanno@gentoo.org>
|
||||
Hans Boehm <boehm@acm.org>
|
||||
Hans-Peter Nilsson <hp@gcc.gnu.org>
|
||||
Hans-Peter Nilsson <hp@axis.com>
|
||||
Henning Makholm <Henning@octoshape.com>
|
||||
Henrik Theiling <theiling@absint.com>
|
||||
Hironori Sakamoto <hsaka@mth.biglobe.ne.jp>
|
||||
Hiroshi Kawashima <kei@arch.sony.co.jp>
|
||||
Hiroshi Yokota <yokota@netlab.cs.tsukuba.ac.jp>
|
||||
Hubert Garavel <Hubert.Garavel@imag.fr>
|
||||
Iain Sandoe <developer@sandoe-acoustics.co.uk>
|
||||
Ian Piumarta <piumarta@prof.inria.fr>
|
||||
|
|
@ -167,6 +186,8 @@ James Dominy
|
|||
Jan Alexander Steffens <jan.steffens@gmail.com>
|
||||
Jan Wielemaker <J.Wielemaker@cs.vu.nl>
|
||||
Jani Kajala <jani@sumea.com>
|
||||
Jared McNeill <jmcneill@NetBSD.org>
|
||||
Jay Krell <jaykrell@microsoft.com>
|
||||
Jean-Baptiste Nivois
|
||||
Jean-Claude Beaudoin <jean.claude.beaudoin@gmail.com>
|
||||
Jean-Daniel Fekete <fekete@cs.umd.edu>
|
||||
|
|
@ -182,6 +203,7 @@ Ji-Yong Chung
|
|||
Jie Liu <lj8175@gmail.com>
|
||||
Jim Marshall <jim.marshall@wbemsolutions.com>
|
||||
Jim Meyering <jim@meyering.net>
|
||||
Joao Abecasis <joao@abecasis.name>
|
||||
Joerg Sonnenberger <joerg@britannica.bec.de>
|
||||
Johannes Schmidt <jschmidt@avtrex.com>
|
||||
Johannes Totz <jtotz@ic.ac.uk>
|
||||
|
|
@ -190,22 +212,27 @@ John Clements <clements@brinkerhoff.org>
|
|||
John Ellis <ellis@xerox.parc.com>
|
||||
John Merryweather Cooper <jmerry@mono-cvs.ximian.com>
|
||||
Jon Moore <jonm@apache.org>
|
||||
Jonas Echterhoff <jonas@unity3d.com>
|
||||
Jonathan Bachrach <jonathan@harlequin.com>
|
||||
Jonathan Chambers <jonathan@unity3d.com>
|
||||
Jonathan Clark
|
||||
Jonathan Pryor <jpryor@novell.com>
|
||||
Josh Peterson <petersonjm1@gmail.com>
|
||||
Joshua Richardson <jric@chegg.com>
|
||||
Juan Jose Garcia-Ripoll <juanjose.garciaripoll@googlemail.com>
|
||||
Kai Tietz <ktietz70@googlemail.com>
|
||||
Kaz Kojima <kkojima@rr.iij4u.or.jp>
|
||||
Kazu Hirata <kazu@codesourcery.com>
|
||||
Kazuhiro Inaoka <inaoka.kazuhiro@renesas.com>
|
||||
Keith Seitz <keiths@redhat.com>
|
||||
Kenjiro Taura <tau@eidos.ic.i.u-tokyo.ac.jp>
|
||||
Kenneth Schalk <schalk@cadtls.hlo.dec.com>
|
||||
Kevin Kenny <kenny@m.cs.uiuc.edu>
|
||||
Kevin Tew <tewk@racket-lang.org>
|
||||
Kevin Warne <kevinw@direct.ca>
|
||||
Kjetil S. Matheussen <ksvalast@ifi.uio.no>
|
||||
Kjetil Matheussen <k.s.matheussen@notam02.no>
|
||||
Klaus Treichel <ktreichel@web.de>
|
||||
Klemens Zwischenbrugger <ka7@la-evento.com>
|
||||
Knut Tvedten <knuttv@ifi.uio.no>
|
||||
Krister Walfridsson <cato@df.lth.se>
|
||||
Kristian Kristensen <kk@cs.aau.dk>
|
||||
|
|
@ -213,9 +240,11 @@ Kumar Srikantan
|
|||
Kurt Miller <kurt@intricatesoftware.com>
|
||||
Lars Farm <lars.farm@ite.mh.se>
|
||||
Laurent Morichetti <l_m@pacbell.net>
|
||||
Leonardo Taccari <iamleot@gmail.com>
|
||||
Linas Vepstas <linasvepstas@gmail.com>
|
||||
Loren J. Rittle <rittle@latour.labs.mot.com>
|
||||
Louis Zhuang <louis.zhuang@acm.org>
|
||||
Lucas Meijer <lucas@unity3d.com>
|
||||
Ludovic Courtes <ludo@gnu.org>
|
||||
Maarten Thibaut <mthibaut@cisco.com>
|
||||
Manuel A. Fernandez Montecelo <manuel.montezelo@gmail.com>
|
||||
|
|
@ -224,6 +253,7 @@ Marc Recht <recht@netbsd.org>
|
|||
Marco Maggi <marco.maggi-ipsu@poste.it>
|
||||
Marcos Dione <Marcos_David.Dione@sophia.inria.fr>
|
||||
Marcus Herbert
|
||||
Marek Vasut <marex@denx.de>
|
||||
Margaret Fleck <mfleck@illinois.edu>
|
||||
Mark Boulter <mboulter@vnet.ibm.com>
|
||||
Mark Mitchell <mark@codesourcery.com>
|
||||
|
|
@ -237,17 +267,23 @@ Matthew Flatt <mflatt@plt-scheme.org>
|
|||
Matthias Andree <matthias.andree@gmx.de>
|
||||
Matthias Drochner <M.Drochner@fz-juelich.de>
|
||||
Maurizio Vairani <maurizio.vairani@cloverinformatica.it>
|
||||
Max Mouratov <mmouratov@gmail.com>
|
||||
Melissa O'Neill <oneill@cs.sfu.ca>
|
||||
Michael Arnoldus <chime@proinf.dk>
|
||||
Michael Fox <mfox@cavium.com>
|
||||
Michael Smith <msmith@spinnakernet.com>
|
||||
Michael Spertus <mps@geodesic.com>
|
||||
Michel Schinz <schinz@alphanet.ch>
|
||||
Miguel de Icaza <miguel@gnome.org>
|
||||
Mikael Djurfeldt <mikael@djurfeldt.com>
|
||||
Mike Frysinger <vapier@gentoo.org>
|
||||
Mike Gran <spk121@yahoo.com>
|
||||
Mike McGaughey <mmcg@cs.monash.edu.au>
|
||||
Mike Stump <mrs@windriver.com>
|
||||
Mitch Harris <maharri@uiuc.edu>
|
||||
Mohan Embar <gnustuff@thisiscool.com>
|
||||
Naoyuki Sawa <sawa_naoyuki-1@yahoo.co.jp>
|
||||
Natanael Copa <ncopa@alpinelinux.org>
|
||||
Nathanael Nerode <neroden@twcny.rr.com>
|
||||
Neale Ferguson <neale@mono-cvs.ximian.com>
|
||||
Neil Sharman <neil@cs.mu.oz.au>
|
||||
|
|
@ -263,6 +299,7 @@ Parag Patel <parag@netcom.com>
|
|||
Patrick Bridges <bridges@cs.arizona.edu>
|
||||
Patrick C. Beard <beard@netscape.com>
|
||||
Patrick Doyle <doylep@eecg.toronto.edu>
|
||||
Paul Bone <paul@bone.id.au>
|
||||
Paul Brook <paul@codesourcery.com>
|
||||
Paul Graham
|
||||
Paul Nash <paulnash@wildseed.com>
|
||||
|
|
@ -300,13 +337,17 @@ Richard Henderson <rth@redhat.com>
|
|||
Richard Sandiford <rsandifo@nildram.co.uk>
|
||||
Rob Haack <rhaack@polaris.unm.edu>
|
||||
Robert Brazile <brazile@diamond.bbn.com>
|
||||
Rodrigo Kumpera <kumpera@gmail.com>
|
||||
Roger Sayle <roger@eyesopen.com>
|
||||
Roland McGrath <roland@redhat.com>
|
||||
Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
|
||||
Romain Naour <romain.naour@gmail.com>
|
||||
Romano Paolo Tenca <rotenca@telvia.it>
|
||||
Rutger Ovidius <ovidr@users.sourceforge.net>
|
||||
Ryan Gonzalez <rymg19@gmail.com>
|
||||
Ryan Murray <rmurray@debian.org>
|
||||
Salvador Eduardo Tropea <salvador@inti.gov.ar>
|
||||
Samuel Martin <s.martin49@gmail.com>
|
||||
Samuel Thibault <samuel.thibault@gnu.org>
|
||||
Scott Ananian <cananian@lesser-magoo.lcs.mit.edu>
|
||||
Scott Schwartz <schwartz@groucho.cse.psu.edu>
|
||||
|
|
@ -323,10 +364,13 @@ Sven Hartrumpf <Sven.Hartrumpf@fernuni-hagen.de>
|
|||
Sven Verdoolaege <skimo@kotnet.org>
|
||||
Takis Psarogiannakopoulos <takis@xfree86.org>
|
||||
Tatsuya Bizenn <bizenn@visha.org>
|
||||
Terrell Russell <terrellrussell@gmail.com>
|
||||
Thiemo Seufer <ths@networkno.de>
|
||||
Thomas Funke <thf@zelator.in-berlin.de>
|
||||
Thomas Klausner <tk@giga.or.at>
|
||||
Thomas Linder Puls <thomas_linder_puls@hotmail.com>
|
||||
Thomas Maier <Thomas.Maier@uni-kassel.de>
|
||||
Thomas Schwinge <thomas@codesourcery.com>
|
||||
Thorsten Glaser <tg@debian.org>
|
||||
Tilman Vogel <Tilman.Vogel@web.de>
|
||||
Tim Bingham <tjb@zko.dec.com>
|
||||
|
|
@ -354,6 +398,7 @@ Xi Wang <xi.wang@gmail.com>
|
|||
Xiaokun Zhu <xiaokun@aero.gla.ac.uk>
|
||||
Yann Dirson <dirson@debian.org>
|
||||
Yannis Bres <Yannis@bres.name>
|
||||
Yuki Okumura <mjt@cltn.org>
|
||||
Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
Yvan Roux <yvan.roux@linaro.org>
|
||||
Zach Saw <zach.saw@gmail.com>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,19 @@
|
|||
# Makefile for Borland C++ 5.5 on NT
|
||||
# If you have the Borland assembler, remove "-DUSE_GENERIC"
|
||||
#
|
||||
bc= c:\Borland\BCC55
|
||||
bcbin= $(bc)\bin
|
||||
bclib= $(bc)\lib
|
||||
bcinclude= $(bc)\include
|
||||
|
||||
gcinclude1 = $(bc)\gc6.2\include
|
||||
gcinclude2 = $(bc)\gc6.2\cord
|
||||
gcinclude1 = .\include
|
||||
|
||||
cc= $(bcbin)\bcc32
|
||||
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
|
||||
defines= -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY
|
||||
cflags= -O2 -R -v- -vi -H -H=gc.csm -I$(bcinclude);$(gcinclude1) -L$(bclib) \
|
||||
-w-pro -w-aus -w-par -w-ccc -w-inl -w-rch -a4
|
||||
defines= -DALL_INTERIOR_POINTERS -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY
|
||||
|
||||
.c.obj:
|
||||
$(cc) @&&|
|
||||
|
|
@ -28,7 +26,7 @@ defines= -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -
|
|||
|
|
||||
|
||||
.rc.res:
|
||||
$(rc) -i$(bcinclude) -r -fo$* $*.rc
|
||||
$(rc) -i$(bcinclude) -r -fo$* $*.rc
|
||||
|
||||
XXXOBJS= XXXalloc.obj XXXreclaim.obj XXXallchblk.obj XXXmisc.obj \
|
||||
XXXmach_dep.obj XXXos_dep.obj XXXmark_rts.obj XXXheaders.obj XXXmark.obj \
|
||||
|
|
@ -44,13 +42,13 @@ all: gctest.exe cord\de.exe test_cpp.exe
|
|||
$(OBJS) test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h MAKEFILE
|
||||
|
||||
gc.lib: $(OBJS)
|
||||
del gc.lib
|
||||
-del gc.lib
|
||||
$(lib) $* @&&|
|
||||
$(XXXOBJS:XXX=+)
|
||||
|
|
||||
|
||||
gctest.exe: tests\test.obj gc.lib
|
||||
$(cc) @&&|
|
||||
$(cc) @&&|
|
||||
$(cflags) -W -e$* tests\test.obj gc.lib
|
||||
|
|
||||
|
||||
|
|
@ -63,25 +61,19 @@ cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj \
|
|||
$(cflags) -W -e$* cord\cordbscs.obj cord\cordxtra.obj \
|
||||
cord\tests\de.obj cord\tests\de_win.obj gc.lib
|
||||
|
|
||||
$(rc) cord\tests\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
|
||||
|
||||
gc_cpp.cpp: gc_cpp.cc
|
||||
copy gc_cpp.cc gc_cpp.cpp
|
||||
gc_cpp.obj: gc_cpp.cc include\gc_cpp.h include\gc.h
|
||||
|
||||
test_cpp.cpp: tests\test_cpp.cc
|
||||
copy tests\test_cpp.cc test_cpp.cpp
|
||||
|
||||
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
|
||||
$(cc) @&&|
|
||||
$(cc) @&&|
|
||||
$(cflags) -W -e$* test_cpp.obj gc.lib
|
||||
|
|
||||
|
||||
scratch:
|
||||
-del *.obj *.res *.exe *.csm cord\*.obj cord\*.res cord\*.exe cord\*.csm
|
||||
|
||||
clean:
|
||||
del gc.lib
|
||||
del *.obj
|
||||
del tests\test.obj
|
||||
-del *.obj *.res *.exe *.csm cord\*.obj cord\*.res cord\*.exe cord\*.csm
|
||||
-del cord\*.tds cord\tests\*.obj cord\tests\*.res
|
||||
-del *.log *.tds gc.lib tests\test.obj "gc.#0*"
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ SET(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required
|
|||
|
||||
PROJECT(gc)
|
||||
|
||||
INCLUDE(CTest)
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
|
||||
|
||||
ADD_DEFINITIONS("-D_CRT_SECURE_NO_DEPRECATE
|
||||
|
|
@ -49,8 +51,7 @@ 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)
|
||||
typd_mlc.c ptr_chck.c mallocx.c gc_cpp.cc)
|
||||
SET(LIBS)
|
||||
OPTION(enable_threads "TODO" NO)
|
||||
IF(enable_threads)
|
||||
|
|
@ -69,6 +70,7 @@ OPTION(enable_parallel_mark "Parallelize marking and free list construction" NO)
|
|||
#ENDIF(Threads_FOUND)
|
||||
|
||||
IF(enable_parallel_mark)
|
||||
ADD_DEFINITIONS("-DPARALLEL_MARK")
|
||||
ENDIF(enable_parallel_mark)
|
||||
|
||||
OPTION(enable_cplusplus "install C++ support" NO)
|
||||
|
|
@ -82,66 +84,61 @@ MESSAGE("HOST = ${HOST}")
|
|||
#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.*)
|
||||
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")
|
||||
SET(SRC ${SRC} thread_local_alloc.c)
|
||||
MESSAGE("Explicit GC_INIT() calls may be required.")
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-linux.*)
|
||||
IF ( HOST MATCHES .*-.*-linux.*)
|
||||
ADD_DEFINITIONS("-DGC_LINUX_THREADS")
|
||||
ADD_DEFINITIONS("-D_REENTRANT")
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-aix.*)
|
||||
IF ( HOST MATCHES .*-.*-aix.*)
|
||||
ADD_DEFINITIONS("-DGC_AIX_THREADS")
|
||||
ADD_DEFINITIONS("-D_REENTRANT")
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-hpux11.*)
|
||||
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.*)
|
||||
IF ( HOST MATCHES .*-.*-hpux10.*)
|
||||
MESSAGE("Only HP/UX 11 POSIX threads are supported.")
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-openbsd.*)
|
||||
IF ( HOST MATCHES .*-.*-openbsd.*)
|
||||
ADD_DEFINITIONS("-DGC_OPENBSD_THREADS")
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-freebsd.*)
|
||||
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)
|
||||
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("-DTHREAD_LOCAL_ALLOC")
|
||||
ADD_DEFINITIONS("-DUSE_COMPILER_TLS")
|
||||
SET(SRC ${SRC} thread_local_alloc.c)
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-gnu.*)
|
||||
IF ( HOST MATCHES .*-.*-gnu.*)
|
||||
ADD_DEFINITIONS("-DGC_GNU_THREADS")
|
||||
ADD_DEFINITIONS("-D_REENTRANT")
|
||||
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
|
||||
SET(SRC ${SRC} thread_local_alloc.c)
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-netbsd.*)
|
||||
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.*)
|
||||
IF ( HOST MATCHES .*-.*-solaris.*)
|
||||
ADD_DEFINITIONS("-DGC_SOLARIS_THREADS")
|
||||
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
|
||||
SET(SRC ${SRC} thread_local_alloc.c)
|
||||
#TODO
|
||||
# if test "$GCC" != yes; then
|
||||
# CFLAGS="$CFLAGS -O"
|
||||
|
|
@ -149,41 +146,33 @@ IF(CMAKE_USE_PTHREADS_INIT)
|
|||
# fi
|
||||
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-irix.*)
|
||||
IF ( HOST MATCHES .*-.*-irix.*)
|
||||
ADD_DEFINITIONS("-DGC_IRIX_THREADS")
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-cygwin.*)
|
||||
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
|
||||
SET(SRC ${SRC} thread_local_alloc.c win32_threads.c)
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-darwin.*)
|
||||
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()
|
||||
SET(SRC ${SRC} darwin_stop_world.c thread_local_alloc.c)
|
||||
#TODO
|
||||
#darwin_threads=true
|
||||
ENDIF()
|
||||
IF ( "HOST" MATCHES .*-.*-osf*)
|
||||
IF ( HOST MATCHES .*-.*-osf.*)
|
||||
ADD_DEFINITIONS("-DGC_OSF1_THREADS")
|
||||
IF (${enable_parallel_mark})
|
||||
ADD_DEFINITIONS("-DPARALLEL_MARK")
|
||||
IF(enable_parallel_mark)
|
||||
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
|
||||
SET(SRC ${SRC} thread_local_alloc.c)
|
||||
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.*)
|
||||
IF ( HOST MATCHES .*-.*-linux.*)
|
||||
ADD_DEFINITIONS("-DGC_LINUX_THREADS")
|
||||
ADD_DEFINITIONS("-D_REENTRANT")
|
||||
ENDIF()
|
||||
|
|
@ -191,10 +180,9 @@ 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")
|
||||
IF(enable_parallel_mark)
|
||||
ADD_DEFINITIONS("-DTHREAD_LOCAL_ALLOC")
|
||||
SET(SRC ${SRC} thread_local_alloc.c)
|
||||
ENDIF()
|
||||
ADD_DEFINITIONS("-DEMPTY_GETENV_RESULTS") #TODO test
|
||||
SET(SRC ${SRC} win32_threads.c)
|
||||
|
|
@ -203,6 +191,10 @@ ENDIF(CMAKE_USE_WIN32_THREADS_INIT)
|
|||
OPTION(enable_gcj_support "Support for gcj" NO)
|
||||
IF(enable_gcj_support)
|
||||
ADD_DEFINITIONS("-DGC_GCJ_SUPPORT")
|
||||
IF(enable_threads)
|
||||
ADD_DEFINITIONS("-DGC_ENABLE_SUSPEND_THREAD")
|
||||
ENDIF(enable_threads)
|
||||
SET(SRC ${SRC} gcj_mlc.c)
|
||||
ENDIF(enable_gcj_support)
|
||||
|
||||
|
||||
|
|
|
|||
1646
src/bdwgc/ChangeLog
1646
src/bdwgc/ChangeLog
File diff suppressed because it is too large
Load diff
|
|
@ -11,6 +11,12 @@
|
|||
|
||||
## Process this file with automake to produce Makefile.in.
|
||||
|
||||
# Info (current:revision:age) for the Libtool versioning system.
|
||||
# These numbers should be updated at most once just before the release,
|
||||
# and, optionally, at most once during the development (after the release).
|
||||
LIBGC_VER_INFO = 4:4:3
|
||||
LIBGCCPP_VER_INFO = 4:2:3
|
||||
|
||||
## FIXME: `make distcheck' in this directory will not currently work.
|
||||
## This is most likely to the explicit flags passed to submakes.
|
||||
|
||||
|
|
@ -18,7 +24,7 @@
|
|||
# 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
|
||||
# Thus there seems to be no real reason to recursively build in the
|
||||
# libatomic_ops directory.
|
||||
# if USE_INTERNAL_LIBATOMICS_OPS
|
||||
# SUBDIRS = @maybe_libatomic_ops@
|
||||
|
|
@ -32,7 +38,7 @@ AM_CPPFLAGS = \
|
|||
-I$(top_builddir)/include -I$(top_srcdir)/include \
|
||||
$(ATOMIC_OPS_CFLAGS)
|
||||
|
||||
# Initialize variables so that we can declare files locally.
|
||||
## Initialize variables so that we can declare files locally.
|
||||
EXTRA_DIST =
|
||||
lib_LTLIBRARIES =
|
||||
include_HEADERS =
|
||||
|
|
@ -49,25 +55,35 @@ pkgconfig_DATA = bdw-gc.pc
|
|||
# ---------
|
||||
|
||||
lib_LTLIBRARIES += libgc.la
|
||||
|
||||
if SINGLE_GC_OBJ
|
||||
|
||||
libgc_la_SOURCES = extra/gc.c
|
||||
|
||||
if PTHREAD_START_STANDALONE
|
||||
AM_CPPFLAGS += -DGC_PTHREAD_START_STANDALONE
|
||||
libgc_la_SOURCES += pthread_start.c
|
||||
endif
|
||||
|
||||
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
|
||||
specific.c stubborn.c typd_mlc.c
|
||||
|
||||
# C Library: Architecture Dependent
|
||||
# ---------------------------------
|
||||
|
||||
if WIN32_THREADS
|
||||
libgc_la_SOURCES += win32_threads.c
|
||||
libgc_la_SOURCES += thread_local_alloc.c win32_threads.c
|
||||
else
|
||||
if PTHREADS
|
||||
libgc_la_SOURCES += pthread_start.c pthread_support.c
|
||||
# Not Cygwin or MinGW.
|
||||
libgc_la_SOURCES += pthread_start.c pthread_support.c thread_local_alloc.c
|
||||
if DARWIN_THREADS
|
||||
libgc_la_SOURCES += darwin_stop_world.c
|
||||
else
|
||||
|
|
@ -84,6 +100,7 @@ if ENABLE_DISCLAIM
|
|||
libgc_la_SOURCES += fnlz_mlc.c
|
||||
endif
|
||||
|
||||
## End of !SINGLE_GC_OBJ
|
||||
endif
|
||||
|
||||
if USE_INTERNAL_LIBATOMIC_OPS
|
||||
|
|
@ -98,27 +115,26 @@ endif
|
|||
# linuxthread semaphore functions get linked:
|
||||
libgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS) $(ATOMIC_OPS_LIBS)
|
||||
libgc_la_DEPENDENCIES = @addobjs@
|
||||
libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info 1:3:0 -no-undefined
|
||||
libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info $(LIBGC_VER_INFO) \
|
||||
-no-undefined
|
||||
|
||||
EXTRA_libgc_la_SOURCES = ia64_save_regs_in_stack.s sparc_mach_dep.S \
|
||||
sparc_netbsd_mach_dep.s sparc_sunos4_mach_dep.s
|
||||
|
||||
|
||||
if CPLUSPLUS
|
||||
# C++ Interface
|
||||
# -------------
|
||||
|
||||
if CPLUSPLUS
|
||||
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
|
||||
libgccpp_la_LDFLAGS = -version-info $(LIBGCCPP_VER_INFO) -no-undefined
|
||||
endif
|
||||
|
||||
# FIXME: If Visual C++ users use Makefile.am, this should go into
|
||||
# pkginclude_HEADERS with proper AM_CONDITIONALization. Otherwise
|
||||
# delete this comment.
|
||||
## 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
|
||||
|
||||
|
||||
|
|
@ -126,7 +142,10 @@ EXTRA_DIST += gc_cpp.cpp
|
|||
# ----
|
||||
|
||||
AM_CXXFLAGS = @GC_CFLAGS@
|
||||
AM_CFLAGS = @GC_CFLAGS@
|
||||
AM_CFLAGS = $(WERROR_CFLAGS) @GC_CFLAGS@
|
||||
|
||||
CFLAGS += $(CFLAGS_EXTRA)
|
||||
CXXFLAGS += $(CFLAGS_EXTRA)
|
||||
|
||||
## FIXME: relies on internal code generated by automake.
|
||||
## FIXME: ./configure --enable-dependency-tracking should be used
|
||||
|
|
@ -165,15 +184,14 @@ CCASFLAGS += $(DEFS)
|
|||
|
||||
# documentation which is not installed
|
||||
#
|
||||
EXTRA_DIST += README.QUICK TODO
|
||||
EXTRA_DIST += README.QUICK
|
||||
|
||||
# other makefiles
|
||||
# :GOTCHA: deliberately we do not include 'Makefile'
|
||||
EXTRA_DIST += BCC_MAKEFILE NT_MAKEFILE \
|
||||
OS2_MAKEFILE PCR-Makefile digimars.mak EMX_MAKEFILE \
|
||||
Makefile.direct SMakefile.amiga WCC_MAKEFILE autogen.sh \
|
||||
NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE \
|
||||
NT_X64_THREADS_MAKEFILE CMakeLists.txt tests/CMakeLists.txt
|
||||
CMakeLists.txt tests/CMakeLists.txt
|
||||
|
||||
# files used by makefiles other than Makefile.am
|
||||
#
|
||||
|
|
@ -197,5 +215,5 @@ 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.
|
||||
## 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.
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
# 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
|
||||
# check - 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
|
||||
# check-cpp - runs C++ test without adding C++ (and cords) interface to gc.a
|
||||
# cord/de - builds dumb editor based on cords.
|
||||
|
||||
ABI_FLAG=
|
||||
|
|
@ -21,10 +22,17 @@ AS_ABI_FLAG=$(ABI_FLAG)
|
|||
# executables.
|
||||
|
||||
CC=cc $(ABI_FLAG)
|
||||
|
||||
CXX=g++ $(ABI_FLAG)
|
||||
# Needed only for "make c++", which adds the c++ interface.
|
||||
|
||||
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.
|
||||
# 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 have to specify the ABI (-o32, -n32, or -64)
|
||||
# if you use something other than the default ABI on your machine.
|
||||
|
||||
LD=ld
|
||||
|
||||
# Redefining srcdir allows object code for the nonPCR version of the collector
|
||||
# to be generated in different directories.
|
||||
|
|
@ -36,17 +44,20 @@ AO_SRC_DIR=$(srcdir)/libatomic_ops
|
|||
|
||||
CFLAGS_EXTRA=
|
||||
CFLAGS= -O -I$(srcdir)/include -I$(AO_SRC_DIR)/src \
|
||||
-DATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS \
|
||||
-DGC_ATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS \
|
||||
$(CFLAGS_EXTRA)
|
||||
|
||||
# To build the parallel collector on Linux, add to the above:
|
||||
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
|
||||
# To build the collector with threads support, add to the above:
|
||||
# -DGC_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 -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
|
||||
|
||||
|
|
@ -111,7 +122,7 @@ SRCS= $(CSRCS) \
|
|||
ia64_save_regs_in_stack.s sparc_mach_dep.S \
|
||||
sparc_netbsd_mach_dep.s sparc_sunos4_mach_dep.s $(CORD_SRCS)
|
||||
|
||||
DOC_FILES= README.QUICK TODO doc/README.Mac doc/README.OS2 \
|
||||
DOC_FILES= 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.hp doc/README.linux doc/README.rs6000 \
|
||||
|
|
@ -136,11 +147,10 @@ GNU_BUILD_FILES= configure.ac Makefile.am configure install-sh Makefile.in \
|
|||
|
||||
OTHER_MAKEFILES= OS2_MAKEFILE NT_MAKEFILE gc.mak \
|
||||
BCC_MAKEFILE EMX_MAKEFILE WCC_MAKEFILE PCR-Makefile SMakefile.amiga \
|
||||
digimars.mak Makefile.direct NT_STATIC_THREADS_MAKEFILE \
|
||||
NT_X64_STATIC_THREADS_MAKEFILE NT_X64_THREADS_MAKEFILE
|
||||
digimars.mak Makefile.direct
|
||||
|
||||
OTHER_FILES= tools/setjmp_t.c tools/callprocs.sh extra/MacOS.c \
|
||||
extra/Mac_files/datastart.c extra/Mac_files/dataend.c \
|
||||
OTHER_FILES= README.QUICK 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 \
|
||||
|
|
@ -154,33 +164,35 @@ CORD_INCLUDE_FILES= $(srcdir)/include/gc.h $(srcdir)/include/cord.h \
|
|||
UTILS= if_mach if_not_there threadlibs
|
||||
|
||||
# Libraries needed for curses applications. Only needed for de.
|
||||
CURSES= -lcurses -ltermlib
|
||||
# It might also require -ltermlib on some targets.
|
||||
CURSES= -lcurses
|
||||
|
||||
# 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 -I$(AO_SRC_DIR)/src
|
||||
SPECIALCFLAGS= -I$(srcdir)/include -I$(AO_SRC_DIR)/src
|
||||
# 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
|
||||
all: base_lib gctest
|
||||
|
||||
atomic_ops.o: $(AO_SRC_DIR)/src/atomic_ops.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
$(CC) $(CFLAGS) -c -o $@ $(AO_SRC_DIR)/src/atomic_ops.c
|
||||
# For some reason, Solaris make does not handle "$<" properly.
|
||||
|
||||
atomic_ops_sysdeps.o: $(AO_SRC_DIR)/src/atomic_ops_sysdeps.S
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
$(CC) $(CFLAGS) -c -o $@ $(AO_SRC_DIR)/src/atomic_ops_sysdeps.S
|
||||
|
||||
LEAKFLAGS=$(CFLAGS) -DFIND_LEAK
|
||||
LEAKFLAGS= $(CFLAGS) -DFIND_LEAK
|
||||
|
||||
BSD-pkg-all: bsd-libgc.a bsd-libleak.a
|
||||
|
||||
bsd-libgc.a:
|
||||
$(MAKE) CFLAGS="$(CFLAGS)" clean c++-t
|
||||
$(MAKE) -f Makefile.direct CFLAGS="$(CFLAGS)" clean c++-t
|
||||
mv gc.a bsd-libgc.a
|
||||
|
||||
bsd-libleak.a:
|
||||
|
|
@ -200,18 +212,18 @@ mach_dep.o $(SRCS)
|
|||
$(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
|
||||
$(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
|
||||
|
||||
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 thread_local_alloc.o win32_threads.o: \
|
||||
$(srcdir)/include/private/specific.h $(srcdir)/include/gc_inline.h \
|
||||
$(srcdir)/include/private/thread_local_alloc.h
|
||||
$(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
|
||||
|
||||
|
|
@ -223,7 +235,6 @@ tests:
|
|||
mkdir tests
|
||||
|
||||
base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
|
||||
echo > base_lib
|
||||
rm -f dont_ar_1
|
||||
./if_mach SPARC SOLARIS touch dont_ar_1
|
||||
./if_mach SPARC SOLARIS $(AR) rus gc.a $(OBJS) dyn_load.o
|
||||
|
|
@ -231,9 +242,11 @@ base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
|
|||
./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
|
||||
echo > base_lib
|
||||
# Ignore ranlib failure; that usually means it doesn't exist, and
|
||||
# isn't needed.
|
||||
|
||||
cords: $(CORD_OBJS) cord/cordtest $(UTILS)
|
||||
cords: $(CORD_OBJS) cord/cordtest $(UTILS) base_lib
|
||||
rm -f dont_ar_3
|
||||
./if_mach SPARC SOLARIS touch dont_ar_3
|
||||
./if_mach SPARC SOLARIS $(AR) rus gc.a $(CORD_OBJS)
|
||||
|
|
@ -241,23 +254,27 @@ cords: $(CORD_OBJS) cord/cordtest $(UTILS)
|
|||
./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
|
||||
echo > cords
|
||||
|
||||
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)
|
||||
test_cpp: $(srcdir)/tests/test_cpp.cc $(srcdir)/include/gc_cpp.h $(srcdir)/include/gc.h \
|
||||
gc_cpp.o 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++
|
||||
check-cpp: test_cpp
|
||||
./test_cpp
|
||||
|
||||
c++-t: c++ test_cpp
|
||||
./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
|
||||
c++: gc_cpp.o $(srcdir)/include/gc_cpp.h base_lib
|
||||
rm -f dont_ar_4
|
||||
./if_mach SPARC SOLARIS touch dont_ar_4
|
||||
./if_mach SPARC SOLARIS $(AR) rus gc.a gc_cpp.o
|
||||
|
|
@ -265,7 +282,6 @@ c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp
|
|||
./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
|
||||
|
|
@ -278,12 +294,12 @@ sunos5gc.so: $(OBJS) dyn_load_sunos53.o
|
|||
|
||||
# Alpha/OSF shared library version of the collector
|
||||
libalphagc.so: $(OBJS)
|
||||
ld -shared -o libalphagc.so $(OBJS) dyn_load.o -lc
|
||||
$(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
|
||||
$(LD) -shared $(ABI_FLAG) -o libirixgc.so $(OBJS) dyn_load.o -lc
|
||||
ln libirixgc.so libgc.so
|
||||
|
||||
# Linux shared library version of the collector
|
||||
|
|
@ -303,33 +319,37 @@ dyn_test:
|
|||
#.SUFFIXES: .lo $(SUFFIXES)
|
||||
#
|
||||
#.c.lo:
|
||||
# $(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -c $< -o $@
|
||||
# $(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)/sparc_mach_dep.S \
|
||||
$(srcdir)/sparc_sunos4_mach_dep.s \
|
||||
$(srcdir)/ia64_save_regs_in_stack.s \
|
||||
$(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
|
||||
$(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 SPARC SOLARIS $(CC) -c -o mach_dep2.o $(srcdir)/sparc_mach_dep.S
|
||||
./if_mach SPARC OPENBSD $(AS) -o mach_dep2.o $(srcdir)/sparc_sunos4_mach_dep.s
|
||||
./if_mach SPARC NETBSD $(AS) -o mach_dep2.o $(srcdir)/sparc_netbsd_mach_dep.s
|
||||
./if_mach SPARC "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
|
||||
./if_mach SPARC "" ld -r -o mach_dep.o mach_dep1.o mach_dep2.o
|
||||
./if_mach IA64 "" as $(AS_ABI_FLAG) -o ia64_save_regs_in_stack.o $(srcdir)/ia64_save_regs_in_stack.s
|
||||
./if_mach SPARC "" $(LD) -r -o mach_dep.o mach_dep1.o mach_dep2.o
|
||||
./if_mach IA64 "" $(AS) -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
|
||||
./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
|
||||
-./if_not_there mach_dep.o `cygpath -w /bin/sh` $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
|
||||
-./if_not_there mach_dep.o /bin/sh $(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.
|
||||
-./if_not_there mark_rts.o $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
|
||||
-./if_not_there mark_rts.o `cygpath -w /bin/sh` $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
|
||||
-./if_not_there mark_rts.o /bin/sh $(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: include/gc_version.h
|
||||
|
||||
|
|
@ -349,17 +369,18 @@ 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/tests/cordtest.c $(CORD_OBJS) gc.a $(UTILS)
|
||||
cord/cordtest: $(srcdir)/cord/tests/cordtest.c $(CORD_OBJS) base_lib $(UTILS)
|
||||
rm -f cord/cordtest
|
||||
./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/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
|
||||
cord/de: $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o base_lib \
|
||||
$(UTILS)
|
||||
rm -f cord/de
|
||||
./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 SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/tests/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses -ltermlib -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 -lcurses -ltermlib -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`
|
||||
|
|
@ -378,12 +399,13 @@ 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 \
|
||||
base_lib c++ threadlibs $(CORD_OBJS) cord/cordtest cord/de
|
||||
rm -f gc.a *.i *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
|
||||
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
|
||||
base_lib c++ $(CORD_OBJS) cord/cordtest cord/de cords \
|
||||
dont_ar_* threadlibs
|
||||
-rm -f *~
|
||||
|
||||
gctest: tests/test.o gc.a $(UTILS)
|
||||
gctest: tests/test.o base_lib $(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`
|
||||
|
|
@ -396,7 +418,7 @@ gctest: tests/test.o gc.a $(UTILS)
|
|||
setjmp_test: $(srcdir)/tools/setjmp_t.c $(srcdir)/include/gc.h $(UTILS)
|
||||
$(CC) $(CFLAGS) -o setjmp_test $(srcdir)/tools/setjmp_t.c
|
||||
|
||||
test: KandRtest cord/cordtest
|
||||
check: KandRtest cord/cordtest
|
||||
cord/cordtest
|
||||
|
||||
# Those tests that work even with a K&R C compiler:
|
||||
|
|
@ -404,13 +426,16 @@ KandRtest: setjmp_test gctest
|
|||
./setjmp_test
|
||||
./gctest
|
||||
|
||||
# A synonym to "check" (for compatibility with older GC versions).
|
||||
test: check
|
||||
|
||||
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)/tools/gcname.c $(srcdir)/include/gc_version.h
|
||||
$(CC) -o gcname $(srcdir)/tools/gcname.c
|
||||
|
||||
#We assume this is being done from source directory.
|
||||
# We assume this is being done from source directory.
|
||||
dist gc.tar: $(SRCS) $(DOC_FILES) $(OTHER_FILES) add_gc_prefix gcname
|
||||
rm -f `./gcname`
|
||||
ln -s . `./gcname`
|
||||
|
|
@ -432,7 +457,7 @@ lint: $(CSRCS) tests/test.c
|
|||
# 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`
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -136,51 +136,50 @@ check_PROGRAMS = cordtest$(EXEEXT) gctest$(EXEEXT) leaktest$(EXEEXT) \
|
|||
middletest$(EXEEXT) smashtest$(EXEEXT) hugetest$(EXEEXT) \
|
||||
realloc_test$(EXEEXT) staticrootstest$(EXEEXT) $(am__EXEEXT_1) \
|
||||
$(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4)
|
||||
TESTS = cordtest$(EXEEXT) gctest$(EXEEXT) leaktest$(EXEEXT) \
|
||||
middletest$(EXEEXT) smashtest$(EXEEXT) hugetest$(EXEEXT) \
|
||||
realloc_test$(EXEEXT) staticrootstest$(EXEEXT) \
|
||||
$(am__append_12) $(am__append_14) $(am__append_16) \
|
||||
$(am__EXEEXT_4)
|
||||
@SINGLE_GC_OBJ_FALSE@am__append_1 = extra/gc.c
|
||||
@PTHREAD_START_STANDALONE_TRUE@@SINGLE_GC_OBJ_TRUE@am__append_1 = -DGC_PTHREAD_START_STANDALONE
|
||||
@PTHREAD_START_STANDALONE_TRUE@@SINGLE_GC_OBJ_TRUE@am__append_2 = pthread_start.c
|
||||
@SINGLE_GC_OBJ_FALSE@am__append_3 = extra/gc.c
|
||||
|
||||
# C Library: Architecture Dependent
|
||||
# ---------------------------------
|
||||
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@am__append_2 = win32_threads.c
|
||||
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_3 = pthread_start.c pthread_support.c
|
||||
@DARWIN_THREADS_TRUE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_4 = darwin_stop_world.c
|
||||
@DARWIN_THREADS_FALSE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_5 = pthread_stop_world.c
|
||||
@MAKE_BACK_GRAPH_TRUE@@SINGLE_GC_OBJ_FALSE@am__append_6 = backgraph.c
|
||||
@ENABLE_DISCLAIM_TRUE@@SINGLE_GC_OBJ_FALSE@am__append_7 = fnlz_mlc.c
|
||||
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@am__append_4 = thread_local_alloc.c win32_threads.c
|
||||
# Not Cygwin or MinGW.
|
||||
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_5 = pthread_start.c pthread_support.c thread_local_alloc.c
|
||||
@DARWIN_THREADS_TRUE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_6 = darwin_stop_world.c
|
||||
@DARWIN_THREADS_FALSE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__append_7 = pthread_stop_world.c
|
||||
@MAKE_BACK_GRAPH_TRUE@@SINGLE_GC_OBJ_FALSE@am__append_8 = backgraph.c
|
||||
@ENABLE_DISCLAIM_TRUE@@SINGLE_GC_OBJ_FALSE@am__append_9 = fnlz_mlc.c
|
||||
|
||||
# C++ Interface
|
||||
# -------------
|
||||
@CPLUSPLUS_TRUE@am__append_8 = libgccpp.la
|
||||
@CPLUSPLUS_TRUE@am__append_9 = include/gc_cpp.h
|
||||
@CPLUSPLUS_TRUE@am__append_10 = include/extra/gc_cpp.h
|
||||
@THREADS_TRUE@am__append_11 = $(THREADDLLIBS)
|
||||
@KEEP_BACK_PTRS_TRUE@am__append_12 = tracetest$(EXEEXT)
|
||||
@KEEP_BACK_PTRS_TRUE@am__append_13 = tracetest
|
||||
@THREADS_TRUE@am__append_14 = threadleaktest$(EXEEXT) \
|
||||
@CPLUSPLUS_TRUE@am__append_10 = libgccpp.la
|
||||
@CPLUSPLUS_TRUE@am__append_11 = include/gc_cpp.h
|
||||
@CPLUSPLUS_TRUE@am__append_12 = include/extra/gc_cpp.h
|
||||
@THREADS_TRUE@am__append_13 = $(THREADDLLIBS)
|
||||
@KEEP_BACK_PTRS_TRUE@am__append_14 = tracetest$(EXEEXT)
|
||||
@KEEP_BACK_PTRS_TRUE@am__append_15 = tracetest
|
||||
@THREADS_TRUE@am__append_16 = threadleaktest$(EXEEXT) \
|
||||
@THREADS_TRUE@ threadkey_test$(EXEEXT) \
|
||||
@THREADS_TRUE@ subthreadcreate_test$(EXEEXT) \
|
||||
@THREADS_TRUE@ initsecondarythread_test$(EXEEXT)
|
||||
@THREADS_TRUE@am__append_15 = threadleaktest threadkey_test \
|
||||
@THREADS_TRUE@am__append_17 = threadleaktest threadkey_test \
|
||||
@THREADS_TRUE@ subthreadcreate_test initsecondarythread_test
|
||||
@CPLUSPLUS_TRUE@am__append_16 = test_cpp$(EXEEXT)
|
||||
@CPLUSPLUS_TRUE@am__append_17 = test_cpp
|
||||
@ENABLE_DISCLAIM_TRUE@am__append_18 = disclaim_test disclaim_bench
|
||||
@ENABLE_DISCLAIM_TRUE@am__append_19 = disclaim_test disclaim_bench
|
||||
@ENABLE_DISCLAIM_TRUE@@THREADS_TRUE@am__append_20 = $(THREADDLLIBS)
|
||||
@CPLUSPLUS_TRUE@am__append_18 = test_cpp$(EXEEXT)
|
||||
@CPLUSPLUS_TRUE@am__append_19 = test_cpp
|
||||
@ENABLE_DISCLAIM_TRUE@am__append_20 = disclaim_test$(EXEEXT) \
|
||||
@ENABLE_DISCLAIM_TRUE@ disclaim_bench$(EXEEXT)
|
||||
@ENABLE_DISCLAIM_TRUE@am__append_21 = disclaim_test disclaim_bench
|
||||
@ENABLE_DISCLAIM_TRUE@@THREADS_TRUE@am__append_22 = $(THREADDLLIBS)
|
||||
subdir = .
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/gc_set_version.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
|
||||
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
|
||||
$(am__configure_deps) $(dist_pkgdata_DATA) \
|
||||
$(am__configure_deps) $(am__dist_doc_DATA_DIST) \
|
||||
$(dist_noinst_HEADERS) $(am__include_HEADERS_DIST) \
|
||||
$(am__pkginclude_HEADERS_DIST) $(am__DIST_COMMON)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
|
|
@ -216,9 +215,9 @@ am__uninstall_files_from_dir = { \
|
|||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgdatadir)" \
|
||||
"$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" \
|
||||
"$(DESTDIR)$(pkgincludedir)"
|
||||
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" \
|
||||
"$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" \
|
||||
"$(DESTDIR)$(includedir)" "$(DESTDIR)$(pkgincludedir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
libcord_la_DEPENDENCIES = $(top_builddir)/libgc.la
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
|
|
@ -238,19 +237,21 @@ am__libgc_la_SOURCES_DIST = allchblk.c alloc.c blacklst.c checksums.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 win32_threads.c \
|
||||
typd_mlc.c thread_local_alloc.c win32_threads.c \
|
||||
pthread_start.c pthread_support.c darwin_stop_world.c \
|
||||
pthread_stop_world.c backgraph.c fnlz_mlc.c extra/gc.c
|
||||
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@am__objects_1 = \
|
||||
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@am__objects_1 = thread_local_alloc.lo \
|
||||
@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_TRUE@ win32_threads.lo
|
||||
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__objects_2 = pthread_start.lo \
|
||||
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@ pthread_support.lo
|
||||
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@ pthread_support.lo \
|
||||
@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@ thread_local_alloc.lo
|
||||
@DARWIN_THREADS_TRUE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__objects_3 = darwin_stop_world.lo
|
||||
@DARWIN_THREADS_FALSE@@PTHREADS_TRUE@@SINGLE_GC_OBJ_FALSE@@WIN32_THREADS_FALSE@am__objects_4 = pthread_stop_world.lo
|
||||
@MAKE_BACK_GRAPH_TRUE@@SINGLE_GC_OBJ_FALSE@am__objects_5 = \
|
||||
@MAKE_BACK_GRAPH_TRUE@@SINGLE_GC_OBJ_FALSE@ backgraph.lo
|
||||
@ENABLE_DISCLAIM_TRUE@@SINGLE_GC_OBJ_FALSE@am__objects_6 = \
|
||||
@ENABLE_DISCLAIM_TRUE@@SINGLE_GC_OBJ_FALSE@ fnlz_mlc.lo
|
||||
@PTHREAD_START_STANDALONE_TRUE@@SINGLE_GC_OBJ_TRUE@am__objects_7 = pthread_start.lo
|
||||
@SINGLE_GC_OBJ_FALSE@am_libgc_la_OBJECTS = allchblk.lo alloc.lo \
|
||||
@SINGLE_GC_OBJ_FALSE@ blacklst.lo checksums.lo dbg_mlc.lo \
|
||||
@SINGLE_GC_OBJ_FALSE@ dyn_load.lo finalize.lo gc_dlopen.lo \
|
||||
|
|
@ -259,15 +260,14 @@ am__libgc_la_SOURCES_DIST = allchblk.c alloc.c blacklst.c checksums.c \
|
|||
@SINGLE_GC_OBJ_FALSE@ misc.lo new_hblk.lo obj_map.lo os_dep.lo \
|
||||
@SINGLE_GC_OBJ_FALSE@ pcr_interface.lo ptr_chck.lo \
|
||||
@SINGLE_GC_OBJ_FALSE@ real_malloc.lo reclaim.lo specific.lo \
|
||||
@SINGLE_GC_OBJ_FALSE@ stubborn.lo thread_local_alloc.lo \
|
||||
@SINGLE_GC_OBJ_FALSE@ typd_mlc.lo $(am__objects_1) \
|
||||
@SINGLE_GC_OBJ_FALSE@ stubborn.lo typd_mlc.lo $(am__objects_1) \
|
||||
@SINGLE_GC_OBJ_FALSE@ $(am__objects_2) $(am__objects_3) \
|
||||
@SINGLE_GC_OBJ_FALSE@ $(am__objects_4) $(am__objects_5) \
|
||||
@SINGLE_GC_OBJ_FALSE@ $(am__objects_6)
|
||||
@SINGLE_GC_OBJ_TRUE@am_libgc_la_OBJECTS = extra/gc.lo $(am__objects_1) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__objects_2) $(am__objects_3) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__objects_4) $(am__objects_5) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__objects_6)
|
||||
@SINGLE_GC_OBJ_TRUE@am_libgc_la_OBJECTS = extra/gc.lo $(am__objects_7) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__objects_1) $(am__objects_2) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__objects_3) $(am__objects_4) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__objects_5) $(am__objects_6)
|
||||
@NEED_ATOMIC_OPS_ASM_FALSE@@USE_INTERNAL_LIBATOMIC_OPS_TRUE@nodist_libgc_la_OBJECTS = libatomic_ops/src/atomic_ops.lo
|
||||
@NEED_ATOMIC_OPS_ASM_TRUE@nodist_libgc_la_OBJECTS = libatomic_ops/src/atomic_ops_sysdeps.lo
|
||||
libgc_la_OBJECTS = $(am_libgc_la_OBJECTS) $(nodist_libgc_la_OBJECTS)
|
||||
|
|
@ -505,7 +505,21 @@ am__can_run_installinfo = \
|
|||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
DATA = $(dist_pkgdata_DATA) $(pkgconfig_DATA)
|
||||
man3dir = $(mandir)/man3
|
||||
NROFF = nroff
|
||||
MANS = $(dist_man3_MANS)
|
||||
am__dist_doc_DATA_DIST = AUTHORS README.md 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.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/debugging.html \
|
||||
doc/finalization.html 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
|
||||
DATA = $(dist_doc_DATA) $(pkgconfig_DATA)
|
||||
am__include_HEADERS_DIST = include/extra/gc_cpp.h include/extra/gc.h
|
||||
am__pkginclude_HEADERS_DIST = include/gc_cpp.h include/gc.h \
|
||||
include/gc_allocator.h include/gc_backptr.h \
|
||||
|
|
@ -722,12 +736,12 @@ TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
|
|||
TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
|
||||
$(TEST_LOG_FLAGS)
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/bdw-gc.pc.in \
|
||||
$(srcdir)/cord/cord.am $(srcdir)/doc/doc.am \
|
||||
$(srcdir)/include/include.am $(srcdir)/tests/tests.am \
|
||||
$(top_srcdir)/include/config.h.in AUTHORS ChangeLog TODO \
|
||||
compile config.guess config.sub depcomp install-sh ltmain.sh \
|
||||
missing test-driver
|
||||
am__DIST_COMMON = $(dist_man3_MANS) $(srcdir)/Makefile.in \
|
||||
$(srcdir)/bdw-gc.pc.in $(srcdir)/cord/cord.am \
|
||||
$(srcdir)/doc/doc.am $(srcdir)/include/include.am \
|
||||
$(srcdir)/tests/tests.am $(top_srcdir)/include/config.h.in \
|
||||
AUTHORS ChangeLog compile config.guess config.sub depcomp \
|
||||
install-sh ltmain.sh missing test-driver
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
|
|
@ -763,20 +777,18 @@ am__relativize = \
|
|||
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
|
||||
done; \
|
||||
reldir="$$dir2"
|
||||
DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
DIST_TARGETS = dist-bzip2 dist-gzip
|
||||
DIST_TARGETS = dist-gzip
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
|
||||
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_CFLAGS = @GC_CFLAGS@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_builddir)/include -I$(top_srcdir)/include \
|
||||
$(ATOMIC_OPS_CFLAGS)
|
||||
|
||||
AM_CFLAGS = $(WERROR_CFLAGS) @GC_CFLAGS@
|
||||
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include \
|
||||
$(ATOMIC_OPS_CFLAGS) $(am__append_1)
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
ATOMIC_OPS_CFLAGS = @ATOMIC_OPS_CFLAGS@
|
||||
|
|
@ -790,13 +802,14 @@ CCAS = @CCAS@
|
|||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@ $(DEFS)
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CFLAGS = @CFLAGS@ $(CFLAGS_EXTRA)
|
||||
CFLAGS_EXTRA = @CFLAGS_EXTRA@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CXXFLAGS = @CXXFLAGS@ $(CFLAGS_EXTRA)
|
||||
CXXLIBS = @CXXLIBS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
|
|
@ -857,6 +870,7 @@ STRIP = @STRIP@
|
|||
THREADDLLIBS = @THREADDLLIBS@
|
||||
UNWINDLIBS = @UNWINDLIBS@
|
||||
VERSION = @VERSION@
|
||||
WERROR_CFLAGS = @WERROR_CFLAGS@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
|
|
@ -920,11 +934,17 @@ top_build_prefix = @top_build_prefix@
|
|||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
# Info (current:revision:age) for the Libtool versioning system.
|
||||
# These numbers should be updated at most once just before the release,
|
||||
# and, optionally, at most once during the development (after the release).
|
||||
LIBGC_VER_INFO = 4:4:3
|
||||
LIBGCCPP_VER_INFO = 4:2:3
|
||||
|
||||
# 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
|
||||
# Thus there seems to be no real reason to recursively build in the
|
||||
# libatomic_ops directory.
|
||||
# if USE_INTERNAL_LIBATOMICS_OPS
|
||||
# SUBDIRS = @maybe_libatomic_ops@
|
||||
|
|
@ -934,12 +954,6 @@ top_srcdir = @top_srcdir@
|
|||
SUBDIRS =
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
# Initialize variables so that we can declare files locally.
|
||||
|
||||
# FIXME: If Visual C++ users use Makefile.am, this should go into
|
||||
# pkginclude_HEADERS with proper AM_CONDITIONALization. Otherwise
|
||||
# delete this comment.
|
||||
|
||||
# headers which are not installed
|
||||
# (see include/include.am for more)
|
||||
#
|
||||
|
|
@ -952,16 +966,14 @@ ACLOCAL_AMFLAGS = -I m4
|
|||
|
||||
# files used by makefiles other than Makefile.am
|
||||
#
|
||||
EXTRA_DIST = $(am__append_1) gc_cpp.cpp README.QUICK TODO BCC_MAKEFILE \
|
||||
EXTRA_DIST = $(am__append_3) gc_cpp.cpp README.QUICK BCC_MAKEFILE \
|
||||
NT_MAKEFILE OS2_MAKEFILE PCR-Makefile digimars.mak \
|
||||
EMX_MAKEFILE Makefile.direct SMakefile.amiga WCC_MAKEFILE \
|
||||
autogen.sh NT_STATIC_THREADS_MAKEFILE \
|
||||
NT_X64_STATIC_THREADS_MAKEFILE NT_X64_THREADS_MAKEFILE \
|
||||
CMakeLists.txt tests/CMakeLists.txt 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 \
|
||||
autogen.sh CMakeLists.txt tests/CMakeLists.txt \
|
||||
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 \
|
||||
|
|
@ -972,14 +984,14 @@ EXTRA_DIST = $(am__append_1) gc_cpp.cpp README.QUICK TODO BCC_MAKEFILE \
|
|||
|
||||
# C Library
|
||||
# ---------
|
||||
lib_LTLIBRARIES = libgc.la $(am__append_8) libcord.la
|
||||
lib_LTLIBRARIES = libgc.la $(am__append_10) libcord.la
|
||||
|
||||
# unprefixed header
|
||||
include_HEADERS = $(am__append_10) include/extra/gc.h
|
||||
include_HEADERS = $(am__append_12) include/extra/gc.h
|
||||
|
||||
# installed headers
|
||||
#
|
||||
pkginclude_HEADERS = $(am__append_9) include/gc.h \
|
||||
pkginclude_HEADERS = $(am__append_11) 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 \
|
||||
|
|
@ -1001,6 +1013,11 @@ dist_noinst_HEADERS = include/cord.h include/cord_pos.h include/ec.h \
|
|||
include/private/thread_local_alloc.h
|
||||
check_LTLIBRARIES = libstaticrootslib_test.la \
|
||||
libstaticrootslib2_test.la
|
||||
TESTS = cordtest$(EXEEXT) gctest$(EXEEXT) leaktest$(EXEEXT) \
|
||||
middletest$(EXEEXT) smashtest$(EXEEXT) hugetest$(EXEEXT) \
|
||||
realloc_test$(EXEEXT) staticrootstest$(EXEEXT) \
|
||||
$(am__append_14) $(am__append_16) $(am__append_18) \
|
||||
$(am__append_20)
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = bdw-gc.pc
|
||||
@SINGLE_GC_OBJ_FALSE@libgc_la_SOURCES = allchblk.c alloc.c blacklst.c \
|
||||
|
|
@ -1010,15 +1027,14 @@ pkgconfig_DATA = bdw-gc.pc
|
|||
@SINGLE_GC_OBJ_FALSE@ mark.c mark_rts.c misc.c new_hblk.c \
|
||||
@SINGLE_GC_OBJ_FALSE@ obj_map.c os_dep.c pcr_interface.c \
|
||||
@SINGLE_GC_OBJ_FALSE@ ptr_chck.c real_malloc.c reclaim.c \
|
||||
@SINGLE_GC_OBJ_FALSE@ specific.c stubborn.c \
|
||||
@SINGLE_GC_OBJ_FALSE@ thread_local_alloc.c typd_mlc.c \
|
||||
@SINGLE_GC_OBJ_FALSE@ $(am__append_2) $(am__append_3) \
|
||||
@SINGLE_GC_OBJ_FALSE@ specific.c stubborn.c typd_mlc.c \
|
||||
@SINGLE_GC_OBJ_FALSE@ $(am__append_4) $(am__append_5) \
|
||||
@SINGLE_GC_OBJ_FALSE@ $(am__append_6) $(am__append_7)
|
||||
@SINGLE_GC_OBJ_FALSE@ $(am__append_6) $(am__append_7) \
|
||||
@SINGLE_GC_OBJ_FALSE@ $(am__append_8) $(am__append_9)
|
||||
@SINGLE_GC_OBJ_TRUE@libgc_la_SOURCES = extra/gc.c $(am__append_2) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__append_3) $(am__append_4) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__append_5) $(am__append_6) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__append_7)
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__append_4) $(am__append_5) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__append_6) $(am__append_7) \
|
||||
@SINGLE_GC_OBJ_TRUE@ $(am__append_8) $(am__append_9)
|
||||
@NEED_ATOMIC_OPS_ASM_TRUE@nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops_sysdeps.S
|
||||
@USE_INTERNAL_LIBATOMIC_OPS_TRUE@nodist_libgc_la_SOURCES = libatomic_ops/src/atomic_ops.c
|
||||
|
||||
|
|
@ -1026,13 +1042,15 @@ pkgconfig_DATA = bdw-gc.pc
|
|||
# linuxthread semaphore functions get linked:
|
||||
libgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS) $(ATOMIC_OPS_LIBS)
|
||||
libgc_la_DEPENDENCIES = @addobjs@
|
||||
libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info 1:3:0 -no-undefined
|
||||
libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info $(LIBGC_VER_INFO) \
|
||||
-no-undefined
|
||||
|
||||
EXTRA_libgc_la_SOURCES = ia64_save_regs_in_stack.s sparc_mach_dep.S \
|
||||
sparc_netbsd_mach_dep.s sparc_sunos4_mach_dep.s
|
||||
|
||||
@CPLUSPLUS_TRUE@libgccpp_la_SOURCES = gc_cpp.cc
|
||||
@CPLUSPLUS_TRUE@libgccpp_la_LIBADD = ./libgc.la
|
||||
@CPLUSPLUS_TRUE@libgccpp_la_LDFLAGS = -version-info 1:3:0 -no-undefined
|
||||
@CPLUSPLUS_TRUE@libgccpp_la_LDFLAGS = -version-info $(LIBGCCPP_VER_INFO) -no-undefined
|
||||
|
||||
# Misc
|
||||
# ----
|
||||
|
|
@ -1047,8 +1065,13 @@ AM_CXXFLAGS = @GC_CFLAGS@
|
|||
#include/private/pthread_stop_world.h \
|
||||
#include/gc_mark.h @addincludes@
|
||||
@ASM_WITH_CPP_UNSUPPORTED_TRUE@ASM_CPP_OPTIONS =
|
||||
|
||||
# Info (current:revision:age) for the Libtool versioning system.
|
||||
# These numbers should be updated at most once just before the release,
|
||||
# and, optionally, at most once during the development (after the release).
|
||||
LIBCORD_VER_INFO = 4:1:3
|
||||
libcord_la_LIBADD = $(top_builddir)/libgc.la
|
||||
libcord_la_LDFLAGS = -version-info 1:3:0 -no-undefined
|
||||
libcord_la_LDFLAGS = -version-info $(LIBCORD_VER_INFO) -no-undefined
|
||||
libcord_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libcord_la_SOURCES = \
|
||||
cord/cordbscs.c \
|
||||
|
|
@ -1061,7 +1084,7 @@ cordtest_LDADD = $(top_builddir)/libgc.la $(top_builddir)/libcord.la
|
|||
# Common libs to _LDADD for all tests.
|
||||
test_ldadd = $(top_builddir)/libgc.la $(EXTRA_TEST_LIBS)
|
||||
gctest_SOURCES = tests/test.c
|
||||
gctest_LDADD = $(test_ldadd) $(am__append_11)
|
||||
gctest_LDADD = $(test_ldadd) $(am__append_13)
|
||||
gctest_DEPENDENCIES = $(top_builddir)/libgc.la
|
||||
leaktest_SOURCES = tests/leak_test.c
|
||||
leaktest_LDADD = $(test_ldadd)
|
||||
|
|
@ -1105,48 +1128,47 @@ libstaticrootslib2_test_la_LDFLAGS = -version-info 1:3:0 -no-undefined \
|
|||
@AVOID_CPP_LIB_TRUE@@CPLUSPLUS_TRUE@test_cpp_LDADD = gc_cpp.o $(test_ldadd) $(CXXLIBS)
|
||||
@ENABLE_DISCLAIM_TRUE@disclaim_test_SOURCES = tests/disclaim_test.c
|
||||
@ENABLE_DISCLAIM_TRUE@disclaim_test_LDADD = $(test_ldadd) \
|
||||
@ENABLE_DISCLAIM_TRUE@ $(am__append_20)
|
||||
@ENABLE_DISCLAIM_TRUE@ $(am__append_22)
|
||||
@ENABLE_DISCLAIM_TRUE@disclaim_bench_SOURCES = tests/disclaim_bench.c
|
||||
@ENABLE_DISCLAIM_TRUE@disclaim_bench_LDADD = $(test_ldadd)
|
||||
|
||||
# installed documentation
|
||||
#
|
||||
dist_pkgdata_DATA = \
|
||||
AUTHORS \
|
||||
README.md \
|
||||
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.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/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
|
||||
@ENABLE_DOCS_TRUE@dist_doc_DATA = \
|
||||
@ENABLE_DOCS_TRUE@ AUTHORS \
|
||||
@ENABLE_DOCS_TRUE@ README.md \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.DGUX386 \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.Mac \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.OS2 \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.amiga \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.arm.cross \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.autoconf \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.cmake \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.cords \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.darwin \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.environment \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.ews4800 \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.hp \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.linux \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.macros \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.rs6000 \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.sgi \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.solaris2 \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.symbian \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.uts \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.win32 \
|
||||
@ENABLE_DOCS_TRUE@ doc/README.win64 \
|
||||
@ENABLE_DOCS_TRUE@ doc/debugging.html \
|
||||
@ENABLE_DOCS_TRUE@ doc/finalization.html \
|
||||
@ENABLE_DOCS_TRUE@ doc/gcdescr.html \
|
||||
@ENABLE_DOCS_TRUE@ doc/gcinterface.html \
|
||||
@ENABLE_DOCS_TRUE@ doc/leak.html \
|
||||
@ENABLE_DOCS_TRUE@ doc/overview.html \
|
||||
@ENABLE_DOCS_TRUE@ doc/porting.html \
|
||||
@ENABLE_DOCS_TRUE@ doc/scale.html \
|
||||
@ENABLE_DOCS_TRUE@ doc/simple_example.html \
|
||||
@ENABLE_DOCS_TRUE@ doc/tree.html
|
||||
|
||||
@ENABLE_DOCS_TRUE@dist_man3_MANS = doc/gc.man
|
||||
all: all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
|
|
@ -1615,27 +1637,68 @@ clean-libtool:
|
|||
|
||||
distclean-libtool:
|
||||
-rm -f libtool config.lt
|
||||
install-dist_pkgdataDATA: $(dist_pkgdata_DATA)
|
||||
install-man3: $(dist_man3_MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
|
||||
@list1='$(dist_man3_MANS)'; \
|
||||
list2=''; \
|
||||
test -n "$(man3dir)" \
|
||||
&& test -n "`echo $$list1$$list2`" \
|
||||
|| exit 0; \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \
|
||||
{ for i in $$list1; do echo "$$i"; done; \
|
||||
if test -n "$$list2"; then \
|
||||
for i in $$list2; do echo "$$i"; done \
|
||||
| sed -n '/\.3[a-z]*$$/p'; \
|
||||
fi; \
|
||||
} | while read p; do \
|
||||
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; echo "$$p"; \
|
||||
done | \
|
||||
sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
|
||||
sed 'N;N;s,\n, ,g' | { \
|
||||
list=; while read file base inst; do \
|
||||
if test "$$base" = "$$inst"; then list="$$list $$file"; else \
|
||||
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
|
||||
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \
|
||||
fi; \
|
||||
done; \
|
||||
for i in $$list; do echo "$$i"; done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
test -z "$$files" || { \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \
|
||||
done; }
|
||||
|
||||
uninstall-man3:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(dist_man3_MANS)'; test -n "$(man3dir)" || exit 0; \
|
||||
files=`{ for i in $$list; do echo "$$i"; done; \
|
||||
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
|
||||
dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir)
|
||||
install-dist_docDATA: $(dist_doc_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-dist_pkgdataDATA:
|
||||
uninstall-dist_docDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
|
||||
@list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir)
|
||||
dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
|
||||
install-pkgconfigDATA: $(pkgconfig_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
|
||||
|
|
@ -2141,6 +2204,7 @@ distdir: $(DISTFILES)
|
|||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
|
||||
$(am__post_remove_distdir)
|
||||
|
|
@ -2265,10 +2329,10 @@ check-am: all-am
|
|||
$(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) $(check_PROGRAMS)
|
||||
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
|
||||
check: check-recursive
|
||||
all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
|
||||
all-am: Makefile $(LTLIBRARIES) $(MANS) $(DATA) $(HEADERS)
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgdatadir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(pkgincludedir)"; do \
|
||||
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(pkgincludedir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-recursive
|
||||
|
|
@ -2338,8 +2402,8 @@ info: info-recursive
|
|||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-dist_pkgdataDATA install-includeHEADERS \
|
||||
install-pkgconfigDATA install-pkgincludeHEADERS
|
||||
install-data-am: install-dist_docDATA install-includeHEADERS \
|
||||
install-man install-pkgconfigDATA install-pkgincludeHEADERS
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
|
|
@ -2355,7 +2419,7 @@ install-info: install-info-recursive
|
|||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
install-man: install-man3
|
||||
|
||||
install-pdf: install-pdf-recursive
|
||||
|
||||
|
|
@ -2387,10 +2451,12 @@ ps: ps-recursive
|
|||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-dist_pkgdataDATA uninstall-includeHEADERS \
|
||||
uninstall-libLTLIBRARIES uninstall-pkgconfigDATA \
|
||||
uninstall-am: uninstall-dist_docDATA uninstall-includeHEADERS \
|
||||
uninstall-libLTLIBRARIES uninstall-man uninstall-pkgconfigDATA \
|
||||
uninstall-pkgincludeHEADERS
|
||||
|
||||
uninstall-man: uninstall-man3
|
||||
|
||||
.MAKE: $(am__recursive_targets) check-am install-am install-strip
|
||||
|
||||
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
|
||||
|
|
@ -2403,19 +2469,19 @@ uninstall-am: uninstall-dist_pkgdataDATA uninstall-includeHEADERS \
|
|||
distclean-hdr distclean-libtool distclean-tags distcleancheck \
|
||||
distdir distuninstallcheck dvi dvi-am html html-am info \
|
||||
info-am install install-am install-data install-data-am \
|
||||
install-dist_pkgdataDATA install-dvi install-dvi-am \
|
||||
install-exec install-exec-am install-html install-html-am \
|
||||
install-dist_docDATA install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am \
|
||||
install-includeHEADERS install-info install-info-am \
|
||||
install-libLTLIBRARIES install-man install-pdf install-pdf-am \
|
||||
install-pkgconfigDATA install-pkgincludeHEADERS install-ps \
|
||||
install-ps-am install-strip installcheck installcheck-am \
|
||||
installdirs installdirs-am maintainer-clean \
|
||||
install-libLTLIBRARIES install-man install-man3 install-pdf \
|
||||
install-pdf-am install-pkgconfigDATA install-pkgincludeHEADERS \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs installdirs-am maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
recheck tags tags-am uninstall uninstall-am \
|
||||
uninstall-dist_pkgdataDATA uninstall-includeHEADERS \
|
||||
uninstall-libLTLIBRARIES uninstall-pkgconfigDATA \
|
||||
uninstall-pkgincludeHEADERS
|
||||
uninstall-dist_docDATA uninstall-includeHEADERS \
|
||||
uninstall-libLTLIBRARIES uninstall-man uninstall-man3 \
|
||||
uninstall-pkgconfigDATA uninstall-pkgincludeHEADERS
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
|
@ -2432,9 +2498,6 @@ uninstall-am: uninstall-dist_pkgdataDATA uninstall-includeHEADERS \
|
|||
.S.s:
|
||||
if $(CPP) $< >$@ ; then :; else rm -f $@; fi
|
||||
|
||||
# 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.
|
||||
|
||||
# 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:
|
||||
|
|
|
|||
|
|
@ -1,61 +1,135 @@
|
|||
# Makefile for Windows NT. Assumes Microsoft compiler, and a single thread.
|
||||
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
|
||||
# Makefile for Windows NT. Assumes Microsoft compiler.
|
||||
# Should be invoked as "nmake -f NT_MAKEFILE [<args>]"; the optional arguments
|
||||
# are: "cpu=AMD64" - to target x64, "cpu=i386" - to target x86,
|
||||
# "make_as_lib=1" - to build it as a static library, "nodebug=1" - to produce
|
||||
# the release variant of the library, "nothreads=1" - to build the library and
|
||||
# the tests without threads support.
|
||||
|
||||
MY_CPU=X86
|
||||
CPU=$(MY_CPU)
|
||||
!include <ntwin32.mak>
|
||||
cc = cl
|
||||
link = link
|
||||
rc = rc
|
||||
|
||||
!IF !DEFINED(CPU) || "$(CPU)" == ""
|
||||
CPU = $(PROCESSOR_ARCHITECTURE)
|
||||
!ENDIF
|
||||
!IF "$(CPU)" == "I386" || "$(CPU)" == "X86" || "$(CPU)" == "x86"
|
||||
CPU = i386
|
||||
!ELSEIF "$(CPU)" == "X64" || "$(CPU)" == "x64" || "$(CPU)" == "amd64"
|
||||
CPU = AMD64
|
||||
!ENDIF
|
||||
|
||||
!IF !DEFINED(NMAKE_WINVER)
|
||||
NMAKE_WINVER = 0x0600
|
||||
!ENDIF
|
||||
|
||||
cflags = $(cflags) -c -DCRTAPI1=_cdecl -DCRTAPI2=_cdecl -GS -D_WINNT -W4
|
||||
!IF "$(CPU)" == "i386"
|
||||
cflags = $(cflags) -D_X86_=1 -DWIN32 -D_WIN32
|
||||
!ELSEIF "$(CPU)" == "AMD64"
|
||||
cflags = $(cflags) -D_AMD64_=1 -DWIN64 -D_WIN64 -DWIN32 -D_WIN32
|
||||
!ENDIF
|
||||
cflags = $(cflags) -D_WIN32_WINNT=$(NMAKE_WINVER) -DWINVER=$(NMAKE_WINVER)
|
||||
|
||||
!IFDEF NODEBUG
|
||||
cvarsmt = -D_MT -MT
|
||||
cdebug = -Ox -DNDEBUG
|
||||
rcvars = -DWIN32 -D_WIN32 -DWINVER=$(NMAKE_WINVER)
|
||||
ldebug = /RELEASE
|
||||
!ELSE
|
||||
cvarsmt = -D_MT -MTd
|
||||
cdebug = -Zi -Od -DDEBUG
|
||||
rcvars = -DWIN32 -D_WIN32 -DWINVER=$(NMAKE_WINVER) -DDEBUG -D_DEBUG
|
||||
ldebug = /DEBUG /DEBUGTYPE:cv
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CPU)" == "i386"
|
||||
CVTRES_CPU=X86
|
||||
!ELSEIF "$(CPU)" == "AMD64"
|
||||
CVTRES_CPU=X64
|
||||
!ENDIF
|
||||
|
||||
!IFNDEF NOTHREADS
|
||||
CFLAGS_MT=$(cvarsmt) -DGC_THREADS -DTHREAD_LOCAL_ALLOC -DPARALLEL_MARK
|
||||
!ENDIF
|
||||
|
||||
!IFDEF MAKE_AS_LIB
|
||||
CFLAGS_GCDLL=-DGC_NOT_DLL
|
||||
GC_LIB=gc.lib
|
||||
LINK_GC=lib /out:$(GC_LIB)
|
||||
!ELSE
|
||||
CFLAGS_GCDLL=-DGC_DLL
|
||||
!IF "$(CPU)" == "AMD64"
|
||||
GC_DLL=gc64.dll
|
||||
GC_LIB=gc64_dll.lib
|
||||
!ELSE
|
||||
GC_DLL=gc.dll
|
||||
GC_LIB=gc_dll.lib
|
||||
!ENDIF
|
||||
LINK_DLL_FLAGS=kernel32.lib user32.lib /subsystem:windows /dll \
|
||||
/INCREMENTAL:NO /pdb:"gc.pdb" /out:$(GC_DLL) /implib:$(GC_LIB)
|
||||
LINK_GC=$(link) $(ldebug) $(LINK_DLL_FLAGS)
|
||||
!ENDIF
|
||||
|
||||
CFLAGS_SPECIFIC=$(CFLAGS_GCDLL) $(CFLAGS_MT)
|
||||
|
||||
# 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
|
||||
# Atomic_ops installation directory. For win32, the source directory
|
||||
# should do, since we only need the headers.
|
||||
# We assume this was manually unpacked.
|
||||
AO_SRC_DIR=libatomic_ops/src
|
||||
AO_INCLUDE_DIR=$(AO_SRC_DIR)
|
||||
|
||||
OBJS= misc.obj win32_threads.obj alloc.obj reclaim.obj allchblk.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 thread_local_alloc.obj
|
||||
|
||||
all: gctest.exe cord\de.exe test_cpp.exe
|
||||
|
||||
.c.obj:
|
||||
$(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj
|
||||
$(cc) $(cdebug) $(cflags) $(CFLAGS_SPECIFIC) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DCORD_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.c /Fo$*.obj /wd4100 /wd4127 /wd4701
|
||||
# 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) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -D_CRT_SECURE_NO_DEPRECATE $*.cpp /Fo$*.obj
|
||||
$(cc) $(cdebug) $(cflags) $(CFLAGS_SPECIFIC) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -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
|
||||
$(GC_LIB): $(OBJS)
|
||||
$(LINK_GC) /MACHINE:$(CPU) $(OBJS)
|
||||
|
||||
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:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
|
||||
gctest.exe: $(GC_LIB) tests\test.obj
|
||||
$(link) /MACHINE:$(CPU) /INCREMENTAL:NO $(ldebug) $(lflags) user32.lib -out:$*.exe tests\test.obj $(GC_LIB)
|
||||
# mapsympe -n -o gctest.sym gctest.exe
|
||||
# This produces a GUI app that opens no window and writes to gctest.gc.log.
|
||||
|
||||
cord\de_win.rbj: cord\de_win.res
|
||||
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
|
||||
cord\tests\de_win.rbj: cord\tests\de_win.res
|
||||
cvtres /MACHINE:$(CVTRES_CPU) /OUT:cord\tests\de_win.rbj cord\tests\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\tests\de_win.res: cord\tests\de_win.rc cord\tests\de_win.h cord\tests\de_cmds.h
|
||||
$(rc) $(rcvars) -r -fo cord\tests\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)
|
||||
# Cord/de is a real win32 GUI app.
|
||||
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\tests\de_win.rbj $(GC_LIB)
|
||||
$(link) /MACHINE:$(CPU) /INCREMENTAL:NO $(ldebug) $(lflags) -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\tests\de.obj cord\tests\de_win.obj cord\tests\de_win.rbj $(GC_LIB) gdi32.lib user32.lib
|
||||
|
||||
gc_cpp.obj: include\gc_cpp.h include\gc.h
|
||||
|
||||
gc_cpp.cpp: gc_cpp.cc
|
||||
# copy gc_cpp.cc gc_cpp.cpp
|
||||
gc_cpp.obj: gc_cpp.cc include\gc_cpp.h include\gc.h
|
||||
|
||||
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)
|
||||
# The output appears in test_cpp.gc.log file.
|
||||
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h $(GC_LIB)
|
||||
$(link) /MACHINE:$(CPU) /INCREMENTAL:NO $(ldebug) $(lflags) user32.lib -out:test_cpp.exe test_cpp.obj $(GC_LIB)
|
||||
|
||||
$(AO_SRC_DIR):
|
||||
tar xvfz $(AO_SRC_DIR).tar.gz
|
||||
|
||||
clean:
|
||||
del *.exe *.log *.obj *.pdb cord\*.exe cord\*.exp cord\*.lib cord\*.obj cord\*.pdb cord\tests\*.rbj cord\tests\*.res cord\tests\*.obj extra\*.obj gc*.lib gc*.dll gc*.exp test_cpp.cpp tests\*.obj 2> nul
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
# 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;
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
# 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;
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
# 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
|
||||
|
|
@ -32,9 +32,9 @@ LDFLAGS = $(CONFIG_LDFLAGS)
|
|||
# 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 fnlz_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 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 fnlz_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 typd_mlc.c ptr_chck.c mallocx.c
|
||||
|
||||
SHELL= /bin/sh
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
|||
Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
|
||||
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
|
||||
Copyright (c) 1999-2001 by Hewlett-Packard. All rights reserved.
|
||||
Copyright (c) 2009-2018 Ivan Maidanski
|
||||
|
||||
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
|
|
@ -26,10 +27,8 @@ For the version number, see README.md 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. With the most recent GC distributions
|
||||
you may have to type "make -f Makefile.direct test" or
|
||||
copy Makefile.direct to Makefile first.
|
||||
Alternative 1 (the old way): type "make -f Makefile.direct check".
|
||||
Link against gc.a.
|
||||
|
||||
Alternative 2 (the new way): type
|
||||
"./configure --prefix=<dir>; make; make check; make install".
|
||||
|
|
@ -48,7 +47,7 @@ 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".
|
||||
Makefile.direct, type "make -f Makefile.direct 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
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
# Boehm-Demers-Weiser Garbage Collector
|
||||
|
||||
This is version 7.5.0 (next release development) of a conservative garbage
|
||||
This is version 7.6.8 of a conservative garbage
|
||||
collector for C and C++.
|
||||
|
||||
You might find a more recent version
|
||||
[here](http://www.hboehm.info/gc/), or
|
||||
[here](https://github.com/ivmai/bdwgc).
|
||||
|
||||
## Download
|
||||
|
||||
You might find a more recent/stable version on the
|
||||
[Download](https://github.com/ivmai/bdwgc/wiki/Download) page, or
|
||||
[BDWGC site](http://www.hboehm.info/gc/).
|
||||
|
||||
Also, the latest bug fixes and new features are available in the
|
||||
[development repository](https://github.com/ivmai/bdwgc).
|
||||
|
||||
|
||||
## Overview
|
||||
|
|
@ -63,7 +69,7 @@ collector. (See doc/README.cords and H.-J. Boehm, R. Atkinson, and M. Plass,
|
|||
in Xerox Cedar, or the "rope" package in the SGI STL or the g++ distribution.)
|
||||
|
||||
Further collector documentation can be found
|
||||
[here](http://www.hboehm.info/gc/).
|
||||
in [overview.html](doc/overview.html).
|
||||
|
||||
|
||||
## General Description
|
||||
|
|
@ -174,14 +180,17 @@ libatomic_ops source repository as well) could look like:
|
|||
git clone git://github.com/ivmai/bdwgc.git
|
||||
cd bdwgc
|
||||
git clone git://github.com/ivmai/libatomic_ops.git
|
||||
autoreconf -vif
|
||||
automake --add-missing
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
make -j
|
||||
make check
|
||||
|
||||
If you are getting "syntax error near unexpected token ATOMIC_OPS" during
|
||||
configure execution, this means pkg.m4 cannot be found, most probably
|
||||
you should run `pkg-config` once before running `./autogen.sh` (autoreconf).
|
||||
|
||||
Below we focus on the collector build using classic makefile.
|
||||
For the Makefile.direct-based process, typing `make test` instead of `make`
|
||||
For the Makefile.direct-based process, typing `make check` 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
|
||||
|
|
@ -453,7 +462,7 @@ equivalents. (`GC_REGISTER_FINALIZER` is necessary, since pointers to
|
|||
objects with debugging information are really pointers to a displacement
|
||||
of 16 bytes form the object beginning, and some translation is necessary
|
||||
when finalization routines are invoked. For details, about what's stored
|
||||
in the header, see the definition of the type oh in debug_malloc.c)
|
||||
in the header, see the definition of the type oh in dbg_mlc.c file.)
|
||||
|
||||
|
||||
## Incremental/Generational Collection
|
||||
|
|
@ -534,9 +543,30 @@ 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 [here](mailto:bdwgc@lists.opendylan.org).
|
||||
If you are contemplating a major addition, you might also send mail to ask
|
||||
whether it's already been done (or whether we tried and discarded it).
|
||||
|
||||
## Feedback, Contribution, Questions and Notifications
|
||||
|
||||
Please address bug reports and new feature ideas to
|
||||
[GitHub issues](https://github.com/ivmai/bdwgc/issues). Before the
|
||||
submission please check that it has not been done yet by someone else.
|
||||
|
||||
If you want to contribute, submit
|
||||
a [pull request](https://github.com/ivmai/bdwgc/pulls) to GitHub.
|
||||
|
||||
If you need help, use
|
||||
[Stack Overflow](https://stackoverflow.com/questions/tagged/boehm-gc).
|
||||
Older technical discussions are available in `bdwgc` mailing list archive - it
|
||||
can be downloaded as a
|
||||
[compressed file](https://github.com/ivmai/bdwgc/files/1038163/bdwgc-mailing-list-archive-2017_04.tar.gz)
|
||||
or browsed at [Narkive](http://bdwgc.opendylan.narkive.com).
|
||||
|
||||
To get new release announcements, subscribe to
|
||||
[RSS feed](https://github.com/ivmai/bdwgc/releases.atom).
|
||||
(To receive the notifications by email, a 3rd-party free service like
|
||||
[IFTTT RSS Feed](https://ifttt.com/feed) can be setup.)
|
||||
To be notified on all issues, please
|
||||
[watch](https://github.com/ivmai/bdwgc/watchers) the project on
|
||||
GitHub.
|
||||
|
||||
|
||||
## Copyright & Warranty
|
||||
|
|
@ -545,21 +575,31 @@ whether it's already been done (or whether we tried and discarded it).
|
|||
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
|
||||
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
|
||||
* Copyright (c) 1999-2011 by Hewlett-Packard Development Company.
|
||||
* Copyright (c) 2008-2018 Ivan Maidanski
|
||||
|
||||
The file linux_threads.c is also
|
||||
The files pthread_stop_world.c, pthread_support.c and some others are also
|
||||
|
||||
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
||||
|
||||
The files Makefile.am, and configure.in are
|
||||
The file gc.h is also
|
||||
|
||||
* Copyright (c) 2001 by Red Hat Inc. All rights reserved.
|
||||
* Copyright (c) 2007 Free Software Foundation, Inc
|
||||
|
||||
The files Makefile.am and configure.ac are
|
||||
|
||||
* Copyright (c) 2001 by Red Hat Inc. All rights reserved.
|
||||
|
||||
The files msvc_dbg.c and msvc_dbg.h are
|
||||
|
||||
* Copyright (c) 2004-2005 Andrei Polushin
|
||||
|
||||
The file initsecondarythread.c is
|
||||
|
||||
* Copyright (c) 2011 Ludovic Courtes
|
||||
|
||||
Several files supporting GNU-style builds are copyrighted by the Free
|
||||
Software Foundation, and carry a different license from that given
|
||||
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.
|
||||
below.
|
||||
|
||||
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
|
|
@ -575,8 +615,3 @@ 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
|
||||
at the notice in config.guess or ltmain.sh.)
|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
# Rewritten smakefile for amiga / sas/c. -Kjetil M.
|
||||
# Dont use the cord-package if you define parm=both or parm=reg.
|
||||
# Don't use the cord-package if you define parm=both or parm=reg.
|
||||
|
||||
|
||||
#----------------TOOLS--------------------------------
|
||||
|
|
@ -32,7 +32,7 @@ DEFINE __USE_SYSBASE
|
|||
|
||||
SOPT= $(OPT) $(IGNORE) \
|
||||
DEFINE AMIGA_SKIP_SEG \
|
||||
DEFINE ATOMIC_UNCOLLECTABLE \
|
||||
DEFINE GC_ATOMIC_UNCOLLECTABLE \
|
||||
DEFINE GC_AMIGA_FASTALLOC \
|
||||
DEFINE GC_AMIGA_RETRY \
|
||||
DEFINE GC_AMIGA_PRINTSTATS \
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
== 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.)
|
||||
|
||||
BCC_MAKEFILE, EMX_MAKEFILE, OS2_MAKEFILE, PCR-Makefile, WCC_MAKEFILE,
|
||||
SMakefile.amiga, 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.
|
||||
|
||||
Use madvise() on Unix/Cygwin.
|
||||
|
||||
Use Linux VM pressure notifications to force GC and unmapping.
|
||||
|
||||
Filter overlaps in GC_add_roots for Unix (same as for Win32).
|
||||
|
||||
Do not resume parallel markers if only 1 core is active at GC mark start.
|
||||
|
||||
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).
|
||||
|
||||
Support musl libc (on sabotage linux).
|
||||
|
||||
== 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.
|
||||
|
||||
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*)".
|
||||
|
||||
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.
|
||||
|
||||
Linux/mips64el (N32): threadleaktest crashes once every 3-4 runs (SIGSEGV in
|
||||
GC_delete_gc_thread(t=0) called from GC_pthread_join) if configured with
|
||||
--disable-shared.
|
||||
|
||||
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.
|
||||
|
||||
Mingw-w32: gctest: "SuspendThread failed" sometimes occurs (if
|
||||
GC_DLL+GC_THREADS+GC_ASSERTIONS).
|
||||
|
||||
Mingw: gctest (compiled with PARALLEL_MARK): launched in gdb with breakpoint
|
||||
at GC_mark_local, after several breakpoint hits, crashes with the messages
|
||||
"Caught ACCESS_VIOLATION in marker; memory mapping disappeared" and
|
||||
"Tried to start parallel mark in bad state", or enters deadlock.
|
||||
|
||||
Mingw: test_cpp: crashes at some iteration if big argument (e.g., 1000) given.
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# Makefile for Watcom C/C++ 10.5, 10.6, 11.0 on NT, OS2 and DOS4GW.
|
||||
# May work with Watcom 10.0.
|
||||
|
||||
# Uncoment one of the lines below for cross compilation.
|
||||
# Uncomment one of the lines below for cross compilation.
|
||||
SYSTEM=MSWIN32
|
||||
#SYSTEM=DOS4GW
|
||||
#SYSTEM=OS2
|
||||
|
|
@ -25,7 +25,7 @@ CPU=5
|
|||
OPTIM=-oneatx -s
|
||||
#OPTIM=-ohneatx -s
|
||||
|
||||
DEFS=-DALL_INTERIOR_POINTERS #-DSMALL_CONFIG #-DGC_DEBUG
|
||||
DEFS=-DALL_INTERIOR_POINTERS #-DSMALL_CONFIG
|
||||
|
||||
|
||||
#####
|
||||
|
|
@ -66,11 +66,10 @@ TEST_DLLFLAG=
|
|||
CC=wcc386
|
||||
CXX=wpp386
|
||||
|
||||
# -DUSE_GENERIC is required !
|
||||
CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(DLLFLAG) -DUSE_GENERIC $(DEFS)
|
||||
CXXFLAGS= $(CFLAGS)
|
||||
TEST_CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(TEST_DLLFLAG) $(DEFS)
|
||||
TEST_CXXFLAGS= $(TEST_CFLAGS)
|
||||
CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -iinclude -zp4 -zc $(SYSFLAG) $(DLLFLAG) $(DEFS)
|
||||
CXXFLAGS= $(CFLAGS) -xs
|
||||
TEST_CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -iinclude -zp4 -zc $(SYSFLAG) $(TEST_DLLFLAG) $(DEFS)
|
||||
TEST_CXXFLAGS= $(TEST_CFLAGS) -xs
|
||||
|
||||
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj &
|
||||
mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj &
|
||||
|
|
@ -96,23 +95,12 @@ gc.dll: $(OBJS) .AUTODEPEND
|
|||
!endif
|
||||
@%append $*.lnk name $*
|
||||
@for %i in ($(OBJS)) do @%append $*.lnk file '%i'
|
||||
!ifeq CALLING s
|
||||
@%append $*.lnk export GC_is_marked
|
||||
@%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_bytes_allocd_
|
||||
@%append $*.lnk export GC_incr_bytes_freed_
|
||||
@%append $*.lnk export GC_generic_malloc_words_small_
|
||||
!endif
|
||||
*wlink @$*.lnk
|
||||
!else
|
||||
gc.lib: $(OBJS) gc_cpp.obj
|
||||
@%create $*.lb1
|
||||
@for %i in ($(OBJS)) do @%append $*.lb1 +'%i'
|
||||
@%append $*.lb1 +'gc_cpp.obj'
|
||||
@%append $*.lb1 +'gc_cpp.obj'
|
||||
*wlib -b -c -n -p=512 $@ @$*.lb1
|
||||
|
||||
!endif
|
||||
|
|
@ -132,13 +120,6 @@ gctest.exe: test.obj gc.lib
|
|||
@%append $*.lnk name $*
|
||||
@%append $*.lnk file test.obj
|
||||
@%append $*.lnk library gc.lib
|
||||
!ifdef MAKE_AS_DLL
|
||||
!ifeq CALLING s
|
||||
@%append $*.lnk import GC_is_marked gc
|
||||
!else
|
||||
@%append $*.lnk import GC_is_marked_ gc
|
||||
!endif
|
||||
!endif
|
||||
*wlink @$*.lnk
|
||||
test_cpp.exe: test_cpp.obj gc.lib
|
||||
%create $*.lnk
|
||||
|
|
@ -154,26 +135,14 @@ test_cpp.exe: test_cpp.obj gc.lib
|
|||
@%append $*.lnk name $*
|
||||
@%append $*.lnk file test_cpp.obj
|
||||
@%append $*.lnk library gc.lib
|
||||
!ifdef MAKE_AS_DLL
|
||||
!ifeq CALLING s
|
||||
@%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_bytes_allocd_ gc
|
||||
@%append $*.lnk import GC_incr_bytes_freed_ gc
|
||||
@%append $*.lnk import GC_generic_malloc_words_small_ gc
|
||||
!endif
|
||||
!endif
|
||||
*wlink @$*.lnk
|
||||
|
||||
gc_cpp.obj: gc_cpp.cc .AUTODEPEND
|
||||
$(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc
|
||||
$(CXX) $(TEST_CXXFLAGS) $*.cc
|
||||
test.obj: tests\test.c .AUTODEPEND
|
||||
$(CC) $(TEST_CFLAGS) $*.c
|
||||
$(CC) $(TEST_CFLAGS) tests\test.c
|
||||
test_cpp.obj: tests\test_cpp.cc .AUTODEPEND
|
||||
$(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc
|
||||
|
||||
$(CXX) $(TEST_CXXFLAGS) tests\test_cpp.cc
|
||||
|
||||
.c.obj: .AUTODEPEND
|
||||
$(CC) $(CFLAGS) $*.c
|
||||
|
|
|
|||
218
src/bdwgc/aclocal.m4
vendored
218
src/bdwgc/aclocal.m4
vendored
|
|
@ -20,32 +20,63 @@ You have another version of autoconf. It may work, but is not guaranteed to.
|
|||
If you have problems, you may need to regenerate the build system entirely.
|
||||
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
|
||||
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# 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.
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 12 (pkg-config-0.29.2)
|
||||
|
||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
# ----------------------------------
|
||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||
dnl
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 2 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl This program is distributed in the hope that it will be useful, but
|
||||
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
dnl General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program; if not, write to the Free Software
|
||||
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
dnl 02111-1307, USA.
|
||||
dnl
|
||||
dnl As a special exception to the GNU General Public License, if you
|
||||
dnl distribute this file as part of a program that contains a
|
||||
dnl configuration script generated by Autoconf, you may include it under
|
||||
dnl the same distribution terms that you use for the rest of that
|
||||
dnl program.
|
||||
|
||||
dnl PKG_PREREQ(MIN-VERSION)
|
||||
dnl -----------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Verify that the version of the pkg-config macros are at least
|
||||
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
|
||||
dnl installed version of pkg-config, this checks the developer's version
|
||||
dnl of pkg.m4 when generating configure.
|
||||
dnl
|
||||
dnl To ensure that this macro is defined, also add:
|
||||
dnl m4_ifndef([PKG_PREREQ],
|
||||
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
|
||||
dnl
|
||||
dnl See the "Since" comment for each macro you use to see what version
|
||||
dnl of the macros you require.
|
||||
m4_defun([PKG_PREREQ],
|
||||
[m4_define([PKG_MACROS_VERSION], [0.29.2])
|
||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
||||
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
||||
])dnl PKG_PREREQ
|
||||
|
||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
dnl ----------------------------------
|
||||
dnl Since: 0.16
|
||||
dnl
|
||||
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
|
||||
dnl first found in the path. Checks that the version of pkg-config found
|
||||
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
|
||||
dnl used since that's the first version where most current features of
|
||||
dnl pkg-config existed.
|
||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
|
||||
|
|
@ -67,18 +98,19 @@ if test -n "$PKG_CONFIG"; then
|
|||
PKG_CONFIG=""
|
||||
fi
|
||||
fi[]dnl
|
||||
])# PKG_PROG_PKG_CONFIG
|
||||
])dnl PKG_PROG_PKG_CONFIG
|
||||
|
||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# Check to see whether a particular set of modules exists. Similar
|
||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
#
|
||||
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
# only at the first occurence in configure.ac, so if the first place
|
||||
# it's called might be skipped (such as if it is within an "if", you
|
||||
# have to call PKG_CHECK_EXISTS manually
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------------------------------
|
||||
dnl Since: 0.18
|
||||
dnl
|
||||
dnl Check to see whether a particular set of modules exists. Similar to
|
||||
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
dnl
|
||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
dnl only at the first occurence in configure.ac, so if the first place
|
||||
dnl it's called might be skipped (such as if it is within an "if", you
|
||||
dnl have to call PKG_CHECK_EXISTS manually
|
||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
|
|
@ -88,8 +120,10 @@ m4_ifvaln([$3], [else
|
|||
$3])dnl
|
||||
fi])
|
||||
|
||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
# ---------------------------------------------
|
||||
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
dnl ---------------------------------------------
|
||||
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
|
||||
dnl pkg_failed based on the result.
|
||||
m4_define([_PKG_CONFIG],
|
||||
[if test -n "$$1"; then
|
||||
pkg_cv_[]$1="$$1"
|
||||
|
|
@ -101,10 +135,11 @@ m4_define([_PKG_CONFIG],
|
|||
else
|
||||
pkg_failed=untried
|
||||
fi[]dnl
|
||||
])# _PKG_CONFIG
|
||||
])dnl _PKG_CONFIG
|
||||
|
||||
# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
# -----------------------------
|
||||
dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
dnl ---------------------------
|
||||
dnl Internal check to see if pkg-config supports short errors.
|
||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
|
|
@ -112,26 +147,24 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
|||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi[]dnl
|
||||
])# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
])dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
|
||||
|
||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
# [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
#
|
||||
# Note that if there is a possibility the first call to
|
||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
#
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl --------------------------------------------------------------
|
||||
dnl Since: 0.4.0
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
AC_DEFUN([PKG_CHECK_MODULES],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||||
|
||||
pkg_failed=no
|
||||
AC_MSG_CHECKING([for $1])
|
||||
AC_MSG_CHECKING([for $2])
|
||||
|
||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||||
|
|
@ -141,11 +174,11 @@ and $1[]_LIBS to avoid the need to call pkg-config.
|
|||
See the pkg-config man page for more details.])
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_RESULT([no])
|
||||
_PKG_SHORT_ERRORS_SUPPORTED
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
|
||||
else
|
||||
else
|
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
|
|
@ -162,7 +195,7 @@ installed software in a non-standard prefix.
|
|||
_PKG_TEXT])[]dnl
|
||||
])
|
||||
elif test $pkg_failed = untried; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_RESULT([no])
|
||||
m4_default([$4], [AC_MSG_FAILURE(
|
||||
[The pkg-config script could not be found or is too old. Make sure it
|
||||
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||
|
|
@ -178,16 +211,40 @@ else
|
|||
AC_MSG_RESULT([yes])
|
||||
$3
|
||||
fi[]dnl
|
||||
])# PKG_CHECK_MODULES
|
||||
])dnl PKG_CHECK_MODULES
|
||||
|
||||
|
||||
# PKG_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable pkgconfigdir as the location where a module
|
||||
# should install pkg-config .pc files. By default the directory is
|
||||
# $libdir/pkgconfig, but the default can be changed by passing
|
||||
# DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
# parameter.
|
||||
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl ---------------------------------------------------------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Checks for existence of MODULES and gathers its build flags with
|
||||
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
|
||||
dnl and VARIABLE-PREFIX_LIBS from --libs.
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
|
||||
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
|
||||
dnl configure.ac.
|
||||
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
_save_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
PKG_CHECK_MODULES($@)
|
||||
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
|
||||
])dnl PKG_CHECK_MODULES_STATIC
|
||||
|
||||
|
||||
dnl PKG_INSTALLDIR([DIRECTORY])
|
||||
dnl -------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable pkgconfigdir as the location where a module
|
||||
dnl should install pkg-config .pc files. By default the directory is
|
||||
dnl $libdir/pkgconfig, but the default can be changed by passing
|
||||
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
dnl parameter.
|
||||
AC_DEFUN([PKG_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
|
|
@ -198,16 +255,18 @@ AC_ARG_WITH([pkgconfigdir],
|
|||
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_INSTALLDIR
|
||||
])dnl PKG_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
# module should install arch-independent pkg-config .pc files. By
|
||||
# default the directory is $datadir/pkgconfig, but the default can be
|
||||
# changed by passing DIRECTORY. The user can override through the
|
||||
# --with-noarch-pkgconfigdir parameter.
|
||||
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
|
||||
dnl --------------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
dnl module should install arch-independent pkg-config .pc files. By
|
||||
dnl default the directory is $datadir/pkgconfig, but the default can be
|
||||
dnl changed by passing DIRECTORY. The user can override through the
|
||||
dnl --with-noarch-pkgconfigdir parameter.
|
||||
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
|
|
@ -218,13 +277,15 @@ AC_ARG_WITH([noarch-pkgconfigdir],
|
|||
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_NOARCH_INSTALLDIR
|
||||
])dnl PKG_NOARCH_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
# -------------------------------------------
|
||||
# Retrieves the value of the pkg-config variable for the given module.
|
||||
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------
|
||||
dnl Since: 0.28
|
||||
dnl
|
||||
dnl Retrieves the value of the pkg-config variable for the given module.
|
||||
AC_DEFUN([PKG_CHECK_VAR],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
|
||||
|
|
@ -233,7 +294,7 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
|
|||
AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||
])# PKG_CHECK_VAR
|
||||
])dnl PKG_CHECK_VAR
|
||||
|
||||
# Copyright (C) 2002-2014 Free Software Foundation, Inc.
|
||||
#
|
||||
|
|
@ -1421,6 +1482,7 @@ AC_SUBST([am__tar])
|
|||
AC_SUBST([am__untar])
|
||||
]) # _AM_PROG_TAR
|
||||
|
||||
m4_include([m4/gc_set_version.m4])
|
||||
m4_include([m4/libtool.m4])
|
||||
m4_include([m4/ltoptions.m4])
|
||||
m4_include([m4/ltsugar.m4])
|
||||
|
|
|
|||
|
|
@ -103,12 +103,13 @@ STATIC int GC_hblk_fl_from_blocks(word blocks_needed)
|
|||
/* 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) {
|
||||
struct hblk * h;
|
||||
hdr * hhdr;
|
||||
|
||||
for (h = GC_hblkfreelist[i]; h != 0; h = hhdr->hb_next) {
|
||||
hhdr = HDR(h);
|
||||
total_free += hhdr->hb_sz;
|
||||
|
|
@ -121,17 +122,17 @@ STATIC int GC_hblk_fl_from_blocks(word blocks_needed)
|
|||
# if !defined(NO_DEBUGGING)
|
||||
void GC_print_hblkfreelist(void)
|
||||
{
|
||||
struct hblk * h;
|
||||
hdr * hhdr;
|
||||
unsigned i;
|
||||
word total;
|
||||
|
||||
for (i = 0; i <= N_HBLK_FLS; ++i) {
|
||||
h = GC_hblkfreelist[i];
|
||||
struct hblk * h = GC_hblkfreelist[i];
|
||||
|
||||
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);
|
||||
hdr * hhdr = HDR(h);
|
||||
|
||||
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" :
|
||||
|
|
@ -152,42 +153,42 @@ void GC_print_hblkfreelist(void)
|
|||
/* 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) {
|
||||
struct hblk * h;
|
||||
hdr * hhdr;
|
||||
|
||||
for (h = GC_hblkfreelist[i]; h != 0; h = hhdr -> hb_next) {
|
||||
hhdr = HDR(h);
|
||||
if (hhdr == wanted) return i;
|
||||
h = hhdr -> hb_next;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GC_dump_regions(void)
|
||||
GC_API void GC_CALL GC_dump_regions(void)
|
||||
{
|
||||
unsigned i;
|
||||
ptr_t start, end;
|
||||
ptr_t p;
|
||||
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;
|
||||
ptr_t start = GC_heap_sects[i].hs_start;
|
||||
size_t bytes = GC_heap_sects[i].hs_bytes;
|
||||
ptr_t end = start + bytes;
|
||||
ptr_t p;
|
||||
|
||||
/* 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);
|
||||
GC_printf("***Section from %p to %p\n", (void *)start, (void *)end);
|
||||
for (p = start; (word)p < (word)end; ) {
|
||||
hhdr = HDR(p);
|
||||
hdr *hhdr = HDR(p);
|
||||
|
||||
if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
|
||||
GC_printf("\t%p Missing header!!(%p)\n", p, (void *)hhdr);
|
||||
GC_printf("\t%p Missing header!!(%p)\n",
|
||||
(void *)p, (void *)hhdr);
|
||||
p += HBLKSIZE;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -196,8 +197,8 @@ void GC_dump_regions(void)
|
|||
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),
|
||||
GC_printf("\t%p\tfree block of size 0x%lx bytes%s\n",
|
||||
(void *)p, (unsigned long)(hhdr -> hb_sz),
|
||||
IS_MAPPED(hhdr) ? "" : " (unmapped)");
|
||||
actual_index = free_list_index_of(hhdr);
|
||||
if (-1 == actual_index) {
|
||||
|
|
@ -209,8 +210,8 @@ void GC_dump_regions(void)
|
|||
}
|
||||
p += hhdr -> hb_sz;
|
||||
} else {
|
||||
GC_printf("\t%p\tused for blocks of size 0x%lx bytes\n", p,
|
||||
(unsigned long)(hhdr -> hb_sz));
|
||||
GC_printf("\t%p\tused for blocks of size 0x%lx bytes\n",
|
||||
(void *)p, (unsigned long)(hhdr -> hb_sz));
|
||||
p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
|
||||
}
|
||||
}
|
||||
|
|
@ -226,9 +227,8 @@ static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
|
|||
int kind, unsigned flags)
|
||||
{
|
||||
word descr;
|
||||
# ifdef MARK_BIT_PER_GRANULE
|
||||
size_t granules;
|
||||
|
||||
# ifdef MARK_BIT_PER_GRANULE
|
||||
if (byte_sz > MAXOBJBYTES)
|
||||
flags |= LARGE_BLOCK;
|
||||
# endif
|
||||
|
|
@ -250,7 +250,7 @@ static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
|
|||
|
||||
# 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 */
|
||||
/* 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;
|
||||
|
|
@ -265,11 +265,16 @@ static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
|
|||
inv_sz = ((unsigned)1 << 31)/byte_sz;
|
||||
inv_sz *= 2;
|
||||
while (inv_sz*byte_sz > byte_sz) ++inv_sz;
|
||||
# endif
|
||||
# ifdef INV_SZ_COMPUTATION_CHECK
|
||||
GC_ASSERT(((1ULL << 32) + byte_sz - 1) / byte_sz == inv_sz);
|
||||
# endif
|
||||
hhdr -> hb_inv_sz = inv_sz;
|
||||
}
|
||||
# else /* MARK_BIT_PER_GRANULE */
|
||||
granules = BYTES_TO_GRANULES(byte_sz);
|
||||
{
|
||||
size_t 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;
|
||||
|
|
@ -280,6 +285,7 @@ static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
|
|||
}
|
||||
hhdr -> hb_map = GC_obj_map[(hhdr -> hb_flags & LARGE_BLOCK) != 0 ?
|
||||
0 : granules];
|
||||
}
|
||||
# endif /* MARK_BIT_PER_GRANULE */
|
||||
|
||||
/* Clear mark bits */
|
||||
|
|
@ -353,19 +359,18 @@ 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;
|
||||
# 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)
|
||||
|| (signed_word)GC_heapsize < 0);
|
||||
|| (GC_heapsize & SIGNB) != 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);
|
||||
|| (GC_heapsize & SIGNB) != 0);
|
||||
# endif
|
||||
|
||||
GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
|
||||
GC_hblkfreelist[index] = h;
|
||||
GC_free_bytes[index] += hhdr -> hb_sz;
|
||||
|
|
@ -373,6 +378,8 @@ STATIC void GC_add_to_fl(struct hblk *h, hdr *hhdr)
|
|||
hhdr -> hb_next = second;
|
||||
hhdr -> hb_prev = 0;
|
||||
if (0 != second) {
|
||||
hdr * second_hdr;
|
||||
|
||||
GET_HDR(second, second_hdr);
|
||||
second_hdr -> hb_prev = h;
|
||||
}
|
||||
|
|
@ -391,19 +398,22 @@ GC_INNER int GC_unmap_threshold = MUNMAP_THRESHOLD;
|
|||
/* way blocks are ever unmapped. */
|
||||
GC_INNER void GC_unmap_old(void)
|
||||
{
|
||||
struct hblk * h;
|
||||
hdr * hhdr;
|
||||
int i;
|
||||
|
||||
if (GC_unmap_threshold == 0)
|
||||
return; /* unmapping disabled */
|
||||
|
||||
for (i = 0; i <= N_HBLK_FLS; ++i) {
|
||||
struct hblk * h;
|
||||
hdr * hhdr;
|
||||
|
||||
for (h = GC_hblkfreelist[i]; 0 != h; h = hhdr -> hb_next) {
|
||||
hhdr = HDR(h);
|
||||
if (!IS_MAPPED(hhdr)) continue;
|
||||
|
||||
if ((unsigned short)GC_gc_no - hhdr -> hb_last_reclaimed >
|
||||
/* Check that the interval is larger than the threshold (the */
|
||||
/* truncated counter value wrapping is handled correctly). */
|
||||
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;
|
||||
|
|
@ -417,14 +427,16 @@ GC_INNER void GC_unmap_old(void)
|
|||
/* 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];
|
||||
struct hblk *h = GC_hblkfreelist[i];
|
||||
|
||||
while (h != 0) {
|
||||
struct hblk *next;
|
||||
hdr *hhdr, *nexthdr;
|
||||
word size, nextsize;
|
||||
|
||||
GET_HDR(h, hhdr);
|
||||
size = hhdr->hb_sz;
|
||||
next = (struct hblk *)((word)h + size);
|
||||
|
|
@ -500,7 +512,7 @@ STATIC struct hblk * GC_get_first_part(struct hblk *h, hdr *hhdr,
|
|||
rest_hdr = GC_install_header(rest);
|
||||
if (0 == rest_hdr) {
|
||||
/* FIXME: This is likely to be very bad news ... */
|
||||
WARN("Header allocation failed: Dropping block.\n", 0);
|
||||
WARN("Header allocation failed: dropping block\n", 0);
|
||||
return(0);
|
||||
}
|
||||
rest_hdr -> hb_sz = total_size - bytes;
|
||||
|
|
@ -583,7 +595,7 @@ GC_allochblk(size_t sz, int kind, unsigned flags/* IGNORE_OFF_PAGE or 0 */)
|
|||
/* split. */
|
||||
|
||||
GC_ASSERT((sz & (GRANULE_BYTES - 1)) == 0);
|
||||
blocks = OBJ_SZ_TO_BLOCKS(sz);
|
||||
blocks = OBJ_SZ_TO_BLOCKS_CHECKED(sz);
|
||||
if ((signed_word)(blocks * HBLKSIZE) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -643,26 +655,26 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split)
|
|||
hdr * hhdr; /* Header corr. to hbp */
|
||||
struct hblk *thishbp;
|
||||
hdr * thishdr; /* Header corr. to thishbp */
|
||||
signed_word size_needed; /* number of bytes in requested objects */
|
||||
signed_word size_avail; /* bytes available in this block */
|
||||
|
||||
size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz);
|
||||
signed_word size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS_CHECKED(sz);
|
||||
/* number of bytes in requested objects */
|
||||
|
||||
/* search for a big enough block in free list */
|
||||
for (hbp = GC_hblkfreelist[n];; hbp = hhdr -> hb_next) {
|
||||
signed_word size_avail; /* bytes available in this block */
|
||||
|
||||
if (NULL == hbp) return NULL;
|
||||
GET_HDR(hbp, hhdr); /* set hhdr value */
|
||||
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) {
|
||||
signed_word next_size;
|
||||
|
||||
GET_HDR(thishbp, thishdr);
|
||||
next_size = (signed_word)(thishdr -> hb_sz);
|
||||
if (next_size < size_avail
|
||||
|
|
@ -721,12 +733,13 @@ GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split)
|
|||
>= 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",
|
||||
"\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
|
||||
} else if (size_avail == 0
|
||||
&& size_needed == (signed_word)HBLKSIZE
|
||||
&& IS_MAPPED(hhdr)) {
|
||||
if (!GC_find_leak) {
|
||||
static unsigned count = 0;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
|
||||
* Copyright (c) 1998 by Silicon Graphics. All rights reserved.
|
||||
* Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
|
||||
* Copyright (c) 2008-2018 Ivan Maidanski
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
|
|
@ -64,21 +65,21 @@ word GC_non_gc_bytes = 0; /* Number of bytes not intended to be collected */
|
|||
word GC_gc_no = 0;
|
||||
|
||||
#ifndef GC_DISABLE_INCREMENTAL
|
||||
GC_INNER int GC_incremental = 0; /* By default, stop the world. */
|
||||
GC_INNER GC_bool GC_incremental = FALSE; /* By default, stop the world. */
|
||||
#endif
|
||||
|
||||
#ifdef THREADS
|
||||
int GC_parallel = FALSE; /* By default, parallel GC is off. */
|
||||
#endif
|
||||
|
||||
#ifndef GC_FULL_FREQ
|
||||
# define GC_FULL_FREQ 19 /* Every 20th collection is a full */
|
||||
#if defined(GC_FULL_FREQ) && !defined(CPPCHECK)
|
||||
int GC_full_freq = GC_FULL_FREQ;
|
||||
#else
|
||||
int GC_full_freq = 19; /* Every 20th collection is a full */
|
||||
/* collection, whether we need it */
|
||||
/* or not. */
|
||||
#endif
|
||||
|
||||
int GC_full_freq = GC_FULL_FREQ;
|
||||
|
||||
STATIC GC_bool GC_need_full_gc = FALSE;
|
||||
/* Need full GC do to heap growth. */
|
||||
|
||||
|
|
@ -90,10 +91,11 @@ STATIC word GC_used_heap_size_after_full = 0;
|
|||
|
||||
/* GC_copyright symbol is externally visible. */
|
||||
char * const GC_copyright[] =
|
||||
{"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ",
|
||||
{"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-2009 by Hewlett-Packard Company. All rights reserved. ",
|
||||
"Copyright (c) 2008-2018 Ivan Maidanski ",
|
||||
"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." };
|
||||
|
|
@ -119,24 +121,25 @@ GC_API unsigned GC_CALL GC_get_version(void)
|
|||
int GC_dont_expand = FALSE;
|
||||
#endif
|
||||
|
||||
#ifndef GC_FREE_SPACE_DIVISOR
|
||||
# define GC_FREE_SPACE_DIVISOR 3 /* must be > 0 */
|
||||
#if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK)
|
||||
word GC_free_space_divisor = GC_FREE_SPACE_DIVISOR; /* must be > 0 */
|
||||
#else
|
||||
word GC_free_space_divisor = 3;
|
||||
#endif
|
||||
|
||||
word GC_free_space_divisor = GC_FREE_SPACE_DIVISOR;
|
||||
|
||||
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 */
|
||||
#if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
|
||||
unsigned long GC_time_limit = GC_TIME_LIMIT;
|
||||
/* We try to keep pause times from exceeding */
|
||||
/* this by much. In milliseconds. */
|
||||
#else
|
||||
unsigned long GC_time_limit = 50;
|
||||
#endif
|
||||
|
||||
unsigned long GC_time_limit = GC_TIME_LIMIT;
|
||||
|
||||
#ifndef NO_CLOCK
|
||||
STATIC CLOCK_TYPE GC_start_time = 0;
|
||||
/* Time at which we stopped world. */
|
||||
|
|
@ -152,7 +155,7 @@ STATIC GC_stop_func GC_default_stop_func = GC_never_stop_func;
|
|||
GC_API void GC_CALL GC_set_stop_func(GC_stop_func stop_func)
|
||||
{
|
||||
DCL_LOCK_STATE;
|
||||
GC_ASSERT(stop_func != 0);
|
||||
GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
|
||||
LOCK();
|
||||
GC_default_stop_func = stop_func;
|
||||
UNLOCK();
|
||||
|
|
@ -202,15 +205,7 @@ GC_API GC_stop_func GC_CALL GC_get_stop_func(void)
|
|||
static word min_bytes_allocd(void)
|
||||
{
|
||||
word result;
|
||||
# ifdef STACK_NOT_SCANNED
|
||||
word stack_size = 0;
|
||||
# elif defined(STACK_GROWS_UP)
|
||||
word stack_size = GC_approx_sp() - GC_stackbottom;
|
||||
/* GC_stackbottom is used only for a single-threaded case. */
|
||||
# else
|
||||
word stack_size = GC_stackbottom - GC_approx_sp();
|
||||
# endif
|
||||
|
||||
word stack_size;
|
||||
word total_root_size; /* includes double stack size, */
|
||||
/* since the stack is expensive */
|
||||
/* to scan. */
|
||||
|
|
@ -226,8 +221,17 @@ static word min_bytes_allocd(void)
|
|||
GC_log_printf("Total stacks size: %lu\n",
|
||||
(unsigned long)stack_size);
|
||||
# endif
|
||||
}
|
||||
} else
|
||||
# endif
|
||||
/* else*/ {
|
||||
# ifdef STACK_NOT_SCANNED
|
||||
stack_size = 0;
|
||||
# elif defined(STACK_GROWS_UP)
|
||||
stack_size = GC_approx_sp() - GC_stackbottom;
|
||||
# else
|
||||
stack_size = GC_stackbottom - GC_approx_sp();
|
||||
# endif
|
||||
}
|
||||
|
||||
total_root_size = 2 * stack_size + GC_root_size;
|
||||
scan_size = 2 * GC_composite_in_use + GC_atomic_in_use / 4
|
||||
|
|
@ -355,11 +359,11 @@ STATIC void GC_finish_collection(void);
|
|||
*/
|
||||
STATIC void GC_maybe_gc(void)
|
||||
{
|
||||
static int n_partial_gcs = 0;
|
||||
|
||||
GC_ASSERT(I_HOLD_LOCK());
|
||||
ASSERT_CANCEL_DISABLED();
|
||||
if (GC_should_collect()) {
|
||||
static int n_partial_gcs = 0;
|
||||
|
||||
if (!GC_incremental) {
|
||||
/* FIXME: If possible, GC_default_stop_func should be used here */
|
||||
GC_try_to_collect_inner(GC_never_stop_func);
|
||||
|
|
@ -386,7 +390,7 @@ STATIC void GC_maybe_gc(void)
|
|||
}
|
||||
/* We try to mark with the world stopped. */
|
||||
/* If we run out of time, this turns into */
|
||||
/* incremental marking. */
|
||||
/* incremental marking. */
|
||||
# ifndef NO_CLOCK
|
||||
if (GC_time_limit != GC_TIME_UNLIMITED) { GET_TIME(GC_start_time); }
|
||||
# endif
|
||||
|
|
@ -407,26 +411,50 @@ STATIC void GC_maybe_gc(void)
|
|||
}
|
||||
}
|
||||
|
||||
STATIC GC_on_collection_event_proc GC_on_collection_event = 0;
|
||||
|
||||
/*
|
||||
* 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_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc fn)
|
||||
{
|
||||
/* fn may be 0 (means no event notifier). */
|
||||
DCL_LOCK_STATE;
|
||||
LOCK();
|
||||
GC_on_collection_event = fn;
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void)
|
||||
{
|
||||
GC_on_collection_event_proc fn;
|
||||
DCL_LOCK_STATE;
|
||||
LOCK();
|
||||
fn = GC_on_collection_event;
|
||||
UNLOCK();
|
||||
return fn;
|
||||
}
|
||||
|
||||
/* Stop the world garbage collection. 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_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
|
||||
{
|
||||
# ifndef SMALL_CONFIG
|
||||
CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
|
||||
CLOCK_TYPE current_time;
|
||||
# endif
|
||||
|
||||
ASSERT_CANCEL_DISABLED();
|
||||
GC_ASSERT(I_HOLD_LOCK());
|
||||
if (GC_dont_gc || (*stop_func)()) return FALSE;
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_START);
|
||||
if (GC_incremental && GC_collection_in_progress()) {
|
||||
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);
|
||||
if ((*stop_func)()) {
|
||||
/* TODO: Notify GC_EVENT_ABANDON */
|
||||
return(FALSE);
|
||||
}
|
||||
GC_collect_a_little_inner(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -450,6 +478,7 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
|
|||
if ((GC_find_leak || stop_func != GC_never_stop_func)
|
||||
&& !GC_reclaim_all(stop_func, FALSE)) {
|
||||
/* Aborted. So far everything is still consistent. */
|
||||
/* TODO: Notify GC_EVENT_ABANDON */
|
||||
return(FALSE);
|
||||
}
|
||||
GC_invalidate_mark_state(); /* Flush mark stack. */
|
||||
|
|
@ -467,16 +496,21 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
|
|||
GC_unpromote_black_lists();
|
||||
} /* else we claim the world is already still consistent. We'll */
|
||||
/* finish incrementally. */
|
||||
/* TODO: Notify GC_EVENT_ABANDON */
|
||||
return(FALSE);
|
||||
}
|
||||
GC_finish_collection();
|
||||
# ifndef SMALL_CONFIG
|
||||
if (GC_print_stats) {
|
||||
CLOCK_TYPE current_time;
|
||||
|
||||
GET_TIME(current_time);
|
||||
GC_log_printf("Complete collection took %lu msecs\n",
|
||||
MS_TIME_DIFF(current_time,start_time));
|
||||
}
|
||||
# endif
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_END);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
|
@ -503,12 +537,13 @@ STATIC int GC_deficit = 0;/* The number of extra calls to GC_mark_some */
|
|||
|
||||
GC_INNER void GC_collect_a_little_inner(int n)
|
||||
{
|
||||
int i;
|
||||
IF_CANCEL(int cancel_state;)
|
||||
|
||||
if (GC_dont_gc) return;
|
||||
DISABLE_CANCEL(cancel_state);
|
||||
if (GC_incremental && GC_collection_in_progress()) {
|
||||
int i;
|
||||
|
||||
for (i = GC_deficit; i < GC_RATE*n; i++) {
|
||||
if (GC_mark_some((ptr_t)0)) {
|
||||
/* Need to finish a collection */
|
||||
|
|
@ -593,7 +628,6 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
|
|||
unsigned i;
|
||||
# ifndef SMALL_CONFIG
|
||||
CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
|
||||
CLOCK_TYPE current_time;
|
||||
# endif
|
||||
|
||||
# if !defined(REDIRECT_MALLOC) && defined(USE_WINALLOC)
|
||||
|
|
@ -608,7 +642,19 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
|
|||
GET_TIME(start_time);
|
||||
# endif
|
||||
|
||||
# if !defined(GC_NO_FINALIZATION) && !defined(GC_TOGGLE_REFS_NOT_NEEDED)
|
||||
GC_process_togglerefs();
|
||||
# endif
|
||||
# ifdef THREADS
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_PRE_STOP_WORLD);
|
||||
# endif
|
||||
STOP_WORLD();
|
||||
# ifdef THREADS
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_POST_STOP_WORLD);
|
||||
# endif
|
||||
|
||||
# ifdef THREAD_LOCAL_ALLOC
|
||||
GC_world_stopped = TRUE;
|
||||
# endif
|
||||
|
|
@ -623,6 +669,9 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
|
|||
# endif
|
||||
|
||||
/* Mark from all roots. */
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_MARK_START);
|
||||
|
||||
/* Minimize junk left in my registers and on the stack */
|
||||
GC_clear_a_few_frames();
|
||||
GC_noop6(0,0,0,0,0,0);
|
||||
|
|
@ -636,7 +685,20 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
|
|||
# ifdef THREAD_LOCAL_ALLOC
|
||||
GC_world_stopped = FALSE;
|
||||
# endif
|
||||
|
||||
# ifdef THREADS
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
|
||||
# endif
|
||||
|
||||
START_WORLD();
|
||||
|
||||
# ifdef THREADS
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_POST_START_WORLD);
|
||||
# endif
|
||||
|
||||
/* TODO: Notify GC_EVENT_MARK_ABANDON */
|
||||
return(FALSE);
|
||||
}
|
||||
if (GC_mark_some(GC_approx_sp())) break;
|
||||
|
|
@ -653,15 +715,31 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
|
|||
if (GC_debugging_started) {
|
||||
(*GC_check_heap)();
|
||||
}
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_MARK_END);
|
||||
|
||||
# ifdef THREAD_LOCAL_ALLOC
|
||||
GC_world_stopped = FALSE;
|
||||
# endif
|
||||
|
||||
# ifdef THREADS
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
|
||||
# endif
|
||||
|
||||
START_WORLD();
|
||||
|
||||
# ifdef THREADS
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_POST_START_WORLD);
|
||||
# endif
|
||||
|
||||
# ifndef SMALL_CONFIG
|
||||
if (GC_PRINT_STATS_FLAG) {
|
||||
unsigned long time_diff;
|
||||
unsigned total_time, divisor;
|
||||
CLOCK_TYPE current_time;
|
||||
|
||||
GET_TIME(current_time);
|
||||
time_diff = MS_TIME_DIFF(current_time,start_time);
|
||||
|
||||
|
|
@ -691,19 +769,15 @@ STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
|
|||
/* Set all mark bits for the free list whose first entry is q */
|
||||
GC_INNER void GC_set_fl_marks(ptr_t q)
|
||||
{
|
||||
struct hblk *h, *last_h;
|
||||
hdr *hhdr;
|
||||
IF_PER_OBJ(size_t sz;)
|
||||
unsigned bit_no;
|
||||
if (q != NULL) {
|
||||
struct hblk *h = HBLKPTR(q);
|
||||
struct hblk *last_h = h;
|
||||
hdr *hhdr = HDR(h);
|
||||
IF_PER_OBJ(size_t sz = hhdr->hb_sz;)
|
||||
|
||||
if (q != NULL) {
|
||||
h = HBLKPTR(q);
|
||||
last_h = h;
|
||||
hhdr = HDR(h);
|
||||
IF_PER_OBJ(sz = hhdr->hb_sz;)
|
||||
for (;;) {
|
||||
unsigned bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, 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;
|
||||
|
|
@ -719,8 +793,8 @@ GC_INNER void GC_set_fl_marks(ptr_t q)
|
|||
hhdr = HDR(h);
|
||||
IF_PER_OBJ(sz = hhdr->hb_sz;)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GC_ASSERTIONS) && defined(THREADS) && defined(THREAD_LOCAL_ALLOC)
|
||||
|
|
@ -769,22 +843,21 @@ GC_INNER void GC_set_fl_marks(ptr_t q)
|
|||
/* Decrement GC_bytes_found by number of bytes on free list. */
|
||||
STATIC void GC_clear_fl_marks(ptr_t q)
|
||||
{
|
||||
struct hblk *h, *last_h;
|
||||
hdr *hhdr;
|
||||
size_t sz;
|
||||
unsigned bit_no;
|
||||
if (q != NULL) {
|
||||
struct hblk *h = HBLKPTR(q);
|
||||
struct hblk *last_h = h;
|
||||
hdr *hhdr = HDR(h);
|
||||
size_t sz = hhdr->hb_sz; /* Normally set only once. */
|
||||
|
||||
if (q != NULL) {
|
||||
h = HBLKPTR(q);
|
||||
last_h = h;
|
||||
hhdr = HDR(h);
|
||||
sz = hhdr->hb_sz; /* Normally set only once. */
|
||||
for (;;) {
|
||||
unsigned bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, sz);
|
||||
|
||||
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;
|
||||
size_t n_marks = hhdr -> hb_n_marks;
|
||||
|
||||
GC_ASSERT(n_marks != 0);
|
||||
clear_mark_bit_from_hdr(hhdr, bit_no);
|
||||
n_marks--;
|
||||
# ifdef PARALLEL_MARK
|
||||
/* Appr. count, don't decrement to zero! */
|
||||
if (0 != n_marks || !GC_parallel) {
|
||||
|
|
@ -806,8 +879,8 @@ STATIC void GC_clear_fl_marks(ptr_t q)
|
|||
hhdr = HDR(h);
|
||||
sz = hhdr->hb_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GC_ASSERTIONS) && defined(THREADS) && defined(THREAD_LOCAL_ALLOC)
|
||||
|
|
@ -832,7 +905,6 @@ STATIC void GC_finish_collection(void)
|
|||
# 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) \
|
||||
|
|
@ -846,6 +918,8 @@ STATIC void GC_finish_collection(void)
|
|||
if (GC_print_stats)
|
||||
GET_TIME(start_time);
|
||||
# endif
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_RECLAIM_START);
|
||||
|
||||
# ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
|
||||
if (GC_bytes_found > 0)
|
||||
|
|
@ -951,8 +1025,12 @@ STATIC void GC_finish_collection(void)
|
|||
|
||||
IF_USE_MUNMAP(GC_unmap_old());
|
||||
|
||||
if (GC_on_collection_event)
|
||||
GC_on_collection_event(GC_EVENT_RECLAIM_END);
|
||||
# ifndef SMALL_CONFIG
|
||||
if (GC_print_stats) {
|
||||
CLOCK_TYPE done_time;
|
||||
|
||||
GET_TIME(done_time);
|
||||
# ifndef GC_NO_FINALIZATION
|
||||
/* A convenient place to output finalization statistics. */
|
||||
|
|
@ -1004,7 +1082,7 @@ STATIC GC_bool GC_try_to_collect_general(GC_stop_func stop_func,
|
|||
/* Externally callable routines to invoke full, stop-the-world collection. */
|
||||
GC_API int GC_CALL GC_try_to_collect(GC_stop_func stop_func)
|
||||
{
|
||||
GC_ASSERT(stop_func != 0);
|
||||
GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
|
||||
return (int)GC_try_to_collect_general(stop_func, FALSE);
|
||||
}
|
||||
|
||||
|
|
@ -1130,9 +1208,9 @@ GC_INNER void GC_add_to_heap(struct hblk *p, size_t bytes)
|
|||
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));
|
||||
GC_printf("Section %d from %p to %p %u/%lu blacklisted\n",
|
||||
i, (void *)start, (void *)&start[len],
|
||||
nbl, (unsigned long)divHBLKSZ(len));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1165,25 +1243,28 @@ GC_word GC_max_retries = 0;
|
|||
/* Returns FALSE on failure. */
|
||||
GC_INNER GC_bool GC_expand_hp_inner(word n)
|
||||
{
|
||||
word bytes;
|
||||
size_t bytes;
|
||||
struct hblk * space;
|
||||
word expansion_slop; /* Number of bytes by which we expect the */
|
||||
/* heap to expand soon. */
|
||||
|
||||
if (n < MINHINCR) n = MINHINCR;
|
||||
bytes = ROUNDUP_PAGESIZE(n * HBLKSIZE);
|
||||
if (GC_max_heapsize != 0 && GC_heapsize + bytes > GC_max_heapsize) {
|
||||
bytes = ROUNDUP_PAGESIZE((size_t)n * HBLKSIZE);
|
||||
if (GC_max_heapsize != 0
|
||||
&& (GC_max_heapsize < (word)bytes
|
||||
|| GC_heapsize > GC_max_heapsize - (word)bytes)) {
|
||||
/* Exceeded self-imposed limit */
|
||||
return(FALSE);
|
||||
}
|
||||
space = GET_MEM(bytes);
|
||||
GC_add_to_our_memory((ptr_t)space, bytes);
|
||||
if (space == 0) {
|
||||
WARN("Failed to expand heap by %" WARN_PRIdPTR " bytes\n", bytes);
|
||||
WARN("Failed to expand heap by %" WARN_PRIdPTR " bytes\n",
|
||||
(word)bytes);
|
||||
return(FALSE);
|
||||
}
|
||||
GC_INFOLOG_PRINTF("Grow heap to %lu KiB after %lu bytes allocated\n",
|
||||
TO_KiB_UL(GC_heapsize + bytes),
|
||||
TO_KiB_UL(GC_heapsize + (word)bytes),
|
||||
(unsigned long)GC_bytes_allocd);
|
||||
/* Adjust heap limits generously for blacklisting to work better. */
|
||||
/* GC_add_to_heap performs minimal adjustment needed for */
|
||||
|
|
@ -1193,7 +1274,7 @@ GC_INNER GC_bool GC_expand_hp_inner(word n)
|
|||
|| (GC_last_heap_addr != 0
|
||||
&& (word)GC_last_heap_addr < (word)space)) {
|
||||
/* Assume the heap is growing up */
|
||||
word new_limit = (word)space + bytes + expansion_slop;
|
||||
word new_limit = (word)space + (word)bytes + expansion_slop;
|
||||
if (new_limit > (word)space) {
|
||||
GC_greatest_plausible_heap_addr =
|
||||
(void *)GC_max((word)GC_greatest_plausible_heap_addr,
|
||||
|
|
@ -1229,8 +1310,8 @@ GC_API int GC_CALL GC_expand_hp(size_t bytes)
|
|||
int result;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
LOCK();
|
||||
if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
|
||||
LOCK();
|
||||
result = (int)GC_expand_hp_inner(divHBLKSZ((word)bytes));
|
||||
if (result) GC_requested_heapsize += bytes;
|
||||
UNLOCK();
|
||||
|
|
@ -1246,6 +1327,8 @@ GC_INNER unsigned GC_fail_count = 0;
|
|||
static word last_fo_entries = 0;
|
||||
static word last_bytes_finalized = 0;
|
||||
|
||||
#define GC_WORD_MAX (~(word)0)
|
||||
|
||||
/* Collect or expand heap in an attempt make the indicated number of */
|
||||
/* free blocks available. Should be called until the blocks are */
|
||||
/* available (setting retry value to TRUE unless this is the first call */
|
||||
|
|
@ -1300,6 +1383,8 @@ GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
|
|||
} else {
|
||||
blocks_to_get = MAXHINCR;
|
||||
}
|
||||
if (blocks_to_get > divHBLKSZ(GC_WORD_MAX))
|
||||
blocks_to_get = divHBLKSZ(GC_WORD_MAX);
|
||||
}
|
||||
|
||||
if (!GC_expand_hp_inner(blocks_to_get)
|
||||
|
|
@ -1310,7 +1395,7 @@ GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
|
|||
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);
|
||||
WARN("Out of Memory! Trying to continue...\n", 0);
|
||||
GC_gcollect_inner();
|
||||
} else {
|
||||
# if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
|
||||
|
|
|
|||
|
|
@ -86,13 +86,13 @@ static back_edges *avail_back_edges = 0;
|
|||
static back_edges * new_back_edges(void)
|
||||
{
|
||||
if (0 == back_edge_space) {
|
||||
back_edge_space = (back_edges *)GET_MEM(
|
||||
ROUNDUP_PAGESIZE_IF_MMAP(MAX_BACK_EDGE_STRUCTS
|
||||
* sizeof(back_edges)));
|
||||
size_t bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(MAX_BACK_EDGE_STRUCTS
|
||||
* sizeof(back_edges));
|
||||
|
||||
back_edge_space = (back_edges *)GET_MEM(bytes_to_get);
|
||||
if (NULL == back_edge_space)
|
||||
ABORT("Insufficient memory for back edges");
|
||||
GC_add_to_our_memory((ptr_t)back_edge_space,
|
||||
MAX_BACK_EDGE_STRUCTS*sizeof(back_edges));
|
||||
GC_add_to_our_memory((ptr_t)back_edge_space, bytes_to_get);
|
||||
}
|
||||
if (0 != avail_back_edges) {
|
||||
back_edges * result = avail_back_edges;
|
||||
|
|
@ -129,26 +129,32 @@ 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) {
|
||||
ptr_t * new_in_progress_space;
|
||||
|
||||
if (NULL == in_progress_space) {
|
||||
in_progress_size = ROUNDUP_PAGESIZE_IF_MMAP(INITIAL_IN_PROGRESS
|
||||
* sizeof(ptr_t))
|
||||
/ sizeof(ptr_t);
|
||||
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));
|
||||
new_in_progress_space =
|
||||
(ptr_t *)GET_MEM(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));
|
||||
if (new_in_progress_space != NULL)
|
||||
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. */
|
||||
}
|
||||
GC_add_to_our_memory((ptr_t)new_in_progress_space,
|
||||
in_progress_size * sizeof(ptr_t));
|
||||
# ifndef GWW_VDB
|
||||
GC_scratch_recycle_no_gww(in_progress_space,
|
||||
n_in_progress * sizeof(ptr_t));
|
||||
# elif defined(LINT2)
|
||||
/* TODO: implement GWW-aware recycling as in alloc_mark_stack */
|
||||
GC_noop1((word)in_progress_space);
|
||||
# endif
|
||||
in_progress_space = new_in_progress_space;
|
||||
}
|
||||
if (in_progress_space == 0)
|
||||
ABORT("MAKE_BACK_GRAPH: Out of in-progress space: "
|
||||
|
|
@ -227,13 +233,6 @@ 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)) {
|
||||
|
|
@ -242,6 +241,14 @@ static void add_edge(ptr_t p, ptr_t q)
|
|||
return;
|
||||
}
|
||||
if (0 == old_back_ptr) {
|
||||
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. */
|
||||
|
||||
SET_OH_BG_PTR(q, p);
|
||||
if (GOT_LUCKY_NUMBER) ensure_struct(q);
|
||||
return;
|
||||
|
|
@ -382,7 +389,8 @@ static word backwards_height(ptr_t p)
|
|||
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);
|
||||
GC_COND_LOG_PRINTF("Found bogus pointer from %p to %p\n",
|
||||
(void *)q, (void *)p);
|
||||
/* Reachable object "points to" unreachable one. */
|
||||
/* Could be caused by our lax treatment of GC descriptors. */
|
||||
this_height = 1;
|
||||
|
|
@ -463,14 +471,19 @@ GC_INNER void GC_traverse_back_graph(void)
|
|||
|
||||
void GC_print_back_graph_stats(void)
|
||||
{
|
||||
GC_ASSERT(I_HOLD_LOCK());
|
||||
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) {
|
||||
ptr_t obj = GC_deepest_obj;
|
||||
|
||||
GC_max_max_height = GC_max_height;
|
||||
UNLOCK();
|
||||
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_print_heap_obj(obj);
|
||||
LOCK();
|
||||
}
|
||||
GC_COND_LOG_PRINTF("Needed max total of %d back-edge structs\n",
|
||||
GC_n_back_edge_structs);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ GC_INNER void GC_default_print_heap_obj_proc(ptr_t p)
|
|||
int kind = HDR(base)->hb_obj_kind;
|
||||
|
||||
GC_err_printf("object at %p of appr. %lu bytes (%s)\n",
|
||||
base, (unsigned long)GC_size(base),
|
||||
(void *)base, (unsigned long)GC_size(base),
|
||||
kind == PTRFREE ? "atomic" :
|
||||
IS_UNCOLLECTABLE(kind) ? "uncollectable" : "composite");
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ GC_INNER void (*GC_print_heap_obj)(ptr_t p) = GC_default_print_heap_obj_proc;
|
|||
|
||||
if (0 == base) {
|
||||
GC_err_printf("Black listing (%s) %p referenced from %p in %s\n",
|
||||
kind_str, (ptr_t)p, source,
|
||||
kind_str, (void *)p, (void *)source,
|
||||
NULL != source ? "root set" : "register");
|
||||
} else {
|
||||
/* FIXME: We can't call the debug version of GC_print_heap_obj */
|
||||
|
|
@ -83,8 +83,8 @@ GC_INNER void (*GC_print_heap_obj)(ptr_t p) = GC_default_print_heap_obj_proc;
|
|||
/* 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));
|
||||
kind_str, (void *)p, (void *)source,
|
||||
(void *)base, (unsigned long)GC_size(base));
|
||||
}
|
||||
}
|
||||
#endif /* PRINT_BLACK_LIST */
|
||||
|
|
@ -109,6 +109,7 @@ GC_INNER void GC_bl_init(void)
|
|||
if (!GC_all_interior_pointers) {
|
||||
GC_bl_init_no_interiors();
|
||||
}
|
||||
GC_ASSERT(NULL == GC_old_stack_bl && NULL == GC_incomplete_stack_bl);
|
||||
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) {
|
||||
|
|
@ -281,7 +282,7 @@ static word total_stack_black_listed(void)
|
|||
|
||||
for (i = 0; i < GC_n_heap_sects; i++) {
|
||||
struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
|
||||
struct hblk * endp1 = start + GC_heap_sects[i].hs_bytes/HBLKSIZE;
|
||||
struct hblk * endp1 = start + divHBLKSZ(GC_heap_sects[i].hs_bytes);
|
||||
|
||||
total += GC_number_stack_black_listed(start, endp1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,18 +39,21 @@ STATIC word GC_faulted[NSUMS] = { 0 };
|
|||
|
||||
STATIC size_t GC_n_faulted = 0;
|
||||
|
||||
void GC_record_fault(struct hblk * h)
|
||||
{
|
||||
word page = ROUNDUP_PAGESIZE((word)h);
|
||||
#if defined(MPROTECT_VDB) && !defined(DARWIN)
|
||||
void GC_record_fault(struct hblk * h)
|
||||
{
|
||||
word page = (word)h & ~(GC_page_size - 1);
|
||||
|
||||
GC_ASSERT(GC_page_size != 0);
|
||||
if (GC_n_faulted >= NSUMS) ABORT("write fault log overflowed");
|
||||
GC_faulted[GC_n_faulted++] = page;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC GC_bool GC_was_faulted(struct hblk *h)
|
||||
{
|
||||
size_t i;
|
||||
word page = ROUNDUP_PAGESIZE((word)h);
|
||||
word page = (word)h & ~(GC_page_size - 1);
|
||||
|
||||
for (i = 0; i < GC_n_faulted; ++i) {
|
||||
if (GC_faulted[i] == page) return TRUE;
|
||||
|
|
@ -90,8 +93,8 @@ STATIC word GC_checksum(struct hblk *h)
|
|||
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;
|
||||
unsigned long GC_n_clean = 0;
|
||||
unsigned long GC_n_dirty = 0;
|
||||
|
||||
STATIC void GC_update_check_page(struct hblk *h, int index)
|
||||
{
|
||||
|
|
@ -196,14 +199,13 @@ void GC_check_dirty(void)
|
|||
}
|
||||
out:
|
||||
GC_COND_LOG_PRINTF("Checked %lu clean and %lu dirty pages\n",
|
||||
(unsigned long)GC_n_clean, (unsigned long)GC_n_dirty);
|
||||
GC_n_clean, GC_n_dirty);
|
||||
if (GC_n_dirty_errors > 0) {
|
||||
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_err_printf("Found %lu changed bit errors\n",
|
||||
(unsigned long)GC_n_changed_errors);
|
||||
GC_err_printf("Found %d changed bit errors\n", GC_n_changed_errors);
|
||||
GC_err_printf(
|
||||
"These may be benign (provoked by nonpointer changes)\n");
|
||||
# ifdef THREADS
|
||||
|
|
|
|||
409
src/bdwgc/configure
vendored
409
src/bdwgc/configure
vendored
|
|
@ -1,8 +1,8 @@
|
|||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for gc 7.5.0.
|
||||
# Generated by GNU Autoconf 2.69 for gc 7.6.8.
|
||||
#
|
||||
# Report bugs to <bdwgc@lists.opendylan.org>.
|
||||
# Report bugs to <https://github.com/ivmai/bdwgc/issues>.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
|
|
@ -275,10 +275,10 @@ fi
|
|||
$as_echo "$0: be upgraded to zsh 4.3.4 or later."
|
||||
else
|
||||
$as_echo "$0: Please tell bug-autoconf@gnu.org and
|
||||
$0: bdwgc@lists.opendylan.org about your system, including
|
||||
$0: any error possibly output before this message. Then
|
||||
$0: install a modern shell, or manually run the script
|
||||
$0: under such a shell if you do have one."
|
||||
$0: https://github.com/ivmai/bdwgc/issues about your
|
||||
$0: system, including any error possibly output before this
|
||||
$0: message. Then install a modern shell, or manually run
|
||||
$0: the script under such a shell if you do have one."
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -590,9 +590,9 @@ MAKEFLAGS=
|
|||
# Identity of this package.
|
||||
PACKAGE_NAME='gc'
|
||||
PACKAGE_TARNAME='gc'
|
||||
PACKAGE_VERSION='7.5.0'
|
||||
PACKAGE_STRING='gc 7.5.0'
|
||||
PACKAGE_BUGREPORT='bdwgc@lists.opendylan.org'
|
||||
PACKAGE_VERSION='7.6.8'
|
||||
PACKAGE_STRING='gc 7.6.8'
|
||||
PACKAGE_BUGREPORT='https://github.com/ivmai/bdwgc/issues'
|
||||
PACKAGE_URL=''
|
||||
|
||||
ac_unique_file="gcj_mlc.c"
|
||||
|
|
@ -647,8 +647,11 @@ ATOMIC_OPS_CFLAGS
|
|||
PKG_CONFIG_LIBDIR
|
||||
PKG_CONFIG_PATH
|
||||
PKG_CONFIG
|
||||
ENABLE_DOCS_FALSE
|
||||
ENABLE_DOCS_TRUE
|
||||
SINGLE_GC_OBJ_FALSE
|
||||
SINGLE_GC_OBJ_TRUE
|
||||
WERROR_CFLAGS
|
||||
USE_LIBDIR_FALSE
|
||||
USE_LIBDIR_TRUE
|
||||
UNWINDLIBS
|
||||
|
|
@ -672,6 +675,8 @@ AVOID_CPP_LIB_FALSE
|
|||
AVOID_CPP_LIB_TRUE
|
||||
ASM_WITH_CPP_UNSUPPORTED_FALSE
|
||||
ASM_WITH_CPP_UNSUPPORTED_TRUE
|
||||
PTHREAD_START_STANDALONE_FALSE
|
||||
PTHREAD_START_STANDALONE_TRUE
|
||||
WIN32_THREADS_FALSE
|
||||
WIN32_THREADS_TRUE
|
||||
DARWIN_THREADS_FALSE
|
||||
|
|
@ -681,6 +686,7 @@ PTHREADS_TRUE
|
|||
THREADS_FALSE
|
||||
THREADS_TRUE
|
||||
THREADDLLIBS
|
||||
CFLAGS_EXTRA
|
||||
GC_CFLAGS
|
||||
CXXCPP
|
||||
CPP
|
||||
|
|
@ -846,7 +852,10 @@ enable_large_config
|
|||
enable_handle_fork
|
||||
enable_gc_assertions
|
||||
enable_munmap
|
||||
enable_werror
|
||||
enable_single_obj_compilation
|
||||
enable_gcov
|
||||
enable_docs
|
||||
with_libatomic_ops
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
|
|
@ -1410,7 +1419,7 @@ 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 7.5.0 to adapt to many kinds of systems.
|
||||
\`configure' configures gc 7.6.8 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
|
|
@ -1481,7 +1490,7 @@ fi
|
|||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of gc 7.5.0:";;
|
||||
short | recursive ) echo "Configuration of gc 7.6.8:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
|
|
@ -1506,25 +1515,28 @@ Optional Features:
|
|||
--enable-threads=TYPE choose threading package
|
||||
--enable-parallel-mark parallelize marking and free list construction
|
||||
--enable-cplusplus install C++ support
|
||||
--disable-gcj-support Disable support for gcj.
|
||||
--enable-sigrt-signals Force GC to use SIGRTMIN-based signals for thread
|
||||
--disable-gcj-support disable support for gcj
|
||||
--enable-sigrt-signals force GC to use SIGRTMIN-based signals for thread
|
||||
suspend/resume
|
||||
--enable-gc-debug include full support for pointer backtracing etc.
|
||||
--disable-java-finalization
|
||||
Disable support for java finalization.
|
||||
disable support for java finalization
|
||||
--disable-atomic-uncollectible
|
||||
Disable support for atomic uncollectible allocation.
|
||||
disable support for atomic uncollectible allocation
|
||||
--enable-redirect-malloc
|
||||
Redirect malloc and friends to GC routines
|
||||
--disable-disclaim Disable alternative (more efficient) finalization
|
||||
interface.
|
||||
--enable-large-config Optimize for large (> 100 MB) heap or root set
|
||||
--enable-handle-fork Attempt to ensure a usable collector after fork() in
|
||||
multi-threaded programs.
|
||||
redirect malloc and friends to GC routines
|
||||
--disable-disclaim disable alternative (more efficient) finalization
|
||||
interface
|
||||
--enable-large-config optimize for large (> 100 MB) heap or root set
|
||||
--enable-handle-fork attempt to ensure a usable collector after fork() in
|
||||
multi-threaded programs
|
||||
--enable-gc-assertions collector-internal assertion checking
|
||||
--enable-munmap=N return page to the os if empty for N collections
|
||||
--enable-werror pass -Werror to the C compiler
|
||||
--enable-single-obj-compilation
|
||||
Compile all library .c files into single .o
|
||||
compile all libgc source files into single .o
|
||||
--enable-gcov turn on code coverage analysis
|
||||
--disable-docs do not build and install documentation
|
||||
|
||||
Optional Packages:
|
||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||
|
|
@ -1542,7 +1554,7 @@ Optional Packages:
|
|||
configuring with a cross compiler
|
||||
--with-cross-host=HOST configuring with a cross compiler
|
||||
--with-libatomic-ops=yes|no|check
|
||||
Use a external libatomic_ops? (default: check)
|
||||
Use an external libatomic_ops? (default: check)
|
||||
|
||||
Some influential environment variables:
|
||||
CC C compiler command
|
||||
|
|
@ -1573,7 +1585,7 @@ Some influential environment variables:
|
|||
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 <bdwgc@lists.opendylan.org>.
|
||||
Report bugs to <https://github.com/ivmai/bdwgc/issues>.
|
||||
_ACEOF
|
||||
ac_status=$?
|
||||
fi
|
||||
|
|
@ -1636,7 +1648,7 @@ fi
|
|||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
gc configure 7.5.0
|
||||
gc configure 7.6.8
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
|
|
@ -2102,9 +2114,9 @@ $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
|
|||
$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
|
||||
$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
|
||||
( $as_echo "## ---------------------------------------- ##
|
||||
## Report this to bdwgc@lists.opendylan.org ##
|
||||
## ---------------------------------------- ##"
|
||||
( $as_echo "## ---------------------------------------------------- ##
|
||||
## Report this to https://github.com/ivmai/bdwgc/issues ##
|
||||
## ---------------------------------------------------- ##"
|
||||
) | sed "s/^/$as_me: WARNING: /" >&2
|
||||
;;
|
||||
esac
|
||||
|
|
@ -2126,7 +2138,7 @@ cat >config.log <<_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 7.5.0, which was
|
||||
It was created by gc $as_me 7.6.8, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
|
|
@ -2474,7 +2486,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
|
|||
ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
## version must conform to [0-9]+[.][0-9]+[.][0-9]+
|
||||
|
||||
|
||||
|
||||
ac_aux_dir=
|
||||
|
|
@ -2617,7 +2629,42 @@ test -n "$target_alias" &&
|
|||
NONENONEs,x,x, &&
|
||||
program_prefix=${target_alias}-
|
||||
|
||||
GC_SET_VERSION
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking GC version numbers" >&5
|
||||
$as_echo_n "checking GC version numbers... " >&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_VERSION_MICRO=`echo $PACKAGE_VERSION | sed 's/^[^.]*[.][^.]*[.]\([0-9][0-9]*\)$/\1/g'`
|
||||
|
||||
if test :$GC_VERSION_MAJOR: = :: \
|
||||
-o :$GC_VERSION_MINOR: = :: \
|
||||
-o :$GC_VERSION_MICRO: = :: ;
|
||||
then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: invalid" >&5
|
||||
$as_echo "invalid" >&6; }
|
||||
as_fn_error $? "nonconforming PACKAGE_VERSION='$PACKAGE_VERSION'" "$LINENO" 5
|
||||
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
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define GC_VERSION_MICRO $GC_VERSION_MICRO
|
||||
_ACEOF
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: major=$GC_VERSION_MAJOR minor=$GC_VERSION_MINOR \
|
||||
micro=$GC_VERSION_MICRO" >&5
|
||||
$as_echo "major=$GC_VERSION_MAJOR minor=$GC_VERSION_MINOR \
|
||||
micro=$GC_VERSION_MICRO" >&6; }
|
||||
|
||||
am__api_version='1.15'
|
||||
|
||||
# Find a good install program. We prefer a C program (faster),
|
||||
|
|
@ -3104,7 +3151,7 @@ fi
|
|||
|
||||
# Define the identity of the package.
|
||||
PACKAGE='gc'
|
||||
VERSION='7.5.0'
|
||||
VERSION='7.6.8'
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
|
|
@ -16098,8 +16145,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
|||
# Only expand once:
|
||||
|
||||
|
||||
# Note: If Autoconf reports that LIBTOOL (or AC_ENABLE_SHARED, or
|
||||
# AC_PROG_LIBTOOL) is undefined, Libtool installation should be checked.
|
||||
|
||||
# Special CFLAGS to use when building
|
||||
gc_cflags=""
|
||||
|
|
@ -16118,7 +16163,7 @@ else
|
|||
if test :$GCC: != :"yes": ; then
|
||||
gc_cflags="${gc_flags} +ESdbgasm"
|
||||
fi
|
||||
# :TODO: actaully we should check using Autoconf if
|
||||
# :TODO: actually we should check using Autoconf if
|
||||
# the compiler supports this option.
|
||||
;;
|
||||
esac
|
||||
|
|
@ -16157,6 +16202,8 @@ esac
|
|||
GC_CFLAGS=${gc_cflags}
|
||||
|
||||
|
||||
|
||||
|
||||
# Check whether --enable-threads was given.
|
||||
if test "${enable_threads+set}" = set; then :
|
||||
enableval=$enable_threads; THREADS=$enableval
|
||||
|
|
@ -16227,6 +16274,9 @@ fi
|
|||
|
||||
|
||||
|
||||
|
||||
old_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $CFLAGS_EXTRA"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
|
||||
$as_echo_n "checking for inline... " >&6; }
|
||||
if ${ac_cv_c_inline+:} false; then :
|
||||
|
|
@ -16269,10 +16319,11 @@ _ACEOF
|
|||
;;
|
||||
esac
|
||||
|
||||
CFLAGS="$old_CFLAGS"
|
||||
|
||||
THREADDLLIBS=
|
||||
need_atomic_ops_asm=false
|
||||
## Libraries needed to support dynamic loading and/or threads.
|
||||
# Libraries needed to support dynamic loading and/or threads.
|
||||
case "$THREADS" in
|
||||
no | none | single)
|
||||
THREADS=none
|
||||
|
|
@ -16333,9 +16384,9 @@ fi
|
|||
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
|
||||
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
|
||||
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;}
|
||||
;;
|
||||
*-*-linux*)
|
||||
*-*-*linux* | *-*-nacl*)
|
||||
$as_echo "#define GC_LINUX_THREADS 1" >>confdefs.h
|
||||
|
||||
$as_echo "#define _REENTRANT 1" >>confdefs.h
|
||||
|
|
@ -16346,6 +16397,12 @@ $as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
|
|||
|
||||
$as_echo "#define _REENTRANT 1" >>confdefs.h
|
||||
|
||||
;;
|
||||
*-*-haiku*)
|
||||
$as_echo "#define GC_HAIKU_THREADS 1" >>confdefs.h
|
||||
|
||||
$as_echo "#define _REENTRANT 1" >>confdefs.h
|
||||
|
||||
;;
|
||||
*-*-hpux11*)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Only HP/UX 11 POSIX threads are supported.\"" >&5
|
||||
|
|
@ -16361,7 +16418,7 @@ $as_echo "$as_me: WARNING: \"Only HP/UX 11 POSIX threads are supported.\"" >&2;}
|
|||
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
|
||||
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
|
||||
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;}
|
||||
THREADDLLIBS="-lpthread -lrt"
|
||||
# HPUX needs REENTRANT for the _r calls.
|
||||
|
||||
|
|
@ -16378,7 +16435,7 @@ $as_echo "$as_me: WARNING: \"Only HP-UX 11 POSIX threads are supported.\"" >&2;}
|
|||
THREADDLLIBS=-pthread
|
||||
AM_CFLAGS="$AM_CFLAGS -pthread"
|
||||
;;
|
||||
*-*-freebsd*)
|
||||
*-*-dragonfly* | *-*-freebsd*)
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"FreeBSD does not yet fully support threads with Boehm GC.\"" >&5
|
||||
$as_echo "$as_me: WARNING: \"FreeBSD does not yet fully support threads with Boehm GC.\"" >&2;}
|
||||
$as_echo "#define GC_FREEBSD_THREADS 1" >>confdefs.h
|
||||
|
|
@ -16402,8 +16459,12 @@ $as_echo "$as_me: WARNING: \"FreeBSD does not yet fully support threads with Boe
|
|||
$as_echo "#define PARALLEL_MARK 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
|
||||
# FIXME: For a reason, gctest hangs up on kFreeBSD if both of
|
||||
# THREAD_LOCAL_ALLOC and GC_ENABLE_SUSPEND_THREAD are defined.
|
||||
if test x"$enable_gcj_support" = xno; then
|
||||
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
$as_echo "#define USE_COMPILER_TLS 1" >>confdefs.h
|
||||
|
||||
;;
|
||||
|
|
@ -16476,7 +16537,7 @@ $as_echo "$as_me: WARNING: \"Only on NetBSD 2.0 or later.\"" >&2;}
|
|||
$as_echo "#define GC_DARWIN_THREADS 1" >>confdefs.h
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
|
||||
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
|
||||
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;}
|
||||
# Parallel-mark is not well-tested on Darwin
|
||||
if test "${enable_parallel_mark}" != no; then
|
||||
$as_echo "#define PARALLEL_MARK 1" >>confdefs.h
|
||||
|
|
@ -16552,7 +16613,7 @@ $as_echo "$THREADDLLIBS" >&6; }
|
|||
$as_echo "#define THREAD_LOCAL_ALLOC 1" >>confdefs.h
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&5
|
||||
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;};
|
||||
$as_echo "$as_me: WARNING: \"Explicit GC_INIT() calls may be required.\"" >&2;}
|
||||
|
||||
$as_echo "#define GC_DGUX386_THREADS 1" >>confdefs.h
|
||||
|
||||
|
|
@ -16619,18 +16680,25 @@ fi
|
|||
|
||||
|
||||
compiler_suncc=no
|
||||
pthread_start_standalone=no
|
||||
case "$host" in
|
||||
powerpc-*-darwin*)
|
||||
*-*-*linux*)
|
||||
# Turn on the workaround described in pthread_start.c.
|
||||
if test "$THREADS" = posix; then :
|
||||
pthread_start_standalone=yes
|
||||
fi
|
||||
;;
|
||||
powerpc-*-darwin*)
|
||||
powerpc_darwin=true
|
||||
;;
|
||||
*-*-solaris*)
|
||||
*-*-solaris*)
|
||||
if test "$GCC" != yes; then
|
||||
# Solaris SunCC
|
||||
compiler_suncc=yes
|
||||
CFLAGS="-O $CFLAGS"
|
||||
fi
|
||||
;;
|
||||
*-*-wince*)
|
||||
*-*-wince*)
|
||||
if test "$enable_gc_debug" != "no"; then
|
||||
|
||||
$as_echo "#define GC_READ_ENV_FILE 1" >>confdefs.h
|
||||
|
|
@ -16638,11 +16706,19 @@ $as_echo "#define GC_READ_ENV_FILE 1" >>confdefs.h
|
|||
fi
|
||||
;;
|
||||
esac
|
||||
if test x$pthread_start_standalone = xyes; then
|
||||
PTHREAD_START_STANDALONE_TRUE=
|
||||
PTHREAD_START_STANDALONE_FALSE='#'
|
||||
else
|
||||
PTHREAD_START_STANDALONE_TRUE='#'
|
||||
PTHREAD_START_STANDALONE_FALSE=
|
||||
fi
|
||||
|
||||
|
||||
if test "$GCC" = yes; then
|
||||
# Output all warnings.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc -Wextra" >&5
|
||||
$as_echo_n "checking for gcc -Wextra... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wextra" >&5
|
||||
$as_echo_n "checking whether compiler supports -Wextra... " >&6; }
|
||||
old_CFLAGS="$CFLAGS"
|
||||
CFLAGS="-Wextra $CFLAGS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
|
|
@ -16670,7 +16746,36 @@ $as_echo "$ac_cv_cc_wextra" >&6; }
|
|||
else
|
||||
WEXTRA="-W"
|
||||
fi
|
||||
CFLAGS="-Wall $WEXTRA $CFLAGS"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wpedantic" >&5
|
||||
$as_echo_n "checking whether compiler supports -Wpedantic... " >&6; }
|
||||
CFLAGS="-Wpedantic -Wno-long-long $CFLAGS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
extern int quiet;
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
ac_cv_cc_pedantic=yes
|
||||
else
|
||||
ac_cv_cc_pedantic=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
CFLAGS="$old_CFLAGS"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_pedantic" >&5
|
||||
$as_echo "$ac_cv_cc_pedantic" >&6; }
|
||||
WPEDANTIC=
|
||||
if test "$ac_cv_cc_pedantic" = yes; then :
|
||||
WPEDANTIC="-Wpedantic -Wno-long-long"
|
||||
fi
|
||||
CFLAGS="-Wall $WEXTRA $WPEDANTIC $CFLAGS"
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for xlc" >&5
|
||||
|
|
@ -16718,8 +16823,8 @@ fi
|
|||
|
||||
if test "$GCC" = yes; then
|
||||
# Disable aliasing optimization unless forced to.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports -fno-strict-aliasing" >&5
|
||||
$as_echo_n "checking whether gcc supports -fno-strict-aliasing... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -fno-strict-aliasing" >&5
|
||||
$as_echo_n "checking whether compiler supports -fno-strict-aliasing... " >&6; }
|
||||
ac_cv_fno_strict_aliasing=no
|
||||
for cflag in $CFLAGS; do
|
||||
case "$cflag" in
|
||||
|
|
@ -16757,6 +16862,42 @@ fi
|
|||
$as_echo "$ac_cv_fno_strict_aliasing" >&6; }
|
||||
fi
|
||||
|
||||
# Check for getcontext (uClibc can be configured without it, for example)
|
||||
for ac_func in getcontext
|
||||
do :
|
||||
ac_fn_c_check_func "$LINENO" "getcontext" "ac_cv_func_getcontext"
|
||||
if test "x$ac_cv_func_getcontext" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_GETCONTEXT 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
if test "$ac_cv_func_getcontext" = "no"; then
|
||||
|
||||
$as_echo "#define NO_GETCONTEXT 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
# Check whether dl_iterate_phdr exists (as a strong symbol).
|
||||
for ac_func in dl_iterate_phdr
|
||||
do :
|
||||
ac_fn_c_check_func "$LINENO" "dl_iterate_phdr" "ac_cv_func_dl_iterate_phdr"
|
||||
if test "x$ac_cv_func_dl_iterate_phdr" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_DL_ITERATE_PHDR 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
if test "$ac_cv_func_dl_iterate_phdr" = "yes"; then
|
||||
|
||||
$as_echo "#define HAVE_DL_ITERATE_PHDR 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
case "$host" in
|
||||
# While IRIX 6 has libdl for the O32 and N32 ABIs, it's missing for N64
|
||||
# and unnecessary everywhere.
|
||||
|
|
@ -16825,6 +16966,25 @@ else
|
|||
fi
|
||||
|
||||
|
||||
# Check for various headers.
|
||||
for ac_header in execinfo.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_execinfo_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_EXECINFO_H 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if test "$ac_cv_header_execinfo_h" != "yes"; then
|
||||
|
||||
$as_echo "#define GC_MISSING_EXECINFO_H 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
# extra LD Flags which are required for targets
|
||||
case "${host}" in
|
||||
*-*-darwin*)
|
||||
|
|
@ -16948,8 +17108,8 @@ if test "${enable_shared}" = yes; then
|
|||
|
||||
if test "$GCC" = yes; then
|
||||
# Pass -fvisibility=hidden option if supported
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports -fvisibility" >&5
|
||||
$as_echo_n "checking whether gcc supports -fvisibility... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -fvisibility" >&5
|
||||
$as_echo_n "checking whether compiler supports -fvisibility... " >&6; }
|
||||
old_CFLAGS="$CFLAGS"
|
||||
CFLAGS="-Werror -fvisibility=hidden $CFLAGS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
|
|
@ -16972,6 +17132,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
|||
CFLAGS="$old_CFLAGS"
|
||||
if test "$ac_cv_fvisibility_hidden" = yes; then :
|
||||
CFLAGS="-DGC_VISIBILITY_HIDDEN_SET -fvisibility=hidden $CFLAGS"
|
||||
else
|
||||
CFLAGS="-DGC_NO_VISIBILITY $CFLAGS"
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_fvisibility_hidden" >&5
|
||||
$as_echo "$ac_cv_fvisibility_hidden" >&6; }
|
||||
|
|
@ -17016,6 +17178,10 @@ $as_echo "#define SUNOS53_SHARED_LIB 1" >>confdefs.h
|
|||
;;
|
||||
ia64-*-*)
|
||||
machdep="ia64_save_regs_in_stack.lo"
|
||||
;;
|
||||
*-*-nacl*)
|
||||
$as_echo "#define NO_EXECUTE_PERMISSION 1" >>confdefs.h
|
||||
|
||||
;;
|
||||
esac
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $machdep" >&5
|
||||
|
|
@ -17039,14 +17205,8 @@ if test "${with_cross_host+set}" = set; then :
|
|||
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
|
||||
|
||||
|
|
@ -17094,6 +17254,9 @@ if test x"$enable_gcj_support" != xno; then
|
|||
|
||||
$as_echo "#define GC_GCJ_SUPPORT 1" >>confdefs.h
|
||||
|
||||
|
||||
$as_echo "#define GC_ENABLE_SUSPEND_THREAD 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
# Check whether --enable-sigrt-signals was given.
|
||||
|
|
@ -17217,6 +17380,8 @@ fi
|
|||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dladdr" >&5
|
||||
$as_echo_n "checking for dladdr... " >&6; }
|
||||
have_dladdr=no
|
||||
old_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $CFLAGS_EXTRA"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
|
|
@ -17237,6 +17402,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
|
|||
have_dladdr=yes
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
CFLAGS="$old_CFLAGS"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_dladdr" >&5
|
||||
$as_echo "$have_dladdr" >&6; }
|
||||
if test x"$have_dladdr" = xyes; then
|
||||
|
|
@ -17254,7 +17420,6 @@ fi
|
|||
|
||||
|
||||
|
||||
## :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"
|
||||
|
|
@ -17285,7 +17450,7 @@ fi
|
|||
|
||||
if test x"$enable_atomic_uncollectible" != x"no"; then
|
||||
|
||||
$as_echo "#define ATOMIC_UNCOLLECTABLE 1" >>confdefs.h
|
||||
$as_echo "#define GC_ATOMIC_UNCOLLECTABLE 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
|
@ -17339,7 +17504,6 @@ if test "${enable_large_config+set}" = set; then :
|
|||
enableval=$enable_large_config;
|
||||
fi
|
||||
|
||||
|
||||
if test "${enable_large_config}" = yes; then
|
||||
|
||||
$as_echo "#define LARGE_CONFIG 1" >>confdefs.h
|
||||
|
|
@ -17351,7 +17515,6 @@ if test "${enable_handle_fork+set}" = set; then :
|
|||
enableval=$enable_handle_fork;
|
||||
fi
|
||||
|
||||
|
||||
if test "${enable_handle_fork}" = yes; then
|
||||
|
||||
$as_echo "#define HANDLE_FORK 1" >>confdefs.h
|
||||
|
|
@ -17395,18 +17558,11 @@ if test "${enable_munmap+set}" = set; then :
|
|||
enableval=$enable_munmap; MUNMAP_THRESHOLD=$enableval
|
||||
fi
|
||||
|
||||
if test "${enable_munmap}" != ""; then
|
||||
if test x$enable_munmap != x -a x$enable_munmap != xno; then
|
||||
|
||||
$as_echo "#define USE_MMAP 1" >>confdefs.h
|
||||
|
||||
case "$host" in
|
||||
*-*-cygwin*)
|
||||
# Workaround for Cygwin: use VirtualAlloc since mmap(PROT_NONE) fails
|
||||
|
||||
$as_echo "#define USE_WINALLOC 1" >>confdefs.h
|
||||
|
||||
;;
|
||||
esac
|
||||
|
||||
$as_echo "#define USE_MUNMAP 1" >>confdefs.h
|
||||
|
||||
|
|
@ -17435,6 +17591,24 @@ else
|
|||
fi
|
||||
|
||||
|
||||
# Check whether --enable-werror was given.
|
||||
if test "${enable_werror+set}" = set; then :
|
||||
enableval=$enable_werror; werror_flag=$enableval
|
||||
else
|
||||
werror_flag=no
|
||||
fi
|
||||
|
||||
if test x$werror_flag = xyes; then
|
||||
WERROR_CFLAGS="-Werror"
|
||||
case "$host" in
|
||||
# _dyld_bind_fully_image_containing_address is deprecated in OS X 10.5+
|
||||
*-*-darwin*)
|
||||
WERROR_CFLAGS="$WERROR_CFLAGS -Wno-deprecated-declarations"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-single-obj-compilation was given.
|
||||
if test "${enable_single_obj_compilation+set}" = set; then :
|
||||
enableval=$enable_single_obj_compilation; single_obj_compilation=yes
|
||||
|
|
@ -17449,6 +17623,37 @@ else
|
|||
fi
|
||||
|
||||
|
||||
# Check whether --enable-gcov was given.
|
||||
if test "${enable_gcov+set}" = set; then :
|
||||
enableval=$enable_gcov;
|
||||
fi
|
||||
|
||||
if test "$enable_gcov" = "yes"; then
|
||||
CFLAGS="$CFLAGS --coverage"
|
||||
if test "${enable_shared}" = no; then
|
||||
# FIXME: As of g++-4.8.4/x86_64, in case of shared library build, test_cpp
|
||||
# linkage fails with "hidden symbol atexit is referenced by DSO" message.
|
||||
CXXFLAGS="$CXXFLAGS --coverage"
|
||||
fi
|
||||
# Turn off optimization to get accurate line numbers.
|
||||
CFLAGS=`echo "$CFLAGS" | sed -e 's/-O\(1\|2\|3\|4\|s\|fast\)\?//g'`
|
||||
CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's/-O\(1\|2\|3\|4\|s\|fast\)\?//g'`
|
||||
fi
|
||||
|
||||
# Check whether --enable-docs was given.
|
||||
if test "${enable_docs+set}" = set; then :
|
||||
enableval=$enable_docs;
|
||||
fi
|
||||
|
||||
if test x$enable_docs != xno; then
|
||||
ENABLE_DOCS_TRUE=
|
||||
ENABLE_DOCS_FALSE='#'
|
||||
else
|
||||
ENABLE_DOCS_TRUE='#'
|
||||
ENABLE_DOCS_FALSE=
|
||||
fi
|
||||
|
||||
|
||||
# Atomic Ops
|
||||
# ----------
|
||||
|
||||
|
|
@ -17463,11 +17668,14 @@ else
|
|||
fi
|
||||
|
||||
|
||||
# Check for an external libatomic_ops if the answer was yes or check. If not
|
||||
# found, fail on yes, and convert check to no.
|
||||
# Note: "syntax error near unexpected token ATOMIC_OPS" reported by configure
|
||||
# means Autotools pkg.m4 file was not found during aclocal.m4 generation.
|
||||
# Check for an external libatomic_ops if the above answer is "yes" or "check".
|
||||
# If not found, fail on "yes", and convert "check" to "no".
|
||||
# First, check that libatomic_ops usage is not disabled explicitly.
|
||||
missing_libatomic_ops=false
|
||||
if test x"$with_libatomic_ops" != xno -a x"$THREADS" != xnone; then :
|
||||
missing_libatomic_ops=true
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -17588,11 +17796,11 @@ $as_echo "no" >&6; }
|
|||
PKG_CONFIG=""
|
||||
fi
|
||||
fi
|
||||
if test x"$with_libatomic_ops" != xno; then :
|
||||
if test x$missing_libatomic_ops = xtrue; then :
|
||||
|
||||
pkg_failed=no
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ATOMIC_OPS" >&5
|
||||
$as_echo_n "checking for ATOMIC_OPS... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for atomic_ops" >&5
|
||||
$as_echo_n "checking for atomic_ops... " >&6; }
|
||||
|
||||
if test -n "$ATOMIC_OPS_CFLAGS"; then
|
||||
pkg_cv_ATOMIC_OPS_CFLAGS="$ATOMIC_OPS_CFLAGS"
|
||||
|
|
@ -17632,7 +17840,7 @@ fi
|
|||
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
|
|
@ -17648,20 +17856,29 @@ fi
|
|||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$ATOMIC_OPS_PKG_ERRORS" >&5
|
||||
|
||||
missing_libatomic_ops=true
|
||||
|
||||
elif test $pkg_failed = untried; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
missing_libatomic_ops=true
|
||||
|
||||
else
|
||||
ATOMIC_OPS_CFLAGS=$pkg_cv_ATOMIC_OPS_CFLAGS
|
||||
ATOMIC_OPS_LIBS=$pkg_cv_ATOMIC_OPS_LIBS
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
missing_libatomic_ops=false
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x$missing_libatomic_ops = xtrue; then :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "atomic_ops.h" "ac_cv_header_atomic_ops_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_atomic_ops_h" = xyes; then :
|
||||
missing_libatomic_ops=false
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
fi
|
||||
if test x$missing_libatomic_ops = xtrue ; then :
|
||||
if test x$missing_libatomic_ops = xtrue; then :
|
||||
if test x"$with_libatomic_ops" != xcheck; then :
|
||||
as_fn_error $? "An external libatomic_ops was not found" "$LINENO" 5
|
||||
fi
|
||||
|
|
@ -17670,7 +17887,8 @@ fi
|
|||
|
||||
# If we have neither an external or an internal version, offer a useful hint
|
||||
# and exit.
|
||||
if test x"$with_libatomic_ops" = xno -a ! -e "$srcdir/libatomic_ops"; then :
|
||||
if test x"$with_libatomic_ops" = xno \
|
||||
-a ! -e "$srcdir/libatomic_ops/src/atomic_ops.h"; then :
|
||||
as_fn_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." "$LINENO" 5
|
||||
|
|
@ -17682,8 +17900,13 @@ $as_echo_n "checking which libatomic_ops to use... " >&6; }
|
|||
|
||||
|
||||
if test x"$with_libatomic_ops" != xno; then :
|
||||
if test x"$THREADS" != xnone; then :
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: external" >&5
|
||||
$as_echo "external" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
|
||||
$as_echo "none" >&6; }
|
||||
fi
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: internal" >&5
|
||||
$as_echo "internal" >&6; }
|
||||
|
|
@ -17879,6 +18102,10 @@ if test -z "${WIN32_THREADS_TRUE}" && test -z "${WIN32_THREADS_FALSE}"; then
|
|||
as_fn_error $? "conditional \"WIN32_THREADS\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${PTHREAD_START_STANDALONE_TRUE}" && test -z "${PTHREAD_START_STANDALONE_FALSE}"; then
|
||||
as_fn_error $? "conditional \"PTHREAD_START_STANDALONE\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${ASM_WITH_CPP_UNSUPPORTED_TRUE}" && test -z "${ASM_WITH_CPP_UNSUPPORTED_FALSE}"; then
|
||||
as_fn_error $? "conditional \"ASM_WITH_CPP_UNSUPPORTED\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
|
|
@ -17911,6 +18138,10 @@ if test -z "${SINGLE_GC_OBJ_TRUE}" && test -z "${SINGLE_GC_OBJ_FALSE}"; then
|
|||
as_fn_error $? "conditional \"SINGLE_GC_OBJ\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${ENABLE_DOCS_TRUE}" && test -z "${ENABLE_DOCS_FALSE}"; then
|
||||
as_fn_error $? "conditional \"ENABLE_DOCS\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${USE_INTERNAL_LIBATOMIC_OPS_TRUE}" && test -z "${USE_INTERNAL_LIBATOMIC_OPS_FALSE}"; then
|
||||
as_fn_error $? "conditional \"USE_INTERNAL_LIBATOMIC_OPS\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
|
|
@ -18316,7 +18547,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by gc $as_me 7.5.0, which was
|
||||
This file was extended by gc $as_me 7.6.8, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
|
|
@ -18376,13 +18607,13 @@ $config_headers
|
|||
Configuration commands:
|
||||
$config_commands
|
||||
|
||||
Report bugs to <bdwgc@lists.opendylan.org>."
|
||||
Report bugs to <https://github.com/ivmai/bdwgc/issues>."
|
||||
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
gc config.status 7.5.0
|
||||
gc config.status 7.6.8
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
|
||||
# Copyright (c) 2005-2009 Hewlett-Packard Development Company, L.P.
|
||||
# Copyright (c) 2009-2018 Ivan Maidanski
|
||||
#
|
||||
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
|
|
@ -11,15 +13,16 @@
|
|||
|
||||
dnl Process this file with autoconf to produce configure.
|
||||
|
||||
# Initialization
|
||||
AC_INIT(gc,7.5.0,bdwgc@lists.opendylan.org)
|
||||
## version must conform to [0-9]+[.][0-9]+[.][0-9]+
|
||||
dnl Initialization.
|
||||
AC_INIT(gc,7.6.8,https://github.com/ivmai/bdwgc/issues)
|
||||
dnl Version must conform to: [0-9]+[.][0-9]+[.][0-9]+
|
||||
|
||||
AC_CONFIG_SRCDIR(gcj_mlc.c)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CANONICAL_TARGET
|
||||
AC_PREREQ(2.61)
|
||||
GC_SET_VERSION
|
||||
AM_INIT_AUTOMAKE([foreign dist-bzip2 nostdinc subdir-objects])
|
||||
AM_INIT_AUTOMAKE([foreign nostdinc subdir-objects])
|
||||
AC_CONFIG_HEADERS([include/config.h])
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
|
|
@ -31,8 +34,8 @@ AC_PROG_CXX
|
|||
AM_PROG_AS
|
||||
AC_PROG_INSTALL
|
||||
LT_INIT
|
||||
# Note: If Autoconf reports that LIBTOOL (or AC_ENABLE_SHARED, or
|
||||
# AC_PROG_LIBTOOL) is undefined, Libtool installation should be checked.
|
||||
dnl Note: If Autoconf reports that LIBTOOL (or AC_ENABLE_SHARED, or
|
||||
dnl AC_PROG_LIBTOOL) is undefined, Libtool installation should be checked.
|
||||
|
||||
# Special CFLAGS to use when building
|
||||
gc_cflags=""
|
||||
|
|
@ -51,7 +54,7 @@ else
|
|||
if test :$GCC: != :"yes": ; then
|
||||
gc_cflags="${gc_flags} +ESdbgasm"
|
||||
fi
|
||||
# :TODO: actaully we should check using Autoconf if
|
||||
# :TODO: actually we should check using Autoconf if
|
||||
# the compiler supports this option.
|
||||
;;
|
||||
esac
|
||||
|
|
@ -90,6 +93,9 @@ esac
|
|||
GC_CFLAGS=${gc_cflags}
|
||||
AC_SUBST(GC_CFLAGS)
|
||||
|
||||
dnl Extra user-defined flags to pass both to C and C++ compilers.
|
||||
AC_SUBST([CFLAGS_EXTRA])
|
||||
|
||||
AC_ARG_ENABLE(threads,
|
||||
[AC_HELP_STRING([--enable-threads=TYPE], [choose threading package])],
|
||||
THREADS=$enableval,
|
||||
|
|
@ -137,6 +143,7 @@ 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_HAIKU_THREADS], [Define to support Haiku 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.])
|
||||
|
|
@ -164,11 +171,14 @@ AH_TEMPLATE([GC_DLL],
|
|||
[Define to build dynamic libraries with only API symbols exposed.])
|
||||
|
||||
dnl Check for a flavor of supported inline keyword.
|
||||
old_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $CFLAGS_EXTRA"
|
||||
AC_C_INLINE
|
||||
CFLAGS="$old_CFLAGS"
|
||||
|
||||
THREADDLLIBS=
|
||||
need_atomic_ops_asm=false
|
||||
## Libraries needed to support dynamic loading and/or threads.
|
||||
# Libraries needed to support dynamic loading and/or threads.
|
||||
case "$THREADS" in
|
||||
no | none | single)
|
||||
THREADS=none
|
||||
|
|
@ -185,9 +195,9 @@ case "$THREADS" in
|
|||
AC_DEFINE(PARALLEL_MARK)
|
||||
fi
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
|
||||
AC_MSG_WARN("Explicit GC_INIT() calls may be required.")
|
||||
;;
|
||||
*-*-linux*)
|
||||
*-*-*linux* | *-*-nacl*)
|
||||
AC_DEFINE(GC_LINUX_THREADS)
|
||||
AC_DEFINE(_REENTRANT)
|
||||
;;
|
||||
|
|
@ -195,6 +205,10 @@ case "$THREADS" in
|
|||
AC_DEFINE(GC_AIX_THREADS)
|
||||
AC_DEFINE(_REENTRANT)
|
||||
;;
|
||||
*-*-haiku*)
|
||||
AC_DEFINE(GC_HAIKU_THREADS)
|
||||
AC_DEFINE(_REENTRANT)
|
||||
;;
|
||||
*-*-hpux11*)
|
||||
AC_MSG_WARN("Only HP/UX 11 POSIX threads are supported.")
|
||||
AC_DEFINE(GC_HPUX_THREADS)
|
||||
|
|
@ -203,7 +217,7 @@ case "$THREADS" in
|
|||
AC_DEFINE(PARALLEL_MARK)
|
||||
fi
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
|
||||
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.])
|
||||
|
|
@ -216,7 +230,7 @@ case "$THREADS" in
|
|||
THREADDLLIBS=-pthread
|
||||
AM_CFLAGS="$AM_CFLAGS -pthread"
|
||||
;;
|
||||
*-*-freebsd*)
|
||||
*-*-dragonfly* | *-*-freebsd*)
|
||||
AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.")
|
||||
AC_DEFINE(GC_FREEBSD_THREADS)
|
||||
AM_CFLAGS="$AM_CFLAGS -pthread"
|
||||
|
|
@ -233,7 +247,11 @@ case "$THREADS" in
|
|||
if test "${enable_parallel_mark}" = yes; then
|
||||
AC_DEFINE(PARALLEL_MARK)
|
||||
fi
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
# FIXME: For a reason, gctest hangs up on kFreeBSD if both of
|
||||
# THREAD_LOCAL_ALLOC and GC_ENABLE_SUSPEND_THREAD are defined.
|
||||
if test x"$enable_gcj_support" = xno; then
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
fi
|
||||
AC_DEFINE(USE_COMPILER_TLS)
|
||||
;;
|
||||
*-*-gnu*)
|
||||
|
|
@ -286,7 +304,7 @@ case "$THREADS" in
|
|||
;;
|
||||
*-*-darwin*)
|
||||
AC_DEFINE(GC_DARWIN_THREADS)
|
||||
AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
|
||||
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)
|
||||
|
|
@ -346,7 +364,7 @@ case "$THREADS" in
|
|||
AC_DEFINE(PARALLEL_MARK)
|
||||
fi
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
AC_MSG_WARN("Explicit GC_INIT() calls may be required.");
|
||||
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,
|
||||
|
|
@ -379,35 +397,52 @@ AM_CONDITIONAL(DARWIN_THREADS, test x$darwin_threads = xtrue)
|
|||
AM_CONDITIONAL(WIN32_THREADS, test x$win32_threads = xtrue)
|
||||
|
||||
compiler_suncc=no
|
||||
pthread_start_standalone=no
|
||||
case "$host" in
|
||||
powerpc-*-darwin*)
|
||||
*-*-*linux*)
|
||||
# Turn on the workaround described in pthread_start.c.
|
||||
AS_IF([test "$THREADS" = posix], [pthread_start_standalone=yes])
|
||||
;;
|
||||
powerpc-*-darwin*)
|
||||
powerpc_darwin=true
|
||||
;;
|
||||
*-*-solaris*)
|
||||
*-*-solaris*)
|
||||
if test "$GCC" != yes; then
|
||||
# Solaris SunCC
|
||||
compiler_suncc=yes
|
||||
CFLAGS="-O $CFLAGS"
|
||||
fi
|
||||
;;
|
||||
*-*-wince*)
|
||||
*-*-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
|
||||
AM_CONDITIONAL(PTHREAD_START_STANDALONE,
|
||||
test x$pthread_start_standalone = xyes)
|
||||
|
||||
if test "$GCC" = yes; then
|
||||
# Output all warnings.
|
||||
AC_MSG_CHECKING(for gcc -Wextra)
|
||||
AC_MSG_CHECKING([whether compiler supports -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"
|
||||
AC_MSG_CHECKING([whether compiler supports -Wpedantic])
|
||||
CFLAGS="-Wpedantic -Wno-long-long $CFLAGS"
|
||||
AC_TRY_COMPILE([],[
|
||||
extern int quiet;
|
||||
], [ac_cv_cc_pedantic=yes], [ac_cv_cc_pedantic=no])
|
||||
CFLAGS="$old_CFLAGS"
|
||||
AC_MSG_RESULT($ac_cv_cc_pedantic)
|
||||
WPEDANTIC=
|
||||
AS_IF([test "$ac_cv_cc_pedantic" = yes],
|
||||
[WPEDANTIC="-Wpedantic -Wno-long-long"])
|
||||
CFLAGS="-Wall $WEXTRA $WPEDANTIC $CFLAGS"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for xlc)
|
||||
|
|
@ -429,7 +464,7 @@ AM_CONDITIONAL([ASM_WITH_CPP_UNSUPPORTED],
|
|||
|
||||
if test "$GCC" = yes; then
|
||||
# Disable aliasing optimization unless forced to.
|
||||
AC_MSG_CHECKING([whether gcc supports -fno-strict-aliasing])
|
||||
AC_MSG_CHECKING([whether compiler supports -fno-strict-aliasing])
|
||||
ac_cv_fno_strict_aliasing=no
|
||||
for cflag in $CFLAGS; do
|
||||
case "$cflag" in
|
||||
|
|
@ -451,6 +486,19 @@ if test "$GCC" = yes; then
|
|||
AC_MSG_RESULT($ac_cv_fno_strict_aliasing)
|
||||
fi
|
||||
|
||||
# Check for getcontext (uClibc can be configured without it, for example)
|
||||
AC_CHECK_FUNCS([getcontext])
|
||||
if test "$ac_cv_func_getcontext" = "no"; then
|
||||
AC_DEFINE([NO_GETCONTEXT], [1], [Missing getcontext function.])
|
||||
fi
|
||||
|
||||
# Check whether dl_iterate_phdr exists (as a strong symbol).
|
||||
AC_CHECK_FUNCS([dl_iterate_phdr])
|
||||
if test "$ac_cv_func_dl_iterate_phdr" = "yes"; then
|
||||
AC_DEFINE([HAVE_DL_ITERATE_PHDR], [1],
|
||||
[Define if 'dl_iterate_phdr' function is available.])
|
||||
fi
|
||||
|
||||
case "$host" in
|
||||
# While IRIX 6 has libdl for the O32 and N32 ABIs, it's missing for N64
|
||||
# and unnecessary everywhere.
|
||||
|
|
@ -473,6 +521,12 @@ case "$host" in
|
|||
esac
|
||||
AM_CONDITIONAL(AVOID_CPP_LIB,test $avoid_cpp_lib = yes)
|
||||
|
||||
# Check for various headers.
|
||||
AC_CHECK_HEADERS([execinfo.h])
|
||||
if test "$ac_cv_header_execinfo_h" != "yes"; then
|
||||
AC_DEFINE([GC_MISSING_EXECINFO_H], [1], [Missing execinfo.h header.])
|
||||
fi
|
||||
|
||||
# extra LD Flags which are required for targets
|
||||
case "${host}" in
|
||||
*-*-darwin*)
|
||||
|
|
@ -555,14 +609,15 @@ if test "${enable_shared}" = yes; then
|
|||
AC_DEFINE(GC_DLL)
|
||||
if test "$GCC" = yes; then
|
||||
# Pass -fvisibility=hidden option if supported
|
||||
AC_MSG_CHECKING([whether gcc supports -fvisibility])
|
||||
AC_MSG_CHECKING([whether compiler 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"])
|
||||
[CFLAGS="-DGC_VISIBILITY_HIDDEN_SET -fvisibility=hidden $CFLAGS"],
|
||||
[CFLAGS="-DGC_NO_VISIBILITY $CFLAGS"])
|
||||
AC_MSG_RESULT($ac_cv_fvisibility_hidden)
|
||||
fi
|
||||
fi
|
||||
|
|
@ -606,6 +661,9 @@ case "$host" in
|
|||
ia64-*-*)
|
||||
machdep="ia64_save_regs_in_stack.lo"
|
||||
;;
|
||||
*-*-nacl*)
|
||||
AC_DEFINE(NO_EXECUTE_PERMISSION)
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT($machdep)
|
||||
addobjs="$addobjs $machdep"
|
||||
|
|
@ -621,13 +679,13 @@ AC_ARG_WITH(target-subdir,
|
|||
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.
|
||||
dnl automake wants to see AC_EXEEXT. But we don't need it. And having
|
||||
dnl it is actually a problem, because the compiler we're passed can't
|
||||
dnl 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.
|
||||
dnl autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
|
||||
dnl to nothing, so nothing would remain between `then' and `fi' if it
|
||||
dnl were not for the `:' below.
|
||||
:
|
||||
AC_EXEEXT
|
||||
fi
|
||||
|
|
@ -674,16 +732,17 @@ 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.])])
|
||||
[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.])
|
||||
AC_DEFINE([GC_ENABLE_SUSPEND_THREAD], 1,
|
||||
[Define to turn on GC_suspend_thread support.])
|
||||
fi
|
||||
|
||||
dnl Interaction with other programs that might use signals.
|
||||
AC_ARG_ENABLE(sigrt-signals,
|
||||
[AC_HELP_STRING([--enable-sigrt-signals],
|
||||
[Force GC to use SIGRTMIN-based signals for thread suspend/resume])])
|
||||
[force GC to use SIGRTMIN-based signals for thread suspend/resume])])
|
||||
if test x"${enable_sigrt_signals}" = xyes; then
|
||||
AC_DEFINE([GC_USESIGRT_SIGNALS], 1,
|
||||
[Force the GC to use signals based on SIGRTMIN+k.])
|
||||
|
|
@ -740,12 +799,15 @@ AM_CONDITIONAL([KEEP_BACK_PTRS], [test x"$keep_back_ptrs" = xtrue])
|
|||
# Check for dladdr (used for debugging).
|
||||
AC_MSG_CHECKING(for dladdr)
|
||||
have_dladdr=no
|
||||
old_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $CFLAGS_EXTRA"
|
||||
AC_TRY_COMPILE([
|
||||
#define _GNU_SOURCE 1
|
||||
#include <dlfcn.h>], [{
|
||||
Dl_info info;
|
||||
(void)dladdr("", &info);
|
||||
}], [ have_dladdr=yes ])
|
||||
CFLAGS="$old_CFLAGS"
|
||||
AC_MSG_RESULT($have_dladdr)
|
||||
if test x"$have_dladdr" = xyes; then
|
||||
AC_DEFINE([HAVE_DLADDR], 1, [Define to use 'dladdr' function.])
|
||||
|
|
@ -756,7 +818,7 @@ 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
|
||||
dnl :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"
|
||||
|
|
@ -771,22 +833,22 @@ fi
|
|||
|
||||
AC_ARG_ENABLE(java-finalization,
|
||||
[AC_HELP_STRING([--disable-java-finalization],
|
||||
[Disable support for 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.])])
|
||||
[disable support for atomic uncollectible allocation])])
|
||||
if test x"$enable_atomic_uncollectible" != x"no"; then
|
||||
AC_DEFINE(ATOMIC_UNCOLLECTABLE, 1,
|
||||
AC_DEFINE([GC_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])])
|
||||
[redirect malloc and friends to GC routines])])
|
||||
|
||||
if test "${enable_redirect_malloc}" = yes; then
|
||||
if test "${enable_gc_debug}" = yes; then
|
||||
|
|
@ -804,7 +866,7 @@ fi
|
|||
|
||||
AC_ARG_ENABLE(disclaim,
|
||||
[AC_HELP_STRING([--disable-disclaim],
|
||||
[Disable alternative (more efficient) finalization interface.])])
|
||||
[disable alternative (more efficient) finalization interface])])
|
||||
if test x"$enable_disclaim" != xno; then
|
||||
AC_DEFINE(ENABLE_DISCLAIM, 1,
|
||||
[Define to enable alternative finalization interface.])
|
||||
|
|
@ -814,17 +876,16 @@ AM_CONDITIONAL(ENABLE_DISCLAIM,
|
|||
|
||||
AC_ARG_ENABLE(large-config,
|
||||
[AC_HELP_STRING([--enable-large-config],
|
||||
[Optimize for large (> 100 MB) heap or root set])])
|
||||
|
||||
[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.])
|
||||
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.])])
|
||||
|
||||
[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.])
|
||||
|
|
@ -835,7 +896,7 @@ 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.
|
||||
dnl These is only correct when targeting 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,
|
||||
|
|
@ -853,24 +914,20 @@ 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.])
|
||||
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
|
||||
if test x$enable_munmap != x -a x$enable_munmap != xno; 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,
|
||||
AH_TEMPLATE([USE_WINALLOC],
|
||||
[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).])
|
||||
|
|
@ -888,12 +945,45 @@ fi
|
|||
|
||||
AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
|
||||
|
||||
AC_ARG_ENABLE(werror,
|
||||
[AS_HELP_STRING([--enable-werror], [pass -Werror to the C compiler])],
|
||||
werror_flag=$enableval, werror_flag=no)
|
||||
if test x$werror_flag = xyes; then
|
||||
WERROR_CFLAGS="-Werror"
|
||||
case "$host" in
|
||||
# _dyld_bind_fully_image_containing_address is deprecated in OS X 10.5+
|
||||
*-*-darwin*)
|
||||
WERROR_CFLAGS="$WERROR_CFLAGS -Wno-deprecated-declarations"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
AC_SUBST([WERROR_CFLAGS])
|
||||
|
||||
AC_ARG_ENABLE(single-obj-compilation,
|
||||
[AC_HELP_STRING([--enable-single-obj-compilation],
|
||||
[Compile all library .c files into single .o])],
|
||||
[compile all libgc source files into single .o])],
|
||||
[single_obj_compilation=yes])
|
||||
AM_CONDITIONAL([SINGLE_GC_OBJ], [test "$single_obj_compilation" = "yes"])
|
||||
|
||||
AC_ARG_ENABLE(gcov,
|
||||
[AC_HELP_STRING([--enable-gcov], [turn on code coverage analysis])])
|
||||
if test "$enable_gcov" = "yes"; then
|
||||
CFLAGS="$CFLAGS --coverage"
|
||||
if test "${enable_shared}" = no; then
|
||||
# FIXME: As of g++-4.8.4/x86_64, in case of shared library build, test_cpp
|
||||
# linkage fails with "hidden symbol atexit is referenced by DSO" message.
|
||||
CXXFLAGS="$CXXFLAGS --coverage"
|
||||
fi
|
||||
# Turn off optimization to get accurate line numbers.
|
||||
CFLAGS=`echo "$CFLAGS" | sed -e 's/-O\(1\|2\|3\|4\|s\|fast\)\?//g'`
|
||||
CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's/-O\(1\|2\|3\|4\|s\|fast\)\?//g'`
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(docs,
|
||||
[AC_HELP_STRING([--disable-docs],
|
||||
[do not build and install documentation])])
|
||||
AM_CONDITIONAL(ENABLE_DOCS, test x$enable_docs != xno)
|
||||
|
||||
# Atomic Ops
|
||||
# ----------
|
||||
|
||||
|
|
@ -901,25 +991,36 @@ AM_CONDITIONAL([SINGLE_GC_OBJ], [test "$single_obj_compilation" = "yes"])
|
|||
# found.
|
||||
AC_ARG_WITH([libatomic-ops],
|
||||
[AS_HELP_STRING([--with-libatomic-ops[=yes|no|check]],
|
||||
[Use a external libatomic_ops? (default: check)])],
|
||||
[Use an 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.
|
||||
# Note: "syntax error near unexpected token ATOMIC_OPS" reported by configure
|
||||
# means Autotools pkg.m4 file was not found during aclocal.m4 generation.
|
||||
# Check for an external libatomic_ops if the above answer is "yes" or "check".
|
||||
# If not found, fail on "yes", and convert "check" to "no".
|
||||
# First, check that libatomic_ops usage is not disabled explicitly.
|
||||
missing_libatomic_ops=false
|
||||
AS_IF([test x"$with_libatomic_ops" != xno],
|
||||
[ PKG_CHECK_MODULES([ATOMIC_OPS], [atomic_ops], [],
|
||||
[ missing_libatomic_ops=true ]) ])
|
||||
AS_IF([test x$missing_libatomic_ops = xtrue ],
|
||||
AS_IF([test x"$with_libatomic_ops" != xno -a x"$THREADS" != xnone],
|
||||
[ missing_libatomic_ops=true ])
|
||||
|
||||
dnl Note: "syntax error near unexpected token ATOMIC_OPS" reported by configure
|
||||
dnl means Autotools pkg.m4 file was not found during aclocal.m4 generation;
|
||||
dnl in this case, most probably, you should run pkg-config once before running
|
||||
dnl autogen.sh (autoreconf); alternatively, comment out the following 3 lines.
|
||||
AS_IF([test x$missing_libatomic_ops = xtrue],
|
||||
[ PKG_CHECK_MODULES([ATOMIC_OPS], [atomic_ops],
|
||||
[ missing_libatomic_ops=false ], [ [] ]) ])
|
||||
|
||||
dnl Retry with AC_CHECK_HEADER if PKG_CHECK_MODULES failed.
|
||||
AS_IF([test x$missing_libatomic_ops = xtrue],
|
||||
[ AC_CHECK_HEADER([atomic_ops.h], [missing_libatomic_ops=false]) ])
|
||||
AS_IF([test x$missing_libatomic_ops = xtrue],
|
||||
[ AS_IF([test x"$with_libatomic_ops" != xcheck],
|
||||
[ AC_MSG_ERROR([An 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"],
|
||||
AS_IF([test x"$with_libatomic_ops" = xno \
|
||||
-a ! -e "$srcdir/libatomic_ops/src/atomic_ops.h"],
|
||||
[ 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.]) ])
|
||||
|
|
@ -927,7 +1028,8 @@ AS_IF([test x"$with_libatomic_ops" = xno -a ! -e "$srcdir/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]) ],
|
||||
[ AS_IF([test x"$THREADS" != xnone],
|
||||
[ AC_MSG_RESULT([external]) ], [ AC_MSG_RESULT([none]) ]) ],
|
||||
[ AC_MSG_RESULT([internal])
|
||||
ATOMIC_OPS_CFLAGS='-I$(top_builddir)/libatomic_ops/src -I$(top_srcdir)/libatomic_ops/src'
|
||||
ATOMIC_OPS_LIBS=""
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
## This file is processed with automake.
|
||||
|
||||
# Info (current:revision:age) for the Libtool versioning system.
|
||||
# These numbers should be updated at most once just before the release,
|
||||
# and, optionally, at most once during the development (after the release).
|
||||
LIBCORD_VER_INFO = 4:1:3
|
||||
|
||||
lib_LTLIBRARIES += libcord.la
|
||||
|
||||
libcord_la_LIBADD = $(top_builddir)/libgc.la
|
||||
libcord_la_LDFLAGS = -version-info 1:3:0 -no-undefined
|
||||
libcord_la_LDFLAGS = -version-info $(LIBCORD_VER_INFO) -no-undefined
|
||||
libcord_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
libcord_la_SOURCES = \
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ 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"); }
|
||||
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
|
||||
|
||||
typedef unsigned long word;
|
||||
|
|
@ -126,14 +126,14 @@ void CORD_dump_inner(CORD x, unsigned n)
|
|||
register struct Concatenation * conc =
|
||||
&(((CordRep *)x) -> concatenation);
|
||||
printf("Concatenation: %p (len: %d, depth: %d)\n",
|
||||
x, (int)(conc -> len), (int)(conc -> depth));
|
||||
(void *)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);
|
||||
if (IS_SUBSTR(x)) printf("(Substring) ");
|
||||
printf("Function: %p (len: %d): ", x, (int)(func -> len));
|
||||
printf("Function: %p (len: %d): ", (void *)x, (int)(func -> len));
|
||||
for (i = 0; i < 20 && i < func -> len; i++) {
|
||||
putchar((*(func -> fn))(i, func -> client_data));
|
||||
}
|
||||
|
|
@ -175,13 +175,14 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
|
|||
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)
|
||||
&& CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) {
|
||||
size_t right_len;
|
||||
|
||||
/* Merge y into right part of x. */
|
||||
if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) {
|
||||
right_len = lenx - LEN(left);
|
||||
|
|
@ -220,11 +221,15 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
|
|||
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->depth = (char)depth;
|
||||
if (lenx <= MAX_LEFT_LEN)
|
||||
result->left_len = (unsigned char)lenx;
|
||||
result->len = (word)result_len;
|
||||
result->left = x;
|
||||
result->right = y;
|
||||
GC_END_STUBBORN_CHANGE(result);
|
||||
GC_reachable_here(x);
|
||||
GC_reachable_here(y);
|
||||
if (depth >= MAX_DEPTH) {
|
||||
return(CORD_balance((CORD)result));
|
||||
} else {
|
||||
|
|
@ -261,11 +266,15 @@ CORD CORD_cat(CORD x, CORD y)
|
|||
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->depth = (char)depth;
|
||||
if (lenx <= MAX_LEFT_LEN)
|
||||
result->left_len = (unsigned char)lenx;
|
||||
result->len = (word)result_len;
|
||||
result->left = x;
|
||||
result->right = y;
|
||||
GC_END_STUBBORN_CHANGE(result);
|
||||
GC_reachable_here(x);
|
||||
GC_reachable_here(y);
|
||||
if (depth >= MAX_DEPTH) {
|
||||
return(CORD_balance((CORD)result));
|
||||
} else {
|
||||
|
|
@ -275,18 +284,17 @@ CORD CORD_cat(CORD x, CORD y)
|
|||
}
|
||||
|
||||
|
||||
|
||||
CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
|
||||
static CordRep *CORD_from_fn_inner(CORD_fn fn, void * client_data, size_t len)
|
||||
{
|
||||
if (len <= 0) return(0);
|
||||
if (len == 0) return(0);
|
||||
if (len <= SHORT_LIMIT) {
|
||||
register char * result;
|
||||
register size_t i;
|
||||
char buf[SHORT_LIMIT+1];
|
||||
register char c;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
c = (*fn)(i, client_data);
|
||||
char c = (*fn)(i, client_data);
|
||||
|
||||
if (c == '\0') goto gen_case;
|
||||
buf[i] = c;
|
||||
}
|
||||
|
|
@ -295,7 +303,7 @@ CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
|
|||
if (result == 0) OUT_OF_MEMORY;
|
||||
memcpy(result, buf, len);
|
||||
result[len] = '\0';
|
||||
return((CORD) result);
|
||||
return (CordRep *)result;
|
||||
}
|
||||
gen_case:
|
||||
{
|
||||
|
|
@ -305,13 +313,20 @@ CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
|
|||
if (result == 0) OUT_OF_MEMORY;
|
||||
result->header = FN_HDR;
|
||||
/* depth is already 0 */
|
||||
result->len = len;
|
||||
result->len = (word)len;
|
||||
result->fn = fn;
|
||||
result->client_data = client_data;
|
||||
return((CORD) result);
|
||||
GC_END_STUBBORN_CHANGE(result);
|
||||
GC_reachable_here(client_data);
|
||||
return (CordRep *)result;
|
||||
}
|
||||
}
|
||||
|
||||
CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
|
||||
{
|
||||
return (/* const */ CORD) CORD_from_fn_inner(fn, client_data, len);
|
||||
}
|
||||
|
||||
size_t CORD_len(CORD x)
|
||||
{
|
||||
if (x == 0) {
|
||||
|
|
@ -348,15 +363,17 @@ char CORD_apply_access_fn(size_t i, void * client_data)
|
|||
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;
|
||||
CordRep * 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);
|
||||
GC_END_STUBBORN_CHANGE(sa);
|
||||
GC_reachable_here(x);
|
||||
result = CORD_from_fn_inner(f, (void *)sa, n);
|
||||
if ((CORD)result != CORD_EMPTY && 0 == result -> function.null)
|
||||
result -> function.header = SUBSTR_HDR;
|
||||
return (CORD)result;
|
||||
}
|
||||
|
||||
# define SUBSTR_LIMIT (10 * SHORT_LIMIT)
|
||||
|
|
@ -430,12 +447,12 @@ CORD CORD_substr_checked(CORD x, size_t i, size_t n)
|
|||
register struct Function * f = &(((CordRep *)x) -> function);
|
||||
char buf[SUBSTR_LIMIT+1];
|
||||
register char * p = buf;
|
||||
register char c;
|
||||
register int j;
|
||||
register int lim = i + n;
|
||||
register size_t j;
|
||||
register size_t lim = i + n;
|
||||
|
||||
for (j = i; j < lim; j++) {
|
||||
c = (*(f -> fn))(j, f -> client_data);
|
||||
char c = (*(f -> fn))(j, f -> client_data);
|
||||
|
||||
if (c == '\0') {
|
||||
return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
|
||||
}
|
||||
|
|
@ -454,9 +471,7 @@ 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. */
|
||||
if (i >= len || n == 0) return(0);
|
||||
if (i + n > len) n = len - i;
|
||||
return(CORD_substr_checked(x, i, n));
|
||||
}
|
||||
|
|
@ -521,10 +536,10 @@ 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;
|
||||
char c = *p;
|
||||
|
||||
if (c == '\0') ABORT("2nd arg to CORD_riter4 too big");
|
||||
if ((*f1)(c, client_data)) return(1);
|
||||
if (p == x) break;
|
||||
|
|
@ -601,18 +616,19 @@ typedef ForestElement Forest [ MAX_DEPTH ];
|
|||
void CORD_init_min_len(void)
|
||||
{
|
||||
register int i;
|
||||
register size_t last, previous, current;
|
||||
size_t last, previous;
|
||||
|
||||
min_len[0] = previous = 1;
|
||||
min_len[1] = last = 2;
|
||||
for (i = 2; i < MAX_DEPTH; i++) {
|
||||
current = last + previous;
|
||||
size_t current = last + previous;
|
||||
|
||||
if (current < last) /* overflow */ current = last;
|
||||
min_len[i] = current;
|
||||
previous = last;
|
||||
last = current;
|
||||
}
|
||||
CORD_max_len = last - 1;
|
||||
CORD_max_len = (int)last - 1;
|
||||
min_len_init = 1;
|
||||
}
|
||||
|
||||
|
|
@ -869,7 +885,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) {
|
||||
if (p[0].cur_end != 0) {
|
||||
return(p[0].cur_leaf[p[0].cur_pos - p[0].cur_start]);
|
||||
} else {
|
||||
return(CORD__pos_fetch(p));
|
||||
|
|
@ -878,7 +894,7 @@ char CORD_pos_fetch(register CORD_pos p)
|
|||
|
||||
void CORD_next(CORD_pos p)
|
||||
{
|
||||
if (p[0].cur_pos < p[0].cur_end - 1) {
|
||||
if (p[0].cur_pos + 1 < p[0].cur_end) {
|
||||
p[0].cur_pos++;
|
||||
} else {
|
||||
CORD__next(p);
|
||||
|
|
|
|||
|
|
@ -30,9 +30,12 @@
|
|||
|
||||
#include "cord.h"
|
||||
#include "ec.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gc.h"
|
||||
|
||||
#define CONV_SPEC_LEN 50 /* Maximum length of a single */
|
||||
|
|
@ -41,6 +44,11 @@
|
|||
/* conversion with default */
|
||||
/* width and prec. */
|
||||
|
||||
#define OUT_OF_MEMORY do { \
|
||||
if (CORD_oom_fn != 0) (*CORD_oom_fn)(); \
|
||||
fprintf(stderr, "Out of memory\n"); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
static int ec_len(CORD_ec x)
|
||||
{
|
||||
|
|
@ -84,7 +92,9 @@ static int extract_conv_spec(CORD_pos source, char *buf,
|
|||
if (!saw_number) {
|
||||
/* Zero fill flag; ignore */
|
||||
break;
|
||||
} /* otherwise fall through: */
|
||||
}
|
||||
current_number *= 10;
|
||||
break;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
|
|
@ -164,6 +174,20 @@ static int extract_conv_spec(CORD_pos source, char *buf,
|
|||
return(result);
|
||||
}
|
||||
|
||||
#if defined(DJGPP) || defined(__STRICT_ANSI__)
|
||||
/* vsnprintf is missing in DJGPP (v2.0.3) */
|
||||
# define GC_VSNPRINTF(buf, bufsz, format, args) vsprintf(buf, format, args)
|
||||
#elif defined(_MSC_VER)
|
||||
# ifdef MSWINCE
|
||||
/* _vsnprintf is deprecated in WinCE */
|
||||
# define GC_VSNPRINTF StringCchVPrintfA
|
||||
# else
|
||||
# define GC_VSNPRINTF _vsnprintf
|
||||
# endif
|
||||
#else
|
||||
# define GC_VSNPRINTF vsnprintf
|
||||
#endif
|
||||
|
||||
int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
||||
{
|
||||
CORD_ec result;
|
||||
|
|
@ -220,11 +244,12 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
|||
if (prec != NONE && len > (size_t)prec) {
|
||||
if (prec < 0) return(-1);
|
||||
arg = CORD_substr(arg, 0, prec);
|
||||
len = prec;
|
||||
len = (unsigned)prec;
|
||||
}
|
||||
if (width != NONE && len < (size_t)width) {
|
||||
char * blanks = GC_MALLOC_ATOMIC(width-len+1);
|
||||
|
||||
if (NULL == blanks) OUT_OF_MEMORY;
|
||||
memset(blanks, ' ', width-len);
|
||||
blanks[width-len] = '\0';
|
||||
if (left_adj) {
|
||||
|
|
@ -249,7 +274,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
|||
char * str = va_arg(args, char *);
|
||||
register char c;
|
||||
|
||||
while ((c = *str++)) {
|
||||
while ((c = *str++) != '\0') {
|
||||
CORD_ec_append(result, c);
|
||||
}
|
||||
goto done;
|
||||
|
|
@ -263,16 +288,17 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
|||
register char * buf;
|
||||
va_list vsprintf_args;
|
||||
int max_size = 0;
|
||||
int res;
|
||||
# ifdef __va_copy
|
||||
int res = 0;
|
||||
|
||||
# if defined(CPPCHECK)
|
||||
va_copy(vsprintf_args, args);
|
||||
# elif defined(__va_copy)
|
||||
__va_copy(vsprintf_args, args);
|
||||
# else
|
||||
# if defined(__GNUC__) && !defined(__DJGPP__) \
|
||||
# elif defined(__GNUC__) && !defined(__DJGPP__) \
|
||||
&& !defined(__EMX__) /* and probably in other cases */
|
||||
va_copy(vsprintf_args, args);
|
||||
# else
|
||||
vsprintf_args = args;
|
||||
# endif
|
||||
va_copy(vsprintf_args, args);
|
||||
# else
|
||||
vsprintf_args = args;
|
||||
# endif
|
||||
if (width == VARIABLE) width = va_arg(args, int);
|
||||
if (prec == VARIABLE) prec = va_arg(args, int);
|
||||
|
|
@ -281,6 +307,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
|||
max_size += CONV_RESULT_LEN;
|
||||
if (max_size >= CORD_BUFSZ) {
|
||||
buf = GC_MALLOC_ATOMIC(max_size + 1);
|
||||
if (NULL == buf) OUT_OF_MEMORY;
|
||||
} else {
|
||||
if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
|
||||
< max_size) {
|
||||
|
|
@ -298,7 +325,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
|||
case 'c':
|
||||
if (long_arg <= 0) {
|
||||
(void) va_arg(args, int);
|
||||
} else if (long_arg > 0) {
|
||||
} else /* long_arg > 0 */ {
|
||||
(void) va_arg(args, long);
|
||||
}
|
||||
break;
|
||||
|
|
@ -314,15 +341,12 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
|||
(void) va_arg(args, double);
|
||||
break;
|
||||
default:
|
||||
# if defined(__va_copy) \
|
||||
|| (defined(__GNUC__) && !defined(__DJGPP__) \
|
||||
&& !defined(__EMX__))
|
||||
va_end(vsprintf_args);
|
||||
# endif
|
||||
return(-1);
|
||||
res = -1;
|
||||
}
|
||||
res = vsprintf(buf, conv_spec, vsprintf_args);
|
||||
# if defined(__va_copy) \
|
||||
if (0 == res)
|
||||
res = GC_VSNPRINTF(buf, max_size + 1, conv_spec,
|
||||
vsprintf_args);
|
||||
# if defined(CPPCHECK) || defined(__va_copy) \
|
||||
|| (defined(__GNUC__) && !defined(__DJGPP__) \
|
||||
&& !defined(__EMX__))
|
||||
va_end(vsprintf_args);
|
||||
|
|
@ -337,7 +361,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
|||
if (buf != result[0].ec_bufptr) {
|
||||
register char c;
|
||||
|
||||
while ((c = *buf++)) {
|
||||
while ((c = *buf++) != '\0') {
|
||||
CORD_ec_append(result, c);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -59,8 +59,8 @@
|
|||
|
||||
typedef void (* oom_fn)(void);
|
||||
|
||||
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
|
||||
ABORT("Out of memory\n"); }
|
||||
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
|
||||
ABORT("Out of memory"); }
|
||||
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
|
||||
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
|
|
@ -136,22 +136,23 @@ int CORD_batched_fill_proc(const char * s, void * client_data)
|
|||
}
|
||||
|
||||
/* 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)
|
||||
/* Assumes len characters are available in buf. */
|
||||
/* Return 1 if buf is filled fully (and len is */
|
||||
/* non-zero), 0 otherwise. */
|
||||
int 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;
|
||||
(void)CORD_iter5(x, i, CORD_fill_proc, CORD_batched_fill_proc, &fd);
|
||||
return CORD_iter5(x, i, CORD_fill_proc, CORD_batched_fill_proc, &fd);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -159,6 +160,8 @@ int CORD_cmp(CORD x, CORD y)
|
|||
CORD_set_pos(xpos, x, 0);
|
||||
CORD_set_pos(ypos, y, 0);
|
||||
for(;;) {
|
||||
size_t avail, yavail;
|
||||
|
||||
if (!CORD_pos_valid(xpos)) {
|
||||
if (CORD_pos_valid(ypos)) {
|
||||
return(-1);
|
||||
|
|
@ -169,8 +172,9 @@ int CORD_cmp(CORD x, CORD y)
|
|||
if (!CORD_pos_valid(ypos)) {
|
||||
return(1);
|
||||
}
|
||||
if ((avail = CORD_pos_chars_left(xpos)) <= 0
|
||||
|| (yavail = CORD_pos_chars_left(ypos)) <= 0) {
|
||||
avail = CORD_pos_chars_left(xpos);
|
||||
if (avail == 0
|
||||
|| (yavail = CORD_pos_chars_left(ypos)) == 0) {
|
||||
register char xcurrent = CORD_pos_fetch(xpos);
|
||||
register char ycurrent = CORD_pos_fetch(ypos);
|
||||
if (xcurrent != ycurrent) return(xcurrent - ycurrent);
|
||||
|
|
@ -195,11 +199,12 @@ int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
|
|||
CORD_pos xpos;
|
||||
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;) {
|
||||
long avail, yavail;
|
||||
|
||||
if (!CORD_pos_valid(xpos)) {
|
||||
if (CORD_pos_valid(ypos)) {
|
||||
return(-1);
|
||||
|
|
@ -224,7 +229,8 @@ int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
|
|||
|
||||
if (avail > yavail) avail = yavail;
|
||||
count += avail;
|
||||
if (count > len) avail -= (count - len);
|
||||
if (count > len)
|
||||
avail -= (long)(count - len);
|
||||
result = strncmp(CORD_pos_cur_char_addr(xpos),
|
||||
CORD_pos_cur_char_addr(ypos), (size_t)avail);
|
||||
if (result != 0) return(result);
|
||||
|
|
@ -241,7 +247,8 @@ char * CORD_to_char_star(CORD x)
|
|||
char * result = GC_MALLOC_ATOMIC(len + 1);
|
||||
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
CORD_fill_buf(x, 0, len, result);
|
||||
if (len > 0 && CORD_fill_buf(x, 0, len, result) != 1)
|
||||
ABORT("CORD_fill_buf malfunction");
|
||||
result[len] = '\0';
|
||||
return(result);
|
||||
}
|
||||
|
|
@ -341,7 +348,7 @@ size_t CORD_chr(CORD x, size_t i, int c)
|
|||
chr_data d;
|
||||
|
||||
d.pos = i;
|
||||
d.target = c;
|
||||
d.target = (char)c;
|
||||
if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) {
|
||||
return(d.pos);
|
||||
} else {
|
||||
|
|
@ -354,7 +361,7 @@ size_t CORD_rchr(CORD x, size_t i, int c)
|
|||
chr_data d;
|
||||
|
||||
d.pos = i;
|
||||
d.target = c;
|
||||
d.target = (char)c;
|
||||
if (CORD_riter4(x, i, CORD_rchr_proc, &d)) {
|
||||
return(d.pos);
|
||||
} else {
|
||||
|
|
@ -428,6 +435,7 @@ void CORD_ec_flush_buf(CORD_ec x)
|
|||
|
||||
if (len == 0) return;
|
||||
s = GC_MALLOC_ATOMIC(len+1);
|
||||
if (NULL == s) OUT_OF_MEMORY;
|
||||
memcpy(s, x[0].ec_buf, len);
|
||||
s[len] = '\0';
|
||||
x[0].ec_cord = CORD_cat_char_star(x[0].ec_cord, s, len);
|
||||
|
|
@ -442,23 +450,22 @@ void CORD_ec_append_cord(CORD_ec x, CORD s)
|
|||
|
||||
char CORD_nul_func(size_t i CORD_ATTR_UNUSED, void * client_data)
|
||||
{
|
||||
return((char)(unsigned long)client_data);
|
||||
return (char)(GC_word)client_data;
|
||||
}
|
||||
|
||||
|
||||
CORD CORD_chars(char c, size_t i)
|
||||
{
|
||||
return(CORD_from_fn(CORD_nul_func, (void *)(unsigned long)c, i));
|
||||
return CORD_from_fn(CORD_nul_func, (void *)(GC_word)(unsigned char)c, i);
|
||||
}
|
||||
|
||||
CORD CORD_from_file_eager(FILE * f)
|
||||
{
|
||||
register int c;
|
||||
CORD_ec ecord;
|
||||
|
||||
CORD_ec_init(ecord);
|
||||
for(;;) {
|
||||
c = getc(f);
|
||||
int c = getc(f);
|
||||
|
||||
if (c == 0) {
|
||||
/* Append the right number of NULs */
|
||||
/* Note that any string of NULs is represented in 4 words, */
|
||||
|
|
@ -470,7 +477,7 @@ CORD CORD_from_file_eager(FILE * f)
|
|||
ecord[0].ec_cord = CORD_cat(ecord[0].ec_cord, CORD_nul(count));
|
||||
}
|
||||
if (c == EOF) break;
|
||||
CORD_ec_append(ecord, c);
|
||||
CORD_ec_append(ecord, (char)c);
|
||||
}
|
||||
(void) fclose(f);
|
||||
return(CORD_balance(CORD_ec_to_cord(ecord)));
|
||||
|
|
@ -519,17 +526,17 @@ typedef struct {
|
|||
} refill_data;
|
||||
|
||||
/* Executed with allocation lock. */
|
||||
static char refill_cache(refill_data * client_data)
|
||||
static void * GC_CALLBACK refill_cache(void * client_data)
|
||||
{
|
||||
register lf_state * state = client_data -> state;
|
||||
register size_t file_pos = client_data -> file_pos;
|
||||
register lf_state * state = ((refill_data *)client_data) -> state;
|
||||
register size_t file_pos = ((refill_data *)client_data) -> file_pos;
|
||||
FILE *f = state -> lf_file;
|
||||
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;
|
||||
cache_line * new_cache = ((refill_data *)client_data) -> new_cache;
|
||||
|
||||
if (line_start != state -> lf_current
|
||||
&& fseek(f, line_start, SEEK_SET) != 0) {
|
||||
&& fseek(f, (long)line_start, SEEK_SET) != 0) {
|
||||
ABORT("fseek failed");
|
||||
}
|
||||
if (fread(new_cache -> data, sizeof(char), LINE_SZ, f)
|
||||
|
|
@ -539,8 +546,10 @@ static char refill_cache(refill_data * client_data)
|
|||
new_cache -> tag = DIV_LINE_SZ(file_pos);
|
||||
/* Store barrier goes here. */
|
||||
ATOMIC_WRITE(state -> lf_cache[line_no], new_cache);
|
||||
GC_END_STUBBORN_CHANGE((/* no volatile */ void *)(state -> lf_cache
|
||||
+ line_no));
|
||||
state -> lf_current = line_start + LINE_SZ;
|
||||
return(new_cache->data[MOD_LINE_SZ(file_pos)]);
|
||||
return (void *)((GC_word)new_cache->data[MOD_LINE_SZ(file_pos)]);
|
||||
}
|
||||
|
||||
char CORD_lf_func(size_t i, void * client_data)
|
||||
|
|
@ -558,8 +567,7 @@ char CORD_lf_func(size_t i, void * client_data)
|
|||
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));
|
||||
return (char)((GC_word)GC_call_with_alloc_lock(refill_cache, &rd));
|
||||
}
|
||||
return(cl -> data[MOD_LINE_SZ(i)]);
|
||||
}
|
||||
|
|
@ -585,11 +593,10 @@ CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
|
|||
/* world is multi-threaded. */
|
||||
char buf[1];
|
||||
|
||||
if (fread(buf, 1, 1, f) > 1) {
|
||||
/* Just to suppress "unused result" compiler warning. */
|
||||
ABORT("fread unexpected result");
|
||||
if (fread(buf, 1, 1, f) > 1
|
||||
|| fseek(f, 0l, SEEK_SET) != 0) {
|
||||
ABORT("Bad f argument or I/O failure");
|
||||
}
|
||||
rewind(f);
|
||||
}
|
||||
state -> lf_file = f;
|
||||
for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
|
||||
|
|
@ -604,13 +611,11 @@ CORD CORD_from_file_lazy(FILE * f)
|
|||
{
|
||||
register long len;
|
||||
|
||||
if (fseek(f, 0l, SEEK_END) != 0) {
|
||||
ABORT("Bad fd argument - fseek failed");
|
||||
if (fseek(f, 0l, SEEK_END) != 0
|
||||
|| (len = ftell(f)) < 0
|
||||
|| fseek(f, 0l, SEEK_SET) != 0) {
|
||||
ABORT("Bad f argument or I/O failure");
|
||||
}
|
||||
if ((len = ftell(f)) < 0) {
|
||||
ABORT("Bad fd argument - ftell failed");
|
||||
}
|
||||
rewind(f);
|
||||
return(CORD_from_file_lazy_inner(f, (size_t)len));
|
||||
}
|
||||
|
||||
|
|
@ -620,13 +625,11 @@ CORD CORD_from_file(FILE * f)
|
|||
{
|
||||
register long len;
|
||||
|
||||
if (fseek(f, 0l, SEEK_END) != 0) {
|
||||
ABORT("Bad fd argument - fseek failed");
|
||||
if (fseek(f, 0l, SEEK_END) != 0
|
||||
|| (len = ftell(f)) < 0
|
||||
|| fseek(f, 0l, SEEK_SET) != 0) {
|
||||
ABORT("Bad f argument or I/O failure");
|
||||
}
|
||||
if ((len = ftell(f)) < 0) {
|
||||
ABORT("Bad fd argument - ftell failed");
|
||||
}
|
||||
rewind(f);
|
||||
if (len < LAZY_THRESHOLD) {
|
||||
return(CORD_from_file_eager(f));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -13,15 +13,28 @@
|
|||
|
||||
# include "gc.h" /* For GC_INIT() only */
|
||||
# include "cord.h"
|
||||
|
||||
# include <stdarg.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. */
|
||||
/* that real clients shouldn't rely on. */
|
||||
|
||||
# define ABORT(string) \
|
||||
{ int x = 0; fprintf(stderr, "FAILED: %s\n", string); x = 1 / x; abort(); }
|
||||
{ fprintf(stderr, "FAILED: %s\n", string); abort(); }
|
||||
|
||||
#if defined(CPPCHECK)
|
||||
# undef CORD_iter
|
||||
# undef CORD_next
|
||||
# undef CORD_pos_fetch
|
||||
# undef CORD_pos_to_cord
|
||||
# undef CORD_pos_to_index
|
||||
# undef CORD_pos_valid
|
||||
# undef CORD_prev
|
||||
#endif
|
||||
|
||||
int count;
|
||||
|
||||
|
|
@ -53,7 +66,6 @@ void test_basics(void)
|
|||
{
|
||||
CORD x = CORD_from_char_star("ab");
|
||||
register int i;
|
||||
char c;
|
||||
CORD y;
|
||||
CORD_pos p;
|
||||
|
||||
|
|
@ -114,11 +126,22 @@ void test_basics(void)
|
|||
i = 0;
|
||||
CORD_set_pos(p, y, i);
|
||||
while(CORD_pos_valid(p)) {
|
||||
c = CORD_pos_fetch(p);
|
||||
char c = CORD_pos_fetch(p);
|
||||
|
||||
if(c != i) ABORT("Traversal of function node failed");
|
||||
CORD_next(p); i++;
|
||||
CORD_next(p);
|
||||
i++;
|
||||
}
|
||||
if (i != 13) ABORT("Bad apparent length for function node");
|
||||
# if defined(CPPCHECK)
|
||||
/* TODO: Actually test these functions. */
|
||||
CORD_prev(p);
|
||||
(void)CORD_pos_to_cord(p);
|
||||
(void)CORD_pos_to_index(p);
|
||||
(void)CORD_iter(CORD_EMPTY, test_fn, NULL);
|
||||
(void)CORD_riter(CORD_EMPTY, test_fn, NULL);
|
||||
CORD_dump(y);
|
||||
# endif
|
||||
}
|
||||
|
||||
void test_extras(void)
|
||||
|
|
@ -128,7 +151,7 @@ void test_extras(void)
|
|||
register int i;
|
||||
CORD y = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
CORD x = "{}";
|
||||
CORD w, z;
|
||||
CORD u, w, z;
|
||||
FILE *f;
|
||||
FILE *f1a, *f1b, *f2;
|
||||
|
||||
|
|
@ -180,7 +203,9 @@ void test_extras(void)
|
|||
ABORT("file substr wrong");
|
||||
if (strcmp(CORD_to_char_star(CORD_substr(w, 1000*36, 36)), y) != 0)
|
||||
ABORT("char * file substr wrong");
|
||||
if (strcmp(CORD_substr(w, 1000*36, 2), "ab") != 0)
|
||||
u = CORD_substr(w, 1000*36, 2);
|
||||
if (!u) ABORT("CORD_substr returned NULL");
|
||||
if (strcmp(u, "ab") != 0)
|
||||
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");
|
||||
|
|
@ -197,13 +222,35 @@ void test_extras(void)
|
|||
if (remove(FNAME1) != 0) {
|
||||
/* 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");
|
||||
fprintf(stderr, "WARNING: remove failed: " FNAME1 "\n");
|
||||
}
|
||||
if (remove(FNAME2) != 0) {
|
||||
fprintf(stderr, "WARNING: remove(FNAME2) failed\n");
|
||||
fprintf(stderr, "WARNING: remove failed: " FNAME2 "\n");
|
||||
}
|
||||
}
|
||||
|
||||
int wrap_vprintf(CORD format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int result;
|
||||
|
||||
va_start(args, format);
|
||||
result = CORD_vprintf(format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
int wrap_vfprintf(FILE * f, CORD format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int result;
|
||||
|
||||
va_start(args, format);
|
||||
result = CORD_vfprintf(f, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(__DJGPP__) || defined(__STRICT_ANSI__)
|
||||
/* snprintf is missing in DJGPP (v2.0.3) */
|
||||
#else
|
||||
|
|
@ -249,6 +296,10 @@ void test_printf(void)
|
|||
# endif
|
||||
result2[sizeof(result2) - 1] = '\0';
|
||||
if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
|
||||
/* TODO: Better test CORD_[v][f]printf. */
|
||||
(void)CORD_printf(CORD_EMPTY);
|
||||
(void)wrap_vfprintf(stdout, CORD_EMPTY);
|
||||
(void)wrap_vprintf(CORD_EMPTY);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
|
|
|
|||
|
|
@ -27,13 +27,15 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for exit() */
|
||||
|
||||
#include "gc.h"
|
||||
#include "cord.h"
|
||||
|
||||
#ifdef THINK_C
|
||||
#define MACINTOSH
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
|
||||
#if (defined(__BORLANDC__) || defined(__CYGWIN__)) && !defined(WIN32)
|
||||
/* If this is DOS or win16, we'll fail anyway. */
|
||||
|
|
@ -63,10 +65,16 @@
|
|||
# define COLS 80
|
||||
#else
|
||||
# include <curses.h>
|
||||
# include <unistd.h> /* for sleep() */
|
||||
# define de_error(s) { fprintf(stderr, s); sleep(2); }
|
||||
#endif
|
||||
#include "de_cmds.h"
|
||||
|
||||
#define OUT_OF_MEMORY do { \
|
||||
fprintf(stderr, "Out of memory\n"); \
|
||||
exit(3); \
|
||||
} while (0)
|
||||
|
||||
/* List of line number to position mappings, in descending order. */
|
||||
/* There may be holes. */
|
||||
typedef struct LineMapRep {
|
||||
|
|
@ -125,21 +133,30 @@ void prune_map(void)
|
|||
do {
|
||||
current_map_size++;
|
||||
if (map -> line < start_line - LINES && map -> previous != 0) {
|
||||
map -> previous = map -> previous -> previous;
|
||||
line_map pred = map -> previous -> previous;
|
||||
|
||||
map -> previous = pred;
|
||||
GC_END_STUBBORN_CHANGE(map);
|
||||
GC_reachable_here(pred);
|
||||
}
|
||||
map = map -> previous;
|
||||
} while (map != 0);
|
||||
}
|
||||
|
||||
/* Add mapping entry */
|
||||
void add_map(int line, size_t pos)
|
||||
void add_map(int line_arg, size_t pos)
|
||||
{
|
||||
line_map new_map = GC_NEW(struct LineMapRep);
|
||||
line_map cur_map;
|
||||
|
||||
if (NULL == new_map) OUT_OF_MEMORY;
|
||||
if (current_map_size >= MAX_MAP_SIZE) prune_map();
|
||||
new_map -> line = line;
|
||||
new_map -> line = line_arg;
|
||||
new_map -> pos = pos;
|
||||
new_map -> previous = current_map;
|
||||
cur_map = current_map;
|
||||
new_map -> previous = cur_map;
|
||||
GC_END_STUBBORN_CHANGE(new_map);
|
||||
GC_reachable_here(cur_map);
|
||||
current_map = new_map;
|
||||
current_map_size++;
|
||||
}
|
||||
|
|
@ -155,7 +172,6 @@ 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;
|
||||
|
|
@ -167,10 +183,11 @@ size_t line_pos(int i, int *c)
|
|||
if (++j > current_map -> line) add_map(j, cur);
|
||||
}
|
||||
if (c != 0) {
|
||||
next = CORD_chr(current, cur, '\n');
|
||||
size_t next = CORD_chr(current, cur, '\n');
|
||||
|
||||
if (next == CORD_NOT_FOUND) next = current_len - 1;
|
||||
if (next < cur + *c) {
|
||||
*c = next - cur;
|
||||
*c = (int)(next - cur);
|
||||
}
|
||||
cur += *c;
|
||||
}
|
||||
|
|
@ -181,10 +198,15 @@ void add_hist(CORD s)
|
|||
{
|
||||
history new_file = GC_NEW(struct HistoryRep);
|
||||
|
||||
if (NULL == new_file) OUT_OF_MEMORY;
|
||||
new_file -> file_contents = current = s;
|
||||
current_len = CORD_len(s);
|
||||
new_file -> previous = now;
|
||||
if (now != 0) now -> map = current_map;
|
||||
GC_END_STUBBORN_CHANGE(new_file);
|
||||
if (now != NULL) {
|
||||
now -> map = current_map;
|
||||
GC_END_STUBBORN_CHANGE(now);
|
||||
}
|
||||
now = new_file;
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +228,6 @@ int screen_size = 0;
|
|||
/* terribly appropriate for tabs. */
|
||||
void replace_line(int i, CORD s)
|
||||
{
|
||||
register int c;
|
||||
CORD_pos p;
|
||||
# if !defined(MACINTOSH)
|
||||
size_t len = CORD_len(s);
|
||||
|
|
@ -215,10 +236,11 @@ void replace_line(int i, CORD s)
|
|||
if (screen == 0 || LINES > screen_size) {
|
||||
screen_size = LINES;
|
||||
screen = (CORD *)GC_MALLOC(screen_size * sizeof(CORD));
|
||||
if (NULL == screen) OUT_OF_MEMORY;
|
||||
}
|
||||
# if !defined(MACINTOSH)
|
||||
/* A gross workaround for an apparent curses bug: */
|
||||
if (i == LINES-1 && len == COLS) {
|
||||
if (i == LINES-1 && len == (unsigned)COLS) {
|
||||
s = CORD_substr(s, 0, len - 1);
|
||||
}
|
||||
# endif
|
||||
|
|
@ -226,7 +248,8 @@ void replace_line(int i, CORD s)
|
|||
move(i, 0); clrtoeol(); move(i,0);
|
||||
|
||||
CORD_FOR (p, s) {
|
||||
c = CORD_pos_fetch(p) & 0x7f;
|
||||
int c = CORD_pos_fetch(p) & 0x7f;
|
||||
|
||||
if (iscntrl(c)) {
|
||||
standout(); addch(c + 0x40); standend();
|
||||
} else {
|
||||
|
|
@ -234,6 +257,8 @@ void replace_line(int i, CORD s)
|
|||
}
|
||||
}
|
||||
screen[i] = s;
|
||||
GC_END_STUBBORN_CHANGE(screen + i);
|
||||
GC_reachable_here(s);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
|
@ -336,7 +361,8 @@ void fix_pos(void)
|
|||
{
|
||||
int my_col = col;
|
||||
|
||||
if ((size_t)line > current_len) line = current_len;
|
||||
if ((size_t)line > current_len)
|
||||
line = (int)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;
|
||||
|
|
@ -417,7 +443,7 @@ void do_command(int c)
|
|||
if (file_pos > new_pos) break;
|
||||
line++;
|
||||
}
|
||||
col = new_pos - line_pos(line, 0);
|
||||
col = (int)(new_pos - line_pos(line, 0));
|
||||
file_pos = new_pos;
|
||||
fix_cursor();
|
||||
} else {
|
||||
|
|
@ -448,7 +474,8 @@ void do_command(int c)
|
|||
locate_mode = 1;
|
||||
break;
|
||||
case TOP:
|
||||
line = col = file_pos = 0;
|
||||
line = col = 0;
|
||||
file_pos = 0;
|
||||
break;
|
||||
case UP:
|
||||
if (line != 0) {
|
||||
|
|
@ -479,7 +506,7 @@ void do_command(int c)
|
|||
break;
|
||||
}
|
||||
col--; file_pos--;
|
||||
/* fall through: */
|
||||
/* FALLTHRU */
|
||||
case DEL:
|
||||
if (file_pos == current_len-1) break;
|
||||
/* Can't delete trailing newline */
|
||||
|
|
@ -541,9 +568,11 @@ void generic_init(void)
|
|||
if ((f = fopen(arg_file_name, "rb")) == NULL) {
|
||||
initial = "\n";
|
||||
} else {
|
||||
size_t len;
|
||||
|
||||
initial = CORD_from_file(f);
|
||||
if (initial == CORD_EMPTY
|
||||
|| CORD_fetch(initial, CORD_len(initial)-1) != '\n') {
|
||||
len = CORD_len(initial);
|
||||
if (0 == len || CORD_fetch(initial, len - 1) != '\n') {
|
||||
initial = CORD_cat(initial, "\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -551,50 +580,51 @@ void generic_init(void)
|
|||
add_hist(initial);
|
||||
now -> map = current_map;
|
||||
now -> previous = now; /* Can't back up further: beginning of the world */
|
||||
GC_END_STUBBORN_CHANGE(now);
|
||||
need_redisplay = ALL;
|
||||
fix_cursor();
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char ** argv;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
void *buf;
|
||||
|
||||
#if defined(MACINTOSH)
|
||||
# if defined(MACINTOSH)
|
||||
console_options.title = "\pDumb Editor";
|
||||
cshow(stdout);
|
||||
argc = ccommand(&argv);
|
||||
#endif
|
||||
# endif
|
||||
GC_INIT();
|
||||
|
||||
if (argc != 2) goto usage;
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s file\n", argv[0]);
|
||||
fprintf(stderr, "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n");
|
||||
fprintf(stderr, "Undo: ^U Write to <file>.new: ^W");
|
||||
fprintf(stderr, "Quit:^D Repeat count: ^R[n]\n");
|
||||
fprintf(stderr, "Top: ^T Locate (search, find): ^L text ^L\n");
|
||||
exit(1);
|
||||
}
|
||||
arg_file_name = argv[1];
|
||||
setvbuf(stdout, GC_MALLOC_ATOMIC(8192), _IOFBF, 8192);
|
||||
buf = GC_MALLOC_ATOMIC(8192);
|
||||
if (NULL == buf) OUT_OF_MEMORY;
|
||||
setvbuf(stdout, buf, _IOFBF, 8192);
|
||||
initscr();
|
||||
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);
|
||||
clrtoeol();
|
||||
refresh();
|
||||
nl();
|
||||
echo();
|
||||
endwin();
|
||||
exit(0);
|
||||
usage:
|
||||
fprintf(stderr, "Usage: %s file\n", argv[0]);
|
||||
fprintf(stderr, "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n");
|
||||
fprintf(stderr, "Undo: ^U Write to <file>.new: ^W");
|
||||
fprintf(stderr, "Quit:^D Repeat count: ^R[n]\n");
|
||||
fprintf(stderr, "Top: ^T Locate (search, find): ^L text ^L\n");
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !WIN32 */
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@ 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. */
|
||||
GC_INIT();
|
||||
# if defined(CPPCHECK)
|
||||
GC_noop1((GC_word)&WinMain);
|
||||
# endif
|
||||
|
||||
if (!hPrevInstance)
|
||||
|
|
@ -65,11 +65,7 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||
wndclass.lpszClassName = szAppName;
|
||||
|
||||
if (RegisterClass (&wndclass) == 0) {
|
||||
char buf[50];
|
||||
|
||||
sprintf(buf, "RegisterClass: error code: 0x%X",
|
||||
(unsigned)GetLastError());
|
||||
de_error(buf);
|
||||
de_error("RegisterClass error");
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -102,11 +98,7 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||
NULL, /* Window class menu */
|
||||
hInstance, NULL);
|
||||
if (hwnd == NULL) {
|
||||
char buf[50];
|
||||
|
||||
sprintf(buf, "CreateWindow: error code: 0x%X",
|
||||
(unsigned)GetLastError());
|
||||
de_error(buf);
|
||||
de_error("CreateWindow error");
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +114,7 @@ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||
DispatchMessage (&msg);
|
||||
}
|
||||
}
|
||||
return msg.wParam;
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
|
||||
/* Return the argument with all control characters replaced by blanks. */
|
||||
|
|
@ -131,6 +123,7 @@ char * plain_chars(char * text, size_t len)
|
|||
char * result = GC_MALLOC_ATOMIC(len + 1);
|
||||
register size_t i;
|
||||
|
||||
if (NULL == result) return NULL;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (iscntrl(((unsigned char *)text)[i])) {
|
||||
result[i] = ' ';
|
||||
|
|
@ -149,6 +142,7 @@ char * control_chars(char * text, size_t len)
|
|||
char * result = GC_MALLOC_ATOMIC(len + 1);
|
||||
register size_t i;
|
||||
|
||||
if (NULL == result) return NULL;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (iscntrl(((unsigned char *)text)[i])) {
|
||||
result[i] = text[i] + 0x40;
|
||||
|
|
@ -163,9 +157,9 @@ char * control_chars(char * text, size_t len)
|
|||
int char_width;
|
||||
int char_height;
|
||||
|
||||
void get_line_rect(int line, int win_width, RECT * rectp)
|
||||
void get_line_rect(int line_arg, int win_width, RECT * rectp)
|
||||
{
|
||||
rectp -> top = line * char_height;
|
||||
rectp -> top = line_arg * (LONG)char_height;
|
||||
rectp -> bottom = rectp->top + char_height;
|
||||
rectp -> left = 0;
|
||||
rectp -> right = win_width;
|
||||
|
|
@ -204,7 +198,7 @@ INT_PTR CALLBACK AboutBoxCallback( HWND hDlg, UINT message,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
||||
LRESULT CALLBACK WndProc (HWND hwnd_arg, UINT message,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static HANDLE hInstance;
|
||||
|
|
@ -221,13 +215,13 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
|||
{
|
||||
case WM_CREATE:
|
||||
hInstance = ( (LPCREATESTRUCT) lParam)->hInstance;
|
||||
dc = GetDC(hwnd);
|
||||
dc = GetDC(hwnd_arg);
|
||||
SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
|
||||
GetTextMetrics(dc, &tm);
|
||||
ReleaseDC(hwnd, dc);
|
||||
ReleaseDC(hwnd_arg, dc);
|
||||
char_width = tm.tmAveCharWidth;
|
||||
char_height = tm.tmHeight + tm.tmExternalLeading;
|
||||
GetClientRect(hwnd, &client_area);
|
||||
GetClientRect(hwnd_arg, &client_area);
|
||||
COLS = (client_area.right - client_area.left)/char_width;
|
||||
LINES = (client_area.bottom - client_area.top)/char_height;
|
||||
generic_init();
|
||||
|
|
@ -235,21 +229,21 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
|||
|
||||
case WM_CHAR:
|
||||
if (wParam == QUIT) {
|
||||
SendMessage( hwnd, WM_CLOSE, 0, 0L );
|
||||
SendMessage(hwnd_arg, WM_CLOSE, 0, 0L);
|
||||
} else {
|
||||
do_command((int)wParam);
|
||||
}
|
||||
return(0);
|
||||
|
||||
case WM_SETFOCUS:
|
||||
CreateCaret(hwnd, NULL, char_width, char_height);
|
||||
ShowCaret(hwnd);
|
||||
CreateCaret(hwnd_arg, NULL, char_width, char_height);
|
||||
ShowCaret(hwnd_arg);
|
||||
caret_visible = 1;
|
||||
update_cursor();
|
||||
return(0);
|
||||
|
||||
case WM_KILLFOCUS:
|
||||
HideCaret(hwnd);
|
||||
HideCaret(hwnd_arg);
|
||||
DestroyCaret();
|
||||
caret_visible = 0;
|
||||
return(0);
|
||||
|
|
@ -273,13 +267,13 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
|||
} else {
|
||||
switch(id) {
|
||||
case IDM_FILEEXIT:
|
||||
SendMessage( hwnd, WM_CLOSE, 0, 0L );
|
||||
SendMessage(hwnd_arg, WM_CLOSE, 0, 0L);
|
||||
return( 0 );
|
||||
|
||||
case IDM_HELPABOUT:
|
||||
if( DialogBox( hInstance, TEXT("ABOUTBOX"),
|
||||
hwnd, AboutBoxCallback ) )
|
||||
InvalidateRect( hwnd, NULL, TRUE );
|
||||
hwnd_arg, AboutBoxCallback ) )
|
||||
InvalidateRect(hwnd_arg, NULL, TRUE);
|
||||
return( 0 );
|
||||
case IDM_HELPCONTENTS:
|
||||
de_error(
|
||||
|
|
@ -292,7 +286,7 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
|||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
DestroyWindow( hwnd );
|
||||
DestroyWindow(hwnd_arg);
|
||||
return 0;
|
||||
|
||||
case WM_DESTROY:
|
||||
|
|
@ -301,8 +295,8 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
|||
return 0;
|
||||
|
||||
case WM_PAINT:
|
||||
dc = BeginPaint(hwnd, &ps);
|
||||
GetClientRect(hwnd, &client_area);
|
||||
dc = BeginPaint(hwnd_arg, &ps);
|
||||
GetClientRect(hwnd_arg, &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));
|
||||
|
|
@ -317,27 +311,32 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
|||
char * blanks = CORD_to_char_star(CORD_chars(' ',
|
||||
COLS - len));
|
||||
char * control = control_chars(text, len);
|
||||
if (NULL == plain || NULL == control)
|
||||
de_error("Out of memory!");
|
||||
|
||||
# define RED RGB(255,0,0)
|
||||
|
||||
SetBkMode(dc, OPAQUE);
|
||||
SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
|
||||
|
||||
TextOutA(dc, this_line.left, this_line.top,
|
||||
plain, (int)len);
|
||||
if (plain != NULL)
|
||||
TextOutA(dc, this_line.left, this_line.top,
|
||||
plain, (int)len);
|
||||
TextOutA(dc, this_line.left + (int)len * char_width,
|
||||
this_line.top,
|
||||
blanks, (int)(COLS - len));
|
||||
SetBkMode(dc, TRANSPARENT);
|
||||
SetTextColor(dc, RED);
|
||||
TextOutA(dc, this_line.left, this_line.top,
|
||||
control, (int)strlen(control));
|
||||
if (control != NULL)
|
||||
TextOutA(dc, this_line.left, this_line.top,
|
||||
control, (int)strlen(control));
|
||||
}
|
||||
}
|
||||
EndPaint(hwnd, &ps);
|
||||
EndPaint(hwnd_arg, &ps);
|
||||
screen_was_painted = 1;
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc (hwnd, message, wParam, lParam);
|
||||
return DefWindowProc(hwnd_arg, message, wParam, lParam);
|
||||
}
|
||||
|
||||
int last_col;
|
||||
|
|
@ -359,11 +358,11 @@ void update_cursor(void)
|
|||
|
||||
void invalidate_line(int i)
|
||||
{
|
||||
RECT line;
|
||||
RECT line_r;
|
||||
|
||||
if (!screen_was_painted) return;
|
||||
/* Invalidating a rectangle before painting seems result in a */
|
||||
/* major performance problem. */
|
||||
get_line_rect(i, COLS*char_width, &line);
|
||||
InvalidateRect(hwnd, &line, FALSE);
|
||||
get_line_rect(i, COLS*char_width, &line_r);
|
||||
InvalidateRect(hwnd, &line_r, FALSE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,11 +44,7 @@
|
|||
/* 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 );
|
||||
|
||||
WPARAM wParam, LPARAM lParam);
|
||||
|
||||
/* Screen dimensions. Maintained by de_win.c. */
|
||||
extern int LINES;
|
||||
|
|
|
|||
|
|
@ -12,52 +12,49 @@
|
|||
#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 */
|
||||
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
|
||||
/* 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
|
||||
BEGIN
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "&Save\t^W", IDM_FILESAVE
|
||||
MENUITEM "E&xit\t^D", IDM_FILEEXIT
|
||||
END
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "&Save\t^W", IDM_FILESAVE
|
||||
MENUITEM "E&xit\t^D", IDM_FILEEXIT
|
||||
END
|
||||
|
||||
POPUP "&Edit"
|
||||
BEGIN
|
||||
MENUITEM "Page &Down\t^R^N", IDM_EDITPDOWN
|
||||
MENUITEM "Page &Up\t^R^P", IDM_EDITPUP
|
||||
MENUITEM "U&ndo\t^U", IDM_EDITUNDO
|
||||
MENUITEM "&Locate\t^L ... ^L", IDM_EDITLOCATE
|
||||
MENUITEM "D&own\t^N", IDM_EDITDOWN
|
||||
MENUITEM "U&p\t^P", IDM_EDITUP
|
||||
MENUITEM "Le&ft\t^B", IDM_EDITLEFT
|
||||
MENUITEM "&Right\t^F", IDM_EDITRIGHT
|
||||
MENUITEM "Delete &Backward\tBS", IDM_EDITBS
|
||||
MENUITEM "Delete F&orward\tDEL", IDM_EDITDEL
|
||||
MENUITEM "&Top\t^T", IDM_EDITTOP
|
||||
END
|
||||
POPUP "&Edit"
|
||||
BEGIN
|
||||
MENUITEM "Page &Down\t^R^N", IDM_EDITPDOWN
|
||||
MENUITEM "Page &Up\t^R^P", IDM_EDITPUP
|
||||
MENUITEM "U&ndo\t^U", IDM_EDITUNDO
|
||||
MENUITEM "&Locate\t^L ... ^L", IDM_EDITLOCATE
|
||||
MENUITEM "D&own\t^N", IDM_EDITDOWN
|
||||
MENUITEM "U&p\t^P", IDM_EDITUP
|
||||
MENUITEM "Le&ft\t^B", IDM_EDITLEFT
|
||||
MENUITEM "&Right\t^F", IDM_EDITRIGHT
|
||||
MENUITEM "Delete &Backward\tBS", IDM_EDITBS
|
||||
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
|
||||
POPUP "&Help"
|
||||
BEGIN
|
||||
MENUITEM "&Contents", IDM_HELPCONTENTS
|
||||
MENUITEM "&About...", IDM_HELPABOUT
|
||||
END
|
||||
|
||||
MENUITEM "Page_&Down", IDM_EDITPDOWN
|
||||
MENUITEM "Page_&Up", IDM_EDITPUP
|
||||
MENUITEM "Page_&Down", IDM_EDITPDOWN
|
||||
MENUITEM "Page_&Up", IDM_EDITPUP
|
||||
END
|
||||
|
||||
|
||||
DE ACCELERATORS
|
||||
BEGIN
|
||||
"^R", IDM_EDITREPEAT
|
||||
|
|
@ -67,9 +64,8 @@ BEGIN
|
|||
"^B", IDM_EDITLEFT
|
||||
"^F", IDM_EDITRIGHT
|
||||
"^T", IDM_EDITTOP
|
||||
VK_DELETE, IDM_EDITDEL, VIRTKEY
|
||||
VK_BACK, IDM_EDITBS, VIRTKEY
|
||||
VK_DELETE, IDM_EDITDEL, VIRTKEY
|
||||
VK_BACK, IDM_EDITBS, VIRTKEY
|
||||
END
|
||||
|
||||
|
||||
/* DE ICON cord\de_win.ICO */
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
|
|||
}
|
||||
|
||||
# ifdef DEBUG_THREADS_EXTRA
|
||||
GC_log_printf("FindTopOfStack start at sp = %p\n", frame);
|
||||
GC_log_printf("FindTopOfStack start at sp = %p\n", (void *)frame);
|
||||
# endif
|
||||
while (frame->savedSP != 0) {
|
||||
/* if there are no more stack frames, stop */
|
||||
|
|
@ -83,11 +83,11 @@ GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
|
|||
/* 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)
|
||||
if ((frame->savedLR & ~0x3) == 0 || (frame->savedLR & ~0x3) == ~0x3UL)
|
||||
break; /* if the next LR is bogus, stop */
|
||||
}
|
||||
# ifdef DEBUG_THREADS_EXTRA
|
||||
GC_log_printf("FindTopOfStack finish at sp = %p\n", frame);
|
||||
GC_log_printf("FindTopOfStack finish at sp = %p\n", (void *)frame);
|
||||
# endif
|
||||
return (ptr_t)frame;
|
||||
}
|
||||
|
|
@ -129,7 +129,9 @@ GC_API void GC_CALL GC_use_threads_discovery(void)
|
|||
/* 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)
|
||||
GC_bool thread_blocked, mach_port_t my_thread,
|
||||
ptr_t *paltstack_lo,
|
||||
ptr_t *paltstack_hi GC_ATTR_UNUSED)
|
||||
{
|
||||
ptr_t lo;
|
||||
if (thread == my_thread) {
|
||||
|
|
@ -140,6 +142,9 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
|
|||
# endif
|
||||
|
||||
} else if (thread_blocked) {
|
||||
# if defined(CPPCHECK)
|
||||
if (NULL == p) ABORT("Invalid GC_thread passed to GC_stack_range_for");
|
||||
# endif
|
||||
lo = p->stop_info.stack_ptr;
|
||||
# ifndef DARWIN_DONT_PARSE_STACK
|
||||
*phi = p->topOfStack;
|
||||
|
|
@ -167,14 +172,20 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
|
|||
arm_unified_thread_state_t unified_state;
|
||||
mach_msg_type_number_t unified_thread_state_count
|
||||
= ARM_UNIFIED_THREAD_STATE_COUNT;
|
||||
|
||||
kern_result = thread_get_state(thread, ARM_UNIFIED_THREAD_STATE,
|
||||
# if defined(CPPCHECK)
|
||||
# define GC_ARM_UNIFIED_THREAD_STATE 1
|
||||
# else
|
||||
# define GC_ARM_UNIFIED_THREAD_STATE ARM_UNIFIED_THREAD_STATE
|
||||
# endif
|
||||
kern_result = thread_get_state(thread, GC_ARM_UNIFIED_THREAD_STATE,
|
||||
(natural_t *)&unified_state,
|
||||
&unified_thread_state_count);
|
||||
if (unified_state.ash.flavor != ARM_THREAD_STATE32) {
|
||||
ABORT("unified_state flavor should be ARM_THREAD_STATE32");
|
||||
}
|
||||
state = unified_state.ts_32;
|
||||
# if !defined(CPPCHECK)
|
||||
if (unified_state.ash.flavor != ARM_THREAD_STATE32) {
|
||||
ABORT("unified_state flavor should be ARM_THREAD_STATE32");
|
||||
}
|
||||
# endif
|
||||
state = unified_state;
|
||||
} else
|
||||
# endif
|
||||
/* else */ {
|
||||
|
|
@ -293,6 +304,8 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
|
|||
GC_push_one(state.THREAD_FLD(fp));
|
||||
GC_push_one(state.THREAD_FLD(lr));
|
||||
|
||||
# elif defined(CPPCHECK)
|
||||
lo = NULL;
|
||||
# else
|
||||
# error FIXME for non-x86 || ppc || arm architectures
|
||||
# endif
|
||||
|
|
@ -302,17 +315,30 @@ STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
|
|||
/* 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
|
||||
|
||||
/* TODO: Determine p and handle altstack if !DARWIN_DONT_PARSE_STACK */
|
||||
# ifdef DARWIN_DONT_PARSE_STACK
|
||||
if (p->altstack != NULL && (word)p->altstack <= (word)lo
|
||||
&& (word)lo <= (word)p->altstack + p->altstack_size) {
|
||||
*paltstack_lo = lo;
|
||||
*paltstack_hi = p->altstack + p->altstack_size;
|
||||
lo = p->stack;
|
||||
*phi = p->stack + p->stack_size;
|
||||
} else
|
||||
# endif
|
||||
/* else */ {
|
||||
*paltstack_lo = NULL;
|
||||
}
|
||||
# ifdef DEBUG_THREADS
|
||||
GC_log_printf("Darwin: Stack for thread %p = [%p,%p)\n",
|
||||
(void *)thread, lo, *phi);
|
||||
(void *)(word)thread, (void *)lo, (void *)(*phi));
|
||||
# endif
|
||||
return lo;
|
||||
}
|
||||
|
||||
GC_INNER void GC_push_all_stacks(void)
|
||||
{
|
||||
int i;
|
||||
ptr_t lo, hi;
|
||||
ptr_t hi, altstack_lo, altstack_hi;
|
||||
task_t my_task = current_task();
|
||||
mach_port_t my_thread = mach_thread_self();
|
||||
GC_bool found_me = FALSE;
|
||||
|
|
@ -324,6 +350,7 @@ GC_INNER void GC_push_all_stacks(void)
|
|||
|
||||
# ifndef DARWIN_DONT_PARSE_STACK
|
||||
if (GC_query_task_threads) {
|
||||
int i;
|
||||
kern_return_t kern_result;
|
||||
thread_act_array_t act_list = 0;
|
||||
|
||||
|
|
@ -334,10 +361,15 @@ GC_INNER void GC_push_all_stacks(void)
|
|||
|
||||
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);
|
||||
ptr_t lo = GC_stack_range_for(&hi, thread, NULL, FALSE, my_thread,
|
||||
&altstack_lo, &altstack_hi);
|
||||
|
||||
if (lo) {
|
||||
GC_ASSERT((word)lo <= (word)hi);
|
||||
total_size += hi - lo;
|
||||
GC_push_all_stack(lo, hi);
|
||||
}
|
||||
/* TODO: Handle altstack */
|
||||
nthreads++;
|
||||
if (thread == my_thread)
|
||||
found_me = TRUE;
|
||||
|
|
@ -349,16 +381,28 @@ GC_INNER void GC_push_all_stacks(void)
|
|||
} else
|
||||
# endif /* !DARWIN_DONT_PARSE_STACK */
|
||||
/* else */ {
|
||||
int i;
|
||||
|
||||
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);
|
||||
ptr_t lo = GC_stack_range_for(&hi, thread, p,
|
||||
(GC_bool)p->thread_blocked,
|
||||
my_thread, &altstack_lo,
|
||||
&altstack_hi);
|
||||
|
||||
if (lo) {
|
||||
GC_ASSERT((word)lo <= (word)hi);
|
||||
total_size += hi - lo;
|
||||
GC_push_all_stack_sections(lo, hi, p->traced_stack_sect);
|
||||
}
|
||||
if (altstack_lo) {
|
||||
total_size += altstack_hi - altstack_lo;
|
||||
GC_push_all_stack(altstack_lo, altstack_hi);
|
||||
}
|
||||
nthreads++;
|
||||
if (thread == my_thread)
|
||||
found_me = TRUE;
|
||||
|
|
@ -429,7 +473,8 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
|
|||
# endif
|
||||
|
||||
# ifdef DEBUG_THREADS
|
||||
GC_log_printf("Attempting to suspend thread %p\n", (void *)thread);
|
||||
GC_log_printf("Attempting to suspend thread %p\n",
|
||||
(void *)(word)thread);
|
||||
# endif
|
||||
/* find the current thread in the old list */
|
||||
found = FALSE;
|
||||
|
|
@ -473,7 +518,8 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
|
|||
continue;
|
||||
}
|
||||
# ifdef DEBUG_THREADS
|
||||
GC_log_printf("Thread state for %p = %d\n", (void *)thread, info.run_state);
|
||||
GC_log_printf("Thread state for %p = %d\n", (void *)(word)thread,
|
||||
info.run_state);
|
||||
# endif
|
||||
if (info.suspend_count != 0) {
|
||||
/* thread is already suspended. */
|
||||
|
|
@ -483,9 +529,11 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
|
|||
}
|
||||
|
||||
# ifdef DEBUG_THREADS
|
||||
GC_log_printf("Suspending %p\n", (void *)thread);
|
||||
GC_log_printf("Suspending %p\n", (void *)(word)thread);
|
||||
# endif
|
||||
kern_result = thread_suspend(thread);
|
||||
do {
|
||||
kern_result = thread_suspend(thread);
|
||||
} while (kern_result == KERN_ABORTED);
|
||||
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. */
|
||||
|
|
@ -495,6 +543,8 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
|
|||
}
|
||||
if (!found)
|
||||
GC_mach_threads_count++;
|
||||
if (GC_on_thread_event)
|
||||
GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, (void *)(word)thread);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
|
@ -504,13 +554,13 @@ STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
|
|||
/* 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);
|
||||
GC_log_printf("Stopping the world from thread %p\n",
|
||||
(void *)(word)my_thread);
|
||||
# endif
|
||||
# ifdef PARALLEL_MARK
|
||||
if (GC_parallel) {
|
||||
|
|
@ -526,6 +576,7 @@ GC_INNER void GC_stop_world(void)
|
|||
|
||||
if (GC_query_task_threads) {
|
||||
# ifndef GC_NO_THREADS_DISCOVERY
|
||||
unsigned i;
|
||||
GC_bool changed;
|
||||
thread_act_array_t act_list, prev_list;
|
||||
mach_msg_type_number_t listcount, prevcount;
|
||||
|
|
@ -573,6 +624,8 @@ GC_INNER void GC_stop_world(void)
|
|||
# endif /* !GC_NO_THREADS_DISCOVERY */
|
||||
|
||||
} else {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
||||
GC_thread p;
|
||||
|
||||
|
|
@ -580,9 +633,14 @@ GC_INNER void GC_stop_world(void)
|
|||
if ((p->flags & FINISHED) == 0 && !p->thread_blocked &&
|
||||
p->stop_info.mach_thread != my_thread) {
|
||||
|
||||
kern_result = thread_suspend(p->stop_info.mach_thread);
|
||||
do {
|
||||
kern_result = thread_suspend(p->stop_info.mach_thread);
|
||||
} while (kern_result == KERN_ABORTED);
|
||||
if (kern_result != KERN_SUCCESS)
|
||||
ABORT("thread_suspend failed");
|
||||
if (GC_on_thread_event)
|
||||
GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
|
||||
(void *)(word)p->stop_info.mach_thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -599,7 +657,7 @@ GC_INNER void GC_stop_world(void)
|
|||
# endif
|
||||
|
||||
# ifdef DEBUG_THREADS
|
||||
GC_log_printf("World stopped from %p\n", (void *)my_thread);
|
||||
GC_log_printf("World stopped from %p\n", (void *)(word)my_thread);
|
||||
# endif
|
||||
mach_port_deallocate(my_task, my_thread);
|
||||
}
|
||||
|
|
@ -616,13 +674,15 @@ GC_INLINE void GC_thread_resume(thread_act_t thread)
|
|||
ABORT("thread_info failed");
|
||||
# endif
|
||||
# ifdef DEBUG_THREADS
|
||||
GC_log_printf("Resuming thread %p with state %d\n", (void *)thread,
|
||||
GC_log_printf("Resuming thread %p with state %d\n", (void *)(word)thread,
|
||||
info.run_state);
|
||||
# endif
|
||||
/* Resume the thread */
|
||||
kern_result = thread_resume(thread);
|
||||
if (kern_result != KERN_SUCCESS)
|
||||
ABORT("thread_resume failed");
|
||||
if (GC_on_thread_event)
|
||||
GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)(word)thread);
|
||||
}
|
||||
|
||||
/* Caller holds allocation lock, and has held it continuously since */
|
||||
|
|
@ -630,7 +690,6 @@ GC_INLINE void GC_thread_resume(thread_act_t thread)
|
|||
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
|
||||
|
|
@ -642,6 +701,7 @@ GC_INNER void GC_start_world(void)
|
|||
|
||||
if (GC_query_task_threads) {
|
||||
# ifndef GC_NO_THREADS_DISCOVERY
|
||||
int i;
|
||||
int j = GC_mach_threads_count;
|
||||
kern_return_t kern_result;
|
||||
thread_act_array_t act_list;
|
||||
|
|
@ -675,7 +735,7 @@ GC_INNER void GC_start_world(void)
|
|||
if (GC_mach_threads[j].already_suspended) {
|
||||
# ifdef DEBUG_THREADS
|
||||
GC_log_printf("Not resuming already suspended thread %p\n",
|
||||
(void *)thread);
|
||||
(void *)(word)thread);
|
||||
# endif
|
||||
} else {
|
||||
GC_thread_resume(thread);
|
||||
|
|
@ -689,6 +749,7 @@ GC_INNER void GC_start_world(void)
|
|||
# endif /* !GC_NO_THREADS_DISCOVERY */
|
||||
|
||||
} else {
|
||||
int i;
|
||||
mach_port_t my_thread = mach_thread_self();
|
||||
|
||||
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
||||
|
|
|
|||
|
|
@ -54,9 +54,24 @@
|
|||
}
|
||||
#endif /* !SHORT_DBG_HDRS */
|
||||
|
||||
#ifdef LINT2
|
||||
long GC_random(void)
|
||||
{
|
||||
static unsigned seed = 1; /* not thread-safe */
|
||||
|
||||
/* Linear congruential pseudo-random numbers generator. */
|
||||
seed = (seed * 1103515245U + 12345) & GC_RAND_MAX; /* overflow is ok */
|
||||
return (long)seed;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef KEEP_BACK_PTRS
|
||||
|
||||
#ifdef LINT2
|
||||
# define RANDOM() GC_random()
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
# define GC_RAND_MAX RAND_MAX
|
||||
|
||||
# if defined(__GLIBC__) || defined(SOLARIS) \
|
||||
|| defined(HPUX) || defined(IRIX5) || defined(OSF1)
|
||||
|
|
@ -64,6 +79,7 @@
|
|||
# else
|
||||
# define RANDOM() (long)rand()
|
||||
# endif
|
||||
#endif /* !LINT2 */
|
||||
|
||||
/* Store back pointer to source in dest, if that appears to be possible. */
|
||||
/* This is not completely safe, since we may mistakenly conclude that */
|
||||
|
|
@ -142,11 +158,10 @@
|
|||
GC_API void * GC_CALL GC_generate_random_heap_address(void)
|
||||
{
|
||||
size_t i;
|
||||
size_t size;
|
||||
word heap_offset = RANDOM();
|
||||
|
||||
if (GC_heapsize > RAND_MAX) {
|
||||
heap_offset *= RAND_MAX;
|
||||
if (GC_heapsize > GC_RAND_MAX) {
|
||||
heap_offset *= GC_RAND_MAX;
|
||||
heap_offset += RANDOM();
|
||||
}
|
||||
heap_offset %= GC_heapsize;
|
||||
|
|
@ -154,6 +169,8 @@
|
|||
/* e.g. RAND_MAX = 1.5* GC_heapsize. But for typical cases, */
|
||||
/* it's not too bad. */
|
||||
for (i = 0;; ++i) {
|
||||
size_t size;
|
||||
|
||||
if (i >= GC_n_heap_sects)
|
||||
ABORT("GC_generate_random_heap_address: size inconsistency");
|
||||
|
||||
|
|
@ -250,15 +267,13 @@
|
|||
# define CROSSES_HBLK(p, sz) \
|
||||
(((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)
|
||||
GC_INNER void *GC_store_debug_info_inner(void *p, word sz GC_ATTR_UNUSED,
|
||||
const char *string, int linenum)
|
||||
{
|
||||
word * result = (word *)((oh *)p + 1);
|
||||
|
||||
GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
|
||||
GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
|
||||
GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK((ptr_t)p, sz)));
|
||||
# ifdef KEEP_BACK_PTRS
|
||||
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
|
||||
# endif
|
||||
|
|
@ -276,14 +291,24 @@ STATIC ptr_t GC_store_debug_info_inner(ptr_t p, word sz GC_ATTR_UNUSED,
|
|||
return((ptr_t)result);
|
||||
}
|
||||
|
||||
GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *string,
|
||||
int linenum)
|
||||
/* Check the allocation is successful, store debugging info into p, */
|
||||
/* start the debugging mode (if not yet), and return displaced pointer. */
|
||||
static void *store_debug_info(void *p, size_t lb,
|
||||
const char *fn, GC_EXTRA_PARAMS)
|
||||
{
|
||||
ptr_t result;
|
||||
void *result;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
if (NULL == p) {
|
||||
GC_err_printf("%s(%lu) returning NULL (%s:%d)\n",
|
||||
fn, (unsigned long)lb, s, i);
|
||||
return NULL;
|
||||
}
|
||||
LOCK();
|
||||
result = GC_store_debug_info_inner(p, sz, string, linenum);
|
||||
if (!GC_debugging_started)
|
||||
GC_start_debugging_inner();
|
||||
ADD_CALL_CHAIN(p, ra);
|
||||
result = GC_store_debug_info_inner(p, (word)lb, s, i);
|
||||
UNLOCK();
|
||||
return result;
|
||||
}
|
||||
|
|
@ -370,7 +395,7 @@ STATIC void GC_print_obj(ptr_t p)
|
|||
case UNCOLLECTABLE:
|
||||
kind_str = "UNCOLLECTABLE";
|
||||
break;
|
||||
# ifdef ATOMIC_UNCOLLECTABLE
|
||||
# ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
case AUNCOLLECTABLE:
|
||||
kind_str = "ATOMIC_UNCOLLECTABLE";
|
||||
break;
|
||||
|
|
@ -387,13 +412,14 @@ STATIC void GC_print_obj(ptr_t p)
|
|||
|
||||
if (NULL != kind_str) {
|
||||
GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,") " %s)\n",
|
||||
(ptr_t)ohdr + sizeof(oh),
|
||||
(void *)((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),
|
||||
" kind=%d descr=0x%lx)\n",
|
||||
(void *)((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);
|
||||
|
|
@ -428,11 +454,11 @@ STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
|
|||
|| ohdr -> oh_string == 0) {
|
||||
GC_err_printf(
|
||||
"%s %p in or near object at %p(<smashed>, appr. sz = %lu)\n",
|
||||
msg, clobbered_addr, p,
|
||||
msg, (void *)clobbered_addr, (void *)p,
|
||||
(unsigned long)(GC_size((ptr_t)ohdr) - DEBUG_BYTES));
|
||||
} else {
|
||||
GC_err_printf("%s %p in or near object at %p (%s:%d, sz=%lu)\n",
|
||||
msg, clobbered_addr, p,
|
||||
msg, (void *)clobbered_addr, (void *)p,
|
||||
(word)(ohdr -> oh_string) < HBLKSIZE ? "(smashed string)" :
|
||||
ohdr -> oh_string[0] == '\0' ? "EMPTY(smashed?)" :
|
||||
ohdr -> oh_string,
|
||||
|
|
@ -440,16 +466,14 @@ STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
|
|||
PRINT_CALL_CHAIN(ohdr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
STATIC void GC_start_debugging_inner(void)
|
||||
GC_INNER void GC_start_debugging_inner(void)
|
||||
{
|
||||
GC_ASSERT(I_HOLD_LOCK());
|
||||
# ifndef SHORT_DBG_HDRS
|
||||
|
|
@ -464,15 +488,6 @@ STATIC void GC_start_debugging_inner(void)
|
|||
GC_register_displacement_inner((word)sizeof(oh));
|
||||
}
|
||||
|
||||
GC_INNER void GC_start_debugging(void)
|
||||
{
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
LOCK();
|
||||
GC_start_debugging_inner();
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
size_t GC_debug_header_size = sizeof(oh);
|
||||
|
||||
GC_API void GC_CALL GC_debug_register_displacement(size_t offset)
|
||||
|
|
@ -486,7 +501,7 @@ GC_API void GC_CALL GC_debug_register_displacement(size_t offset)
|
|||
}
|
||||
|
||||
#ifdef GC_ADD_CALLER
|
||||
# if defined(HAVE_DLADDR) && defined(GC_RETURN_ADDR_PARENT)
|
||||
# if defined(HAVE_DLADDR) && defined(GC_HAVE_RETURN_ADDR_PARENT)
|
||||
# include <dlfcn.h>
|
||||
|
||||
STATIC void GC_caller_func_offset(word ad, const char **symp, int *offp)
|
||||
|
|
@ -514,84 +529,52 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc(size_t lb,
|
|||
/* 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);
|
||||
result = GC_malloc(SIZET_SAT_ADD(lb, DEBUG_BYTES));
|
||||
# ifdef GC_ADD_CALLER
|
||||
if (s == NULL) {
|
||||
GC_caller_func_offset(ra, &s, &i);
|
||||
}
|
||||
# endif
|
||||
if (result == 0) {
|
||||
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();
|
||||
}
|
||||
ADD_CALL_CHAIN(result, ra);
|
||||
return (GC_store_debug_info(result, (word)lb, s, i));
|
||||
return store_debug_info(result, lb, "GC_debug_malloc", OPT_RA s, i);
|
||||
}
|
||||
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL
|
||||
GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
|
||||
{
|
||||
void * result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
|
||||
void * result = GC_malloc_ignore_off_page(SIZET_SAT_ADD(lb, DEBUG_BYTES));
|
||||
|
||||
if (result == 0) {
|
||||
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();
|
||||
}
|
||||
ADD_CALL_CHAIN(result, ra);
|
||||
return (GC_store_debug_info(result, (word)lb, s, i));
|
||||
return store_debug_info(result, lb, "GC_debug_malloc_ignore_off_page",
|
||||
OPT_RA s, i);
|
||||
}
|
||||
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL
|
||||
GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
|
||||
{
|
||||
void * result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
|
||||
void * result = GC_malloc_atomic_ignore_off_page(
|
||||
SIZET_SAT_ADD(lb, DEBUG_BYTES));
|
||||
|
||||
if (result == 0) {
|
||||
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();
|
||||
}
|
||||
ADD_CALL_CHAIN(result, ra);
|
||||
return (GC_store_debug_info(result, (word)lb, s, i));
|
||||
return store_debug_info(result, lb,
|
||||
"GC_debug_malloc_atomic_ignore_off_page",
|
||||
OPT_RA s, i);
|
||||
}
|
||||
|
||||
STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
|
||||
{
|
||||
void * result = GC_generic_malloc(lb + DEBUG_BYTES, knd);
|
||||
void * result = GC_generic_malloc(SIZET_SAT_ADD(lb, DEBUG_BYTES), knd);
|
||||
|
||||
if (NULL == result) {
|
||||
GC_err_printf(
|
||||
"GC_debug_generic_malloc(%lu, %d) returning NULL (%s:%d)\n",
|
||||
(unsigned long)lb, knd, s, i);
|
||||
return NULL;
|
||||
}
|
||||
if (!GC_debugging_started) {
|
||||
GC_start_debugging();
|
||||
}
|
||||
ADD_CALL_CHAIN(result, ra);
|
||||
return GC_store_debug_info(result, (word)lb, s, i);
|
||||
return store_debug_info(result, lb, "GC_debug_generic_malloc",
|
||||
OPT_RA 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. */
|
||||
/* We assume we already hold the GC lock. */
|
||||
GC_INNER void * GC_debug_generic_malloc_inner(size_t lb, int k)
|
||||
{
|
||||
void * result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
|
||||
void * result = GC_generic_malloc_inner(
|
||||
SIZET_SAT_ADD(lb, DEBUG_BYTES), k);
|
||||
|
||||
if (result == 0) {
|
||||
GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
|
||||
|
|
@ -609,7 +592,7 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
|
|||
int k)
|
||||
{
|
||||
void * result = GC_generic_malloc_inner_ignore_off_page(
|
||||
lb + DEBUG_BYTES, k);
|
||||
SIZET_SAT_ADD(lb, DEBUG_BYTES), k);
|
||||
|
||||
if (result == 0) {
|
||||
GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
|
||||
|
|
@ -628,18 +611,10 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
|
|||
GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_stubborn(size_t lb,
|
||||
GC_EXTRA_PARAMS)
|
||||
{
|
||||
void * result = GC_malloc_stubborn(lb + DEBUG_BYTES);
|
||||
void * result = GC_malloc_stubborn(SIZET_SAT_ADD(lb, DEBUG_BYTES));
|
||||
|
||||
if (result == 0) {
|
||||
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();
|
||||
}
|
||||
ADD_CALL_CHAIN(result, ra);
|
||||
return (GC_store_debug_info(result, (word)lb, s, i));
|
||||
return store_debug_info(result, lb, "GC_debug_malloc_stubborn",
|
||||
OPT_RA s, i);
|
||||
}
|
||||
|
||||
GC_API void GC_CALL GC_debug_change_stubborn(const void *p)
|
||||
|
|
@ -657,22 +632,6 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
|
|||
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;
|
||||
|
||||
if (q == 0) {
|
||||
ABORT_ARG1("GC_debug_end_stubborn_change: bad arg", ": %p", p);
|
||||
}
|
||||
hhdr = HDR(q);
|
||||
if (hhdr -> hb_obj_kind != STUBBORN) {
|
||||
ABORT_ARG1("GC_debug_end_stubborn_change: arg not stubborn",
|
||||
": %p", p);
|
||||
}
|
||||
GC_end_stubborn_change(q);
|
||||
}
|
||||
|
||||
#else /* !STUBBORN_ALLOC */
|
||||
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_stubborn(size_t lb,
|
||||
|
|
@ -683,26 +642,30 @@ STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
|
|||
|
||||
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 */
|
||||
|
||||
GC_API void GC_CALL GC_debug_end_stubborn_change(const void *p)
|
||||
{
|
||||
const void * q = GC_base_C(p);
|
||||
|
||||
if (NULL == q) {
|
||||
ABORT_ARG1("GC_debug_end_stubborn_change: bad arg", ": %p", p);
|
||||
}
|
||||
# ifdef STUBBORN_ALLOC
|
||||
if (HDR(q) -> hb_obj_kind != STUBBORN)
|
||||
ABORT_ARG1("GC_debug_end_stubborn_change: arg not stubborn",
|
||||
": %p", p);
|
||||
# endif
|
||||
GC_end_stubborn_change(q);
|
||||
}
|
||||
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_atomic(size_t lb,
|
||||
GC_EXTRA_PARAMS)
|
||||
{
|
||||
void * result = GC_malloc_atomic(lb + DEBUG_BYTES);
|
||||
void * result = GC_malloc_atomic(SIZET_SAT_ADD(lb, DEBUG_BYTES));
|
||||
|
||||
if (result == 0) {
|
||||
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, i));
|
||||
return store_debug_info(result, lb, "GC_debug_malloc_atomic",
|
||||
OPT_RA s, i);
|
||||
}
|
||||
|
||||
GC_API GC_ATTR_MALLOC char * GC_CALL GC_debug_strdup(const char *str,
|
||||
|
|
@ -769,39 +732,25 @@ GC_API GC_ATTR_MALLOC char * GC_CALL GC_debug_strndup(const char *str,
|
|||
GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_uncollectable(size_t lb,
|
||||
GC_EXTRA_PARAMS)
|
||||
{
|
||||
void * result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
|
||||
void * result = GC_malloc_uncollectable(
|
||||
SIZET_SAT_ADD(lb, UNCOLLECTABLE_DEBUG_BYTES));
|
||||
|
||||
if (result == 0) {
|
||||
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, i));
|
||||
return store_debug_info(result, lb, "GC_debug_malloc_uncollectable",
|
||||
OPT_RA s, i);
|
||||
}
|
||||
|
||||
#ifdef ATOMIC_UNCOLLECTABLE
|
||||
#ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL
|
||||
GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
|
||||
{
|
||||
void * result =
|
||||
GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
|
||||
void * result = GC_malloc_atomic_uncollectable(
|
||||
SIZET_SAT_ADD(lb, UNCOLLECTABLE_DEBUG_BYTES));
|
||||
|
||||
if (result == 0) {
|
||||
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, i));
|
||||
return store_debug_info(result, lb,
|
||||
"GC_debug_malloc_atomic_uncollectable",
|
||||
OPT_RA s, i);
|
||||
}
|
||||
#endif /* ATOMIC_UNCOLLECTABLE */
|
||||
#endif /* GC_ATOMIC_UNCOLLECTABLE */
|
||||
|
||||
#ifndef GC_FREED_MEM_MARKER
|
||||
# if CPP_WORDSZ == 32
|
||||
|
|
@ -818,6 +767,14 @@ GC_API void GC_CALL GC_debug_free(void * p)
|
|||
|
||||
base = GC_base(p);
|
||||
if (base == 0) {
|
||||
# if defined(REDIRECT_MALLOC) \
|
||||
&& ((defined(NEED_CALLINFO) && defined(GC_HAVE_BUILTIN_BACKTRACE)) \
|
||||
|| defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS) \
|
||||
|| defined(MSWIN32))
|
||||
/* In some cases, we should ignore objects that do not belong */
|
||||
/* to the GC heap. See the comment in GC_free. */
|
||||
if (!GC_is_heap_ptr(p)) return;
|
||||
# endif
|
||||
ABORT_ARG1("Invalid pointer passed to free()", ": %p", p);
|
||||
}
|
||||
if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
|
||||
|
|
@ -852,7 +809,7 @@ GC_API void GC_CALL GC_debug_free(void * p)
|
|||
} else {
|
||||
hdr * hhdr = HDR(p);
|
||||
if (hhdr -> hb_obj_kind == UNCOLLECTABLE
|
||||
# ifdef ATOMIC_UNCOLLECTABLE
|
||||
# ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
|| hhdr -> hb_obj_kind == AUNCOLLECTABLE
|
||||
# endif
|
||||
) {
|
||||
|
|
@ -894,6 +851,11 @@ GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
|
|||
if (p == 0) {
|
||||
return GC_debug_malloc(lb, OPT_RA s, i);
|
||||
}
|
||||
if (0 == lb) /* and p != NULL */ {
|
||||
GC_debug_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
# ifdef GC_ADD_CALLER
|
||||
if (s == NULL) {
|
||||
GC_caller_func_offset(ra, &s, &i);
|
||||
|
|
@ -924,7 +886,7 @@ GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
|
|||
case UNCOLLECTABLE:
|
||||
result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
|
||||
break;
|
||||
# ifdef ATOMIC_UNCOLLECTABLE
|
||||
# ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
case AUNCOLLECTABLE:
|
||||
result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
|
||||
break;
|
||||
|
|
@ -961,7 +923,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL
|
|||
return GC_debug_malloc(lb, OPT_RA s, i);
|
||||
case UNCOLLECTABLE:
|
||||
return GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
|
||||
# ifdef ATOMIC_UNCOLLECTABLE
|
||||
# ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
case AUNCOLLECTABLE:
|
||||
return GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
|
||||
# endif
|
||||
|
|
@ -1109,7 +1071,7 @@ STATIC void GC_CALLBACK GC_debug_invoke_finalizer(void * obj, void * data)
|
|||
}
|
||||
|
||||
/* Special finalizer_proc value to detect GC_register_finalizer() failure. */
|
||||
#define OFN_UNSET (GC_finalization_proc)(signed_word)-1
|
||||
#define OFN_UNSET ((GC_finalization_proc)~(signed_word)0)
|
||||
|
||||
/* Set ofn and ocd to reflect the values we got back. */
|
||||
static void store_old(void *obj, GC_finalization_proc my_old_fn,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,8 @@
|
|||
# compiler from www.digitalmars.com
|
||||
# Written by Walter Bright
|
||||
|
||||
|
||||
DEFINES=-DNDEBUG -D_WINDOWS -DGC_DLL -DALL_INTERIOR_POINTERS -DWIN32_THREADS
|
||||
CFLAGS=-Iinclude $(DEFINES) -wx -g
|
||||
DEFINES=-D_WINDOWS -DGC_DLL -DGC_THREADS -DGC_DISCOVER_TASK_THREADS -DALL_INTERIOR_POINTERS
|
||||
CFLAGS=-Iinclude -Ilibatomic_ops\src $(DEFINES) -wx -g
|
||||
LFLAGS=/ma/implib/co
|
||||
CC=sc
|
||||
|
||||
|
|
@ -40,31 +39,35 @@ OBJS= \
|
|||
typd_mlc.obj\
|
||||
win32_threads.obj
|
||||
|
||||
targets: gc.dll gc.lib gctest.exe
|
||||
targets: gc.dll gc.lib gctest.exe test_cpp.exe
|
||||
|
||||
gc.dll: $(OBJS) gc.def digimars.mak
|
||||
sc -ogc.dll $(OBJS) -L$(LFLAGS) gc.def kernel32.lib user32.lib
|
||||
$(CC) -ogc.dll $(OBJS) -L$(LFLAGS) gc.def kernel32.lib user32.lib
|
||||
|
||||
gc.def: digimars.mak
|
||||
echo LIBRARY GC >gc.def
|
||||
echo DESCRIPTION "Hans Boehm Garbage Collector" >>gc.def
|
||||
echo DESCRIPTION "Boehm-Demers-Weiser Garbage Collector" >>gc.def
|
||||
echo EXETYPE NT >>gc.def
|
||||
echo EXPORTS >>gc.def
|
||||
echo GC_is_visible_print_proc >>gc.def
|
||||
echo GC_is_valid_displacement_print_proc >>gc.def
|
||||
|
||||
clean:
|
||||
del gc.def
|
||||
del *.log gc.def gc.dll gc.lib gc.map gctest.map test_cpp.map
|
||||
del tests\test.obj gctest.exe tests\test_cpp.obj test_cpp.exe
|
||||
del $(OBJS)
|
||||
|
||||
gctest.exe: gc.lib tests\test.obj
|
||||
$(CC) -ogctest.exe tests\test.obj gc.lib
|
||||
|
||||
gctest.exe : gc.lib tests\test.obj
|
||||
sc -ogctest.exe tests\test.obj gc.lib
|
||||
tests\test.obj: tests\test.c
|
||||
$(CC) -c $(CFLAGS) tests\test.c -otests\test.obj
|
||||
|
||||
tests\test.obj : tests\test.c
|
||||
$(CC) -c -g -DNDEBUG -D_WINDOWS -DGC_DLL \
|
||||
-DALL_INTERIOR_POINTERS -DWIN32_THREADS \
|
||||
-Iinclude tests\test.c -otests\test.obj
|
||||
test_cpp.exe: gc.lib tests\test_cpp.obj
|
||||
$(CC) -otest_cpp.exe tests\test_cpp.obj gc.lib
|
||||
|
||||
tests\test_cpp.obj: tests\test_cpp.cc
|
||||
$(CC) -c $(CFLAGS) -cpp tests\test_cpp.cc -otests\test_cpp.obj
|
||||
|
||||
allchblk.obj: allchblk.c
|
||||
alloc.obj: alloc.c
|
||||
|
|
@ -74,7 +77,7 @@ 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
|
||||
gc_cpp.obj: gc_cpp.cc gc_cpp.cpp
|
||||
headers.obj: headers.c
|
||||
mach_dep.obj: mach_dep.c
|
||||
malloc.obj: malloc.c
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Garbage Collector (parallel iversion) for ix86 DG/UX Release R4.20MU07
|
||||
Garbage Collector (parallel version) for x86 DG/UX Release R4.20MU07
|
||||
|
||||
|
||||
*READ* the file README.QUICK.
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
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.
|
||||
Finally, we support parallel mark for the SMP DG/UX machines.
|
||||
To build the garbage collector do:
|
||||
|
||||
./configure --enable-parallel-mark
|
||||
|
|
@ -24,13 +24,7 @@
|
|||
|
||||
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.
|
||||
2) Pass "CFLAGS=-DDEBUG_THREADS" to "make".
|
||||
|
||||
In a machine with 4 CPUs (my own machine) the option parallel
|
||||
mark (aka --enable-parallel-mark) makes a BIG difference.
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ o 68K Linker
|
|||
|
||||
Prefix Files to configure the GC sources
|
||||
----------------------------------------
|
||||
The Codewarrior equivalent of commandline compilers -DNAME=X is to use
|
||||
The Codewarrior equivalent of command-line compilers -DNAME=X is to use
|
||||
prefix-files. A TEXT file that is automatically #included before the first byte
|
||||
of every source file. I used these:
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ of every source file. I used these:
|
|||
#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 ATOMIC_UNCOLLECTABLE // GC_malloc_atomic_uncollectable()
|
||||
#define GC_ATOMIC_UNCOLLECTABLE // GC_malloc_atomic_uncollectable()
|
||||
|
||||
// define either or none as per personal preference
|
||||
// used in malloc.c
|
||||
|
|
@ -271,7 +271,7 @@ action! malloc will call GC_malloc and free GC_free, new/delete too. You
|
|||
don't have to call free or delete. You may have to be a bit cautious about
|
||||
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.
|
||||
include "gc.h" and tweak its use a bit.
|
||||
|
||||
== Symantec SPM ==
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ WHATS NEW:
|
|||
It is also 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
|
||||
theres either very little fast-memory left or verly little
|
||||
there's either very little fast-memory left or very little
|
||||
chip-memory left. Its not a very common situation, but gctest
|
||||
sometimes (very rare) use many minutes because of this.
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ WHATS NEW:
|
|||
program, and prints out the info when the atexit-handler
|
||||
is called.
|
||||
|
||||
My reccomendation is to set all this flags, except GC_AMIGA_PRINTSTATS and
|
||||
My recommendation is to set all this flags, except GC_AMIGA_PRINTSTATS and
|
||||
GC_AMIGA_ONLYFAST.
|
||||
|
||||
If your program demands high response-time, you should
|
||||
|
|
@ -70,7 +70,7 @@ WHATS NEW:
|
|||
GC_AMIGA_RETRY does not seem to slow down much.
|
||||
|
||||
Also, when compiling up programs, and GC_AMIGA_FASTALLOC was not defined when
|
||||
compilling gc, you can define GC_AMIGA_MAKINGLIB to avoid having these allocation-
|
||||
compiling gc, you can define GC_AMIGA_MAKINGLIB to avoid having these allocation-
|
||||
functions wrapped. (see gc.h)
|
||||
|
||||
Note that GC_realloc must not be called before any of
|
||||
|
|
@ -249,7 +249,7 @@ will not behave well with Amiga specific code. Especially not inter-
|
|||
process comms via messages, and setting up public structures like
|
||||
Intuition objects or anything else in the system lists. For the
|
||||
time being the use of this library is limited to single threaded
|
||||
ANSI/POSIX compliant or near-complient code. (ie. Stick to stdio
|
||||
ANSI/POSIX compliant or near-compliant code. (ie. Stick to stdio
|
||||
for now). Given this limitation there is currently no mechanism for
|
||||
allocating "CHIP" or "PUBLIC" memory under the garbage collector.
|
||||
I'll add this after giving it considerable thought. The major
|
||||
|
|
@ -260,7 +260,7 @@ If you allocate your own stack in client code, you will have to
|
|||
assign the pointer plus stack size to GC_stackbottom.
|
||||
|
||||
The initial stack size of the target program can be compiled in by
|
||||
setting the __stack symbol (see SAS documentaion). It can be over-
|
||||
setting the __stack symbol (see SAS documentation). It can be over-
|
||||
ridden from the CLI by running the AmigaDOS "stack" program, or from
|
||||
the WorkBench by setting the stack size in the tool types window.
|
||||
|
||||
|
|
@ -282,7 +282,7 @@ The library as it stands is compatible with the GigaMem commercial
|
|||
virtual memory software, and probably similar PD software.
|
||||
|
||||
The performance of "gctest" on an Amiga 2630 (68030 @ 25Mhz)
|
||||
compares favourably with an HP9000 with similar architecture (a 325
|
||||
compares favorably with an HP9000 with similar architecture (a 325
|
||||
with a 68030 I think).
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ 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.
|
||||
|
||||
This is a string packages that uses a tree-based representation.
|
||||
See cord.h for a description of the functions provided. Ec.h describes
|
||||
"extensible cords", which are essentially output streams that write
|
||||
|
|
@ -43,7 +41,7 @@ To build the editor, type "make cord/de" in the gc directory.
|
|||
This package assumes an ANSI C compiler such as gcc. It will
|
||||
not compile with an old-style K&R compiler.
|
||||
|
||||
Note that CORD_printf iand friends use C functions with variable numbers
|
||||
Note that CORD_printf and friends use C functions with variable numbers
|
||||
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
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ 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>
|
||||
#include "gc.h"
|
||||
extern "C" void my_library_init() { GC_init(); }
|
||||
|
||||
Compile this code into a my_library_init.o, and link it into your
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ GC_PRINT_BACK_HEIGHT - Print max length of chain through unreachable objects
|
|||
(http://www.hpl.hp.com/techreports/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
|
||||
thread suspend signals (Pthreads only). 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
|
||||
|
|
|
|||
|
|
@ -2,27 +2,28 @@ GC on EWS4800
|
|||
-------------
|
||||
|
||||
1. About EWS4800
|
||||
EWS4800 is 32bit/64bit workstation.
|
||||
|
||||
Vender: NEC Corporation
|
||||
EWS4800 is a 32/64-bit workstation.
|
||||
|
||||
Vendor: NEC Corporation
|
||||
OS: UX/4800 R9.* - R13.* (SystemV R4.2)
|
||||
CPU: R4000, R4400, R10000 (MIPS)
|
||||
|
||||
2. Compiler
|
||||
|
||||
32bit:
|
||||
32-bit:
|
||||
Use ANSI C compiler.
|
||||
CC = /usr/abiccs/bin/cc
|
||||
|
||||
64bit:
|
||||
Use 64bit ANSI C compiler.
|
||||
64-bit:
|
||||
Use the 64-bit ANSI C compiler.
|
||||
CC = /usr/ccs64/bin/cc
|
||||
AR = /usr/ccs64/bin/ar
|
||||
|
||||
3. ELF file format
|
||||
*** Caution: The following infomation is empirical. ***
|
||||
*** Caution: The following information is empirical. ***
|
||||
|
||||
32bit:
|
||||
32-bit:
|
||||
ELF file has an unique format. (See a.out(4) and end(3C).)
|
||||
|
||||
&_start
|
||||
|
|
@ -57,7 +58,7 @@ GC on EWS4800
|
|||
&edata and DATASTART2. The global symbol &_DYNAMIC_LINKING is used
|
||||
for the detection.
|
||||
|
||||
64bit:
|
||||
64-bit:
|
||||
ELF file has a simple format. (See end(3C).)
|
||||
|
||||
_ftext
|
||||
|
|
@ -76,5 +77,5 @@ 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
|
||||
yet pass with dynamic libraries. The reasons for that are not yet
|
||||
understood. (HB, paraphrasing message from Hironori SAKAMOTO.)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ The collector should compile with either plain cc or cc -Ae. Cc -Aa
|
|||
fails to define _HPUX_SOURCE and thus will not configure the collector
|
||||
correctly.
|
||||
|
||||
Incremental collection support was reccently added, and should now work.
|
||||
Incremental collection support was added recently, and should now work.
|
||||
|
||||
In spite of past claims, pthread support under HP/UX 11 should now work.
|
||||
Define GC_HPUX_THREADS for the build. Incremental collection still does not
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ See below for M68K specific notes.
|
|||
|
||||
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".
|
||||
Dynamic libraries are supported on an ELF system.
|
||||
|
||||
The collector appears to work reliably with Linux threads, but beware
|
||||
of older versions of glibc and gdb.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ GC_NO_THREAD_REDIRECTS Tested by gc.h. Prevents redirection of thread
|
|||
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_DONT_INCLUDE_WINDOWS_H Tested by gc.h. MS Windows only. Do not include
|
||||
windows.h from gc.h (but Windows-specific thread creation
|
||||
routines are declared).
|
||||
|
||||
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
|
||||
|
|
@ -107,10 +111,6 @@ SUNOS5SIGS Solaris-like signal handling. This is probably misnamed,
|
|||
PCR Set if the collector is being built as part of the Xerox Portable
|
||||
Common Runtime.
|
||||
|
||||
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
|
||||
|
|
@ -257,9 +257,11 @@ FINALIZE_ON_DEMAND Causes finalizers to be run only in response
|
|||
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)
|
||||
GC_NO_FINALIZATION Exclude finalization support (for smaller code size).
|
||||
|
||||
ATOMIC_UNCOLLECTABLE Includes code for GC_malloc_atomic_uncollectable.
|
||||
GC_TOGGLE_REFS_NOT_NEEDED Exclude toggle-refs support.
|
||||
|
||||
GC_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.
|
||||
|
||||
|
|
@ -392,12 +394,18 @@ USE_COMPILER_TLS Causes thread local allocation to use
|
|||
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.)
|
||||
|
||||
GC_ATTR_TLS_FAST Use specific attributes for GC_thread_key like
|
||||
__attribute__((tls_model("local-exec"))).
|
||||
|
||||
PARALLEL_MARK Allows the marker to run in multiple threads. Recommended
|
||||
for multiprocessors.
|
||||
|
||||
GC_ALWAYS_MULTITHREADED Force multi-threaded mode at GC initialization.
|
||||
(Turns GC_allow_register_threads into a no-op routine.)
|
||||
|
||||
GC_ENABLE_SUSPEND_THREAD (Linux only) Turn on thread suspend/resume API
|
||||
support.
|
||||
|
||||
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.
|
||||
|
|
@ -557,7 +565,7 @@ GC_FULL_FREQ=<value> Set alternate default number of partial collections
|
|||
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,
|
||||
getting canceled 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.)
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ will run on other pthreads platforms. But please tell me if it does.)
|
|||
include gc.h. Gc.h redefines some of the pthread primitives as macros which
|
||||
also provide the collector with information it requires.
|
||||
|
||||
4) pthread_cond_wait and pthread_cond_timed_wait should be prepared for
|
||||
premature wakeups. (I believe the pthreads and realted standards require this
|
||||
4) pthread_cond_wait and pthread_cond_timedwait should be prepared for
|
||||
premature wakeups. (I believe the pthreads and related standards require this
|
||||
anyway. Irix pthreads often terminate a wait if a signal arrives.
|
||||
The garbage collector uses signals to stop threads.)
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ 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
|
||||
I encountered "symbol <unknown>: offset .... 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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
The collector has at various times been compiled under Windows 95 & later, NT,
|
||||
and XP, with the original Microsoft SDK, with Visual C++ 2.0, 4.0, and 6, with
|
||||
the GNU win32 tools, with Borland 4.5, with Watcom C, and recently
|
||||
the GNU win32 tools, with Borland C++ Builder, with Watcom C, and
|
||||
with the Digital Mars compiler. It is likely that some of these have been
|
||||
broken in the meantime. Patches are appreciated.
|
||||
|
||||
|
|
@ -41,10 +41,13 @@ in 6.1alpha4, since we now separate heap sections with an unused page.)
|
|||
|
||||
Microsoft Tools
|
||||
---------------
|
||||
For Microsoft development tools, rename NT_MAKEFILE as
|
||||
MAKEFILE. (Make sure that the CPU environment variable is defined
|
||||
to be i386.) In order to use the gc_cpp.h C++ interface, all
|
||||
client code should include gc_cpp.h.
|
||||
For Microsoft development tools, type
|
||||
"nmake -f NT_MAKEFILE cpu=i386 make_as_lib=1 nothreads=1 nodebug=1"
|
||||
to build the release variant of the collector as a static library without
|
||||
threads support.
|
||||
|
||||
In order to use the gc_cpp.h C++ interface, all client code should include
|
||||
gc_cpp.h.
|
||||
|
||||
For historical reasons,
|
||||
the collector test program "gctest" is linked as a GUI application,
|
||||
|
|
@ -93,10 +96,8 @@ I expect that -a1 introduces major performance penalties on a
|
|||
486 or Pentium.) Note that this changes structure layouts. (As a last
|
||||
resort, gcconfig.h can be changed to allow 1 byte alignment. But
|
||||
this has significant negative performance implications.)
|
||||
The Makefile is set up to assume Borland 4.5. If you have another
|
||||
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.
|
||||
The Makefile is set up to assume Borland 5.5. If you have another
|
||||
version, change the line near the top.
|
||||
|
||||
Digital Mars compiler
|
||||
---------------------
|
||||
|
|
@ -180,10 +181,15 @@ to the collector DLL still exists, but requires that both
|
|||
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
|
||||
To build the collector as a dynamic library which handles threads similarly
|
||||
to other platforms, type "nmake -f NT_MAKEFILE". If automatic tracking of
|
||||
threads attached to the collector DLL (i.e. support of both kinds of thread
|
||||
tracking) is needed then delete "-DTHREAD_LOCAL_ALLOC" from NT_MAKEFILE
|
||||
manually before the build.
|
||||
|
||||
The alternate way (not well tested) to build the dynamic library that supports
|
||||
both kinds of thread tracking is to use gc.mak instead of NT_MAKEFILE.
|
||||
To build the garbage collector test with VC++ from the command line, use
|
||||
|
||||
nmake /F ".\gc.mak" CFG="gctest - Win32 Release"
|
||||
|
||||
|
|
@ -194,10 +200,9 @@ 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.)
|
||||
with Microsoft tools (e.g., NT_MAKEFILE) and with the GNU
|
||||
tools. The collector must be built with GC_THREADS defined (this is the
|
||||
default in NT_MAKEFILE, ./configure and CMakeLists.txt).
|
||||
|
||||
For the normal, non-dll-based thread tracking to work properly,
|
||||
threads should be created with GC_CreateThread or GC_beginthreadex,
|
||||
|
|
|
|||
|
|
@ -1,26 +1,27 @@
|
|||
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.
|
||||
NT_MAKEFILE has been used in this environment. Type
|
||||
"nmake -f NT_MAKEFILE cpu=AMD64 nodebug=1" in a Visual C++ command line
|
||||
window to build the release variant of the dynamic library with threads
|
||||
support 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.
|
||||
Test_cpp.exe might not run correctly in case of dynamic GC linking. (It seems
|
||||
that we're getting wrong instances of operator new/delete in some cases.)
|
||||
|
||||
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.
|
||||
This process is completely analogous to NT_MAKEFILE usage
|
||||
for the 32-bit library version.
|
||||
|
||||
Note that currently a few warnings are still generated by default,
|
||||
and a number of others have been explicitly turned off in the makefile.
|
||||
A similar procedure using NT_MAKEFILE is applicable to build the static
|
||||
library - just pass "make_as_lib=1" as an extra argument to nmake.
|
||||
If needed, it is also possible to build the library without threads
|
||||
support - this could be done by passing "nothreads=1" argument to nmake.
|
||||
|
||||
VC++ note: to suppress warnings use -D_CRT_SECURE_NO_DEPRECATE.
|
||||
Note that some warnings have been explicitly turned off in the makefile.
|
||||
|
||||
VC++ note: to suppress warnings -D_CRT_SECURE_NO_DEPRECATE is used.
|
||||
|
||||
gcc note: -fno-strict-aliasing should be used if optimizing.
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ before including <TT>gc.h</tt> and allocating with <TT>GC_MALLOC</tt>),
|
|||
so that objects will be identified by their allocation site,
|
||||
<LI> Running the application long enough so
|
||||
that most of the heap is composed of "leaked" memory, and
|
||||
<LI> Then calling <TT>GC_generate_random_backtrace()</tt> from backptr.h
|
||||
<LI> Then calling <TT>GC_generate_random_backtrace()</tt> from gc_backptr.h
|
||||
a few times to determine why some randomly sampled objects in the heap are
|
||||
being retained.
|
||||
</ol>
|
||||
|
|
@ -285,7 +285,7 @@ collector's layout description for <TT>s</tt> is such that the pointer field
|
|||
will be scanned. Call <TT>*GC_find_header(s)</tt> to look at the descriptor
|
||||
for the heap chunk. The <TT>hb_descr</tt> field specifies the layout
|
||||
of objects in that chunk. See gc_mark.h for the meaning of the descriptor.
|
||||
(If it's low order 2 bits are zero, then it is just the length of the
|
||||
(If its low order 2 bits are zero, then it is just the length of the
|
||||
object prefix to be scanned. This form is always used for objects allocated
|
||||
with <TT>GC_malloc</tt> or <TT>GC_malloc_atomic</tt>.)
|
||||
<LI> If the failure is not deterministic, you may still be able to apply some
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
## Process this file with automake to produce Makefile.in.
|
||||
|
||||
# installed documentation
|
||||
#
|
||||
dist_pkgdata_DATA = \
|
||||
if ENABLE_DOCS
|
||||
dist_doc_DATA = \
|
||||
AUTHORS \
|
||||
README.md \
|
||||
doc/README.DGUX386 \
|
||||
|
|
@ -38,7 +38,6 @@ dist_pkgdata_DATA = \
|
|||
doc/README.win64 \
|
||||
doc/debugging.html \
|
||||
doc/finalization.html \
|
||||
doc/gc.man \
|
||||
doc/gcdescr.html \
|
||||
doc/gcinterface.html \
|
||||
doc/leak.html \
|
||||
|
|
@ -47,3 +46,6 @@ dist_pkgdata_DATA = \
|
|||
doc/scale.html \
|
||||
doc/simple_example.html \
|
||||
doc/tree.html
|
||||
|
||||
dist_man3_MANS = doc/gc.man
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.TH GC_MALLOC 1L "2 October 2003"
|
||||
.TH BDWGC 3 "22 July 2018"
|
||||
.SH NAME
|
||||
GC_malloc, GC_malloc_atomic, GC_free, GC_realloc, GC_enable_incremental, GC_register_finalizer, GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page, GC_set_warn_proc \- Garbage collecting malloc replacement
|
||||
.SH SYNOPSIS
|
||||
|
|
@ -11,7 +11,7 @@ void GC_free(void *ptr);
|
|||
void * GC_realloc(void *ptr, size_t size);
|
||||
.br
|
||||
.sp
|
||||
cc ... gc.a
|
||||
cc ... -lgc
|
||||
.LP
|
||||
.SH DESCRIPTION
|
||||
.I GC_malloc
|
||||
|
|
@ -91,7 +91,7 @@ Other facilities not discussed here include limited facilities to support increm
|
|||
.SH "SEE ALSO"
|
||||
The README and gc.h files in the distribution. More detailed definitions of the functions exported by the collector are given there. (The above list is not complete.)
|
||||
.LP
|
||||
The web site at http://www.hboehm.info/gc/ .
|
||||
The web site at http://www.hboehm.info/gc/ (or https://github.com/ivmai/bdwgc/).
|
||||
.LP
|
||||
Boehm, H., and M. Weiser, "Garbage Collection in an Uncooperative Environment",
|
||||
"Software Practice & Experience", September 1988, pp. 807-820.
|
||||
|
|
@ -100,4 +100,4 @@ The malloc(3) man page.
|
|||
.LP
|
||||
.SH AUTHOR
|
||||
Hans-J. Boehm (boehm@acm.org).
|
||||
Some of the code was written by others, most notably Alan Demers.
|
||||
Some of the code was written by others (see the AUTHORS file for the details), most notably by Alan Demers, and, recently, Ivan Maidanski.
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ One (<TT>STUBBORN</tt>) is immutable without special precautions.
|
|||
In spite of that, it is very likely that most C clients of the
|
||||
collector currently
|
||||
use at most two kinds: <TT>NORMAL</tt> and <TT>PTRFREE</tt> objects.
|
||||
The <A HREF="http://gcc.gnu.org/java">gcj</a> runtime also makes
|
||||
heavy use of a kind (allocated with GC_gcj_malloc) that stores
|
||||
The <A HREF="https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcj/">GCJ</a> runtime
|
||||
also makes heavy use of a kind (allocated with GC_gcj_malloc) that stores
|
||||
type information at a known offset in method tables.
|
||||
<P>
|
||||
The collector uses a two level allocator. A large block is defined to
|
||||
|
|
@ -133,7 +133,7 @@ large block free list.
|
|||
<P>
|
||||
In order to avoid allocating blocks for too many distinct object sizes,
|
||||
the collector normally does not directly allocate objects of every possible
|
||||
request size. Instead request are rounded up to one of a smaller number
|
||||
request size. Instead, the request is rounded up to one of a smaller number
|
||||
of allocated sizes, for which free lists are maintained. The exact
|
||||
allocated sizes are computed on demand, but subject to the constraint
|
||||
that they increase roughly in geometric progression. Thus objects
|
||||
|
|
@ -230,7 +230,7 @@ At the beginning of the mark phase, all root segments
|
|||
(as described above) are pushed on the
|
||||
stack by <TT>GC_push_roots</tt>. (Registers and eagerly processed
|
||||
stack sections are processed by pushing the referenced objects instead
|
||||
of the stack section itself.) If <TT>ALL_INTERIOR_PTRS</tt> is not
|
||||
of the stack section itself.) If <TT>ALL_INTERIOR_POINTERS</tt> is not
|
||||
defined, then stack roots require special treatment. In this case, the
|
||||
normal marking code ignores interior pointers, but <TT>GC_push_all_stack</tt>
|
||||
explicitly checks for interior pointers and pushes descriptors for target
|
||||
|
|
@ -272,7 +272,7 @@ each call, so that it can also be used by the incremental collector.
|
|||
It is fairly carefully tuned, since it usually consumes a large majority
|
||||
of the garbage collection time.
|
||||
<P>
|
||||
The fact that it perform a only a small amount of work per call also
|
||||
The fact that it performs only a small amount of work per call also
|
||||
allows it to be used as the core routine of the parallel marker. In that
|
||||
case it is normally invoked on thread-private mark stacks instead of the
|
||||
global mark stack. More details can be found in
|
||||
|
|
@ -471,6 +471,9 @@ catching write faults. This is
|
|||
implemented for many Unix-like systems and for win32. It is not possible
|
||||
in a few environments.
|
||||
<LI>
|
||||
(<TT>GWW_VDB</tt>) By using the Win32 GetWriteWatch function to read dirty
|
||||
bits.
|
||||
<LI>
|
||||
(<TT>PROC_VDB</tt>) By retrieving dirty bit information from /proc.
|
||||
(Currently only Sun's
|
||||
Solaris supports this. Though this is considerably cleaner, performance
|
||||
|
|
@ -489,9 +492,9 @@ the vast majority of objects use <TT>GC_malloc_stubborn</tt>.
|
|||
|
||||
The collector implements <I>black-listing</i> of pages, as described
|
||||
in
|
||||
<A HREF="http://www.acm.org/pubs/citations/proceedings/pldi/155090/p197-boehm/">
|
||||
<A HREF="http://dl.acm.org/citation.cfm?doid=155090.155109">
|
||||
Boehm, ``Space Efficient Conservative Collection'', PLDI '93</a>, also available
|
||||
<A HREF="papers/pldi93.ps.Z">here</a>.
|
||||
<A HREF="https://www.cs.rice.edu/~javaplt/311/Readings/pldi93.pdf">here</a>.
|
||||
<P>
|
||||
During the mark phase, the collector tracks ``near misses'', i.e. attempts
|
||||
to follow a ``pointer'' to just outside the garbage-collected heap, or
|
||||
|
|
@ -534,23 +537,16 @@ common Pthreads implementations.
|
|||
In particular, it is very difficult for the collector to stop all other
|
||||
threads in the system and examine the register contents. This is currently
|
||||
accomplished with very different mechanisms for some Pthreads
|
||||
implementations. The Solaris implementation temporarily disables much
|
||||
of the user-level threads implementation by stopping kernel-level threads
|
||||
("lwp"s). The Linux/HPUX/OSF1 and Irix implementations sends signals to
|
||||
implementations. For Linux/HPUX/OSF1, Solaris and Irix it sends signals to
|
||||
individual Pthreads and has them wait in the signal handler.
|
||||
<P>
|
||||
The Linux and Irix implementations use
|
||||
only documented Pthreads calls, but rely on extensions to their semantics.
|
||||
The Linux implementation <TT>linux_threads.c</tt> relies on only very
|
||||
The Linux implementation <TT>pthread_stop_world.c</tt> relies on only very
|
||||
mild extensions to the pthreads semantics, and already supports a large number
|
||||
of other Unix-like pthreads implementations. Our goal is to make this the
|
||||
only pthread support in the collector.
|
||||
<P>
|
||||
(The Irix implementation is separate only for historical reasons and should
|
||||
clearly be merged. The current Solaris implementation probably performs
|
||||
better in the uniprocessor case, but does not support thread operations in the
|
||||
collector. Hence it cannot support the parallel marker.)
|
||||
<P>
|
||||
All implementations must
|
||||
intercept thread creation and a few other thread-specific calls to allow
|
||||
enumeration of threads and location of thread stacks. This is current
|
||||
|
|
@ -617,12 +613,5 @@ 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:bdwgc@lists.opendylan.org"><tt>bdwgc@lists.opendylan.org</tt></a>
|
||||
(GC mailing list) or
|
||||
<A HREF="mailto:boehm@acm.org"><TT>boehm@acm.org</tt></a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ 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>
|
||||
<DT> <B> void 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
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ 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,
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<td><a href="http://www.hboehm.info/gc/04tutorial.pdf">Tutorial Slides</a></td>
|
||||
<td><a href="http://www.hboehm.info/gc/faq.html">FAQ</a></td>
|
||||
<td><a href="simple_example.html">Example</a></td>
|
||||
<td><a href="http://www.hboehm.info/gc/gc_source/">Download</a></td>
|
||||
<td><a href="https://github.com/ivmai/bdwgc/wiki/Download">Download</a></td>
|
||||
<td><a href="http://www.hboehm.info/gc/license.txt">License</a></td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
|
@ -27,11 +27,10 @@
|
|||
before that at
|
||||
<tt>http://reality.sgi.com/boehm/gc.html</tt>
|
||||
and before that at
|
||||
<a href="ftp://ftp.parc.xerox.com/pub/gc/gc.html">
|
||||
<tt>ftp://ftp.parc.xerox.com/pub/gc/gc.html</tt></a>. ]
|
||||
<tt>ftp://ftp.parc.xerox.com/pub/gc/gc.html</tt>. ]
|
||||
<p>
|
||||
The <a href="http://www.hboehm.info">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
|
||||
The <a href="http://www.hboehm.info">Boehm</a>-<a href="http://www.cs.cornell.edu/annual_report/00-01/bios.htm#demers">Demers</a>-<a href="http://www.ubiq.com/hypertext/weiser/weiser.html">Weiser</a>
|
||||
conservative Garbage Collector (<b>BDWGC</b>) 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,
|
||||
|
|
@ -52,23 +51,14 @@ 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.hboehm.info/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.hboehm.info/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.
|
||||
</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>.
|
||||
Typically several versions are offered for
|
||||
<a href="https://github.com/ivmai/bdwgc/wiki/Download">downloading</a>:
|
||||
preview, stable, legacy.
|
||||
Usually you should use the one marked as the <i>latest stable</i> release.
|
||||
Preview versions may contain additional features, platform support,
|
||||
but are likely to be less well tested.
|
||||
The list of changes for each version is specified on the
|
||||
<a href="https://github.com/ivmai/bdwgc/releases">releases</a> page.
|
||||
</p><p>
|
||||
The arguments for and against conservative garbage collection
|
||||
in C and C++ are briefly
|
||||
|
|
@ -110,8 +100,7 @@ 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>.
|
||||
<tt>http://homepage.mac.com/pcbeard/gc/</tt>.
|
||||
(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
|
||||
|
|
@ -124,7 +113,7 @@ Precompiled versions of the collector for NetBSD are available
|
|||
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://web.yl.is.s.u-tokyo.ac.jp/gc/">parallel collector</a>
|
||||
a <a href="http://ieeexplore.ieee.org/abstract/document/1592629/">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.
|
||||
|
|
@ -265,7 +254,7 @@ Proceedings of the ACM SIGPLAN '96 Conference on Programming Language Design
|
|||
and Implementation.
|
||||
</p><p>
|
||||
Boehm, H., and D. Chase, <a href="http://www.hboehm.info/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.
|
||||
<i>Journal of C Language Translation 4</i>, 2 (December 1992), pp. 126-141.
|
||||
</p><p>
|
||||
<b>Other related information: </b>
|
||||
</p><p>
|
||||
|
|
@ -275,7 +264,9 @@ using programs written for malloc/free.
|
|||
</p><p>
|
||||
Joel Bartlett's <a href="ftp://gatekeeper.dec.com/pub/compaq/WRL/research-reports/WRL-TN-12.ps">mostly copying conservative garbage collector for C++</a>.
|
||||
</p><p>
|
||||
John Ellis and David Detlef's <a href="ftp://ftp.parc.xerox.com/pub/ellis/gc/gc.ps">Safe Efficient Garbage Collection for C++</a> proposal.
|
||||
John Ellis and David Detlef's
|
||||
<a href="http://dl.acm.org/citation.cfm?id=1267983">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>
|
||||
|
|
@ -283,7 +274,8 @@ Slides for Hans Boehm's <a href="http://www.hboehm.info/gc/myths.ps">Allocation
|
|||
</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 runtime system for
|
||||
<a href="https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcj/">GCJ</a>,
|
||||
the static GNU java compiler.
|
||||
</p><p>
|
||||
<a href="http://w3m.sourceforge.net/">W3m</a>, a text-based web browser.
|
||||
|
|
@ -335,11 +327,11 @@ research in algebraic geometry and commutative algebra.
|
|||
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>.
|
||||
<a href="http://www.visual-prolog.com/">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>
|
||||
</p><h1><a name="collector">More information on the BDWGC primary site</a></h1>
|
||||
<a href="simple_example.html">A simple illustration of how to build and
|
||||
use the collector</a>.
|
||||
<p>
|
||||
|
|
@ -362,8 +354,12 @@ garbage collector.</a>
|
|||
</p><p>
|
||||
<a href="scale.html">Scalability of the collector to multiprocessors.</a>
|
||||
</p><p>
|
||||
<a href="http://www.hboehm.info/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.hboehm.info/gc/gc_source/">Directory</a> containing
|
||||
the distribution files of all garbage collector releases.
|
||||
It duplicates
|
||||
<a href="https://github.com/ivmai/bdwgc/wiki/Download">Download</a> page on
|
||||
GitHub.
|
||||
</p><h1><a name="background">More background information</a></h1>
|
||||
<a href="http://www.hboehm.info/gc/bounds.html">An attempt to establish a bound on space usage of
|
||||
conservative garbage collectors</a>.
|
||||
<p>
|
||||
|
|
@ -398,37 +394,38 @@ Technical Report version</a>).
|
|||
<a href="http://www.hboehm.info/gc/gctalk.ps">Slides for OOPSLA 98 garbage collection talk</a>.
|
||||
</p><p>
|
||||
<a href="http://www.hboehm.info/gc/papers/">Related papers</a>.
|
||||
</p><h1><a name="contacts">Contacts and Mailing List</a></h1>
|
||||
<a>We have recently set up two mailing list for collector announcements
|
||||
and discussions:
|
||||
</a><ul>
|
||||
<li><a href="mailto:bdwgc-announce@lists.opendylan.org">bdwgc-announce@lists.opendylan.org</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:bdwgc@lists.opendylan.org">bdwgc@lists.opendylan.org</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, please visit
|
||||
<a href="https://lists.opendylan.org/mailman/listinfo/bdwgc-announce">lists.opendylan.org/mailman/listinfo/bdwgc-announce</a>
|
||||
and
|
||||
<a href="https://lists.opendylan.org/mailman/listinfo/bdwgc">lists.opendylan.org/mailman/listinfo/bdwgc</a>,
|
||||
respectively.
|
||||
</p><h1><a name="contacts">Contacts and new release announcements</a></h1>
|
||||
GitHub and Stack Overflow are the major two places for communication.
|
||||
<p>
|
||||
The archives for these lists appear
|
||||
<a href="https://lists.opendylan.org/pipermail/bdwgc-announce/">here</a> and
|
||||
<a href="https://lists.opendylan.org/pipermail/bdwgc/">here</a>,
|
||||
respectively.
|
||||
Technical questions (how to, how does it work, etc.) should be posted to
|
||||
<a href="https://stackoverflow.com/questions/tagged/boehm-gc">Stack Overflow</a>
|
||||
with "boehm-gc" tag.
|
||||
</p><p>
|
||||
To contribute, please rebase your code to the latest
|
||||
<a href="https://github.com/ivmai/bdwgc/tree/master/">master</a> and submit
|
||||
a <a href="https://github.com/ivmai/bdwgc/pulls">pull request</a> to GitHub.
|
||||
</p><p>
|
||||
To report a bug, or propose (request) a new feature, create
|
||||
a <a href="https://github.com/ivmai/bdwgc/issues">GitHub issue</a>.
|
||||
Please make sure it has not been reported yet by someone else.
|
||||
</p><p>
|
||||
To receive notifications on every release, please subscribe to
|
||||
<a href="https://github.com/ivmai/bdwgc/releases.atom">Releases RSS feed</a>.
|
||||
Notifications on all issues and pull requests are available by
|
||||
<a href="https://github.com/ivmai/bdwgc/watchers">watching</a> the project.
|
||||
</p><p>
|
||||
Mailing lists (bdwgc-announce@lists.opendylan.org, bdwgc@lists.opendylan.org,
|
||||
and the former gc-announce@linux.hpl.hp.com and gc@linux.hpl.hp.com) are not
|
||||
used at this moment. Their content is available in
|
||||
<a href="https://github.com/ivmai/bdwgc/files/1037650/bdwgc-announce-mailing-list-archive-2014_02.tar.gz">bdwgc-announce</a>
|
||||
and
|
||||
<a href="https://github.com/ivmai/bdwgc/files/1038163/bdwgc-mailing-list-archive-2017_04.tar.gz">bdwgc</a>
|
||||
archive files, respectively.
|
||||
The gc list archive may also be read at
|
||||
<a href="http://dir.gmane.org/gmane.comp.programming.garbage-collection.boehmgc">gmane.org</a>.
|
||||
<a href="http://bdwgc.opendylan.narkive.com">Narkive</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:boehm@acm.org">boehm@acm.org</a>), but the gc
|
||||
mailing list is usually preferred.
|
||||
</p></body></html>
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ should be defined to the limits of the second main data segment.
|
|||
<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
|
||||
has more than one stack per thread, and is not supported yet, you will
|
||||
need to do more work. Grep for "IA64" in the source for an example.)
|
||||
<DT><TT>STACKBOTTOM</tt>
|
||||
<DD>
|
||||
|
|
@ -166,7 +166,7 @@ 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
|
||||
Segmentation violation or Bus error is signaled, round that
|
||||
to the nearest plausible page boundary, and use that as the
|
||||
stack base.
|
||||
<DT><TT>DYNAMIC_LOADING</tt>
|
||||
|
|
@ -181,7 +181,7 @@ 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>
|
||||
<DT><TT>PREFETCH, GC_PREFETCH_FOR_WRITE</tt>
|
||||
<DD>
|
||||
The collector uses <TT>PREFETCH</tt>(<I>x</i>) to preload the cache
|
||||
with *<I>x</i>.
|
||||
|
|
@ -196,12 +196,6 @@ word stores of 0 are used instead.
|
|||
<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
|
||||
|
|
@ -214,7 +208,7 @@ tweaking of conditional compilation tests.
|
|||
<P>
|
||||
For GC7, if your platform supports <TT>getcontext()</tt>, then defining
|
||||
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.
|
||||
(if it isn't defined there yet) 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
|
||||
|
|
|
|||
|
|
@ -64,23 +64,12 @@ 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.
|
||||
spin-then-sleep lock to be replaced 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
|
||||
|
|
@ -145,7 +134,7 @@ 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
|
||||
(The times for the <TT>malloc</tt>/<TT>free</tt> version
|
||||
with glibc <TT>malloc</tt>
|
||||
are 10.51 (standard library, pthreads not linked),
|
||||
20.90 (one thread, pthreads linked),
|
||||
|
|
@ -167,7 +156,7 @@ avoided in time-critical code.
|
|||
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.
|
||||
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
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ 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
|
||||
If you have not so yet, unpack the collector and enter
|
||||
the newly created directory with
|
||||
<PRE>
|
||||
tar xvfz gc<version>.tar.gz
|
||||
|
|
@ -55,7 +55,7 @@ strong preference of the would-be maintainer of those project files.)
|
|||
If you need thread support, configure the collector with
|
||||
</font>
|
||||
<PRE style="color:green">
|
||||
--enable-threads=posix --enable-thread-local-alloc --enable-parallel-mark
|
||||
--enable-threads=posix --enable-parallel-mark
|
||||
</pre>
|
||||
<FONT COLOR=green>
|
||||
instead of
|
||||
|
|
@ -143,22 +143,6 @@ 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>
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ freed; free lists are used (e.g. alloc_hdr). HBLK's below are collected.
|
|||
HBLKSIZE | |--------------- | (words)
|
||||
(bytes) | | v MAX_OFFSET
|
||||
| + - - - - - - - - - - -+ --- (bytes)
|
||||
| | | !All_INTERIOR_PTRS ^ |
|
||||
| | | !ALL_INTERIOR_POINTERS ^ |
|
||||
| | | sets j only for hb_sz |
|
||||
| | Object N | valid object offsets. | |
|
||||
v | | All objects WORDSZ v v
|
||||
|
|
|
|||
|
|
@ -52,18 +52,18 @@ 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(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(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.
|
||||
#if !defined(DARWIN) && !defined(SCO_ELF) && !defined(SOLARISDL) \
|
||||
&& !defined(AIX) && !defined(DGUX) && !defined(IRIX5) && !defined(HPUX) \
|
||||
&& !defined(CYGWIN32) && !defined(MSWIN32) && !defined(MSWINCE) \
|
||||
&& !(defined(ALPHA) && defined(OSF1)) \
|
||||
&& !(defined(FREEBSD) && defined(__ELF__)) \
|
||||
&& !((defined(LINUX) || defined(NACL)) && defined(__ELF__)) \
|
||||
&& !(defined(NETBSD) && defined(__ELF__)) \
|
||||
&& !defined(HAIKU) && !defined(HURD) \
|
||||
&& !(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) \
|
||||
&& !defined(CPPCHECK)
|
||||
# error We only know how to find data segments of dynamic libraries for above.
|
||||
# error Additional SVR4 variants might not be too hard to add.
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
|
@ -82,14 +82,15 @@ STATIC GC_has_static_roots_func GC_has_static_roots = 0;
|
|||
|
||||
#if defined(OPENBSD)
|
||||
# include <sys/param.h>
|
||||
# if OpenBSD >= 200519
|
||||
# if (OpenBSD >= 200519) && !defined(HAVE_DL_ITERATE_PHDR)
|
||||
# define HAVE_DL_ITERATE_PHDR
|
||||
# endif
|
||||
#endif /* OPENBSD */
|
||||
|
||||
#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
|
||||
|| (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
|
||||
|| defined(NETBSD) || defined(OPENBSD)))
|
||||
|| defined(NACL) || defined(NETBSD) \
|
||||
|| defined(OPENBSD)))
|
||||
# include <stddef.h>
|
||||
# if !defined(OPENBSD) && !defined(PLATFORM_ANDROID)
|
||||
/* OpenBSD does not have elf.h file; link.h below is sufficient. */
|
||||
|
|
@ -109,9 +110,9 @@ STATIC GC_has_static_roots_func GC_has_static_roots = 0;
|
|||
# undef EM_ALPHA
|
||||
# endif
|
||||
# include <link.h>
|
||||
# if !defined(GC_DONT_DEFINE_LINK_MAP)
|
||||
/* link_map and r_debug should be defined explicitly, */
|
||||
/* as only bionic/linker/linker.h defines them but the header */
|
||||
# if !defined(GC_DONT_DEFINE_LINK_MAP) && !(__ANDROID_API__ >= 21)
|
||||
/* link_map and r_debug are defined in link.h of NDK r10+. */
|
||||
/* bionic/linker/linker.h defines them too but the header */
|
||||
/* itself is a C++ one starting from Android 4.3. */
|
||||
struct link_map {
|
||||
uintptr_t l_addr;
|
||||
|
|
@ -179,23 +180,26 @@ GC_FirstDLOpenedLinkMap(void)
|
|||
/* at program startup. */
|
||||
if( dynStructureAddr == 0 ) {
|
||||
void* startupSyms = dlopen(0, RTLD_LAZY);
|
||||
dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
|
||||
dynStructureAddr = (ElfW(Dyn)*)(word)dlsym(startupSyms, "_DYNAMIC");
|
||||
}
|
||||
# else
|
||||
dynStructureAddr = &_DYNAMIC;
|
||||
# endif
|
||||
|
||||
if (dynStructureAddr == 0) {
|
||||
if (0 == COVERT_DATAFLOW(dynStructureAddr)) {
|
||||
/* _DYNAMIC symbol not resolved. */
|
||||
return(0);
|
||||
}
|
||||
if( cachedResult == 0 ) {
|
||||
if (cachedResult == 0) {
|
||||
int tag;
|
||||
for( dp = ((ElfW(Dyn) *)(&_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 NULL */
|
||||
if (tag == DT_DEBUG) {
|
||||
struct r_debug *rd = (struct r_debug *)dp->d_un.d_ptr;
|
||||
if (rd != NULL) {
|
||||
struct link_map *lm = rd->r_map;
|
||||
if (lm != NULL)
|
||||
cachedResult = lm->l_next; /* might be NULL */
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -213,8 +217,9 @@ GC_FirstDLOpenedLinkMap(void)
|
|||
# if defined(SOLARISDL)
|
||||
|
||||
/* Add dynamic library data sections to the root set. */
|
||||
# if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
|
||||
--> fix mutual exclusion with dlopen
|
||||
# if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS) \
|
||||
&& !defined(CPPCHECK)
|
||||
# error Fix mutual exclusion with dlopen
|
||||
# endif
|
||||
|
||||
# ifndef USE_PROC_FOR_LIBRARIES
|
||||
|
|
@ -257,7 +262,8 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
|
||||
#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) \
|
||||
|| (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
|
||||
|| defined(NETBSD) || defined(OPENBSD)))
|
||||
|| defined(NACL) || defined(NETBSD) \
|
||||
|| defined(OPENBSD)))
|
||||
|
||||
#ifdef USE_PROC_FOR_LIBRARIES
|
||||
|
||||
|
|
@ -279,9 +285,10 @@ 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) {
|
||||
signed_word i;
|
||||
|
||||
while (nsorted < n &&
|
||||
(word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start)
|
||||
++nsorted;
|
||||
|
|
@ -299,7 +306,7 @@ static void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
|
|||
}
|
||||
}
|
||||
|
||||
STATIC word GC_register_map_entries(char *maps)
|
||||
STATIC void GC_register_map_entries(char *maps)
|
||||
{
|
||||
char *prot;
|
||||
char *buf_ptr = maps;
|
||||
|
|
@ -307,19 +314,6 @@ STATIC word GC_register_map_entries(char *maps)
|
|||
unsigned int maj_dev;
|
||||
ptr_t least_ha, greatest_ha;
|
||||
unsigned i;
|
||||
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);
|
||||
|
|
@ -330,7 +324,8 @@ STATIC word GC_register_map_entries(char *maps)
|
|||
for (;;) {
|
||||
buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, &prot,
|
||||
&maj_dev, 0);
|
||||
if (buf_ptr == NULL) return 1;
|
||||
if (NULL == buf_ptr)
|
||||
break;
|
||||
if (prot[1] == 'w') {
|
||||
/* This is a writable mapping. Add it to */
|
||||
/* the root set unless it is already otherwise */
|
||||
|
|
@ -395,15 +390,21 @@ STATIC word GC_register_map_entries(char *maps)
|
|||
}
|
||||
if ((word)start < (word)end)
|
||||
GC_add_roots_inner((char *)start, (char *)end, TRUE);
|
||||
} else if (prot[0] == '-' && prot[1] == '-' && prot[2] == '-') {
|
||||
/* Even roots added statically might disappear partially */
|
||||
/* (e.g. the roots added by INCLUDE_LINUX_THREAD_DESCR). */
|
||||
GC_remove_roots_subregion(start, end);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
GC_INNER void GC_register_dynamic_libraries(void)
|
||||
{
|
||||
if (!GC_register_map_entries(GC_get_maps()))
|
||||
char *maps = GC_get_maps();
|
||||
|
||||
if (NULL == maps)
|
||||
ABORT("Failed to read /proc for library registration");
|
||||
GC_register_map_entries(maps);
|
||||
}
|
||||
|
||||
/* We now take care of the main data segment ourselves: */
|
||||
|
|
@ -423,23 +424,28 @@ GC_INNER GC_bool GC_register_main_static_data(void)
|
|||
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
|
||||
|| (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)) \
|
||||
|| defined(PLATFORM_ANDROID) /* Are others OK here, too? */
|
||||
/* 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
|
||||
# ifndef HAVE_DL_ITERATE_PHDR
|
||||
# define HAVE_DL_ITERATE_PHDR
|
||||
# endif
|
||||
# ifdef PLATFORM_ANDROID
|
||||
/* Android headers might have no such definition for some targets. */
|
||||
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *),
|
||||
void *data);
|
||||
# endif
|
||||
# pragma weak dl_iterate_phdr
|
||||
#endif
|
||||
#endif /* __GLIBC__ >= 2 || PLATFORM_ANDROID */
|
||||
|
||||
#if (defined(FREEBSD) && __FreeBSD__ >= 7)
|
||||
#if (defined(FREEBSD) && __FreeBSD__ >= 7) || defined(__DragonFly__)
|
||||
/* 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
|
||||
/* have dl_iterate_phdr; therefore, we need not make it weak as below. */
|
||||
# ifndef HAVE_DL_ITERATE_PHDR
|
||||
# define HAVE_DL_ITERATE_PHDR
|
||||
# endif
|
||||
# define DL_ITERATE_PHDR_STRONG
|
||||
#elif defined(HAVE_DL_ITERATE_PHDR)
|
||||
/* 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. */
|
||||
# pragma weak dl_iterate_phdr
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DL_ITERATE_PHDR)
|
||||
|
|
@ -464,6 +470,7 @@ GC_INNER GC_bool GC_register_main_static_data(void)
|
|||
} load_segs[MAX_LOAD_SEGS];
|
||||
|
||||
static int n_load_segs;
|
||||
static GC_bool load_segs_overflow;
|
||||
# endif /* PT_GNU_RELRO */
|
||||
|
||||
STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
|
||||
|
|
@ -479,75 +486,80 @@ STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
|
|||
return -1;
|
||||
|
||||
p = info->dlpi_phdr;
|
||||
for( i = 0; i < (int)info->dlpi_phnum; i++, p++ ) {
|
||||
switch( p->p_type ) {
|
||||
for (i = 0; i < (int)info->dlpi_phnum; i++, p++) {
|
||||
if (p->p_type == PT_LOAD) {
|
||||
GC_has_static_roots_func callback = GC_has_static_roots;
|
||||
if ((p->p_flags & PF_W) == 0) continue;
|
||||
|
||||
start = (ptr_t)p->p_vaddr + info->dlpi_addr;
|
||||
end = start + p->p_memsz;
|
||||
if (callback != 0 && !callback(info->dlpi_name, start, p->p_memsz))
|
||||
continue;
|
||||
# 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);
|
||||
}
|
||||
# if CPP_WORDSZ == 64
|
||||
/* TODO: 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 & ~(word)(sizeof(word) - 1));
|
||||
# endif
|
||||
if (n_load_segs >= MAX_LOAD_SEGS) {
|
||||
if (!load_segs_overflow) {
|
||||
WARN("Too many PT_LOAD segments;"
|
||||
" registering as roots directly...\n", 0);
|
||||
load_segs_overflow = TRUE;
|
||||
}
|
||||
GC_add_roots_inner(start, end, TRUE);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
break;
|
||||
# endif
|
||||
|
||||
case PT_LOAD:
|
||||
{
|
||||
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;
|
||||
# else
|
||||
GC_add_roots_inner(start, end, TRUE);
|
||||
# endif /* !PT_GNU_RELRO */
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef PT_GNU_RELRO
|
||||
p = info->dlpi_phdr;
|
||||
for (i = 0; i < (int)info->dlpi_phnum; i++, p++) {
|
||||
if (p->p_type == PT_GNU_RELRO) {
|
||||
/* This entry is known to be constant and will eventually be */
|
||||
/* remapped as 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 one\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 (0 == j && 0 == GC_has_static_roots)
|
||||
WARN("Failed to find PT_GNU_RELRO segment"
|
||||
" inside PT_LOAD region\n", 0);
|
||||
/* No warning reported in case of the callback is present */
|
||||
/* because most likely the segment has been excluded. */
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
*(int *)ptr = 1; /* Signal that we were called */
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -560,7 +572,7 @@ GC_INNER GC_bool GC_register_main_static_data(void)
|
|||
/* zero (otherwise a compiler might issue a warning). */
|
||||
return FALSE;
|
||||
# else
|
||||
return (dl_iterate_phdr == 0); /* implicit conversion to function ptr */
|
||||
return 0 == COVERT_DATAFLOW(dl_iterate_phdr);
|
||||
# endif
|
||||
}
|
||||
|
||||
|
|
@ -575,6 +587,7 @@ STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
|
|||
{
|
||||
static GC_bool excluded_segs = FALSE;
|
||||
n_load_segs = 0;
|
||||
load_segs_overflow = FALSE;
|
||||
if (!EXPECT(excluded_segs, TRUE)) {
|
||||
GC_exclude_static_roots_inner((ptr_t)load_segs,
|
||||
(ptr_t)load_segs + sizeof(load_segs));
|
||||
|
|
@ -606,7 +619,7 @@ STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
|
|||
|
||||
/* Evaluate DATASTART only once. */
|
||||
if (datastart_cached == (ptr_t)(word)-1) {
|
||||
datastart_cached = (ptr_t)(DATASTART);
|
||||
datastart_cached = DATASTART;
|
||||
}
|
||||
datastart = (char *)datastart_cached;
|
||||
# else
|
||||
|
|
@ -617,19 +630,29 @@ STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
|
|||
static ptr_t dataend_cached = 0;
|
||||
/* Evaluate DATAEND only once. */
|
||||
if (dataend_cached == 0) {
|
||||
dataend_cached = (ptr_t)(DATAEND);
|
||||
dataend_cached = DATAEND;
|
||||
}
|
||||
dataend = (char *)dataend_cached;
|
||||
}
|
||||
# else
|
||||
dataend = DATAEND;
|
||||
# endif
|
||||
if (NULL == *(char * volatile *)&datastart
|
||||
|| (word)datastart > (word)dataend)
|
||||
ABORT_ARG2("Wrong DATASTART/END pair",
|
||||
": %p .. %p", (void *)datastart, (void *)dataend);
|
||||
|
||||
/* 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);
|
||||
# ifdef GC_HAVE_DATAREGION2
|
||||
if ((word)DATASTART2 - 1U >= (word)DATAEND2) {
|
||||
/* Subtract one to check also for NULL */
|
||||
/* without a compiler warning. */
|
||||
ABORT_ARG2("Wrong DATASTART/END2 pair",
|
||||
": %p .. %p", (void *)DATASTART2, (void *)DATAEND2);
|
||||
}
|
||||
GC_add_roots_inner(DATASTART2, DATAEND2, TRUE);
|
||||
# endif
|
||||
}
|
||||
return TRUE;
|
||||
|
|
@ -677,17 +700,21 @@ extern ElfW(Dyn) _DYNAMIC[];
|
|||
STATIC struct link_map *
|
||||
GC_FirstDLOpenedLinkMap(void)
|
||||
{
|
||||
ElfW(Dyn) *dp;
|
||||
static struct link_map *cachedResult = 0;
|
||||
|
||||
if (0 == (ptr_t)_DYNAMIC) {
|
||||
if (0 == COVERT_DATAFLOW(_DYNAMIC)) {
|
||||
/* _DYNAMIC symbol not resolved. */
|
||||
return(0);
|
||||
}
|
||||
if( cachedResult == 0 ) {
|
||||
# if defined(NETBSD) && defined(RTLD_DI_LINKMAP)
|
||||
# if defined(CPPCHECK)
|
||||
# define GC_RTLD_DI_LINKMAP 2
|
||||
# else
|
||||
# define GC_RTLD_DI_LINKMAP RTLD_DI_LINKMAP
|
||||
# endif
|
||||
struct link_map *lm = NULL;
|
||||
if (!dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lm) && lm != NULL) {
|
||||
if (!dlinfo(RTLD_SELF, GC_RTLD_DI_LINKMAP, &lm) && lm != NULL) {
|
||||
/* Now lm points link_map object of libgc. Since it */
|
||||
/* might not be the first dynamically linked object, */
|
||||
/* try to find it (object next to the main object). */
|
||||
|
|
@ -697,12 +724,18 @@ GC_FirstDLOpenedLinkMap(void)
|
|||
cachedResult = lm->l_next;
|
||||
}
|
||||
# else
|
||||
ElfW(Dyn) *dp;
|
||||
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 NULL */
|
||||
if (tag == DT_DEBUG) {
|
||||
struct r_debug *rd = (struct r_debug *)dp->d_un.d_ptr;
|
||||
/* d_ptr could be null if libs are linked statically. */
|
||||
if (rd != NULL) {
|
||||
struct link_map *lm = rd->r_map;
|
||||
if (lm != NULL)
|
||||
cachedResult = lm->l_next; /* might be NULL */
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -776,7 +809,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
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 */
|
||||
int needed_sz = 0; /* Required size of addr_map */
|
||||
int i;
|
||||
long flags;
|
||||
ptr_t start;
|
||||
|
|
@ -803,17 +836,19 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
": fd = %d, errno = %d", fd, errno);
|
||||
}
|
||||
if (needed_sz >= current_sz) {
|
||||
GC_scratch_recycle_no_gww(addr_map,
|
||||
(size_t)current_sz * sizeof(prmap_t));
|
||||
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));
|
||||
(size_t)current_sz * sizeof(prmap_t));
|
||||
if (addr_map == NULL)
|
||||
ABORT("Insufficient memory for address map");
|
||||
}
|
||||
if (ioctl(fd, PIOCMAP, addr_map) < 0) {
|
||||
ABORT_ARG3("/proc PIOCMAP ioctl failed",
|
||||
": errcode= %d, needed_sz= %d, addr_map= %p",
|
||||
errno, needed_sz, addr_map);
|
||||
errno, needed_sz, (void *)addr_map);
|
||||
};
|
||||
if (GC_n_heap_sects > 0) {
|
||||
heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
|
||||
|
|
@ -913,7 +948,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
# else
|
||||
char * stack_top
|
||||
= (char *)((word)GC_approx_sp() &
|
||||
~(GC_sysinfo.dwAllocationGranularity - 1));
|
||||
~(word)(GC_sysinfo.dwAllocationGranularity - 1));
|
||||
|
||||
if (base == limit) return;
|
||||
if ((word)limit > (word)stack_top
|
||||
|
|
@ -964,7 +999,6 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
GC_INNER void GC_register_dynamic_libraries(void)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION buf;
|
||||
size_t result;
|
||||
DWORD protect;
|
||||
LPVOID p;
|
||||
char * base;
|
||||
|
|
@ -975,7 +1009,8 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
# endif
|
||||
base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
|
||||
while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress) {
|
||||
result = VirtualQuery(p, &buf, sizeof(buf));
|
||||
size_t result = VirtualQuery(p, &buf, sizeof(buf));
|
||||
|
||||
# ifdef MSWINCE
|
||||
if (result == 0) {
|
||||
/* Page is free; advance to the next possible allocation base */
|
||||
|
|
@ -992,7 +1027,9 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
protect = buf.Protect;
|
||||
if (buf.State == MEM_COMMIT
|
||||
&& (protect == PAGE_EXECUTE_READWRITE
|
||||
|| protect == PAGE_READWRITE)
|
||||
|| protect == PAGE_EXECUTE_WRITECOPY
|
||||
|| protect == PAGE_READWRITE
|
||||
|| protect == PAGE_WRITECOPY)
|
||||
&& (buf.Type == MEM_IMAGE
|
||||
# ifdef GC_REGISTER_MEM_PRIVATE
|
||||
|| (protect == PAGE_READWRITE && buf.Type == MEM_PRIVATE)
|
||||
|
|
@ -1033,29 +1070,18 @@ extern int errno;
|
|||
|
||||
GC_INNER void GC_register_dynamic_libraries(void)
|
||||
{
|
||||
int status;
|
||||
ldr_process_t mypid;
|
||||
|
||||
/* module */
|
||||
ldr_module_t moduleid = LDR_NULL_MODULE;
|
||||
ldr_module_info_t moduleinfo;
|
||||
size_t moduleinfosize = sizeof(moduleinfo);
|
||||
size_t modulereturnsize;
|
||||
|
||||
/* 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();
|
||||
ldr_module_t moduleid = LDR_NULL_MODULE;
|
||||
ldr_process_t mypid = ldr_my_process(); /* obtain id of this process */
|
||||
|
||||
/* For each module */
|
||||
while (TRUE) {
|
||||
|
||||
/* Get the next (first) module */
|
||||
status = ldr_next_module(mypid, &moduleid);
|
||||
ldr_module_info_t moduleinfo;
|
||||
size_t modulereturnsize;
|
||||
ldr_region_t region;
|
||||
ldr_region_info_t regioninfo;
|
||||
size_t regionreturnsize;
|
||||
int status = ldr_next_module(mypid, &moduleid);
|
||||
/* Get the next (first) module */
|
||||
|
||||
/* Any more modules? */
|
||||
if (moduleid == LDR_NULL_MODULE)
|
||||
|
|
@ -1071,7 +1097,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
|
||||
/* Get the module information */
|
||||
status = ldr_inq_module(mypid, moduleid, &moduleinfo,
|
||||
moduleinfosize, &modulereturnsize);
|
||||
sizeof(moduleinfo), &modulereturnsize);
|
||||
if (status != 0 )
|
||||
ABORT("ldr_inq_module failed");
|
||||
|
||||
|
|
@ -1091,7 +1117,7 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
for (region = 0; region < moduleinfo.lmi_nregion; region++) {
|
||||
/* Get the region information */
|
||||
status = ldr_inq_region(mypid, moduleid, region, ®ioninfo,
|
||||
regioninfosize, ®ionreturnsize);
|
||||
sizeof(regioninfo), ®ionreturnsize);
|
||||
if (status != 0 )
|
||||
ABORT("ldr_inq_region failed");
|
||||
|
||||
|
|
@ -1131,15 +1157,13 @@ extern int sys_nerr;
|
|||
|
||||
GC_INNER void GC_register_dynamic_libraries(void)
|
||||
{
|
||||
int status;
|
||||
int index = 1; /* Ordinal position in shared library search list */
|
||||
struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
|
||||
|
||||
/* For each dynamic library loaded */
|
||||
while (TRUE) {
|
||||
|
||||
/* Get info about next shared library */
|
||||
status = shl_get(index, &shl_desc);
|
||||
struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
|
||||
int status = shl_get(index, &shl_desc);
|
||||
/* Get info about next shared library */
|
||||
|
||||
/* Check if this is the end of the list or if some error occurred */
|
||||
if (status != 0) {
|
||||
|
|
@ -1186,18 +1210,24 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
# include <sys/errno.h>
|
||||
GC_INNER void GC_register_dynamic_libraries(void)
|
||||
{
|
||||
int ldibuflen = 8192;
|
||||
|
||||
for (;;) {
|
||||
int len;
|
||||
char *ldibuf;
|
||||
int ldibuflen;
|
||||
struct ld_info *ldi;
|
||||
# if defined(CPPCHECK)
|
||||
char ldibuf[ldibuflen];
|
||||
# else
|
||||
char *ldibuf = alloca(ldibuflen);
|
||||
# endif
|
||||
|
||||
ldibuf = alloca(ldibuflen = 8192);
|
||||
|
||||
while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
|
||||
len = loadquery(L_GETINFO, ldibuf, ldibuflen);
|
||||
if (len < 0) {
|
||||
if (errno != ENOMEM) {
|
||||
ABORT("loadquery failed");
|
||||
}
|
||||
ldibuf = alloca(ldibuflen *= 2);
|
||||
ldibuflen *= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
ldi = (struct ld_info *)ldibuf;
|
||||
|
|
@ -1210,6 +1240,8 @@ GC_INNER void GC_register_dynamic_libraries(void)
|
|||
TRUE);
|
||||
ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* AIX */
|
||||
|
||||
|
|
@ -1282,8 +1314,6 @@ STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr,
|
|||
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;
|
||||
|
|
@ -1315,9 +1345,12 @@ STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr,
|
|||
|
||||
/* Sections constructed on demand. */
|
||||
for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
|
||||
fmt = GC_dyld_add_sect_fmts[j];
|
||||
const char *fmt = GC_dyld_add_sect_fmts[j];
|
||||
|
||||
/* Add our manufactured aligned BSS sections. */
|
||||
for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
|
||||
char secnam[16];
|
||||
|
||||
(void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
|
||||
secnam[sizeof(secnam) - 1] = '\0';
|
||||
sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
|
||||
|
|
@ -1347,8 +1380,6 @@ STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
|
|||
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,
|
||||
|
|
@ -1368,8 +1399,11 @@ STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
|
|||
|
||||
/* 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];
|
||||
const char *fmt = GC_dyld_add_sect_fmts[j];
|
||||
|
||||
for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
|
||||
char secnam[16];
|
||||
|
||||
(void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
|
||||
secnam[sizeof(secnam) - 1] = '\0';
|
||||
sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
|
||||
|
|
@ -1424,12 +1458,13 @@ GC_INNER void GC_init_dyld(void)
|
|||
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);
|
||||
/* Ignore 2 compiler warnings here: passing argument 1 of */
|
||||
/* '_dyld_register_func_for_add/remove_image' from incompatible */
|
||||
/* pointer type. */
|
||||
_dyld_register_func_for_add_image(
|
||||
(void (*)(const struct mach_header*, intptr_t))GC_dyld_image_add);
|
||||
_dyld_register_func_for_remove_image(
|
||||
(void (*)(const struct mach_header*, intptr_t))GC_dyld_image_remove);
|
||||
/* Structure mach_header64 has the same fields */
|
||||
/* as mach_header except for the reserved one */
|
||||
/* at the end, so these casts are OK. */
|
||||
|
||||
/* Set this early to avoid reentrancy issues. */
|
||||
initialized = TRUE;
|
||||
|
|
@ -1465,6 +1500,21 @@ GC_INNER GC_bool GC_register_main_static_data(void)
|
|||
|
||||
#endif /* DARWIN */
|
||||
|
||||
#if defined(HAIKU)
|
||||
# include <kernel/image.h>
|
||||
|
||||
GC_INNER void GC_register_dynamic_libraries(void)
|
||||
{
|
||||
image_info info;
|
||||
int32 cookie = 0;
|
||||
|
||||
while (get_next_image_info(0, &cookie, &info) == B_OK) {
|
||||
ptr_t data = (ptr_t)info.data;
|
||||
GC_add_roots_inner(data, data + info.data_size, TRUE);
|
||||
}
|
||||
}
|
||||
#endif /* HAIKU */
|
||||
|
||||
#elif defined(PCR)
|
||||
|
||||
# include "il/PCR_IL.h"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
|
||||
#if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM)
|
||||
# include "gc_priv.h"
|
||||
# include "private/gc_priv.h"
|
||||
# include <stdio.h>
|
||||
# include <signal.h>
|
||||
# define GC_AMIGA_DEF
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
Find the base of the stack.
|
||||
******************************************************************/
|
||||
|
||||
ptr_t GC_get_main_stack_base()
|
||||
ptr_t GC_get_main_stack_base(void)
|
||||
{
|
||||
struct Process *proc = (struct Process*)SysBase->ThisTask;
|
||||
|
||||
|
|
@ -65,16 +65,13 @@ ptr_t GC_get_main_stack_base()
|
|||
Register data segments.
|
||||
******************************************************************/
|
||||
|
||||
void GC_register_data_segments()
|
||||
void GC_register_data_segments(void)
|
||||
{
|
||||
struct Process *proc;
|
||||
struct CommandLineInterface *cli;
|
||||
BPTR myseglist;
|
||||
ULONG *data;
|
||||
|
||||
int num;
|
||||
|
||||
|
||||
# ifdef __GNUC__
|
||||
ULONG dataSegSize;
|
||||
GC_bool found_segment = FALSE;
|
||||
|
|
@ -90,10 +87,9 @@ ptr_t GC_get_main_stack_base()
|
|||
|
||||
/* Reference: Amiga Guru Book Pages: 538ff,565,573
|
||||
and XOper.asm */
|
||||
myseglist = proc->pr_SegList;
|
||||
if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {
|
||||
if (proc->pr_CLI == NULL) {
|
||||
myseglist = proc->pr_SegList;
|
||||
} else {
|
||||
if (proc->pr_CLI != NULL) {
|
||||
/* ProcLoaded 'Loaded as a command: '*/
|
||||
cli = BADDR(proc->pr_CLI);
|
||||
myseglist = cli->cli_Module;
|
||||
|
|
@ -108,11 +104,11 @@ ptr_t GC_get_main_stack_base()
|
|||
|
||||
/* xoper hunks Shell Process */
|
||||
|
||||
num=0;
|
||||
for (data = (ULONG *)BADDR(myseglist); data != NULL;
|
||||
data = (ULONG *)BADDR(data[0])) {
|
||||
if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
|
||||
((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
|
||||
if ((ULONG)GC_register_data_segments < (ULONG)(&data[1])
|
||||
|| (ULONG)GC_register_data_segments > (ULONG)(&data[1])
|
||||
+ data[-1]) {
|
||||
# ifdef __GNUC__
|
||||
if (dataSegSize == data[-1]) {
|
||||
found_segment = TRUE;
|
||||
|
|
@ -121,7 +117,6 @@ ptr_t GC_get_main_stack_base()
|
|||
GC_add_roots_inner((char *)&data[1],
|
||||
((char *)&data[1]) + data[-1], FALSE);
|
||||
}
|
||||
++num;
|
||||
} /* for */
|
||||
# ifdef __GNUC__
|
||||
if (!found_segment) {
|
||||
|
|
@ -213,7 +208,6 @@ int ncur151=0;
|
|||
|
||||
void GC_amiga_free_all_mem(void){
|
||||
struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM));
|
||||
struct GC_Amiga_AllocedMemoryHeader *temp;
|
||||
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
printf("\n\n"
|
||||
|
|
@ -228,11 +222,11 @@ void GC_amiga_free_all_mem(void){
|
|||
printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects);
|
||||
printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries);
|
||||
printf("\n");
|
||||
printf("Succeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
|
||||
printf("Succeeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
|
||||
printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2);
|
||||
printf("\n");
|
||||
printf(
|
||||
"Number of retries before succeding a chip->fast force:\n"
|
||||
"Number of retries before succeeding a chip->fast force:\n"
|
||||
"0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
|
||||
cur0,cur1,cur10,cur50,cur150,cur151
|
||||
);
|
||||
|
|
@ -244,7 +238,7 @@ void GC_amiga_free_all_mem(void){
|
|||
#endif
|
||||
|
||||
while(gc_am!=NULL){
|
||||
temp=gc_am->next;
|
||||
struct GC_Amiga_AllocedMemoryHeader *temp = gc_am->next;
|
||||
FreeMem(gc_am,gc_am->size);
|
||||
gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp));
|
||||
}
|
||||
|
|
@ -267,6 +261,8 @@ size_t latestsize;
|
|||
#endif
|
||||
|
||||
|
||||
#ifdef GC_AMIGA_FASTALLOC
|
||||
|
||||
/*
|
||||
* The actual function that is called with the GET_MEM macro.
|
||||
*
|
||||
|
|
@ -277,11 +273,10 @@ void *GC_amiga_get_mem(size_t size){
|
|||
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
if(GC_amiga_dontalloc==TRUE){
|
||||
// printf("rejected, size: %d, latestsize: %d\n",size,latestsize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We really don't want to use chip-mem, but if we must, then as little as possible.
|
||||
/* We really don't want to use chip-mem, but if we must, then as little as possible. */
|
||||
if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL;
|
||||
#endif
|
||||
|
||||
|
|
@ -292,8 +287,6 @@ void *GC_amiga_get_mem(size_t size){
|
|||
gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader);
|
||||
GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am));
|
||||
|
||||
// printf("Allocated %d (%d) bytes at address: %x. Latest: %d\n",size,tot,gc_am,latestsize);
|
||||
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
if((char *)gc_am<chipmax){
|
||||
allochip+=size;
|
||||
|
|
@ -306,7 +299,7 @@ void *GC_amiga_get_mem(size_t size){
|
|||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
|
|
@ -348,7 +341,6 @@ void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const
|
|||
|
||||
if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))){
|
||||
ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1);
|
||||
// GC_free(ret2);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -362,16 +354,16 @@ void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const
|
|||
|
||||
|
||||
void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){
|
||||
void *ret,*ret2;
|
||||
void *ret;
|
||||
|
||||
GC_amiga_dontalloc=TRUE; // Pretty tough thing to do, but its indeed necessary.
|
||||
GC_amiga_dontalloc=TRUE; /* Pretty tough thing to do, but its indeed necessary. */
|
||||
latestsize=size;
|
||||
|
||||
ret=(*AllocFunction)(size);
|
||||
|
||||
if(((char *)ret) <= chipmax){
|
||||
if(ret==NULL){
|
||||
//Give GC access to allocate memory.
|
||||
/* Give GC access to allocate memory. */
|
||||
#ifdef GC_AMIGA_GC
|
||||
if(!GC_dont_gc){
|
||||
GC_gcollect();
|
||||
|
|
@ -380,8 +372,9 @@ void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)
|
|||
#endif
|
||||
ret=(*AllocFunction)(size);
|
||||
}
|
||||
if(ret==NULL)
|
||||
#endif
|
||||
if(ret==NULL){
|
||||
{
|
||||
GC_amiga_dontalloc=FALSE;
|
||||
ret=(*AllocFunction)(size);
|
||||
if(ret==NULL){
|
||||
|
|
@ -397,13 +390,13 @@ void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)
|
|||
}
|
||||
#ifdef GC_AMIGA_RETRY
|
||||
else{
|
||||
void *ret2;
|
||||
/* We got chip-mem. Better try again and again and again etc., we might get fast-mem sooner or later... */
|
||||
/* Using gctest to check the effectiveness of doing this, does seldom give a very good result. */
|
||||
/* However, real programs doesn't normally rapidly allocate and deallocate. */
|
||||
// printf("trying to force... %d bytes... ",size);
|
||||
if(
|
||||
AllocFunction!=GC_malloc_uncollectable
|
||||
#ifdef ATOMIC_UNCOLLECTABLE
|
||||
#ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
&& AllocFunction!=GC_malloc_atomic_uncollectable
|
||||
#endif
|
||||
){
|
||||
|
|
@ -423,12 +416,10 @@ void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)
|
|||
#endif
|
||||
}
|
||||
if(((char *)ret2)>chipmax){
|
||||
// printf("Succeeded.\n");
|
||||
GC_free(ret);
|
||||
ret=ret2;
|
||||
}else{
|
||||
GC_free(ret2);
|
||||
// printf("But did not succeed.\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -447,7 +438,7 @@ void GC_amiga_set_toany(void (*func)(void)){
|
|||
GC_amiga_toany=func;
|
||||
}
|
||||
|
||||
#endif // !GC_AMIGA_ONLYFAST
|
||||
#endif /* !GC_AMIGA_ONLYFAST */
|
||||
|
||||
|
||||
void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){
|
||||
|
|
@ -456,8 +447,7 @@ void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2
|
|||
ret=(*AllocFunction)(size);
|
||||
|
||||
if(ret==NULL){
|
||||
// Enable chip-mem allocation.
|
||||
// printf("ret==NULL\n");
|
||||
/* Enable chip-mem allocation. */
|
||||
#ifdef GC_AMIGA_GC
|
||||
if(!GC_dont_gc){
|
||||
GC_gcollect();
|
||||
|
|
@ -466,8 +456,9 @@ void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2
|
|||
#endif
|
||||
ret=(*AllocFunction)(size);
|
||||
}
|
||||
if(ret==NULL)
|
||||
#endif
|
||||
if(ret==NULL){
|
||||
{
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
|
||||
if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
|
||||
|
|
@ -487,13 +478,13 @@ void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2
|
|||
|
||||
void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){
|
||||
atexit(&GC_amiga_free_all_mem);
|
||||
chipmax=(char *)SysBase->MaxLocMem; // For people still having SysBase in chip-mem, this might speed up a bit.
|
||||
chipmax=(char *)SysBase->MaxLocMem; /* For people still having SysBase in chip-mem, this might speed up a bit. */
|
||||
GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast;
|
||||
return GC_amiga_allocwrapper_fast(size,AllocFunction);
|
||||
}
|
||||
|
||||
|
||||
#endif //GC_AMIGA_FASTALLOC
|
||||
#endif /* GC_AMIGA_FASTALLOC */
|
||||
|
||||
|
||||
|
||||
|
|
@ -508,7 +499,8 @@ void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
|
|||
void *ret;
|
||||
latestsize=new_size_in_bytes;
|
||||
ret=GC_realloc(old_object,new_size_in_bytes);
|
||||
if(ret==NULL && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
|
||||
if(ret==NULL && new_size_in_bytes != 0
|
||||
&& GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
|
||||
/* Out of fast-mem. */
|
||||
#ifdef GC_AMIGA_GC
|
||||
if(!GC_dont_gc){
|
||||
|
|
@ -518,8 +510,9 @@ void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
|
|||
#endif
|
||||
ret=GC_realloc(old_object,new_size_in_bytes);
|
||||
}
|
||||
if(ret==NULL)
|
||||
#endif
|
||||
if(ret==NULL){
|
||||
{
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
|
||||
if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
|
||||
|
|
@ -533,7 +526,7 @@ void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
|
|||
}
|
||||
#endif
|
||||
}
|
||||
if(ret==NULL){
|
||||
if(ret==NULL && new_size_in_bytes != 0){
|
||||
WARN("Out of Memory! Returning NIL!\n", 0);
|
||||
}
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
|
|
@ -545,4 +538,4 @@ void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
|
|||
#endif
|
||||
}
|
||||
|
||||
#endif //GC_AMIGA_AM
|
||||
#endif /* GC_AMIGA_AM */
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ unloading shared library.
|
|||
|
||||
#define GC_BUILD
|
||||
#include "gc.h"
|
||||
#include "gc_priv.h"
|
||||
#include "private/gc_priv.h"
|
||||
|
||||
// use 'CODE' resource 0 to get exact location of the beginning of global space.
|
||||
/* use 'CODE' resource 0 to get exact location of the beginning of global space. */
|
||||
|
||||
typedef struct {
|
||||
unsigned long aboveA5;
|
||||
|
|
@ -35,7 +35,7 @@ typedef struct {
|
|||
unsigned long JTOffset;
|
||||
} *CodeZeroPtr, **CodeZeroHandle;
|
||||
|
||||
void* GC_MacGetDataStart()
|
||||
void* GC_MacGetDataStart(void)
|
||||
{
|
||||
CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
|
||||
if (code0) {
|
||||
|
|
@ -48,6 +48,8 @@ void* GC_MacGetDataStart()
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_TEMPORARY_MEMORY
|
||||
|
||||
/* track the use of temporary memory so it can be freed all at once. */
|
||||
|
||||
typedef struct TemporaryMemoryBlock TemporaryMemoryBlock, **TemporaryMemoryHandle;
|
||||
|
|
@ -58,13 +60,14 @@ struct TemporaryMemoryBlock {
|
|||
};
|
||||
|
||||
static TemporaryMemoryHandle theTemporaryMemory = NULL;
|
||||
static Boolean firstTime = true;
|
||||
|
||||
void GC_MacFreeTemporaryMemory(void);
|
||||
|
||||
Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
|
||||
{
|
||||
# if !defined(SHARED_LIBRARY_BUILD)
|
||||
static Boolean firstTime = true;
|
||||
# endif
|
||||
OSErr result;
|
||||
TemporaryMemoryHandle tempMemBlock;
|
||||
Ptr tempPtr = nil;
|
||||
|
|
@ -76,13 +79,13 @@ Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
|
|||
if (clearMemory) memset(tempPtr, 0, size);
|
||||
tempPtr = StripAddress(tempPtr);
|
||||
|
||||
// keep track of the allocated blocks.
|
||||
/* keep track of the allocated blocks. */
|
||||
(**tempMemBlock).nextBlock = theTemporaryMemory;
|
||||
theTemporaryMemory = tempMemBlock;
|
||||
}
|
||||
|
||||
# if !defined(SHARED_LIBRARY_BUILD)
|
||||
// install an exit routine to clean up the memory used at the end.
|
||||
/* install an exit routine to clean up the memory used at the end. */
|
||||
if (firstTime) {
|
||||
atexit(&GC_MacFreeTemporaryMemory);
|
||||
firstTime = false;
|
||||
|
|
@ -94,7 +97,7 @@ Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
|
|||
|
||||
extern word GC_fo_entries;
|
||||
|
||||
static void perform_final_collection()
|
||||
static void perform_final_collection(void)
|
||||
{
|
||||
unsigned i;
|
||||
word last_fo_entries = 0;
|
||||
|
|
@ -111,7 +114,7 @@ static void perform_final_collection()
|
|||
}
|
||||
|
||||
|
||||
void GC_MacFreeTemporaryMemory()
|
||||
void GC_MacFreeTemporaryMemory(void)
|
||||
{
|
||||
# if defined(SHARED_LIBRARY_BUILD)
|
||||
/* if possible, collect all memory, and invoke all finalizers. */
|
||||
|
|
@ -119,11 +122,15 @@ void GC_MacFreeTemporaryMemory()
|
|||
# endif
|
||||
|
||||
if (theTemporaryMemory != NULL) {
|
||||
# if !defined(SHARED_LIBRARY_BUILD)
|
||||
long totalMemoryUsed = 0;
|
||||
# endif
|
||||
TemporaryMemoryHandle tempMemBlock = theTemporaryMemory;
|
||||
while (tempMemBlock != NULL) {
|
||||
TemporaryMemoryHandle nextBlock = (**tempMemBlock).nextBlock;
|
||||
# if !defined(SHARED_LIBRARY_BUILD)
|
||||
totalMemoryUsed += GetHandleSize((Handle)tempMemBlock);
|
||||
# endif
|
||||
DisposeHandle((Handle)tempMemBlock);
|
||||
tempMemBlock = nextBlock;
|
||||
}
|
||||
|
|
@ -132,16 +139,19 @@ void GC_MacFreeTemporaryMemory()
|
|||
# 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);
|
||||
totalMemoryUsed);
|
||||
fprintf(stdout, "[total collections: %lu]\n",
|
||||
(unsigned long)GC_gc_no);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_TEMPORARY_MEMORY */
|
||||
|
||||
#if __option(far_data)
|
||||
|
||||
void* GC_MacGetDataEnd()
|
||||
void* GC_MacGetDataEnd(void)
|
||||
{
|
||||
CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
|
||||
if (code0) {
|
||||
|
|
|
|||
|
|
@ -12,17 +12,16 @@
|
|||
/* Boehm, November 17, 1995 12:10 pm PST */
|
||||
|
||||
#ifdef __MWERKS__
|
||||
|
||||
// for CodeWarrior Pro with Metrowerks Standard Library (MSL).
|
||||
// #define MSL_USE_PRECOMPILED_HEADERS 0
|
||||
/* 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.
|
||||
/* 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.
|
||||
#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. */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
||||
* Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2018 Ivan Maidanski
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ typedef GC_word word;
|
|||
typedef ULONG ULONG_ADDR;
|
||||
#endif
|
||||
|
||||
static HANDLE GetSymHandle()
|
||||
static HANDLE GetSymHandle(void)
|
||||
{
|
||||
static HANDLE symHandle = NULL;
|
||||
if (!symHandle) {
|
||||
|
|
@ -158,8 +158,8 @@ size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread,
|
|||
#elif defined(_M_ALPHA64)
|
||||
machineType = IMAGE_FILE_MACHINE_ALPHA64;
|
||||
stackFrame.AddrPC.Offset = context->Fir;
|
||||
#else
|
||||
#error Unknown CPU
|
||||
#elif !defined(CPPCHECK)
|
||||
# error Unknown CPU
|
||||
#endif
|
||||
for (frameIndex = 0; frameIndex < maxFrames; ) {
|
||||
BOOL bRet = StackWalk(machineType, hProcess, hThread, &stackFrame,
|
||||
|
|
@ -308,7 +308,6 @@ size_t GetDescriptionFromAddress(void* address, const char* format,
|
|||
char*const begin = buffer;
|
||||
char*const end = buffer + size;
|
||||
size_t line_number = 0;
|
||||
char str[128];
|
||||
|
||||
if (size) {
|
||||
*buffer = 0;
|
||||
|
|
@ -317,7 +316,9 @@ size_t GetDescriptionFromAddress(void* address, const char* format,
|
|||
size = (GC_ULONG_PTR)end < (GC_ULONG_PTR)buffer ? 0 : end - buffer;
|
||||
|
||||
if (line_number) {
|
||||
wsprintf(str, "(%d) : ", line_number);
|
||||
char str[128];
|
||||
|
||||
wsprintf(str, "(%d) : ", (int)line_number);
|
||||
if (size) {
|
||||
strncpy(buffer, str, size)[size - 1] = 0;
|
||||
}
|
||||
|
|
@ -341,8 +342,6 @@ size_t GetDescriptionFromAddress(void* address, const char* format,
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -354,12 +353,15 @@ size_t GetDescriptionFromStack(void* const frames[], size_t count,
|
|||
char*const end = begin + size;
|
||||
char* buffer = begin + (count + 1) * sizeof(char*);
|
||||
size_t i;
|
||||
(void)format;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (description) description[i] = buffer;
|
||||
if (size)
|
||||
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;
|
||||
if (size)
|
||||
description[count] = NULL;
|
||||
return buffer - begin;
|
||||
}
|
||||
|
||||
|
|
@ -374,8 +376,14 @@ 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);
|
||||
if (symbols != NULL)
|
||||
GetDescriptionFromStack(addresses, count, NULL, symbols, size);
|
||||
return symbols;
|
||||
}
|
||||
|
||||
#endif /* !_M_AMD64 */
|
||||
#else
|
||||
|
||||
extern int GC_quiet;
|
||||
/* ANSI C does not allow translation units to be empty. */
|
||||
|
||||
#endif /* _M_AMD64 */
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ char* GC_get_private_path_and_zero_file()
|
|||
|
||||
size_t size = path8.Length() + 1;
|
||||
char* copyChar = (char*) malloc( size );
|
||||
memcpy( copyChar, path8.PtrZ(), size );
|
||||
if (copyChar)
|
||||
memcpy( copyChar, path8.PtrZ(), size );
|
||||
|
||||
return copyChar; // ownership passed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ 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)
|
||||
#define HASH2(addr,log_size) HASH3(addr, (word)1 << (log_size), log_size)
|
||||
|
||||
struct hash_chain_entry {
|
||||
word hidden_key;
|
||||
|
|
@ -55,7 +55,7 @@ STATIC struct dl_hashtbl_s GC_dl_hashtbl = {
|
|||
STATIC struct dl_hashtbl_s GC_ll_hashtbl = { NULL, -1, 0 };
|
||||
#endif
|
||||
|
||||
STATIC struct finalizable_object {
|
||||
struct finalizable_object {
|
||||
struct hash_chain_entry prolog;
|
||||
# define fo_hidden_base prolog.hidden_key
|
||||
/* Pointer to object base. */
|
||||
|
|
@ -67,50 +67,68 @@ STATIC struct finalizable_object {
|
|||
ptr_t fo_client_data;
|
||||
word fo_object_size; /* In bytes. */
|
||||
finalization_mark_proc fo_mark_proc; /* Mark-through procedure */
|
||||
} **GC_fo_head = 0;
|
||||
|
||||
STATIC struct finalizable_object * GC_finalize_now = 0;
|
||||
/* List of objects that should be finalized now. */
|
||||
};
|
||||
|
||||
static signed_word log_fo_table_size = -1;
|
||||
|
||||
GC_INNER void GC_push_finalizer_structures(void)
|
||||
STATIC struct {
|
||||
struct finalizable_object **fo_head;
|
||||
/* List of objects that should be finalized now: */
|
||||
struct finalizable_object *finalize_now;
|
||||
} GC_fnlz_roots = { NULL, NULL };
|
||||
|
||||
GC_API void GC_CALL GC_push_finalizer_structures(void)
|
||||
{
|
||||
GC_ASSERT((word)&GC_dl_hashtbl.head % sizeof(word) == 0);
|
||||
GC_ASSERT((word)&GC_fo_head % sizeof(word) == 0);
|
||||
GC_ASSERT((word)&GC_finalize_now % sizeof(word) == 0);
|
||||
|
||||
GC_ASSERT((word)(&GC_dl_hashtbl.head) % sizeof(word) == 0);
|
||||
GC_ASSERT((word)(&GC_fnlz_roots) % sizeof(word) == 0);
|
||||
# ifndef GC_LONG_REFS_NOT_NEEDED
|
||||
GC_ASSERT((word)&GC_ll_hashtbl.head % sizeof(word) == 0);
|
||||
GC_push_all((ptr_t)(&GC_ll_hashtbl.head),
|
||||
(ptr_t)(&GC_ll_hashtbl.head) + sizeof(word));
|
||||
GC_ASSERT((word)(&GC_ll_hashtbl.head) % sizeof(word) == 0);
|
||||
GC_PUSH_ALL_SYM(GC_ll_hashtbl.head);
|
||||
# endif
|
||||
|
||||
GC_push_all((ptr_t)(&GC_dl_hashtbl.head),
|
||||
(ptr_t)(&GC_dl_hashtbl.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));
|
||||
GC_PUSH_ALL_SYM(GC_dl_hashtbl.head);
|
||||
GC_PUSH_ALL_SYM(GC_fnlz_roots);
|
||||
}
|
||||
|
||||
/* Double the size of a hash table. *size_ptr is the log of its current */
|
||||
/* size. May be a no-op. */
|
||||
/* Threshold of log_size to initiate full collection before growing */
|
||||
/* a hash table. */
|
||||
#ifndef GC_ON_GROW_LOG_SIZE_MIN
|
||||
# define GC_ON_GROW_LOG_SIZE_MIN CPP_LOG_HBLKSIZE
|
||||
#endif
|
||||
|
||||
/* Double the size of a hash table. *log_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)
|
||||
signed_word *log_size_ptr, word *entries_ptr)
|
||||
{
|
||||
register word i;
|
||||
register struct hash_chain_entry *p;
|
||||
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));
|
||||
word old_size = log_old_size == -1 ? 0 : (word)1 << log_old_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);
|
||||
struct hash_chain_entry **new_table;
|
||||
|
||||
GC_ASSERT(I_HOLD_LOCK());
|
||||
/* Avoid growing the table in case of at least 25% of entries can */
|
||||
/* be deleted by enforcing a collection. Ignored for small tables. */
|
||||
if (log_old_size >= GC_ON_GROW_LOG_SIZE_MIN) {
|
||||
IF_CANCEL(int cancel_state;)
|
||||
|
||||
DISABLE_CANCEL(cancel_state);
|
||||
(void)GC_try_to_collect_inner(GC_never_stop_func);
|
||||
RESTORE_CANCEL(cancel_state);
|
||||
/* GC_finalize might decrease entries value. */
|
||||
if (*entries_ptr < ((word)1 << log_old_size) - (*entries_ptr >> 2))
|
||||
return;
|
||||
}
|
||||
|
||||
new_table = (struct hash_chain_entry **)
|
||||
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");
|
||||
|
|
@ -126,12 +144,14 @@ STATIC void GC_grow_table(struct hash_chain_entry ***table,
|
|||
size_t new_hash = HASH3(real_key, new_size, log_new_size);
|
||||
|
||||
p -> next = new_table[new_hash];
|
||||
GC_dirty(p);
|
||||
new_table[new_hash] = p;
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
*log_size_ptr = log_new_size;
|
||||
*table = new_table;
|
||||
GC_dirty(new_table); /* entire object */
|
||||
}
|
||||
|
||||
GC_API int GC_CALL GC_register_disappearing_link(void * * link)
|
||||
|
|
@ -146,20 +166,24 @@ GC_API int GC_CALL GC_register_disappearing_link(void * * link)
|
|||
|
||||
STATIC int GC_register_disappearing_link_inner(
|
||||
struct dl_hashtbl_s *dl_hashtbl, void **link,
|
||||
const void *obj)
|
||||
const void *obj, const char *tbl_log_name)
|
||||
{
|
||||
struct disappearing_link *curr_dl;
|
||||
size_t index;
|
||||
struct disappearing_link * new_dl;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
if (EXPECT(GC_find_leak, FALSE)) return GC_UNIMPLEMENTED;
|
||||
LOCK();
|
||||
GC_ASSERT(obj != NULL && GC_base_C(obj) == obj);
|
||||
if (dl_hashtbl -> log_size == -1
|
||||
|| dl_hashtbl -> entries > ((word)1 << dl_hashtbl -> log_size)) {
|
||||
GC_grow_table((struct hash_chain_entry ***)&dl_hashtbl -> head,
|
||||
&dl_hashtbl -> log_size);
|
||||
GC_COND_LOG_PRINTF("Grew dl table to %u entries\n",
|
||||
&dl_hashtbl -> log_size, &dl_hashtbl -> entries);
|
||||
# ifdef LINT2
|
||||
if (dl_hashtbl->log_size < 0) ABORT("log_size is negative");
|
||||
# endif
|
||||
GC_COND_LOG_PRINTF("Grew %s table to %u entries\n", tbl_log_name,
|
||||
1 << (unsigned)dl_hashtbl -> log_size);
|
||||
}
|
||||
index = HASH2(link, dl_hashtbl -> log_size);
|
||||
|
|
@ -202,8 +226,10 @@ STATIC int GC_register_disappearing_link_inner(
|
|||
new_dl -> dl_hidden_obj = GC_HIDE_POINTER(obj);
|
||||
new_dl -> dl_hidden_link = GC_HIDE_POINTER(link);
|
||||
dl_set_next(new_dl, dl_hashtbl -> head[index]);
|
||||
GC_dirty(new_dl);
|
||||
dl_hashtbl -> head[index] = new_dl;
|
||||
dl_hashtbl -> entries++;
|
||||
GC_dirty(dl_hashtbl->head + index);
|
||||
UNLOCK();
|
||||
return GC_SUCCESS;
|
||||
}
|
||||
|
|
@ -211,9 +237,10 @@ STATIC int GC_register_disappearing_link_inner(
|
|||
GC_API int GC_CALL GC_general_register_disappearing_link(void * * link,
|
||||
const void * obj)
|
||||
{
|
||||
if (((word)link & (ALIGNMENT-1)) != 0 || NULL == link)
|
||||
if (((word)link & (ALIGNMENT-1)) != 0 || !NONNULL_ARG_NOT_NULL(link))
|
||||
ABORT("Bad arg to GC_general_register_disappearing_link");
|
||||
return GC_register_disappearing_link_inner(&GC_dl_hashtbl, link, obj);
|
||||
return GC_register_disappearing_link_inner(&GC_dl_hashtbl, link, obj,
|
||||
"dl");
|
||||
}
|
||||
|
||||
#ifdef DBG_HDRS_ALL
|
||||
|
|
@ -229,16 +256,22 @@ GC_INLINE struct disappearing_link *GC_unregister_disappearing_link_inner(
|
|||
{
|
||||
struct disappearing_link *curr_dl;
|
||||
struct disappearing_link *prev_dl = NULL;
|
||||
size_t index = HASH2(link, dl_hashtbl->log_size);
|
||||
size_t index;
|
||||
|
||||
if (dl_hashtbl->log_size == -1)
|
||||
return NULL; /* prevent integer shift by a negative amount */
|
||||
|
||||
index = HASH2(link, dl_hashtbl->log_size);
|
||||
for (curr_dl = dl_hashtbl -> head[index]; curr_dl;
|
||||
curr_dl = dl_next(curr_dl)) {
|
||||
if (curr_dl -> dl_hidden_link == GC_HIDE_POINTER(link)) {
|
||||
/* Remove found entry from the table. */
|
||||
if (NULL == prev_dl) {
|
||||
dl_hashtbl -> head[index] = dl_next(curr_dl);
|
||||
GC_dirty(dl_hashtbl->head + index);
|
||||
} else {
|
||||
dl_set_next(prev_dl, dl_next(curr_dl));
|
||||
GC_dirty(prev_dl);
|
||||
}
|
||||
dl_hashtbl -> entries--;
|
||||
break;
|
||||
|
|
@ -263,12 +296,213 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Toggle-ref support. */
|
||||
#ifndef GC_TOGGLE_REFS_NOT_NEEDED
|
||||
typedef union {
|
||||
/* Lowest bit is used to distinguish between choices. */
|
||||
void *strong_ref;
|
||||
GC_hidden_pointer weak_ref;
|
||||
} GCToggleRef;
|
||||
|
||||
STATIC GC_toggleref_func GC_toggleref_callback = 0;
|
||||
STATIC GCToggleRef *GC_toggleref_arr = NULL;
|
||||
STATIC int GC_toggleref_array_size = 0;
|
||||
STATIC int GC_toggleref_array_capacity = 0;
|
||||
|
||||
GC_INNER void GC_process_togglerefs(void)
|
||||
{
|
||||
int i;
|
||||
int new_size = 0;
|
||||
GC_bool needs_barrier = FALSE;
|
||||
|
||||
GC_ASSERT(I_HOLD_LOCK());
|
||||
for (i = 0; i < GC_toggleref_array_size; ++i) {
|
||||
GCToggleRef r = GC_toggleref_arr[i];
|
||||
void *obj = r.strong_ref;
|
||||
|
||||
if (((word)obj & 1) != 0) {
|
||||
obj = GC_REVEAL_POINTER(r.weak_ref);
|
||||
}
|
||||
if (NULL == obj) {
|
||||
continue;
|
||||
}
|
||||
switch (GC_toggleref_callback(obj)) {
|
||||
case GC_TOGGLE_REF_DROP:
|
||||
break;
|
||||
case GC_TOGGLE_REF_STRONG:
|
||||
GC_toggleref_arr[new_size++].strong_ref = obj;
|
||||
needs_barrier = TRUE;
|
||||
break;
|
||||
case GC_TOGGLE_REF_WEAK:
|
||||
GC_toggleref_arr[new_size++].weak_ref = GC_HIDE_POINTER(obj);
|
||||
break;
|
||||
default:
|
||||
ABORT("Bad toggle-ref status returned by callback");
|
||||
}
|
||||
}
|
||||
|
||||
if (new_size < GC_toggleref_array_size) {
|
||||
BZERO(&GC_toggleref_arr[new_size],
|
||||
(GC_toggleref_array_size - new_size) * sizeof(GCToggleRef));
|
||||
GC_toggleref_array_size = new_size;
|
||||
}
|
||||
if (needs_barrier)
|
||||
GC_dirty(GC_toggleref_arr); /* entire object */
|
||||
}
|
||||
|
||||
STATIC void GC_normal_finalize_mark_proc(ptr_t);
|
||||
|
||||
static void push_and_mark_object(void *p)
|
||||
{
|
||||
GC_normal_finalize_mark_proc(p);
|
||||
while (!GC_mark_stack_empty()) {
|
||||
MARK_FROM_MARK_STACK();
|
||||
}
|
||||
GC_set_mark_bit(p);
|
||||
if (GC_mark_state != MS_NONE) {
|
||||
while (!GC_mark_some(0)) {
|
||||
/* Empty. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void GC_mark_togglerefs(void)
|
||||
{
|
||||
int i;
|
||||
if (NULL == GC_toggleref_arr)
|
||||
return;
|
||||
|
||||
/* TODO: Hide GC_toggleref_arr to avoid its marking from roots. */
|
||||
GC_set_mark_bit(GC_toggleref_arr);
|
||||
for (i = 0; i < GC_toggleref_array_size; ++i) {
|
||||
void *obj = GC_toggleref_arr[i].strong_ref;
|
||||
if (obj != NULL && ((word)obj & 1) == 0) {
|
||||
push_and_mark_object(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void GC_clear_togglerefs(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < GC_toggleref_array_size; ++i) {
|
||||
if ((GC_toggleref_arr[i].weak_ref & 1) != 0) {
|
||||
if (!GC_is_marked(GC_REVEAL_POINTER(GC_toggleref_arr[i].weak_ref))) {
|
||||
GC_toggleref_arr[i].weak_ref = 0;
|
||||
} else {
|
||||
/* No need to copy, BDWGC is a non-moving collector. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func fn)
|
||||
{
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
LOCK();
|
||||
GC_toggleref_callback = fn;
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void)
|
||||
{
|
||||
GC_toggleref_func fn;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
LOCK();
|
||||
fn = GC_toggleref_callback;
|
||||
UNLOCK();
|
||||
return fn;
|
||||
}
|
||||
|
||||
static GC_bool ensure_toggleref_capacity(int capacity_inc)
|
||||
{
|
||||
GC_ASSERT(capacity_inc >= 0);
|
||||
if (NULL == GC_toggleref_arr) {
|
||||
GC_toggleref_array_capacity = 32; /* initial capacity */
|
||||
GC_toggleref_arr = GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
|
||||
GC_toggleref_array_capacity * sizeof(GCToggleRef),
|
||||
NORMAL);
|
||||
if (NULL == GC_toggleref_arr)
|
||||
return FALSE;
|
||||
}
|
||||
if ((unsigned)GC_toggleref_array_size + (unsigned)capacity_inc
|
||||
>= (unsigned)GC_toggleref_array_capacity) {
|
||||
GCToggleRef *new_array;
|
||||
while ((unsigned)GC_toggleref_array_capacity
|
||||
< (unsigned)GC_toggleref_array_size + (unsigned)capacity_inc) {
|
||||
GC_toggleref_array_capacity *= 2;
|
||||
if (GC_toggleref_array_capacity < 0) /* overflow */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
new_array = GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
|
||||
GC_toggleref_array_capacity * sizeof(GCToggleRef),
|
||||
NORMAL);
|
||||
if (NULL == new_array)
|
||||
return FALSE;
|
||||
BCOPY(GC_toggleref_arr, new_array,
|
||||
GC_toggleref_array_size * sizeof(GCToggleRef));
|
||||
GC_INTERNAL_FREE(GC_toggleref_arr);
|
||||
GC_toggleref_arr = new_array;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GC_API int GC_CALL GC_toggleref_add(void *obj, int is_strong_ref)
|
||||
{
|
||||
int res = GC_SUCCESS;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
GC_ASSERT(NONNULL_ARG_NOT_NULL(obj));
|
||||
LOCK();
|
||||
if (GC_toggleref_callback != 0) {
|
||||
if (!ensure_toggleref_capacity(1)) {
|
||||
res = GC_NO_MEMORY;
|
||||
} else {
|
||||
GC_toggleref_arr[GC_toggleref_array_size].strong_ref =
|
||||
is_strong_ref ? obj : (void *)GC_HIDE_POINTER(obj);
|
||||
if (is_strong_ref)
|
||||
GC_dirty(GC_toggleref_arr + GC_toggleref_array_size);
|
||||
GC_toggleref_array_size++;
|
||||
}
|
||||
}
|
||||
UNLOCK();
|
||||
return res;
|
||||
}
|
||||
#endif /* !GC_TOGGLE_REFS_NOT_NEEDED */
|
||||
|
||||
/* Finalizer callback support. */
|
||||
STATIC GC_await_finalize_proc GC_object_finalized_proc = 0;
|
||||
|
||||
GC_API void GC_CALL GC_set_await_finalize_proc(GC_await_finalize_proc fn)
|
||||
{
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
LOCK();
|
||||
GC_object_finalized_proc = fn;
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
|
||||
{
|
||||
GC_await_finalize_proc fn;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
LOCK();
|
||||
fn = GC_object_finalized_proc;
|
||||
UNLOCK();
|
||||
return fn;
|
||||
}
|
||||
|
||||
#ifndef GC_LONG_REFS_NOT_NEEDED
|
||||
GC_API int GC_CALL GC_register_long_link(void * * link, const void * obj)
|
||||
{
|
||||
if (((word)link & (ALIGNMENT-1)) != 0 || NULL == link)
|
||||
if (((word)link & (ALIGNMENT-1)) != 0 || !NONNULL_ARG_NOT_NULL(link))
|
||||
ABORT("Bad arg to GC_register_long_link");
|
||||
return GC_register_disappearing_link_inner(&GC_ll_hashtbl, link, obj);
|
||||
return GC_register_disappearing_link_inner(&GC_ll_hashtbl, link, obj,
|
||||
"long dl");
|
||||
}
|
||||
|
||||
GC_API int GC_CALL GC_unregister_long_link(void * * link)
|
||||
|
|
@ -298,6 +532,9 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
|||
word curr_hidden_link;
|
||||
word new_hidden_link;
|
||||
|
||||
if (dl_hashtbl->log_size == -1)
|
||||
return GC_NOT_FOUND; /* prevent integer shift by a negative amount */
|
||||
|
||||
/* Find current link. */
|
||||
curr_index = HASH2(link, dl_hashtbl -> log_size);
|
||||
curr_hidden_link = GC_HIDE_POINTER(link);
|
||||
|
|
@ -333,10 +570,13 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
|||
dl_hashtbl -> head[curr_index] = dl_next(curr_dl);
|
||||
} else {
|
||||
dl_set_next(prev_dl, dl_next(curr_dl));
|
||||
GC_dirty(prev_dl);
|
||||
}
|
||||
curr_dl -> dl_hidden_link = new_hidden_link;
|
||||
dl_set_next(curr_dl, dl_hashtbl -> head[new_index]);
|
||||
dl_hashtbl -> head[new_index] = curr_dl;
|
||||
GC_dirty(curr_dl);
|
||||
GC_dirty(dl_hashtbl->head); /* entire object */
|
||||
return GC_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +585,8 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
|||
int result;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
if (((word)new_link & (ALIGNMENT-1)) != 0 || new_link == NULL)
|
||||
if (((word)new_link & (ALIGNMENT-1)) != 0
|
||||
|| !NONNULL_ARG_NOT_NULL(new_link))
|
||||
ABORT("Bad new_link arg to GC_move_disappearing_link");
|
||||
if (((word)link & (ALIGNMENT-1)) != 0)
|
||||
return GC_NOT_FOUND; /* Nothing to do. */
|
||||
|
|
@ -362,8 +603,9 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
|
|||
int result;
|
||||
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)new_link & (ALIGNMENT-1)) != 0
|
||||
|| !NONNULL_ARG_NOT_NULL(new_link))
|
||||
ABORT("Bad new_link arg to GC_move_long_link");
|
||||
if (((word)link & (ALIGNMENT-1)) != 0)
|
||||
return GC_NOT_FOUND; /* Nothing to do. */
|
||||
|
||||
|
|
@ -393,7 +635,6 @@ STATIC void GC_ignore_self_finalize_mark_proc(ptr_t p)
|
|||
hdr * hhdr = HDR(p);
|
||||
word descr = hhdr -> hb_descr;
|
||||
ptr_t q;
|
||||
word r;
|
||||
ptr_t scan_limit;
|
||||
ptr_t target_limit = p + hhdr -> hb_sz - 1;
|
||||
|
||||
|
|
@ -403,7 +644,8 @@ STATIC void GC_ignore_self_finalize_mark_proc(ptr_t p)
|
|||
scan_limit = target_limit + 1 - sizeof(word);
|
||||
}
|
||||
for (q = p; (word)q <= (word)scan_limit; q += ALIGNMENT) {
|
||||
r = *(word *)q;
|
||||
word r = *(word *)q;
|
||||
|
||||
if (r < (word)p || r > (word)target_limit) {
|
||||
GC_PUSH_ONE_HEAP(r, q, GC_mark_stack_top);
|
||||
}
|
||||
|
|
@ -435,41 +677,45 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|||
GC_finalization_proc *ofn, void **ocd,
|
||||
finalization_mark_proc mp)
|
||||
{
|
||||
ptr_t base;
|
||||
struct finalizable_object * curr_fo, * prev_fo;
|
||||
struct finalizable_object * curr_fo;
|
||||
size_t index;
|
||||
struct finalizable_object *new_fo = 0;
|
||||
hdr *hhdr = NULL; /* initialized to prevent warning. */
|
||||
GC_oom_func oom_fn;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
if (EXPECT(GC_find_leak, FALSE)) return;
|
||||
LOCK();
|
||||
if (log_fo_table_size == -1
|
||||
|| GC_fo_entries > ((word)1 << log_fo_table_size)) {
|
||||
GC_grow_table((struct hash_chain_entry ***)&GC_fo_head,
|
||||
&log_fo_table_size);
|
||||
GC_grow_table((struct hash_chain_entry ***)&GC_fnlz_roots.fo_head,
|
||||
&log_fo_table_size, &GC_fo_entries);
|
||||
# ifdef LINT2
|
||||
if (log_fo_table_size < 0) ABORT("log_size is negative");
|
||||
# endif
|
||||
GC_COND_LOG_PRINTF("Grew fo table to %u entries\n",
|
||||
1 << (unsigned)log_fo_table_size);
|
||||
}
|
||||
/* in the THREADS case we hold allocation lock. */
|
||||
base = (ptr_t)obj;
|
||||
for (;;) {
|
||||
index = HASH2(base, log_fo_table_size);
|
||||
prev_fo = 0;
|
||||
curr_fo = GC_fo_head[index];
|
||||
struct finalizable_object *prev_fo = NULL;
|
||||
GC_oom_func oom_fn;
|
||||
|
||||
index = HASH2(obj, log_fo_table_size);
|
||||
curr_fo = GC_fnlz_roots.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)) {
|
||||
if (curr_fo -> fo_hidden_base == GC_HIDE_POINTER(obj)) {
|
||||
/* 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. */
|
||||
/* Delete the structure for obj. */
|
||||
if (prev_fo == 0) {
|
||||
GC_fo_head[index] = fo_next(curr_fo);
|
||||
GC_fnlz_roots.fo_head[index] = fo_next(curr_fo);
|
||||
} else {
|
||||
fo_set_next(prev_fo, fo_next(curr_fo));
|
||||
GC_dirty(prev_fo);
|
||||
}
|
||||
if (fn == 0) {
|
||||
GC_fo_entries--;
|
||||
|
|
@ -483,14 +729,18 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|||
curr_fo -> fo_fn = fn;
|
||||
curr_fo -> fo_client_data = (ptr_t)cd;
|
||||
curr_fo -> fo_mark_proc = mp;
|
||||
GC_dirty(curr_fo);
|
||||
/* 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;
|
||||
GC_fnlz_roots.fo_head[index] = curr_fo;
|
||||
} else {
|
||||
fo_set_next(prev_fo, curr_fo);
|
||||
GC_dirty(prev_fo);
|
||||
}
|
||||
}
|
||||
if (NULL == prev_fo)
|
||||
GC_dirty(GC_fnlz_roots.fo_head + index);
|
||||
UNLOCK();
|
||||
# ifndef DBG_HDRS_ALL
|
||||
if (EXPECT(new_fo != 0, FALSE)) {
|
||||
|
|
@ -504,7 +754,11 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|||
curr_fo = fo_next(curr_fo);
|
||||
}
|
||||
if (EXPECT(new_fo != 0, FALSE)) {
|
||||
/* new_fo is returned by GC_oom_fn(), so fn != 0 and hhdr != 0. */
|
||||
/* new_fo is returned by GC_oom_fn(). */
|
||||
GC_ASSERT(fn != 0);
|
||||
# ifdef LINT2
|
||||
if (NULL == hhdr) ABORT("Bad hhdr in GC_register_finalizer_inner");
|
||||
# endif
|
||||
break;
|
||||
}
|
||||
if (fn == 0) {
|
||||
|
|
@ -513,7 +767,7 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|||
UNLOCK();
|
||||
return;
|
||||
}
|
||||
GET_HDR(base, hhdr);
|
||||
GET_HDR(obj, hhdr);
|
||||
if (EXPECT(0 == hhdr, FALSE)) {
|
||||
/* We won't collect it, hence finalizer wouldn't be run. */
|
||||
if (ocd) *ocd = 0;
|
||||
|
|
@ -541,14 +795,16 @@ STATIC void GC_register_finalizer_inner(void * obj,
|
|||
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_hidden_base = GC_HIDE_POINTER(obj);
|
||||
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, GC_fo_head[index]);
|
||||
fo_set_next(new_fo, GC_fnlz_roots.fo_head[index]);
|
||||
GC_dirty(new_fo);
|
||||
GC_fo_entries++;
|
||||
GC_fo_head[index] = new_fo;
|
||||
GC_fnlz_roots.fo_head[index] = new_fo;
|
||||
GC_dirty(GC_fnlz_roots.fo_head + index);
|
||||
UNLOCK();
|
||||
}
|
||||
|
||||
|
|
@ -593,27 +849,29 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
|||
STATIC void GC_dump_finalization_links(
|
||||
const struct dl_hashtbl_s *dl_hashtbl)
|
||||
{
|
||||
struct disappearing_link *curr_dl;
|
||||
ptr_t real_ptr, real_link;
|
||||
size_t dl_size = dl_hashtbl->log_size == -1 ? 0 :
|
||||
1 << dl_hashtbl->log_size;
|
||||
(size_t)1 << dl_hashtbl->log_size;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < dl_size; i++) {
|
||||
struct disappearing_link *curr_dl;
|
||||
|
||||
for (curr_dl = dl_hashtbl -> 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);
|
||||
ptr_t real_ptr = GC_REVEAL_POINTER(curr_dl -> dl_hidden_obj);
|
||||
ptr_t real_link = GC_REVEAL_POINTER(curr_dl -> dl_hidden_link);
|
||||
|
||||
GC_printf("Object: %p, link: %p\n",
|
||||
(void *)real_ptr, (void *)real_link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GC_dump_finalization(void)
|
||||
GC_API void GC_CALL GC_dump_finalization(void)
|
||||
{
|
||||
struct finalizable_object * curr_fo;
|
||||
size_t fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size;
|
||||
ptr_t real_ptr;
|
||||
size_t fo_size = log_fo_table_size == -1 ? 0 :
|
||||
(size_t)1 << log_fo_table_size;
|
||||
size_t i;
|
||||
|
||||
GC_printf("Disappearing (short) links:\n");
|
||||
|
|
@ -624,10 +882,11 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
|||
# endif
|
||||
GC_printf("Finalizers:\n");
|
||||
for (i = 0; i < fo_size; i++) {
|
||||
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);
|
||||
for (curr_fo = GC_fnlz_roots.fo_head[i];
|
||||
curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
|
||||
ptr_t real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
||||
|
||||
GC_printf("Finalizable object: %p\n", (void *)real_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -672,10 +931,11 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
|||
{ \
|
||||
size_t i; \
|
||||
size_t dl_size = dl_hashtbl->log_size == -1 ? 0 : \
|
||||
1 << dl_hashtbl->log_size; \
|
||||
(size_t)1 << dl_hashtbl->log_size; \
|
||||
GC_bool needs_barrier = FALSE; \
|
||||
for (i = 0; i < dl_size; i++) { \
|
||||
struct disappearing_link *prev_dl = NULL; \
|
||||
curr_dl = dl_hashtbl -> head[i]; \
|
||||
prev_dl = NULL; \
|
||||
while (curr_dl) {
|
||||
|
||||
#define ITERATE_DL_HASHTBL_END(curr_dl, prev_dl) \
|
||||
|
|
@ -683,6 +943,8 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
|||
curr_dl = dl_next(curr_dl); \
|
||||
} \
|
||||
} \
|
||||
if (needs_barrier) \
|
||||
GC_dirty(dl_hashtbl -> head); /* entire object */ \
|
||||
}
|
||||
|
||||
#define DELETE_DL_HASHTBL_ENTRY(dl_hashtbl, curr_dl, prev_dl, next_dl) \
|
||||
|
|
@ -690,8 +952,10 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
|||
next_dl = dl_next(curr_dl); \
|
||||
if (NULL == prev_dl) { \
|
||||
dl_hashtbl -> head[i] = next_dl; \
|
||||
needs_barrier = TRUE; \
|
||||
} else { \
|
||||
dl_set_next(prev_dl, next_dl); \
|
||||
GC_dirty(prev_dl); \
|
||||
} \
|
||||
GC_clear_mark_bit(curr_dl); \
|
||||
dl_hashtbl -> entries--; \
|
||||
|
|
@ -702,15 +966,14 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
|
|||
GC_INLINE void GC_make_disappearing_links_disappear(
|
||||
struct dl_hashtbl_s* dl_hashtbl)
|
||||
{
|
||||
struct disappearing_link *curr, *prev, *next;
|
||||
ptr_t real_ptr, real_link;
|
||||
struct disappearing_link *curr, *next;
|
||||
|
||||
ITERATE_DL_HASHTBL_BEGIN(dl_hashtbl, curr, prev)
|
||||
real_ptr = GC_REVEAL_POINTER(curr -> dl_hidden_obj);
|
||||
real_link = GC_REVEAL_POINTER(curr -> dl_hidden_link);
|
||||
ptr_t real_ptr = GC_REVEAL_POINTER(curr -> dl_hidden_obj);
|
||||
ptr_t real_link = GC_REVEAL_POINTER(curr -> dl_hidden_link);
|
||||
|
||||
if (!GC_is_marked(real_ptr)) {
|
||||
*(word *)real_link = 0;
|
||||
GC_clear_mark_bit(curr);
|
||||
DELETE_DL_HASHTBL_ENTRY(dl_hashtbl, curr, prev, next);
|
||||
}
|
||||
ITERATE_DL_HASHTBL_END(curr, prev)
|
||||
|
|
@ -719,13 +982,12 @@ GC_INLINE void GC_make_disappearing_links_disappear(
|
|||
GC_INLINE void GC_remove_dangling_disappearing_links(
|
||||
struct dl_hashtbl_s* dl_hashtbl)
|
||||
{
|
||||
struct disappearing_link *curr, *prev, *next;
|
||||
ptr_t real_link;
|
||||
struct disappearing_link *curr, *next;
|
||||
|
||||
ITERATE_DL_HASHTBL_BEGIN(dl_hashtbl, curr, prev)
|
||||
real_link = GC_base(GC_REVEAL_POINTER(curr -> dl_hidden_link));
|
||||
ptr_t real_link = GC_base(GC_REVEAL_POINTER(curr -> dl_hidden_link));
|
||||
|
||||
if (NULL != real_link && !GC_is_marked(real_link)) {
|
||||
GC_clear_mark_bit(curr);
|
||||
DELETE_DL_HASHTBL_ENTRY(dl_hashtbl, curr, prev, next);
|
||||
}
|
||||
ITERATE_DL_HASHTBL_END(curr, prev)
|
||||
|
|
@ -739,7 +1001,9 @@ GC_INNER void GC_finalize(void)
|
|||
struct finalizable_object * curr_fo, * prev_fo, * next_fo;
|
||||
ptr_t real_ptr;
|
||||
size_t i;
|
||||
size_t fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size;
|
||||
size_t fo_size = log_fo_table_size == -1 ? 0 :
|
||||
(size_t)1 << log_fo_table_size;
|
||||
GC_bool needs_barrier = FALSE;
|
||||
|
||||
# ifndef SMALL_CONFIG
|
||||
/* Save current GC_[dl/ll]_entries value for stats printing */
|
||||
|
|
@ -749,14 +1013,17 @@ GC_INNER void GC_finalize(void)
|
|||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef GC_TOGGLE_REFS_NOT_NEEDED
|
||||
GC_mark_togglerefs();
|
||||
# endif
|
||||
GC_make_disappearing_links_disappear(&GC_dl_hashtbl);
|
||||
|
||||
/* 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 = GC_fo_head[i]; curr_fo != 0;
|
||||
curr_fo = fo_next(curr_fo)) {
|
||||
for (curr_fo = GC_fnlz_roots.fo_head[i];
|
||||
curr_fo != NULL; 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)) {
|
||||
|
|
@ -772,7 +1039,7 @@ GC_INNER void GC_finalize(void)
|
|||
/* unreachable. */
|
||||
GC_bytes_finalized = 0;
|
||||
for (i = 0; i < fo_size; i++) {
|
||||
curr_fo = GC_fo_head[i];
|
||||
curr_fo = GC_fnlz_roots.fo_head[i];
|
||||
prev_fo = 0;
|
||||
while (curr_fo != 0) {
|
||||
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
||||
|
|
@ -782,15 +1049,25 @@ GC_INNER void GC_finalize(void)
|
|||
}
|
||||
/* Delete from hash table */
|
||||
next_fo = fo_next(curr_fo);
|
||||
if (prev_fo == 0) {
|
||||
GC_fo_head[i] = next_fo;
|
||||
if (NULL == prev_fo) {
|
||||
GC_fnlz_roots.fo_head[i] = next_fo;
|
||||
if (GC_object_finalized_proc) {
|
||||
GC_dirty(GC_fnlz_roots.fo_head + i);
|
||||
} else {
|
||||
needs_barrier = TRUE;
|
||||
}
|
||||
} else {
|
||||
fo_set_next(prev_fo, next_fo);
|
||||
GC_dirty(prev_fo);
|
||||
}
|
||||
GC_fo_entries--;
|
||||
if (GC_object_finalized_proc)
|
||||
GC_object_finalized_proc(real_ptr);
|
||||
|
||||
/* Add to list of objects awaiting finalization. */
|
||||
fo_set_next(curr_fo, GC_finalize_now);
|
||||
GC_finalize_now = curr_fo;
|
||||
fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
|
||||
GC_dirty(curr_fo);
|
||||
GC_fnlz_roots.finalize_now = curr_fo;
|
||||
/* unhide object pointer so any future collections will */
|
||||
/* see it. */
|
||||
curr_fo -> fo_hidden_base =
|
||||
|
|
@ -810,8 +1087,8 @@ GC_INNER void GC_finalize(void)
|
|||
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)) {
|
||||
for (curr_fo = GC_fnlz_roots.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) {
|
||||
|
|
@ -826,30 +1103,37 @@ GC_INNER void GC_finalize(void)
|
|||
/* 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) {
|
||||
curr_fo = GC_fnlz_roots.finalize_now;
|
||||
# if defined(GC_ASSERTIONS) || defined(LINT2)
|
||||
if (curr_fo != NULL && log_fo_table_size < 0)
|
||||
ABORT("log_size is negative");
|
||||
# endif
|
||||
prev_fo = NULL;
|
||||
while (curr_fo != NULL) {
|
||||
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
|
||||
if (NULL == prev_fo) {
|
||||
GC_fnlz_roots.finalize_now = next_fo;
|
||||
} else {
|
||||
fo_set_next(prev_fo, next_fo);
|
||||
|
||||
GC_dirty(prev_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]);
|
||||
fo_set_next(curr_fo, GC_fnlz_roots.fo_head[i]);
|
||||
GC_dirty(curr_fo);
|
||||
GC_fo_entries++;
|
||||
GC_fo_head[i] = curr_fo;
|
||||
GC_fnlz_roots.fo_head[i] = curr_fo;
|
||||
curr_fo = prev_fo;
|
||||
needs_barrier = TRUE;
|
||||
}
|
||||
}
|
||||
prev_fo = curr_fo;
|
||||
|
|
@ -857,8 +1141,13 @@ GC_INNER void GC_finalize(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (needs_barrier)
|
||||
GC_dirty(GC_fnlz_roots.fo_head); /* entire object */
|
||||
|
||||
GC_remove_dangling_disappearing_links(&GC_dl_hashtbl);
|
||||
# ifndef GC_TOGGLE_REFS_NOT_NEEDED
|
||||
GC_clear_togglerefs();
|
||||
# endif
|
||||
# ifndef GC_LONG_REFS_NOT_NEEDED
|
||||
GC_make_disappearing_links_disappear(&GC_ll_hashtbl);
|
||||
GC_remove_dangling_disappearing_links(&GC_ll_hashtbl);
|
||||
|
|
@ -880,33 +1169,28 @@ GC_INNER void GC_finalize(void)
|
|||
/* 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;
|
||||
struct finalizable_object * next_fo;
|
||||
int i;
|
||||
int fo_size;
|
||||
|
||||
fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size;
|
||||
GC_bytes_finalized = 0;
|
||||
for (i = 0; i < fo_size; i++) {
|
||||
curr_fo = GC_fo_head[i];
|
||||
prev_fo = 0;
|
||||
while (curr_fo != 0) {
|
||||
real_ptr = GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
||||
struct finalizable_object * curr_fo = GC_fnlz_roots.fo_head[i];
|
||||
|
||||
GC_fnlz_roots.fo_head[i] = NULL;
|
||||
while (curr_fo != NULL) {
|
||||
ptr_t real_ptr = (ptr_t)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) {
|
||||
GC_fo_head[i] = next_fo;
|
||||
} else {
|
||||
fo_set_next(prev_fo, next_fo);
|
||||
}
|
||||
GC_fo_entries--;
|
||||
|
||||
/* Add to list of objects awaiting finalization. */
|
||||
fo_set_next(curr_fo, GC_finalize_now);
|
||||
GC_finalize_now = curr_fo;
|
||||
fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
|
||||
GC_dirty(curr_fo);
|
||||
GC_fnlz_roots.finalize_now = curr_fo;
|
||||
|
||||
/* unhide object pointer so any future collections will */
|
||||
/* see it. */
|
||||
|
|
@ -917,6 +1201,7 @@ GC_INNER void GC_finalize(void)
|
|||
curr_fo = next_fo;
|
||||
}
|
||||
}
|
||||
GC_fo_entries = 0; /* all entries deleted from the hash table */
|
||||
}
|
||||
|
||||
/* Invoke all remaining finalizers that haven't yet been run.
|
||||
|
|
@ -958,19 +1243,20 @@ GC_INNER void GC_finalize(void)
|
|||
/* getting into that safe state is expensive.) */
|
||||
GC_API int GC_CALL GC_should_invoke_finalizers(void)
|
||||
{
|
||||
return GC_finalize_now != 0;
|
||||
return GC_fnlz_roots.finalize_now != NULL;
|
||||
}
|
||||
|
||||
/* 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 bytes_freed_before = 0; /* initialized to prevent warning. */
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
while (GC_finalize_now != 0) {
|
||||
while (GC_fnlz_roots.finalize_now != NULL) {
|
||||
struct finalizable_object * curr_fo;
|
||||
|
||||
# ifdef THREADS
|
||||
LOCK();
|
||||
# endif
|
||||
|
|
@ -978,25 +1264,22 @@ GC_API int GC_CALL GC_invoke_finalizers(void)
|
|||
bytes_freed_before = GC_bytes_freed;
|
||||
/* Don't do this outside, since we need the lock. */
|
||||
}
|
||||
curr_fo = GC_finalize_now;
|
||||
curr_fo = GC_fnlz_roots.finalize_now;
|
||||
# ifdef THREADS
|
||||
if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
|
||||
if (curr_fo != 0) GC_fnlz_roots.finalize_now = fo_next(curr_fo);
|
||||
UNLOCK();
|
||||
if (curr_fo == 0) break;
|
||||
# else
|
||||
GC_finalize_now = fo_next(curr_fo);
|
||||
GC_fnlz_roots.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
|
||||
/* Explicit freeing of curr_fo is probably a bad idea. */
|
||||
/* It throws off accounting if nearly all objects are */
|
||||
/* finalizable. Otherwise it should not matter. */
|
||||
}
|
||||
/* bytes_freed_before is initialized whenever count != 0 */
|
||||
if (count != 0 && bytes_freed_before != GC_bytes_freed) {
|
||||
|
|
@ -1007,7 +1290,7 @@ GC_API int GC_CALL GC_invoke_finalizers(void)
|
|||
return count;
|
||||
}
|
||||
|
||||
static GC_word last_finalizer_notification = 0;
|
||||
static word last_finalizer_notification = 0;
|
||||
|
||||
GC_INNER void GC_notify_or_invoke_finalizers(void)
|
||||
{
|
||||
|
|
@ -1020,7 +1303,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
|
|||
# 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;
|
||||
if (NULL == GC_fnlz_roots.finalize_now) return;
|
||||
# endif
|
||||
LOCK();
|
||||
|
||||
|
|
@ -1045,14 +1328,12 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
|
|||
# endif
|
||||
# ifdef MAKE_BACK_GRAPH
|
||||
if (GC_print_back_height) {
|
||||
UNLOCK();
|
||||
GC_print_back_graph_stats();
|
||||
LOCK();
|
||||
}
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
if (GC_finalize_now == 0) {
|
||||
if (NULL == GC_fnlz_roots.finalize_now) {
|
||||
UNLOCK();
|
||||
return;
|
||||
}
|
||||
|
|
@ -1065,7 +1346,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
|
|||
(void) GC_invoke_finalizers();
|
||||
*pnested = 0; /* Reset since no more finalizers. */
|
||||
# ifndef THREADS
|
||||
GC_ASSERT(GC_finalize_now == 0);
|
||||
GC_ASSERT(NULL == GC_fnlz_roots.finalize_now);
|
||||
# endif /* Otherwise GC can run concurrently and add more */
|
||||
}
|
||||
return;
|
||||
|
|
@ -1100,7 +1381,7 @@ GC_INNER void GC_notify_or_invoke_finalizers(void)
|
|||
(unsigned long)IF_LONG_REFS_PRESENT_ELSE(
|
||||
GC_ll_hashtbl.entries, 0));
|
||||
|
||||
for (fo = GC_finalize_now; 0 != fo; fo = fo_next(fo))
|
||||
for (fo = GC_fnlz_roots.finalize_now; fo != NULL; fo = fo_next(fo))
|
||||
++ready;
|
||||
GC_log_printf("%lu finalization-ready objects;"
|
||||
" %ld/%ld short/long links cleared\n",
|
||||
|
|
|
|||
|
|
@ -17,29 +17,32 @@
|
|||
#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 */
|
||||
#include "gc_inline.h" /* for GC_malloc_kind */
|
||||
|
||||
STATIC int GC_finalized_kind = 0;
|
||||
|
||||
#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
|
||||
/* The first bit is already used for a debug purpose. */
|
||||
# define FINALIZER_CLOSURE_FLAG 0x2
|
||||
#else
|
||||
# define FINALIZER_CLOSURE_FLAG 0x1
|
||||
#endif
|
||||
|
||||
STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj)
|
||||
{
|
||||
word fc_word = *(word *)obj;
|
||||
|
||||
if ((fc_word & 1) != 0) {
|
||||
if ((fc_word & FINALIZER_CLOSURE_FLAG) != 0) {
|
||||
/* 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 */
|
||||
/* on such fragments is always multiple of 4 (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. */
|
||||
const struct GC_finalizer_closure *fc = (void *)(fc_word & ~(word)1);
|
||||
const struct GC_finalizer_closure *fc
|
||||
= (void *)(fc_word & ~(word)FINALIZER_CLOSURE_FLAG);
|
||||
(*fc->proc)((word *)obj + 1, fc->cd);
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -66,8 +69,7 @@ GC_API void GC_CALL GC_init_finalized_malloc(void)
|
|||
/* start of the user region. */
|
||||
GC_register_displacement_inner(sizeof(word));
|
||||
|
||||
GC_finalized_objfreelist = (ptr_t *)GC_new_free_list_inner();
|
||||
GC_finalized_kind = GC_new_kind_inner((void **)GC_finalized_objfreelist,
|
||||
GC_finalized_kind = GC_new_kind_inner(GC_new_free_list_inner(),
|
||||
GC_DS_LENGTH, TRUE, TRUE);
|
||||
GC_register_disclaim_proc(GC_finalized_kind, GC_finalized_disclaim, TRUE);
|
||||
UNLOCK();
|
||||
|
|
@ -81,90 +83,17 @@ GC_API void GC_CALL GC_register_disclaim_proc(int kind, GC_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,
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb,
|
||||
const struct GC_finalizer_closure *fclos)
|
||||
#else
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb,
|
||||
const struct GC_finalizer_closure *fclos)
|
||||
#endif
|
||||
{
|
||||
ptr_t op;
|
||||
word lg;
|
||||
DCL_LOCK_STATE;
|
||||
word *op;
|
||||
|
||||
lb += sizeof(word);
|
||||
GC_ASSERT(done_init);
|
||||
if (SMALL_OBJ(lb)) {
|
||||
GC_DBG_COLLECT_AT_MALLOC(lb);
|
||||
lg = GC_size_map[lb];
|
||||
LOCK();
|
||||
op = GC_finalized_objfreelist[lg];
|
||||
if (EXPECT(0 == op, FALSE)) {
|
||||
UNLOCK();
|
||||
op = GC_generic_malloc(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 {
|
||||
GC_finalized_objfreelist[lg] = obj_link(op);
|
||||
obj_link(op) = 0;
|
||||
GC_bytes_allocd += GRANULES_TO_BYTES(lg);
|
||||
UNLOCK();
|
||||
}
|
||||
GC_ASSERT(lg > 0);
|
||||
} else {
|
||||
op = GC_generic_malloc(lb, GC_finalized_kind);
|
||||
if (NULL == op)
|
||||
return NULL;
|
||||
GC_ASSERT(GC_size(op) >= lb);
|
||||
}
|
||||
*(word *)op = (word)fclos | 1;
|
||||
return GC_clear_stack((word *)op + 1);
|
||||
op = GC_malloc_kind(SIZET_SAT_ADD(lb, sizeof(word)), GC_finalized_kind);
|
||||
if (EXPECT(NULL == op, FALSE))
|
||||
return NULL;
|
||||
*op = (word)fclos | FINALIZER_CLOSURE_FLAG;
|
||||
return op + 1;
|
||||
}
|
||||
|
||||
#ifdef THREAD_LOCAL_ALLOC
|
||||
GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t client_lb,
|
||||
const struct GC_finalizer_closure *fclos)
|
||||
{
|
||||
size_t lb = client_lb + sizeof(word);
|
||||
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;
|
||||
*(word *)result = (word)fclos | 1;
|
||||
PREFETCH_FOR_WRITE(next);
|
||||
return (word *)result + 1;
|
||||
}
|
||||
#endif /* THREAD_LOCAL_ALLOC */
|
||||
|
||||
#endif /* ENABLE_DISCLAIM */
|
||||
|
|
|
|||
323
src/bdwgc/gc.mak
323
src/bdwgc/gc.mak
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=gctest - Win32 Release
|
||||
!MESSAGE No configuration specified. Defaulting to cord - Win32 Debug.
|
||||
!MESSAGE No configuration specified. Defaulting to gctest - Win32 Release.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "gc - Win32 Release" && "$(CFG)" != "gc - Win32 Debug" &&\
|
||||
|
|
@ -110,8 +110,9 @@ 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"
|
||||
-@erase ".\Release\msvc_dbg.copied.obj"
|
||||
-@erase ".\Release\msvc_dbg.copied.sbr"
|
||||
-@erase ".\msvc_dbg.copied.c"
|
||||
|
||||
"$(OUTDIR)" :
|
||||
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
||||
|
|
@ -119,10 +120,10 @@ CLEAN :
|
|||
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 "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_PROJ=/nologo /MD /W3 /EHsc /O2 /I include /D "NDEBUG" /D "WIN32"\
|
||||
/D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE"\
|
||||
/FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch"\
|
||||
/I./libatomic_ops/src /Fo"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\Release/
|
||||
CPP_SBRS=.\Release/
|
||||
|
||||
|
|
@ -155,31 +156,31 @@ 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\fnlz_mlc.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\msvc_dbg.sbr" \
|
||||
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\fnlz_mlc.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\msvc_dbg.copied.sbr"\
|
||||
".\Release\win32_threads.sbr"
|
||||
|
||||
".\Release\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
|
||||
|
|
@ -195,31 +196,31 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.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\fnlz_mlc.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\msvc_dbg.obj" \
|
||||
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\fnlz_mlc.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\msvc_dbg.copied.obj"\
|
||||
".\Release\win32_threads.obj"
|
||||
|
||||
".\Release\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
|
|
@ -301,8 +302,9 @@ 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"
|
||||
-@erase ".\Debug\msvc_dbg.copied.obj"
|
||||
-@erase ".\Debug\msvc_dbg.copied.sbr"
|
||||
-@erase ".\msvc_dbg.copied.c"
|
||||
|
||||
"$(OUTDIR)" :
|
||||
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
||||
|
|
@ -310,10 +312,10 @@ CLEAN :
|
|||
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 "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)/"\
|
||||
CPP_PROJ=/nologo /MDd /W3 /Gm /EHsc /Zi /Od /I include /D "_DEBUG"\
|
||||
/D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS"\
|
||||
/D "GC_ASSERTIONS" /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE"\
|
||||
/FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /Fo"$(INTDIR)/"\
|
||||
/I./libatomic_ops/src /Fd"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\Debug/
|
||||
CPP_SBRS=.\Debug/
|
||||
|
|
@ -347,31 +349,31 @@ 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\fnlz_mlc.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\msvc_dbg.sbr" \
|
||||
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\fnlz_mlc.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\msvc_dbg.copied.sbr"\
|
||||
".\Debug\win32_threads.sbr"
|
||||
|
||||
".\Debug\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
|
||||
|
|
@ -387,31 +389,31 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.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\fnlz_mlc.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\msvc_dbg.obj" \
|
||||
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\fnlz_mlc.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\msvc_dbg.copied.obj"\
|
||||
".\Debug\win32_threads.obj"
|
||||
|
||||
".\Debug\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
|
|
@ -437,22 +439,23 @@ INTDIR=.\gctest\Release
|
|||
ALL : "gc - Win32 Release" ".\Release\gctest.exe"
|
||||
|
||||
CLEAN :
|
||||
-@erase ".\gctest\Release\test.obj"
|
||||
-@erase ".\gctest\Release\test.copied.obj"
|
||||
-@erase ".\test.copied.c"
|
||||
-@erase ".\Release\gctest.exe"
|
||||
|
||||
"$(OUTDIR)" :
|
||||
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
||||
|
||||
test.c : tests\test.c
|
||||
copy tests\test.c test.c
|
||||
test.copied.c : tests\test.c
|
||||
copy tests\test.c test.copied.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 "GC_THREADS" /YX /c
|
||||
CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
|
||||
"ALL_INTERIOR_POINTERS" /D "GC_THREADS" \
|
||||
/I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch" \
|
||||
/YX /Fo"$(INTDIR)/" /c
|
||||
CPP_PROJ=/nologo /MD /W3 /EHsc /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS"\
|
||||
/D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE"\
|
||||
/I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch"\
|
||||
/Fo"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\gctest\Release/
|
||||
CPP_SBRS=.\.
|
||||
|
||||
|
|
@ -485,7 +488,7 @@ BSC32=bscmake.exe
|
|||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
|
||||
BSC32_SBRS= \
|
||||
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
|
||||
|
|
@ -494,8 +497,8 @@ 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" \
|
||||
LINK32_OBJS=\
|
||||
".\gctest\Release\test.copied.obj"\
|
||||
".\Release\gc.lib"
|
||||
|
||||
".\Release\gctest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
|
|
@ -525,8 +528,9 @@ CLEAN :
|
|||
-@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\test.copied.obj"
|
||||
-@erase ".\gctest\Debug\test.copied.sbr"
|
||||
-@erase ".\test.copied.c"
|
||||
-@erase ".\gctest\Debug\vc40.idb"
|
||||
-@erase ".\gctest\Debug\vc40.pdb"
|
||||
|
||||
|
|
@ -536,9 +540,9 @@ 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 "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_THREADS" /FR"$(INTDIR)/"\
|
||||
/I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
|
||||
CPP_PROJ=/nologo /MDd /W3 /Gm /EHsc /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
|
||||
/D "ALL_INTERIOR_POINTERS" /D "GC_THREADS" /D "_CRT_SECURE_NO_DEPRECATE" /FR"$(INTDIR)/"\
|
||||
/I./libatomic_ops/src /Fp"$(INTDIR)/gctest.pch" /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\gctest\Debug/
|
||||
CPP_SBRS=.\gctest\Debug/
|
||||
|
||||
|
|
@ -571,8 +575,8 @@ BSC32=bscmake.exe
|
|||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
|
||||
BSC32_SBRS= \
|
||||
".\gctest\Debug\test.sbr"
|
||||
BSC32_SBRS=\
|
||||
".\gctest\Debug\test.copied.sbr"
|
||||
|
||||
".\gctest\Debug\gctest.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
|
|
@ -587,9 +591,9 @@ LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.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"
|
||||
LINK32_OBJS=\
|
||||
".\Debug\gc.lib"\
|
||||
".\gctest\Debug\test.copied.obj"
|
||||
|
||||
".\Debug\gctest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
|
|
@ -627,8 +631,8 @@ CLEAN :
|
|||
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\
|
||||
/I./libatomic_ops/src "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c
|
||||
CPP_PROJ=/nologo /MD /W3 /EHsc /O2 /I "." /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS"\
|
||||
/D "ALL_INTERIOR_POINTERS" /I./libatomic_ops/src /Fp"$(INTDIR)/cord.pch" /Fo"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\cord\Release/
|
||||
CPP_SBRS=.\.
|
||||
|
||||
|
|
@ -662,7 +666,7 @@ BSC32=bscmake.exe
|
|||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
|
||||
BSC32_SBRS= \
|
||||
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
|
||||
|
|
@ -671,12 +675,12 @@ 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" \
|
||||
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)
|
||||
|
|
@ -719,8 +723,8 @@ 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 /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\
|
||||
CPP_PROJ=/nologo /MDd /W3 /Gm /EHsc /Zi /Od /I "." /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
|
||||
/D "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch"\
|
||||
/I./libatomic_ops/src /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
|
||||
CPP_OBJS=.\cord\Debug/
|
||||
CPP_SBRS=.\.
|
||||
|
|
@ -755,7 +759,7 @@ BSC32=bscmake.exe
|
|||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
|
||||
BSC32_SBRS= \
|
||||
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
|
||||
|
|
@ -764,12 +768,12 @@ 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" \
|
||||
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)
|
||||
|
|
@ -1945,6 +1949,9 @@ NODEP_CPP_WIN32=\
|
|||
|
||||
SOURCE=.\extra\msvc_dbg.c
|
||||
|
||||
msvc_dbg.copied.c : extra\msvc_dbg.c
|
||||
copy extra\msvc_dbg.c msvc_dbg.copied.c
|
||||
|
||||
!IF "$(CFG)" == "gc - Win32 Release"
|
||||
|
||||
DEP_CPP_WIN32=\
|
||||
|
|
@ -1961,9 +1968,9 @@ NODEP_CPP_WIN32=\
|
|||
".\th\PCR_ThCtl.h"\
|
||||
|
||||
|
||||
".\Release\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
||||
".\Release\msvc_dbg.copied.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
||||
|
||||
".\Release\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
||||
".\Release\msvc_dbg.copied.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
||||
|
|
@ -1982,9 +1989,9 @@ NODEP_CPP_WIN32=\
|
|||
".\th\PCR_ThCtl.h"\
|
||||
|
||||
|
||||
".\Debug\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
||||
".\Debug\msvc_dbg.copied.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
||||
|
||||
".\Debug\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
||||
".\Debug\msvc_dbg.copied.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
||||
|
||||
|
||||
!ENDIF
|
||||
|
|
@ -2090,15 +2097,15 @@ NODEP_CPP_TEST_=\
|
|||
!IF "$(CFG)" == "gctest - Win32 Release"
|
||||
|
||||
|
||||
".\gctest\Release\test.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
|
||||
".\gctest\Release\test.copied.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
|
||||
|
||||
|
||||
!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
|
||||
|
||||
|
||||
".\gctest\Debug\test.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
|
||||
".\gctest\Debug\test.copied.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
|
||||
|
||||
".\gctest\Debug\test.sbr" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
|
||||
".\gctest\Debug\test.copied.sbr" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
|
||||
|
||||
|
||||
!ENDIF
|
||||
|
|
|
|||
|
|
@ -27,62 +27,73 @@ built-in "new" and "delete".
|
|||
# define GC_BUILD
|
||||
#endif
|
||||
|
||||
#include "gc_cpp.h"
|
||||
#include "gc.h"
|
||||
|
||||
#if !defined(GC_NEW_DELETE_NEED_THROW) && defined(__GNUC__) \
|
||||
&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
|
||||
# define GC_NEW_DELETE_NEED_THROW
|
||||
#include <new> // for bad_alloc, precedes include of gc_cpp.h
|
||||
|
||||
#include "gc_cpp.h" // for GC_OPERATOR_NEW_ARRAY, GC_DECL_DELETE_THROW
|
||||
|
||||
#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
|
||||
# define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
|
||||
#else
|
||||
# define GC_ALLOCATOR_THROW_OR_ABORT() throw std::bad_alloc()
|
||||
#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);
|
||||
GC_API void GC_CALL GC_throw_bad_alloc() {
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
}
|
||||
|
||||
#if !defined(__CYGWIN__)
|
||||
void operator delete( void* obj ) GC_DECL_DELETE_THROW {
|
||||
GC_FREE(obj);
|
||||
}
|
||||
#endif /* !__CYGWIN__ */
|
||||
#if !defined(_MSC_VER) && !defined(__DMC__)
|
||||
|
||||
#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 ) GC_DECL_NEW_THROW
|
||||
{
|
||||
# ifndef GC_DEBUG
|
||||
return GC_malloc_uncollectable(size);
|
||||
# else
|
||||
return GC_debug_malloc_uncollectable(size, szFileName, nLine);
|
||||
# endif
|
||||
}
|
||||
|
||||
# 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);
|
||||
}
|
||||
# if !defined(GC_NEW_DELETE_THROW_NOT_NEEDED) \
|
||||
&& !defined(GC_NEW_DELETE_NEED_THROW) \
|
||||
&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) \
|
||||
&& (__cplusplus < 201103L || defined(__clang__))
|
||||
# define GC_NEW_DELETE_NEED_THROW
|
||||
# endif
|
||||
|
||||
#endif /* _MSC_VER */
|
||||
# ifdef GC_NEW_DELETE_NEED_THROW
|
||||
# define GC_DECL_NEW_THROW throw(std::bad_alloc)
|
||||
# else
|
||||
# define GC_DECL_NEW_THROW /* empty */
|
||||
# endif
|
||||
|
||||
void* operator new(size_t size) GC_DECL_NEW_THROW {
|
||||
void* obj = GC_MALLOC_UNCOLLECTABLE(size);
|
||||
if (0 == obj)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return obj;
|
||||
}
|
||||
|
||||
void operator delete(void* obj) GC_DECL_DELETE_THROW {
|
||||
GC_FREE(obj);
|
||||
}
|
||||
|
||||
# if defined(GC_OPERATOR_NEW_ARRAY) && !defined(CPPCHECK)
|
||||
void* operator new[](size_t size) GC_DECL_NEW_THROW {
|
||||
void* obj = GC_MALLOC_UNCOLLECTABLE(size);
|
||||
if (0 == obj)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return obj;
|
||||
}
|
||||
|
||||
void operator delete[](void* obj) GC_DECL_DELETE_THROW {
|
||||
GC_FREE(obj);
|
||||
}
|
||||
# endif // GC_OPERATOR_NEW_ARRAY
|
||||
|
||||
# if __cplusplus > 201103L // C++14
|
||||
void operator delete(void* obj, size_t size) GC_DECL_DELETE_THROW {
|
||||
(void)size; // size is ignored
|
||||
GC_FREE(obj);
|
||||
}
|
||||
|
||||
# if defined(GC_OPERATOR_NEW_ARRAY) && !defined(CPPCHECK)
|
||||
void operator delete[](void* obj, size_t size) GC_DECL_DELETE_THROW {
|
||||
(void)size;
|
||||
GC_FREE(obj);
|
||||
}
|
||||
# endif
|
||||
# endif // C++14
|
||||
|
||||
#endif // !_MSC_VER
|
||||
|
|
|
|||
|
|
@ -54,8 +54,6 @@ int GC_gcj_debug_kind = 0;
|
|||
|
||||
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,
|
||||
|
|
@ -69,7 +67,9 @@ STATIC struct GC_ms_entry * GC_gcj_fake_mark_proc(word * addr GC_ATTR_UNUSED,
|
|||
GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
|
||||
void * /* really GC_mark_proc */mp)
|
||||
{
|
||||
GC_bool ignore_gcj_info;
|
||||
# ifndef GC_IGNORE_GCJ_INFO
|
||||
GC_bool ignore_gcj_info;
|
||||
# endif
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
if (mp == 0) /* In case GC_DS_PROC is unused. */
|
||||
|
|
@ -84,7 +84,7 @@ GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
|
|||
GC_gcj_malloc_initialized = TRUE;
|
||||
# ifdef GC_IGNORE_GCJ_INFO
|
||||
/* This is useful for debugging on platforms with missing getenv(). */
|
||||
ignore_gcj_info = 1;
|
||||
# define ignore_gcj_info TRUE
|
||||
# else
|
||||
ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO"));
|
||||
# endif
|
||||
|
|
@ -101,7 +101,7 @@ GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
|
|||
/* 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),
|
||||
/* 0 | */ GC_DS_LENGTH,
|
||||
TRUE, TRUE);
|
||||
} else {
|
||||
GC_gcj_kind = GC_new_kind_inner(
|
||||
|
|
@ -114,16 +114,14 @@ GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
|
|||
/* Set up object kind for objects that require mark proc call. */
|
||||
if (ignore_gcj_info) {
|
||||
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_gcj_debug_kind = GC_new_kind_inner(GC_new_free_list_inner(),
|
||||
GC_MAKE_PROC(mp_index,
|
||||
1 /* allocated with debug info */),
|
||||
FALSE, TRUE);
|
||||
}
|
||||
UNLOCK();
|
||||
# undef ignore_gcj_info
|
||||
}
|
||||
|
||||
#define GENERAL_MALLOC_INNER(lb,k) \
|
||||
|
|
@ -164,12 +162,12 @@ static void maybe_finalize(void)
|
|||
#endif
|
||||
{
|
||||
ptr_t op;
|
||||
word lg;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
GC_DBG_COLLECT_AT_MALLOC(lb);
|
||||
if(SMALL_OBJ(lb)) {
|
||||
lg = GC_size_map[lb];
|
||||
word lg = GC_size_map[lb];
|
||||
|
||||
LOCK();
|
||||
op = GC_gcjobjfreelist[lg];
|
||||
if(EXPECT(0 == op, FALSE)) {
|
||||
|
|
@ -182,11 +180,9 @@ static void maybe_finalize(void)
|
|||
}
|
||||
} else {
|
||||
GC_gcjobjfreelist[lg] = obj_link(op);
|
||||
GC_bytes_allocd += GRANULES_TO_BYTES(lg);
|
||||
GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
|
||||
}
|
||||
*(void **)op = ptr_to_struct_containing_descr;
|
||||
GC_ASSERT(((void **)op)[1] == 0);
|
||||
UNLOCK();
|
||||
} else {
|
||||
LOCK();
|
||||
maybe_finalize();
|
||||
|
|
@ -196,10 +192,12 @@ static void maybe_finalize(void)
|
|||
UNLOCK();
|
||||
return((*oom_fn)(lb));
|
||||
}
|
||||
*(void **)op = ptr_to_struct_containing_descr;
|
||||
UNLOCK();
|
||||
}
|
||||
return((void *) op);
|
||||
*(void **)op = ptr_to_struct_containing_descr;
|
||||
UNLOCK();
|
||||
GC_dirty(op);
|
||||
REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
|
||||
return (void *)op;
|
||||
}
|
||||
|
||||
/* Similar to GC_gcj_malloc, but add debug info. This is allocated */
|
||||
|
|
@ -214,7 +212,8 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_gcj_malloc(size_t lb,
|
|||
/* confuse the backtrace. */
|
||||
LOCK();
|
||||
maybe_finalize();
|
||||
result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
|
||||
result = GC_generic_malloc_inner(SIZET_SAT_ADD(lb, DEBUG_BYTES),
|
||||
GC_gcj_debug_kind);
|
||||
if (result == 0) {
|
||||
GC_oom_func oom_fn = GC_oom_fn;
|
||||
UNLOCK();
|
||||
|
|
@ -223,12 +222,15 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_gcj_malloc(size_t lb,
|
|||
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_inner();
|
||||
}
|
||||
ADD_CALL_CHAIN(result, ra);
|
||||
return (GC_store_debug_info(result, (word)lb, s, i));
|
||||
result = GC_store_debug_info_inner(result, (word)lb, s, i);
|
||||
UNLOCK();
|
||||
GC_dirty(result);
|
||||
REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* There is no THREAD_LOCAL_ALLOC for GC_gcj_malloc_ignore_off_page(). */
|
||||
|
|
@ -236,12 +238,12 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
|
|||
void * ptr_to_struct_containing_descr)
|
||||
{
|
||||
ptr_t op;
|
||||
word lg;
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
GC_DBG_COLLECT_AT_MALLOC(lb);
|
||||
if(SMALL_OBJ(lb)) {
|
||||
lg = GC_size_map[lb];
|
||||
word lg = GC_size_map[lb];
|
||||
|
||||
LOCK();
|
||||
op = GC_gcjobjfreelist[lg];
|
||||
if (EXPECT(0 == op, FALSE)) {
|
||||
|
|
@ -254,7 +256,7 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
|
|||
}
|
||||
} else {
|
||||
GC_gcjobjfreelist[lg] = obj_link(op);
|
||||
GC_bytes_allocd += GRANULES_TO_BYTES(lg);
|
||||
GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
|
||||
}
|
||||
} else {
|
||||
LOCK();
|
||||
|
|
@ -268,7 +270,9 @@ GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
|
|||
}
|
||||
*(void **)op = ptr_to_struct_containing_descr;
|
||||
UNLOCK();
|
||||
return((void *) op);
|
||||
GC_dirty(op);
|
||||
REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
|
||||
return (void *)op;
|
||||
}
|
||||
|
||||
#endif /* GC_GCJ_SUPPORT */
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ static ptr_t scratch_free_ptr = 0;
|
|||
GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
|
||||
{
|
||||
ptr_t result = scratch_free_ptr;
|
||||
word bytes_to_get;
|
||||
size_t bytes_to_get;
|
||||
|
||||
bytes = ROUNDUP_GRANULE_SIZE(bytes);
|
||||
for (;;) {
|
||||
|
|
@ -170,7 +170,7 @@ static hdr * alloc_hdr(void)
|
|||
register hdr * result;
|
||||
|
||||
if (hdr_free_list == 0) {
|
||||
result = (hdr *) GC_scratch_alloc((word)(sizeof(hdr)));
|
||||
result = (hdr *)GC_scratch_alloc(sizeof(hdr));
|
||||
} else {
|
||||
result = hdr_free_list;
|
||||
hdr_free_list = (hdr *) (result -> hb_next);
|
||||
|
|
@ -194,7 +194,7 @@ GC_INNER void GC_init_headers(void)
|
|||
{
|
||||
register unsigned i;
|
||||
|
||||
GC_all_nils = (bottom_index *)GC_scratch_alloc((word)sizeof(bottom_index));
|
||||
GC_all_nils = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
|
||||
if (GC_all_nils == NULL) {
|
||||
GC_err_printf("Insufficient memory for GC_all_nils\n");
|
||||
EXIT();
|
||||
|
|
@ -224,14 +224,14 @@ static GC_bool get_index(word addr)
|
|||
if (p -> key == hi) return(TRUE);
|
||||
p = p -> hash_link;
|
||||
}
|
||||
r = (bottom_index*)GC_scratch_alloc((word)(sizeof (bottom_index)));
|
||||
r = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
|
||||
if (r == 0) return(FALSE);
|
||||
BZERO(r, sizeof (bottom_index));
|
||||
r -> hash_link = old;
|
||||
GC_top_index[i] = r;
|
||||
# else
|
||||
if (GC_top_index[hi] != GC_all_nils) return(TRUE);
|
||||
r = (bottom_index*)GC_scratch_alloc((word)(sizeof (bottom_index)));
|
||||
r = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
|
||||
if (r == 0) return(FALSE);
|
||||
GC_top_index[hi] = r;
|
||||
BZERO(r, sizeof (bottom_index));
|
||||
|
|
@ -277,14 +277,14 @@ GC_INNER struct hblkhdr * GC_install_header(struct hblk *h)
|
|||
GC_INNER GC_bool GC_install_counts(struct hblk *h, size_t sz/* bytes */)
|
||||
{
|
||||
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; (word)hbp < (word)h + sz; hbp += 1) {
|
||||
i = HBLK_PTR_DIFF(hbp, h);
|
||||
word i = HBLK_PTR_DIFF(hbp, h);
|
||||
|
||||
SET_HDR(hbp, (hdr *)(i > MAX_JUMP? MAX_JUMP : i));
|
||||
}
|
||||
return(TRUE);
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@
|
|||
/* Define to recognise all pointers to the interior of objects. */
|
||||
#undef ALL_INTERIOR_POINTERS
|
||||
|
||||
/* Define to enable atomic uncollectible allocation. */
|
||||
#undef ATOMIC_UNCOLLECTABLE
|
||||
|
||||
/* See doc/README.macros. */
|
||||
#undef DARWIN_DONT_PARSE_STACK
|
||||
|
||||
|
|
@ -30,6 +27,9 @@
|
|||
/* Define to enable internal debug assertions. */
|
||||
#undef GC_ASSERTIONS
|
||||
|
||||
/* Define to enable atomic uncollectible allocation. */
|
||||
#undef GC_ATOMIC_UNCOLLECTABLE
|
||||
|
||||
/* Define to support Darwin pthreads. */
|
||||
#undef GC_DARWIN_THREADS
|
||||
|
||||
|
|
@ -39,6 +39,9 @@
|
|||
/* Define to build dynamic libraries with only API symbols exposed. */
|
||||
#undef GC_DLL
|
||||
|
||||
/* Define to turn on GC_suspend_thread support. */
|
||||
#undef GC_ENABLE_SUSPEND_THREAD
|
||||
|
||||
/* Define to support FreeBSD pthreads. */
|
||||
#undef GC_FREEBSD_THREADS
|
||||
|
||||
|
|
@ -48,6 +51,9 @@
|
|||
/* Define to support GNU pthreads. */
|
||||
#undef GC_GNU_THREADS
|
||||
|
||||
/* Define to support Haiku pthreads. */
|
||||
#undef GC_HAIKU_THREADS
|
||||
|
||||
/* Define if backtrace information is supported. */
|
||||
#undef GC_HAVE_BUILTIN_BACKTRACE
|
||||
|
||||
|
|
@ -63,6 +69,9 @@
|
|||
/* Define to support pthreads on Linux. */
|
||||
#undef GC_LINUX_THREADS
|
||||
|
||||
/* Missing execinfo.h header. */
|
||||
#undef GC_MISSING_EXECINFO_H
|
||||
|
||||
/* Define to support NetBSD pthreads. */
|
||||
#undef GC_NETBSD_THREADS
|
||||
|
||||
|
|
@ -93,6 +102,15 @@
|
|||
/* See doc/README.macros. */
|
||||
#undef GC_USE_DLOPEN_WRAP
|
||||
|
||||
/* The major version number of this GC release. */
|
||||
#undef GC_VERSION_MAJOR
|
||||
|
||||
/* The micro version number of this GC release. */
|
||||
#undef GC_VERSION_MICRO
|
||||
|
||||
/* The minor version number of this GC release. */
|
||||
#undef GC_VERSION_MINOR
|
||||
|
||||
/* Define to support pthreads-win32 or winpthreads. */
|
||||
#undef GC_WIN32_PTHREADS
|
||||
|
||||
|
|
@ -108,6 +126,15 @@
|
|||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define if 'dl_iterate_phdr' function is available. */
|
||||
#undef HAVE_DL_ITERATE_PHDR
|
||||
|
||||
/* Define to 1 if you have the <execinfo.h> header file. */
|
||||
#undef HAVE_EXECINFO_H
|
||||
|
||||
/* Define to 1 if you have the `getcontext' function. */
|
||||
#undef HAVE_GETCONTEXT
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
|
|
@ -162,6 +189,9 @@
|
|||
/* Define to make the collector not allocate executable memory by default. */
|
||||
#undef NO_EXECUTE_PERMISSION
|
||||
|
||||
/* Missing getcontext function. */
|
||||
#undef NO_GETCONTEXT
|
||||
|
||||
/* Prohibit installation of pthread_atfork() handlers. */
|
||||
#undef NO_HANDLE_FORK
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef GC_DLL
|
||||
#if defined(GC_DLL) && !defined(CORD_NOT_DLL)
|
||||
/* Same as for GC_API in gc_config_macros.h. */
|
||||
# ifdef CORD_BUILD
|
||||
# if defined(__MINGW32__) || defined(__CEGCC__)
|
||||
|
|
@ -66,8 +66,8 @@
|
|||
# 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))
|
||||
# elif defined(__GNUC__) && !defined(GC_NO_VISIBILITY) \
|
||||
&& (__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
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ typedef struct CORD_ec_struct {
|
|||
/* 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. */
|
||||
/* Flush the buffer part of the extended cord 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);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* 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.
|
||||
* Copyright (c) 2009-2018 Ivan Maidanski
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
|
|
@ -31,6 +32,11 @@
|
|||
#ifndef GC_H
|
||||
#define GC_H
|
||||
|
||||
/* Help debug mixed up preprocessor symbols. */
|
||||
#if (defined(WIN64) && !defined(_WIN64)) && defined(_MSC_VER)
|
||||
#pragma message("Warning: Expecting _WIN64 for x64 targets! Notice the leading underscore!")
|
||||
#endif
|
||||
|
||||
#include "gc_version.h"
|
||||
/* Define version numbers here to allow test on build machine */
|
||||
/* for cross-builds. Note that this defines the header */
|
||||
|
|
@ -54,7 +60,7 @@ typedef void * GC_PTR; /* preserved only for backward compatibility */
|
|||
/* better choices. But those had incorrect definitions on some older */
|
||||
/* systems. Notably "typedef int size_t" is WRONG. */
|
||||
#ifdef _WIN64
|
||||
# ifdef __int64
|
||||
# if defined(__int64) && !defined(CPPCHECK)
|
||||
typedef unsigned __int64 GC_word;
|
||||
typedef __int64 GC_signed_word;
|
||||
# else
|
||||
|
|
@ -129,10 +135,50 @@ 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). */
|
||||
|
||||
typedef enum {
|
||||
GC_EVENT_START /* COLLECTION */,
|
||||
GC_EVENT_MARK_START,
|
||||
GC_EVENT_MARK_END,
|
||||
GC_EVENT_RECLAIM_START,
|
||||
GC_EVENT_RECLAIM_END,
|
||||
GC_EVENT_END /* COLLECTION */,
|
||||
GC_EVENT_PRE_STOP_WORLD /* STOPWORLD_BEGIN */,
|
||||
GC_EVENT_POST_STOP_WORLD /* STOPWORLD_END */,
|
||||
GC_EVENT_PRE_START_WORLD /* STARTWORLD_BEGIN */,
|
||||
GC_EVENT_POST_START_WORLD /* STARTWORLD_END */,
|
||||
GC_EVENT_THREAD_SUSPENDED,
|
||||
GC_EVENT_THREAD_UNSUSPENDED
|
||||
} GC_EventType;
|
||||
|
||||
typedef void (GC_CALLBACK * GC_on_collection_event_proc)(GC_EventType);
|
||||
/* Invoked to indicate progress through the */
|
||||
/* collection process. Not used for thread */
|
||||
/* suspend/resume notifications. Called with */
|
||||
/* the GC lock held (or, even, the world */
|
||||
/* stopped). May be 0 (means no notifier). */
|
||||
GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc);
|
||||
GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void);
|
||||
/* Both the supplied setter and the getter */
|
||||
/* acquire the GC lock (to avoid data races). */
|
||||
|
||||
#ifdef GC_THREADS
|
||||
typedef void (GC_CALLBACK * GC_on_thread_event_proc)(GC_EventType,
|
||||
void * /* thread_id */);
|
||||
/* Invoked when a thread is suspended or */
|
||||
/* resumed during collection. Called with the */
|
||||
/* GC lock held (and the world stopped */
|
||||
/* partially). May be 0 (means no notifier). */
|
||||
GC_API void GC_CALL GC_set_on_thread_event(GC_on_thread_event_proc);
|
||||
GC_API GC_on_thread_event_proc GC_CALL GC_get_on_thread_event(void);
|
||||
/* Both the supplied setter and the getter */
|
||||
/* acquire the GC lock (to avoid data races). */
|
||||
#endif
|
||||
|
||||
GC_API GC_ATTR_DEPRECATED int GC_find_leak;
|
||||
/* Do not actually garbage collect, but simply */
|
||||
/* Set to true to turn on the leak-finding mode */
|
||||
/* (do not actually garbage collect, but simply */
|
||||
/* report inaccessible memory that was not */
|
||||
/* deallocated with GC_free. Initial value */
|
||||
/* 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 */
|
||||
|
|
@ -274,7 +320,7 @@ GC_API GC_ATTR_DEPRECATED GC_word GC_free_space_divisor;
|
|||
/* 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. */
|
||||
/* The initial value is GC_FREE_SPACE_DIVISOR. */
|
||||
/* Increasing its value will use less space */
|
||||
/* but more collection time. Decreasing it */
|
||||
/* will appreciably decrease collection time */
|
||||
|
|
@ -283,6 +329,8 @@ GC_API GC_ATTR_DEPRECATED GC_word GC_free_space_divisor;
|
|||
/* 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). */
|
||||
/* In version 7.1 (and before), the setter */
|
||||
/* returned the old value. */
|
||||
GC_API void GC_CALL GC_set_free_space_divisor(GC_word);
|
||||
GC_API GC_word GC_CALL GC_get_free_space_divisor(void);
|
||||
|
||||
|
|
@ -395,6 +443,10 @@ GC_API void GC_CALL GC_atfork_child(void);
|
|||
/* from the main program instead. */
|
||||
GC_API void GC_CALL GC_init(void);
|
||||
|
||||
/* Returns non-zero (TRUE) if and only if the collector is initialized */
|
||||
/* (or, at least, the initialization is in progress). */
|
||||
GC_API int GC_CALL GC_is_init_called(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 */
|
||||
|
|
@ -482,7 +534,20 @@ GC_API size_t GC_CALL GC_size(const void * /* obj_addr */) GC_ATTR_NONNULL(1);
|
|||
/* 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. */
|
||||
/* It does not change the content of the object from its beginning to */
|
||||
/* the minimum of old size and new_size_in_bytes; the content above in */
|
||||
/* case of object size growth is initialized to zero (not guaranteed */
|
||||
/* for atomic object type). The function follows ANSI conventions for */
|
||||
/* NULL old_object (i.e., equivalent to GC_malloc regardless of new */
|
||||
/* size). If new size is zero (and old_object is non-NULL) then the */
|
||||
/* call is equivalent to GC_free (and NULL is returned). If old_object */
|
||||
/* is non-NULL, it must have been returned by an earlier call to */
|
||||
/* GC_malloc* or GC_realloc. In case of the allocation failure, the */
|
||||
/* memory pointed by old_object is untouched (and not freed). */
|
||||
/* If the returned pointer is not the same as old_object and both of */
|
||||
/* them are non-NULL then old_object is freed. Returns either NULL (in */
|
||||
/* case of the allocation failure or zero new size) or pointer to the */
|
||||
/* allocated memory. */
|
||||
GC_API void * GC_CALL GC_realloc(void * /* old_object */,
|
||||
size_t /* new_size_in_bytes */)
|
||||
/* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2);
|
||||
|
|
@ -585,7 +650,7 @@ GC_API GC_stop_func GC_CALL GC_get_stop_func(void);
|
|||
/* 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 */
|
||||
/* four ones below 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);
|
||||
|
||||
|
|
@ -680,6 +745,10 @@ GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s *,
|
|||
size_t /* stats_sz */);
|
||||
#endif
|
||||
|
||||
/* Count total memory use in bytes by all allocated blocks. Acquires */
|
||||
/* the lock. */
|
||||
GC_API size_t GC_CALL GC_get_memory_use(void);
|
||||
|
||||
/* Disable garbage collection. Even GC_gcollect calls will be */
|
||||
/* ineffective. */
|
||||
GC_API void GC_CALL GC_disable(void);
|
||||
|
|
@ -708,7 +777,7 @@ 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_POINTER_HEAP 1 /* May protect non-atomic objects. */
|
||||
#define GC_PROTECTS_PTRFREE_HEAP 2
|
||||
#define GC_PROTECTS_STATIC_DATA 4 /* Currently never. */
|
||||
#define GC_PROTECTS_STACK 8 /* Probably impractical. */
|
||||
|
|
@ -718,7 +787,8 @@ GC_API void GC_CALL GC_enable_incremental(void);
|
|||
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. */
|
||||
/* Return 0 if there is no more work to be done (including the */
|
||||
/* case when garbage collection is not appropriate). */
|
||||
/* 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 */
|
||||
|
|
@ -933,6 +1003,7 @@ GC_API void GC_CALL GC_debug_register_finalizer(void * /* obj */,
|
|||
/* be avoided, or broken by disappearing links. */
|
||||
/* All but the last finalizer registered for an object */
|
||||
/* is ignored. */
|
||||
/* No-op in the leak-finding mode. */
|
||||
/* 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 */
|
||||
|
|
@ -1070,6 +1141,7 @@ GC_API int GC_CALL GC_general_register_disappearing_link(void ** /* link */,
|
|||
/* explicitly deallocate the object containing link. */
|
||||
/* Explicit deallocation of obj may or may not cause */
|
||||
/* link to eventually be cleared. */
|
||||
/* No-op in the leak-finding mode. */
|
||||
/* This function can be used to implement certain types */
|
||||
/* of weak pointers. Note, however, this generally */
|
||||
/* requires that the allocation lock is held (see */
|
||||
|
|
@ -1081,7 +1153,8 @@ GC_API int GC_CALL GC_general_register_disappearing_link(void ** /* link */,
|
|||
/* 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). */
|
||||
/* memory (and GC_oom_fn did not handle the problem), */
|
||||
/* GC_UNIMPLEMENTED if GC_find_leak is true. */
|
||||
|
||||
GC_API int GC_CALL GC_move_disappearing_link(void ** /* link */,
|
||||
void ** /* new_link */)
|
||||
|
|
@ -1124,7 +1197,54 @@ GC_API int GC_CALL GC_unregister_long_link(void ** /* link */);
|
|||
/* Similar to GC_unregister_disappearing_link but for a */
|
||||
/* registration by either of the above two routines. */
|
||||
|
||||
/* Support of toggle-ref style of external memory management */
|
||||
/* without hooking up to the host retain/release machinery. */
|
||||
/* The idea of toggle-ref is that an external reference to */
|
||||
/* an object is kept and it can be either a strong or weak */
|
||||
/* reference; a weak reference is used when the external peer */
|
||||
/* has no interest in the object, and a strong otherwise. */
|
||||
typedef enum {
|
||||
GC_TOGGLE_REF_DROP,
|
||||
GC_TOGGLE_REF_STRONG,
|
||||
GC_TOGGLE_REF_WEAK
|
||||
} GC_ToggleRefStatus;
|
||||
|
||||
/* The callback is to decide (return) the new state of a given */
|
||||
/* object. Invoked by the collector for all objects registered */
|
||||
/* for toggle-ref processing. Invoked with the allocation lock */
|
||||
/* held (but the "world" is running). */
|
||||
typedef GC_ToggleRefStatus (GC_CALLBACK *GC_toggleref_func)(void * /* obj */);
|
||||
|
||||
/* Set (register) a callback that decides the state of a given */
|
||||
/* object (by, probably, inspecting its native state). */
|
||||
/* The argument may be 0 (means no callback). Both the setter */
|
||||
/* and the getter acquire the allocation lock (to avoid data */
|
||||
/* races). */
|
||||
GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func);
|
||||
GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void);
|
||||
|
||||
/* Register a given object for toggle-ref processing. It will */
|
||||
/* be stored internally and the toggle-ref callback will be */
|
||||
/* invoked on the object until the callback returns */
|
||||
/* GC_TOGGLE_REF_DROP or the object is collected. If is_strong */
|
||||
/* is true then the object is registered with a strong ref, */
|
||||
/* a weak one otherwise. Returns GC_SUCCESS if registration */
|
||||
/* succeeded (or no callback registered yet), GC_NO_MEMORY if */
|
||||
/* it failed for lack of memory. */
|
||||
GC_API int GC_CALL GC_toggleref_add(void * /* obj */, int /* is_strong */)
|
||||
GC_ATTR_NONNULL(1);
|
||||
|
||||
/* Finalizer callback support. Invoked by the collector (with */
|
||||
/* the allocation lock held) for each unreachable object */
|
||||
/* enqueued for finalization. */
|
||||
typedef void (GC_CALLBACK * GC_await_finalize_proc)(void * /* obj */);
|
||||
GC_API void GC_CALL GC_set_await_finalize_proc(GC_await_finalize_proc);
|
||||
GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void);
|
||||
/* Zero means no callback. The setter */
|
||||
/* and getter acquire the lock too. */
|
||||
|
||||
/* Returns !=0 if GC_invoke_finalizers has something to do. */
|
||||
/* Does not use any synchronization. */
|
||||
GC_API int GC_CALL GC_should_invoke_finalizers(void);
|
||||
|
||||
GC_API int GC_CALL GC_invoke_finalizers(void);
|
||||
|
|
@ -1155,7 +1275,8 @@ GC_API int GC_CALL GC_invoke_finalizers(void);
|
|||
/* 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). */
|
||||
/* lock (to avoid data races). In version 7.1 (and before), the setter */
|
||||
/* returned the old warn_proc value. */
|
||||
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);
|
||||
|
|
@ -1180,6 +1301,9 @@ 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);
|
||||
|
||||
/* A portable way to abort the application because of not enough memory.*/
|
||||
GC_API void GC_CALL GC_abort_on_oom(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 */
|
||||
|
|
@ -1303,6 +1427,7 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
|
|||
/* latter case, the explicit call is normally required for threads */
|
||||
/* created by third-party libraries. */
|
||||
/* A manually registered thread requires manual unregistering. */
|
||||
/* Returns GC_SUCCESS on success, GC_DUPLICATE if already registered. */
|
||||
GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *)
|
||||
GC_ATTR_NONNULL(1);
|
||||
|
||||
|
|
@ -1310,6 +1435,14 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
|
|||
/* registered with the garbage collector. */
|
||||
GC_API int GC_CALL GC_thread_is_registered(void);
|
||||
|
||||
/* Notify the collector about the stack and the alt-stack of the */
|
||||
/* current thread. stack_start/size is used to determine the stack */
|
||||
/* boundaries when a thread is suspended while it is on an alt-stack. */
|
||||
GC_API void GC_CALL GC_register_altstack(void * /* stack_start */,
|
||||
GC_word /* stack_size */,
|
||||
void * /* altstack_base */,
|
||||
GC_word /* altstack_size */);
|
||||
|
||||
/* 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 */
|
||||
|
|
@ -1402,6 +1535,15 @@ GC_API void * GC_CALL GC_is_valid_displacement(void * /* p */);
|
|||
/* Defined only if the library has been compiled without NO_DEBUGGING. */
|
||||
GC_API void GC_CALL GC_dump(void);
|
||||
|
||||
/* Dump information about each block of every GC memory section. */
|
||||
/* Defined only if the library has been compiled without NO_DEBUGGING. */
|
||||
GC_API void GC_CALL GC_dump_regions(void);
|
||||
|
||||
/* Dump information about every registered disappearing link and */
|
||||
/* finalizable object. */
|
||||
/* Defined only if the library has been compiled without NO_DEBUGGING. */
|
||||
GC_API void GC_CALL GC_dump_finalization(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 */
|
||||
|
|
@ -1417,10 +1559,10 @@ GC_API void GC_CALL GC_dump(void);
|
|||
((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))
|
||||
# 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. */
|
||||
|
|
@ -1478,8 +1620,14 @@ typedef int (GC_CALLBACK * GC_has_static_roots_func)(
|
|||
GC_API void GC_CALL GC_register_has_static_roots_callback(
|
||||
GC_has_static_roots_func);
|
||||
|
||||
#if !defined(CPPCHECK) && !defined(GC_WINDOWS_H_INCLUDED) && defined(WINAPI)
|
||||
/* windows.h is included before gc.h */
|
||||
# define GC_WINDOWS_H_INCLUDED
|
||||
#endif
|
||||
|
||||
#if defined(GC_WIN32_THREADS) \
|
||||
&& (!defined(GC_PTHREADS) || defined(GC_BUILD) || defined(WINAPI))
|
||||
&& (!defined(GC_PTHREADS) || defined(GC_BUILD) \
|
||||
|| defined(GC_WINDOWS_H_INCLUDED))
|
||||
/* Note: for Cygwin and pthreads-win32, this is skipped */
|
||||
/* unless windows.h is included before gc.h. */
|
||||
|
||||
|
|
@ -1493,7 +1641,10 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
|
|||
# include <process.h> /* For _beginthreadex, _endthreadex */
|
||||
# endif
|
||||
|
||||
# include <windows.h>
|
||||
# if defined(GC_BUILD) || !defined(GC_DONT_INCLUDE_WINDOWS_H)
|
||||
# include <windows.h>
|
||||
# define GC_WINDOWS_H_INCLUDED
|
||||
# endif
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -1506,14 +1657,14 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
|
|||
# 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
|
||||
# ifndef DECLSPEC_NORETURN
|
||||
/* Typically defined in winnt.h. */
|
||||
# ifdef GC_WINDOWS_H_INCLUDED
|
||||
# define DECLSPEC_NORETURN /* empty */
|
||||
# else
|
||||
# define DECLSPEC_NORETURN __declspec(noreturn)
|
||||
# endif
|
||||
GC_API BOOL WINAPI GC_DllMain(HINSTANCE /* inst */, ULONG /* reason */,
|
||||
LPVOID /* reserved */);
|
||||
# endif /* GC_INSIDE_DLL */
|
||||
# endif
|
||||
|
||||
# if !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) \
|
||||
&& !defined(UINTPTR_MAX)
|
||||
|
|
@ -1521,7 +1672,28 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
|
|||
# else
|
||||
typedef uintptr_t GC_uintptr_t;
|
||||
# endif
|
||||
# define GC_WIN32_SIZE_T GC_uintptr_t
|
||||
|
||||
# ifdef _WIN64
|
||||
# define GC_WIN32_SIZE_T GC_uintptr_t
|
||||
# elif defined(GC_WINDOWS_H_INCLUDED)
|
||||
# define GC_WIN32_SIZE_T DWORD
|
||||
# else
|
||||
# define GC_WIN32_SIZE_T unsigned long
|
||||
# endif
|
||||
|
||||
# ifdef GC_INSIDE_DLL
|
||||
/* Export GC DllMain to be invoked from client DllMain. */
|
||||
# ifdef GC_UNDERSCORE_STDCALL
|
||||
# define GC_DllMain _GC_DllMain
|
||||
# endif
|
||||
# ifdef GC_WINDOWS_H_INCLUDED
|
||||
GC_API BOOL WINAPI GC_DllMain(HINSTANCE /* inst */,
|
||||
ULONG /* reason */,
|
||||
LPVOID /* reserved */);
|
||||
# else
|
||||
GC_API int __stdcall GC_DllMain(void *, unsigned long, void *);
|
||||
# endif
|
||||
# endif /* GC_INSIDE_DLL */
|
||||
|
||||
/* All threads must be created using GC_CreateThread or */
|
||||
/* GC_beginthreadex, or must explicitly call GC_register_my_thread */
|
||||
|
|
@ -1533,20 +1705,24 @@ GC_API void GC_CALL GC_register_has_static_roots_callback(
|
|||
/* 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(
|
||||
# ifdef GC_WINDOWS_H_INCLUDED
|
||||
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
|
||||
|
||||
GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(
|
||||
GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(
|
||||
DWORD /* dwExitCode */);
|
||||
# else
|
||||
struct _SECURITY_ATTRIBUTES;
|
||||
GC_API void *__stdcall GC_CreateThread(struct _SECURITY_ATTRIBUTES *,
|
||||
GC_WIN32_SIZE_T,
|
||||
unsigned long (__stdcall *)(void *),
|
||||
void *, unsigned long, unsigned long *);
|
||||
GC_API DECLSPEC_NORETURN void __stdcall GC_ExitThread(unsigned long);
|
||||
# endif
|
||||
|
||||
# if !defined(_WIN32_WCE) && !defined(__CEGCC__)
|
||||
GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
|
||||
|
|
@ -1603,11 +1779,21 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
|
|||
#if defined(__CYGWIN32__) || defined(__CYGWIN__)
|
||||
/* 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__)
|
||||
# ifdef __x86_64__
|
||||
/* Cygwin/x64 does not add leading underscore to symbols anymore. */
|
||||
extern int __data_start__[], __data_end__[];
|
||||
extern int __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__)
|
||||
# else
|
||||
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__)
|
||||
# endif /* !__x86_64__ */
|
||||
# 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. */
|
||||
|
|
@ -1618,23 +1804,29 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
|
|||
# define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND)
|
||||
#elif (defined(PLATFORM_ANDROID) || defined(__ANDROID__)) \
|
||||
&& !defined(GC_NOT_DLL)
|
||||
# pragma weak __data_start
|
||||
extern int __data_start[], _end[];
|
||||
# pragma weak _etext
|
||||
# pragma weak __data_start
|
||||
# pragma weak __dso_handle
|
||||
extern int _etext[], __dso_handle[];
|
||||
/* Explicitly register caller static data roots (__data_start points */
|
||||
/* to the beginning typically but NDK "gold" linker could provide it */
|
||||
/* incorrectly, so the workaround is to check the value and use */
|
||||
/* __dso_handle as an alternative data start reference if provided). */
|
||||
/* It also works for Android/x86 target where __data_start is not */
|
||||
/* defined currently (regardless of linker used). */
|
||||
extern int _etext[], __data_start[], __dso_handle[];
|
||||
# pragma weak __end__
|
||||
extern int __end__[], _end[];
|
||||
/* Explicitly register caller static data roots. Workaround for */
|
||||
/* __data_start: NDK "gold" linker might miss it or place it */
|
||||
/* incorrectly, __dso_handle is an alternative data start reference. */
|
||||
/* Workaround for _end: NDK Clang 3.5+ does not place it at correct */
|
||||
/* offset (as of NDK r10e) but "bfd" linker provides __end__ symbol */
|
||||
/* that could be used instead. */
|
||||
# define GC_INIT_CONF_ROOTS \
|
||||
(void)((GC_word)__data_start < (GC_word)_etext \
|
||||
&& (GC_word)_etext < (GC_word)__dso_handle ? \
|
||||
(GC_add_roots(__dso_handle, _end), 0) : \
|
||||
(GC_word)__data_start != 0 ? \
|
||||
(GC_add_roots(__data_start, _end), 0) : 0)
|
||||
&& (GC_word)_etext < (GC_word)__dso_handle \
|
||||
? (__end__ != 0 \
|
||||
? (GC_add_roots(__dso_handle, __end__), 0) \
|
||||
: (GC_word)__dso_handle < (GC_word)_end \
|
||||
? (GC_add_roots(__dso_handle, _end), 0) : 0) \
|
||||
: __data_start != 0 ? (__end__ != 0 \
|
||||
? (GC_add_roots(__data_start, __end__), 0) \
|
||||
: (GC_word)__data_start < (GC_word)_end \
|
||||
? (GC_add_roots(__data_start, _end), 0) : 0) : 0)
|
||||
#else
|
||||
# define GC_INIT_CONF_ROOTS /* empty */
|
||||
#endif
|
||||
|
|
@ -1658,14 +1850,14 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
|
|||
/* 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)
|
||||
#elif defined(GC_MAX_RETRIES) && !defined(CPPCHECK)
|
||||
/* 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
|
||||
#if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK)
|
||||
/* 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)
|
||||
|
|
@ -1673,34 +1865,34 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
|
|||
# define GC_INIT_CONF_FREE_SPACE_DIVISOR /* empty */
|
||||
#endif
|
||||
|
||||
#ifdef GC_FULL_FREQ
|
||||
#if defined(GC_FULL_FREQ) && !defined(CPPCHECK)
|
||||
/* 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
|
||||
|
||||
#ifdef GC_TIME_LIMIT
|
||||
#if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
|
||||
/* 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(GC_SIG_SUSPEND) && defined(GC_THREADS)
|
||||
#if defined(GC_SIG_SUSPEND) && defined(GC_THREADS) && !defined(CPPCHECK)
|
||||
# define GC_INIT_CONF_SUSPEND_SIGNAL GC_set_suspend_signal(GC_SIG_SUSPEND)
|
||||
#else
|
||||
# define GC_INIT_CONF_SUSPEND_SIGNAL /* empty */
|
||||
#endif
|
||||
|
||||
#if defined(GC_SIG_THR_RESTART) && defined(GC_THREADS)
|
||||
#if defined(GC_SIG_THR_RESTART) && defined(GC_THREADS) && !defined(CPPCHECK)
|
||||
# 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
|
||||
#if defined(GC_MAXIMUM_HEAP_SIZE) && !defined(CPPCHECK)
|
||||
/* 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 */
|
||||
|
|
@ -1718,7 +1910,7 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
|
|||
# define GC_INIT_CONF_IGNORE_WARN /* empty */
|
||||
#endif
|
||||
|
||||
#ifdef GC_INITIAL_HEAP_SIZE
|
||||
#if defined(GC_INITIAL_HEAP_SIZE) && !defined(CPPCHECK)
|
||||
/* 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(); \
|
||||
|
|
|
|||
|
|
@ -38,16 +38,23 @@
|
|||
*/
|
||||
|
||||
#ifndef GC_ALLOCATOR_H
|
||||
|
||||
#define GC_ALLOCATOR_H
|
||||
|
||||
#include "gc.h"
|
||||
#include <new> // for placement new
|
||||
#include <new> // for placement new and bad_alloc
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define GC_ATTR_UNUSED __attribute__((__unused__))
|
||||
#ifndef GC_ATTR_EXPLICIT
|
||||
# if (__cplusplus >= 201103L) || defined(CPPCHECK)
|
||||
# define GC_ATTR_EXPLICIT explicit
|
||||
# else
|
||||
# define GC_ATTR_EXPLICIT /* empty */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
|
||||
# define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
|
||||
#else
|
||||
# define GC_ATTR_UNUSED
|
||||
# define GC_ALLOCATOR_THROW_OR_ABORT() throw std::bad_alloc()
|
||||
#endif
|
||||
|
||||
/* First some helpers to allow us to dispatch on whether or not a type
|
||||
|
|
@ -85,15 +92,24 @@ GC_DECLARE_PTRFREE(long double);
|
|||
// 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);
|
||||
void *obj = ignore_off_page ? GC_MALLOC_IGNORE_OFF_PAGE(n) : GC_MALLOC(n);
|
||||
if (0 == obj)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return obj;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#if !defined(__WATCOMC__)
|
||||
/* Note: template-id not supported in this context by Watcom compiler. */
|
||||
template <>
|
||||
inline void * GC_selective_alloc<GC_true_type>(size_t n, GC_true_type,
|
||||
bool ignore_off_page) {
|
||||
void * obj = ignore_off_page ? GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(n)
|
||||
: GC_MALLOC_ATOMIC(n);
|
||||
if (0 == obj)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return obj;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now the public gc_allocator<T> class:
|
||||
*/
|
||||
|
|
@ -116,7 +132,8 @@ public:
|
|||
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() {}
|
||||
template <class GC_Tp1> GC_ATTR_EXPLICIT
|
||||
gc_allocator(const gc_allocator<GC_Tp1>&) throw() {}
|
||||
# endif
|
||||
~gc_allocator() throw() {}
|
||||
|
||||
|
|
@ -133,7 +150,7 @@ public:
|
|||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
|
||||
void deallocate(pointer __p, size_type /* GC_n */)
|
||||
{ GC_FREE(__p); }
|
||||
|
||||
size_type max_size() const throw()
|
||||
|
|
@ -191,7 +208,7 @@ public:
|
|||
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>
|
||||
template <class GC_Tp1> GC_ATTR_EXPLICIT
|
||||
gc_allocator_ignore_off_page(const gc_allocator_ignore_off_page<GC_Tp1>&)
|
||||
throw() {}
|
||||
# endif
|
||||
|
|
@ -210,7 +227,7 @@ public:
|
|||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
|
||||
void deallocate(pointer __p, size_type /* GC_n */)
|
||||
{ GC_FREE(__p); }
|
||||
|
||||
size_type max_size() const throw()
|
||||
|
|
@ -271,8 +288,8 @@ public:
|
|||
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() {}
|
||||
template <class GC_Tp1> GC_ATTR_EXPLICIT
|
||||
traceable_allocator(const traceable_allocator<GC_Tp1>&) throw() {}
|
||||
# endif
|
||||
~traceable_allocator() throw() {}
|
||||
|
||||
|
|
@ -282,11 +299,14 @@ public:
|
|||
// 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)));
|
||||
void * obj = GC_MALLOC_UNCOLLECTABLE(GC_n * sizeof(GC_Tp));
|
||||
if (0 == obj)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return static_cast<GC_Tp*>(obj);
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n)
|
||||
void deallocate(pointer __p, size_type /* GC_n */)
|
||||
{ GC_FREE(__p); }
|
||||
|
||||
size_type max_size() const throw()
|
||||
|
|
|
|||
|
|
@ -64,7 +64,8 @@
|
|||
|
||||
#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_GNU_THREADS) \
|
||||
|| defined(GC_HAIKU_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) \
|
||||
|
|
@ -88,18 +89,22 @@
|
|||
# define GC_IRIX_THREADS
|
||||
# endif
|
||||
# if defined(__sparc) && !defined(__linux__) \
|
||||
|| defined(sun) && (defined(i386) || defined(__i386__) \
|
||||
|| defined(__amd64__))
|
||||
|| ((defined(sun) || defined(__sun)) \
|
||||
&& (defined(i386) || defined(__i386__) \
|
||||
|| defined(__amd64) || defined(__amd64__)))
|
||||
# define GC_SOLARIS_THREADS
|
||||
# elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define GC_DARWIN_THREADS
|
||||
# elif defined(__HAIKU__)
|
||||
# define GC_HAIKU_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__)
|
||||
# if defined(__FreeBSD__) || defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD_kernel__)
|
||||
# define GC_FREEBSD_THREADS
|
||||
# elif defined(__NetBSD__)
|
||||
# define GC_NETBSD_THREADS
|
||||
|
|
@ -172,7 +177,7 @@
|
|||
#if defined(GC_DLL) && !defined(GC_API)
|
||||
|
||||
# if defined(__MINGW32__) || defined(__CEGCC__)
|
||||
# ifdef GC_BUILD
|
||||
# if defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__)
|
||||
# define GC_API __declspec(dllexport)
|
||||
# else
|
||||
# define GC_API __declspec(dllimport)
|
||||
|
|
@ -202,8 +207,8 @@
|
|||
|
||||
# elif defined(__GNUC__)
|
||||
/* Only matters if used in conjunction with -fvisibility=hidden option. */
|
||||
# if defined(GC_BUILD) && (__GNUC__ >= 4 \
|
||||
|| defined(GC_VISIBILITY_HIDDEN_SET))
|
||||
# if defined(GC_BUILD) && !defined(GC_NO_VISIBILITY) \
|
||||
&& (__GNUC__ >= 4 || defined(GC_VISIBILITY_HIDDEN_SET))
|
||||
# define GC_API extern __attribute__((__visibility__("default")))
|
||||
# endif
|
||||
# endif
|
||||
|
|
@ -232,7 +237,7 @@
|
|||
# elif defined(__GNUC__) && (__GNUC__ > 3 \
|
||||
|| (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
# define GC_ATTR_MALLOC __attribute__((__malloc__))
|
||||
# elif defined(_MSC_VER) && _MSC_VER >= 14
|
||||
# elif defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
# define GC_ATTR_MALLOC __declspec(noalias) __declspec(restrict)
|
||||
# else
|
||||
# define GC_ATTR_MALLOC
|
||||
|
|
@ -270,7 +275,7 @@
|
|||
# define GC_ATTR_DEPRECATED /* empty */
|
||||
# elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
# define GC_ATTR_DEPRECATED __attribute__((__deprecated__))
|
||||
# elif defined(_MSC_VER) && _MSC_VER >= 12
|
||||
# elif defined(_MSC_VER) && _MSC_VER >= 1200
|
||||
# define GC_ATTR_DEPRECATED __declspec(deprecated)
|
||||
# else
|
||||
# define GC_ATTR_DEPRECATED /* empty */
|
||||
|
|
@ -287,7 +292,8 @@
|
|||
# include <features.h>
|
||||
# endif
|
||||
# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
|
||||
&& !defined(__ia64__) && !defined(__UCLIBC__) \
|
||||
&& !defined(__ia64__) \
|
||||
&& !defined(GC_MISSING_EXECINFO_H) \
|
||||
&& !defined(GC_HAVE_BUILTIN_BACKTRACE)
|
||||
# define GC_HAVE_BUILTIN_BACKTRACE
|
||||
# endif
|
||||
|
|
@ -319,7 +325,8 @@
|
|||
/* 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(__FreeBSD__) || defined(__DragonFly__) || defined(__HAIKU__) \
|
||||
|| defined(__FreeBSD_kernel__) \
|
||||
|| defined(PLATFORM_ANDROID) || defined(__ANDROID__)) \
|
||||
&& !defined(GC_CAN_SAVE_CALL_STACKS)
|
||||
# define GC_ADD_CALLER
|
||||
|
|
@ -329,6 +336,7 @@
|
|||
# define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
|
||||
# if (__GNUC__ >= 4) && (defined(__i386__) || defined(__amd64__) \
|
||||
|| defined(__x86_64__) /* and probably others... */)
|
||||
# define GC_HAVE_RETURN_ADDR_PARENT
|
||||
# define GC_RETURN_ADDR_PARENT \
|
||||
(GC_word)__builtin_extract_return_addr(__builtin_return_address(1))
|
||||
# endif
|
||||
|
|
@ -361,14 +369,16 @@
|
|||
# ifndef GC_PTHREAD_CREATE_CONST
|
||||
# define GC_PTHREAD_CREATE_CONST /* empty */
|
||||
# endif
|
||||
# ifndef GC_PTHREAD_EXIT_ATTRIBUTE
|
||||
# ifndef GC_HAVE_PTHREAD_EXIT
|
||||
# define GC_HAVE_PTHREAD_EXIT
|
||||
# define GC_PTHREAD_EXIT_ATTRIBUTE /* empty */
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(GC_PTHREAD_EXIT_ATTRIBUTE) \
|
||||
# if !defined(GC_HAVE_PTHREAD_EXIT) \
|
||||
&& !defined(PLATFORM_ANDROID) && !defined(__ANDROID__) \
|
||||
&& (defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS))
|
||||
# define GC_HAVE_PTHREAD_EXIT
|
||||
/* Intercept pthread_exit on Linux and Solaris. */
|
||||
# if defined(__GNUC__) /* since GCC v2.7 */
|
||||
# define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__))
|
||||
|
|
@ -379,7 +389,7 @@
|
|||
# endif
|
||||
# endif
|
||||
|
||||
# if (!defined(GC_PTHREAD_EXIT_ATTRIBUTE) || defined(__native_client__)) \
|
||||
# if (!defined(GC_HAVE_PTHREAD_EXIT) || 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
|
||||
|
|
|
|||
|
|
@ -149,91 +149,125 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
|
|||
#endif
|
||||
|
||||
#ifndef THINK_CPLUS
|
||||
# define GC_cdecl GC_CALLBACK
|
||||
# define GC_cdecl GC_CALLBACK
|
||||
#else
|
||||
# define GC_cdecl _cdecl
|
||||
# define GC_cdecl _cdecl
|
||||
#endif
|
||||
|
||||
#if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \
|
||||
#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(_MSC_VER) && _MSC_VER <= 1020) \
|
||||
|| (defined(__WATCOMC__) && __WATCOMC__ < 1050))
|
||||
# define GC_NO_OPERATOR_NEW_ARRAY
|
||||
# define GC_NO_OPERATOR_NEW_ARRAY
|
||||
#endif
|
||||
|
||||
#if !defined(GC_NO_OPERATOR_NEW_ARRAY) && !defined(GC_OPERATOR_NEW_ARRAY)
|
||||
# define GC_OPERATOR_NEW_ARRAY
|
||||
# define GC_OPERATOR_NEW_ARRAY
|
||||
#endif
|
||||
|
||||
#if (!defined(__BORLANDC__) || __BORLANDC__ > 0x0620) \
|
||||
&& ! defined ( __sgi ) && ! defined( __WATCOMC__ ) \
|
||||
&& ! defined (__sgi) && ! defined(__WATCOMC__) \
|
||||
&& (!defined(_MSC_VER) || _MSC_VER > 1020)
|
||||
# define GC_PLACEMENT_DELETE
|
||||
# define GC_PLACEMENT_DELETE
|
||||
#endif
|
||||
|
||||
#ifndef GC_DECL_DELETE_THROW
|
||||
# if defined(__DMC__) || (defined(__BORLANDC__) \
|
||||
&& (defined(_RWSTD_NO_EXCEPTIONS) || defined(_RWSTD_NO_EX_SPEC))) \
|
||||
|| (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) \
|
||||
|| (defined(__WATCOMC__) && !defined(_CPPUNWIND))
|
||||
# define GC_DECL_DELETE_THROW /* empty */
|
||||
# ifndef GC_NEW_ABORTS_ON_OOM
|
||||
# define GC_NEW_ABORTS_ON_OOM
|
||||
# endif
|
||||
# else
|
||||
# define GC_DECL_DELETE_THROW throw()
|
||||
# endif
|
||||
#endif // !GC_DECL_DELETE_THROW
|
||||
|
||||
#if defined(GC_NEW_ABORTS_ON_OOM) || defined(_LIBCPP_NO_EXCEPTIONS)
|
||||
# define GC_OP_NEW_OOM_CHECK(obj) \
|
||||
do { if (!(obj)) GC_abort_on_oom(); } while (0)
|
||||
#elif defined(GC_INCLUDE_NEW)
|
||||
# include <new> // for bad_alloc
|
||||
# define GC_OP_NEW_OOM_CHECK(obj) if (obj) {} else throw std::bad_alloc()
|
||||
#else
|
||||
// "new" header is not included, so bad_alloc cannot be thrown directly.
|
||||
GC_API void GC_CALL GC_throw_bad_alloc();
|
||||
# define GC_OP_NEW_OOM_CHECK(obj) if (obj) {} else GC_throw_bad_alloc()
|
||||
#endif // !GC_NEW_ABORTS_ON_OOM && !GC_INCLUDE_NEW
|
||||
|
||||
#ifdef GC_NAMESPACE
|
||||
namespace boehmgc
|
||||
{
|
||||
#endif
|
||||
|
||||
enum GCPlacement {
|
||||
enum GCPlacement
|
||||
{
|
||||
UseGC,
|
||||
# ifndef GC_NAME_CONFLICT
|
||||
GC=UseGC,
|
||||
GC = UseGC,
|
||||
# endif
|
||||
NoGC,
|
||||
PointerFreeGC
|
||||
# ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
, PointerFreeNoGC
|
||||
# endif
|
||||
};
|
||||
|
||||
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. */
|
||||
inline void operator delete( void* obj );
|
||||
# ifdef GC_PLACEMENT_DELETE
|
||||
inline void operator delete( void*, GCPlacement );
|
||||
/* called if construction fails. */
|
||||
inline void operator delete( void*, void* );
|
||||
# endif
|
||||
/**
|
||||
* Instances of classes derived from "gc" will be allocated in the collected
|
||||
* heap by default, unless an explicit NoGC placement is specified.
|
||||
*/
|
||||
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.
|
||||
inline void operator delete(void* obj);
|
||||
|
||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||
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 );
|
||||
inline void operator delete[]( void* obj );
|
||||
# ifdef GC_PLACEMENT_DELETE
|
||||
inline void operator delete(void*, GCPlacement);
|
||||
// Called if construction fails.
|
||||
inline void operator delete(void*, void*);
|
||||
# endif // GC_PLACEMENT_DELETE
|
||||
|
||||
# ifdef GC_OPERATOR_NEW_ARRAY
|
||||
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);
|
||||
inline void operator delete[](void* obj);
|
||||
# ifdef GC_PLACEMENT_DELETE
|
||||
inline void operator delete[]( void*, GCPlacement );
|
||||
inline void operator delete[]( void*, void* );
|
||||
inline void operator delete[](void*, GCPlacement);
|
||||
inline void operator delete[](void*, void*);
|
||||
# endif
|
||||
#endif /* GC_OPERATOR_NEW_ARRAY */
|
||||
# endif // GC_OPERATOR_NEW_ARRAY
|
||||
};
|
||||
/*
|
||||
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:
|
||||
inline gc_cleanup();
|
||||
inline virtual ~gc_cleanup();
|
||||
/**
|
||||
* Instances of classes derived from "gc_cleanup" will be allocated
|
||||
* in the collected heap by default. When the collector discovers
|
||||
* an inaccessible object derived from "gc_cleanup" or containing
|
||||
* a member derived from "gc_cleanup", its destructors will be invoked.
|
||||
*/
|
||||
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
|
||||
inaccessible object derived from "gc_cleanup" or containing a
|
||||
member derived from "gc_cleanup", its destructors will be
|
||||
invoked. */
|
||||
|
||||
extern "C" {
|
||||
typedef void (GC_CALLBACK * GCCleanUpFunc)( void* obj, void* clientData );
|
||||
typedef void (GC_CALLBACK * GCCleanUpFunc)(void* obj, void* clientData);
|
||||
}
|
||||
|
||||
#ifdef GC_NAMESPACE
|
||||
|
|
@ -244,193 +278,268 @@ extern "C" {
|
|||
// Disable warning that "no matching operator delete found; memory will
|
||||
// not be freed if initialization throws an exception"
|
||||
# pragma warning(disable:4291)
|
||||
// TODO: "non-member operator new or delete may not be declared inline"
|
||||
// warning is disabled for now.
|
||||
# pragma warning(disable:4595)
|
||||
#endif
|
||||
|
||||
inline void* operator new( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
|
||||
inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
|
||||
GC_NS_QUALIFY(GCCleanUpFunc) cleanup = 0,
|
||||
void* clientData = 0 );
|
||||
/*
|
||||
Allocates a collectible or uncollectible object, according to the
|
||||
value of "gcp".
|
||||
|
||||
For collectible objects, if "cleanup" is non-null, then when the
|
||||
allocated object "obj" becomes inaccessible, the collector will
|
||||
invoke the function "cleanup( obj, clientData )" but will not
|
||||
invoke the object's destructors. It is an error to explicitly
|
||||
delete an object allocated with a non-null "cleanup".
|
||||
|
||||
It is an error to specify a non-null "cleanup" with NoGC or for
|
||||
classes derived from "gc_cleanup" or containing members derived
|
||||
from "gc_cleanup". */
|
||||
void* clientData = 0);
|
||||
// Allocates a collectible or uncollectible object, according to the
|
||||
// value of "gcp".
|
||||
//
|
||||
// For collectible objects, if "cleanup" is non-null, then when the
|
||||
// allocated object "obj" becomes inaccessible, the collector will
|
||||
// invoke the function "cleanup(obj, clientData)" but will not
|
||||
// invoke the object's destructors. It is an error to explicitly
|
||||
// delete an object allocated with a non-null "cleanup".
|
||||
//
|
||||
// It is an error to specify a non-null "cleanup" with NoGC or for
|
||||
// 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 * );
|
||||
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 no way to redirect new in this environment without
|
||||
* including this everywhere.
|
||||
*/
|
||||
# if _MSC_VER > 1020
|
||||
void *operator new[]( size_t size );
|
||||
void operator delete[]( void* obj );
|
||||
#if defined(_MSC_VER) || defined(__DMC__)
|
||||
// The following ensures that the system default operator new[] does not
|
||||
// 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 no way to redirect new in this environment without
|
||||
// including this everywhere.
|
||||
// Inlining done to avoid mix up of new and delete operators by VC++ 9 (due
|
||||
// to arbitrary ordering during linking).
|
||||
|
||||
# ifdef GC_OPERATOR_NEW_ARRAY
|
||||
inline void* operator new[](size_t size)
|
||||
{
|
||||
void* obj = GC_MALLOC_UNCOLLECTABLE(size);
|
||||
GC_OP_NEW_OOM_CHECK(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
inline void operator delete[](void* obj)
|
||||
{
|
||||
GC_FREE(obj);
|
||||
}
|
||||
# endif
|
||||
|
||||
void* operator new( size_t size );
|
||||
void operator delete( void* obj );
|
||||
inline void* operator new(size_t size)
|
||||
{
|
||||
void* obj = GC_MALLOC_UNCOLLECTABLE(size);
|
||||
GC_OP_NEW_OOM_CHECK(obj);
|
||||
return 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 );
|
||||
#endif /* _MSC_VER */
|
||||
inline void operator delete(void* obj)
|
||||
{
|
||||
GC_FREE(obj);
|
||||
}
|
||||
|
||||
// This new operator is used by VC++ in case of Debug builds:
|
||||
# ifdef GC_DEBUG
|
||||
inline void* operator new(size_t size, int /* nBlockUse */,
|
||||
const char* szFileName, int nLine)
|
||||
{
|
||||
void* obj = GC_debug_malloc_uncollectable(size, szFileName, nLine);
|
||||
GC_OP_NEW_OOM_CHECK(obj);
|
||||
return obj;
|
||||
}
|
||||
# else
|
||||
inline void* operator new(size_t size, int /* nBlockUse */,
|
||||
const char* /* szFileName */, int /* nLine */)
|
||||
{
|
||||
void* obj = GC_malloc_uncollectable(size);
|
||||
GC_OP_NEW_OOM_CHECK(obj);
|
||||
return obj;
|
||||
}
|
||||
# endif /* !GC_DEBUG */
|
||||
|
||||
# ifdef GC_OPERATOR_NEW_ARRAY
|
||||
// This new operator is used by VC++ 7+ in Debug builds:
|
||||
inline void* operator new[](size_t size, int nBlockUse,
|
||||
const char* szFileName, int nLine)
|
||||
{
|
||||
return operator new(size, nBlockUse, szFileName, nLine);
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||
inline void* operator new[]( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
|
||||
// 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 */
|
||||
void* clientData = 0);
|
||||
#endif // GC_OPERATOR_NEW_ARRAY
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
Inline implementation
|
||||
|
||||
****************************************************************************/
|
||||
/* Inline implementation */
|
||||
|
||||
#ifdef GC_NAMESPACE
|
||||
namespace boehmgc
|
||||
{
|
||||
#endif
|
||||
|
||||
inline void* gc::operator new( size_t size ) {
|
||||
return GC_MALLOC( size );
|
||||
inline void* gc::operator new(size_t size)
|
||||
{
|
||||
void* obj = GC_MALLOC(size);
|
||||
GC_OP_NEW_OOM_CHECK(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
inline void* gc::operator new( size_t size, GCPlacement gcp ) {
|
||||
if (gcp == UseGC)
|
||||
return GC_MALLOC( size );
|
||||
else if (gcp == PointerFreeGC)
|
||||
return GC_MALLOC_ATOMIC( size );
|
||||
else
|
||||
return GC_MALLOC_UNCOLLECTABLE( size );
|
||||
inline void* gc::operator new(size_t size, GCPlacement gcp)
|
||||
{
|
||||
void* obj;
|
||||
switch (gcp) {
|
||||
case UseGC:
|
||||
obj = GC_MALLOC(size);
|
||||
break;
|
||||
case PointerFreeGC:
|
||||
obj = GC_MALLOC_ATOMIC(size);
|
||||
break;
|
||||
# ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
case PointerFreeNoGC:
|
||||
obj = GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
|
||||
break;
|
||||
# endif
|
||||
case NoGC:
|
||||
default:
|
||||
obj = GC_MALLOC_UNCOLLECTABLE(size);
|
||||
}
|
||||
GC_OP_NEW_OOM_CHECK(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
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 );
|
||||
inline void gc::operator delete(void* obj)
|
||||
{
|
||||
GC_FREE(obj);
|
||||
}
|
||||
|
||||
#ifdef GC_PLACEMENT_DELETE
|
||||
inline void gc::operator delete( void*, void* ) {}
|
||||
inline void gc::operator delete(void*, void*) {}
|
||||
|
||||
inline void gc::operator delete( void* p, GCPlacement /* gcp */ ) {
|
||||
inline void gc::operator delete(void* p, GCPlacement /* gcp */)
|
||||
{
|
||||
GC_FREE(p);
|
||||
}
|
||||
#endif
|
||||
#endif // GC_PLACEMENT_DELETE
|
||||
|
||||
#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 ) {
|
||||
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* ) {}
|
||||
inline void gc::operator delete[](void*, void*) {}
|
||||
|
||||
inline void gc::operator delete[]( void* p, GCPlacement /* gcp */ ) {
|
||||
inline void gc::operator delete[](void* p, GCPlacement /* gcp */)
|
||||
{
|
||||
gc::operator delete(p);
|
||||
}
|
||||
# endif
|
||||
#endif /* GC_OPERATOR_NEW_ARRAY */
|
||||
#endif // GC_OPERATOR_NEW_ARRAY
|
||||
|
||||
inline gc_cleanup::~gc_cleanup() {
|
||||
GC_register_finalizer_ignore_self( GC_base(this), 0, 0, 0, 0 );
|
||||
inline gc_cleanup::~gc_cleanup()
|
||||
{
|
||||
void* base = GC_base(this);
|
||||
if (0 == base) return; // Non-heap object.
|
||||
GC_register_finalizer_ignore_self(base, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
inline void GC_CALLBACK 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;
|
||||
void* oldData;
|
||||
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 );
|
||||
if (0 != oldProc) {
|
||||
GC_register_finalizer_ignore_self( base, oldProc, oldData, 0, 0 );
|
||||
}
|
||||
inline gc_cleanup::gc_cleanup()
|
||||
{
|
||||
GC_finalization_proc oldProc;
|
||||
void* oldData;
|
||||
void* this_ptr = (void*)this;
|
||||
void* base = GC_base(this_ptr);
|
||||
if (base != 0) {
|
||||
// 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_ptr - (char*)base),
|
||||
&oldProc, &oldData);
|
||||
if (oldProc != 0) {
|
||||
GC_register_finalizer_ignore_self(base, oldProc, oldData, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GC_NAMESPACE
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void* operator new( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
|
||||
inline void* operator new(size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
|
||||
GC_NS_QUALIFY(GCCleanUpFunc) cleanup,
|
||||
void* clientData )
|
||||
void* clientData)
|
||||
{
|
||||
void* obj;
|
||||
|
||||
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 == GC_NS_QUALIFY(PointerFreeGC)) {
|
||||
obj = GC_MALLOC_ATOMIC( size );
|
||||
} else {
|
||||
obj = GC_MALLOC_UNCOLLECTABLE( size );
|
||||
};
|
||||
return obj;
|
||||
void* obj;
|
||||
switch (gcp) {
|
||||
case GC_NS_QUALIFY(UseGC):
|
||||
obj = GC_MALLOC(size);
|
||||
if (cleanup != 0 && obj != 0) {
|
||||
GC_REGISTER_FINALIZER_IGNORE_SELF(obj, cleanup, clientData, 0, 0);
|
||||
}
|
||||
break;
|
||||
case GC_NS_QUALIFY(PointerFreeGC):
|
||||
obj = GC_MALLOC_ATOMIC(size);
|
||||
break;
|
||||
# ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
case GC_NS_QUALIFY(PointerFreeNoGC):
|
||||
obj = GC_MALLOC_ATOMIC_UNCOLLECTABLE(size);
|
||||
break;
|
||||
# endif
|
||||
case GC_NS_QUALIFY(NoGC):
|
||||
default:
|
||||
obj = GC_MALLOC_UNCOLLECTABLE(size);
|
||||
}
|
||||
GC_OP_NEW_OOM_CHECK(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
#ifdef GC_PLACEMENT_DELETE
|
||||
inline void operator delete( void *p, GC_NS_QUALIFY(GCPlacement) /* gcp */,
|
||||
inline void operator delete(void* p, GC_NS_QUALIFY(GCPlacement) /* gcp */,
|
||||
GC_NS_QUALIFY(GCCleanUpFunc) /* cleanup */,
|
||||
void* /* clientData */ )
|
||||
void* /* clientData */)
|
||||
{
|
||||
GC_FREE(p);
|
||||
}
|
||||
#endif /* GC_PLACEMENT_DELETE */
|
||||
#endif // GC_PLACEMENT_DELETE
|
||||
|
||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||
inline void* operator new[]( size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
|
||||
inline void* operator new[](size_t size, GC_NS_QUALIFY(GCPlacement) gcp,
|
||||
GC_NS_QUALIFY(GCCleanUpFunc) cleanup,
|
||||
void* clientData )
|
||||
void* clientData)
|
||||
{
|
||||
return ::operator new( size, gcp, cleanup, 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_OPERATOR_NEW_ARRAY
|
||||
|
||||
#endif /* GC_CPP_H */
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ struct GC_finalizer_closure {
|
|||
/* 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. */
|
||||
/* Note that GC_size (applied to such allocated object) returns a value */
|
||||
/* slightly bigger than the specified allocation size, and that GC_base */
|
||||
/* result points to a word prior to the start of the allocated object. */
|
||||
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*/);
|
||||
|
|
|
|||
|
|
@ -42,12 +42,34 @@
|
|||
# define GC_ASSERT(expr) /* empty */
|
||||
#endif
|
||||
|
||||
#ifndef GC_PREFETCH_FOR_WRITE
|
||||
# define GC_PREFETCH_FOR_WRITE(x) (void)0
|
||||
#endif
|
||||
|
||||
/* Object kinds; must match PTRFREE, NORMAL in gc_priv.h. */
|
||||
#define GC_I_PTRFREE 0
|
||||
#define GC_I_NORMAL 1
|
||||
|
||||
/* 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 */);
|
||||
|
||||
/* Generalized version of GC_malloc and GC_malloc_atomic. */
|
||||
/* Uses appropriately the thread-local (if available) or the global */
|
||||
/* free-list of the specified kind. */
|
||||
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||
GC_malloc_kind(size_t /* lb */, int /* k */);
|
||||
|
||||
#ifdef GC_THREADS
|
||||
/* Same as above but uses only the global free-list. */
|
||||
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||
GC_malloc_kind_global(size_t /* lb */, int /* k */);
|
||||
#else
|
||||
# define GC_malloc_kind_global GC_malloc_kind
|
||||
#endif
|
||||
|
||||
/* 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 */
|
||||
|
|
@ -56,17 +78,17 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
|
|||
/* 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. */
|
||||
/* are initialized to (void *)1, then we allocate num_direct granules */
|
||||
/* directly using generic_malloc 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,\
|
||||
# define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct, \
|
||||
kind,default_expr,init) \
|
||||
do { \
|
||||
if (GC_EXPECT((granules) >= GC_TINY_FREELISTS,0)) { \
|
||||
|
|
@ -76,14 +98,31 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
|
|||
void *my_entry=*my_fl; \
|
||||
void *next; \
|
||||
\
|
||||
while (GC_EXPECT((GC_word)my_entry \
|
||||
<= (num_direct) + GC_TINY_FREELISTS + 1, 0)) { \
|
||||
for (;;) { \
|
||||
if (GC_EXPECT((GC_word)my_entry \
|
||||
> (num_direct) + GC_TINY_FREELISTS + 1, 1)) { \
|
||||
next = *(void **)(my_entry); \
|
||||
result = (void *)my_entry; \
|
||||
*my_fl = next; \
|
||||
init; \
|
||||
GC_PREFETCH_FOR_WRITE(next); \
|
||||
if ((kind) != GC_I_PTRFREE) { \
|
||||
GC_end_stubborn_change(my_fl); \
|
||||
GC_reachable_here(next); \
|
||||
} \
|
||||
GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
|
||||
GC_ASSERT((kind) == GC_I_PTRFREE \
|
||||
|| ((GC_word *)result)[1] == 0); \
|
||||
break; \
|
||||
} \
|
||||
/* Entry contains counter or NULL */ \
|
||||
if ((GC_word)my_entry - 1 < (num_direct)) { \
|
||||
if ((GC_signed_word)my_entry - (GC_signed_word)(num_direct) <= 0 \
|
||||
/* (GC_word)my_entry <= (num_direct) */ \
|
||||
&& my_entry != 0 /* NULL */) { \
|
||||
/* Small counter value, not NULL */ \
|
||||
*my_fl = (char *)my_entry + (granules) + 1; \
|
||||
result = (default_expr); \
|
||||
goto out; \
|
||||
break; \
|
||||
} else { \
|
||||
/* Large counter or NULL */ \
|
||||
GC_generic_malloc_many(((granules) == 0? GC_GRANULE_BYTES : \
|
||||
|
|
@ -92,18 +131,10 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
|
|||
my_entry = *my_fl; \
|
||||
if (my_entry == 0) { \
|
||||
result = (*GC_get_oom_fn())((granules)*GC_GRANULE_BYTES); \
|
||||
goto out; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
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: ; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
|
@ -117,30 +148,37 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t /* lb */, int /* k */,
|
|||
/* 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_KIND(result,n,tiny_fl,k,init) \
|
||||
do { \
|
||||
size_t grans = GC_WORDS_TO_WHOLE_GRANULES(n); \
|
||||
GC_FAST_MALLOC_GRANS(result, grans, tiny_fl, 0, k, \
|
||||
GC_malloc_kind(grans * GC_GRANULE_BYTES, k), \
|
||||
init); \
|
||||
} while (0)
|
||||
|
||||
# define GC_MALLOC_WORDS(result,n,tiny_fl) \
|
||||
do { \
|
||||
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); \
|
||||
} while (0)
|
||||
GC_MALLOC_WORDS_KIND(result, n, tiny_fl, GC_I_NORMAL, \
|
||||
*(void **)(result) = 0)
|
||||
|
||||
# define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
|
||||
do { \
|
||||
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 */); \
|
||||
} while (0)
|
||||
GC_MALLOC_WORDS_KIND(result, n, tiny_fl, GC_I_PTRFREE, (void)0)
|
||||
|
||||
/* And once more for two word initialized objects: */
|
||||
# define GC_CONS(result, first, second, tiny_fl) \
|
||||
do { \
|
||||
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); \
|
||||
} while (0)
|
||||
do { \
|
||||
void *l = (void *)(first); \
|
||||
void *r = (void *)(second); \
|
||||
GC_MALLOC_WORDS_KIND(result, 2, tiny_fl, GC_I_NORMAL, (void)0); \
|
||||
if ((result) != 0 /* NULL */) { \
|
||||
*(void **)(result) = l; \
|
||||
((void **)(result))[1] = r; \
|
||||
GC_end_stubborn_change(result); \
|
||||
GC_reachable_here(l); \
|
||||
GC_reachable_here(r); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
GC_API void GC_CALL GC_print_free_list(int /* kind */,
|
||||
size_t /* sz_in_granules */);
|
||||
|
||||
#endif /* !GC_INLINE_H */
|
||||
|
|
|
|||
|
|
@ -101,10 +101,10 @@ typedef struct GC_ms_entry * (*GC_mark_proc)(GC_word * /* addr */,
|
|||
| (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 */
|
||||
/* object given by descr & ~GC_DS_TAGS. */
|
||||
/* If the descriptor is negative, the real */
|
||||
/* descriptor is at (*<object_start>) - */
|
||||
/* (descr & ~DS_TAGS) - GC_INDIR_PER_OBJ_BIAS */
|
||||
/* (descr&~GC_DS_TAGS) - GC_INDIR_PER_OBJ_BIAS */
|
||||
/* The latter alternative can be used if each */
|
||||
/* object contains a type descriptor in the */
|
||||
/* first word. */
|
||||
|
|
@ -184,7 +184,7 @@ 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. By default, there are only */
|
||||
/* a few kinds: composite (pointer-free), atomic, uncollectible, etc. */
|
||||
/* a few kinds: composite (pointerful), atomic, uncollectible, etc. */
|
||||
/* We claim it is possible for clever client code that understands the */
|
||||
/* GC internals to add more, e.g. to communicate object layout */
|
||||
/* information to the collector. Note that in the multi-threaded */
|
||||
|
|
@ -204,6 +204,11 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
|||
/* first page of the resulting object */
|
||||
/* are ignored. */
|
||||
|
||||
/* Generalized version of GC_malloc_[atomic_]uncollectable. */
|
||||
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
|
||||
GC_generic_malloc_uncollectable(
|
||||
size_t /* lb */, int /* knd */);
|
||||
|
||||
/* Same as above but primary for allocating an object of the same kind */
|
||||
/* as an existing one (kind obtained by GC_get_kind_and_size). */
|
||||
/* Not suitable for GCJ and typed-malloc kinds. */
|
||||
|
|
@ -274,10 +279,13 @@ 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.) */
|
||||
/* on the third argument.) GC_push_all_eager also ensures that stack */
|
||||
/* is scanned immediately, not just scheduled for scanning. */
|
||||
GC_API void GC_CALL GC_push_all(char * /* bottom */, char * /* top */);
|
||||
GC_API void GC_CALL GC_push_all_eager(char * /* bottom */, char * /* top */);
|
||||
GC_API void GC_CALL GC_push_conditional(char * /* bottom */, char * /* top */,
|
||||
int /* bool all */);
|
||||
GC_API void GC_CALL GC_push_finalizer_structures(void);
|
||||
|
||||
/* Set and get the client push-other-roots procedure. A client */
|
||||
/* supplied procedure should also call the original procedure. */
|
||||
|
|
@ -287,6 +295,21 @@ 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);
|
||||
|
||||
/* Walk the GC heap visiting all reachable objects. Assume the caller */
|
||||
/* holds the allocation lock. Object base pointer, object size and */
|
||||
/* client custom data are passed to the callback (holding the lock). */
|
||||
typedef void (GC_CALLBACK *GC_reachable_object_proc)(void * /* obj */,
|
||||
size_t /* bytes */,
|
||||
void * /* client_data */);
|
||||
GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
|
||||
GC_reachable_object_proc,
|
||||
void * /* client_data */) GC_ATTR_NONNULL(1);
|
||||
|
||||
GC_API int GC_CALL GC_is_tmp_root(void *);
|
||||
|
||||
GC_API void GC_CALL GC_print_trace(GC_word /* gc_no */);
|
||||
GC_API void GC_CALL GC_print_trace_inner(GC_word /* gc_no */);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,15 +33,23 @@
|
|||
#ifndef GC_PTHREAD_REDIRECTS_ONLY
|
||||
# include <pthread.h>
|
||||
|
||||
# ifndef GC_SUSPEND_THREAD_ID
|
||||
# define GC_SUSPEND_THREAD_ID pthread_t
|
||||
# endif
|
||||
|
||||
# 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>
|
||||
GC_API int GC_pthread_sigmask(int /* how */, const sigset_t *,
|
||||
sigset_t * /* oset */);
|
||||
# include <signal.h> /* needed anyway for proper redirection */
|
||||
# if defined(GC_PTHREAD_SIGMASK_NEEDED) \
|
||||
|| defined(_BSD_SOURCE) || defined(_GNU_SOURCE) \
|
||||
|| (_POSIX_C_SOURCE >= 199506L) || (_XOPEN_SOURCE >= 500)
|
||||
GC_API int GC_pthread_sigmask(int /* how */, const sigset_t *,
|
||||
sigset_t * /* oset */);
|
||||
# endif
|
||||
# endif /* !GC_NO_PTHREAD_SIGMASK */
|
||||
|
||||
# ifndef GC_PTHREAD_CREATE_CONST
|
||||
|
|
@ -59,7 +67,7 @@
|
|||
GC_API int GC_pthread_cancel(pthread_t);
|
||||
# endif
|
||||
|
||||
# if defined(GC_PTHREAD_EXIT_ATTRIBUTE) && !defined(GC_PTHREAD_EXIT_DECLARED)
|
||||
# if defined(GC_HAVE_PTHREAD_EXIT) && !defined(GC_PTHREAD_EXIT_DECLARED)
|
||||
# define GC_PTHREAD_EXIT_DECLARED
|
||||
GC_API void GC_pthread_exit(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
|
||||
# endif
|
||||
|
|
@ -88,7 +96,7 @@
|
|||
# undef pthread_cancel
|
||||
# define pthread_cancel GC_pthread_cancel
|
||||
# endif
|
||||
# ifdef GC_PTHREAD_EXIT_ATTRIBUTE
|
||||
# ifdef GC_HAVE_PTHREAD_EXIT
|
||||
# undef pthread_exit
|
||||
# define pthread_exit GC_pthread_exit
|
||||
# endif
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ typedef GC_word * GC_bitmap;
|
|||
typedef GC_word GC_descr;
|
||||
|
||||
GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * /* GC_bitmap bm */,
|
||||
size_t /* len */);
|
||||
size_t /* len (number_of_bits_in_bitmap) */);
|
||||
/* Return a type descriptor for the object whose layout */
|
||||
/* is described by the argument. */
|
||||
/* The least significant bit of the first word is one */
|
||||
|
|
@ -81,8 +81,10 @@ 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. */
|
||||
/* The size may NOT be less than the number of */
|
||||
/* meaningful bits in the bitmap of d multiplied by */
|
||||
/* sizeof GC_word. The returned object is cleared. */
|
||||
/* The returned object may NOT be passed to GC_realloc. */
|
||||
|
||||
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 */,
|
||||
|
|
@ -97,7 +99,9 @@ GC_API GC_ATTR_MALLOC void * GC_CALL
|
|||
/* 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. */
|
||||
/* must be a multiple of 2. The element size may NOT */
|
||||
/* be less than the number of meaningful bits in the */
|
||||
/* bitmap of d multiplied by sizeof GC_word. */
|
||||
/* Returned object is cleared. */
|
||||
|
||||
#ifdef GC_DEBUG
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@
|
|||
/* 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 5
|
||||
#define GC_TMP_VERSION_MICRO 0 /* 7.5.0 */
|
||||
#define GC_TMP_VERSION_MINOR 6
|
||||
#define GC_TMP_VERSION_MICRO 8 /* 7.6.8 */
|
||||
|
||||
#ifdef GC_VERSION_MAJOR
|
||||
# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR \
|
||||
|
|
|
|||
|
|
@ -33,13 +33,28 @@
|
|||
* 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.
|
||||
* 1) It may mean that we get stuck in an infinite loop running
|
||||
* 2) It may mean that we get stuck in an infinite loop running
|
||||
* finalizers which create new finalizable objects, though that's
|
||||
* probably unlikely.
|
||||
* Thus this is not recommended for general use.
|
||||
*/
|
||||
GC_API void GC_CALL GC_finalize_all(void);
|
||||
|
||||
#ifdef GC_THREADS
|
||||
/* External thread suspension support. No thread suspension count */
|
||||
/* (so a thread which has been suspended numerous times will be */
|
||||
/* resumed with the very first call to GC_resume_thread). */
|
||||
/* Acquire the allocation lock. Thread should be registered in GC */
|
||||
/* (otherwise no-op, GC_is_thread_suspended returns false). */
|
||||
/* Unimplemented on some platforms. Not recommended for general use. */
|
||||
# ifndef GC_SUSPEND_THREAD_ID
|
||||
# define GC_SUSPEND_THREAD_ID void*
|
||||
# endif
|
||||
GC_API void GC_CALL GC_suspend_thread(GC_SUSPEND_THREAD_ID);
|
||||
GC_API void GC_CALL GC_resume_thread(GC_SUSPEND_THREAD_ID);
|
||||
GC_API int GC_CALL GC_is_thread_suspended(GC_SUSPEND_THREAD_ID);
|
||||
#endif /* GC_THREADS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@
|
|||
*/
|
||||
|
||||
//
|
||||
// This is a revision of gc_alloc.h for SGI STL versions > 3.0
|
||||
// Unlike earlier versions, it supplements the standard "alloc.h"
|
||||
// This is a revision of gc_allocator.h for SGI STL versions > 3.0.
|
||||
// Unlike earlier versions, it supplements the standard (STL) alloc.h
|
||||
// instead of replacing it.
|
||||
//
|
||||
// This is sloppy about variable names used in header files.
|
||||
// It also doesn't yet understand the new header file names or
|
||||
// namespaces.
|
||||
//
|
||||
// This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE.
|
||||
// This assumes the collector has been compiled with -DGC_ATOMIC_UNCOLLECTABLE.
|
||||
// The user should also consider -DREDIRECT_MALLOC=GC_uncollectable_malloc,
|
||||
// to ensure that object allocated through malloc are traced.
|
||||
//
|
||||
|
|
@ -85,11 +85,13 @@ extern "C" {
|
|||
|
||||
GC_API void GC_CALL GC_incr_bytes_allocd(size_t bytes);
|
||||
GC_API void GC_CALL GC_incr_bytes_freed(size_t bytes);
|
||||
|
||||
GC_API char * GC_CALL GC_generic_malloc_words_small(size_t word, int kind);
|
||||
/* FIXME: Doesn't exist anymore. */
|
||||
}
|
||||
|
||||
#define GC_generic_malloc_words_small(lw, k) \
|
||||
GC_generic_malloc((lw) * sizeof(GC_word), k)
|
||||
|
||||
#define GC_ALLOCATOR_THROW_OR_ABORT() GC_abort_on_oom()
|
||||
|
||||
// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
|
||||
// AUNCOLLECTABLE in gc_priv.h.
|
||||
|
||||
|
|
@ -98,11 +100,15 @@ enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
|
|||
|
||||
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 };
|
||||
#if defined(CPPCHECK)
|
||||
const unsigned GC_bytes_per_word = sizeof(char *);
|
||||
const unsigned GC_word_alignment = GC_byte_alignment/GC_bytes_per_word;
|
||||
#else
|
||||
enum { GC_bytes_per_word = sizeof(char *) };
|
||||
enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
|
||||
#endif
|
||||
|
||||
inline void * &GC_obj_link(void * p)
|
||||
{ return *reinterpret_cast<void **>(p); }
|
||||
|
|
@ -156,6 +162,10 @@ 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)
|
||||
{
|
||||
void * op = GC_generic_malloc_words_small(nwords, kind);
|
||||
if (0 == op)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
|
||||
GC_bytes_recently_allocd += GC_uncollectable_bytes_recently_allocd;
|
||||
GC_non_gc_bytes +=
|
||||
GC_uncollectable_bytes_recently_allocd;
|
||||
|
|
@ -170,8 +180,7 @@ void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
|
|||
|
||||
GC_incr_bytes_freed(GC_bytes_recently_freed);
|
||||
GC_bytes_recently_freed = 0;
|
||||
|
||||
return GC_generic_malloc_words_small(nwords, kind);
|
||||
return op;
|
||||
}
|
||||
|
||||
typedef GC_aux_template<0> GC_aux;
|
||||
|
|
@ -189,9 +198,15 @@ class single_client_gc_alloc_template {
|
|||
void ** flh;
|
||||
void * op;
|
||||
|
||||
if (n > GC_max_fast_bytes) return GC_malloc(n);
|
||||
flh = GC_objfreelist_ptr + nwords;
|
||||
if (0 == (op = *flh)) {
|
||||
if (n > GC_max_fast_bytes) {
|
||||
op = GC_malloc(n);
|
||||
if (0 == op)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return op;
|
||||
}
|
||||
flh = &GC_objfreelist_ptr[nwords];
|
||||
op = *flh;
|
||||
if (0 == op) {
|
||||
return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
|
||||
}
|
||||
*flh = GC_obj_link(op);
|
||||
|
|
@ -204,9 +219,15 @@ class single_client_gc_alloc_template {
|
|||
void ** flh;
|
||||
void * op;
|
||||
|
||||
if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
|
||||
flh = GC_aobjfreelist_ptr + nwords;
|
||||
if (0 == (op = *flh)) {
|
||||
if (n > GC_max_fast_bytes) {
|
||||
op = GC_malloc_atomic(n);
|
||||
if (0 == op)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return op;
|
||||
}
|
||||
flh = &GC_aobjfreelist_ptr[nwords];
|
||||
op = *flh;
|
||||
if (0 == op) {
|
||||
return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
|
||||
}
|
||||
*flh = GC_obj_link(op);
|
||||
|
|
@ -215,13 +236,12 @@ class single_client_gc_alloc_template {
|
|||
}
|
||||
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;
|
||||
size_t nwords = GC_round_up(n);
|
||||
void ** 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));
|
||||
|
|
@ -231,13 +251,12 @@ class single_client_gc_alloc_template {
|
|||
}
|
||||
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;
|
||||
size_t nwords = GC_round_up(n);
|
||||
void ** flh = &GC_aobjfreelist_ptr[nwords];
|
||||
|
||||
GC_obj_link(p) = *flh;
|
||||
*flh = p;
|
||||
GC_aux::GC_bytes_recently_freed += nwords * GC_bytes_per_word;
|
||||
|
|
@ -257,9 +276,15 @@ class single_client_traceable_alloc_template {
|
|||
void ** flh;
|
||||
void * op;
|
||||
|
||||
if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
|
||||
flh = GC_uobjfreelist_ptr + nwords;
|
||||
if (0 == (op = *flh)) {
|
||||
if (n > GC_max_fast_bytes) {
|
||||
op = GC_malloc_uncollectable(n);
|
||||
if (0 == op)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return op;
|
||||
}
|
||||
flh = &GC_uobjfreelist_ptr[nwords];
|
||||
op = *flh;
|
||||
if (0 == op) {
|
||||
return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
|
||||
}
|
||||
*flh = GC_obj_link(op);
|
||||
|
|
@ -273,9 +298,15 @@ class single_client_traceable_alloc_template {
|
|||
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)) {
|
||||
if (n > GC_max_fast_bytes) {
|
||||
op = GC_malloc_atomic_uncollectable(n);
|
||||
if (0 == op)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return op;
|
||||
}
|
||||
flh = &GC_auobjfreelist_ptr[nwords];
|
||||
op = *flh;
|
||||
if (0 == op) {
|
||||
return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
|
||||
}
|
||||
*flh = GC_obj_link(op);
|
||||
|
|
@ -285,13 +316,12 @@ class single_client_traceable_alloc_template {
|
|||
}
|
||||
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;
|
||||
size_t nwords = GC_round_up_uncollectable(n);
|
||||
void ** flh = &GC_uobjfreelist_ptr[nwords];
|
||||
|
||||
GC_obj_link(p) = *flh;
|
||||
*flh = p;
|
||||
GC_aux::GC_uncollectable_bytes_recently_freed +=
|
||||
|
|
@ -300,13 +330,12 @@ class single_client_traceable_alloc_template {
|
|||
}
|
||||
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;
|
||||
size_t nwords = GC_round_up_uncollectable(n);
|
||||
void ** flh = &GC_auobjfreelist_ptr[nwords];
|
||||
|
||||
GC_obj_link(p) = *flh;
|
||||
*flh = p;
|
||||
GC_aux::GC_uncollectable_bytes_recently_freed +=
|
||||
|
|
@ -320,9 +349,18 @@ 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 * allocate(size_t n) {
|
||||
void * op = GC_malloc(n);
|
||||
if (0 == op)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return op;
|
||||
}
|
||||
static void * ptr_free_allocate(size_t n) {
|
||||
void * op = GC_malloc_atomic(n);
|
||||
if (0 == op)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return op;
|
||||
}
|
||||
static void deallocate(void *, size_t) { }
|
||||
static void ptr_free_deallocate(void *, size_t) { }
|
||||
};
|
||||
|
|
@ -332,9 +370,18 @@ 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 * allocate(size_t n) {
|
||||
void * op = GC_malloc_uncollectable(n);
|
||||
if (0 == op)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return op;
|
||||
}
|
||||
static void * ptr_free_allocate(size_t n) {
|
||||
void * op = GC_malloc_atomic_uncollectable(n);
|
||||
if (0 == op)
|
||||
GC_ALLOCATOR_THROW_OR_ABORT();
|
||||
return op;
|
||||
}
|
||||
static void deallocate(void *p, size_t) { GC_free(p); }
|
||||
static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
|
||||
};
|
||||
|
|
@ -351,12 +398,12 @@ typedef traceable_alloc_template < 0 > traceable_alloc;
|
|||
class simple_alloc<T, alloc> { \
|
||||
public: \
|
||||
static T *allocate(size_t n) \
|
||||
{ return 0 == n? 0 : \
|
||||
reinterpret_cast<T*>(alloc::ptr_free_allocate(n * sizeof(T))); } \
|
||||
{ reinterpret_cast<T*>(alloc::ptr_free_allocate(0 == n ? 1 \
|
||||
: n * sizeof(T))); } \
|
||||
static T *allocate(void) \
|
||||
{ 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)); } \
|
||||
{ alloc::ptr_free_deallocate(p, 0 == n ? 1 : n * sizeof(T)); } \
|
||||
static void deallocate(T *p) \
|
||||
{ alloc::ptr_free_deallocate(p, sizeof(T)); } \
|
||||
};
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ typedef struct {
|
|||
/* 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))
|
||||
# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(~1 & (word)(p))
|
||||
# else
|
||||
# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(p)
|
||||
# endif
|
||||
|
|
@ -121,8 +121,7 @@ typedef struct {
|
|||
#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. */
|
||||
/* header; it should be called with the allocation lock held. */
|
||||
/* 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)
|
||||
|
|
@ -157,6 +156,10 @@ typedef struct {
|
|||
#endif
|
||||
|
||||
#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
|
||||
# ifdef SHORT_DBG_HDRS
|
||||
# error Non-ptr stored in object results in GC_HAS_DEBUG_INFO malfunction
|
||||
/* We may mistakenly conclude that p has a debugging wrapper. */
|
||||
# endif
|
||||
# define GC_HAS_DEBUG_INFO(p) \
|
||||
((*((word *)p) & 1) && GC_has_other_debug_info(p) > 0)
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
typedef struct hblkhdr hdr;
|
||||
|
||||
#if CPP_WORDSZ != 32 && CPP_WORDSZ < 36
|
||||
--> Get a real machine.
|
||||
# error Get a real machine
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -98,22 +98,21 @@ typedef struct 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. */
|
||||
/* except that in the case of large objects, it gets the header for */
|
||||
/* the object beginning if GC_all_interior_pointers 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) \
|
||||
do { \
|
||||
#define HC_GET_HDR(p, hhdr, source) \
|
||||
{ /* cannot use do-while(0) here */ \
|
||||
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; \
|
||||
if (NULL == hhdr) break; /* go to the enclosing loop end */ \
|
||||
} \
|
||||
} while (0)
|
||||
}
|
||||
|
||||
typedef struct bi {
|
||||
hdr * index[BOTTOM_SZ];
|
||||
|
|
|
|||
|
|
@ -36,8 +36,12 @@
|
|||
# include <base/PCR_Base.h>
|
||||
# include <th/PCR_Th.h>
|
||||
GC_EXTERN PCR_Th_ML GC_allocate_ml;
|
||||
# define DCL_LOCK_STATE \
|
||||
# if defined(CPPCHECK)
|
||||
# define DCL_LOCK_STATE /* empty */
|
||||
# else
|
||||
# define DCL_LOCK_STATE \
|
||||
PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
|
||||
# endif
|
||||
# define UNCOND_LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
|
||||
# define UNCOND_UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
|
||||
# endif
|
||||
|
|
@ -99,7 +103,7 @@
|
|||
# define NUMERIC_THREAD_ID_UNIQUE
|
||||
# endif
|
||||
# else /* pthreads-win32 */
|
||||
# define NUMERIC_THREAD_ID(id) ((unsigned long)(id.p))
|
||||
# define NUMERIC_THREAD_ID(id) ((unsigned long)(word)(id.p))
|
||||
/* Using documented internal details of pthreads-win32 library. */
|
||||
/* Faster than pthread_equal(). Should not change with */
|
||||
/* future versions of pthreads-win32 library. */
|
||||
|
|
@ -133,8 +137,7 @@
|
|||
AO_CLEAR(&GC_allocate_lock); }
|
||||
# else
|
||||
# define UNCOND_LOCK() \
|
||||
{ GC_ASSERT(I_DONT_HOLD_LOCK()); \
|
||||
if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
|
||||
{ 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 */
|
||||
|
|
@ -154,11 +157,7 @@
|
|||
pthread_mutex_unlock(&GC_allocate_ml); }
|
||||
# else /* !GC_ASSERTIONS */
|
||||
# if defined(NO_PTHREAD_TRYLOCK)
|
||||
# ifdef USE_SPIN_LOCK
|
||||
# define UNCOND_LOCK() GC_lock()
|
||||
# else
|
||||
# define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml)
|
||||
# endif
|
||||
# define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml)
|
||||
# else
|
||||
# define UNCOND_LOCK() \
|
||||
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) \
|
||||
|
|
@ -183,15 +182,25 @@
|
|||
|| GC_lock_holder != NUMERIC_THREAD_ID(pthread_self()))
|
||||
# endif
|
||||
# endif /* GC_ASSERTIONS */
|
||||
GC_EXTERN volatile GC_bool GC_collecting;
|
||||
# define ENTER_GC() GC_collecting = 1;
|
||||
# define EXIT_GC() GC_collecting = 0;
|
||||
# ifndef GC_WIN32_THREADS
|
||||
GC_EXTERN volatile GC_bool GC_collecting;
|
||||
# define ENTER_GC() (void)(GC_collecting = TRUE)
|
||||
# define EXIT_GC() (void)(GC_collecting = FALSE)
|
||||
# endif
|
||||
GC_INNER void GC_lock(void);
|
||||
# endif /* GC_PTHREADS with linux_threads.c implementation */
|
||||
# ifdef GC_ALWAYS_MULTITHREADED
|
||||
# endif /* GC_PTHREADS */
|
||||
# if defined(GC_ALWAYS_MULTITHREADED) \
|
||||
&& (defined(USE_PTHREAD_LOCKS) || defined(USE_SPIN_LOCK))
|
||||
# define GC_need_to_lock TRUE
|
||||
# define set_need_to_lock() (void)0
|
||||
# else
|
||||
# if defined(GC_ALWAYS_MULTITHREADED) && !defined(CPPCHECK)
|
||||
# error Runtime initialization of GC lock is needed!
|
||||
# endif
|
||||
# undef GC_ALWAYS_MULTITHREADED
|
||||
GC_EXTERN GC_bool GC_need_to_lock;
|
||||
# define set_need_to_lock() (void)(GC_need_to_lock = TRUE)
|
||||
/* We are multi-threaded now. */
|
||||
# endif
|
||||
|
||||
# else /* !THREADS */
|
||||
|
|
@ -207,7 +216,8 @@
|
|||
# endif /* !THREADS */
|
||||
|
||||
#if defined(UNCOND_LOCK) && !defined(LOCK)
|
||||
# if defined(LINT2) || defined(GC_ALWAYS_MULTITHREADED)
|
||||
# if (defined(LINT2) && defined(USE_PTHREAD_LOCKS)) \
|
||||
|| defined(GC_ALWAYS_MULTITHREADED)
|
||||
/* Instruct code analysis tools not to care about GC_need_to_lock */
|
||||
/* influence to LOCK/UNLOCK semantic. */
|
||||
# define LOCK() UNCOND_LOCK()
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#ifndef GC_PMARK_H
|
||||
#define GC_PMARK_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#if defined(HAVE_CONFIG_H) && !defined(GC_PRIVATE_H)
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
|
|
@ -30,6 +30,12 @@
|
|||
# define GC_BUILD
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \
|
||||
&& !defined(_GNU_SOURCE) && defined(GC_PTHREADS) \
|
||||
&& !defined(GC_NO_PTHREAD_SIGMASK)
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST)
|
||||
# include "dbg_mlc.h"
|
||||
#endif
|
||||
|
|
@ -130,57 +136,54 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
|
|||
|
||||
/* 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) \
|
||||
#define PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, source) \
|
||||
do { \
|
||||
hdr * my_hhdr; \
|
||||
HC_GET_HDR(current, my_hhdr, source, exit_label); \
|
||||
HC_GET_HDR(current, my_hhdr, source); /* contains "break" */ \
|
||||
PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
|
||||
source, exit_label, my_hhdr, TRUE); \
|
||||
exit_label: ; \
|
||||
source, my_hhdr, TRUE); \
|
||||
} while (0)
|
||||
|
||||
/* Set mark bit, exit if it was already set. */
|
||||
/* Set mark bit, exit (using "break" statement) if it is 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) \
|
||||
do { \
|
||||
# define SET_MARK_BIT_EXIT_IF_SET(hhdr, bit_no) \
|
||||
{ /* cannot use do-while(0) here */ \
|
||||
char * mark_byte_addr = (char *)hhdr -> hb_marks + (bit_no); \
|
||||
if (*mark_byte_addr) goto exit_label; \
|
||||
if (*mark_byte_addr != 0) break; /* go to the enclosing loop end */ \
|
||||
*mark_byte_addr = 1; \
|
||||
} while (0)
|
||||
}
|
||||
#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) \
|
||||
do { \
|
||||
# define OR_WORD_EXIT_IF_SET(addr, bits) \
|
||||
{ /* cannot use do-while(0) here */ \
|
||||
if (!(*(addr) & (bits))) { \
|
||||
AO_or((volatile AO_t *)(addr), (AO_t)(bits)); \
|
||||
} else { \
|
||||
goto exit_label; \
|
||||
break; /* go to the enclosing loop end */ \
|
||||
} \
|
||||
} while (0)
|
||||
}
|
||||
# else
|
||||
# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \
|
||||
do { \
|
||||
# define OR_WORD_EXIT_IF_SET(addr, bits) \
|
||||
{ /* cannot use do-while(0) here */ \
|
||||
word old = *(addr); \
|
||||
word my_bits = (bits); \
|
||||
if (old & my_bits) goto exit_label; \
|
||||
*(addr) = (old | my_bits); \
|
||||
} while (0)
|
||||
if ((old & my_bits) != 0) \
|
||||
break; /* go to the enclosing loop end */ \
|
||||
*(addr) = old | my_bits; \
|
||||
}
|
||||
# endif /* !PARALLEL_MARK */
|
||||
# define SET_MARK_BIT_EXIT_IF_SET(hhdr,bit_no,exit_label) \
|
||||
do { \
|
||||
# define SET_MARK_BIT_EXIT_IF_SET(hhdr, bit_no) \
|
||||
{ /* cannot use do-while(0) here */ \
|
||||
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); \
|
||||
} while (0)
|
||||
OR_WORD_EXIT_IF_SET(mark_word_addr, \
|
||||
(word)1 << modWORDSZ(bit_no)); /* contains "break" */ \
|
||||
}
|
||||
#endif /* !USE_MARK_BYTES */
|
||||
|
||||
#ifdef PARALLEL_MARK
|
||||
|
|
@ -228,7 +231,7 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
|
|||
/* 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) \
|
||||
source, hhdr, do_offset_check) \
|
||||
do { \
|
||||
size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
|
||||
/* displ is always within range. If current doesn't point to */ \
|
||||
|
|
@ -252,7 +255,7 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
|
|||
} else { \
|
||||
if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
|
||||
GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
|
||||
goto exit_label; \
|
||||
break; /* go to the end of PUSH_CONTENTS_HDR */ \
|
||||
} \
|
||||
} \
|
||||
gran_displ = 0; \
|
||||
|
|
@ -264,7 +267,7 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
|
|||
+ byte_offset; \
|
||||
if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
|
||||
GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
|
||||
goto exit_label; \
|
||||
break; \
|
||||
} \
|
||||
gran_displ -= gran_offset; \
|
||||
base -= obj_displ; \
|
||||
|
|
@ -274,31 +277,27 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
|
|||
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); \
|
||||
SET_MARK_BIT_EXIT_IF_SET(hhdr, gran_displ); \
|
||||
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)); \
|
||||
(unsigned)GC_gc_no, (void *)base, (void *)(source))); \
|
||||
INCR_MARKS(hhdr); \
|
||||
GC_STORE_BACK_PTR((ptr_t)source, base); \
|
||||
GC_STORE_BACK_PTR((ptr_t)(source), base); \
|
||||
PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
|
||||
} while (0)
|
||||
#endif /* MARK_BIT_PER_GRANULE */
|
||||
|
||||
#ifdef MARK_BIT_PER_OBJ
|
||||
# define PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \
|
||||
source, exit_label, hhdr, do_offset_check) \
|
||||
source, hhdr, do_offset_check) \
|
||||
do { \
|
||||
size_t displ = HBLKDISPL(current); /* Displacement in block; in bytes. */\
|
||||
unsigned32 low_prod, high_prod; \
|
||||
unsigned32 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) { \
|
||||
ptr_t base; \
|
||||
if (EXPECT(inv_sz == LARGE_INV_SZ, FALSE)) { \
|
||||
size_t obj_displ; \
|
||||
base = (ptr_t)(hhdr -> hb_block); \
|
||||
obj_displ = (ptr_t)(current) - base; \
|
||||
|
|
@ -309,19 +308,25 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
|
|||
} else { \
|
||||
if (do_offset_check && !GC_valid_offsets[obj_displ]) { \
|
||||
GC_ADD_TO_BLACK_LIST_NORMAL(current, source); \
|
||||
goto exit_label; \
|
||||
break; /* go to the end of PUSH_CONTENTS_HDR */ \
|
||||
} \
|
||||
} \
|
||||
GC_ASSERT(hhdr -> hb_sz > HBLKSIZE || \
|
||||
hhdr -> hb_block == HBLKPTR(current)); \
|
||||
GC_ASSERT((word)hhdr->hb_block < (word)(current)); \
|
||||
} else { \
|
||||
GC_ASSERT((word)(hhdr)->hb_block <= (word)(current)); \
|
||||
high_prod = 0; \
|
||||
} else { \
|
||||
unsigned32 low_prod; \
|
||||
base = (ptr_t)(current); \
|
||||
LONG_MULT(high_prod, low_prod, (unsigned32)displ, inv_sz); \
|
||||
if ((low_prod >> 16) != 0) { \
|
||||
size_t obj_displ; \
|
||||
/* Accurate enough if HBLKSIZE <= 2**15. */ \
|
||||
GC_STATIC_ASSERT(HBLKSIZE <= (1 << 15)); \
|
||||
size_t obj_displ = (((low_prod >> 16) + 1) * (hhdr->hb_sz)) >> 16; \
|
||||
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; \
|
||||
break; \
|
||||
} \
|
||||
base -= obj_displ; \
|
||||
} \
|
||||
|
|
@ -331,14 +336,14 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
|
|||
GC_ASSERT(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); \
|
||||
SET_MARK_BIT_EXIT_IF_SET(hhdr, high_prod); \
|
||||
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)); \
|
||||
(unsigned)GC_gc_no, (void *)base, (void *)(source))); \
|
||||
INCR_MARKS(hhdr); \
|
||||
GC_STORE_BACK_PTR((ptr_t)source, base); \
|
||||
GC_STORE_BACK_PTR((ptr_t)(source), base); \
|
||||
PUSH_OBJ(base, hhdr, mark_stack_top, mark_stack_limit); \
|
||||
} while (0)
|
||||
#endif /* MARK_BIT_PER_OBJ */
|
||||
|
|
@ -359,7 +364,7 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
|
|||
* if the mark stack overflows.
|
||||
*/
|
||||
|
||||
#if NEED_FIXUP_POINTER
|
||||
#ifdef NEED_FIXUP_POINTER
|
||||
/* Try both the raw version and the fixed up one. */
|
||||
# define GC_PUSH_ONE_STACK(p, source) \
|
||||
do { \
|
||||
|
|
@ -439,34 +444,34 @@ typedef int mark_state_t; /* Current state of marking, as follows:*/
|
|||
/* grungy if it was marked dirty in the */
|
||||
/* last set of bits we retrieved. */
|
||||
|
||||
/* Invariant I: all roots and marked */
|
||||
/* 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_NONE 0 /* No marking in progress. I holds. */
|
||||
#define MS_NONE 0 /* No marking in progress. "I" holds. */
|
||||
/* Mark stack is empty. */
|
||||
|
||||
#define MS_PUSH_RESCUERS 1 /* Rescuing objects are currently */
|
||||
/* being pushed. I holds, except */
|
||||
/* being pushed. "I" holds, except */
|
||||
/* that grungy roots may point to */
|
||||
/* unmarked objects, as may marked */
|
||||
/* grungy objects above scan_ptr. */
|
||||
|
||||
#define MS_PUSH_UNCOLLECTABLE 2 /* I holds, except that marked */
|
||||
#define MS_PUSH_UNCOLLECTABLE 2 /* "I" holds, except that marked */
|
||||
/* uncollectible objects above scan_ptr */
|
||||
/* may point to unmarked objects. */
|
||||
/* Roots may point to unmarked objects */
|
||||
|
||||
#define MS_ROOTS_PUSHED 3 /* I holds, mark stack may be nonempty */
|
||||
#define MS_ROOTS_PUSHED 3 /* "I" holds, mark stack may be nonempty. */
|
||||
|
||||
#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_PARTIALLY_INVALID 4 /* "I" may not hold, e.g. because of */
|
||||
/* the mark stack overflow. However */
|
||||
/* marked heap objects below scan_ptr */
|
||||
/* point to marked or stacked objects. */
|
||||
|
||||
#define MS_INVALID 5 /* I may not hold. */
|
||||
#define MS_INVALID 5 /* "I" may not hold. */
|
||||
|
||||
GC_EXTERN mark_state_t GC_mark_state;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@
|
|||
# define _USING_POSIX4A_DRAFT10 1
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) && !defined(__MINGW_EXCPT_DEFINE_PSDK) \
|
||||
&& defined(__i386__) && defined(GC_EXTERN) /* defined in gc.c */
|
||||
/* See the description in mark.c. */
|
||||
# define __MINGW_EXCPT_DEFINE_PSDK 1
|
||||
#endif
|
||||
|
||||
# if defined(NO_DEBUGGING) && !defined(GC_ASSERTIONS) && !defined(NDEBUG)
|
||||
/* To turn off assertion checking (in atomic_ops.h). */
|
||||
# define NDEBUG 1
|
||||
|
|
@ -90,10 +96,30 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
/* byte displacements and which can be used */
|
||||
/* for address comparisons. */
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#if defined(SIZE_MAX) && !defined(CPPCHECK)
|
||||
# define GC_SIZE_MAX ((size_t)SIZE_MAX)
|
||||
/* Extra cast to workaround some buggy SIZE_MAX definitions. */
|
||||
#else
|
||||
# define GC_SIZE_MAX (~(size_t)0)
|
||||
#endif
|
||||
|
||||
/* Saturated addition of size_t values. Used to avoid value wrap */
|
||||
/* around on overflow. The arguments should have no side effects. */
|
||||
#define SIZET_SAT_ADD(a, b) \
|
||||
((a) < GC_SIZE_MAX - (b) ? (a) + (b) : GC_SIZE_MAX)
|
||||
|
||||
#ifndef GCCONFIG_H
|
||||
# include "gcconfig.h"
|
||||
#endif
|
||||
|
||||
#if !defined(GC_ATOMIC_UNCOLLECTABLE) && defined(ATOMIC_UNCOLLECTABLE)
|
||||
/* For compatibility with old-style naming. */
|
||||
# define GC_ATOMIC_UNCOLLECTABLE
|
||||
#endif
|
||||
|
||||
#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 */
|
||||
|
|
@ -104,7 +130,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
/* located in the "extra" folder). */
|
||||
# if defined(GC_DLL) && defined(__GNUC__) && !defined(MSWIN32) \
|
||||
&& !defined(MSWINCE) && !defined(CYGWIN32)
|
||||
# if __GNUC__ >= 4
|
||||
# if (__GNUC__ >= 4) && !defined(GC_NO_VISIBILITY)
|
||||
/* See the corresponding GC_API definition. */
|
||||
# define GC_INNER __attribute__((__visibility__("hidden")))
|
||||
# else
|
||||
|
|
@ -129,6 +155,26 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
# include "gc_hdrs.h"
|
||||
#endif
|
||||
|
||||
#ifndef GC_ATTR_NO_SANITIZE_ADDR
|
||||
# ifndef ADDRESS_SANITIZER
|
||||
# define GC_ATTR_NO_SANITIZE_ADDR /* empty */
|
||||
# elif __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 8)
|
||||
# define GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize("address")))
|
||||
# else
|
||||
# define GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize_address))
|
||||
# endif
|
||||
#endif /* !GC_ATTR_NO_SANITIZE_ADDR */
|
||||
|
||||
#ifndef GC_ATTR_NO_SANITIZE_MEMORY
|
||||
# ifndef MEMORY_SANITIZER
|
||||
# define GC_ATTR_NO_SANITIZE_MEMORY /* empty */
|
||||
# elif __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 8)
|
||||
# define GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
|
||||
# else
|
||||
# define GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
|
||||
# endif
|
||||
#endif /* !GC_ATTR_NO_SANITIZE_MEMORY */
|
||||
|
||||
#ifndef GC_ATTR_UNUSED
|
||||
# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
# define GC_ATTR_UNUSED __attribute__((__unused__))
|
||||
|
|
@ -157,10 +203,20 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
# define GC_INLINE static
|
||||
#endif
|
||||
|
||||
#ifndef GC_ATTR_NOINLINE
|
||||
# if __GNUC__ >= 4
|
||||
# define GC_ATTR_NOINLINE __attribute__((__noinline__))
|
||||
# elif _MSC_VER >= 1400
|
||||
# define GC_ATTR_NOINLINE __declspec(noinline)
|
||||
# else
|
||||
# define GC_ATTR_NOINLINE /* empty */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef GC_API_OSCALL
|
||||
/* This is used to identify GC routines called by name from OS. */
|
||||
# if defined(__GNUC__)
|
||||
# if __GNUC__ >= 4
|
||||
# if (__GNUC__ >= 4) && !defined(GC_NO_VISIBILITY)
|
||||
/* Same as GC_API if GC_DLL. */
|
||||
# define GC_API_OSCALL extern __attribute__((__visibility__("default")))
|
||||
# else
|
||||
|
|
@ -250,36 +306,39 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
|
||||
|
||||
#ifndef GC_NO_FINALIZATION
|
||||
# define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
|
||||
GC_INNER void GC_notify_or_invoke_finalizers(void);
|
||||
# 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);
|
||||
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
|
||||
# ifndef GC_TOGGLE_REFS_NOT_NEEDED
|
||||
GC_INNER void GC_process_togglerefs(void);
|
||||
/* Process the toggle-refs before GC starts. */
|
||||
# endif
|
||||
# ifndef SMALL_CONFIG
|
||||
GC_INNER void GC_print_finalization_stats(void);
|
||||
# endif
|
||||
#else
|
||||
# define GC_INVOKE_FINALIZERS() (void)0
|
||||
# define GC_INVOKE_FINALIZERS() (void)0
|
||||
#endif /* GC_NO_FINALIZATION */
|
||||
|
||||
#if !defined(DONT_ADD_BYTE_AT_END)
|
||||
# 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)
|
||||
# define EXTRA_BYTES ((size_t)(GC_all_interior_pointers? 1 : 0))
|
||||
# else
|
||||
# define EXTRA_BYTES GC_all_interior_pointers
|
||||
# define EXTRA_BYTES (size_t)GC_all_interior_pointers
|
||||
# endif
|
||||
# define MAX_EXTRA_BYTES 1
|
||||
#else
|
||||
|
|
@ -420,7 +479,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
# define BCOPY_EXISTS
|
||||
# endif
|
||||
|
||||
# ifndef BCOPY_EXISTS
|
||||
# if !defined(BCOPY_EXISTS) || defined(CPPCHECK)
|
||||
# include <string.h>
|
||||
# define BCOPY(x,y,n) memcpy(y, x, (size_t)(n))
|
||||
# define BZERO(x,n) memset(x, 0, (size_t)(n))
|
||||
|
|
@ -455,8 +514,19 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
# endif
|
||||
# endif
|
||||
|
||||
#ifdef THREADS
|
||||
GC_EXTERN GC_on_thread_event_proc GC_on_thread_event;
|
||||
#endif
|
||||
|
||||
/* Abandon ship */
|
||||
# ifdef PCR
|
||||
# if defined(SMALL_CONFIG) || defined(PCR)
|
||||
# define GC_on_abort(msg) (void)0 /* be silent on abort */
|
||||
# else
|
||||
GC_API_PRIV GC_abort_func GC_on_abort;
|
||||
# endif
|
||||
# if defined(CPPCHECK)
|
||||
# define ABORT(msg) { GC_on_abort(msg); abort(); }
|
||||
# elif defined(PCR)
|
||||
# define ABORT(s) PCR_Base_Panic(s)
|
||||
# else
|
||||
# if defined(MSWINCE) && !defined(DebugBreak) \
|
||||
|
|
@ -468,11 +538,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
/* instead of defining it as a macro). */
|
||||
# define DebugBreak() _exit(-1) /* there is no abort() in WinCE */
|
||||
# endif
|
||||
# ifdef SMALL_CONFIG
|
||||
# define GC_on_abort(msg) (void)0 /* be silent on abort */
|
||||
# else
|
||||
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))
|
||||
|
|
@ -494,17 +559,18 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
/* should match their format specifiers. */
|
||||
#define ABORT_ARG1(C_msg, C_fmt, arg1) \
|
||||
do { \
|
||||
GC_COND_LOG_PRINTF(C_msg /* + */ C_fmt, arg1); \
|
||||
GC_INFOLOG_PRINTF(C_msg /* + */ C_fmt "\n", arg1); \
|
||||
ABORT(C_msg); \
|
||||
} while (0)
|
||||
#define ABORT_ARG2(C_msg, C_fmt, arg1, arg2) \
|
||||
do { \
|
||||
GC_COND_LOG_PRINTF(C_msg /* + */ C_fmt, arg1, arg2); \
|
||||
GC_INFOLOG_PRINTF(C_msg /* + */ C_fmt "\n", arg1, arg2); \
|
||||
ABORT(C_msg); \
|
||||
} while (0)
|
||||
#define ABORT_ARG3(C_msg, C_fmt, arg1, arg2, arg3) \
|
||||
do { \
|
||||
GC_COND_LOG_PRINTF(C_msg /* + */ C_fmt, arg1, arg2, arg3); \
|
||||
GC_INFOLOG_PRINTF(C_msg /* + */ C_fmt "\n", \
|
||||
arg1, arg2, arg3); \
|
||||
ABORT(C_msg); \
|
||||
} while (0)
|
||||
|
||||
|
|
@ -524,7 +590,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
|||
/* 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))
|
||||
(word)(arg))
|
||||
GC_EXTERN GC_warn_proc GC_current_warn_proc;
|
||||
|
||||
/* Print format type macro for decimal signed_word value passed WARN(). */
|
||||
|
|
@ -537,11 +603,16 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
|
|||
# define WARN_PRIdPTR "ld"
|
||||
#endif
|
||||
|
||||
/* A tagging macro (for a code static analyzer) to indicate that the */
|
||||
/* string obtained from an untrusted source (e.g., argv[], getenv) is */
|
||||
/* safe to use in a vulnerable operation (e.g., open, exec). */
|
||||
#define TRUSTED_STRING(s) (char*)COVERT_DATAFLOW(s)
|
||||
|
||||
/* Get environment entry */
|
||||
#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)
|
||||
#elif defined(NO_GETENV) && !defined(CPPCHECK)
|
||||
# define GETENV(name) NULL
|
||||
#elif defined(EMPTY_GETENV_RESULTS)
|
||||
/* Workaround for a reputed Wine bug. */
|
||||
|
|
@ -586,7 +657,8 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
|
|||
# define GC_MACH_THREAD_STATE x86_THREAD_STATE64
|
||||
# define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
|
||||
# endif
|
||||
# elif defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE)
|
||||
# elif defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE) \
|
||||
&& !defined(CPPCHECK)
|
||||
# define GC_THREAD_STATE_T arm_unified_thread_state_t
|
||||
# define GC_MACH_THREAD_STATE ARM_UNIFIED_THREAD_STATE
|
||||
# define GC_MACH_THREAD_STATE_COUNT ARM_UNIFIED_THREAD_STATE_COUNT
|
||||
|
|
@ -600,7 +672,7 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
|
|||
# define GC_THREAD_STATE_T arm_thread_state64_t
|
||||
# define GC_MACH_THREAD_STATE ARM_THREAD_STATE64
|
||||
# define GC_MACH_THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT
|
||||
# else
|
||||
# elif !defined(CPPCHECK)
|
||||
# error define GC_THREAD_STATE_T
|
||||
# endif
|
||||
# ifndef GC_MACH_THREAD_STATE
|
||||
|
|
@ -624,17 +696,14 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
|
|||
/* without __, thus hopefully, not breaking any existing */
|
||||
/* Makefile.direct builds. */
|
||||
# if __DARWIN_UNIX03
|
||||
# if defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE)
|
||||
# define THREAD_FLD(x) ts_32.__ ## x
|
||||
# else
|
||||
# define THREAD_FLD(x) __ ## x
|
||||
# endif
|
||||
# define THREAD_FLD_NAME(x) __ ## x
|
||||
# else
|
||||
# if defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE)
|
||||
# define THREAD_FLD(x) ts_32. ## x
|
||||
# else
|
||||
# define THREAD_FLD(x) x
|
||||
# endif
|
||||
# define THREAD_FLD_NAME(x) x
|
||||
# endif
|
||||
# if defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE)
|
||||
# define THREAD_FLD(x) ts_32.THREAD_FLD_NAME(x)
|
||||
# else
|
||||
# define THREAD_FLD(x) THREAD_FLD_NAME(x)
|
||||
# endif
|
||||
#endif /* DARWIN */
|
||||
|
||||
|
|
@ -739,7 +808,7 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
|
|||
# elif HBLKSIZE == 16384
|
||||
# define CPP_LOG_HBLKSIZE 14
|
||||
# else
|
||||
--> fix HBLKSIZE
|
||||
# error fix HBLKSIZE
|
||||
# endif
|
||||
# undef HBLKSIZE
|
||||
#endif
|
||||
|
|
@ -748,11 +817,11 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
|
|||
# define LOG_HBLKSIZE ((size_t)CPP_LOG_HBLKSIZE)
|
||||
# define HBLKSIZE ((size_t)CPP_HBLKSIZE)
|
||||
|
||||
#define GC_SQRT_SIZE_MAX ((((size_t)1) << (WORDSZ / 2)) - 1)
|
||||
|
||||
/* max size objects supported by freelist (larger objects are */
|
||||
/* Max size objects supported by freelist (larger objects are */
|
||||
/* allocated directly with allchblk(), by rounding to the next */
|
||||
/* multiple of HBLKSIZE. */
|
||||
|
||||
/* multiple of HBLKSIZE). */
|
||||
#define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2)
|
||||
#define MAXOBJBYTES ((size_t)CPP_MAXOBJBYTES)
|
||||
#define CPP_MAXOBJWORDS BYTES_TO_WORDS(CPP_MAXOBJBYTES)
|
||||
|
|
@ -772,17 +841,17 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
|
|||
|
||||
# define modHBLKSZ(n) ((n) & (HBLKSIZE-1))
|
||||
|
||||
# define HBLKPTR(objptr) ((struct hblk *)(((word) (objptr)) & ~(HBLKSIZE-1)))
|
||||
|
||||
# define HBLKPTR(objptr) ((struct hblk *)(((word)(objptr)) \
|
||||
& ~(word)(HBLKSIZE-1)))
|
||||
# define HBLKDISPL(objptr) (((size_t) (objptr)) & (HBLKSIZE-1))
|
||||
|
||||
/* Round up allocation size (in bytes) to a multiple of a granule. */
|
||||
#define ROUNDUP_GRANULE_SIZE(bytes) \
|
||||
(((bytes) + (GRANULE_BYTES - 1)) & ~(GRANULE_BYTES - 1))
|
||||
#define ROUNDUP_GRANULE_SIZE(lb) /* lb should have no side-effect */ \
|
||||
(SIZET_SAT_ADD(lb, GRANULE_BYTES - 1) & ~(GRANULE_BYTES - 1))
|
||||
|
||||
/* Round up byte allocation requests to integral number of words, etc. */
|
||||
# define ROUNDED_UP_GRANULES(n) \
|
||||
BYTES_TO_GRANULES((n) + (GRANULE_BYTES - 1 + EXTRA_BYTES))
|
||||
# define ROUNDED_UP_GRANULES(lb) /* lb should have no side-effect */ \
|
||||
BYTES_TO_GRANULES(SIZET_SAT_ADD(lb, GRANULE_BYTES - 1 + EXTRA_BYTES))
|
||||
# if MAX_EXTRA_BYTES == 0
|
||||
# define SMALL_OBJ(bytes) EXPECT((bytes) <= (MAXOBJBYTES), TRUE)
|
||||
# else
|
||||
|
|
@ -792,7 +861,8 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
|
|||
/* This really just tests bytes <= MAXOBJBYTES - EXTRA_BYTES. */
|
||||
/* But we try to avoid looking up EXTRA_BYTES. */
|
||||
# endif
|
||||
# define ADD_SLOP(bytes) ((bytes) + EXTRA_BYTES)
|
||||
# define ADD_SLOP(lb) /* lb should have no side-effect */ \
|
||||
SIZET_SAT_ADD(lb, EXTRA_BYTES)
|
||||
# ifndef MIN_WORDS
|
||||
# define MIN_WORDS 2 /* FIXME: obsolete */
|
||||
# endif
|
||||
|
|
@ -943,9 +1013,9 @@ struct hblkhdr {
|
|||
/* without generating a negative result. We avoid */
|
||||
/* generating free blocks larger than that. */
|
||||
word hb_descr; /* object descriptor for marking. See */
|
||||
/* mark.h. */
|
||||
/* gc_mark.h. */
|
||||
# ifdef MARK_BIT_PER_GRANULE
|
||||
short * hb_map; /* Essentially a table of remainders */
|
||||
unsigned short * hb_map; /* Essentially a table of remainders */
|
||||
/* mod BYTES_TO_GRANULES(hb_sz), except */
|
||||
/* for large blocks. See GC_obj_map. */
|
||||
# endif
|
||||
|
|
@ -1010,9 +1080,11 @@ struct hblk {
|
|||
|
||||
# define HBLK_IS_FREE(hdr) (((hdr) -> hb_flags & FREE_BLK) != 0)
|
||||
|
||||
# define OBJ_SZ_TO_BLOCKS(sz) divHBLKSZ((sz) + HBLKSIZE-1)
|
||||
# define OBJ_SZ_TO_BLOCKS(lb) divHBLKSZ((lb) + HBLKSIZE-1)
|
||||
# define OBJ_SZ_TO_BLOCKS_CHECKED(lb) /* lb should have no side-effect */ \
|
||||
divHBLKSZ(SIZET_SAT_ADD(lb, HBLKSIZE - 1))
|
||||
/* Size of block (in units of HBLKSIZE) needed to hold objects of */
|
||||
/* given sz (in bytes). */
|
||||
/* given lb (in bytes). The checked variant prevents wrap around. */
|
||||
|
||||
/* Object free list link */
|
||||
# define obj_link(p) (*(void **)(p))
|
||||
|
|
@ -1206,17 +1278,17 @@ struct _GC_arrays {
|
|||
/* free list for objects */
|
||||
# define GC_aobjfreelist GC_arrays._aobjfreelist
|
||||
void *_aobjfreelist[MAXOBJGRANULES+1];
|
||||
/* free list for atomic objs */
|
||||
/* free list for atomic objects */
|
||||
# endif
|
||||
void *_uobjfreelist[MAXOBJGRANULES+1];
|
||||
/* Uncollectible but traced objs */
|
||||
/* objects on this and auobjfreelist */
|
||||
/* Uncollectible but traced objects. */
|
||||
/* Objects on this and _auobjfreelist */
|
||||
/* are always marked, except during */
|
||||
/* garbage collections. */
|
||||
# ifdef ATOMIC_UNCOLLECTABLE
|
||||
# ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
# define GC_auobjfreelist GC_arrays._auobjfreelist
|
||||
void *_auobjfreelist[MAXOBJGRANULES+1];
|
||||
/* Atomic uncollectible but traced objs */
|
||||
/* Atomic uncollectible but traced objects. */
|
||||
# endif
|
||||
size_t _size_map[MAXOBJBYTES+1];
|
||||
/* Number of granules to allocate when asked for a certain */
|
||||
|
|
@ -1228,7 +1300,7 @@ struct _GC_arrays {
|
|||
# endif
|
||||
# ifdef MARK_BIT_PER_GRANULE
|
||||
# define GC_obj_map GC_arrays._obj_map
|
||||
short * _obj_map[MAXOBJGRANULES+1];
|
||||
unsigned 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 */
|
||||
|
|
@ -1266,7 +1338,7 @@ struct _GC_arrays {
|
|||
volatile page_hash_table _dirty_pages;
|
||||
/* Pages dirtied since last GC_read_dirty. */
|
||||
# endif
|
||||
# if defined(PROC_VDB) || defined(GWW_VDB)
|
||||
# if (defined(CHECKSUMS) && defined(GWW_VDB)) || defined(PROC_VDB)
|
||||
# define GC_written_pages GC_arrays._written_pages
|
||||
page_hash_table _written_pages; /* Pages ever dirtied */
|
||||
# endif
|
||||
|
|
@ -1335,16 +1407,17 @@ GC_API_PRIV GC_FAR struct _GC_arrays GC_arrays;
|
|||
#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes)
|
||||
|
||||
/* Object kinds: */
|
||||
#define MAXOBJKINDS 16
|
||||
|
||||
#ifndef MAXOBJKINDS
|
||||
# define MAXOBJKINDS 16
|
||||
#endif
|
||||
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. */
|
||||
void **ok_freelist; /* Array of free list headers for this kind of */
|
||||
/* object. Point either to GC_arrays or to */
|
||||
/* storage allocated with GC_scratch_alloc. */
|
||||
struct hblk **ok_reclaim_list;
|
||||
/* List headers for lists of blocks waiting to be */
|
||||
/* swept. */
|
||||
/* Indexed by object size in granules. */
|
||||
/* 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;
|
||||
|
|
@ -1385,7 +1458,7 @@ GC_EXTERN struct obj_kind {
|
|||
# define endGC_objfreelist (beginGC_objfreelist + sizeof(GC_objfreelist))
|
||||
|
||||
extern ptr_t GC_aobjfreelist[MAXOBJGRANULES+1];
|
||||
/* free list for atomic (PTRFREE) objs */
|
||||
/* free list for atomic (PTRFREE) objects */
|
||||
# define beginGC_aobjfreelist ((ptr_t)(&GC_aobjfreelist))
|
||||
# define endGC_aobjfreelist (beginGC_aobjfreelist + sizeof(GC_aobjfreelist))
|
||||
#endif /* SEPARATE_GLOBALS */
|
||||
|
|
@ -1394,7 +1467,7 @@ GC_EXTERN struct obj_kind {
|
|||
#define PTRFREE 0
|
||||
#define NORMAL 1
|
||||
#define UNCOLLECTABLE 2
|
||||
#ifdef ATOMIC_UNCOLLECTABLE
|
||||
#ifdef GC_ATOMIC_UNCOLLECTABLE
|
||||
# define AUNCOLLECTABLE 3
|
||||
# define STUBBORN 4
|
||||
# define IS_UNCOLLECTABLE(k) (((k) & ~1) == UNCOLLECTABLE)
|
||||
|
|
@ -1413,18 +1486,18 @@ GC_EXTERN word GC_n_heap_sects; /* Number of separately added heap */
|
|||
/* sections. */
|
||||
#endif
|
||||
|
||||
GC_EXTERN word GC_page_size;
|
||||
GC_EXTERN size_t GC_page_size;
|
||||
|
||||
/* Round up allocation size to a multiple of a page size. */
|
||||
/* GC_setpagesize() is assumed to be already invoked. */
|
||||
#define ROUNDUP_PAGESIZE(bytes) \
|
||||
(((bytes) + GC_page_size - 1) & ~(GC_page_size - 1))
|
||||
#define ROUNDUP_PAGESIZE(lb) /* lb should have no side-effect */ \
|
||||
(SIZET_SAT_ADD(lb, GC_page_size - 1) & ~(GC_page_size - 1))
|
||||
|
||||
/* Same as above but used to make GET_MEM() argument safe. */
|
||||
#ifdef MMAP_SUPPORTED
|
||||
# define ROUNDUP_PAGESIZE_IF_MMAP(bytes) ROUNDUP_PAGESIZE(bytes)
|
||||
# define ROUNDUP_PAGESIZE_IF_MMAP(lb) ROUNDUP_PAGESIZE(lb)
|
||||
#else
|
||||
# define ROUNDUP_PAGESIZE_IF_MMAP(bytes) (bytes)
|
||||
# define ROUNDUP_PAGESIZE_IF_MMAP(lb) (lb)
|
||||
#endif
|
||||
|
||||
#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
|
||||
|
|
@ -1451,7 +1524,8 @@ GC_EXTERN word GC_black_list_spacing;
|
|||
# define TRUE_INCREMENTAL FALSE
|
||||
#else
|
||||
GC_EXTERN GC_bool GC_incremental;
|
||||
/* Using incremental/generational collection. */
|
||||
/* Using incremental/generational collection. */
|
||||
/* Assumes dirty bits are being maintained. */
|
||||
# define TRUE_INCREMENTAL \
|
||||
(GC_incremental && GC_time_limit != GC_TIME_UNLIMITED)
|
||||
/* True incremental, not just generational, mode */
|
||||
|
|
@ -1589,23 +1663,12 @@ GC_INNER void GC_initiate_gc(void);
|
|||
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((ptr_t)(b), (ptr_t)(t))
|
||||
#endif
|
||||
#define GC_PUSH_ALL_SYM(sym) \
|
||||
GC_push_all((ptr_t)&(sym), (ptr_t)&(sym) + sizeof(sym))
|
||||
|
||||
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 */
|
||||
|
|
@ -1634,7 +1697,7 @@ GC_EXTERN void (*GC_push_typed_structures)(void);
|
|||
/* the typed allocation support if unused. */
|
||||
|
||||
GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
|
||||
ptr_t arg);
|
||||
volatile ptr_t arg);
|
||||
|
||||
#if defined(SPARC) || defined(IA64)
|
||||
/* Cause all stacked registers to be saved in memory. Return a */
|
||||
|
|
@ -1676,6 +1739,9 @@ GC_INNER void GC_set_fl_marks(ptr_t p);
|
|||
/* set. Abort if not. */
|
||||
#endif
|
||||
void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp);
|
||||
#ifdef USE_PROC_FOR_LIBRARIES
|
||||
GC_INNER void GC_remove_roots_subregion(ptr_t b, ptr_t e);
|
||||
#endif
|
||||
GC_INNER void GC_exclude_static_roots_inner(void *start, void *finish);
|
||||
#if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
|
||||
|| defined(CYGWIN32) || defined(PCR)
|
||||
|
|
@ -1748,6 +1814,14 @@ GC_INNER ptr_t GC_scratch_alloc(size_t bytes);
|
|||
/* small objects. Deallocation is not */
|
||||
/* possible. May return NULL. */
|
||||
|
||||
#ifdef GWW_VDB
|
||||
/* GC_scratch_recycle_no_gww() not used. */
|
||||
#else
|
||||
# define GC_scratch_recycle_no_gww GC_scratch_recycle_inner
|
||||
#endif
|
||||
GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes);
|
||||
/* Reuse the memory region by the heap. */
|
||||
|
||||
/* Heap block layout maps: */
|
||||
GC_INNER GC_bool GC_add_map_entry(size_t sz);
|
||||
/* Add a heap block map for objects of */
|
||||
|
|
@ -1829,6 +1903,13 @@ GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func f);
|
|||
#define GC_gcollect_inner() \
|
||||
(void)GC_try_to_collect_inner(GC_never_stop_func)
|
||||
|
||||
#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
|
||||
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. */
|
||||
#endif
|
||||
|
||||
GC_EXTERN GC_bool GC_is_initialized; /* GC_init() has been run. */
|
||||
|
||||
#if defined(MSWIN32) || defined(MSWINCE)
|
||||
|
|
@ -1846,12 +1927,15 @@ GC_INNER void GC_collect_a_little_inner(int n);
|
|||
GC_INNER void * GC_generic_malloc_inner(size_t lb, int k);
|
||||
/* Allocate an object of the given */
|
||||
/* kind but assuming lock already held. */
|
||||
GC_INNER void * GC_generic_malloc_inner_ignore_off_page(size_t lb, int k);
|
||||
#if defined(DBG_HDRS_ALL) || defined(GC_GCJ_SUPPORT) \
|
||||
|| !defined(GC_NO_FINALIZATION)
|
||||
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. */
|
||||
#endif
|
||||
|
||||
GC_INNER ptr_t GC_allocobj(size_t sz, int kind);
|
||||
/* Make the indicated */
|
||||
|
|
@ -1862,7 +1946,7 @@ GC_INNER ptr_t GC_allocobj(size_t sz, int kind);
|
|||
/* GC_DBG_EXTRAS is used by GC debug API functions (unlike GC_EXTRAS */
|
||||
/* used by GC debug API macros) thus GC_RETURN_ADDR_PARENT (pointing */
|
||||
/* to client caller) should be used if possible. */
|
||||
# ifdef GC_RETURN_ADDR_PARENT
|
||||
# ifdef GC_HAVE_RETURN_ADDR_PARENT
|
||||
# define GC_DBG_EXTRAS GC_RETURN_ADDR_PARENT, NULL, 0
|
||||
# else
|
||||
# define GC_DBG_EXTRAS GC_RETURN_ADDR, NULL, 0
|
||||
|
|
@ -1889,13 +1973,9 @@ GC_INNER ptr_t GC_allocobj(size_t sz, int kind);
|
|||
#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
|
||||
#if defined(THREAD_LOCAL_ALLOC) && defined(GC_GCJ_SUPPORT)
|
||||
GC_INNER void * GC_core_gcj_malloc(size_t, void *);
|
||||
# endif
|
||||
#endif /* THREAD_LOCAL_ALLOC */
|
||||
#endif
|
||||
|
||||
GC_INNER void GC_init_headers(void);
|
||||
GC_INNER struct hblkhdr * GC_install_header(struct hblk *h);
|
||||
|
|
@ -1973,6 +2053,11 @@ GC_EXTERN GC_bool GC_have_errors; /* We saw a smashed or leaked object. */
|
|||
GC_INNER void GC_generate_random_backtrace_no_gc(void);
|
||||
#endif
|
||||
|
||||
#ifdef LINT2
|
||||
# define GC_RAND_MAX (~0U >> 1)
|
||||
GC_API_PRIV long GC_random(void);
|
||||
#endif
|
||||
|
||||
GC_EXTERN GC_bool GC_print_back_height;
|
||||
|
||||
#ifdef MAKE_BACK_GRAPH
|
||||
|
|
@ -2037,26 +2122,40 @@ GC_EXTERN GC_bool GC_print_back_height;
|
|||
#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. */
|
||||
/* h is about to be written or allocated. Ensure that */
|
||||
/* it is not write protected by the virtual dirty bit */
|
||||
/* implementation. I.e., this is a call that: */
|
||||
/* - hints that [h, h+nblocks) is about to be written; */
|
||||
/* - guarantees that protection is removed; */
|
||||
/* - may speed up some dirty bit implementations; */
|
||||
/* - may be essential if we need to ensure that */
|
||||
/* pointer-free system call buffers in the heap are */
|
||||
/* not protected. */
|
||||
|
||||
GC_INNER void GC_dirty_init(void);
|
||||
GC_INNER GC_bool GC_dirty_init(void);
|
||||
/* Returns true if dirty bits are maintained (otherwise */
|
||||
/* it is OK to be called again if the client invokes */
|
||||
/* GC_enable_incremental once more). */
|
||||
#endif /* !GC_DISABLE_INCREMENTAL */
|
||||
|
||||
#ifdef MANUAL_VDB
|
||||
GC_INNER void GC_dirty_inner(const void *p); /* does not require locking */
|
||||
# define GC_dirty(p) (GC_incremental ? GC_dirty_inner(p) : (void)0)
|
||||
# define REACHABLE_AFTER_DIRTY(p) GC_reachable_here(p)
|
||||
#else
|
||||
# define GC_dirty(p) (void)(p)
|
||||
# define REACHABLE_AFTER_DIRTY(p) (void)(p)
|
||||
#endif
|
||||
|
||||
/* 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)))
|
||||
|
||||
|
|
@ -2244,12 +2343,13 @@ 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 */
|
||||
GC_INNER void GC_start_debugging_inner(void); /* defined in dbg_mlc.c. */
|
||||
/* Should not be called if GC_debugging_started. */
|
||||
|
||||
/* 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);
|
||||
/* Assumes we hold the allocation lock. */
|
||||
GC_INNER void *GC_store_debug_info_inner(void *p, word sz, const char *str,
|
||||
int linenum);
|
||||
|
||||
#ifdef REDIRECT_MALLOC
|
||||
# ifdef GC_LINUX_THREADS
|
||||
|
|
@ -2350,6 +2450,14 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
|
|||
# define GC_STATIC_ASSERT(expr) (void)sizeof(char[(expr)? 1 : -1])
|
||||
#endif
|
||||
|
||||
/* Runtime check for an argument declared as non-null is actually not null. */
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
/* Workaround tautological-pointer-compare Clang warning. */
|
||||
# define NONNULL_ARG_NOT_NULL(arg) (*(volatile void **)&(arg) != NULL)
|
||||
#else
|
||||
# define NONNULL_ARG_NOT_NULL(arg) (NULL != (arg))
|
||||
#endif
|
||||
|
||||
#define COND_DUMP_CHECKS \
|
||||
do { \
|
||||
GC_ASSERT(GC_compute_large_free_bytes() == GC_large_free_bytes); \
|
||||
|
|
@ -2386,12 +2494,13 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
|
|||
/* GC_notify_all_builder() is called when GC_fl_builder_count */
|
||||
/* reaches 0. */
|
||||
|
||||
GC_INNER void GC_wait_for_markers_init(void);
|
||||
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_EXTERN signed_word GC_fl_builder_count; /* Protected by mark lock. */
|
||||
|
||||
GC_INNER void GC_notify_all_marker(void);
|
||||
GC_INNER void GC_wait_marker(void);
|
||||
|
|
@ -2402,6 +2511,8 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
|
|||
/* my_mark_no. Returns if the mark cycle finishes or */
|
||||
/* was already done, or there was nothing to do for */
|
||||
/* some other reason. */
|
||||
|
||||
GC_INNER void GC_start_mark_threads_inner(void);
|
||||
#endif /* PARALLEL_MARK */
|
||||
|
||||
#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && !defined(NACL) \
|
||||
|
|
@ -2426,7 +2537,7 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
|
|||
# ifndef GC_OPENBSD_UTHREADS
|
||||
# define SIG_SUSPEND SIGXFSZ
|
||||
# endif
|
||||
# elif defined(_SIGRTMIN)
|
||||
# elif defined(_SIGRTMIN) && !defined(CPPCHECK)
|
||||
# define SIG_SUSPEND _SIGRTMIN + 6
|
||||
# else
|
||||
# define SIG_SUSPEND SIGRTMIN + 6
|
||||
|
|
@ -2473,18 +2584,19 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
|
|||
# define NEED_FIND_LIMIT
|
||||
#endif
|
||||
|
||||
#if (defined(SVR4) || defined(AUX) || defined(DGUX) \
|
||||
#if (defined(SVR4) || defined(AIX) || 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__))
|
||||
#if defined(DATASTART_USES_BSDGETDATASTART)
|
||||
# include <machine/trap.h>
|
||||
# if !defined(PCR)
|
||||
# define NEED_FIND_LIMIT
|
||||
# endif
|
||||
#endif /* FREEBSD */
|
||||
GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t, ptr_t);
|
||||
# define DATASTART_IS_FUNC
|
||||
#endif /* DATASTART_USES_BSDGETDATASTART */
|
||||
|
||||
#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \
|
||||
&& !defined(NEED_FIND_LIMIT)
|
||||
|
|
@ -2499,10 +2611,10 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
|
|||
|
||||
#if defined(NEED_FIND_LIMIT) \
|
||||
|| (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))
|
||||
JMP_BUF GC_jmp_buf;
|
||||
GC_EXTERN JMP_BUF GC_jmp_buf;
|
||||
|
||||
/* Set up a handler for address faults which will longjmp to */
|
||||
/* GC_jmp_buf; */
|
||||
/* 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);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -19,10 +19,10 @@
|
|||
#define GC_PTHREAD_STOP_WORLD_H
|
||||
|
||||
struct thread_stop_info {
|
||||
# ifndef GC_OPENBSD_UTHREADS
|
||||
word last_stop_count; /* GC_last_stop_count value when thread */
|
||||
/* last successfully handled a suspend */
|
||||
/* signal. */
|
||||
# if !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
|
||||
volatile AO_t last_stop_count;
|
||||
/* The value of GC_stop_count when the thread */
|
||||
/* last successfully handled a suspend signal. */
|
||||
# endif
|
||||
|
||||
ptr_t stack_ptr; /* Valid only when stopped. */
|
||||
|
|
@ -34,7 +34,12 @@ struct thread_stop_info {
|
|||
/* 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
|
||||
# ifdef ARM32
|
||||
/* Space for r4-r8, r10-r12, r14. */
|
||||
# define NACL_GC_REG_STORAGE_SIZE 9
|
||||
# else
|
||||
# define NACL_GC_REG_STORAGE_SIZE 20
|
||||
# endif
|
||||
ptr_t reg_storage[NACL_GC_REG_STORAGE_SIZE];
|
||||
# endif
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,12 +46,17 @@ typedef struct GC_Thread_Rep {
|
|||
/* guaranteed to be dead, but we may */
|
||||
/* not yet have registered the join.) */
|
||||
pthread_t id;
|
||||
# ifdef PLATFORM_ANDROID
|
||||
# ifdef USE_TKILL_ON_ANDROID
|
||||
pid_t kernel_id;
|
||||
# endif
|
||||
/* Extra bookkeeping information the stopping code uses */
|
||||
struct thread_stop_info stop_info;
|
||||
|
||||
# if defined(GC_ENABLE_SUSPEND_THREAD) && !defined(GC_DARWIN_THREADS) \
|
||||
&& !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
|
||||
volatile AO_t suspended_ext; /* Thread was suspended externally. */
|
||||
# endif
|
||||
|
||||
unsigned char flags;
|
||||
# define FINISHED 1 /* Thread has exited. */
|
||||
# define DETACHED 2 /* Thread is treated as detached. */
|
||||
|
|
@ -62,9 +67,6 @@ typedef struct GC_Thread_Rep {
|
|||
/* 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. */
|
||||
|
||||
|
|
@ -86,6 +88,12 @@ typedef struct GC_Thread_Rep {
|
|||
|
||||
ptr_t stack_end; /* Cold end of the stack (except for */
|
||||
/* main thread). */
|
||||
ptr_t altstack; /* The start of the alt-stack if there */
|
||||
/* is one, NULL otherwise. */
|
||||
word altstack_size; /* The size of the alt-stack if exists. */
|
||||
ptr_t stack; /* The start and size of the normal */
|
||||
/* stack (set by GC_register_altstack). */
|
||||
word stack_size;
|
||||
# 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; */
|
||||
|
|
@ -114,18 +122,15 @@ typedef struct GC_Thread_Rep {
|
|||
# endif
|
||||
} * GC_thread;
|
||||
|
||||
# define THREAD_TABLE_SZ 256 /* Must be power of 2 */
|
||||
#ifndef THREAD_TABLE_SZ
|
||||
# define THREAD_TABLE_SZ 256 /* Power of 2 (for speed). */
|
||||
#endif
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
/* 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" */
|
||||
/* thread is a valid pthread id or qtid is a valid "quick thread 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. */
|
||||
|
|
@ -76,7 +76,9 @@ typedef tsd * GC_key_t;
|
|||
#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);
|
||||
#define GC_remove_specific(key) \
|
||||
GC_remove_specific_after_fork(key, pthread_self())
|
||||
GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t);
|
||||
|
||||
/* An internal version of getspecific that assumes a cache miss. */
|
||||
GC_INNER void * GC_slow_getspecific(tsd * key, word qtid,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue