summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Boehm <boehm@acm.org>1994-08-03 00:00:00 +0000
committerIvan Maidanski <ivmai@mail.ru>2014-05-17 17:08:29 +0400
commit476effec75b5c16bd545d91b36328cdeda3eebc6 (patch)
treedfeebb182511357fa6f185c68e1f50c2da729eb0
parent290962da56de5c0a72cd27a46536fd7ba869c0cc (diff)
downloadbdwgc-gc4_2.tar.gz
gc4.2 tarball importgc4_2
-rw-r--r--EMX_MAKEFILE141
-rw-r--r--MacOS.c55
-rw-r--r--MacProjects.sit.hqx608
-rw-r--r--Makefile9
-rw-r--r--PCR-Makefile86
-rw-r--r--README167
-rw-r--r--README.Mac54
-rw-r--r--README.QUICK2
-rw-r--r--README.amiga14
-rw-r--r--SCoptions.amiga7
-rw-r--r--SMakefile.amiga41
-rw-r--r--alloc.c53
-rwxr-xr-xcallprocs1
-rw-r--r--checksums.c15
-rw-r--r--config.h43
-rwxr-xr-xcord/SCOPTIONS.amiga14
-rw-r--r--cord/SMakefile.amiga20
-rw-r--r--cord/cord.h19
-rw-r--r--cord/cordbscs.c4
-rw-r--r--cord/cordprnt.c5
-rw-r--r--cord/cordtest.c19
-rw-r--r--cord/cordxtra.c8
-rw-r--r--cord/de.c72
-rw-r--r--cord/gc.h475
-rw-r--r--dbg_mlc.c64
-rw-r--r--dyn_load.c6
-rw-r--r--finalize.c24
-rw-r--r--gc.h56
-rw-r--r--gc_c++.cc4
-rw-r--r--gc_c++.h50
-rw-r--r--gc_hdrs.h4
-rw-r--r--gc_priv.h109
-rw-r--r--headers.c14
-rw-r--r--mach_dep.c65
-rw-r--r--makefile.depend0
-rw-r--r--malloc.c71
-rw-r--r--mark.c56
-rw-r--r--mark_rts.c6
-rw-r--r--misc.c26
-rw-r--r--os_dep.c170
-rw-r--r--pc_excludes3
-rw-r--r--pcr_interface.c30
-rw-r--r--reclaim.c27
-rw-r--r--setjmp_t.c6
-rw-r--r--solaris_threads.c443
-rw-r--r--stubborn.c8
-rw-r--r--test.c100
-rw-r--r--typd_mlc.c24
48 files changed, 2784 insertions, 514 deletions
diff --git a/EMX_MAKEFILE b/EMX_MAKEFILE
new file mode 100644
index 00000000..74477817
--- /dev/null
+++ b/EMX_MAKEFILE
@@ -0,0 +1,141 @@
+#
+# OS/2 specific Makefile for the EMX environment
+#
+# You need GNU Make 3.71, gcc 2.5.7, emx 0.8h and GNU fileutils 3.9
+# or similar tools. C++ interface and de.exe weren't tested.
+#
+# Rename this file "Makefile".
+#
+
+# Primary targets:
+# gc.a - builds basic library
+# c++ - adds C++ interface to library and include directory
+# cords - adds cords (heavyweight strings) to library and include directory
+# test - prints porting information, then builds basic version of gc.a, and runs
+# some tests of collector and cords. Does not add cords or c++ interface to gc.a
+# cord/de.exe - builds dumb editor based on cords.
+CC= gcc
+CXX=g++
+# Needed only for "make c++", which adds the c++ interface
+
+CFLAGS= -O -DALL_INTERIOR_POINTERS -DSILENT
+# Setjmp_test may yield overly optimistic results when compiled
+# without optimization.
+# -DSILENT disables statistics printing, and improves performance.
+# -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
+# altered stubborn objects, at substantial performance cost.
+# -DFIND_LEAK causes the collector to assume that all inaccessible
+# objects should have been explicitly deallocated, and reports exceptions
+# -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
+# (Clients should also define SOLARIS_THREADS and then include
+# gc.h before performing thr_ or GC_ operations.)
+# -DALL_INTERIOR_POINTERS allows all pointers to the interior
+# of objects to be recognized. (See gc_private.h for consequences.)
+# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
+# usually causing it to use less space in such situations.
+# Incremental collection no longer works in this case.
+# -DDONT_ADD_BYTE_AT_END is meaningful only with
+# -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
+# causes all objects to be padded so that pointers just past the end of
+# an object can be recognized. This can be expensive. (The padding
+# is normally more than one byte due to alignment constraints.)
+# -DDONT_ADD_BYTE_AT_END disables the padding.
+
+AR= ar
+RANLIB= ar s
+
+# Redefining srcdir allows object code for the nonPCR version of the collector
+# to be generated in different directories
+srcdir = .
+VPATH = $(srcdir)
+
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o
+
+CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
+
+CORD_INCLUDE_FILES= $(srcdir)/gc.h $(srcdir)/cord/cord.h $(srcdir)/cord/ec.h \
+ $(srcdir)/cord/cord_pos.h
+
+# Libraries needed for curses applications. Only needed for de.
+CURSES= -lcurses -ltermlib
+
+# The following is irrelevant on most systems. But a few
+# versions of make otherwise fork the shell specified in
+# the SHELL environment variable.
+SHELL= bash
+
+SPECIALCFLAGS =
+# Alternative flags to the C compiler for mach_dep.c.
+# Mach_dep.c often doesn't like optimization, and it's
+# not time-critical anyway.
+
+all: gc.a gctest.exe
+
+$(OBJS) test.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
+ $(srcdir)/config.h $(srcdir)/gc_typed.h
+# The dependency on Makefile is needed. Changing
+# options such as -DSILENT affects the size of GC_arrays,
+# invalidating all .o files that rely on gc_priv.h
+
+mark.o typd_mlc.o finalize.o: $(srcdir)/gc_mark.h
+
+gc.a: $(OBJS)
+ $(AR) ru gc.a $(OBJS)
+ $(RANLIB) gc.a
+
+cords: $(CORD_OBJS) cord/cordtest.exe
+ $(AR) ru gc.a $(CORD_OBJS)
+ $(RANLIB) gc.a
+ cp $(srcdir)/cord/cord.h include/cord.h
+ cp $(srcdir)/cord/ec.h include/ec.h
+ cp $(srcdir)/cord/cord_pos.h include/cord_pos.h
+
+gc_c++.o: $(srcdir)/gc_c++.cc $(srcdir)/gc_c++.h
+ $(CXX) -c -O $(srcdir)/gc_c++.cc
+
+c++: gc_c++.o $(srcdir)/gc_c++.h
+ $(AR) ru gc.a gc_c++.o
+ $(RANLIB) gc.a
+ cp $(srcdir)/gc_c++.h include/gc_c++.h
+
+mach_dep.o: $(srcdir)/mach_dep.c
+ $(CC) -o mach_dep.o -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
+
+mark_rts.o: $(srcdir)/mark_rts.c
+ $(CC) -o mark_rts.o -c $(CFLAGS) $(srcdir)/mark_rts.c
+
+cord/cordbscs.o: $(srcdir)/cord/cordbscs.c $(CORD_INCLUDE_FILES)
+ $(CC) $(CFLAGS) -c $(srcdir)/cord/cordbscs.c -o cord/cordbscs.o
+
+cord/cordxtra.o: $(srcdir)/cord/cordxtra.c $(CORD_INCLUDE_FILES)
+ $(CC) $(CFLAGS) -c $(srcdir)/cord/cordxtra.c -o cord/cordxtra.o
+
+cord/cordprnt.o: $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
+ $(CC) $(CFLAGS) -c $(srcdir)/cord/cordprnt.c -o cord/cordprnt.o
+
+cord/cordtest.exe: $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
+ $(CC) $(CFLAGS) -o cord/cordtest.exe $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
+
+cord/de.exe: $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a
+ $(CC) $(CFLAGS) -o cord/de.exe $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a $(CURSES)
+
+clean:
+ rm -f gc.a test.o gctest.exe output-local output-diff $(OBJS) \
+ setjmp_test mon.out gmon.out a.out core \
+ $(CORD_OBJS) cord/cordtest.exe cord/de.exe
+ -rm -f *~
+
+gctest.exe: test.o gc.a
+ $(CC) $(CFLAGS) -o gctest.exe test.o gc.a
+
+# If an optimized setjmp_test generates a segmentation fault,
+# odds are your compiler is broken. Gctest may still work.
+# Try compiling setjmp_t.c unoptimized.
+setjmp_test.exe: $(srcdir)/setjmp_t.c $(srcdir)/gc.h
+ $(CC) $(CFLAGS) -o setjmp_test.exe $(srcdir)/setjmp_t.c
+
+test: setjmp_test.exe gctest.exe
+ ./setjmp_test
+ ./gctest
+ make cord/cordtest.exe
+ cord/cordtest
diff --git a/MacOS.c b/MacOS.c
new file mode 100644
index 00000000..90c249b8
--- /dev/null
+++ b/MacOS.c
@@ -0,0 +1,55 @@
+/*
+ MacOS.c
+
+ Some routines for the Macintosh OS port of the Hans-J. Boehm, Alan J. Demers
+ garbage collector.
+
+ <Revision History>
+
+ by Patrick C. Beard.
+ */
+/* Boehm, July 28, 1994 10:35 am PDT */
+
+#include <Resources.h>
+#include <Memory.h>
+#include <LowMem.h>
+#include <stdio.h>
+#include <string.h>
+
+// use 'CODE' resource 0 to get exact location of the beginning of global space.
+
+typedef struct {
+ unsigned long aboveA5;
+ unsigned long belowA5;
+ unsigned long JTSize;
+ unsigned long JTOffset;
+} *CodeZeroPtr, **CodeZeroHandle;
+
+void* GC_MacGetDataStart()
+{
+ CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
+ if (code0) {
+ long belowA5Size = (**code0).belowA5;
+ ReleaseResource((Handle)code0);
+ return (LMGetCurrentA5() - belowA5Size);
+ }
+ fprintf(stderr, "Couldn't load the jump table.");
+ exit(-1);
+ return 0;
+}
+
+Ptr GC_MacTemporaryNewPtr(Size size, Boolean clearMemory)
+{
+ OSErr result;
+ Handle tempHandle;
+ Ptr tempPtr;
+
+ tempHandle = TempNewHandle(size, &result);
+ if (tempHandle && result == noErr) {
+ HLockHi(tempHandle);
+ tempPtr = *tempHandle;
+ if (clearMemory) memset(tempPtr, 0, size);
+ return tempPtr;
+ }
+ return nil;
+}
diff --git a/MacProjects.sit.hqx b/MacProjects.sit.hqx
new file mode 100644
index 00000000..85a73d7b
--- /dev/null
+++ b/MacProjects.sit.hqx
@@ -0,0 +1,608 @@
+(This file must be converted with BinHex 4.0)
+
+:$deKBe"bEfTPBh4c,R0TG!"6594%8dP8)3%!!!"`(3!!!!"ZMP0*9#%!!3!!F"e
+b6'&e!J!!!!!@!!!J)!Y0B@03FQpUC@0dF`!!!!!!!!!!!!!!!!!!!!!!!!!!"fm
+!!!"k!-i"0J*L!!!!"J!!!!!!!!!!!!!!!!!!!)B!!!%Jrrrrr`%!UP96hDTCI!8
+!!!!!!!'$1J!!!!!!!'qA!!!!!!!!!!!!!1lb$3!'BfpbC#kj!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!-+m!!!!!!!!!!!!!!!!!!!!!!!@!!!B@`!!!"B!!!"!8&*
+25NY"5%`"!+Qe$$LU@Ab2!!"F'!!!!!!!!"GP!!!!!#Ap!!!!!!!!!!$&*`i!kf9
+QXT8Ec5jEZCXZA!#qEVETTU9ml6MGE,Z`K@h+6ldqlI,`p&UI65*mB@[QfB$GQXr
+A!6ZlKHdijCH,HT[`MPdZI$'fMbcqbXU-f6C'f$D6m+-,ci9ffa`8lf),Zj,XXb2
+lii[af#*Cf6kfm)AY#)YZYUP!eA9GNf+pA4hERXZ!*pP(ET%X*pRNf%)B@FM6jI!
+"R1HJ35YM'XEBXK"M5h&UGbjK62p0aJCdc8XZXFAM%EPjP4a0mA!d*5F#ATqXpm8
+5IZX$+l4-beaGVX@Z9[GPa)!ei03iEDHbMRkDKBm1I-id4`PHChi[BjrFpkj29EJ
+GVG)#hT@)VE$bMQ$#bSPkUFZA#-G6i@K`0+,5Q*c$CqMX@j1+pB@MV"$TrpXCi0c
+rM4'F2i#FCQ!9iiF30*ejj0f6'fI0%MaPAiTha2`bBd8(6fJdr[Rh&V3Kec+f%fe
+"Nh1a%aPD0%&$E)H5VZPQRpiCCbaAbqjME0iK&IA6prDV%Aid(mKP5Vc`e9)m0k,
+bBVNMM1N1)lDM%'(p,2Gd!Hmi(mBSXjlYQ&Il5cl([K2kP(E)UC!!eaq,SYGjQBm
+qk%[*bG3EI(lkeGUkZYVRiD1JJ5l'TB5UR#U(A'l#BMN5miAMXPqHbc3ArddZac6
+Qbm3YK4Y3"G)Fm9-qN!$*6GGdMC!!Zd`-cGcbVl0bG+T@a(8U4[lqSAaNP,4+3SI
+$kNhfPLKGCU2@kXZ(LUbqZ-QeTYH,pYE(d4[UN!"`2+2B'SfPj",qD"31HNaVM9h
+!V6(H')ZZNK2SLEA@4+P#aLQ[,EBQNJRIK8ij'8XRI$*3iQ%j!3fQ-[e2hX2fjhC
+UY$rCT(NLYrhf[%TjqHM6LTDCEbfliH!H"0iDM[SLDEr-kcZm2SIXpFZ*j+aCea"
+'A#1JhZUA!q'Sc&1*Y-b9lmS,mNN"Eb5TCY8@NK,b@K9S$!R%mQQM5%*8$d3P*#,
+l('1A-K3lqQjJC&M'YT!!(I'9-i[kfb)YKS4SbIQR@+fdA%Uc%P%NbFYkA63GLBJ
+Dbc5)'r3KSDU5S5@%BVmF6i93J65X#('M)5)(8Tk)(+@UT'-kf%CAK$"X!eXMUYF
+4!YP)ad`8,dk%Jk'8D2L&Yfki3D0S99I3ULlr)khDSX`80**LEqpL&Gd'9EX+S4e
+MhH3feCpGSVV`HI9--h#`q!I+ADp9le29Hjek$kRhpHTpZhVrNR)[E9,ZrpD`m+f
+'8a9"mBjD%I68R&$K*Ve1INGVc%YI8C(`4Y%jI)e16*%)jlIi@Ld9Gc'R1BGr#CR
+J2$jjKbV91Acb$[8qjr"9M+,[S&QiLjSU*9l5Jhi99@T51dS[lUrLNhG+cr-Rle!
+$GJkIY*p`(Tqd-jh(*qfS66Q(2aAALHIa5IX,cq16pY4ERF-Rl5HGabIYU3FiKdr
+D6ck(Mrk"Y*pbRMpTIp%jI23rT"h9J(2mLI[&jr%*QhUJFrMd83pdcRrN[@RRmG%
+lP9*rSJaaA[i`H'2-hQGXqmKAT%%@`YPAAGmU05f9"NZNPZ(F)j@hi[C`jFh)l*F
+'Lqk6"Jeka*l$q4$15R[3dCI,1@*-jeMLk'-DbpcFGQQ`H,Rd162M[5`LE4SiK*`
+2"`h)FP#@P&jif,JmcU4"h50"IGZQS$E6+UAj('0IB'*erE@G8V-dU0r,6GhkbJB
+qLh(`Ge6f5qRUqLDEfiEFqhLlTDr8`(8C+e4DJIcDbTZVkeeZT`[C@a#[U,`9D-l
+QGX6AmhDZ#jUN3Hd1(AANTX!KDEKNYV3ipl6YF'QCT621-pDiCXqNDbIY(E)0Xr*
+iFFDkD#-8e3lm+8dFa!#*Y3bAr&2PrFCe[-rBpaN-j4J,'T!!mfcP0MDeCSka2k"
+GZP&+,phSq&lZm$8eE!jTh'eFYV('-2!*2Mh68&X#pc`9M,3-MlbhFMd[#hlAdY"
+f@m#DQCPTVDj[&&S9Ib[B6YKjaGM6"F8'p6G"`A9mlBJM%dCM9a,3CIbCQFKjeK*
+MXhpr3ddVZkVpfp0clSeYFc4A",8$15NG[h$JmD8E1EaTkT+H$dbXjG$!'GbIZ4b
+irGD25@Ri"c%fNA`MSK9`iYb5XJ"Q-la2HeIFY'I6c[Zef`-@k*l0[)eh@4`@FlI
+4YTmC8TUEcAYf,h`mGfM6qMdE!PSTE@%C+q&`6@D'TD[cKlNKhQRIaXU[$+0H6Fe
+FC2qN)ib*81I!Fh9Q+2#$'8ZrZQZff@+1AK1d1'h"FTb9LfeB+0Q"##CC8VUZ+JI
+YY8If13Za*mCLHrGYcif3!'lDcA8cQDNYc)`"lVD[+(2D!heahm$MZ"mQ2#$F[RH
+!694MGe2-C-mG#IEdKS#KSlc'(jQe$bd-2'(bcUX22))X[A%&ZcJh8RIC8TYPlC%
+pHfrEh$E'2E6hr3Tl06il(dHXL[MPirQlbZqJi2GpF#[+(DQll$VLPYTlfejJE'j
+lTbdh-[Y"kAU`JN-dhfRqNCPpp@ZccF%kZ'4'F+,6&TLLm0AXlcDVNF(ZL@TNGcG
+UXqBC-0i-0a+$TdJa[[E()hcZMdIDYU&U9G99XDUJC8B9-bqc0ajJCI[f-peAPp8
+GQ9G[[k4m2lZklXM!`B@f3"BHEa$eTb(`L1!`#!k$L9b+#4l6(UTL9`HQA!8fMLm
+%68qqjjjY6#IV,&9-0iEm*(!rb,[LCC[lRpe3Zq[Cpc&l2k[G$6jG#9CRVM9V'fl
+)I@m$[-&R6qSZYmaNZXhVkhD4'R@lK4+2jE,G9r'bc#,HF",4&*DHCpUJH6C3iB&
+*MRJC)e6THFZhJAZ3!-pP4Yi3d(Ve%ShU@'epj[-IRfmae0C[qpJRjpqc2UK([Dr
+ZjPKqdQPUC)TDZXX4eDT4FlF1YdXEKh1l,HZPG1Ec8[V3B6Km,5DM3ka)qJ1'USF
+DAprBfG3mM`eNZ+F,GCmET(69fZ(0P[BrI[,[E[ckVRe2L[MDh8GBJf@ffBcB6AY
+[&cN"0FH`HA"iKFK`UaPPH`H(h5,$VQESp$G#a$+U-,Nl#[81MXrGhkh$l5QU1R#
+@TmimflackC,(Fm0YpZ#)G*!!(e&cYScP$+XjpUKaNkeA[kI"GT!!D@[,+"IMc4U
+QUl%aRD@''@Smk1fq9mpQX%U0`rl`&kVBj4T(mf0II,,*BEIEKhEYZDRpfkcH-Kh
+-Ad#p%PdHqc2NhrV2qHZijM@%kYIb6D--f[TA9,6GZ-,8e0pd)c)jEZNQG+jXUXK
+))pFS-[A)5P[VXFk3!,ZRhkHhB+3XTAIHdQ2Uhq9SU'2f"NH$P,lRPTjT9K'M,%I
+,0Fc4mS&GY5@1PVS5+8f1H'Ep-aZ!FVKrep!YG8@lKka&MTD[$$PDpYiL'cEIe+-
+McUk'lZrq)D11%,9#2km%G@)kG6Q9$BK2'2K%jA3qSDV)fI,$&QI,h*,ZUFG3eMY
+Ep$GMCMkbD'-0'lLVGMUk[q,!0kR1r&AcKeX#&E`Sd`!@Gr$*3,X@NFe9,ViJ-c1
+ZJ9pd@brP"Z6CUa`&M+[i!Pl8E6l'dZ*Xi3dFEVKKT-D!,Urpkd-Ckm$(&hijpr5
+((UjX&e`@Y$@Mkh`VkL"m9PFrF,"aq2Nb1'NRBXmKpL"LGb,f$iLp$l%YL2dMBRH
+1pFaP[)T0a@brLP8%TdM$,!@F1(!1!5H&Z"raEM@H30`00@,`HJM6B!2Uq5TdT[A
+(1Y0U)!C)$GcYa"lhZD3)lR@N!1kA%b2F,G`MT@Xe@qI2F-40@bqYe@4DDSp)$r$
+(FAZHIdR*YB5B)61p9X0E-beLhd"me"IR$J9e[-'qLE)dk#M%KJ0#BrX-0#rkq6j
+$E@'I3GR&+%ac`%+KfP9J-3Fam5Z`Q%MBMFp6ZQ92Yq$%(a$k%"I#,DH9)ECBa,J
+DSdq3!2ZP8TGd-B1L90RGc+!Sp9ZpU`Yk9bXX-0DNb54BU0CU+,#BJ4Rl22S90PB
+H2+DY+AF%5kBM0DRHH!dY[ATS4dSed+q9QGQ91k`UFhIZX+*-mGprjSQ@2ScemEf
+ikA20"4I8e2$m0SkVYEeCFKH@FfcYlCj@bGhXE1edHVSk4FK9b'lUP0`H@e16all
+-hHbaZ6h08P-KHC'VfH0ZlZMUG0UFbc`Gc4fGcQ@#DZ2mGPZ,kfTq45HrSZNPJXK
+6G3#F5dkYk)d,8r"HlaUq*La(r$b'VDM)'Kl$XQj[1*N+ql"aP%a(8NQq1L4(Z5r
+@'`p(C$m4@"e1K@,TP)UeeTX+ak*@5Xbcj2j`dYX6NC-mQ8)fX8RbH!+Vb&J%VZE
+HU*q(Hq-*8%BDYT0M#@aYq@593k1MZA'"De'(#`V%B`NS%)Yb1C(!&PFXRB4'[SM
+X6B"M)V@'pi465B941LVhaE%F,2XMDiJ)jpi)eVaN2d4)pr6%%P%Hkk(YBF*,m@5
+k"q*!%@rNU!B31TP5KCL2#DHR[GQfJ2Zmk55d5S8S2a)"L9L#Tf,FQdbQHl(&&3)
+KEb5#C@Z[cbFRNf')VfLJ8ZC*1!BZ#hPAbEa(KU%J9L6X#kHJTem'GXcRKA5+P(R
+Gj6iIPUVJVU6UVXjfQl29jA%lR-ff*KHASkV,dR%#j"#4Zf)4Eb+Fj&@T8-)c%p)
+N8*@53P(1UaSMB5b&&q6!SPN-p*9#GB)F#3("Sa"9P$L&3G"R$8&!-*AcYS'RLDD
+(Jhe,)kl)%c8KDCfTk2Cb65,49bH&Eq)aXDB1Km@%b83d(%ZS(JS8E)6m(YU&mm@
+#dI"Df@q&TLjCKL`He*G9X"$N)4[i3&qq2Lh$dJ8CA"dN4'1R0,qe"CYhBA)dq+*
+`R(!f%8MfNM"BeBVc**JQUa8YdXNdmP#$8"&)q(#+1+!kF"J4[STMdalb`C+q%)"
+6DG8*#RTVe*H3!([K3"3GP5kbH66')l&S8%l`eE(%bL6KTd,`X-qEc"I&&cX$$SK
+Hf4Z&$S&d"&85ZP"Y9VLHYKdF)e'Y)a&23bMiDXdM&aahApcVpe09*DZLlK@mZb+
+0KL,ZaBAF*+0ma!*U)FkAAT!!LVjJB,FLY8LN%Kj0KPI*C'`hD""Ck+[`!%idVed
+[95!)!'V`EmqD&,BKX8Y*46N5$NE*C+))T"*Hk+2@!(,&5diU0#`NRFVC5TXj@'M
+0QM-X@d(R%-l$,([T--[b%CDei*ca0-ZqcFkbEkpJfCN1PTePBGNVZPLfaXQb9kj
+MfAIdXq`lYl2XlqjJfGpEcl,[ZTGPVajNfAN2iMc%XVBp,'[IbE*0cl$Xr#dXkhJ
+Bjl-Xfj9jIA@$A6D29P&0@-#Db#Bqm6@a`%'Sf298PceTXFU)0[T#0N'c#PYfYkT
+CH#p#I"1ar&5@abThBjhQ+36bLidAJYXNXCk$*PNE4HpFJ9KqYlN-h-TCZF+l'%m
+fA(m[X[V8l%RJ0KNr`9ZAama["jH$fa3fa85V8dbc("GXG4I@IbH$fd9L,BHDmrN
+iD88Yral&&(#EbUBU[%["Qpf0-lrKI4'iABbI`T[`(aR$RJTZCVAPCkCUF,F8&QH
+`YLS@F5l"-Jf@FP,`L!NEVrUm$bm'`M3f6H%G@iIX+Q56-[5CJIN@r"6Hqj(4K(1
+,b&9@I#V`%c`a6'"E`BkQ'`L[BYQ#SmhX!F'[8[!BcB0$phd0GjU@d`#$iSqT(&%
+('L+VdFLQeX4T6ecAeG6C'%M%H[-EZp5LbG&d,q@'Srkq*,TpkME8JC,QpAa9JcY
+9$9LriM8c+MSjPM$B8IkGQ()6Ic@I0(S"Br`"M96lNbr)HhR0X2BVI2+rr+NmJKq
+j')22I8m30K[-E-2j-'(NLp[S4dqFd,HpqV-dGU,DS+QihbDj@K(9dhh@V"IhV3U
+iLab2LSU"CHZ&Gc4f1XP$4TTNa424P09(#Qm[rdCYrK4Ba,'S`pES3,*aG"JPX"B
+j(XqIi'3qaNYj&LE%C#`biAfAr!Nq9!Fe&8-ZGa0`0)CN#QeI!%K*9R3-UDL!e(T
+Y-e9VkTFpU90)ZMc5NND($8LPUhdKEd*!R@"IV,U'f--eQK+`$mF%cM%ep5qka"1
+2*3RU"+H5-8A"ALMU635"&$VK%3-k"F'UZG%+2f&K"9-2&X65pe%qTD0mR+34q'$
+%0FVRbrN69PIjY+KmD)V#JQFU`*mA+X#MD0)E59[d[Ej36f6PIeH!BlT4"6MYVG-
+9i+HqKViGIjdr43835Q(m3k[fTHSi*ZrAhIQ6&Vcb5'01#*qS%m@[eKiJ(N25rdY
+&fEkSG54r#[F,jM6r)68a(!L%bDf+4Pr)Rh$rU*UN%DNCmLG%56RZN!$5[*2FV4e
+`L%D2H5J'8-ak!XIiDU8id`@d[9pd$rNDd)PSLCJ88J(iG3F`jPEUBpp`+beArkY
+E4q[rkfiYe2mA+XT*T%)&11YVUJ"[q,T3!Flkf[!,ArqX!cKCFif[e0`c2F"IM2B
+!pRDEk!&k)PlIbJK'e,rT!XGIUJ&R[,eVe0Zdm)$S"$`-iPZ*KB,NVq[l'Cj$#+Z
+D0pPE2+5j[bISkBf-Mp9&[0NGB&1&p$9LN326llAbEfG%Sil9[14BllJ2%k,MpBH
+mr8EpdCqZ2q0Nc!H%-lqB2c'[(qAHSA,[p5C@[Yj*IRkd#h"JZiH3!09AL-ErkJ*
+Sp9(Y!K5r-Q-[RTMbi$QZmE&Q"'r1L8lJ8"qJi$5lf`3MXG4jYPU-630S'Bjm31Y
+8BU6S'cpXTRcjkjfJ1P2ZX$NA)+SA$H5iB[iI9f"Q81JX4D9!CjPBkF&Qm[KT'bK
+L#bRI,E5kD%UYaqX!e#f5!mGjm2mV%mB@5HL,(@"[j&5PS0R#'j@Lq$mU4F(rCbY
+&BIrXE+8Sq2pXTD$*`KZ9SM"CH+e5M%i@rQFD,68[S6d$Be4Hl4PIE9r0mG$SG+R
+6hLCf6E!&M'C6M#,(pCSbYf0IZH"XPiIf"`baj$KU-qD62IA2Z`"kFH(89RC2d[H
+EZG'a2HVmAY,a2HTa)ID5aRE(DA2paIhkNhl9rf,$[H4A'ql8#EkkiIj+Y@M#&S"
+!LS4l6L(pV"F-RCdFU6A1fG`)MU`8Vlj%[1(HrqS&al1D"Z5IQIPT"9$r+iM#m2j
+&8L[q@!,6Tk2K[V0[AiaYaVVFLqa8mr)[H+&d@(p91`KVI+Nj`M3crSV#k2C*ShM
+4!(lYG2eR6`"IMk-`6ckTEr*-lGSp@V[FblT%[iBhCrcUZ[8i@,AVa1B-G6kR0fF
+%dUK+%r+Z"a,Hd@*')0&M3k,c2e-ak(fL8adq[FiiAY&,2kp-6%j10mjXdCeqRkN
+2Vmf0$l(Ym'B[F`*TY0+IR!SPAh$YQr-`QR2pqccXU'G2pL2(+i(K9jAJk*cVjfm
+q&GjS1[RQdl%*j)5AAh)5jH'i)j4Ab!bkAM`r5#mrrKqcBIl2$Lar#1Ghf!'2&ZF
+-R20aKR"q!1Hp1*r#HCJGk*k'XalRFTcVF(i8ja$1CpJ"V`jR*8i(cK8iEm@j!qF
+HR-qa!ce6F&k&FbR1Y6Lhi"c%q8ef`!IH2[$ffA(kFEiAjcDFAm*jN!!Gm*IMR)d
+6cm%IrjpPE2#1d$6kjd-9fX9XXX2Q)TIG3Ap)"2FG#r"Q11k$5pVa5LKHRd@BP0r
+VDRI4A2"Ep"FJ8%Hq6hp5"-`Ui5NAlRAd0d4`[mDeV)2LEBh5r"C@V-(r-D2UTIP
+SNjh`0GZEl%XSrclk+b$i!a+lQqb,@R"rGR&R1r+daLClNjYTY&2R,fP&ckE&&&N
+ejZ$(m"SYr9XRlQH$@lqVa)S1)Hpf*9EmBH6Ka9D+'Ek)'0kI&ARV%B-f)Zph%1Z
+'Te%RLqp$E!qU*h3XTXe2HQF9V`6ShifA8GZC*THE`LjX"3EqP*VJm8(%m'BZaI4
+rK"MUJq"d)r$J'4'M2(EpMI5RG[3ES-f$+rk5rZ#+IL0FCllZFq`b0"@VJA&RI5Q
+ELEc2)MD%"rq*hb1)QGaQpNl`f+V8)[B1j$R"EahV&aKh)ADG%Y2l`#r,Y),h"U&
+INBM4Ui[38X4Z%c%&idr'-$idK[%4%92iNEH@-M2&c"mAHH88+hRl'%Bh0$KFh,[
+5'iSFrdG5arkp92k26Shq4bP0rB5Zf'SjdG9)qDAYiCi%ARUANcVU#%X,VjIr2`!
+!!!d!#'GM,QaTBLkj!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"%13!!!!!!!!!!!!!
+!!!!!!!!!KJ!!,IJ!!!!@!!!!J&"56dT,38K-!3#TY3`iUPPlr`!!51N!!!!!!!!
+9,3!!!!#A3`!!!!!!!!!!%ki1`1YPCTGG02REZYPQK![!9ZkQQhECfR'k@EF``ME
+Ph[TpfV@'TpIk05Ll0I2XNYfDcpF"1lZ&l@0f@l+e)cbpA#3lRQ4hVUc-T1fAX#e
+K@m+MqlaSYpPQQed,Acbfd+jE2*2XJB[af(+%mSYY&lD2X1LQK!S82VZZ35rCIKN
+R2#1hX-8kXT!!K5a(&R),h@56#58,`+UHq9fZ4"SL@YC2e)#[YQS9NIiCSMjG`kT
+h@'1aX0b`ASiN45L5P1-"Vdmf"(hQF+M6r'@IPV6NDR1YG$@jjh!0e)Z[jN,1QD0
+CmFfq,j8ZbJEYrr!4SXmHHqrRCVRY6G*bd4D2VM@,PQ$F,,MdBTF[(SSP3j(J@%3
+Yip)-MU'eCf-bfK1+8$l5qhGcL5bpha[&p`A3D34@)Ai)JG0j)aqmY1lUUj8kC9p
+5Y%6p-P("bI-F6Ajq,NFEFL24AV3&pFk96Q4Sd330d)2CG%d(I@&[M#K663m6,6f
+PSRjKAkkA%@IbJ9b@MHG20FFcSfTGP"NKdTe'l-&m"'e4jZNmhVPkL$LcPKjF@[h
+rkMPlc[06h#)RZlcqD!5pcQ[ek)1qT*a)AUcRe90YE@Yc,-AKB#9Ip$50U1jaaXj
+NTUb8`e&I+#EljF@NZH*(Q3aTM(18@a)hSKQN,kM62+klR`TeGfUH+(cJBf+m1J-
+URkeT'f@&kFEc5["0UprXqF3BBHH13BH2fC[S,XVfQA9DXbmA+M$lBU@ZMGeH0,J
+qJHj3Ki4c'BAQ5$3T&iP[4U#K`eTcG+S`4d9G0,*HMU-VeTVMaGPLR2+Q3R-m%IG
+GiT36d96F*`-P&T,M&d6$p"%Y8Ri3SY)XLpeP@diH4H#U8-3A6[PP8G[LpGPPVeq
+1*kkqHJPMa$3+e&9q14#+b#)C6mNLHkkGQNX+H--*0DXkRa5A0kP!idJS,*FfKU5
+3!1N"QBbNU$Plp$Z*M'@+J5KRkVEcN[c9d4EN$+A`%D+YYm#4KV*ahHhJ-8RdAZ6
+0VRJ$(a1&!X@UL$SZT,pG2r!CJfZB`1Ij!H0-i,1!Z)B*I&LJ8X-%IV%DZCZSb$'
+Qh`)lp2`KSQZ2%jAGpaYmpUUL2pBr)f[MIm#IJLYc1)&IU[VY"$kE)(-`JBpQ51&
+J![m5A*Q$#AcfE1CJ!RmkVXc""2kPZ$)(%rKSf"8SH-LPp3LJ$q&Mq$M4NN0S15p
+l#rm+A*R$LIV98hMkIrXIlYM+reJrmmXDQX"RlqBD*[#C1l(EF+%hl6V6Qk,e(kT
+-dp!#rJl3N!$j)!e9ieZ$q(X-0,6`@4VkNfNdY1J%$Eeh"JhGB+5KT6BDXLkMSES
+B$68NDDK4SU'Q665dI$-0YDbQ)@N4$E@YaIF1I(1YI[pZG#cj-qGpQ&FIaqML0fI
+1qp"M`N1RmHq*lbMG`*eU,RFQI+E"irMhCH56CMXb&M2[D[BPF$$m1"IRIKAASQD
+A`9rielrlKr!*lY9i@,4DcCi1"I%[H`,UR@I6I-UKEIlpk%N%5lk25cL[eDchA+D
+S&fI92ScUfe#K8YP-YBpqj4J9$NZSJUCSeY-B#VcV@#e',MU3!-1k4hc`a+-hj66
+bIPhQ&eQqJ&'i1+XS60UTF!ZcJX%Ca`j*5Z`+a23%j6(AL&(K2BT(GUrcGSA2$8M
+1$P0bFjHaNBQQGNTEG)-FEk[Mr2EHV1+i6i@@&)ZbQ,DrFfr4`$[h[[[`P2394pp
+pq#T@jcQA)Qe[S8AEU`a(mNHYK@G5KdPEkSKkrF)4kSaliaZc3I8PJ)U$fe-(Pe[
+Y$[VDrI9ddRS6RA3GTT2YKk%A9L)8qlHVeFP0YVlXA!%kHJVpmjiFGe$VmAe&G5h
+H"0JIapj(*EfDAXf@c*E-RR*eQMJ!lQS*VaB`$2U1TIIi8FdTN!$jr,G[SD+[l02
+%1*DmLI3rDp2F`,(83EVNlT@D*8VX#5SUrU5Q5m&iK[46pX'a%%XNkBVT2CV0i1C
+Ghjj"eha`NbE1X8%cc5qI6bX3UjL6"2D,G)H5GjpPfee(k4D1(624r'Fr6jp@-!j
+CYKhFUEQFmijhN!"qkclDS'"XYhci(6PYpB#r-[,cH`bkI!Vm-*24d)bapac+1`Y
+[a"Z8idI15%FpM-YR6l[p+`M2!Rpi)Q*e11VB$,hKX+qV-lc1l'1*lbRrARAZUf"
+KI$QVS-9DKcQ'TQ4X8XCBr-JNpd904J9V`1@ZEd*b85,T$dA0A9$Q@4`Yc94aQQj
+XB)G2K$E*RL5!%ULq[H9[FPqSB'D@UFBk$rbBLS-q6b`H@Ur8"#i2j,l`f4Nj*$0
+i)KhHch44L!V19PkBVpaGM`jAB`"$Q-Ca1D3lLk62)DfUXeZjmJfq,QpF)BNVEaV
+0IG(eU4c9Y8V,Q%eI0"))"C@DQ+1[jllSC-EBC)kBc5jr22'U3STc5R)hY8!K'Rd
+be#d$aR`HTf5-6bFV$Rc'mAU(#rSA$fMqU1+813pS4E3)(K$eX3(mKrl2UPAclfV
+P@GA[e-VU[kK@hDmGj@@N[!1mV@YfJ)ZkcM[!flSfr*ZZLrpCeqFpYq30chfc"rM
+D@!pJFeL9(U!cl2@Y#bH5rpd$6-EN!@pUHrqBYZ[X$DcY+CJIqGBP8Yf*rr6h0qY
+%4jhM[0l@k'(1rCe"6hGiFU`Zi[IG`E)QLINY`B-9EaKUq*rZB&ba'&PF8+cher1
+"Pa@Eq,@fAjdNR%2+DrZ#BXrj$f[lS[rSArHI56,Q!iSb[j(liYh&@1dYDZhGh[L
+khhD5Mije!IB'+lmD+&D(eC0rG3&I(HX#XRUPNQkm42$ijGMN@$1#hmq*cZ0`(j!
+!a@P`0bX9bFQehE'hh@*m'Y##N5,VS$Xh8[40(MC6R[rE6P#G+EGBRFX4e5X0j+4
+LqTp8B'D3!1mX&DG!CaPIjiNRPD("j'J[8*4A5,PZSFR&8fTpGbM"h5)VF*)(rEm
+aBF5E5HBh&-3Sp)*6m'cKSP-8rUY6j2ArYP1`rLmk49lrEcX&6aBZ1N9qX[#@8ia
+0&[i`MCBD9[%lJj+)[-%cZGTl0IYMBp1P9PZcmYBNfVN@cDBbLTc8DmVXZ(TFf5i
+2[am`4"16U-fBAqkTIcFc80Pe0Y6aM,Ni,[[#hP$hIh8"NhEeJH0['ehZGKZL*BP
+NUV-c'Sr!!Xcrh`-BDa+QIZ(PM@IMfTjTI2(-qi%kj8dkp0VUQK6#fpp3pRPq%fp
+kei%alh+[DH01Yb5j-HCA(ma1JZ9GjpmqF!IcqYX("@Q-T5Nje32*cDS(%S3[qjA
+kFGVRdr2YUr'p%epXRP(f'"PdhGj3"2[Lk2Q9pq*l(0p4HRl9A(aA)TrheZ5@)E,
+Q"BQPYA#UNi8[C1pkVAUISGjVe(ZAHYqZh[HSpmHcpq,kl"f8FTf[@YVB8IC&fAT
++Q[rL@e)rGH(EXk#f5DTI,I8A5Bh$Q8-9Gq"fX1)@C2C+r3825rd'2@)[i[XB[K@
+fS,dRNl&(5@GICHmKM@PaCSr8ArJ"k8Y'%Yd8PREfR8,128%$XZbF*D9@R#lj3)b
+NIYfKS,jjCe#EET*5BP&*6f$DJYSE@k8'U9mr+%Slp"8@F68*e'q[k*95#fVVV@i
+VFKm@$P02X8(SdQD`Y"Eje4@h,+L&hPh)[K[a@49h!-hCi%"mZh!)AE"8kYFqb-Y
+mU$4`5KSZ@LLYc$aY29eFCQU0LE3jTMNkrFETJ`2@B5U2&DE0l6[!U,E[ck825#P
+P65%e$KIpSZ+4NXfLTk6RLmUqRk!"1Fp92%!cUKD9p!DdUhG)UG8ll$r*R&j54BZ
+Biik506ZU$(fI%E26PZSLU1HTB,KaH23M&GY&@I$(*N[cA3&cHPkkD8&YRF*9iIH
+$$XE1-8C2jaRVefm$Jj[&TP&l1S4e5N8"AGUIRSHFjda4@[MqfkUDk(V($fCRh$Z
+D&fQZ#@Vl-P)UGNRING8l",4CfLDp&*K@,F#"-hJL24qi[HC255RS"c'DaVT4SV1
+Ja-9&C9Lm9#0kY2I(5SrZh2Z)GNr!"0k(dZm5E5DlbGK4BMe"KU6Q&Z24!bZ1C%l
+Yh(ldYS"@5TNSE@BFS8R20E@erM3c)&TY$e$jY5'HND3[Yhh@(U*5dGVhBSd4$,`
+`Gr@6qaFD6FE)NU$*D3f@ieZadSV&a3mL3J4'DLSci&ilFXbCMcda(KXmYLFcbVa
+TGpA-Sp,Q%&kj#lGYECR6&ZL*qIU1i(kDmB$`XF%qQUE'2Xqa8PYQ*0MCh38-(HI
+9rGbSI@a&i)P5lp,D`#&Nk8[@BRI6D-fFe9E6TT'MJhIYDKk[[@[`SpRUeIM#A"b
+a5Ui[&mrGeIT1+[Ap)fSVb)c8c,Q*DdX1hM8)M&h0eeNcS`Zr+Yf-UU!3c3mEIQk
+N*lqcd"LXJ8VQ"UFjVB(,X[9U6R3Be8Krac3eFU!$hUaj&KA[JKUjJUHB-E(TPk0
+Lm5p(Qaq!DeA@9&*Pd$5hNSaVE(A28pQa%k4lFNh0b0*Dfc[+6p!0050p*eGB!d2
+3Z%Aa(d[JN!"53cpUk)pRNU68-I1a5VSKF0ReU-Eqp@$Tm3mrp!$TC*fTNR6Mb-H
+"qh(4&L[EeI[FEGAlRlZGE,e8I3$eY-@TaPKYe&UfC(jb'l3K&Nl[+$I0)pfZl6A
+lQBfD!`S6Kc0$(GH,XR5lX,b-@"U5AL*Yd,J3U0$!G(ZXM"K9HXRd!q#H&)ZT4&J
+#@UpHiR9X9&fEI[66bdb'kYS(2[ACC3pY$qVKp`Xk"(I"QLUCSkD1FN5eDY6BSF2
+YbVVKc!(6GLQ9IP4+R6S0K@mLV@'!#U3r*EJH2,kfVV@qB5ReTB@R$Ei[$&+UFY2
+`,T2McilrrGE[lMpfA)P[1M"#&Y0#Sa'aEB-I8h)#DSjK9rr`@LA$V@D8$IB2Zj8
+-QjUKdfm&L@AX-*Plmhi(a@FHkG$KpK5l$T6PU6%Z01jG[HT)CVMC&Kb96SS40HI
+ZmCaK0FF@+GPTlGBIY9K2NVDkM(24LPD4VXT+1P-9'DSmk1eq`SZh+M4ffm'[9p*
+mMEhKm$H1epYY0Y[!rU2E($qJ@Y0X92i+kVASmZL6b,rM0rQEKHBYK!9[jCH19G$
+FZhC@mpDeTI@pp9Z4+A",eD0cT4P+4JUj*8UQ(PNTFbh2GalUpHP0D-@Pe0jE1dY
+lppXY0@5cf#e5kU&E1fHDP4KRf4ZAN!#pmFlpe8AfaTSL+F@+H(ElXlF"jA6[rS&
+ED`S1$*J,l)hI'V!h$YiU'hCYkp4ac5j,aimr40`4`L[d5i[J%l1jbkQ`)$kPlc-
+9Xm@8bJ*RidmERBf,LcTQR%AClQc8Ba2XPY(f(9A8GhreE(4rKB&Rf'HqhA"2Bf#
+@+%KE8-@piP+JhBM)VNUA@*kH&p0!,lVG9`S$mQb9pMc'p@+j+1J`RUh5j'`8&J%
+eE"QY-U$,Fhah)'hZqr5+[mimrBQ$&3kPPZA0$HJkVi)23QFeYAdRkiCI+S15pL,
+f)Q*I4H`qa(k'f1f)hBhB2b&fhhM2A#BUD8D`",GC`FZNB8S#*`DF8m"*)Zj([%1
+0aa&hJidSY0k&QBi"IViHR@RYfFjd!4!$c!EZ0UiHpmA-#1iec!$ZmlNLh%h#)k@
+U0EZAcEA(5RGI@De*0eD25&m@4h"l56bHc69eN5%pZeSMQY+08LSh+1'q1(-UU"-
+@fdl1dRrZLprkjQPq`2$D$Z)P8r0,J['@hY-NZ4ZF6De16eZV%R)TLi5VUN3JLKI
+f'a,CI`d3LXC&,+U%%ZBm[U[*d5#jFaZ*cacJ4k,#Ka+`1bi8MBKZ1C(!rVKam2T
+@bHfaeYGlE'[F$4kVfp-JeCm"MhRpIKk2M9A,Ermp2,KVDRbPfK5@*AY&JYF#b('
+",5'a-H"f9i2(hG$5eZUd1YGi@KTD@TeVcJ*$(+!fQZJ55ENl&ZA9JL#X1aVID*i
+k&4Kebac@4YF0iTT@F8hpDk+jTMiV"SCc+9X02,b1@h4l0iU0)6RX&e%X8Ja[&&(
+m"3)m4Nf'I0MQR%L&N`QaS8Z13#[GX9"BpR-"'d,*VQJUU@*YmV+#c*bBUe,i3`P
+[CeK1L%35f9a03Q!U'q'r9l"!H#0q%HU1a9%bd[#I$k*a,'rdb@S0[,PTZDZpa38
+'`$BBJ%$PH"bEXD1T"$MbK@9[($A'NaY&CbLCb&D8LXJp-FKCpSFhFL&#H-2`!pN
+2%V,2*!6Hc3'!mC)LNHS%1@$%'cl$!BM'(V!X%9J!91pa0&LA#jmA1Nb)C"IR+kB
+"`dP'K6H"c9,BN!$GKB)JECL4eqH$PB4!ITB$Y@54J'+JXLl[HPPdbK!8b!U(I+%
+Nq26,bVB),kM,8TRMAHlabG"B0**3eGAUX$UEA"khhBPp-biK4e59T@)-#%q-#eF
+dl)f(%U)bf4Ahc!-eFIJUI%eKSl)Z(-*IEFM6J5AH8C5IpDrca6%4)$`#8K@6cPE
+!3h-3L%VPR'bJD5l6)e!pjVb`"6QZH%,#2#r,ffZHa+6$`&Nh1HpQ6E()FUDZDLL
+3!*F4mMYjclJ['SaJh1ihJe1A,)-@CHS2#B%HPJ%'j`RjjT3-5HGT11[3''kcSP%
+[M11mXVN!aDX9TaBmf%mXb(+45U53!!F2JL-`mD%Nem!Z$5&#9c(mI`R3"dRkZJ#
+F6+P+b+)h4AaaZ4X+K1Q-GapS*m,4#0CALJh4q$VZD8!)01cc*R+Qq+Yf""$GXMF
+#(J+T-&`5[,!hCfYpAAC3M-4Hab5q$T(&9cf29A"1IGcjX+Zb91&lHHfZ6D'KL'%
+KUD)Q'IB4$DK'R,0H&"9j4F$Z,09+)PYi*"&D,l1`h5K$EE1bG3!RNZ-1lBpL[#J
+0qZhFQ-5QHHbTCe-1idNGLd`aJ@3FE`Q`A%(a!&E&Vj58EeLBZRaVTlj('2[R'Y4
+rEpG-AV8r5r-#PGZY,RjkF3q2hR'rIcRk"G`I@Z9Sj8IpMb(-5h3IGcPFr2MK+4j
+fS4erPXIaU%c2JhIFbhRJM[Z9VM8Y(*pI*beVT%,0pGQ(*CS2eGXBAh0l[@d9jhq
+FKpkiheY[Dfr%rF'9V3l1keqfUSQI&"j55126rbRJm1,FU8eB'i`9XK`V1)ABV'b
+Xm#q"JEA&(#ZDJcc`a6&pL[V6@$I,XHYDJ$&%@J9[$c#H)8dQFaPGpd9JB,'[N[F
+3mMDVXB2!``)PT3iCLP'H!L%@3XaimeCH-krr-,"le[i9Vl(9hiBBhI3PQS0r`M!
+&G9"Y-Fe$hKG3ape8UY4d'(N1Yj'Z!jI[bMiZS[FJlf(N,9+A!cX4ke"M[F!HbA+
+QldDX6)hG$)`4&H-Qe,dj[eLiIhI[*!#,KIm2$3!*Cf-ZE'PL-5kj!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!%(&!!!!!!!!!!!!!!!!!!!!!"KE!!""03!!!"B!!!$!8&*
+25NY"5%`"!+Qe$$LU@AM!!!")3J!!!!!!!",0!!!!!*qp!!!!!!!!!!"cr!l!kf9
+QPef8fm9D0eXBi3+`P4YGD#PINkd,j4*'@*4l1Q(VGAPiHUh24Q6(emc`$GLYEh`
+GX,0EH'Uh*9Zlf0E,K41qX#hCNEfb-NrEc`MEM2!R2,V`ApKhX3B,ArM#&YTeC*p
+*&Ri,ArM#6l)*j4GEq-,f%4EGP&#"!-UZkq@$K8m@eK'qm)8mKlXMYj!!K5a(&R)
+,@mK#*K3+X+VRS-q95%9%LbiLFZ#VVPY1T(f"U&IM@2jP5b)4&4eVaALD4H*T-4R
+d"m6b8-!BMA61-IjB6@VbY(Z@HCUm-cJ(1S#[kVfFddHej2(Hqb[RjB-ZkpH*lMe
+kpIHRH9e0`Q,@RT4@'ePV+'PNR(Uj*j!!M#65NAKS*+,3Z#L(Sf[VATq@ZL0a+NC
+krQBQ8@22ciIaI30bkS&9LKp#d(6@d&F[XXfH,I-8!fR@+R@*4#8RaM3Drra-3KZ
+bLQJIfJ+lHjNE'@Sd33GSEcjGe8%rh*FJbTRS!D+&*aA8(plASd6BkA`J9qAMa@2
+LmGb``SYb3d5D8iMY,8DSKh,2&r(1mL(LQ3fdGk(TArQF1@2kP,H+kE#r5iUMerQ
+!McB85)ZTp"GmhMdQ5hYlbd)F(U`jJjc,69JQ4U9!*#&fLI0*GFPIjh+NdXq3!'p
+Th)LQN!#fa+Ck5R-2P@TZ96eGZ[Yf0XT!"pl69Hh$h&qDdE`+I,2+0hqq05,AfD2
+6i'2dTf*Pq5l6TMB'#U%5Bb"4k9NImk1p$6$dKKSNR-dS0FDPY&M'(Sr$38qSMG*
+%CT5B6BU[&C2SLGA'C(QHM&[F8'T-TT+"#paL5XSN!b*3%K%a1DB(PijSR[b$"H8
+fQHfUfRML#!+A4H+"D+C,C!fYrS",p(H*bG6Xf3Xi4N)P3eh@*3BMFC'PNaQ4jFq
+FLB@NS$qD8V*-aD5NZ%%"'N8#X8,D#*)XT!p#FL4`e5U5DEF6kD[NdL'ILC[(l2M
+q8CF85NRTJd5EEN3Y'XM(0EG!ac64eFLEA[d42QB**A+4)ZTi,recrX$R'*c$HA`
+q1H!ijr'jJ6L(mrJSIc+(mrMP5Q3R89R,L(p,A2$c$84cMK&9hAd1RpHUX[rP2b9
+I`[m(I`+ZA-2cq*9+[6f2ciXJeq!m2MpFJr2iPbKqIB,S![X)$add[6T)0!-qVYe
+k$TplPe0Y4-[*ae`+I[PD)J[Di-[Kr6Qr2SF2$"QrH`crTfLG8EF[IiQSrTjcq"F
+Sq+JrQkiB`Dqi&10'D&HpJZLUPmrKmjk$ik1'A-6e4amLkhm(dB,$D$B[rX`r&bV
+id'Z6HC6r([#r&Ic49YT3!cr'Rjb2P*lklri()e8C(cT[fMr#I`,m)+#ZrbiDlZC
+2p1IkmKTd[Rjm5H%2[TZE4hK8`JY,qSPQSeGZrF8jI0jaXPfkphV6m1RH&%hr3-e
+@'N!Y'UMp!3dBpp'!#9mciZD60&$r$!h-(D5"HFGSi'Se$9bMSB'&4KU`Q'R!1KR
+IHKTScpFaaI%iU!rbPhF3+VQ,)1V,`SR&-q-Epa%GHl[I2hYQI'-l1S$A0qEJTGI
+TMBdje6V%*q$HMFU11$,c"mb2GC@kK2Xajq(H3[cS-FhK8,i*RV(e"6D[SMXiUEC
+K9C[J%2UdrDbb3e[Gb'B6F`lQA08p3UDf`@la@T!!q`"V-A5AkjJQDa6kbPBMhe4
+pBff$aq[f)(XRiY1UY`,0l@K"I!YVBCT3TG#RhU[K3kE+i%PKX+aH@*ClhR+U[-V
+3PQ"CBd*ej-*9&rBIX!c5j%4TeVKdQdXLGHmI#GF+'ARX3-l"XPpA2eKa2HZZk2i
+4+JY45)HF9kYhdj5kH48p3I@+E8*Qa6EADlP6#qTShT*6&GGf9+cF9UIVr4kERQd
+dP3Pp*Fq&SXl"iDpAEf&9S9F-MFfh"BhC@GQQfJDEV&ATAi9D1(C"-AUqU&LIGM-
+8[*jY'(CP)l"V@9#6lFV13XkV"SRUIrrQZLDDfr,Lp*ah@r-meC8KG@p1b#3Zk(e
+ba6BQNDDbAAJV1-R%S)%lG$al"A"lM0m4-[!2BM5*qdD16K-bE(jC&GSI-qY@hj1
+S2,*phi2U28%$G"r)AXlD$5k$[U2#FTadDG@0qL1(PMbC1lPpbj'EJfSKBk#XNH-
+`9ADQSEhYPlN$V-fkQbE2LF$c8l*IXYlVLP!PDqYpdkb(!Qr-A2(X`AUp34pI%$+
+i,D(*q&B[Xq!C`Pj%L+#)Z5B(lG9$4ph&f01MXIkMHh,$A$Ie$[-XUQb18%@3!(Q
+YUk[FeQ"h)Y$l*1kR1"i3EZr[T8P+l!Fm9QR0$B8kBf&JD(LHl9Gkp50,JNpAqKF
+f"!mM5eZaQLl*$CYRV,!B0J`GkEpY4r-Sph$r0r2XPAKp)BjB$HGAL"IZ#Vm6-Vp
+IJ&Y*EXJmibZF@lVrYRjJl'LqbT)EVRp)Z!kXi"$95ijIkHRCRpEVH`JZQ4QDj,B
+%,mlc94h[d#Z4[[c3kr6K,cMifE28p5F)6d10aq-35dZ,M6GSrQJd%1k-VM%'H#1
+bCr,26B@[M)A1C&T*Um@'rN"9-6)TieMmH8RK#djk'HZ!afY[3R*C+Yd9NBaK0'G
+RF03d9F&T@ZAJ(8FUXN(dT3'8![ZPVApCq'+D0$@[P02QDqHYF#MJ5b3MDf91d2*
+3iF[V53(*b2XB$9l1K#P#*@HBPaDCHqhSF&8k+)4T(+G$QM0)fJ,5FT[,`TQ[#i6
+p59NNcVaTZ2"&ekpSC'X6&R%e!e)m'!R*R,K'MaDqk+T'e13DF6A$AFR8Z`iT,cM
+*fp3+KkLdk8K-")aa$+GL4%mhGacd61,G$LId53eSrLE#qQ)0D%1d$$9!#[!#m'r
+q2q0@eEqiPFqUrYQYh2eIZ&AcF89j'kPB!6lh0Dm!ArLk@!%qplAZrrQkr"pp29C
+c+ckUZCrf!(mkdJ0B@bab$p!Cp3I@4&2Trq`"aQ1U!Cpkqq#)YfdZ"rIf"-b2!QY
+5Q9MUhq[lTccjBd0&Fl[9kH1DGh@'I,(Sq&KGa'qlJd90!YHh!Jp@r&'iiEqkJe(
+(UYjhV2rMqF$EMNepl1eh*`PRNBVHIXqaCqX2prBAp8IlBIdC*f-q)$[c*i8[TV-
+Mh&X9lM&rFXdrGC)2Mh3",SH&[aSS9iE9ihpe!3q0G!&j[e*&$#m4I&eLBRbX'F&
+[jd4M1,`2b1-i[(M$!NCLHR8XmAQe'*d'Y'+Nb(d3+i`8!q1(cC6jSl*21d&PTYa
+UF5p'9#XhN!$ML[PrA)'C3E'cP#X&1X[N'Pmb,3m0aJqV&Qp[0KLY!92eEjlZ&Qc
+b#a6iZXhc(e1Mm3Mmrp&XB8aIcTl'H[[mIKqG*ZD2a2(@rrrR-ZEre'#BMXdKGD5
+TXj!!aP"(ZMSID9b[c5&X&rPfbiZdp9cqp8ce'8,YCrQ9)`bDHeC2DpkdZY,HBpq
+%6)CEaYk$b"3j)i2F#MP6Lkb-XB(AY2dp!Df"%L4NpYh8@GPcd09S*QZMUe()l,q
+TFkT4M[%XPh-"ZCbh(M59ZCcQ-L%cNkT9,fpjq@DJR1SjH1!QFmQK!mB5Pr1C!bj
+RrdfLEXIQ6JhRl'RXH18'iKYKX!p'Zl#X0mZQmbdReBf)6qMpA[9d0U'Qa1hmTG2
+YR&r@-H8-bKDh%elMZi8+Da"j&@2%&MDJGTiSI50rekU9qa6PEPEZBH@q4ER[8Hj
+2jHrPp[`GGPl'Hrjh5[l)NIG9@EXVQ[ri'IJRM'phE816B&q"[6%#YZiFVYk+ff2
+90b)6MLYj31M6D4&l%pp(m+ffKPcGZ4`fkfKFbehGT$,-cqh"eTYVKI[ea')8&EE
+hRN61R5%GXV!V5!p(FYI!QAem9e$cpT!!1YZ%+M$1lDkJN!$jNee"(C18b+%1e'E
+9bf#m!flN$*lMLV%0[aPQmhmch,`E9D['A%-e)F2-'Y+[Y0THTkUMadRcl%Vcd-)
+'kjFR(kGVc%1p*jCBJJ2`H+0FIaU$Kf81IH$3PmbP5HBapC%DZLCim9b`F6dDUMc
+fYIfl550U$$@N'88q"Y`l@(ZLDNI2UcHE$Vjk#ePlb(3)I0U6C0DEp1V'MERAESB
+h@2f&(C-0XdLcBi[j)&I$I%K@iSRF3-GF9T9GbKVI4Ub-#'q41U5["bSmF+%V888
+F9AM,m#*`6l$j9-%DJfUr9Z$Vf-M8N!"pq,Z,$$T6`ql[h,YSrjD3!"Ee[VD$mDQ
+LUNlN882(C%695P6ISF(Y8YYJlT!!BBZ3!-Nq,'41RS,$0j!!@RH!5S3r)&3pe2J
+'@j[GXC!!d0hjfP(hQ8l)e'`Bh'&SqF0MIl[TC`H2(T2M'`i08D1KAUp(E(2rlA*
+18-R4lHJEA#eRH*@-U[kq3DqFB98b00T0%,'+9jMFAF9k"mIR(Zc3i2BFVcT`PXq
+XVpI[@l(mbGaJXc8d,*aJ3dV1cY'F35A('UrBESPTMc4D6T!!fP6&Fp'+[Y160a$
+[M&h@aakYS5Y8,XF62cPQGeQYeJ-(Mfa'Rcl1dDa!Ldf`'iHAEUZMhRY-dp(pP3C
+Ii(AQ,aah1S26@%Qf%5cZBKF"E48L1fSmE(&f9N)&[fKfAFTdb,2@Z)SBFpPL9Y+
+K2m25i(Db4JBhE"bZdk(,DrRCJDbaplY,rMchr,FHUfk4Z5aZGU$V[!ae%$ic0r5
+HX!fq938Rl82X6F3H3ZaZa2i1X9X3fiRBhb0fpfM2A-9UD%US!VGTSBZ&38S$*`'
+FNm"*)pk&H)F56b,ZK4S5["l'2%Z(HVi@R@R$QFkd&SK"VJEZ9XiHprPF%Gc0A!(
+FVq#-F$F`Rj!!-DPf,CVT5P6ZZY5NbMT03m+2fC1i[F@HbZFD`U6,6MHT@&2@+@3
++Ja,H&qG1KM5XdEUGCfNVI[6-ikIiN!$mJah%#bB@P`4lQPSFJVFBaQMGeb4i(Hk
+Q0VH[[8d1HBVCpME"kl2Bl6lV5Ur$Cr(k()+pQ,c8ir"j(DhYE@k,Hk@[eG(DjPl
+*@&dGbf#*-EMM6`G)U6",Ll'%P23Rel1B'*15kid6*`,$YUM&i[4F`kjXBeIDhaF
+"HBT@J22)M`CmI-meLrRAXr84-GV&*#aaMUjR%[jE3#b55NF#@*DFbN66+EBZ,-C
+C3)SP)P'aLa0B&dQ(T8aD`GVJ6dHNZ*%R&PLbVNM+haN98bb94MCRNf)BimEjraD
+SCIji&i[%%NP34KVq6)'8a*,TJ+K`i!mM&hZ@YRUJ!05'!P+FLFNNPNj,Q43d#N4
+&Ia)FNqReV$156Z8CCH*LG`,rC8$XLUlR4"Mc4l'9@Zb##*R16LNCCe)Rrl-$(#r
+08TP1L!0&r0(6'N"SV0R+#i(hGACILm1bQ!Amm''+TF-m2aS&#5R*dK,cTr"`%`Z
+S`b#%"aAiE`Mq3%"-T5)32kq"3TQPi"Li,1aI+l*1%BD#@0&))*+'RPfLr"M$$qR
+b8KCd&lX$)M`Qa91+ZpTD,1iQMmrVFZ-jPiH*FF9PQ33(C"#4HD5S2aP*XCTd11Q
+E"@Q5+&XT@9('DQc4#2l$3P%1l-L@3$pIc-E)F5%JH"bLbM8`ci"2f5%JQ)S&fm$
+6R+D2J6f'c5J,BP+Z#5RMV,aZ(p3N,[UkP1bEK#6rU`Bi6**0*NFM8P,a8,"S)q4
+hmMAH!5N8aaZ#,L-dpBJLC*'I#F"#N!#(f`!cqC4iA8D%TBXbH2MM&aqIfMFjX63
+m`Kd0[LJFBmlQ"&,mK3c$FlN%ikm98V9j,6+T$2*3Je!4Z2#401I!Uc5-#&mPm-F
+J)"mX'3J$1*e4R*!!4fq+"j*L$!j%d9(S)T[&*4D9iL%abGC*b68TMTm1`m-"IkT
+3&2qKHf#!L)Rq1(3)CU+SNY#&eqBme`pY"mF)[0Ca%6q%b1-V0Bqli+cl%RimS8"
+9j9C&h5YkGh8'$8A#M`YhNiMb)3@93P`S[5!9ImI!hVc8FL)[iI&8C+h)MHd&$8i
+@qZCj!#GHd!lYMeai33hql9bIaL*hV)(R46ND#F@jbH3LN!"1iVNhGKI)0B#liRd
+R&4X@,Th#fFMA$Crp5aM8GeGi+YpL2dhe"Nef@6cm9FHGI,+0qcf,d5rJ[Rpj5aY
+rfId)`YKf6%pj@MaHh*rMXb4dZbrcD6HBDIPF'rI*I*k0qk@HPDdmIS90@15N8YA
+Fr'XCe3ef+mGAh@+h,ZIjGr#C-ZjhfDe,mGT!YAGC@`[2keZd[%R!rE!X'MppZel
+K8a!X6VBKK[q$`@-P*l%l@*k1B0c`EH6K2fl`@0R[))Eh2cbQP4!$4aklbJQmRD5
+@mABMEbHTFVQ,kDV[)iDACA,H6X5`*9L1l3-HYK(,X81)iBm*b*`#`'LrEK2IiUl
+p+[+fVric[Y9CqcAN(I[+r63$Ic'K&(Ph0j66,16GLpK@UT4j(!C'SeG29d(,kIQ
+h6I4lb,X2HCA8)f1i%AY-LGd!l#IbQQP$b0-SX6@)(9F`9L(fNK*EKPLi0,E'(ik
+Hr9-$Cri!3H'r%Scmc3&9`i4fDCfBE,Iar2m$!!!!$3!*Cf-ZE'PL-Lkj!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!Sk!!!!!!!!!!!!!!!!!!!!!#hi!!"A3J!!!"B!!!%
+!8&*25NY"5%`"!+Qe$$LU@AUp!!!i5!!!!!!!!"@G!!!!!&k"!!!!!!!!!!"U3`h
+!kf8Q@pR+EH@8ZpPH0e[B`LN!@cH,EYTNIHE#0P[B`[E+2,mcVm[$dq2VXr`)ArM
+k'Ej,GQ[qAJIXl,D,8Zk@m,-M2,eF113,6l,2@eQCRQeM#pX5RS4(&imYY0[QC''
+,4aIf@l*S4lE&&Z-RfB3ZE01&,f`ELfl++4i)S1`UVfm818k@ilQ3!&Yi#Ahb#pP
+N)3XMbj(IK*&P2IAmE%#N)U*Plb&k2ljUkaSLl6H*"MAZ0HpaTY-*dEe461CB2*N
+6-p&`4*`@LeJ5mHjkbqI9T#CrPrp+IfYJ,ZI![k6kFFkV2p896`aqcV#m'&cZ[C&
+Spp%2I(T1`0XUV'*GQG4k#qZ)C5b-8jrQMf6Lk9`m'CZ++$3ZPI$6GIC[cUAkidN
+U4`EqHKk4Bq!ENrLHK*`QB&ALMa!dR6ra"jFf,9`Sma3M1GD4kK'*+XCH&qQ#jlp
+TD%1Z)YU2YU$CGk82'@Sd+X1dVjLZ#Y&RpUH**"Xp3Y4i5N(pc--$5S5pQJpNBc&
+HrYPiA*T8H*%d3D3jMGLqFS3'5(UfM(H1$a(2Y01q4Y[rjh2fpjSqdcV%A'qi*j9
+%Vr-c2YTB*#GQFqr`qG(2jZcUDQr%M`IVq%0,-iLDRZEBNM6p5M'4LX66BSqiJP6
+[rLY*)T9TV[c+i88dLl396DUR03p3THBfeH(+2AH`-qadB&kMkTVN&DE(Yk"mLlq
+26BPdlUI6i'-*CrZULVePNpS5+B8U,*'d`Eqj,ibQ0X,3%@U3!(!ZSp+561A%+[C
+%%RAcT0U5ZSKC8U`TPG`SCY!*UbfCD88b2R&,T5@6c83ZpSRC9$i6%B'5MSXC45j
+dZI)Ia5Bh`fbAmEUa%36H'dp'%[NHNGNl`K'['1i4-pQ&#aXi4PSP3lfh4ic'Nb,
+,CI)L+rk@A&4+LSB6@5A,9Nl+L&X8S$0))&C+Qd+5a3Y#2)iN9fcaTpe"C$,+*L(
+r,YU+KqBAMUUZi!A2Ij@2%Per!eaRY"MAh!)GFd3I3&j0l6rJBfT`XB*r@NN*R8P
+rQcr`Z@D[irilrL@[iCI-pera,jh#(pJlK6mGIYLaM+MfXEI`hr8ErZp@)RF49E9
+2i9Gi8FmI*PTbM-Kirj[iTGpjrP@r`BI0Pr!re20VI$4eCIb@Aq-A[ITrr'2kEr!
+0H2)U2)r26EcLIr&jam&acZ0clILFl6`qeij$`3FZE8B!I3MrkHiNDRJFEHA-Yr!
+j4pl%R1GIABc`rZ1rqKqZ2II!mra,qVlTRlpA'N$m"*pVcchd22pCH,*GZKrhTVf
+[pUBBU)iZ[j9'lIcl))df2%1MMQGTe28`M6CrQdCEMY1Sp`#0YSh4k+TU'Zfk95B
+ipk-2%aepN!#@h4)B+(CUaR,(4S3H4Ijb"99+*c"8i&d-5FF9I253!%IaII-hpk0
+G`TA5MGDUP8QD*AemFC+UT8I`QL(GjE*)KGp1NN(DPDE&$ZQqeGZp5HR'00@3!$!
+Nc@QSB4JKfrC*pkcdN!$*BT'f#YH`B1Ihb#L-h16Yl(),2R38i(CBjMC61Zj+5Xr
+,6,iP-cPFC$,jJ-c%##DMH"XB"LUF'GiR`'`@Q$fT-*XKM0cXF3I@0,F+,CdbYa2
+H&bl@Q5bNUdZ5IS'&CYJY9'hSef*8eEI8CYpclkk@a9lTa,VYMIBpXp-Uc[H9ajK
+&1V(rhYM-eGXEYGC+Uk&'XfIfbL$0K!NFARNY4Z5M8jR3k53dqPC$6G5!,!Z2[R*
+R3dfE*kBcH+5[4SPZ@ldp69B#dKLq,`*Y%G!fbQJmib9m6q-lJF`ANAPe%Bmc4)B
+A'E0@ElFDdY4)0CV"aeB'1Ir"2fkS5D[hlj01mf`C$fbX&TRIc18e)H08&K5jE$N
+8LDSE0%ZHd)G@*U94QYPqdMJQ(9-Uab#-h&UX5EHrTEAGc@e,*q5,&94M3cfr1-p
+K5++I-%4*lE-Y)*e[2HRD(&&eB9QkiC2QbleND0Y,KKK9f"FX)-15#C+Qhq2DEE@
+[DADhZ'+$"HCQAA1$T1([YMfNLHSElD3DI$*%&AVAlNDlDXIJd++DYKYMT"jR,@C
+hfMKbZpQaZ%Xk`9TB9jU-4Tr$1mb5dSQ#"AcZJ#Y`4YGfq6UEb-CMVMfdY-3Bh04
+&cZaHQI'1k)`LApFqk95)e,Ia,,#EF1d@KM4Qll!DIF"d-Z#PSlAEBhA-ACMI@-A
+F9U-`T0lDjVKkHe569SA8DH,)PcKS"K!@K(3bmcSHC9f'1MMYM#LTY,)1V8)c1!p
+!Kb$V@R)YTRJkRRG9Tq$Q&9&EdrD4Q)Be&4C`E+aBk!TYXQ+pL258)r0G-DZpe%K
+2rILZ"[rYAHhp%lQ&82%eN!#19Rm6lpRkiYQ)*8*C8ZfYrSDYp%AQ($kHR&24i@a
+#Ek$56dh*H-2#PdK+Ar!ab9M$rN"c+j+VXVQHH-V5LmEX,)kDCLXiV9Gaip"Pie[
+%B!j!B(m@U@)+b51!%C!!BXP`SSLdGhA(Aj5qk+eQ&rAd0!@l`!Rl-F&d*Vj4CJr
+&$j@qk""RPC!!,,cEd@#6TTIL9('@ZEE-20#-2KM-FcfBfA%kT$Q,9&9#@Y2NGA,
+QQb+piB`X*fIH1PRk`LB8MCSk"6iEd895b@Jm*R2L'RfTp-88C8T0VK&AXlFRNre
+4,HP,04GSl8!YUE5jH*m)'-YV101Rp26afS5H'HcaF%,rk"4r+MZ!V)AJAK0%9*m
+80`9lZa-Ei"BJFU%(YcMV!G`Yh[%!cEpi31@[2+$X&Qpl!(H,GcbJl"C[Hm#dAhU
+!rVmpi!$#LKDGVMEZ!G05hHZ$IH%dYi$rF)#cpDVk9EhbZFJreqY8Yr#,HZAG`Xm
+mjA@NXJHmAGRF!pkTl,)([&hCZPp@0ZmAIPhCl3[29,Brb1GpZP3ff#2+KAhKUmT
+qVCmUGi*[p&2RF+Bk`GGlkRrU![M-3&(AjflL8m&T'6'5#-IlrV-,Z'"A(hK`DKE
+J$kaf)DV2j[,GhDP-%KCJq6F2i&JAQ1S%89RPfJkXkq+GS$kh1Gd6l%[`UH!&X'U
+Eejchbk@[l2!PlKd+plj`CS2F$Cj9DAUTkS%8i&82*"5qf#2caqrFr*mcjDTVqX,
+a*$BC,q`drjGRr4F%R2qRAm'HdL1Z@10#@QjG5#[J1(TKk19lDZ"q`Y$ik1m'b@$
+BJ"9a3c3+&'6ac54Kk!IGI'XTS3(q4YHq9lk,A)XdkGf!Hb)ED)8hqFThJHj6-#C
+#[MFBfK@'YjaKU%P,S6VAEL!X*"[`PJd@J&6p[L"kKdq6$Mh!3M)-hTfHj,lDrTa
+K3,K'lMSQV&9makZaMQI$+l(Ya10`q"@ZAPTZU5RL6"kb9N(""LKi5"LLjFk6NiH
+`ch8-qf3kk9RA'TlRHTm`G,TIaYGMKq`P-hEAc0JKXe9C,*-(LMb`+2H#bPJ,e!B
+,'8*UefrCU[bH0NIbTIERG#90aT`RTE'd9,$j('hl5"I6+9YSicE8LGU"h6(J+-Z
+%f-XlYNhTV[Le&&-LRZ9lGMa1Q,Ec[AUH,qm3EX*q[,*M@$Ti`$f2%C-lPV(+Nm@
+h9UfmCbR[HZAGUlbh+Hqpb[[TiRXDld,`RYTCR!E&Ica!Q2V*HlqZIRhE*lk#ZZV
+&Yhq4(Hh-@Q'S5[#-5irAhSVABl8h)(0!'+Ti4"M5D4($pKNG`,I@&I2f5j)h44V
+['QmrUF`VT,h#818e`ZG-a2SS)H`B2)@FZf-kC(PjPT!![q+drTSd0[!dMmHdE6Y
+LkN+VN!"RbrApd4Q,j*j*'0)HBBD3!,E@`4B5!hp[lB#3!&pNEhB'R-KpK,@EqkI
+TQ+CJJ8VVN@qV[@'4(3lT4rCGL-qT[49S2RFliYYB1p2%$1MYpQPid4ULTi6aUU@
+SmfHGTkFCcCeT9V#N951AA(A*N@(R1&@R+`X@l#@Qi-4ra#YG2Np!R['UPfSIe9r
+,q[ApRm@K"k+B$MR2eqkK@GEPqS'SHZef)EpfZrF&kA5$PCCcM82kGGZYZX&2XCU
+#`eD&kRNQP[#-6pjBZidCBpma1pTZMeS+m`ZYLqa0XPD9hiUeFqb5B[4X@E%Kl9B
+SH#hE-ZNYa,(L@4A9&(S+mj(c[$P&5hrrCQXV,@YrVNB+E'pEVPSF8`p+3MjpmH"
+6DlFce+DK5hJj1X2'S)%[GU+`!,J$PR[KGN09L''I%R8M4qHJ%PG8'E(0@-rke3q
+N$5-lpMqUhKXe3rI4`Z@Xbq`eQd*kj`R5j93hQ%B1AI'8G'V(YT'ESfSKEkD#KH-
+`9@'HZD[cHp)`ki569bq*miPYi9fZhGiipMSl"eqX0d'"Nr2@IZhJ8T2CP'b)QAh
+1@$@qY9FkFD4S(b*%8+5q6S,fkSQM[R,Xm*RBND0lT8QZQhTRrAc-*H+NMl+!Dlh
+4jiVfTb1$6q&pQZ-"iBiMJc4$L6h)B`DA0"(VlZX&KSER0AhIT$j`4I5`)GaSMck
+1,+eq2EeEQUbIZpCThM)aFZ6fR@eRZ2FHq@L4[4*I@SSM9XIjPH+PYm*[61EhAA#
+VN!!QkZGHcERPMYaq""Jlfpl[P#DAIN(i)&LK3P6IGRrI4&rlbk@Q@$fUC&jXKXm
+CR9RNUcS4-LQ4SG!-*A)S"'p@(3IMRDK'cZ!CVKMEmX0*YZ+(NjM'8+bZ[SlUBZC
+jG@4DjfVk@c)H28'DVkfVRfLdZpj6IB*@eNm-MPhKM)kLaKfbrcLLMmXFKX"K+#2
+P51Baqd!GVBc1A!BfhLr&$-FqmK"Q2D,'A%HD-mM(J(XRTMV'R322hf`lq2`Yj"S
+Jfb(`kFT3[FPQ8MZZNeki'EA"PPi5UME2*mh1EI8(Z4VeKf3PRT4'3mZBXE#D19j
+(0-5&PdNG-bd&+QVJ%QrD5"a9H0Rm(($(f!V5-dbZ`PU"Vf@6c9liiLGEc$Uq$lb
+ljD&Y-5hmIP')mCQMbLVbU$P8MDKDLCT#'V`ZDaUA$TQh#IR#&iAmUG1Sm#fNeJe
+6KI!KJZ["iqe0RFhZ4Z,cRbli2TqSe@dChfPZrm0MIh2pe`mH25E(YabD))GjUFQ
+%f0BMGmJj859(Yh0SI,fF%9!bM%H'aJ0bKN[*d'L[KiK'lM$5I@@r3m9,MiBdH$h
+$A3H9&D`h,6AYAl[Q+@Qmc4@E&-EBK**cejQFF5A(PG6[F2CT4ac1-9,EM$`A,DQ
+90&BRDFa@dPNabr1qB+Gj9+[bZKll8KdY8(RG6hlj@,2AjA)0(acCf[iFfFdeB2i
+'kK*dHI4aj0rkC[ke628@`U+hmJe6$0S'eXpTZhkpSAQJqATN-VcbcHKFDCDFN8H
+ZAXl8)LY[XI2jfN-$%DdC,EQ3!0pr8lGKi+$A88mZKpFKj"qkUAZf4Bla,+qRJEb
+Hf`lDUVbHqLSKcb[Lq,EM0`2Pp-$"iC[U+`i0@bUmRUm-Hce(EK*e1lGfDcKR[b2
+dR3m6l`MK&GV'+[K%$HpbDKf)6arm9'd0QejAiI0mcq2cV+J+c6U,XXhRdH)Lc(@
+6f!fR`3GX0HMq+U2Ij$lc9IIGRZJF9P&`J-9pl&+JABA)cMSr@e@BReDKAM5l,Q-
+kj,RU['@-C@`9U`LCcV)dqcc-`9!0edeDGHMbfVmqA,!-I[++2jHHrGKMYHdbPe9
+YER5Gli82SXlUlB0M6H-[BfC+qa&l%E%[)(BrBRq(f#f)hBABhb0frjQHfFMUD&C
+-MpHFf%aKR(,!532R&("bL2FJ(P,L'F3$8#1&@Zr&&%`(2pq)cY4qYM0G"-3S9`0
+[&fH2p`UZ#0leA!'m&h"'H*YC8-ME9,YDjRR6KPfAf93&Mfe#q$al#UqAfG2&A$1
+IaGEB9+bei"(bT8%*liZP8jML1P`lTV,1rE6kchlPLG2biB@IhLGUZ+Km3-L2fEX
+3+)HGlHh"9L(JpV9fqS*GRA,)AmjZlK3#3@GcFp#e,Z!11J0"Yp"F6PlYG`F$lSk
+Z6Tr6YblBiHlSp+eMc'TPH4`i!RHF(NaPHeP1l%ZR-Z(-CYBRpU8bQbdAA35-TTC
+fTmHrNLhZC)ZEIbS#mK5Y!1FAFq[ldN&qlBVeK6HccA%adF0511U8f-a5Z$#)DA3
+Z(X%KT@`qNFZb6EeLNN95IHPi3ZcK"$E&FlfTI%l"fK,1a90*#dmXX@3pm@bi1b&
+Q@6D(E-iQbc!36[,VKBYB10R$iRhT$#JM$5F98aNFRBU)#SFQVlYTPApeKam+3'd
+SN!"+-M'6`4'U9$i,M5)*-C`"adaZ-qZ1jl*&4[QNf*r'481a*l'C%f%XR-#9+V%
+()K6hT"K'H3$JH$Q@cAG$(#J56VbU!B61jK3K@M"##lDlRDYB*)`kc,*F,mp2*%!
+LP@'j&!YRXrNq(+IU"D&`)S%,NH&)4-aQia#rU)&#Q@94-DLbh["'NA@,+#L)PBK
+(iMRSf5-#1a8*3lULP#AGaIk)L"T,*E0+GA@f1hfYrQ$!kh-lQre-6#T9PNpc3!B
+4Q6q9#'IL@9DAkmd%jd1D$'`V+b[+@&e6)Sj,PQ8jF$mV"IT&-hZ0("F#JLFKUZb
+"43CmAJm"`93XP3eUQY---V$(b"bf)'CN6mKDjKGeqjNRFG%hCH@k5DINfjUSX*4
+FC()dRXSS043YPa(bZrQ*VdJUPX6H3Sm&Q[T&%E,)#`FS)FM$b`$6rDci`Eb)NLl
+,i1rJ3[$jIkX("mAL[+,"&mEa@Q9c!YNq,JcZ[U3Chj!!b#iUDT(2jT%($i)MF1(
+M1Fk"Zc3+%A@9aRP3b)H5M23#1*GA+U')hTU-C-3q9#"-4k',E*C-X83U'4-cE&-
+UXb(,mA1pU1&)1&XbaCpd$``3I@)i#4fLq34F%VT`EbjbrARCS@)%lR9Fa*p$&2%
+9cq09F+lkdQ%XBm"9HDR#pmUeZck2KL)GaS0AN`Ml5%89)bjC,dJPhbMJ3&&U1C&
+EH$)EhbMb`Jk!"LF,IBXmJ*-XDBIf4cCH8%2pGQr1iFJE6X4a8djJ6i8AQ@`#Z3b
+@TA++"r#Uq'NPP4X@,Th#fF,25Cdl$%Y$prA1jPIYjUK18VAAkHIl)AIcD6IH$ka
+#[i$h3f[DXH0%G!$KYAJrl@rhmqfZCrKm#4h`F6i""c-YRhAMAFeRh(KIjPrA`H-
+,QS3@$e@UPK8hG&3IERCaI08YcDie22p12QI'qljQefS2h[ZZl'cRH8-Y@'(#qr(
+baGQKAGrQNa&FF&U-f)2&@-8Th"A#pJ+29Gi$4HAY*!bM+j'(#h8mTPf('+j2mGM
+P5a!l4QSjp[r!ic#T*'NQAIi*a)B9(SmLGU)BXr`!H,Ki*-GqL"LZ[mNa#E(l2hJ
+p[p+NM3'[DrfImBY2fMl%$&GrMZB5@DFM0Q+I4[14GcYL*Y`Vi[bq!1baJ)RH$bh
+PE3GNr3lbpL*[J!CN$"pL$bZa!@!ELjTC+j!!je"L9BJ0+aKA)hDA%VXEX8"PhiC
+`Eq,FNF1c"a&,Ya1RcKkUl01l8T[%6&F6crmr!!!0!!KRBh4PFh3ZZEN!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!EN3!!!!!!!!!!!!!!!!!!!!!368!!'b$!!!!&J!!!!"
+38Np+5d&)6!%!UE8-1+TCH,8!!&N4!!!!!!!!&0%!!!!!XeN!!!!!!!!!!'l[$J$
+VC@BbZfLM9LjK@`(BbYeddr*D1ljZeLeXBCYZGMTKkh@YiHQe2TZd'&mccblCVIP
+m(E#cfhE-@MMCHK(HXFZ&NadVX[0@e[I5pM2#Y[Q%EEV`f'DrrEcL#erB`ViMr$Z
+bl9cB`Xp&XLiH@rM#GS4&0eZS31'rUe&H0ZMmMLe(0YZANB8XC*0EMKaGb%)@mR3
+jr(QHJ`EiBdc&'&Yd"f-,FDSrXTJalAFCkp8i&PpQ55CMSQ1&'-r`D$`MTX+"S+L
+,"$0L1Q2k@P$0e-cEjPhNEI*0)3l5ScUAFq*4,IK@l`09Xq6JdY%IBq`,qcr`a8N
+q9j-`RlHP%XY-[#@5-R'LAZN0TU,*6$3H'B`S0-B@m1KDZeGP%Yh41#Y&H[jk+Q1
+02GmC`2NMb'N!9MPHK+$TY'-I'@ZE2PhL+3Bc[#84%KNV1rbD8-1D2fJ+90FaYKe
+YJGfcb)--0CUJA@bER+jUCerHRQ5X8-mHC'cZ%3AebrIh+"&q)Kr)eA+mp046[$#
+Jm'+&BiaTML+fV44K2Dc`A!R[&"r'+,1"ECYEreXq*jr6qP5fL*R13#J44krc1Kq
+Yh00Gj(2fUEHdYERRiU'JKLjkR0A+#Ia#BF3L-CB)4T0L5*c09*IqS&"J+X-8kCE
+"6AkUf#M'2["*0S%ahf@)km"jXUTYJ,`PdF*cjk!STakG"SFTN!$ZUT!!HdQEfK3
+XKXT-`@59Ge9A!%eXN!#M!p3Ji94'Z5QHb)J9r&Yaq13aY5NaNTX5h*D)Va"6k(c
+9TP5P6-BMVLihTG+Ti#8H-Ch)TS)L8**4-380*V$aUQG9cjBeX2&USqUlZ"HISRa
+R(M)+Bl1N&hD8@QDqTAV0iEd)A"'0"f2CN!$)'eS#3CFB#)QTp26TF`JMUC+JVJL
+*i@KFj*P89Z6bFrA)BP)i%%XV@I@PT*5i@J%kMJ4LaE4"*%PZ2q3Q*($9%Q%U$Hh
+RG(a6hp+M,LZ@PI)GM+fp'A8TVd$I#Kdc-$lb*YHmLBqj3KQZG2iAIq!6"Te$q$4
+&S(-)R`a%ja!qbL'Vq"rm5L@b'64@i(k2(#plJE(,8%dri'EX2BLpK8qeLM3BiMm
+'9p*J#(q%8Lq(m+Y`*3j$q&3%LF-32TSELF-3rL@i%SFKI'V'L--3rQKFLF-3rPK
+FLF-3rRKFUBB-iD1YP$3B`Vm8eh&$q1Krk#%0KrJ6Gp*`#*mk4Y*`#*pk$lj&Gki
+hl6cCQmiEC,4QM8TZlXe5j5,rQSZ[X)LajMLVLZJj"VM[Df16fR88i9pNNi6VKDb
+L9('`dNEX'CrE`&5pKmYr*0qeDZ8q3EQEPAZRFPqRh,FUpfr,pdUlI%G$!K@8,[c
+eKbE)c0UYErl6*i8qeSQcHdC$Nf"I)[49#-lq`U-eYq(fF-h0b1`4qXSH&2Td@X4
+HaVN6CideiZSZ&&`*TR%YGR8cPA&fBD[39hkpm)#"m5i@%cEf(N(1Tb)kC,NS5mJ
+Z1+Ur2XQ%2XfM%@hcaSJkeb4Nq5apGhM8M)EV@J@(d+IGak[DY6@0I$VMi1qUk4'
+b-aVX&Tm&Z3pbYl'l8XFe1408@SEmqTUECc4iI4i[XMFM2URQ0U"j('l%eh%hed5
+UK$le0Jf0Z+V#4i6qLTR#SX*cPU19eFE@*-qCNUUpSkmE[@qATCq05CER6!Xh3&&
+eljq3!&1PF3KcpPImBmd1rBfm@prp&3b5')[SN!$cBXfpE%,G,(e2@,eNJj!!AE,
+"p9,Kk*`k0SXdEYF[h9#RkrdFRjaVV+q!Hjk1a*cp!aqV@FHV)`H0MFfhKdfjDEQ
+Q'3df5D[bldAFK&e8M$eA8Ua2Ha-8[*'[(R$PSQK6+m+DA#Jh$6N['K0XjKqZVfY
+LelUIRec`E@LHTESUSZiY#0RN*Ef2,pR!iFfU0Z'9m+Kk$JdmN81j+i(EBrUXN!#
+&Ia"MSmJh8R35R$LlSMU-QXDleCp29ZhGZ(f(HQ[B#0hcZIIb0U2,D'MA@`iaA8C
+eXf([RJ@2&ijXA,GhI9JYC)dXCb)FVXT00EDerVL`LlGDlf9MVSkLANl)MEGq`49
+P9Ebepf@c!3VmD1U5ThE20"J0m6N4SmF5'B1cCT%&5a$E%'%-LTKV#p"HI@brTa4
+liRKXhrkYK3(56Eh*2)e908HC2XapeQA9(QZi1aRXI4chSi3(K$[fpE*45Za,&+Z
+b&Sj&1VSkJD'K20Y2$1UG#m*29!AQ0S3I4CC@[iaG@KJ`6ePL-DiqYRIIlCZDMh2
+[h2GaQEd5ReQ-)eC,r)VaiPhKGeMLpd0`+bXF-drj%((,l,Yp(c!f09pM+3c-I%L
+i!DcJ%0Ah(6maX+HHQ@Q)Q1'5UC&4(NYiR-aAGDMGS%6kfNFTN6hYU-fU&m"i%pa
+)$*iQaIMUR`l`f6mGD,iA9D[@A-YU)mDTYFb`e'Vl1eDpra$62,A8I'aZJr@b-BI
+B"mh(HJm[X)6cm(LM9(mD`ip+(2V!S5p9b$#*am5GYHb$iA(AJShVQj'U!hpdhle
+-)fU-Y8ac(2N!F$r*fj,9QhTHA&qrqm9EQE@(eHm"RlB8-a[U$HV'0B@AeX-EI1E
+SpM('D8bcDCej0kPKhL-Tm9JKhhiYVmiYj)eR%+ZL`LY-(6(-"#Sm-0U9V'D%+Va
+LI"kiKrPXTZH0BA9!+e"6aqSEFPqrHjj49pp`lfHr-1qqG4%Yk[f-GSk&(BfU6U5
+SXAd-SQSPDQMAi(DjVEq`alK1b1Dq,Q52()A$9c1eEKFV%cl-8293iaYXVAE(A0D
+Eirife(fZ%l+eUrXh'GerI1"[eMklHrm"+Ejkcc(@D*aT-#"fdlilT*b`NU2Ee0H
+r6-V`+4R9qrVkI9+'9FR3D0I5M))U61'Z8Vf$i`XlfM@i28e9"mlbQ`dc$GZA,(k
+md0pXM3`)KrNa*@IcmCaq*FFDefqdG'Rh0PS1-h9p0H@L&DeMQMS,daMVQ+l1Mpl
+ZT3BfPG@SA0D([eR,VP5j()mpFX$ZXPUYZhE[[FRp2'X`6JEc9e'[4TI(2Shmfhk
+HIb0Ar3*KaLrbU`BC02FXQp5mGPQ9[FHq&TNFYk`GR5ZE)'9NNDZA-VA)bTS``bi
+8lZX*DSeSaBAXpPXkURTfZaV0c0VSDK5bpph5-G%Na5M,jCc$A-j2l+k[F$R0&8+
+@(2(#ZKI@!q9ScqjGYjM,pZ`bPEQF6qjb1IIG)ZSfhG5K)FlHa[D$(fA8%D*@D1G
+@S%j-TLkRTK(a%EfIUjR-4p5@HC`rGRUFXb[D*ja%@HGaDM&2AM1`F%-Gkremr@4
+dIqAKle+Gq8[(TjcK5E`Xe`J@Gr'a3,X1N8feAMir0bfTJPmd@blR1Z4CDedPM'[
+jI&l@EMM*dZKamNB10k`CU01Kbh-rZbYRkVel`9m8RV[ci4Uha'9qX`0Gja@SJr#
+CZD(hX+hrP@SiD6YL,b2f%',h)2EhL0f+f'E%rJ'aHilhc0@mPNh!6+5@6BU-%rT
+C"MK*i"`"6JEa%1,Y5Mb&Z!pU*1$e6XcAGDMR+p#C0TcX6'F!-8aUi'iPpVM2*N9
+`0j-#Z&p*M(!hFVq3!+eAECNheC@XfR*j[5VRV$mQI)drMYXVr0YbVV'6kA+6ke@
+m+HH8jM653heai8K%`aZY'`HcMMrbdTmb&e*bTNS6,CS,65fq0"H5jN!2B4qJ8Ci
+%PIrY9jj`(X@!qXcN5GQ+Q$0bC&dG,fiZH*[F$X&A@Q5`Z0hq*X(Rm$5eH[aYV9,
+)@mUfY`Sq[m9ZpeZAqKaqLmr[%1bPj)9HKprRD'PVp9Jm5rdYMTC@ce+*UQfHfq,
+dIT!!ApA+Vl+I*iJm43I!HFA-XUkNRjCXH&GJ&9m9&@-KRX"Z5@`96f#aX5ZDcN5
+$f-j)Cf1C0&rC+FCj-0'9M-E%%"&B'Fed*V)C"@Ye)"00a%f8@'6*3p&dS#-QTRN
+kJfaLNqE*&0BfX63jJ`IL)4lY5UC!'@RBj%bNX2X5&"810TI$0YqlX-8,"C+*&"4
+)a,QB5Q%A*T&03k0J6!bN`$'9@F8lSTQdc#JE&lZ6@+383l&94)6c3!c,-Q)))Q3
+l1K+T1%pdd+BPi@9i1YX"FD"))(C#!`L0I9*CL(QBV2RG$XYm(JaNdp!UddRjX4K
+)*&)mNq#"G$VEKBfA6K!+a'*B6!d%Jf)k(BAiXJB+CCk'Bq#bcX!+NAH)-"6%LN@
+$d3cd$)R!6J3$N!"1PV+SZpJG&1'a4$bYZ+[9EI%dHIdqPmGKXAZj'&GFPNd5))H
+)h*Z)"9,40+r0G+Emdb"0#P8T,5R+HDdY&X8#E8N1,18N3&mZ9+I*N4!32!j4T4)
+R-iJ%6Cd3%%c&SQhJDD,Tjf$[Y1'+2+NQT%h6C0eHVdNNqXUdj*YN3PVTKF-5NXQ
+ND$548M`8,YN)q4fd0a4-41,4e@,)"%fpSJKCr+J[+f!Kb%-f#)+qH%0@K+9,-RK
+E5!KEUc#[bBNYT5Jj'Ra41%ilQ`LNZdJB$*162!fQk4Qb&YPd&RQS3DJ)*(`d3aa
+3(6L-#&mPXC8-q@$*B#H!-eR&#6*k8cbB%V[J3"3GK5kbH6c"BiPi4%caPBR8mM6
+KCcVKi@!JA5b+Vh8'(""GBL!1(F,C'+SNG+(D,(0p`hC`M%#eMN4m!d,'9fSHZH#
+8qj+"8)LU+PN9GDrNh@9C0"6*!#lN*K(P)a&@#R'ap)*8r&8$qf5TT83UiI&dG)9
+)a[D""T'&[M)2i-5,fR94"B)!S!ErGUc+B(--HfG8P'245*a-*K@"6#S!IC3D3+i
+ilk45`d,5+Ca0Y"q$2M&[Z)hP*p(j*C`(@Ilb3bc2F4SIC[NVCV$mHl8Xrcicbdq
+VB[RTXeRqUJD@V`Zcr0A,@2lpGl$m0CYCr[G5,2rlRf(jf4pPqBBHR$YBIJjb,F#
+caA"qJZAEELZeTe0f)RD!eJaqpNcCfBRE5#`ci(hL'GCh$Q-8PQcSIIfj"#Xdp)i
+p[h43M38C['X+UZjcfD24*Y2lqM-'R1Mp`IRXX9JISIHe4b@YeBh(1d&DdMZc$$)
+1#"2BK%IUcqXp(TLAiY@cXmYlmXUI39kL!,(LcUZde((A3GDhC4DVR+JX!TjrX("
+dS*l'@*L@NLk)lep(icACMpqiIhLbmCS4eRjl[(EfJ`hd13KkYXli+PC*8@q`lM4
+TKdA`0L'UTI[dkBaKdr40h)@Z2d0i%LSG[P#"&Xf'U"jG6l#c)lEF&+3UZAA-GqU
+,Ti4&(-YD,$BAN[@$`bM#SQpF&%p`N[ABjIACSBHU)Td*44-QY",UNcKU0P("DEU
+1kTZ1ZQ"r"N"TX&rBmPI&%r9kSU`8QRrU@#U9CPcL"#hh&%pD+bNLQD!6dp!dJ89
+Cf8RQj5AQ2VXG#ZQJ%'B84)GT6L*TLdL,E5i,-9mCl!bN**')HG0!mF5kQ+)4GIq
+N*PV$F$3LF5+0[PNmX93kU#CT4'TfKP,TX`kT,$V*ep3#KkLdQ)CKr-"-Th(dJhT
+kb((3%k-`LI[E0D$jie,Y+0D!9N3VT$N4&B"rprp*YkVqeDfdT2M2ELAhAh5VjUf
++FJDT9!%Zq*SU`%9IPbV!"9rVIZhVbTrjqR60eEpCFprT!Eiaf!0Bh4DT"qL)"B,
+,BaK3rUi(')kT"VcMlGf$hUCa0k)MX,JDA)jaF[Srk[Xl2(FKV'KZYcVpT(QS)q,
+[LJf2e8AmTM[!RJ,TUmFB(l22eH*rGJI((8[cYE11$E`e(cMMf24EhMil56L&92,
+f1FHHUMrNlB[e4rY'r4NQBciJ1I14iSN24JabEe'iG`95bhrC5AjpX!Y`BEH$N!#
+9,IRK[lS!V+89Z`$CVdcIK8mJq%0LFRLX'F&[jN5RFDJ2N!"a(,jQLC'ddRHK@Kb
+I"Y!U&2Q!PQQNN@*`q,#CmYCIGS,+6,R&iTQ2U&CU))F9mrq`!M1$8QFT93TdPUR
+PIZbP$TqfJ5*Y)4@lK5B[6DQef!fRET%F1-b$rpqF-$S&59pXJ!CLjbS&c4BZ9SV
+bAe@+N[m[9!Vbrm9+8I,rK8T"Ni@,PD)d@IK&T4LF,2ch0&T`,+Bp!heFA1NIAQe
+IcE9cF,V8DQf@GNf`pBeQ8aT&$ZXeCACM@lANE+qIpJGdLI3`DM2Q-chefl9LSZ(
+P%a0'Ql5eLJV3k[eG$c#-`XcJM'25&fBLLRXp$K[0d#[a0BYB)0Se,)6#``IeZG,
+hjmjA!19r%@5'1aB+68X3e@EMdHi,1rh(Gckp[S9@42A&,a1KG*MqVAB3eM"6(E*
+RiQ$Aih0iI936T"q6#,,irrB%Jcj%Tb(j-"EYN!"Ur@qlJP0)*@qrYQ0jfYY[GBV
+r-LNpikbh*kA%ji5VP5S*9j16p("eCK@qePr%1Plj6R3&leDqbPrYJ9*2F,(fR0L
+VH,If92fkpSamGkIMZ%UMIUE51ah)RX%1a,HdMHBiHKJVT+b$$i29JCcHl#R9UV1
+E2DFVkSLI9e36eBM68arj0dadQLjm1J[Ic2UrBXAmIcL5rAqQDE1hfX+T4&Fm'iY
+4YD,21B[aE"Hj0aS2GDIaCA$k-M(&LGN[mj@I%VSIhdRGU%`4k@ZVKKLq!Dl%'@C
+#p,Xmka4-YK)IiDCK*-9Em@F'T)H#3C1'9c''(p"-+G6ifZH"'iNrkmXGT!3*Sfr
+,pM2rT-AklZUF5$rB-dPYCQ0G&LmjqLlk%3lFYmh(0m0ale[XEU9pq8F4TJjKRpF
+YEB9m$`3GU+mrT*rM!,1*m+mApaVkr3hFcGkP,45IBa2Q19QjUPQZUkT0GL[KUcj
+MYbkQr+hd#aT-TAV3EPhSa2h*4DeZbR[4EVAl%(pjhZ)QG1eUI8RI[Le`*IhGd(X
+f)LCe*[MGQL03'lpJ3l(bc9!@EU9BaIYBhpfeFNclBH$KG`!S0[*1a*jKDJR[(X4
+Q3N[SU!dLPQ1U3Q%F'rP2L(eI`9i1I[MUM"4,)+mB5b2[-5@f%RN2hl#@ING(Zak
+aajEp1AdE@,X"'"Xrp!#EJMp&Z4YjlSC+0JejAdAHTeQ9T-'AN!$AjM1`Dk!06DQ
+)dIZ4j`('rDa(`PJ(M,eb60Z%f!&C[dXA!`1pMK6l!mReFTjIFVfF4lT@+ccD%6[
+)4NNqS,N'IS"&`T!!I`0-aVJC2(D8Gbd2G-C1rE24bIml+[i+dZ"I(+ND4V3P9SU
+T0K[P9lUM(5Pma9e-rcm0$4*548&%688Z6@&M8(*[DQ9MG(-!!!!!!!!!!!!!!!!
+!QYm!!!!!!!!!!!!!!!!!!!!!9d)!!'qY!!!!&J!d!%"849K85d&)6!%!UPPjNDT
+CI(`!!!&q!!!$)!!!!0%!!!(TMdebX!!!!!!!!%&H%3!)(!`k"&&am(J6T3$f%Si
+%8qYVl30C4T19`S@l*L8NqT0mIT)5%(`!6C'C!3pi)"J)GJqf$j@GSl"H5k#P$Kj
+lT-[9*f`kG#q!'1b)Zf"U,Ge[4L(66c(D@U0914SjN4Q0CFK3r$+MPHQ-[!IQj18
+&M$C(Dj@MMECBjjh[0pUjd"D$jqcX(Y!&3e+-dCDL2Xi)r9T6`H[RM+6`plC+2!&
+LS5%8pI6h$*r&lpKdq2$X(4'MGf6GdReMB51ISe"p9`f"B&G(%f1Qk+RBZqmBX!"
+46U21B$8Q@pdH"i*pI"iF&XTA28cSBR`J`ardJ58J2Hc(b8cIIX!$3pMY$i8"QjX
+8*!i`"1QF2qJ&Q-$2h5MGRHN6HQ!`5"!4!Pc)kd-J,6[,(F)q$p$AVkp`Y6(EfJ%
+pL$41lTF-c28L2Z!2HB+FejFVi4&i&2@(-R-0GiA#F5$6JheKR(`GN!$,Fh94(&%
+c6bY%i)LJGXk41bXCC,N$2K$QN!#2N!$m-%!FUDlRbi$)*m3SQpI$kNCK2MiAd3'
+[Dd2NcC8PTm`epJ*aZMrN4YN!)aq45a$4i",!ZMd"8VX1`MjI9XiNKZj`',L$`9`
+q)pD3!19,cQe5$rV6Fq@Xa*BZ)!FmlP"1(aBK!f(%[#L4-4`$'!h&ZqA*3!qc@$)
+14aMeB`DN@A8@5bqph@BbY`CHAiBrj22+3*6aHaK!USpBl-rbpbIc)KZH4AV"6IC
+pETDBG2Pai"qkpGcT39*YhbH-fk2jE9)LY6+!C&a4"[D&PY4B5Ej1&MY9Fb[&6`K
+9L+Y,Uq8jdQ+cBR2dPE!6pISK$)8ibJmQ*LJej22aRi%*i`Z"%-6%R+#,IM9!)ME
+IKeJfEQCG'5$&3'D3!"3B#,eZl-la2rH&I-L0I9i*+DcY*PZe!d#I$&Vjh-JVE-Z
+4UUX0C5"9SfNJh!m!!#%K#deKBe"bEfTPBh4c!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!(S!cJ%f!Q)!!!!"!!"XJ`!!!!!!!!!@!!!!KJ!!!5$rrrrr!3#U992GUPP
+m"3!!!!!!!B-k!!!!!!!!EbF!!!!!!!!!!!!!3i@&kJ!!:
+
+
+
+
+™
diff --git a/Makefile b/Makefile
index feb83e60..3c877275 100644
--- a/Makefile
+++ b/Makefile
@@ -45,7 +45,7 @@ OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers
CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c
-CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c cord/cord.h cord/ec.h cord/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC
+CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c cord/cord.h cord/ec.h cord/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC cord/SCOPTIONS.amiga cord/SMakefile.amiga
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
@@ -53,9 +53,10 @@ SRCS= $(CSRCS) mips_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s sparc_mach_dep
OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE \
README test.c setjmp_t.c SMakefile.amiga SCoptions.amiga \
- README.amiga README.win32 cord/README include/gc.h \
+ README.amiga README.win32 cord/README cord/gc.h include/gc.h \
include/gc_typed.h README.QUICK callprocs pc_excludes \
- barrett_diagram README.OS2
+ barrett_diagram README.OS2 README.Mac MacProjects.sit.hqx \
+ MacOS.c EMX_MAKEFILE makefile.depend
CORD_INCLUDE_FILES= $(srcdir)/gc.h $(srcdir)/cord/cord.h $(srcdir)/cord/ec.h \
$(srcdir)/cord/cord_pos.h
@@ -141,7 +142,7 @@ cord/cordprnt.o: $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
cord/cordtest: $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
rm -f cord/cordtest
./if_mach SPARC SUNOS5 $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -lthread
- ./if_not_there cord/cord_test $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
+ ./if_not_there cord/cordtest $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
cord/de: $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a
rm -f cord/de
diff --git a/PCR-Makefile b/PCR-Makefile
index 637ceb7e..fb8a1f54 100644
--- a/PCR-Makefile
+++ b/PCR-Makefile
@@ -1,46 +1,68 @@
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o pcr_interface.o blacklst.o finalize.o new_hblk.o real_malloc.o dynamic_load.o dbg_mlc.o malloc.o stubborn.o
+#
+# Default target
+#
-CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dynamic_load.c debug_mlc.c malloc.c stubborn.c
+default: gc.o
-SHELL= /bin/sh
+include ../config/common.mk
-# Fix to point to local pcr installation directory.
-PCRDIR= /project/ppcr/dev
-CC= gcc
-CFLAGS= -g -DPCR -I$(PCRDIR) -I$(PCRDIR)/ansi -I$(PCRDIR)/posix
+#
+# compilation flags, etc.
+#
-# We assume that mach_dep.o has already been built by top level makefile. It doesn't
-# care about pcr vs UNIX, and we don't want to repeat that cruft.
-default: gc.o
+CPPFLAGS = $(INCLUDE) $(CONFIG_CPPFLAGS) \
+ -DPCR_NO_RENAME -DPCR_NO_HOSTDEP_ERR
+#CFLAGS = -DPCR -DSILENT $(CONFIG_CFLAGS)
+CFLAGS = -DPCR $(CONFIG_CFLAGS)
+SPECIALCFLAGS = # For code involving asm's
+
+ASPPFLAGS = $(INCLUDE) $(CONFIG_ASPPFLAGS) \
+ -DPCR_NO_RENAME -DPCR_NO_HOSTDEP_ERR -DASM
-all: gc.o test.o gcpcr
+ASFLAGS = $(CONFIG_ASFLAGS)
-gcpcr: gc.o test.o $(PCRDIR)/base/pcr.o $(PCRDIR)/base/PCR_BaseMain.o
- $(CC) -o gcpcr $(PCRDIR)/base/pcr.o $(PCRDIR)/base/PCR_BaseMain.o gc.o test.o -ldl
+LDRFLAGS = $(CONFIG_LDRFLAGS)
-gc.o: $(OBJS)
- -ld -r -o gc.o $(OBJS)
+LDFLAGS = $(CONFIG_LDFLAGS)
#
-# Dependency construction
#
-# NOTE: the makefile must include "# DO NOT DELETE THIS LINE" after the
-# last target. "make depend" will replace everything following that line
-# by a newly-constructed list of dependencies.
#
-depend: $(CSRCS)
- rm -f makedep eddep ; \
- $(CC) -M $(CFLAGS) $(CSRCS) \
- | sed -e '/:$$/d' > makedep ; \
- echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep ; \
- echo '$$r makedep' >>eddep ; \
- echo 'w' >>eddep ; \
- cp PCR-Makefile PCR-Makefile.bak ; \
- ex - PCR-Makefile < eddep ; \
- rm -f eddep makedep
- touch depend
-
-# DO NOT DELETE THIS LINE
+#
+# BEGIN PACKAGE-SPECIFIC PART
+#
+#
+#
+#
+
+# Fix to point to local pcr installation directory.
+PCRDIR= ..
+
+COBJ= alloc.o reclaim.o allchblk.o misc.o os_dep.o mark_rts.o headers.o mark.o obj_map.o pcr_interface.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o
+
+CSRC= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c
+
+SHELL= /bin/sh
+
+default: gc.o
+
+gc.o: $(COBJ) mach_dep.o
+ $(LDR) $(CONFIG_LDRFLAGS) -o gc.o $(COBJ) mach_dep.o
+
+
+mach_dep.o: mach_dep.c mips_mach_dep.s rs6000_mach_dep.s if_mach if_not_there
+ rm -f mach_dep.o
+ ./if_mach MIPS "" as -o mach_dep.o mips_mach_dep.s
+ ./if_mach RS6000 "" as -o mach_dep.o rs6000_mach_dep.s
+ ./if_mach ALPHA "" as -o mach_dep.o alpha_mach_dep.s
+ ./if_mach SPARC SUNOS5 as -o mach_dep.o sparc_mach_dep.s
+ ./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) mach_dep.c
+
+if_mach: if_mach.c config.h
+ $(CC) $(CFLAGS) -o if_mach if_mach.c
+
+if_not_there: if_not_there.c
+ $(CC) $(CFLAGS) -o if_not_there if_not_there.c
diff --git a/README b/README
index 8cb1c44f..aa4e2b08 100644
--- a/README
+++ b/README
@@ -10,7 +10,7 @@ Permission to modify the code and to distribute modified code is granted,
provided the above notices are retained, and a notice that the code was
modified is included with the above copyright notice.
-This is version 4.1 of a conservative garbage collector for C and C++.
+This is version 4.2 of a conservative garbage collector for C and C++.
HISTORY -
@@ -28,8 +28,10 @@ Robert Brazile (brazile@diamond.bbn.com) originally supplied the ULTRIX code.
Al Dosser (dosser@src.dec.com) and Regis Cridlig (Regis.Cridlig@cl.cam.ac.uk)
subsequently provided updates and information on variation between ULTRIX
systems. Parag Patel (parag@netcom.com) supplied the A/UX code.
-Jesper Peterson(jep@mtiame.mtia.oz.au) supplied the Amiga port.
-Thomas Funke (thf@zelator.in-berlin.de(?)) supplied the NeXT port.
+Jesper Peterson(jep@mtiame.mtia.oz.au) and
+Michel Schinz supplied the Amiga port.
+Thomas Funke (thf@zelator.in-berlin.de(?)) and
+Brian D.Carlstrom (bdc@clark.lcs.mit.edu) supplied the NeXT ports.
Bill Janssen (janssen@parc.xerox.com) supplied the SunOS dynamic loader
specific code. Manuel Serrano (serrano@cornas.inria.fr) supplied linux and
Sony News specific code. Al Dosser provided Alpha/OSF/1 code. He and
@@ -40,6 +42,7 @@ Brent Benson (brent@jade.ssd.csd.harris.com) ported the collector to
a Motorola 88K processor running CX/UX (Harris NightHawk).
Ari Huttunen (Ari.Huttunen@hut.fi) generalized the OS/2 port to
nonIBM development environments (a nontrivial task).
+Patrick Beard (beard@cs.ucdavis.edu) provided the initial MacOS port.
David Chase, then at Olivetti Research, suggested several improvements.
Scott Schwartz (schwartz@groucho.cse.psu.edu) supplied some of the
code to save and print call stacks for leak detection on a SPARC.
@@ -64,6 +67,13 @@ Boehm, H., "Space Efficient Conservative Garbage Collection", Proceedings
of the ACM SIGPLAN '91 Conference on Programming Language Design and
Implementation, SIGPLAN Notices 28, 6 (June 1993), pp. 197-206.
+ Possible interactions between the collector and optimizing compilers are
+discussed in
+
+Boehm, H., and D. Chase, "A Proposal for GC-safe C Compilation",
+The Journal of C Language Translation 4, 2 (December 1992).
+(Also available from parcftp.xerox.com:pub/gc, among other places.)
+
Unlike the collector described in the second reference, this collector
operates either with the mutator stopped during the entire collection
(default) or incrementally during allocations. (The latter is supported
@@ -189,9 +199,11 @@ trademarks of their respective holders):
Sun 3
Sun 4 under SunOS 4.X or Solaris2.X (with or without threads)
Vax under 4.3BSD, Ultrix
- Intel 386 or 486 under many operating systems, but not MSDOS.
+ Intel 386 or 486 under most operating systems, but not MSDOS.
(Win32S is somewhat supported, so it is possible to
- build applications for Windows 3.1)
+ build applications for Windows 3.1. There exists a port
+ to DOS + 32 bit extender for at least one 32 bit extender.
+ However, I don't have source for this.)
Sequent Symmetry (single threaded)
Encore Multimax (single threaded)
MIPS M/120 (and presumably M/2000) (RISC/os 4.0 with BSD libraries)
@@ -201,13 +213,14 @@ trademarks of their respective holders):
HP9000/700
DECstations under Ultrix
DEC Alpha running OSF/1
- SGI workstations under IRIX
+ SGI workstations under IRIX 4 & 5
Sony News
- Apple MacIntosh under A/UX
+ Apple MacIntosh under A/UX or MacOS
Commodore Amiga (see README.amiga)
NeXT machines
- In a few cases (Amiga, OS/2, Win32) a separate makefile is supplied.
+ In a few cases (Amiga, OS/2, Win32, MacOS) a separate makefile
+or equivalent is supplied.
Dynamic libraries are completely supported only under SunOS
(and even that support is not functional on the last Sun 3 release),
@@ -228,16 +241,14 @@ enforced by the standard C compilers. If you use a nonstandard compiler
you may have to adjust the alignment parameters defined in gc_private.h.
A port to a machine that is not byte addressed, or does not use 32 bit
-addresses will require a major effort. (Parts of the code try to anticipate
-64 bit addresses. Others will need to be rewritten, since different data
-structures are needed.) A port to MSDOS is hopeless, unless you are willing
-to assume an 80386 or better, and that only flat 32 bit pointers will ever be
-used.
+or 64 bit addresses will require a major effort. A port to MSDOS is hard,
+unless you are willing to assume an 80386 or better, and that only flat
+32 bit pointers will ever need to be seen by the collector.
For machines not already mentioned, or for nonstandard compilers, the
following are likely to require change:
-1. The parameters at the top of gc_private.h.
+1. The parameters in config.h.
The parameters that will usually require adjustment are
STACKBOTTOM, ALIGNMENT and DATASTART. Setjmp_test
prints its guesses of the first two.
@@ -271,27 +282,39 @@ following are likely to require change:
If your compiler does not allow in-line assembly code, or if you prefer
not to use such a facility, mach_dep.c may be replaced by a .s file
(as we did for the MIPS machine and the PC/RT).
-
-3. mark_roots.c.
- These are the top level mark routines that determine which sections
- of memory the collector should mark from. This is normally not
- architecture specific (aside from the macros defined in gc_private.h and
- referenced here), but it can be programming language and compiler
- specific. The supplied routine should work for most C compilers
- running under UNIX. Calls to GC_add_roots may sometimes be used
- for similar effect.
-
-4. The sigsetmask call does not appear to exist under early system V UNIX.
- It is used by the collector to block and unblock signals at times at
- which an asynchronous allocation inside a signal handler could not
- be tolerated. Under system V, it is possible to remove these calls,
- provided no storage allocation is done by signal handlers. The
- alternative is to issue a sequence of system V system calls, one per
- signal that is actually used. This may be a bit slow.
-
- For a different versions of Berkeley UN*X or different machines using the
+ At this point enough architectures are supported by mach_dep.c
+ that you will rarely need to do more than adjust for assembler
+ syntax.
+
+3. os_dep.c (and gc_priv.h).
+ Several kinds of operating system dependent routines reside here.
+ Many are optional. Several are invoked only through corresponding
+ macros in gc_priv.h, which may also be redefined as appropriate.
+ The routine GC_register_data_segments is crucial. It registers static
+ data areas that must be traversed by the collector. (User calls to
+ GC_add_roots may sometimes be used for similar effect.)
+ Routines to obtain memory from the OS also reside here.
+ Alternatively this can be done entirely by the macro GET_MEM
+ defined in gc_priv.h. Routines to disable and reenable signals
+ also reside here if they are need by the macros DISABLE_SIGNALS
+ and ENABLE_SIGNALS defined in gc_priv.h.
+ In a multithreaded environment, the macros LOCK and UNLOCK
+ in gc_priv.h will need to be suitably redefined.
+ The incremental collector requires page dirty information, which
+ is acquired through routines defined in os_dep.c. Unless directed
+ otherwise by config.h, these are implemented as stubs that simply
+ treat all pages as dirty. (This of course makes the incremental
+ collector much less useful.)
+
+4. dyn_load.c
+ This provides a routine that allows the collector to scan data
+ segments associated with dynamic libraries. Often it is not
+ necessary to provide this routine unless user-written dynamic
+ libraries are used.
+
+ For a different version of UN*X or different machines using the
Motorola 68000, Vax, SPARC, 80386, NS 32000, PC/RT, or MIPS architecture,
-it should frequently suffice to change definitions in gc_private.h.
+it should frequently suffice to change definitions in config.h.
THE C INTERFACE TO THE ALLOCATOR
@@ -333,7 +356,7 @@ good way for the collector to compute this value.) Client code may include
the old object. The new object is taken to be atomic iff the old one
was. If the new object is composite and larger than the original object,
then the newly added bytes are cleared (we hope). This is very likely
- to allocate a new object, unless MERGE_SIZES is defined in gc_private.h.
+ to allocate a new object, unless MERGE_SIZES is defined in gc_priv.h.
Even then, it is likely to recycle the old object only if the object
is grown in small additive increments (which, we claim, is generally bad
coding practice.)
@@ -341,9 +364,10 @@ good way for the collector to compute this value.) Client code may include
4) GC_free(object)
- explicitly deallocate an object returned by GC_malloc or
GC_malloc_atomic. Not necessary, but can be used to minimize
- collections if performance is critical.
+ collections if performance is critical. Probably a performance
+ loss for very small objects (<= 8 bytes).
-5) GC_expand_hp(number_of_4K_blocks)
+5) GC_expand_hp(bytes)
- Explicitly increase the heap size. (This is normally done automatically
if a garbage collection failed to GC_reclaim enough memory. Explicit
calls to GC_expand_hp may prevent unnecessarily frequent collections at
@@ -364,8 +388,16 @@ good way for the collector to compute this value.) Client code may include
This is intended as a way to register data areas for dynamic libraries,
or to replace the entire data ans bss segments by smaller areas that are
known to contain all the roots.
-
-8) Several routines to allow for registration of finalization code.
+
+8) GC_enable_incremental()
+ - Enables generational and incremental collection. Useful for large
+ heaps on machines that provide access to page dirty information.
+ Some dirty bit implementations may interfere with debugging
+ (by catching address faults) and place restrictions on heap arguments
+ to system calls (since write faults inside a system call may not be
+ handled well).
+
+9) Several routines to allow for registration of finalization code.
User supplied finalization code may be invoked when an object becomes
unreachable. To call (*f)(obj, x) when obj becomes inaccessible, use
GC_register_finalizer(obj, f, x, 0, 0);
@@ -398,9 +430,30 @@ and friends.
To avoid name conflicts, client code should avoid this prefix, except when
accessing garbage collector routines or variables.
- Thre are provisions for allocation with explicit type information.
+ There are provisions for allocation with explicit type information.
This is rarely necessary. Details can be found in gc_typed.h.
+THE C++ INTERFACE TO THE ALLOCATOR:
+
+ The Ellis-Hull C++ interface to the collector is included in
+the collector distribution. If you intend to use this, type
+"make c++" after the initial build of the collector is complete.
+See gc_c++.h for the difinition of the interface. This interface
+tries to approximate the Ellis-Detlefs C++ garbage collection
+proposal without compiler changes.
+
+Cautions:
+1. Arrays allocated without new placement syntax are
+allocated as uncollectable objects. They are traced by the
+collector, but will not be reclaimed.
+
+2. Failure to use "make c++" in combination with (1) will
+result in arrays allocated using the default new operator.
+This is likely to result in disaster without linker warnings.
+
+3. If your compiler supports an overloaded new[] operator,
+then gc_c++.cc and gc_c++.h should be suitably modified.
+
USE AS LEAK DETECTOR:
@@ -553,7 +606,7 @@ may vary.) The incremental/generational collection facility helps,
but is portable only if "stubborn" allocation is used.
Please address bug reports to boehm@parc.xerox.com. If you are
contemplating a major addition, you might also send mail to ask whether
-it's already been done.
+it's already been done (or whether we tried and discarded it).
RECENT VERSIONS:
@@ -733,7 +786,7 @@ Version 3.7:
Version 4.0:
- Added support for Solaris threads (which was possible
- only be reimplementing some fraction of Solaris threads,
+ only by reimplementing some fraction of Solaris threads,
since Sun doesn't currently make the thread debugging
interface available).
- Added non-threads win32 and win32S support.
@@ -749,7 +802,7 @@ Version 4.0:
tables it maintains. (This probably does not matter for well-
-written code. It no doubt does for C++ code that overuses
destructors.)
-- Added typed allocation primitves. Rewrote the marker to
+- Added typed allocation primitives. Rewrote the marker to
accommodate them with more reasonable efficiency. This
change should also speed up marking for GC_malloc allocated
objects a little. See gc_typed.h for new primitives.
@@ -813,3 +866,31 @@ Since version 4.0:
in 4.0. Worked around what appears to be CSet/2 V1.0
optimizer bug.
- Fixed a Makefile bug for target "c++".
+
+Since version 4.1:
+- Multiple bug fixes/workarounds in the Solaris threads version.
+ (It occasionally failed to locate some register contents for
+ marking. It also turns out that thr_suspend and friends are
+ unreliable in Solaris 2.3. Dirty bit reads appear
+ to be unreliable under some weird
+ circumstances. My stack marking code
+ contained a serious performance bug. The new code is
+ extremely defensive, and has not failed in several cpu
+ hours of testing. But no guarantees ...)
+- Added MacOS support (thanks to Patrick Beard.)
+- Fixed several syntactic bugs in gc_c++.h and friends. (These
+ didn't bother g++, but did bother most other compilers.)
+ Fixed gc_c++.h finalization interface. (It didn't.)
+- 64 bit alignment for allocated objects was not guaranteed in a
+ few cases in which it should have been.
+- Added GC_malloc_atomic_ignore_off_page.
+- Added GC_collect_a_little.
+- Added some prototypes to gc.h.
+- Some other minor bug fixes (notably in Makefile).
+- Fixed OS/2 / EMX port (thanks to Ari Huttunen).
+- Fixed AmigaDOS port. (thanks to Michel Schinz).
+- Fixed the DATASTART definition under Solaris. There
+ was a 1 in 16K chance of the collector missing the first
+ 64K of static data (and thus crashing).
+- Fixed some blatant anachronisms in the README file.
+- Fixed PCR-Makefile for upcoming PPCR release. \ No newline at end of file
diff --git a/README.Mac b/README.Mac
new file mode 100644
index 00000000..612d2348
--- /dev/null
+++ b/README.Mac
@@ -0,0 +1,54 @@
+README.Mac
+----------
+
+This is a preliminary version of my port of the collector to the Macintosh.
+It passes all tests in the file test.c, but there might be more bugs lurking.
+
+Mac Specific Files
+------------------
+
+Since I built the collector under Symantec C++ 7, and it doesn't use Makefile's
+in the standard sense, I'm including the file mac_proj.sit.hqx, which contains
+a binhexed (similar to uuencoding) copy of the compressed project files you'll
+need to build this on the Macintosh. This contains projects for building
+the test program, gctest.pi, a project containing just the library sources,
+gc.lib.pi, for testing the cord library, cord.pi, and finally a hacked up
+version of the cord text editor, de, that runs under the console emulation
+library, ANSI++, under Symantec. It has a pretty weak emulation of curses
+and only really works if you hack console.c a little bit in ANSI++. However
+it works well enough to page through a file and move around editing, etc.
+
+Changes
+-------
+
+The biggest changes made to the source was providing a target for MACINTOSH.
+Some care had to be taken to fit it in with the rest of the #ifdefs, as usual.
+The most most major change was converting the GC_arrays structure from static
+data to dynamically allocated, because no file can contain more than 32k of
+global data under Symantec C/C++. However; on the non-Macintosh platforms
+I still leave it as global data, I just take a pointer to it rather than
+dynamically allocating it.
+
+One thing this affects is that it is really a good idea to call GC_init
+before using the collector. I don't trust the collector to be able to
+do this automatically with these new changes.
+
+Also, since GC_arrays is no longer at a constant location, the static
+initialization of the array GC_obj_kinds won't work. So, I added a new
+function to mark.c, called C_init_mark() which does the rest of the
+initializations of GC_obj_kinds.
+
+Happy garbage collecting!
+
+Patrick Beard, June 6, 1994.
+
+I undid some of Patrick's changes, to keep things as consistent as
+possible across platforms. GC_arrays is statically allocated. A few
+of its former components are now dynamically allocated separately.
+It should not be necessary to call GC_init explicitly.
+
+I replaced the macro MACINTOSH with MACOS, both for consistency with
+other platforms, and to better distinguish it from AUX (which is
+admittedly less interesting, but was already supported).
+
+Hans-J. Boehm, June 9, 1994
diff --git a/README.QUICK b/README.QUICK
index 98947660..3273c8ba 100644
--- a/README.QUICK
+++ b/README.QUICK
@@ -37,3 +37,5 @@ and calls to realloc by calls to GC_REALLOC. If the object is known
to never contain pointers, use GC_MALLOC_ATOMIC instead of
GC_MALLOC.
+Define GC_DEBUG before including gc.h for additional checking.
+
diff --git a/README.amiga b/README.amiga
index cfb1fe81..e8345d44 100644
--- a/README.amiga
+++ b/README.amiga
@@ -1,4 +1,18 @@
+[Note: The original Amiga port was made by Jesper Peterson. I (Michel
+Schinz) modified it slightly to reflect the changes made in the new
+official distribution, and to take advantage of the new SAS/C 6.x
+features. I also created a makefile to compile the "cord" package (see
+the cord subdirectory).
+
+If you have any problem with this version, please contact me at
+schinz@alphanet.ch (but do *not* send long files, since we pay for
+every mail!).
+
+Following is Jesper's original README.amiga. Please read it
+carefully.]
+
+
ADDITIONAL NOTES FOR AMIGA PORT
These notes assume some familiarity with Amiga internals.
diff --git a/SCoptions.amiga b/SCoptions.amiga
index 9207e13e..26fef04b 100644
--- a/SCoptions.amiga
+++ b/SCoptions.amiga
@@ -2,14 +2,11 @@ CPU=68030
NOSTACKCHECK
ERRORREXX
OPTIMIZE
+VERBOSE
MAPHUNK
NOVERSION
NOICONS
OPTIMIZERTIME
DEFINE SILENT
-IGNORE=105
-IGNORE=304
-IGNORE=154
-IGNORE=85
-IGNORE=100
IGNORE=161
+IGNORE=100
diff --git a/SMakefile.amiga b/SMakefile.amiga
index 0727f423..97c9b8e6 100644
--- a/SMakefile.amiga
+++ b/SMakefile.amiga
@@ -1,45 +1,46 @@
-OBJS= alloc.o reclaim.o allochblk.o misc.o mach_dep.o os_dep.o mark_roots.o headers.o mark.o obj_map.o black_list.o finalize.o new_hblk.o real_malloc.o dynamic_load.o debug_malloc.o malloc.o stubborn.o checksums.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o
-INC= gc_private.h gc_headers.h gc.h config.h
+INC= gc_private.h gc_hdrs.h gc.h config.h
-all: gctest setjmp_test
+all: gctest setjmp_t
alloc.o : alloc.c $(INC)
reclaim.o : reclaim.c $(INC)
-allochblk.o : allochblk.c $(INC)
+allchblk.o : allchblk.c $(INC)
misc.o : misc.c $(INC)
os_dep.o : os_dep.c $(INC)
-mark_roots.o : mark_roots.c $(INC)
+mark_rts.o : mark_rts.c $(INC)
headers.o : headers.c $(INC)
mark.o : mark.c $(INC)
obj_map.o : obj_map.c $(INC)
-black_list.o : black_list.c $(INC)
+blacklst.o : blacklst.c $(INC)
finalize.o : finalize.c $(INC)
+ sc noopt finalize.c # There seems to be a bug in the optimizer (V6.51).
+ # gctest won't work if you remove this...
new_hblk.o : new_hblk.c $(INC)
real_malloc.o : real_malloc.c $(INC)
-dynamic_load.o : dynamic_load.c $(INC)
-debug_malloc.o : debug_malloc.c $(INC)
+dyn_load.o : dyn_load.c $(INC)
+dbg_mlc.o : dbg_mlc.c $(INC)
malloc.o : malloc.c $(INC)
stubborn.o : stubborn.c $(INC)
checksums.o : checksums.c $(INC)
-test.o : test.c $(INC)
-
+typd_mlc.o: typd_mlc.c $(INC)
mach_dep.o : mach_dep.c $(INC)
- sc noopt mach_dep.c # optimizer mangles reg save hack
+test.o : test.c $(INC)
gc.lib: $(OBJS)
- oml gc.lib r $(OBJS)
+ oml gc.lib r $(OBJS)
clean:
- delete gc.lib gctest setjmp_test \#?.o
+ delete gc.lib gctest setjmp_t \#?.o
gctest: gc.lib test.o
- slink LIB:c.o test.o to $@ lib gc.lib LIB:sc.lib LIB:scm.lib
+ slink LIB:c.o test.o to $@ lib gc.lib LIB:sc.lib LIB:scm.lib
-setjmp_test: setjmp_test.c gc.h
- sc setjmp_test.c
- slink LIB:c.o $@.o to $@ lib LIB:sc.lib
+setjmp_t: setjmp_t.c gc.h
+ sc setjmp_t.c
+ slink LIB:c.o $@.o to $@ lib LIB:sc.lib
-test: setjmp_test gctest
- setjmp_test
- gctest
+test: setjmp_t gctest
+ setjmp_t
+ gctest
diff --git a/alloc.c b/alloc.c
index 33629ab6..ee30d656 100644
--- a/alloc.c
+++ b/alloc.c
@@ -12,14 +12,17 @@
* modified is included with the above copyright notice.
*
*/
-/* Boehm, May 19, 1994 2:02 pm PDT */
+/* Boehm, July 25, 1994 1:22 pm PDT */
-# include <stdio.h>
-# include <signal.h>
-# include <sys/types.h>
# include "gc_priv.h"
+# include <stdio.h>
+# ifndef MACOS
+# include <signal.h>
+# include <sys/types.h>
+# endif
+
/*
* Separate free lists are maintained for different sized objects
* up to MAXOBJSZ.
@@ -124,7 +127,7 @@ word GC_adj_words_allocd()
/* This doesn't reflect useful work. But if there is lots of */
/* new fragmentation, the same is probably true of the heap, */
/* and the collection will be correspondingly cheaper. */
- if (result < (signed_word)(GC_words_allocd >> 2)) {
+ if (result < (signed_word)(GC_words_allocd >> 3)) {
/* Always count at least 1/8 of the allocations. We don't want */
/* to collect too infrequently, since that would inhibit */
/* coalescing of free storage blocks. */
@@ -176,7 +179,12 @@ void GC_maybe_gc()
/* We try to mark with the world stopped. */
/* If we run out of time, this turns into */
/* incremental marking. */
- if (GC_stopped_mark(FALSE)) GC_finish_collection();
+ if (GC_stopped_mark(FALSE)) {
+# ifdef SAVE_CALL_CHAIN
+ GC_save_callers(GC_last_stack);
+# endif
+ GC_finish_collection();
+ }
n_partial_gcs++;
}
}
@@ -196,6 +204,9 @@ void GC_gcollect_inner()
GC_promote_black_lists();
/* GC_reclaim_or_delete_all(); -- not needed: no intervening allocation */
GC_clear_marks();
+# ifdef SAVE_CALL_CHAIN
+ GC_save_callers(GC_last_stack);
+# endif
(void) GC_stopped_mark(TRUE);
GC_finish_collection();
}
@@ -211,7 +222,7 @@ int GC_deficit = 0; /* The number of extra calls to GC_mark_some */
/* Negative values are equivalent to 0. */
extern bool GC_collection_in_progress();
-void GC_collect_a_little(n)
+void GC_collect_a_little_inner(n)
int n;
{
register int i;
@@ -220,7 +231,10 @@ int n;
for (i = GC_deficit; i < GC_RATE*n; i++) {
if (GC_mark_some()) {
/* Need to finish a collection */
- (void) GC_stopped_mark(TRUE);
+# ifdef SAVE_CALL_CHAIN
+ GC_save_callers(GC_last_stack);
+# endif
+ (void) GC_stopped_mark(TRUE);
GC_finish_collection();
break;
}
@@ -231,6 +245,20 @@ int n;
}
}
+int GC_collect_a_little(NO_PARAMS)
+{
+ int result;
+ DCL_LOCK_STATE;
+
+ DISABLE_SIGNALS();
+ LOCK();
+ GC_collect_a_little_inner(1);
+ result = (int)GC_collection_in_progress();
+ UNLOCK();
+ ENABLE_SIGNALS();
+ return(result);
+}
+
/*
* Assumes lock is held, signals are disabled.
* We stop the world.
@@ -407,7 +435,7 @@ void GC_finish_collection()
"Immediately reclaimed %ld bytes in heap of size %lu bytes\n",
(long)WORDS_TO_BYTES(GC_mem_found),
(unsigned long)GC_heapsize);
- GC_printf2("%lu (atomic) + %lu (composite) bytes in use\n",
+ GC_printf2("%lu (atomic) + %lu (composite) collectable bytes in use\n",
(unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
(unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
# endif
@@ -428,7 +456,7 @@ void GC_finish_collection()
}
/* Externally callable routine to invoke full, stop-world collection */
-void GC_gcollect()
+void GC_gcollect(NO_PARAMS)
{
DCL_LOCK_STATE;
@@ -576,6 +604,9 @@ word needed_blocks;
static int count = 0; /* How many failures? */
if (!GC_incremental && !GC_dont_gc && GC_should_collect()) {
+# ifdef SAVE_CALL_CHAIN
+ GC_save_callers(GC_last_stack);
+# endif
GC_gcollect_inner();
} else {
word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
@@ -619,7 +650,7 @@ int kind;
while (*flh == 0) {
/* Do our share of marking work */
- if(GC_incremental && !GC_dont_gc) GC_collect_a_little(1);
+ if(GC_incremental && !GC_dont_gc) GC_collect_a_little_inner(1);
/* Sweep blocks for objects of this size */
GC_continue_reclaim(sz, kind);
if (*flh == 0) {
diff --git a/callprocs b/callprocs
index 4f105cc2..a8793f0b 100755
--- a/callprocs
+++ b/callprocs
@@ -1,3 +1,4 @@
#!/bin/sh
GC_DEBUG=1
+export GC_DEBUG
$* 2>&1 | awk '{print "0x3e=c\""$0"\""};/^\t##PC##=/ {if ($2 != 0) {print $2"?i"}}' | adb $1 | sed "s/^ >/>/"
diff --git a/checksums.c b/checksums.c
index 2cc37e41..50420576 100644
--- a/checksums.c
+++ b/checksums.c
@@ -10,7 +10,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:07 pm PDT */
+/* Boehm, July 14, 1994 3:27 pm PDT */
# ifdef CHECKSUMS
# include "gc_priv.h"
@@ -80,13 +80,19 @@ int index;
if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed");
pe -> old_sum = pe -> new_sum;
pe -> new_sum = GC_checksum(h);
+# ifndef MSWIN32
+ if (pe -> new_sum != 0 && !GC_page_was_ever_dirty(h)) {
+ GC_printf1("GC_page_was_ever_dirty(0x%lx) is wrong\n",
+ (unsigned long)h);
+ }
+# endif
if (GC_page_was_dirty(h)) {
GC_n_dirty++;
} else {
GC_n_clean++;
}
if (pe -> new_valid && pe -> old_sum != pe -> new_sum) {
- if (!GC_page_was_dirty(h)) {
+ if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) {
/* Set breakpoint here */GC_n_dirty_errors++;
}
# ifdef STUBBORN_ALLOC
@@ -139,6 +145,11 @@ out:
if (GC_n_changed_errors > 0) {
GC_printf1("Found %lu changed bit errors\n",
(unsigned long)GC_n_changed_errors);
+ GC_printf0("These may be benign (provoked by nonpointer changes)\n");
+# ifdef THREADS
+ GC_printf0(
+ "Also expect 1 per thread currently allocating a stubborn obj.\n");
+# endif
}
}
diff --git a/config.h b/config.h
index 4e096102..ce8411ab 100644
--- a/config.h
+++ b/config.h
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:11 pm PDT */
+/* Boehm, July 28, 1994 11:03 am PDT */
#ifndef CONFIG_H
@@ -65,7 +65,7 @@
# define SUNOS5
# define mach_type_known
# endif
-# if defined(__OS2__) && defined(__32BIT__)
+# if (defined(__OS2__) || defined(__EMX__)) && defined(__32BIT__)
# define I386
# define OS2
# define mach_type_known
@@ -114,8 +114,13 @@
# define mach_type_known
# endif
# if defined(_AMIGA)
+# define M68K
# define AMIGA
+# define mach_type_known
+# endif
+# if defined(THINK_C)
# define M68K
+# define MACOS
# define mach_type_known
# endif
# if defined(NeXT) && defined(mc68000)
@@ -123,6 +128,11 @@
# define NEXT
# define mach_type_known
# endif
+# if defined(NeXT) && defined(i386)
+# define I386
+# define NEXT
+# define mach_type_known
+# endif
# if defined(__FreeBSD__) && defined(i386)
# define I386
# define FREEBSD
@@ -168,11 +178,11 @@
# endif
/* Mapping is: M68K ==> Motorola 680X0 */
/* (SUNOS4,HP,NEXT, and SYSV (A/UX), */
- /* and AMIGA variants) */
+ /* MACOS and AMIGA variants) */
/* I386 ==> Intel 386 */
/* (SEQUENT, OS2, SCO, LINUX, NETBSD, */
/* FREEBSD, THREE86BSD, MSWIN32, */
- /* BSDI, SUNOS5 variants) */
+ /* BSDI, SUNOS5, NEXT variants) */
/* NS32K ==> Encore Multimax */
/* MIPS ==> R2000 or R3000 */
/* (RISCOS, ULTRIX variants) */
@@ -311,6 +321,15 @@
/* STACKBOTTOM and DATASTART handled specially */
/* in os_dep.c */
# endif
+# ifdef MACOS
+# include <LowMem.h>
+# define OS_TYPE "MACOS"
+# define DATASTART ((ptr_t) LMGetCurStackBase())
+ /* globals begin above stack. */
+# define DATAEND ((ptr_t) LMGetCurrentA5())
+ /* and end at a5. */
+# define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
+# endif
# ifdef NEXT
# define OS_TYPE "NEXT"
# define DATASTART ((ptr_t) get_etext())
@@ -347,7 +366,8 @@
extern int etext;
# ifdef SUNOS5
# define OS_TYPE "SUNOS5"
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0x10003) & ~0x3))
+ extern char * GC_SysVGetDataStart(int max_page_size);
+# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000)
# define PROC_VDB
# endif
# ifdef SUNOS4
@@ -382,8 +402,8 @@
# ifdef SUNOS5
# define OS_TYPE "SUNOS5"
extern int etext;
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1003) & ~0x3))
- extern int _start();
+ extern ptr_t GC_SysVGetDataStart(int max_page_size);
+# define DATASTART GC_SysVGetDataStart(0x1000)
# define STACKBOTTOM ((ptr_t)(&_start))
# define PROC_VDB
# endif
@@ -430,6 +450,11 @@
extern char etext;
# define DATASTART ((ptr_t)(&etext))
# endif
+# ifdef NEXT
+# define OS_TYPE "NEXT"
+# define DATASTART ((ptr_t) get_etext())
+# define STACKBOTTOM ((ptr_t)0xc0000000)
+# endif
# endif
# ifdef NS32K
@@ -538,4 +563,8 @@
# define DEFAULT_VDB
# endif
+# if defined(SPARC)
+# define SAVE_CALL_CHAIN
+# endif
+
# endif
diff --git a/cord/SCOPTIONS.amiga b/cord/SCOPTIONS.amiga
new file mode 100755
index 00000000..2a091970
--- /dev/null
+++ b/cord/SCOPTIONS.amiga
@@ -0,0 +1,14 @@
+MATH=STANDARD
+CPU=68030
+NOSTACKCHECK
+OPTIMIZE
+VERBOSE
+NOVERSION
+NOICONS
+OPTIMIZERTIME
+INCLUDEDIR=/
+DEFINE AMIGA
+LIBRARY=cord.lib
+LIBRARY=/gc.lib
+IGNORE=100
+IGNORE=161
diff --git a/cord/SMakefile.amiga b/cord/SMakefile.amiga
new file mode 100644
index 00000000..5aef131e
--- /dev/null
+++ b/cord/SMakefile.amiga
@@ -0,0 +1,20 @@
+# Makefile for cord.lib
+# Michel Schinz 1994/07/20
+
+OBJS = cordbscs.o cordprnt.o cordxtra.o
+
+all: cord.lib cordtest
+
+cordbscs.o: cordbscs.c
+cordprnt.o: cordprnt.c
+cordxtra.o: cordxtra.c
+cordtest.o: cordtest.c
+
+cord.lib: $(OBJS)
+ oml cord.lib r $(OBJS)
+
+cordtest: cordtest.o cord.lib
+ sc cordtest.o link
+
+clean:
+ delete cord.lib cordtest \#?.o \#?.lnk
diff --git a/cord/cord.h b/cord/cord.h
index cdf5e03c..d6f58ada 100644
--- a/cord/cord.h
+++ b/cord/cord.h
@@ -37,6 +37,23 @@
* ASCII NUL characters may be embedded in cords using CORD_from_fn.
* This is handled correctly, but CORD_to_char_star will produce a string
* with embedded NULs when given such a cord.
+ *
+ * This interface is fairly big, largely for performance reasons.
+ * The most basic constants and functions:
+ *
+ * CORD - the type fo a cord;
+ * CORD_EMPTY - empty cord;
+ * CORD_len(cord) - length of a cord;
+ * CORD_cat(cord1,cord2) - concatenation of two cords;
+ * CORD_substr(cord, start, len) - substring (or subcord);
+ * CORD_pos i; CORD_FOR(i, cord) { ... CORD_pos_fetch(i) ... } -
+ * examine each character in a cord. CORD_pos_fetch(i) is the char.
+ * CORD_fetch(int i) - Retrieve i'th character (slowly).
+ * CORD_cmp(cord1, cord2) - compare two cords.
+ * CORD_from_file(FILE * f) - turn a read-only file into a cord.
+ * CORD_to_char_start(cord) - convert to C string.
+ * (Non-NULL C constant strings are cords.)
+ * CORD_printf (etc.) - cord version of printf. Use %r for cords.
*/
# ifndef CORD_H
@@ -149,7 +166,7 @@ int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
size_t CORD_pos_to_index(CORD_pos p);
/* Fetch the character located at the given position:
- char CORD_pos_fetch(register CORD_pos p);
+ char CORD_pos_fetch(CORD_pos p);
/* Initialize the position to refer to the give cord and index.
/* Note that this is the most expensive function on positions:
diff --git a/cord/cordbscs.c b/cord/cordbscs.c
index d828155b..98cdbb39 100644
--- a/cord/cordbscs.c
+++ b/cord/cordbscs.c
@@ -12,8 +12,8 @@
*
* Author: Hans-J. Boehm (boehm@parc.xerox.com)
*/
-/* Boehm, May 19, 1994 2:18 pm PDT */
-# include "../gc.h"
+/* Boehm, June 9, 1994 2:22 pm PDT */
+# include "gc.h"
# include "cord.h"
# include <stdlib.h>
# include <stdio.h>
diff --git a/cord/cordprnt.c b/cord/cordprnt.c
index 1b043152..e4e05304 100644
--- a/cord/cordprnt.c
+++ b/cord/cordprnt.c
@@ -20,14 +20,14 @@
/* We assume that void * and char * have the same size. */
/* All this cruft is needed because we want to rely on the underlying */
/* sprintf implementation whenever possible. */
-/* Boehm, May 19, 1994 2:19 pm PDT */
+/* Boehm, July 25, 1994 3:42 pm PDT */
#include "cord.h"
#include "ec.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
-#include "../gc.h"
+#include "gc.h"
#define CONV_SPEC_LEN 50 /* Maximum length of a single */
/* conversion specification. */
@@ -254,7 +254,6 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
/* Use standard sprintf to perform conversion */
{
register char * buf;
- int needed_sz;
va_list vsprintf_args = args;
/* The above does not appear to be sanctioned */
/* by the ANSI C standard. */
diff --git a/cord/cordtest.c b/cord/cordtest.c
index cf1c4a45..2b35772b 100644
--- a/cord/cordtest.c
+++ b/cord/cordtest.c
@@ -10,8 +10,9 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:21 pm PDT */
+/* Boehm, July 25, 1994 3:24 pm PDT */
# include "cord.h"
+# include <string.h>
# include <stdio.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) */
@@ -45,7 +46,7 @@ char id_cord_fn(size_t i, void * client_data)
return((char)i);
}
-test_basics()
+void test_basics()
{
CORD x = "ab";
register int i;
@@ -112,11 +113,14 @@ test_basics()
if (i != 13) ABORT("Bad apparent length for function node");
}
-test_extras()
+void test_extras()
{
-# ifdef __OS2__
+# if defined(__OS2__)
# define FNAME1 "tmp1"
# define FNAME2 "tmp2"
+# elif defined(AMIGA)
+# define FNAME1 "T:tmp1"
+# define FNAME2 "T:tmp2"
# else
# define FNAME1 "/tmp/cord_test"
# define FNAME2 "/tmp/cord_test2"
@@ -182,7 +186,7 @@ test_extras()
}
}
-test_printf()
+void test_printf()
{
CORD result;
char result2[200];
@@ -190,7 +194,7 @@ test_printf()
short s;
CORD x;
- if (CORD_sprintf(&result, "%7.2f%ln", 3.14159, &l) != 7)
+ if (CORD_sprintf(&result, "%7.2f%ln", 3.14159F, &l) != 7)
ABORT("CORD_sprintf failed 1");
if (CORD_cmp(result, " 3.14") != 0)ABORT("CORD_sprintf goofed 1");
if (l != 7) ABORT("CORD_sprintf goofed 2");
@@ -210,6 +214,9 @@ test_printf()
main()
{
+# ifdef THINK_C
+ printf("cordtest:\n");
+# endif
test_basics();
test_extras();
test_printf();
diff --git a/cord/cordxtra.c b/cord/cordxtra.c
index 4aaaf6e7..ff8c8b50 100644
--- a/cord/cordxtra.c
+++ b/cord/cordxtra.c
@@ -17,7 +17,7 @@
* implementation. They serve also serve as example client code for
* cord_basics.
*/
-/* Boehm, May 19, 1994 2:18 pm PDT */
+/* Boehm, July 25, 1994 3:46 pm PDT */
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
@@ -27,7 +27,7 @@
/* We use this for lazy file reading, */
/* so that we remain independent */
/* of the threads primitives. */
-# include "../gc.h"
+# include "gc.h"
/* The standard says these are in stdio.h, but they aren't always: */
# ifndef SEEK_SET
@@ -86,7 +86,7 @@ int CORD_batched_fill_proc(const char * s, void * client_data)
register char * buf = d -> buf;
register const char * t = s;
- while(((d -> buf)[count] = *t++) != '\0') {
+ while((buf[count] = *t++) != '\0') {
count++;
if (count >= max) {
d -> count = count;
@@ -97,7 +97,7 @@ int CORD_batched_fill_proc(const char * s, void * client_data)
return(0);
}
-/* Fill buf with between min and max characters starting at i. */
+/* 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)
{
diff --git a/cord/de.c b/cord/de.c
index c2cad50a..5f8fd3b5 100644
--- a/cord/de.c
+++ b/cord/de.c
@@ -26,20 +26,44 @@
* The redisplay algorithm doesn't let curses do the scrolling.
* The rule for moving the window over the file is suboptimal.
*/
+/* Boehm, June 13, 1994 2:35 pm PDT */
+
/* Boehm, May 19, 1994 2:20 pm PDT */
#include <stdio.h>
-#include "../gc.h"
+#include "gc.h"
#include "cord.h"
-#ifdef WIN32
+
+#ifdef THINK_C
+#define MACINTOSH
+#include <ctype.h>
+#endif
+
+#if defined(WIN32)
# include <windows.h>
# include "de_win.h"
+#elif defined(MACINTOSH)
+# include <console.h>
+/* curses emulation. */
+# define initscr()
+# define endwin()
+# define nonl()
+# define noecho() csetmode(C_NOECHO, stdout)
+# define cbreak() csetmode(C_CBREAK, stdout)
+# define refresh()
+# define addch(c) putchar(c)
+# define standout() cinverse(1, stdout)
+# define standend() cinverse(0, stdout)
+# define move(line,col) cgotoxy(col + 1, line + 1, stdout)
+# define clrtoeol() ccleol(stdout)
+# define de_error(s) { fprintf(stderr, s); getchar(); }
+# define LINES 25
+# define COLS 80
#else
# include <curses.h>
# define de_error(s) { fprintf(stderr, s); sleep(2); }
#endif
#include "de_cmds.h"
-
/* List of line number to position mappings, in descending order. */
/* There may be holes. */
typedef struct LineMapRep {
@@ -174,20 +198,26 @@ int screen_size = 0;
# ifndef WIN32
/* Replace a line in the curses stdscr. All control characters are */
/* displayed as upper case characters in standout mode. This isn't */
-/* terribly appropriate for tabs. */
+/* terribly appropriate for tabs. */
void replace_line(int i, CORD s)
{
register int c;
CORD_pos p;
+ size_t len = CORD_len(s);
if (screen == 0 || LINES > screen_size) {
screen_size = LINES;
screen = (CORD *)GC_MALLOC(screen_size * sizeof(CORD));
}
- if (CORD_cmp(screen[i], s) != 0) {
- move(i,0); clrtoeol();
+# if !defined(MACINTOSH)
/* A gross workaround for an apparent curses bug: */
- if (i == LINES-1) s = CORD_substr(s, 0, CORD_len(s) - 1);
+ if (i == LINES-1 && len == COLS) {
+ s = CORD_substr(s, 0, CORD_len(s) - 1);
+ }
+# endif
+ if (CORD_cmp(screen[i], s) != 0) {
+ move(i, 0); clrtoeol(); move(i,0);
+
CORD_FOR (p, s) {
c = CORD_pos_fetch(p) & 0x7f;
if (iscntrl(c)) {
@@ -263,7 +293,7 @@ void normalize_display()
int old_col = dis_col;
dis_granularity = 1;
- if (LINES > 15 && COLS > 15) dis_granularity = 5;
+ if (LINES > 15 && COLS > 15) dis_granularity = 2;
while (dis_line > line) dis_line -= dis_granularity;
while (dis_col > col) dis_col -= dis_granularity;
while (line >= dis_line + LINES) dis_line += dis_granularity;
@@ -273,8 +303,11 @@ void normalize_display()
}
}
-# ifndef WIN32
-# define move_cursor(x,y) move(y,x)
+# if defined(WIN32)
+# elif defined(MACINTOSH)
+# define move_cursor(x,y) cgotoxy(x + 1, y + 1, stdout)
+# else
+# define move_cursor(x,y) move(y,x)
# endif
/* Adjust display so that cursor is visible; move cursor into position */
@@ -309,7 +342,11 @@ void fix_pos()
}
}
-#ifndef WIN32
+#if defined(WIN32)
+# define beep() Beep(1000 /* Hz */, 300 /* msecs */)
+#elif defined(MACINTOSH)
+# define beep() SysBeep(1)
+#else
/*
* beep() is part of some curses packages and not others.
* We try to match the type of the builtin one, if any.
@@ -323,8 +360,6 @@ void fix_pos()
putc('\007', stderr);
return(0);
}
-#else
-# define beep() Beep(1000 /* Hz */, 300 /* msecs */)
#endif
# define NO_PREFIX -1
@@ -489,6 +524,7 @@ void do_command(int c)
}
/* OS independent initialization */
+
void generic_init(void)
{
FILE * f;
@@ -519,6 +555,13 @@ char ** argv;
{
int c;
CORD initial;
+
+#if defined(MACINTOSH)
+ console_options.title = "\pDumb Editor";
+ cshow(stdout);
+ GC_init();
+ argc = ccommand(&argv);
+#endif
if (argc != 2) goto usage;
arg_file_name = argv[1];
@@ -527,7 +570,8 @@ char ** argv;
noecho(); nonl(); cbreak();
generic_init();
while ((c = getchar()) != QUIT) {
- do_command(c);
+ if (c == EOF) break;
+ do_command(c);
}
done:
endwin();
diff --git a/cord/gc.h b/cord/gc.h
new file mode 100644
index 00000000..34e56bf4
--- /dev/null
+++ b/cord/gc.h
@@ -0,0 +1,475 @@
+/*
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, June 8, 1994 1:12 pm PDT */
+
+#ifndef _GC_H
+
+# define _GC_H
+
+# include <stddef.h>
+
+/* Define word and signed_word to be unsigned and signed types of the */
+/* size as char * or void *. There seems to be no way to do this */
+/* even semi-portably. The following is probably no better/worse */
+/* than almost anything else. */
+/* The ANSI standard suggests that size_t and ptr_diff_t might be */
+/* better choices. But those appear to have incorrect definitions */
+/* on may systems. Notably "typedef int size_t" seems to be both */
+/* frequent and WRONG. */
+typedef unsigned long GC_word;
+typedef long GC_signed_word;
+
+/* Public read-only variables */
+
+extern GC_word GC_gc_no;/* Counter incremented per collection. */
+ /* Includes empty GCs at startup. */
+
+
+/* Public R/W variables */
+
+extern int GC_quiet; /* Disable statistics output. Only matters if */
+ /* collector has been compiled with statistics */
+ /* enabled. This involves a performance cost, */
+ /* and is thus not the default. */
+
+extern int GC_dont_gc; /* Dont collect unless explicitly requested, e.g. */
+ /* beacuse it's not safe. */
+
+extern int GC_dont_expand;
+ /* Dont expand heap unless explicitly requested */
+ /* or forced to. */
+
+extern int GC_full_freq; /* Number of partial collections between */
+ /* full collections. Matters only if */
+ /* GC_incremental is set. */
+
+extern GC_word GC_non_gc_bytes;
+ /* Bytes not considered candidates for collection. */
+ /* Used only to control scheduling of collections. */
+
+extern GC_word GC_free_space_divisor;
+ /* We try to make sure that we allocate at */
+ /* least N/GC_free_space_divisor bytes between */
+ /* collections, where N is the heap size plus */
+ /* a rough estimate of the root set size. */
+ /* Initially, GC_free_space_divisor = 4. */
+ /* Increasing its value will use less space */
+ /* but more collection time. Decreasing it */
+ /* will appreciably decrease collection time */
+ /* at the expense of space. */
+ /* GC_free_space_divisor = 1 will effectively */
+ /* disable collections. */
+
+
+/* Public procedures */
+/*
+ * general purpose allocation routines, with roughly malloc calling conv.
+ * The atomic versions promise that no relevant pointers are contained
+ * in the object. The nonatomic versions guarantee that the new object
+ * is cleared. GC_malloc_stubborn promises that no changes to the object
+ * will occur after GC_end_stubborn_change has been called on the
+ * result of GC_malloc_stubborn. GC_malloc_uncollectable allocates an object
+ * that is scanned for pointers to collectable objects, but is not itself
+ * collectable. GC_malloc_uncollectable and GC_free called on the resulting
+ * object implicitly update GC_non_gc_bytes appropriately.
+ */
+#if defined(__STDC__) || defined(__cplusplus)
+ extern void * GC_malloc(size_t size_in_bytes);
+ extern void * GC_malloc_atomic(size_t size_in_bytes);
+ extern void * GC_malloc_uncollectable(size_t size_in_bytes);
+ extern void * GC_malloc_stubborn(size_t size_in_bytes);
+# else
+ extern char * GC_malloc(/* size_in_bytes */);
+ extern char * GC_malloc_atomic(/* size_in_bytes */);
+ extern char * GC_malloc_uncollectable(/* size_in_bytes */);
+ extern char * GC_malloc_stubborn(/* size_in_bytes */);
+# endif
+
+#if defined(__STDC__) && !defined(__cplusplus)
+# define NO_PARAMS void
+#else
+# define NO_PARAMS
+#endif
+
+/* Explicitly deallocate an object. Dangerous if used incorrectly. */
+/* Requires a pointer to the base of an object. */
+/* If the argument is stubborn, it should not be changeable when freed. */
+/* An object should not be enable for finalization when it is */
+/* explicitly deallocated. */
+/* GC_free(0) is a no-op, as required by ANSI C for free. */
+#if defined(__STDC__) || defined(__cplusplus)
+ extern void GC_free(void * object_addr);
+# else
+ extern void GC_free(/* object_addr */);
+# endif
+
+/*
+ * Stubborn objects may be changed only if the collector is explicitly informed.
+ * The collector is implicitly informed of coming change when such
+ * an object is first allocated. The following routines inform the
+ * collector that an object will no longer be changed, or that it will
+ * once again be changed. Only nonNIL pointer stores into the object
+ * are considered to be changes. The argument to GC_end_stubborn_change
+ * must be exacly the value returned by GC_malloc_stubborn or passed to
+ * GC_change_stubborn. (In the second case it may be an interior pointer
+ * within 512 bytes of the beginning of the objects.)
+ * There is a performance penalty for allowing more than
+ * one stubborn object to be changed at once, but it is acceptable to
+ * do so. The same applies to dropping stubborn objects that are still
+ * changeable.
+ */
+void GC_change_stubborn(/* p */);
+void GC_end_stubborn_change(/* p */);
+
+/* Return a pointer to the base (lowest address) of an object given */
+/* a pointer to a location within the object. */
+/* Return 0 if displaced_pointer doesn't point to within a valid */
+/* object. */
+# if defined(__STDC__) || defined(__cplusplus)
+ void * GC_base(void * displaced_pointer);
+# else
+ char * GC_base(/* char * displaced_pointer */);
+# endif
+
+/* Given a pointer to the base of an object, return its size in bytes. */
+/* The returned size may be slightly larger than what was originally */
+/* requested. */
+# if defined(__STDC__) || defined(__cplusplus)
+ size_t GC_size(void * object_addr);
+# else
+ size_t GC_size(/* char * object_addr */);
+# endif
+
+/* For compatibility with C library. This is occasionally faster than */
+/* a malloc followed by a bcopy. But if you rely on that, either here */
+/* or with the standard C library, your code is broken. In my */
+/* opinion, it shouldn't have been invented, but now we're stuck. -HB */
+/* The resulting object has the same kind as the original. */
+/* If the argument is stubborn, the result will have changes enabled. */
+/* It is an error to have changes enabled for the original object. */
+/* Follows ANSI comventions for NULL old_object. */
+# if defined(__STDC__) || defined(__cplusplus)
+ extern void * GC_realloc(void * old_object, size_t new_size_in_bytes);
+# else
+ extern char * GC_realloc(/* old_object, new_size_in_bytes */);
+# endif
+
+
+/* Explicitly increase the heap size. */
+/* Returns 0 on failure, 1 on success. */
+extern int GC_expand_hp(/* number_of_bytes */);
+
+/* Clear the set of root segments */
+extern void GC_clear_roots(NO_PARAMS);
+
+/* Add a root segment */
+extern void GC_add_roots(/* low_address, high_address_plus_1 */);
+
+/* Add a displacement to the set of those considered valid by the */
+/* collector. GC_register_displacement(n) means that if p was returned */
+/* by GC_malloc, then (char *)p + n will be considered to be a valid */
+/* pointer to n. N must be small and less than the size of p. */
+/* (All pointers to the interior of objects from the stack are */
+/* considered valid in any case. This applies to heap objects and */
+/* static data.) */
+/* Preferably, this should be called before any other GC procedures. */
+/* Calling it later adds to the probability of excess memory */
+/* retention. */
+/* This is a no-op if the collector was compiled with recognition of */
+/* arbitrary interior pointers enabled, which is now the default. */
+void GC_register_displacement(/* n */);
+
+/* Explicitly trigger a full, world-stop collection. */
+void GC_gcollect(NO_PARAMS);
+
+/* Return the number of bytes in the heap. Excludes collector private */
+/* data structures. Includes empty blocks and fragmentation loss. */
+/* Includes some pages that were allocated but never written. */
+size_t GC_get_heap_size(NO_PARAMS);
+
+/* Enable incremental/generational collection. */
+/* Not advisable unless dirty bits are */
+/* available or most heap objects are */
+/* pointerfree(atomic) or immutable. */
+/* Don't use in leak finding mode. */
+/* Ignored if GC_dont_gc is true. */
+void GC_enable_incremental(NO_PARAMS);
+
+/* Perform some garbage collection work, if appropriate. */
+/* Return 0 if there is no more work to be done. */
+/* Typically performs an amount of work corresponding roughly */
+/* to marking from one page. May do more work if further */
+/* progress requires it, e.g. if incremental collection is */
+/* disabled. It is reasonable to call this in a wait loop */
+/* until it returns 0. */
+int GC_collect_a_little(NO_PARAMS);
+
+/* Allocate an object of size lb bytes. The client guarantees that */
+/* as long as the object is live, it will be referenced by a pointer */
+/* that points to somewhere within the first 256 bytes of the object. */
+/* (This should normally be declared volatile to prevent the compiler */
+/* from invalidating this assertion.) This routine is only useful */
+/* if a large array is being allocated. It reduces the chance of */
+/* accidentally retaining such an array as a result of scanning an */
+/* integer that happens to be an address inside the array. (Actually, */
+/* it reduces the chance of the allocator not finding space for such */
+/* an array, since it will try hard to avoid introducing such a false */
+/* reference.) On a SunOS 4.X or MS Windows system this is recommended */
+/* for arrays likely to be larger than 100K or so. For other systems, */
+/* or if the collector is not configured to recognize all interior */
+/* pointers, the threshold is normally much higher. */
+# if defined(__STDC__) || defined(__cplusplus)
+ void * GC_malloc_ignore_off_page(size_t lb);
+# else
+ char * GC_malloc_ignore_off_page(/* size_t lb */);
+# endif
+# if defined(__STDC__) || defined(__cplusplus)
+ void * GC_malloc_atomic_ignore_off_page(size_t lb);
+# else
+ char * GC_malloc_atomic_ignore_off_page(/* size_t lb */);
+# endif
+
+/* Debugging (annotated) allocation. GC_gcollect will check */
+/* objects allocated in this way for overwrites, etc. */
+# if defined(__STDC__) || defined(__cplusplus)
+ extern void * GC_debug_malloc(size_t size_in_bytes,
+ char * descr_string, int descr_int);
+ extern void * GC_debug_malloc_atomic(size_t size_in_bytes,
+ char * descr_string, int descr_int);
+ extern void * GC_debug_malloc_uncollectable(size_t size_in_bytes,
+ char * descr_string, int descr_int);
+ extern void * GC_debug_malloc_stubborn(size_t size_in_bytes,
+ char * descr_string, int descr_int);
+ extern void GC_debug_free(void * object_addr);
+ extern void * GC_debug_realloc(void * old_object,
+ size_t new_size_in_bytes,
+ char * descr_string, int descr_int);
+# else
+ extern char * GC_debug_malloc(/* size_in_bytes, descr_string, descr_int */);
+ extern char * GC_debug_malloc_atomic(/* size_in_bytes, descr_string,
+ descr_int */);
+ extern char * GC_debug_malloc_uncollectable(/* size_in_bytes, descr_string,
+ descr_int */);
+ extern char * GC_debug_malloc_stubborn(/* size_in_bytes, descr_string,
+ descr_int */);
+ extern void GC_debug_free(/* object_addr */);
+ extern char * GC_debug_realloc(/* old_object, new_size_in_bytes,
+ descr_string, descr_int */);
+# endif
+void GC_debug_change_stubborn(/* p */);
+void GC_debug_end_stubborn_change(/* p */);
+# ifdef GC_DEBUG
+# define GC_MALLOC(sz) GC_debug_malloc(sz, __FILE__, __LINE__)
+# define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, __FILE__, __LINE__)
+# define GC_MALLOC_UNCOLLECTABLE(sz) GC_debug_malloc_uncollectable(sz, \
+ __FILE__, __LINE__)
+# define GC_REALLOC(old, sz) GC_debug_realloc(old, sz, __FILE__, \
+ __LINE__)
+# define GC_FREE(p) GC_debug_free(p)
+# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+ GC_register_finalizer(GC_base(p), GC_debug_invoke_finalizer, \
+ GC_make_closure(f,d), of, od)
+# define GC_MALLOC_STUBBORN(sz) GC_debug_malloc_stubborn(sz, __FILE__, \
+ __LINE__)
+# define GC_CHANGE_STUBBORN(p) GC_debug_change_stubborn(p)
+# define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p)
+# else
+# define GC_MALLOC(sz) GC_malloc(sz)
+# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
+# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
+# define GC_REALLOC(old, sz) GC_realloc(old, sz)
+# define GC_FREE(p) GC_free(p)
+# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+ GC_register_finalizer(p, f, d, of, od)
+# define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
+# define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
+# define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
+# endif
+/* The following are included because they are often convenient, and */
+/* reduce the chance for a misspecifed size argument. But calls may */
+/* expand to something syntactically incorrect if t is a complicated */
+/* type expression. */
+# define GC_NEW(t) (t *)GC_MALLOC(sizeof (t))
+# define GC_NEW_ATOMIC(t) (t *)GC_MALLOC_ATOMIC(sizeof (t))
+# define GC_NEW_STUBBORN(t) (t *)GC_MALLOC_STUBBORN(sizeof (t))
+# define GC_NEW_UNCOLLECTABLE(t) (t *)GC_MALLOC_UNCOLLECTABLE(sizeof (t))
+
+/* Finalization. Some of these primitives are grossly unsafe. */
+/* The idea is to make them both cheap, and sufficient to build */
+/* a safer layer, closer to PCedar finalization. */
+/* The interface represents my conclusions from a long discussion */
+/* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes, */
+/* Christian Jacobi, and Russ Atkinson. It's not perfect, and */
+/* probably nobody else agrees with it. Hans-J. Boehm 3/13/92 */
+# if defined(__STDC__) || defined(__cplusplus)
+ typedef void (*GC_finalization_proc)(void * obj, void * client_data);
+# else
+ typedef void (*GC_finalization_proc)(/* void * obj, void * client_data */);
+# endif
+
+# if defined(__STDC__) || defined(__cplusplus)
+ void GC_register_finalizer(void * obj,
+ GC_finalization_proc fn, void * cd,
+ GC_finalization_proc *ofn, void ** ocd);
+# else
+ void GC_register_finalizer(/* void * obj,
+ GC_finalization_proc fn, void * cd,
+ GC_finalization_proc *ofn, void ** ocd */);
+# endif
+ /* When obj is no longer accessible, invoke */
+ /* (*fn)(obj, cd). If a and b are inaccessible, and */
+ /* a points to b (after disappearing links have been */
+ /* made to disappear), then only a will be */
+ /* finalized. (If this does not create any new */
+ /* pointers to b, then b will be finalized after the */
+ /* next collection.) Any finalizable object that */
+ /* is reachable from itself by following one or more */
+ /* pointers will not be finalized (or collected). */
+ /* Thus cycles involving finalizable objects should */
+ /* be avoided, or broken by disappearing links. */
+ /* Fn should terminate as quickly as possible, and */
+ /* defer extended computation. */
+ /* All but the last finalizer registered for an object */
+ /* is ignored. */
+ /* Finalization may be removed by passing 0 as fn. */
+ /* The old finalizer and client data are stored in */
+ /* *ofn and *ocd. */
+ /* Fn is never invoked on an accessible object, */
+ /* provided hidden pointers are converted to real */
+ /* pointers only if the allocation lock is held, and */
+ /* such conversions are not performed by finalization */
+ /* routines. */
+ /* If GC_register_finalizer is aborted as a result of */
+ /* a signal, the object may be left with no */
+ /* finalization, even if neither the old nor new */
+ /* finalizer were NULL. */
+ /* Obj should be the nonNULL starting address of an */
+ /* object allocated by GC_malloc or friends. */
+
+/* The following routine may be used to break cycles between */
+/* finalizable objects, thus causing cyclic finalizable */
+/* objects to be finalized in the correct order. Standard */
+/* use involves calling GC_register_disappearing_link(&p), */
+/* where p is a pointer that is not followed by finalization */
+/* code, and should not be considered in determining */
+/* finalization order. */
+int GC_register_disappearing_link(/* void ** link */);
+ /* Link should point to a field of a heap allocated */
+ /* object obj. *link will be cleared when obj is */
+ /* found to be inaccessible. This happens BEFORE any */
+ /* finalization code is invoked, and BEFORE any */
+ /* decisions about finalization order are made. */
+ /* This is useful in telling the finalizer that */
+ /* some pointers are not essential for proper */
+ /* finalization. This may avoid finalization cycles. */
+ /* Note that obj may be resurrected by another */
+ /* finalizer, and thus the clearing of *link may */
+ /* be visible to non-finalization code. */
+ /* There's an argument that an arbitrary action should */
+ /* be allowed here, instead of just clearing a pointer. */
+ /* But this causes problems if that action alters, or */
+ /* examines connectivity. */
+ /* Returns 1 if link was already registered, 0 */
+ /* otherwise. */
+ /* Only exists for backward compatibility. See below: */
+int GC_general_register_disappearing_link(/* void ** link, void * obj */);
+ /* A slight generalization of the above. *link is */
+ /* cleared when obj first becomes inaccessible. This */
+ /* can be used to implement weak pointers easily and */
+ /* safely. Typically link will point to a location */
+ /* holding a disguised pointer to obj. In this way */
+ /* soft pointers are broken before any object */
+ /* reachable from them are finalized. Each link */
+ /* May be registered only once, i.e. with one obj */
+ /* value. This was added after a long email discussion */
+ /* with John Ellis. */
+ /* Obj must be a pointer to the first word of an object */
+ /* we allocated. It is unsafe to explicitly deallocate */
+ /* the object containing link. Explicitly deallocating */
+ /* obj may or may not cause link to eventually be */
+ /* cleared. */
+int GC_unregister_disappearing_link(/* void ** link */);
+ /* Returns 0 if link was not actually registered. */
+ /* Undoes a registration by either of the above two */
+ /* routines. */
+
+/* Auxiliary fns to make finalization work correctly with displaced */
+/* pointers introduced by the debugging allocators. */
+# if defined(__STDC__) || defined(__cplusplus)
+ void * GC_make_closure(GC_finalization_proc fn, void * data);
+ void GC_debug_invoke_finalizer(void * obj, void * data);
+# else
+ char * GC_make_closure(/* GC_finalization_proc fn, char * data */);
+ void GC_debug_invoke_finalizer(/* void * obj, void * data */);
+# endif
+
+
+/* The following is intended to be used by a higher level */
+/* (e.g. cedar-like) finalization facility. It is expected */
+/* that finalization code will arrange for hidden pointers to */
+/* disappear. Otherwise objects can be accessed after they */
+/* have been collected. */
+# ifdef I_HIDE_POINTERS
+# if defined(__STDC__) || defined(__cplusplus)
+# define HIDE_POINTER(p) (~(size_t)(p))
+# define REVEAL_POINTER(p) ((void *)(HIDE_POINTER(p)))
+# else
+# define HIDE_POINTER(p) (~(unsigned long)(p))
+# define REVEAL_POINTER(p) ((char *)(HIDE_POINTER(p)))
+# endif
+ /* Converting a hidden pointer to a real pointer requires verifying */
+ /* that the object still exists. This involves acquiring the */
+ /* allocator lock to avoid a race with the collector. */
+
+# if defined(__STDC__) || defined(__cplusplus)
+ typedef void * (*GC_fn_type)();
+ void * GC_call_with_alloc_lock(GC_fn_type fn, void * client_data);
+# else
+ typedef char * (*GC_fn_type)();
+ char * GC_call_with_alloc_lock(/* GC_fn_type fn, char * client_data */);
+# endif
+# endif
+
+#ifdef SOLARIS_THREADS
+/* We need to intercept calls to many of the threads primitives, so */
+/* that we can locate thread stacks and stop the world. */
+/* Note also that the collector cannot see thread specific data. */
+/* Thread specific data should generally consist of pointers to */
+/* uncollectable objects, which are deallocated using the destructor */
+/* facility in thr_keycreate. */
+# include <thread.h>
+ int GC_thr_create(void *stack_base, size_t stack_size,
+ void *(*start_routine)(void *), void *arg, long flags,
+ thread_t *new_thread);
+ int GC_thr_join(thread_t wait_for, thread_t *departed, void **status);
+ int GC_thr_suspend(thread_t target_thread);
+ int GC_thr_continue(thread_t target_thread);
+ void * GC_dlopen(const char *path, int mode);
+
+# define thr_create GC_thr_create
+# define thr_join GC_thr_join
+# define thr_suspend GC_thr_suspend
+# define thr_continue GC_thr_continue
+# define dlopen GC_dlopen
+
+/* This returns a list of objects, linked through their first */
+/* word. Its use can greatly reduce lock contention problems, since */
+/* the allocation lock can be acquired and released many fewer times. */
+void * GC_malloc_many(size_t lb);
+#define GC_NEXT(p) (*(void **)(p)) /* Retrieve the next element */
+ /* in returned list. */
+
+#endif /* SOLARIS_THREADS */
+
+#endif /* _GC_H */
diff --git a/dbg_mlc.c b/dbg_mlc.c
index 87275d66..f9c7ff0d 100644
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -11,33 +11,17 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:07 pm PDT */
+/* Boehm, June 16, 1994 4:54 pm PDT */
# include "gc_priv.h"
/* Do we want to and know how to save the call stack at the time of */
/* an allocation? How much space do we want to use in each object? */
-# if defined(SPARC) && defined(SUNOS4)
-# include <machine/frame.h>
-# define SAVE_CALL_CHAIN
-# define NFRAMES 5 /* Number of frames to save. */
-# define NARGS 2 /* Mumber of arguments to save for each call. */
-# if NARGS > 6
- --> We only know how to to get the first 6 arguments
-# endif
-# endif
-
# define START_FLAG ((word)0xfedcedcb)
# define END_FLAG ((word)0xbcdecdef)
/* Stored both one past the end of user object, and one before */
/* the end of the object as seen by the allocator. */
-#ifdef SAVE_CALL_CHAIN
- struct callinfo {
- word ci_pc;
- word ci_arg[NARGS]; /* bit-wise complement to avoid retention */
- };
-#endif
/* Object header */
typedef struct {
@@ -56,50 +40,6 @@ typedef struct {
#undef ROUNDED_UP_WORDS
#define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
-#if defined(SPARC) && defined(SUNOS4)
-/* Fill in the pc and argument information for up to NFRAMES of my */
-/* callers. Ignore my frame and my callers frame. */
-void GC_save_callers (info)
-struct callinfo info[NFRAMES];
-{
- struct frame *frame;
- struct frame *fp;
- int nframes = 0;
- word GC_save_regs_in_stack();
-
- frame = (struct frame *) GC_save_regs_in_stack ();
-
- for (fp = frame -> fr_savfp; fp != 0 && nframes < NFRAMES;
- fp = fp -> fr_savfp, nframes++) {
- register int i;
-
- info[nframes].ci_pc = fp->fr_savpc;
- for (i = 0; i < NARGS; i++) {
- info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
- }
- }
- if (nframes < NFRAMES) info[nframes].ci_pc = 0;
-}
-
-void GC_print_callers (info)
-struct callinfo info[NFRAMES];
-{
- register int i,j;
-
- GC_err_printf0("\tCall chain at allocation:\n");
- for (i = 0; i < NFRAMES; i++) {
- if (info[i].ci_pc == 0) break;
- GC_err_printf1("\t##PC##= 0x%X\n\t\targs: ", info[i].ci_pc);
- for (j = 0; j < NARGS; j++) {
- if (j != 0) GC_err_printf0(", ");
- GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
- ~(info[i].ci_arg[j]));
- }
- GC_err_printf0("\n");
- }
-}
-
-#endif /* SPARC & SUNOS4 */
#ifdef SAVE_CALL_CHAIN
# define ADD_CALL_CHAIN(base) GC_save_callers(((oh *)(base)) -> oh_ci)
@@ -204,7 +144,7 @@ ptr_t p, clobbered_addr;
if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
|| ohdr -> oh_string == 0) {
GC_err_printf1("<smashed>, appr. sz = %ld)\n",
- BYTES_TO_WORDS(GC_size((ptr_t)ohdr)));
+ GC_size((ptr_t)ohdr) - DEBUG_BYTES);
} else {
if (ohdr -> oh_string[0] == '\0') {
GC_err_puts("EMPTY(smashed?)");
diff --git a/dyn_load.c b/dyn_load.c
index 28817b0c..caec398e 100644
--- a/dyn_load.c
+++ b/dyn_load.c
@@ -13,7 +13,7 @@
* Original author: Bill Janssen
* Heavily modified by Hans Boehm and others
*/
-/* Boehm, May 19, 1994 1:57 pm PDT */
+/* Boehm, June 7, 1994 4:35 pm PDT */
/*
* This is incredibly OS specific code for tracking down data sections in
@@ -26,7 +26,9 @@
* None of this is safe with dlclose and incremental collection.
* But then not much of anything is safe in the presence of dlclose.
*/
-#include <sys/types.h>
+#ifndef MACOS
+# include <sys/types.h>
+#endif
#include "gc_priv.h"
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR)
diff --git a/finalize.c b/finalize.c
index 45339b3c..031021ee 100644
--- a/finalize.c
+++ b/finalize.c
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:08 pm PDT */
+/* Boehm, June 9, 1994 2:17 pm PDT */
# define I_HIDE_POINTERS
# include "gc.h"
# include "gc_priv.h"
@@ -92,8 +92,8 @@ signed_word * log_size_ptr;
word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
register word new_size = 1 << log_new_size;
struct hash_chain_entry **new_table = (struct hash_chain_entry **)
- GC_malloc_ignore_off_page_inner(
- (size_t)new_size * sizeof(struct hash_chain_entry *));
+ GC_generic_malloc_inner_ignore_off_page(
+ (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
if (new_table == 0) {
if (table == 0) {
@@ -232,12 +232,18 @@ out:
/* in the nonthreads case, we try to avoid disabling signals, */
/* since it can be expensive. Threads packages typically */
/* make it cheaper. */
-void GC_register_finalizer(obj, fn, cd, ofn, ocd)
-extern_ptr_t obj;
-GC_finalization_proc fn;
-extern_ptr_t cd;
-GC_finalization_proc * ofn;
-extern_ptr_t * ocd;
+# if defined(__STDC__)
+ void GC_register_finalizer(void * obj,
+ GC_finalization_proc fn, void * cd,
+ GC_finalization_proc *ofn, void ** ocd)
+# else
+ void GC_register_finalizer(obj, fn, cd, ofn, ocd)
+ extern_ptr_t obj;
+ GC_finalization_proc fn;
+ extern_ptr_t cd;
+ GC_finalization_proc * ofn;
+ extern_ptr_t * ocd;
+# endif
{
ptr_t base;
struct finalizable_object * curr_fo, * prev_fo;
diff --git a/gc.h b/gc.h
index 65a26093..ca7eb506 100644
--- a/gc.h
+++ b/gc.h
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:13 pm PDT */
+/* Boehm, July 7, 1994 11:32 am PDT */
#ifndef _GC_H
@@ -96,6 +96,12 @@ extern GC_word GC_free_space_divisor;
extern char * GC_malloc_stubborn(/* size_in_bytes */);
# endif
+#if defined(__STDC__) && !defined(__cplusplus)
+# define NO_PARAMS void
+#else
+# define NO_PARAMS
+#endif
+
/* Explicitly deallocate an object. Dangerous if used incorrectly. */
/* Requires a pointer to the base of an object. */
/* If the argument is stubborn, it should not be changeable when freed. */
@@ -165,7 +171,7 @@ void GC_end_stubborn_change(/* p */);
extern int GC_expand_hp(/* number_of_bytes */);
/* Clear the set of root segments */
-extern void GC_clear_roots();
+extern void GC_clear_roots(NO_PARAMS);
/* Add a root segment */
extern void GC_add_roots(/* low_address, high_address_plus_1 */);
@@ -184,13 +190,13 @@ extern void GC_add_roots(/* low_address, high_address_plus_1 */);
/* arbitrary interior pointers enabled, which is now the default. */
void GC_register_displacement(/* n */);
-/* Explicitly trigger a collection. */
-void GC_gcollect();
+/* Explicitly trigger a full, world-stop collection. */
+void GC_gcollect(NO_PARAMS);
/* Return the number of bytes in the heap. Excludes collector private */
/* data structures. Includes empty blocks and fragmentation loss. */
/* Includes some pages that were allocated but never written. */
-size_t GC_get_heap_size();
+size_t GC_get_heap_size(NO_PARAMS);
/* Enable incremental/generational collection. */
/* Not advisable unless dirty bits are */
@@ -198,7 +204,16 @@ size_t GC_get_heap_size();
/* pointerfree(atomic) or immutable. */
/* Don't use in leak finding mode. */
/* Ignored if GC_dont_gc is true. */
-void GC_enable_incremental();
+void GC_enable_incremental(NO_PARAMS);
+
+/* Perform some garbage collection work, if appropriate. */
+/* Return 0 if there is no more work to be done. */
+/* Typically performs an amount of work corresponding roughly */
+/* to marking from one page. May do more work if further */
+/* progress requires it, e.g. if incremental collection is */
+/* disabled. It is reasonable to call this in a wait loop */
+/* until it returns 0. */
+int GC_collect_a_little(NO_PARAMS);
/* Allocate an object of size lb bytes. The client guarantees that */
/* as long as the object is live, it will be referenced by a pointer */
@@ -219,6 +234,11 @@ void GC_enable_incremental();
# else
char * GC_malloc_ignore_off_page(/* size_t lb */);
# endif
+# if defined(__STDC__) || defined(__cplusplus)
+ void * GC_malloc_atomic_ignore_off_page(size_t lb);
+# else
+ char * GC_malloc_atomic_ignore_off_page(/* size_t lb */);
+# endif
/* Debugging (annotated) allocation. GC_gcollect will check */
/* objects allocated in this way for overwrites, etc. */
@@ -264,6 +284,8 @@ void GC_debug_end_stubborn_change(/* p */);
__LINE__)
# define GC_CHANGE_STUBBORN(p) GC_debug_change_stubborn(p)
# define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p)
+# define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+ GC_general_register_disappearing_link(link, GC_base(obj))
# else
# define GC_MALLOC(sz) GC_malloc(sz)
# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
@@ -275,6 +297,8 @@ void GC_debug_end_stubborn_change(/* p */);
# define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
# define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
# define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
+# define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+ GC_general_register_disappearing_link(link, obj)
# endif
/* The following are included because they are often convenient, and */
/* reduce the chance for a misspecifed size argument. But calls may */
@@ -297,10 +321,16 @@ void GC_debug_end_stubborn_change(/* p */);
# else
typedef void (*GC_finalization_proc)(/* void * obj, void * client_data */);
# endif
-
-void GC_register_finalizer(/* void * obj,
- GC_finalization_proc fn, void * cd,
- GC_finalization_proc *ofn, void ** ocd */);
+
+# if defined(__STDC__) || defined(__cplusplus)
+ void GC_register_finalizer(void * obj,
+ GC_finalization_proc fn, void * cd,
+ GC_finalization_proc *ofn, void ** ocd);
+# else
+ void GC_register_finalizer(/* void * obj,
+ GC_finalization_proc fn, void * cd,
+ GC_finalization_proc *ofn, void ** ocd */);
+# endif
/* When obj is no longer accessible, invoke */
/* (*fn)(obj, cd). If a and b are inaccessible, and */
/* a points to b (after disappearing links have been */
@@ -329,7 +359,10 @@ void GC_register_finalizer(/* void * obj,
/* finalization, even if neither the old nor new */
/* finalizer were NULL. */
/* Obj should be the nonNULL starting address of an */
- /* object allocated by GC_malloc or friends. */
+ /* object allocated by GC_malloc or friends. */
+ /* Note that any garbage collectable object referenced */
+ /* by cd will be considered accessible until the */
+ /* finalizer is invoked. */
/* The following routine may be used to break cycles between */
/* finalizable objects, thus causing cyclic finalizable */
@@ -423,6 +456,7 @@ int GC_unregister_disappearing_link(/* void ** link */);
/* uncollectable objects, which are deallocated using the destructor */
/* facility in thr_keycreate. */
# include <thread.h>
+# include <signal.h>
int GC_thr_create(void *stack_base, size_t stack_size,
void *(*start_routine)(void *), void *arg, long flags,
thread_t *new_thread);
diff --git a/gc_c++.cc b/gc_c++.cc
index 6654241a..592d91da 100644
--- a/gc_c++.cc
+++ b/gc_c++.cc
@@ -18,8 +18,10 @@ You should ensure (using implementation-dependent techniques) that the
linker finds this module before the library that defines the default
built-in "new" and "delete".
+Authors: Jesse Hull and John Ellis
**************************************************************************/
+/* Boehm, June 8, 1994 3:10 pm PDT */
#include "gc_c++.h"
@@ -27,7 +29,7 @@ void* operator new( size_t size ) {
return GC_MALLOC_UNCOLLECTABLE( size ); }
void operator delete( void* obj ) {
- return GC_FREE( obj ); }
+ GC_FREE( obj ); }
diff --git a/gc_c++.h b/gc_c++.h
index 26019076..d9d703b0 100644
--- a/gc_c++.h
+++ b/gc_c++.h
@@ -65,6 +65,16 @@ back to A, forming a cycle, that's considered a storage leak, and
neither will ever become inaccessible. See the C interface gc.h for
low-level facilities for handling such cycles of objects with cleanup.
+Cautions:
+1. Arrays allocated without new placement syntax are
+allocated as uncollectable objects. They are traced by the
+collector, but will not be reclaimed.
+
+2. Be sure the collector has been augmented with "make c++".
+
+3. If your compiler supports an overloaded new[] operator,
+then gc_c++.cc and gc_c++.h should be suitably modified.
+
****************************************************************************/
#ifndef GC_CPP_H
@@ -78,9 +88,9 @@ enum GCPlacement {GC, NoGC};
class gc {
public:
- void* operator new( size_t size );
- void* operator new( size_t size, GCPlacement gcp );
- void operator delete( void* obj ); };
+ inline void* operator new( size_t size );
+ inline void* operator new( size_t size, GCPlacement gcp );
+ inline void operator delete( void* obj ); };
/*
Intances of classes derived from "gc" will be allocated in the
collected heap by default, unless an explicit NoGC placement is
@@ -88,10 +98,10 @@ public:
class gc_cleanup: public gc {
public:
- gc_cleanup();
- virtual ~gc_cleanup();
+ inline gc_cleanup();
+ inline virtual ~gc_cleanup();
private:
- static void cleanup( void* obj, void* clientData ); };
+ inline static void cleanup( void* obj, void* clientData ); };
/*
Instances of classes derived from "gc_cleanup" will be allocated
in the collected heap by default. Further, when the collector
@@ -101,7 +111,7 @@ private:
inheritance heirarchy -- i.e. it should always be a virtual
base. */
-void* operator new(
+inline void* operator new(
size_t size,
GCPlacement gcp,
void (*cleanup)( void*, void* ) = 0,
@@ -120,8 +130,8 @@ Inline implementation
****************************************************************************/
inline void* gc::operator new( size_t size ) {
- return GC_MALLOC( size ); };
-
+ return GC_MALLOC( size ); }
+
inline void* gc::operator new( size_t size, GCPlacement gcp ) {
if (gcp == GC)
return GC_MALLOC( size );
@@ -129,22 +139,24 @@ inline void* gc::operator new( size_t size, GCPlacement gcp ) {
return GC_MALLOC_UNCOLLECTABLE( size ); }
inline void gc::operator delete( void* obj ) {
- GC_FREE( obj ); };
-
-inline gc_cleanup::gc_cleanup() {
- GC_REGISTER_FINALIZER( GC_base( this ), cleanup, this, 0, 0 ); }
-
-inline void gc_cleanup::cleanup( void* obj, void* realThis ) {
- ((gc_cleanup*) realThis)->~gc_cleanup(); }
-
+ GC_FREE( obj ); }
+
inline gc_cleanup::~gc_cleanup() {
GC_REGISTER_FINALIZER( this, 0, 0, 0, 0 ); }
+inline void gc_cleanup::cleanup( void* obj, void* displ ) {
+ ((gc_cleanup*) ((char *)obj + (ptrdiff_t)displ))->~gc_cleanup(); }
+
+inline gc_cleanup::gc_cleanup() {
+ register void *base = GC_base((void *)this);
+ GC_REGISTER_FINALIZER( base, cleanup,
+ (void *)((char *)this - (char *)base), 0, 0 ); }
+
inline void* operator new(
size_t size,
GCPlacement gcp,
- void (*cleanup)( void*, void* ) = 0,
- void* clientData = 0 )
+ void (*cleanup)( void*, void* ),
+ void* clientData )
{
void* obj;
diff --git a/gc_hdrs.h b/gc_hdrs.h
index c4fd5577..f24ad9ac 100644
--- a/gc_hdrs.h
+++ b/gc_hdrs.h
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:16 pm PDT */
+/* Boehm, July 14, 1994 12:49 pm PDT */
# ifndef GC_HEADERS_H
# define GC_HEADERS_H
typedef struct hblkhdr hdr;
@@ -104,7 +104,7 @@ typedef struct bi {
(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
register bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \
\
- while (_bi -> key != hi && _bi != &GC_all_nils) \
+ while (_bi -> key != hi && _bi != GC_all_nils) \
_bi = _bi -> hash_link; \
(bottom_indx) = _bi; \
}
diff --git a/gc_priv.h b/gc_priv.h
index 501e6f3b..d8fbb726 100644
--- a/gc_priv.h
+++ b/gc_priv.h
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:17 pm PDT */
+/* Boehm, July 28, 1994 10:35 am PDT */
# ifndef GC_PRIVATE_H
@@ -39,8 +39,8 @@ typedef GC_signed_word signed_word;
# define FALSE 0
typedef char * ptr_t; /* A generic pointer to which we can add */
- /* byte displacments. */
- /* Prefereably identical to caddr_t, if it */
+ /* byte displacements. */
+ /* Preferably identical to caddr_t, if it */
/* exists. */
#if defined(__STDC__)
@@ -159,6 +159,10 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* include assembly code to do it well. */
#endif
+#ifdef HP_PA
+# define ALIGN_DOUBLE
+#endif
+
#define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */
/* free lists are actually maintained. This applies */
/* only to the top level routines in misc.c, not to */
@@ -188,6 +192,35 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/*********************************/
/* */
+/* Stack saving for debugging */
+/* */
+/*********************************/
+
+/*
+ * Number of frames and arguments to save in objects allocated by
+ * debugging allocator.
+ */
+# define NFRAMES 5 /* Number of frames to save. */
+# define NARGS 2 /* Mumber of arguments to save for each call. */
+
+
+#ifdef SAVE_CALL_CHAIN
+ struct callinfo {
+ word ci_pc;
+ word ci_arg[NARGS]; /* bit-wise complement to avoid retention */
+ };
+
+/* Fill in the pc and argument information for up to NFRAMES of my */
+/* callers. Ignore my frame and my callers frame. */
+void GC_save_callers (/* struct callinfo info[NFRAMES] */);
+
+void GC_print_callers (/* struct callinfo info[NFRAMES] */);
+
+#endif
+
+
+/*********************************/
+/* */
/* OS interface routines */
/* */
/*********************************/
@@ -254,15 +287,28 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
+ HBLKSIZE-1)
# else
# if defined(AMIGA) || defined(NEXT)
-# define GET_MEM(bytes) HBLKPTR(calloc(1, (size_t)bytes + HBLKSIZE) \
- + HBLKSIZE-1)
+# define GET_MEM(bytes) HBLKPTR((size_t) \
+ calloc(1, (size_t)bytes + HBLKSIZE) \
+ + HBLKSIZE-1)
# else
# ifdef MSWIN32
extern ptr_t GC_win32_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
# else
- extern ptr_t GC_unix_get_mem();
-# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
+# ifdef MACOS
+# if defined(USE_TEMPORARY_MEMORY)
+ extern Ptr GC_MacTemporaryNewPtr(size_t size,
+ Boolean clearMemory);
+# define GET_MEM(bytes) HBLKPTR( \
+ GC_MacTemporaryNewPtr(bytes + HBLKSIZE, true) + HBLKSIZE-1)
+# else
+# define GET_MEM(bytes) HBLKPTR( \
+ NewPtrClear(bytes + HBLKSIZE) + HBLKSIZE-1)
+# endif
+# else
+ extern ptr_t GC_unix_get_mem();
+# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
+# endif
# endif
# endif
# endif
@@ -302,8 +348,8 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# include <base/PCR_Base.h>
# include <th/PCR_Th.h>
extern PCR_Th_ML GC_allocate_ml;
-# define DCL_LOCK_STATE PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mas
-k
+# define DCL_LOCK_STATE \
+ PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
# define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
# define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
# define FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml))
@@ -349,7 +395,8 @@ k
# define ENABLE_SIGNALS() \
PCR_Th_SetSigMask(&GC_old_sig_mask, NIL)
# else
-# if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) || defined(MSWIN32)
+# if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \
+ || defined(MSWIN32) || defined(MACOS)
/* Also useful for debugging, and unusually */
/* correct client code. */
/* Should probably use thr_sigsetmask for SOLARIS_THREADS. */
@@ -388,7 +435,6 @@ k
/* Abandon ship */
# ifdef PCR
- void PCR_Base_Panic(const char *fmt, ...);
# define ABORT(s) PCR_Base_Panic(s)
# else
# ifdef SMALL_CONFIG
@@ -401,8 +447,7 @@ k
/* Exit abnormally, but without making a mess (e.g. out of memory) */
# ifdef PCR
- void PCR_Base_Exit(int status);
-# define EXIT() PCR_Base_Exit(1)
+# define EXIT() PCR_Base_Exit(1,PCR_waitForever)
# else
# define EXIT() (void)exit(1)
# endif
@@ -483,10 +528,21 @@ k
/* Round up byte allocation requests to integral number of words, etc. */
# ifdef ADD_BYTE_AT_END
# define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1))
+# ifdef ALIGN_DOUBLE
+# define ALIGNED_WORDS(n) (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2)) & ~1)
+# else
+# define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n)
+# endif
# define SMALL_OBJ(bytes) ((bytes) < WORDS_TO_BYTES(MAXOBJSZ))
# define ADD_SLOP(bytes) ((bytes)+1)
# else
# define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + (WORDS_TO_BYTES(1) - 1))
+# ifdef ALIGN_DOUBLE
+# define ALIGNED_WORDS(n) \
+ (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1) & ~1)
+# else
+# define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n)
+# endif
# define SMALL_OBJ(bytes) ((bytes) <= WORDS_TO_BYTES(MAXOBJSZ))
# define ADD_SLOP(bytes) (bytes)
# endif
@@ -656,7 +712,7 @@ struct _GC_arrays {
/* free list for immutable objects */
ptr_t _obj_map[MAXOBJSZ+1];
/* If not NIL, then a pointer to a map of valid */
- /* object addresses. hbh_map[sz][i] is j if the */
+ /* object addresses. _obj_map[sz][i] is j if the */
/* address block_start+i is a valid pointer */
/* to an object at */
/* block_start+i&~3 - WORDS_TO_BYTES(j). */
@@ -668,7 +724,7 @@ struct _GC_arrays {
/* It is OBJ_INVALID if */
/* block_start+WORDS_TO_BYTES(i) is not */
/* valid as a pointer to an object. */
- /* We assume that all values of j <= OBJ_INVALID */
+ /* We assume all values of j <= OBJ_INVALID. */
/* The zeroth entry corresponds to large objects.*/
# ifdef ALL_INTERIOR_POINTERS
# define map_entry_type short
@@ -701,11 +757,7 @@ struct _GC_arrays {
/* GC_valid_offsets[i] ==> */
/* GC_modws_valid_offsets[i%sizeof(word)] */
# endif
- struct hblk * _reclaim_list[MAXOBJSZ+1];
- struct hblk * _areclaim_list[MAXOBJSZ+1];
- struct hblk * _ureclaim_list[MAXOBJSZ+1];
# ifdef STUBBORN_ALLOC
- struct hblk * _sreclaim_list[MAXOBJSZ+1];
page_hash_table _changed_pages;
/* Stubborn object pages that were changes since last call to */
/* GC_read_changed. */
@@ -726,8 +778,16 @@ struct _GC_arrays {
/* Start address of memory regions obtained from kernel. */
# endif
/* Block header index; see gc_headers.h */
- bottom_index _all_nils;
+ bottom_index * _all_nils;
bottom_index * _top_index [TOP_SZ];
+#ifdef SAVE_CALL_CHAIN
+ struct callinfo _last_stack[NFRAMES]; /* Stack at last garbage collection.*/
+ /* Useful for debugging mysterious */
+ /* object disappearances. */
+ /* In the multithreaded case, we */
+ /* currently only save the calling */
+ /* stack. */
+#endif
};
extern GC_FAR struct _GC_arrays GC_arrays;
@@ -738,11 +798,7 @@ extern GC_FAR struct _GC_arrays GC_arrays;
# define GC_sobjfreelist GC_arrays._sobjfreelist
# define GC_valid_offsets GC_arrays._valid_offsets
# define GC_modws_valid_offsets GC_arrays._modws_valid_offsets
-# define GC_reclaim_list GC_arrays._reclaim_list
-# define GC_areclaim_list GC_arrays._areclaim_list
-# define GC_ureclaim_list GC_arrays._ureclaim_list
# ifdef STUBBORN_ALLOC
-# define GC_sreclaim_list GC_arrays._sreclaim_list
# define GC_changed_pages GC_arrays._changed_pages
# define GC_prev_changed_pages GC_arrays._prev_changed_pages
# endif
@@ -756,6 +812,7 @@ extern GC_FAR struct _GC_arrays GC_arrays;
# define GC_heapsize GC_arrays._heapsize
# define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc
# define GC_heap_sects GC_arrays._heap_sects
+# define GC_last_stack GC_arrays._last_stack
# ifdef MSWIN32
# define GC_heap_bases GC_arrays._heap_bases
# endif
@@ -1030,7 +1087,7 @@ bool GC_collect_or_expand(/* needed_blocks */);
/* blocks available. Should be called */
/* until it fails by returning FALSE. */
void GC_init(); /* Initialize collector. */
-void GC_collect_a_little(/* n */);
+void GC_collect_a_little_inner(/* int n */);
/* Do n units worth of garbage */
/* collection work, if appropriate. */
/* A unit is an amount appropriate for */
@@ -1050,7 +1107,7 @@ ptr_t GC_generic_malloc_words_small(/*words, kind*/);
/* As above, but size in units of words */
/* Bypasses MERGE_SIZES. Assumes */
/* words <= MAXOBJSZ. */
-ptr_t GC_malloc_ignore_off_page_inner(/* bytes */);
+ptr_t GC_generic_malloc_inner_ignore_off_page(/* bytes, kind */);
/* Allocate an object, where */
/* the client guarantees that there */
/* will always be a pointer to the */
diff --git a/headers.c b/headers.c
index 2efa27a8..696362d9 100644
--- a/headers.c
+++ b/headers.c
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:08 pm PDT */
+/* Boehm, June 8, 1994 12:27 pm PDT */
/*
* This implements:
@@ -102,9 +102,11 @@ hdr * hhdr;
void GC_init_headers()
{
register int i;
-
+
+ GC_all_nils = (bottom_index *)GC_scratch_alloc((word)sizeof(bottom_index));
+ BZERO(GC_all_nils, sizeof(bottom_index));
for (i = 0; i < TOP_SZ; i++) {
- GC_top_index[i] = &GC_all_nils;
+ GC_top_index[i] = GC_all_nils;
}
}
@@ -123,7 +125,7 @@ register word addr;
register bottom_index * old;
old = p = GC_top_index[i];
- while(p != &GC_all_nils) {
+ while(p != GC_all_nils) {
if (p -> key == hi) return(TRUE);
p = p -> hash_link;
}
@@ -133,7 +135,7 @@ register word addr;
r -> hash_link = old;
GC_top_index[i] = r;
# else
- if (GC_top_index[hi] != &GC_all_nils) return(TRUE);
+ if (GC_top_index[hi] != GC_all_nils) return(TRUE);
r = (bottom_index*)GC_scratch_alloc((word)(sizeof (bottom_index)));
if (r == 0) return(FALSE);
GC_top_index[hi] = r;
@@ -242,7 +244,7 @@ struct hblk * h;
register word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
GET_BI(h, bi);
- if (bi == &GC_all_nils) {
+ if (bi == GC_all_nils) {
register word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
bi = GC_all_bottom_indices;
while (bi != 0 && bi -> key < hi) bi = bi -> asc_link;
diff --git a/mach_dep.c b/mach_dep.c
index cd441f97..4cbf54ab 100644
--- a/mach_dep.c
+++ b/mach_dep.c
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 1:58 pm PDT */
+/* Boehm, July 25, 1994 3:39 pm PDT */
# include "gc_priv.h"
# include <stdio.h>
# include <setjmp.h>
@@ -19,6 +19,9 @@
# define _setjmp(b) setjmp(b)
# define _longjmp(b,v) longjmp(b,v)
# endif
+# ifdef AMIGA
+# include <dos.h>
+# endif
/* Routine to mark from registers that are preserved by the C compiler. */
@@ -27,22 +30,7 @@
/* on your architecture. Run the test_setjmp program to see whether */
/* there is any chance it will work. */
-#ifdef AMIGA
-__asm GC_push_regs(
- register __a2 word a2,
- register __a3 word a3,
- register __a4 word a4,
- register __a5 word a5,
- register __a6 word a6,
- register __d2 const word d2,
- register __d3 const word d3,
- register __d4 const word d4,
- register __d5 const word d5,
- register __d6 const word d6,
- register __d7 const word d7)
-#else
- void GC_push_regs()
-#endif
+void GC_push_regs()
{
# ifdef RT
register long TMP_SP; /* must be bound to r11 */
@@ -107,20 +95,41 @@ __asm GC_push_regs(
/* AMIGA - could be replaced by generic code */
/* SAS/C optimizer mangles this so compile with "noopt" */
/* a0, a1, d0 and d1 are caller save */
- GC_push_one(a2);
- GC_push_one(a3);
- GC_push_one(a4);
- GC_push_one(a5);
- GC_push_one(a6);
+ GC_push_one(getreg(REG_A2));
+ GC_push_one(getreg(REG_A3));
+ GC_push_one(getreg(REG_A4));
+ GC_push_one(getreg(REG_A5));
+ GC_push_one(getreg(REG_A6));
/* Skip stack pointer */
- GC_push_one(d2);
- GC_push_one(d3);
- GC_push_one(d4);
- GC_push_one(d5);
- GC_push_one(d6);
- GC_push_one(d7);
+ GC_push_one(getreg(REG_D2));
+ GC_push_one(getreg(REG_D3));
+ GC_push_one(getreg(REG_D4));
+ GC_push_one(getreg(REG_D5));
+ GC_push_one(getreg(REG_D6));
+ GC_push_one(getreg(REG_D7));
# endif
+# if defined(M68K) && defined(MACOS)
+# define PushMacReg(reg) \
+ move.l reg,(sp) \
+ jsr GC_push_one
+ asm {
+ sub.w #4,sp ; reserve space for one parameter.
+ PushMacReg(a2);
+ PushMacReg(a3);
+ PushMacReg(a4);
+ ; skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
+ PushMacReg(d2);
+ PushMacReg(d3);
+ PushMacReg(d4);
+ PushMacReg(d5);
+ PushMacReg(d6);
+ PushMacReg(d7);
+ add.w #4,sp ; fix stack.
+ }
+# undef PushMacReg
+# endif /* Macintosh */
+
# if defined(I386) &&!defined(OS2) &&!defined(SUNOS5) &&!defined(MSWIN32)
/* I386 code, generic code does not appear to work */
/* It does appear to work under OS2, and asms dont */
diff --git a/makefile.depend b/makefile.depend
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/makefile.depend
diff --git a/malloc.c b/malloc.c
index 770826eb..dcf386af 100644
--- a/malloc.c
+++ b/malloc.c
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:03 pm PDT */
+/* Boehm, July 13, 1994 12:32 pm PDT */
#include <stdio.h>
#include "gc_priv.h"
@@ -34,13 +34,14 @@ register ptr_t op;
register ptr_t *opp;
if( SMALL_OBJ(lb) ) {
+ register struct obj_kind * kind = GC_obj_kinds + k;
# ifdef MERGE_SIZES
lw = GC_size_map[lb];
# else
- lw = ROUNDED_UP_WORDS(lb);
+ lw = ALIGNED_WORDS(lb);
if (lw == 0) lw = 1;
# endif
- opp = &(GC_obj_kinds[k].ok_freelist[lw]);
+ opp = &(kind -> ok_freelist[lw]);
if( (op = *opp) == 0 ) {
# ifdef MERGE_SIZES
if (GC_size_map[lb] == 0) {
@@ -54,6 +55,14 @@ register ptr_t *opp;
return(GC_generic_malloc_inner(lb, k));
}
# endif
+ if (kind -> ok_reclaim_list == 0) {
+ /* Allocate reclaim list */
+ struct hblk ** result = (struct hblk **)
+ GC_scratch_alloc((MAXOBJSZ+1) * sizeof(struct hblk *));
+ if (result == 0) goto out;
+ BZERO(result, (MAXOBJSZ+1)*sizeof(struct hblk *));
+ kind -> ok_reclaim_list = result;
+ }
op = GC_allocobj(lw, k);
if (op == 0) goto out;
}
@@ -73,7 +82,8 @@ register ptr_t *opp;
if (!GC_is_initialized) GC_init_inner();
/* Do our share of marking work */
- if(GC_incremental && !GC_dont_gc) GC_collect_a_little((int)n_blocks);
+ if(GC_incremental && !GC_dont_gc)
+ GC_collect_a_little_inner((int)n_blocks);
lw = ROUNDED_UP_WORDS(lb);
while ((h = GC_allochblk(lw, k, 0)) == 0
&& GC_collect_or_expand(n_blocks));
@@ -93,8 +103,9 @@ out:
/* Allocate a composite object of size n bytes. The caller guarantees */
/* that pointers past the first page are not relevant. Caller holds */
/* allocation lock. */
-ptr_t GC_malloc_ignore_off_page_inner(lb)
+ptr_t GC_generic_malloc_inner_ignore_off_page(lb, k)
register size_t lb;
+register int k;
{
# ifdef ALL_INTERIOR_POINTERS
register struct hblk * h;
@@ -103,13 +114,14 @@ register size_t lb;
register ptr_t op;
if (lb <= HBLKSIZE)
- return(GC_generic_malloc_inner((word)lb, NORMAL));
+ return(GC_generic_malloc_inner((word)lb, k));
n_blocks = divHBLKSZ(ADD_SLOP(lb) + HDR_BYTES + HBLKSIZE-1);
if (!GC_is_initialized) GC_init_inner();
/* Do our share of marking work */
- if(GC_incremental && !GC_dont_gc) GC_collect_a_little((int)n_blocks);
+ if(GC_incremental && !GC_dont_gc)
+ GC_collect_a_little_inner((int)n_blocks);
lw = ROUNDED_UP_WORDS(lb);
- while ((h = GC_allochblk(lw, NORMAL, IGNORE_OFF_PAGE)) == 0
+ while ((h = GC_allochblk(lw, k, IGNORE_OFF_PAGE)) == 0
&& GC_collect_or_expand(n_blocks));
if (h == 0) {
op = 0;
@@ -120,29 +132,46 @@ register size_t lb;
GC_words_allocd += lw;
return((ptr_t)op);
# else
- return(GC_generic_malloc_inner((word)lb, NORMAL));
+ return(GC_generic_malloc_inner((word)lb, k));
# endif
}
-# if defined(__STDC__) || defined(__cplusplus)
- void * GC_malloc_ignore_off_page(size_t lb)
-# else
- char * GC_malloc_ignore_off_page(lb)
- register size_t lb;
-# endif
+ptr_t GC_generic_malloc_ignore_off_page(lb, k)
+register size_t lb;
+register int k;
{
- register extern_ptr_t result;
+ register ptr_t result;
DCL_LOCK_STATE;
GC_invoke_finalizers();
DISABLE_SIGNALS();
LOCK();
- result = GC_malloc_ignore_off_page_inner(lb);
+ result = GC_generic_malloc_inner_ignore_off_page(lb,k);
UNLOCK();
ENABLE_SIGNALS();
return(result);
}
+# if defined(__STDC__) || defined(__cplusplus)
+ void * GC_malloc_ignore_off_page(size_t lb)
+# else
+ char * GC_malloc_ignore_off_page(lb)
+ register size_t lb;
+# endif
+{
+ return((extern_ptr_t)GC_generic_malloc_ignore_off_page(lb, NORMAL));
+}
+
+# if defined(__STDC__) || defined(__cplusplus)
+ void * GC_malloc_atomic_ignore_off_page(size_t lb)
+# else
+ char * GC_malloc_atomic_ignore_off_page(lb)
+ register size_t lb;
+# endif
+{
+ return((extern_ptr_t)GC_generic_malloc_ignore_off_page(lb, PTRFREE));
+}
+
ptr_t GC_generic_malloc(lb, k)
register word lb;
register int k;
@@ -218,7 +247,7 @@ DCL_LOCK_STATE;
obj_link(op) = 0;
return(op);
}
- lw = ROUNDED_UP_WORDS(lb);
+ lw = ALIGNED_WORDS(lb);
GC_invoke_finalizers();
DISABLE_SIGNALS();
LOCK();
@@ -280,7 +309,7 @@ DCL_LOCK_STATE;
# ifdef MERGE_SIZES
lw = GC_size_map[lb];
# else
- lw = ROUNDED_UP_WORDS(lb);
+ lw = ALIGNED_WORDS(lb);
# endif
opp = &(GC_aobjfreelist[lw]);
FASTLOCK();
@@ -315,7 +344,7 @@ DCL_LOCK_STATE;
# ifdef MERGE_SIZES
lw = GC_size_map[lb];
# else
- lw = ROUNDED_UP_WORDS(lb);
+ lw = ALIGNED_WORDS(lb);
# endif
opp = &(GC_objfreelist[lw]);
FASTLOCK();
@@ -355,7 +384,7 @@ DCL_LOCK_STATE;
# endif
lw = GC_size_map[lb];
# else
- lw = ROUNDED_UP_WORDS(lb);
+ lw = ALIGNED_WORDS(lb);
# endif
opp = &(GC_uobjfreelist[lw]);
FASTLOCK();
diff --git a/mark.c b/mark.c
index b73ff0e4..a3ed7d30 100644
--- a/mark.c
+++ b/mark.c
@@ -31,9 +31,9 @@ word GC_n_mark_procs = 0;
/* GC_init is called. */
/* It's done here, since we need to deal with mark descriptors. */
struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
-/* PTRFREE */ { &GC_aobjfreelist[0], &GC_areclaim_list[0],
+/* PTRFREE */ { &GC_aobjfreelist[0], 0 /* filled in dynamically */,
0 | DS_LENGTH, FALSE, FALSE },
-/* NORMAL */ { &GC_objfreelist[0], &GC_reclaim_list[0],
+/* NORMAL */ { &GC_objfreelist[0], 0,
# ifdef ADD_BYTE_AT_END
(word)(WORDS_TO_BYTES(-1)) | DS_LENGTH,
# else
@@ -41,10 +41,10 @@ struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
# endif
TRUE /* add length to descr */, TRUE },
/* UNCOLLECTABLE */
- { &GC_uobjfreelist[0], &GC_ureclaim_list[0],
+ { &GC_uobjfreelist[0], 0,
0 | DS_LENGTH, TRUE /* add length to descr */, TRUE },
# ifdef STUBBORN_ALLOC
-/*STUBBORN*/ { &GC_sobjfreelist[0], &GC_sreclaim_list[0],
+/*STUBBORN*/ { &GC_sobjfreelist[0], 0,
0 | DS_LENGTH, TRUE /* add length to descr */, TRUE },
# endif
};
@@ -722,6 +722,51 @@ register bool interior_ptrs;
}
}
+# ifdef TRACE_BUF
+
+# define TRACE_ENTRIES 1000
+
+struct trace_entry {
+ char * kind;
+ word gc_no;
+ word words_allocd;
+ word arg1;
+ word arg2;
+} GC_trace_buf[TRACE_ENTRIES];
+
+int GC_trace_buf_ptr = 0;
+
+void GC_add_trace_entry(char *kind, word arg1, word arg2)
+{
+ GC_trace_buf[GC_trace_buf_ptr].kind = kind;
+ GC_trace_buf[GC_trace_buf_ptr].gc_no = GC_gc_no;
+ GC_trace_buf[GC_trace_buf_ptr].words_allocd = GC_words_allocd;
+ GC_trace_buf[GC_trace_buf_ptr].arg1 = arg1 ^ 0x80000000;
+ GC_trace_buf[GC_trace_buf_ptr].arg2 = arg2 ^ 0x80000000;
+ GC_trace_buf_ptr++;
+ if (GC_trace_buf_ptr >= TRACE_ENTRIES) GC_trace_buf_ptr = 0;
+}
+
+void GC_print_trace(word gc_no, bool lock)
+{
+ int i;
+ struct trace_entry *p;
+
+ if (lock) LOCK();
+ for (i = GC_trace_buf_ptr-1; i != GC_trace_buf_ptr; i--) {
+ if (i < 0) i = TRACE_ENTRIES-1;
+ p = GC_trace_buf + i;
+ if (p -> gc_no < gc_no || p -> kind == 0) return;
+ printf("Trace:%s (gc:%d,words:%d) 0x%X, 0x%X\n",
+ p -> kind, p -> gc_no, p -> words_allocd,
+ (p -> arg1) ^ 0x80000000, (p -> arg2) ^ 0x80000000);
+ }
+ printf("Trace incomplete\n");
+ if (lock) UNLOCK();
+}
+
+# endif /* TRACE_BUF */
+
/*
* A version of GC_push_all that treats all interior pointers as valid
*/
@@ -731,6 +776,9 @@ ptr_t top;
{
# ifdef ALL_INTERIOR_POINTERS
GC_push_all(bottom, top);
+# ifdef TRACE_BUF
+ GC_add_trace_entry("GC_push_all_stack", bottom, top);
+# endif
# else
word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
diff --git a/mark_rts.c b/mark_rts.c
index 376746f1..17210313 100644
--- a/mark_rts.c
+++ b/mark_rts.c
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 1:58 pm PDT */
+/* Boehm, July 4, 1994 10:46 am PDT */
# include <stdio.h>
# include "gc_priv.h"
@@ -210,7 +210,7 @@ char * b; char * e;
n_root_sets++;
}
-void GC_clear_roots()
+void GC_clear_roots(NO_PARAMS)
{
DCL_LOCK_STATE;
@@ -222,14 +222,12 @@ void GC_clear_roots()
ENABLE_SIGNALS();
}
-# ifndef THREADS
ptr_t GC_approx_sp()
{
word dummy;
return((ptr_t)(&dummy));
}
-# endif
/*
* Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional
diff --git a/misc.c b/misc.c
index f4b5d9ca..5a359150 100644
--- a/misc.c
+++ b/misc.c
@@ -11,15 +11,15 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:04 pm PDT */
+/* Boehm, July 11, 1994 4:41 pm PDT */
-#define DEBUG /* Some run-time consistency checks */
-#undef DEBUG
-#define VERBOSE
-#undef VERBOSE
#include <stdio.h>
#include <signal.h>
+#ifdef SOLARIS_THREADS
+# include <sys/syscall.h>
+#endif
+
#define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */
#include "gc_priv.h"
@@ -329,7 +329,7 @@ ptr_t arg;
}
}
-size_t GC_get_heap_size()
+size_t GC_get_heap_size(NO_PARAMS)
{
return ((size_t) GC_heapsize);
}
@@ -464,7 +464,7 @@ void GC_init_inner()
# endif
}
-void GC_enable_incremental()
+void GC_enable_incremental(NO_PARAMS)
{
DCL_LOCK_STATE;
@@ -527,6 +527,12 @@ out:
}
#endif
+#ifdef SOLARIS_THREADS
+# define WRITE(f, buf, len) syscall(SYS_write, (f), (buf), (len))
+#else
+# define WRITE(f, buf, len) write((f), (buf), (len))
+#endif
+
/* A version of printf that is unlikely to call malloc, and is thus safer */
/* to call from the collector in case malloc has been bound to GC_malloc. */
/* Assumes that no more than 1023 characters are written at once. */
@@ -550,7 +556,7 @@ long a, b, c, d, e, f;
ABORT("write to stdout failed");
fflush(GC_stdout);
# else
- if (write(1, buf, strlen(buf)) < 0) ABORT("write to stdout failed");
+ if (WRITE(1, buf, strlen(buf)) < 0) ABORT("write to stdout failed");
# endif
}
@@ -570,7 +576,7 @@ long a, b, c, d, e, f;
ABORT("write to stderr failed");
fflush(GC_stderr);
# else
- if (write(2, buf, strlen(buf)) < 0) ABORT("write to stderr failed");
+ if (WRITE(2, buf, strlen(buf)) < 0) ABORT("write to stderr failed");
# endif
}
@@ -584,7 +590,7 @@ char *s;
ABORT("write to stderr failed");
fflush(GC_stderr);
# else
- if (write(2, s, strlen(s)) < 0) ABORT("write to stderr failed");
+ if (WRITE(2, s, strlen(s)) < 0) ABORT("write to stderr failed");
# endif
}
diff --git a/os_dep.c b/os_dep.c
index 89932bd8..4e7dbdbf 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -10,11 +10,12 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:10 pm PDT */
-# if !defined(OS2) && !defined(PCR) && !defined(AMIGA)
+/* Boehm, July 28, 1994 11:11 am PDT */
+
+# include "gc_priv.h"
+# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)
# include <sys/types.h>
# endif
-# include "gc_priv.h"
# include <stdio.h>
# include <signal.h>
@@ -38,6 +39,10 @@
# include <windows.h>
#endif
+#ifdef MACOS
+# include <Processes.h>
+#endif
+
#ifdef IRIX5
# include <sys/uio.h>
#endif
@@ -108,13 +113,6 @@ struct o32_obj {
# else /* IBM's compiler */
-# define INCL_DOSEXCEPTIONS
-# define INCL_DOSPROCESS
-# define INCL_DOSERRORS
-# define INCL_DOSMODULEMGR
-# define INCL_DOSMEMMGR
-# include <os2.h>
-
/* A kludge to get around what appears to be a header file bug */
# ifndef WORD
# define WORD unsigned short
@@ -129,6 +127,14 @@ struct o32_obj {
# endif /* __IBMC__ */
+# define INCL_DOSEXCEPTIONS
+# define INCL_DOSPROCESS
+# define INCL_DOSERRORS
+# define INCL_DOSMODULEMGR
+# define INCL_DOSMEMMGR
+# include <os2.h>
+
+
/* Disable and enable signals during nontrivial allocations */
void GC_disable_signals(void)
@@ -150,7 +156,7 @@ void GC_enable_signals(void)
# else
-# if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32)
+# if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) && !defined(MACOS)
# ifdef sigmask
/* Use the traditional BSD interface */
@@ -677,18 +683,41 @@ void GC_register_data_segments()
# else
+# if defined(SUNOS5) || defined(AUX)
+char * GC_SysVGetDataStart(int max_page_size)
+{
+ extern int etext;
+ word text_end = ((word)(&etext) + sizeof(word) - 1) & ~(sizeof(word) - 1);
+ /* etext rounded to word boundary */
+ word next_page = ((text_end + (word)max_page_size - 1)
+ & ~((word)max_page_size - 1));
+ word page_offset = (text_end & ((word)max_page_size - 1));
+
+ return((char *)(next_page + page_offset));
+}
+# endif
+
void GC_register_data_segments()
{
-# ifndef NEXT
+# if !defined(NEXT) && !defined(MACOS)
extern int end;
# endif
-# if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT)
+# if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS)
GC_add_roots_inner(DATASTART, (char *)(&end));
# endif
# if !defined(PCR) && defined(NEXT)
GC_add_roots_inner(DATASTART, (char *) get_end());
# endif
+# if defined(MACOS)
+ {
+ extern void* GC_MacGetDataStart(void);
+ /* globals begin above stack and end at a5. */
+ GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
+ (ptr_t)LMGetCurrentA5());
+ }
+# endif
+
/* Dynamic libraries are added at every collection, since they may */
/* change. */
}
@@ -701,7 +730,8 @@ void GC_register_data_segments()
* Auxiliary routines for obtaining memory from OS.
*/
-# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32)
+# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
+ && !defined(MSWIN32) && !defined(MACOS)
extern caddr_t sbrk();
# ifdef __STDC__
@@ -757,7 +787,7 @@ word bytes;
# endif
-# ifdef __OS2__
+# ifdef OS2
void * os2_alloc(size_t bytes)
{
@@ -1384,7 +1414,8 @@ word n;
#include <sys/stat.h>
#include <fcntl.h>
-#define BUFSZ 20000
+#define INITIAL_BUF_SZ 4096
+word GC_proc_buf_size = INITIAL_BUF_SZ;
char *GC_proc_buf;
page_hash_table GC_written_pages = { 0 }; /* Pages ever dirtied */
@@ -1438,11 +1469,11 @@ void GC_dirty_init()
if (fd < 0) {
ABORT("/proc open failed");
}
- GC_proc_fd = ioctl(fd, PIOCOPENPD, 0);
+ GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
if (GC_proc_fd < 0) {
ABORT("/proc ioctl failed");
}
- GC_proc_buf = GC_scratch_alloc(BUFSZ);
+ GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
# ifdef SOLARIS_THREADS
GC_fresh_pages = (struct hblk **)
GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));
@@ -1461,6 +1492,13 @@ struct hblk *h;
{
}
+#ifdef SOLARIS_THREADS
+ int GC_read_from_fixed_lwp(int fd, char *buf, int nbytes);
+# define READ GC_read_from_fixed_lwp
+#else
+# define READ read
+#endif
+
void GC_read_dirty()
{
unsigned long ps, np;
@@ -1470,12 +1508,36 @@ void GC_read_dirty()
char * bufp;
ptr_t current_addr, limit;
int i;
+int dummy;
BZERO(GC_grungy_pages, (sizeof GC_grungy_pages));
bufp = GC_proc_buf;
- if (read(GC_proc_fd, bufp, BUFSZ) <= 0) {
- ABORT("/proc read failed: BUFSZ too small?\n");
+ if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
+# ifdef PRINTSTATS
+ GC_printf1("/proc read failed: GC_proc_buf_size = %lu\n",
+ GC_proc_buf_size);
+# endif
+ {
+ /* Retry with larger buffer. */
+ word new_size = 2 * GC_proc_buf_size;
+ char * new_buf = GC_scratch_alloc(new_size);
+
+ if (new_buf != 0) {
+ GC_proc_buf = bufp = new_buf;
+ GC_proc_buf_size = new_size;
+ }
+ if (syscall(SYS_read, GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
+ WARN("Insufficient space for /proc read\n");
+ /* Punt: */
+ memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
+# ifdef SOLARIS_THREADS
+ BZERO(GC_fresh_pages,
+ MAX_FRESH_PAGES * sizeof (struct hblk *));
+# endif
+ return;
+ }
+ }
}
/* Copy dirty bits into GC_grungy_pages */
nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
@@ -1524,6 +1586,8 @@ void GC_read_dirty()
# endif
}
+#undef READ
+
bool GC_page_was_dirty(h)
struct hblk *h;
{
@@ -1555,6 +1619,7 @@ struct hblk *h;
return(result);
}
+/* Caller holds allocation lock. */
void GC_is_fresh(h, n)
struct hblk *h;
word n;
@@ -1567,7 +1632,7 @@ word n;
if (GC_fresh_pages != 0) {
for (i = 0; i < n; i++) {
- PAGE_IS_FRESH(h + n);
+ ADD_FRESH_PAGE(h + i);
}
}
# endif
@@ -1640,6 +1705,69 @@ struct hblk *h;
# endif /* PCR_VDB */
+/*
+ * Call stack save code for debugging.
+ * Should probably be in mach_dep.c, but that requires reorganization.
+ */
+#if defined(SPARC)
+# if defined(SUNOS4)
+# include <machine/frame.h>
+# else
+# include <sys/frame.h>
+# endif
+# if NARGS > 6
+ --> We only know how to to get the first 6 arguments
+# endif
+
+/* Fill in the pc and argument information for up to NFRAMES of my */
+/* callers. Ignore my frame and my callers frame. */
+void GC_save_callers (info)
+struct callinfo info[NFRAMES];
+{
+ struct frame *frame;
+ struct frame *fp;
+ int nframes = 0;
+ word GC_save_regs_in_stack();
+
+ frame = (struct frame *) GC_save_regs_in_stack ();
+
+ for (fp = frame -> fr_savfp; fp != 0 && nframes < NFRAMES;
+ fp = fp -> fr_savfp, nframes++) {
+ register int i;
+
+ info[nframes].ci_pc = fp->fr_savpc;
+ for (i = 0; i < NARGS; i++) {
+ info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
+ }
+ }
+ if (nframes < NFRAMES) info[nframes].ci_pc = 0;
+}
+
+#endif /* SPARC */
+
+#ifdef SAVE_CALL_CHAIN
+
+void GC_print_callers (info)
+struct callinfo info[NFRAMES];
+{
+ register int i,j;
+
+ GC_err_printf0("\tCall chain at allocation:\n");
+ for (i = 0; i < NFRAMES; i++) {
+ if (info[i].ci_pc == 0) break;
+ GC_err_printf1("\t##PC##= 0x%X\n\t\targs: ", info[i].ci_pc);
+ for (j = 0; j < NARGS; j++) {
+ if (j != 0) GC_err_printf0(", ");
+ GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
+ ~(info[i].ci_arg[j]));
+ }
+ GC_err_printf0("\n");
+ }
+}
+
+#endif /* SAVE_CALL_CHAIN */
+
+
diff --git a/pc_excludes b/pc_excludes
index 6f1465fa..58639886 100644
--- a/pc_excludes
+++ b/pc_excludes
@@ -7,9 +7,6 @@ alpha_mach_dep.s
sparc_mach_dep.s
PCR-Makefile
setjmp_t.c
-SMakefile.amiga
-SCoptions.amiga
-README.amiga
callprocs
gc.man
pc_excludes
diff --git a/pcr_interface.c b/pcr_interface.c
index 0985c8f8..1c52938d 100644
--- a/pcr_interface.c
+++ b/pcr_interface.c
@@ -10,7 +10,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 1:59 pm PDT */
+/* Boehm, March 28, 1994 1:58 pm PST */
# include "gc_priv.h"
# ifdef PCR
@@ -20,7 +20,9 @@
* We wrap all of the allocator functions to avoid questions of
* compatibility between the prototyped and nonprototyped versions of the f
*/
+# include "config/PCR_StdTypes.h"
# include "mm/PCR_MM.h"
+# include <errno.h>
# define MY_MAGIC 17L
@@ -111,4 +113,30 @@ void GC_pcr_install()
{
PCR_MM_Install(&GC_Rep, &GC_old_allocator);
}
+
+PCR_ERes
+PCR_GC_Setup(void)
+{
+ return PCR_ERes_okay;
+}
+
+PCR_ERes
+PCR_GC_Run(void)
+{
+
+ if( !PCR_Base_TestPCRArg("-nogc") ) {
+ GC_quiet = ( PCR_Base_TestPCRArg("-gctrace") ? 0 : 1 );
+ GC_init();
+ if( !PCR_Base_TestPCRArg("-nogc_incremental") ) {
+ /*
+ * awful hack to test whether VD is implemented ...
+ */
+ if( PCR_VD_Start( 0, NIL, 0) != PCR_ERes_FromErr(ENOSYS) ) {
+ GC_enable_incremental();
+ }
+ }
+ }
+ return PCR_ERes_okay;
+}
+
# endif
diff --git a/reclaim.c b/reclaim.c
index 004cbf1d..2029227f 100644
--- a/reclaim.c
+++ b/reclaim.c
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:00 pm PDT */
+/* Boehm, June 13, 1994 6:22 pm PDT */
#include <stdio.h>
#include "gc_priv.h"
@@ -606,9 +606,11 @@ int abort_if_found; /* Abort if a GC_reclaimable object is found */
for (kind = 0; kind < GC_n_kinds; kind++) {
register ptr_t *fop;
register ptr_t *lim;
- register struct hblk ** hbpp;
- register struct hblk ** hlim;
-
+ register struct hblk ** rlp;
+ register struct hblk ** rlim;
+ register struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
+
+ if (rlist == 0) continue; /* This kind not used. */
if (!abort_if_found) {
lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]);
for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) {
@@ -616,10 +618,9 @@ int abort_if_found; /* Abort if a GC_reclaimable object is found */
}
} /* otherwise free list objects are marked, */
/* and its safe to leave them */
- hlim = &(GC_obj_kinds[kind].ok_reclaim_list[MAXOBJSZ+1]);
- for( hbpp = GC_obj_kinds[kind].ok_reclaim_list;
- hbpp < hlim; hbpp++ ) {
- *hbpp = 0;
+ rlim = rlist + MAXOBJSZ+1;
+ for( rlp = rlist; rlp < rlim; rlp++ ) {
+ *rlp = 0;
}
}
@@ -646,10 +647,11 @@ int kind;
register hdr * hhdr;
register struct hblk * hbp;
register struct obj_kind * ok = &(GC_obj_kinds[kind]);
- struct hblk ** rlh = &(ok -> ok_reclaim_list[sz]);
+ struct hblk ** rlh = ok -> ok_reclaim_list;
ptr_t *flh = &(ok -> ok_freelist[sz]);
-
+ if (rlh == 0) return; /* No blocks of this kind. */
+ rlh += sz;
while ((hbp = *rlh) != 0) {
hhdr = HDR(hbp);
*rlh = hhdr -> hb_next;
@@ -673,6 +675,7 @@ void GC_reclaim_or_delete_all()
register hdr * hhdr;
register struct hblk * hbp;
register struct obj_kind * ok;
+ struct hblk ** rlp;
struct hblk ** rlh;
# ifdef PRINTTIMES
CLOCK_TYPE start_time;
@@ -683,8 +686,10 @@ void GC_reclaim_or_delete_all()
for (kind = 0; kind < GC_n_kinds; kind++) {
ok = &(GC_obj_kinds[kind]);
+ rlp = ok -> ok_reclaim_list;
+ if (rlp == 0) continue;
for (sz = 1; sz <= MAXOBJSZ; sz++) {
- rlh = &(ok -> ok_reclaim_list[sz]);
+ rlh = rlp + sz;
while ((hbp = *rlh) != 0) {
hhdr = HDR(hbp);
*rlh = hhdr -> hb_next;
diff --git a/setjmp_t.c b/setjmp_t.c
index 14dcd30c..13c4ffea 100644
--- a/setjmp_t.c
+++ b/setjmp_t.c
@@ -10,7 +10,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:01 pm PDT */
+/* Boehm, July 25, 1994 2:34 pm PDT */
/* Check whether setjmp actually saves registers in jmp_buf. */
/* If it doesn't, the generic mark_regs code won't work. */
@@ -59,7 +59,7 @@ getpagesize()
}
#endif
-#ifdef AMIGA
+#if defined(AMIGA) || defined(MACOS)
int
getpagesize()
{
@@ -67,7 +67,7 @@ getpagesize()
}
#endif
-#ifdef __OS2__
+#ifdef OS2
#define INCL_DOSFILEMGR
#define INCL_DOSMISC
#define INCL_DOSERRORS
diff --git a/solaris_threads.c b/solaris_threads.c
index 94f461e8..19c63b30 100644
--- a/solaris_threads.c
+++ b/solaris_threads.c
@@ -14,29 +14,283 @@
* Support code for Solaris threads. Provides functionality we wish Sun
* had provided. Relies on some information we probably shouldn't rely on.
*/
-/* Boehm, May 19, 1994 2:05 pm PDT */
+/* Boehm, July 23, 1994 11:11 am PDT */
# if defined(SOLARIS_THREADS)
# include "gc_priv.h"
# include <thread.h>
# include <synch.h>
+# include <signal.h>
+# include <fcntl.h>
# include <sys/types.h>
# include <sys/mman.h>
# include <sys/time.h>
# include <sys/resource.h>
+# include <sys/stat.h>
+# include <sys/syscall.h>
+# include <sys/procfs.h>
+# include <sys/lwp.h>
+# include <sys/reg.h>
# define _CLASSIC_XOPEN_TYPES
# include <unistd.h>
+# define MAX_LWPS 32
+
#undef thr_join
#undef thr_create
#undef thr_suspend
#undef thr_continue
-mutex_t GC_thr_lock; /* Acquired before allocation lock */
-cond_t GC_prom_join_cv; /* Broadcast whenany thread terminates */
+cond_t GC_prom_join_cv; /* Broadcast when any thread terminates */
cond_t GC_create_cv; /* Signalled when a new undetached */
/* thread starts. */
+
+
+lwpid_t GC_read_lwp; /* Lwp for reading /proc. */
+
+/* We use the allocation lock to protect thread-related data structures. */
+
+/* We stop the world using /proc primitives. This makes some */
+/* minimal assumptions about the threads implementation. */
+/* We don't play by the rules, since the rules make this */
+/* impossible (as of Solaris 2.3). Also note that as of */
+/* Solaris 2.3 the various thread and lwp suspension */
+/* primitives failed to stop threads by the time the request */
+/* is completed. */
+
+
+static sigset_t old_mask;
+# define MAX_LWPS 32
+
+/* Sleep for n milliseconds, n < 1000 */
+void GC_msec_sleep(int n)
+{
+ struct timespec ts;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000*n;
+ if (syscall(SYS_nanosleep, &ts, 0) < 0) {
+ ABORT("nanosleep failed");
+ }
+}
+/* Turn off preemption; gross but effective. */
+/* Caller has allocation lock. */
+/* Actually this is not needed under Solaris 2.3 and */
+/* 2.4, but hopefully that'll change. */
+void preempt_off()
+{
+ sigset_t set;
+
+ (void)sigfillset(&set);
+ syscall(SYS_sigprocmask, SIG_SETMASK, &set, &old_mask);
+}
+
+void preempt_on()
+{
+ syscall(SYS_sigprocmask, SIG_SETMASK, &old_mask, NULL);
+}
+
+int GC_main_proc_fd = -1;
+
+struct lwp_cache_entry {
+ lwpid_t lc_id;
+ int lc_descr; /* /proc file descriptor. */
+} GC_lwp_cache[MAX_LWPS];
+
+prgregset_t GC_lwp_registers[MAX_LWPS];
+
+/* Return a file descriptor for the /proc entry corresponding */
+/* to the given lwp. The file descriptor may be stale if the */
+/* lwp exited and a new one was forked. */
+static int open_lwp(lwpid_t id)
+{
+ int result;
+ static int next_victim = 0;
+ register int i;
+
+ for (i = 0; i < MAX_LWPS; i++) {
+ if (GC_lwp_cache[i].lc_id == id) return(GC_lwp_cache[i].lc_descr);
+ }
+ if ((result = syscall(SYS_ioctl, GC_main_proc_fd, PIOCOPENLWP, &id)) < 0) {
+ return(-1) /* exited? */;
+ }
+ if (GC_lwp_cache[next_victim].lc_id != 0)
+ (void)syscall(SYS_close, GC_lwp_cache[next_victim].lc_descr);
+ GC_lwp_cache[next_victim].lc_id = id;
+ GC_lwp_cache[next_victim].lc_descr = result;
+ next_victim++;
+ return(result);
+}
+
+static void uncache_lwp(lwpid_t id)
+{
+ register int i;
+
+ for (i = 0; i < MAX_LWPS; i++) {
+ if (GC_lwp_cache[i].lc_id == id) {
+ (void)syscall(SYS_close, GC_lwp_cache[id].lc_descr);
+ GC_lwp_cache[i].lc_id = 0;
+ break;
+ }
+ }
+}
+
+lwpid_t GC_current_ids[MAX_LWPS + 1]; /* Sequence of current lwp ids */
+
+/* Stop all lwps in process. Assumes preemption is off. */
+/* Caller has allocation lock (and any other locks he may */
+/* need). */
+static void stop_all_lwps()
+{
+ int lwp_fd;
+ char buf[30];
+ prstatus_t status;
+ lwpid_t last_ids[MAX_LWPS + 1];
+ register int i;
+ bool changed;
+ lwpid_t me = _lwp_self();
+
+ if (GC_main_proc_fd == -1) {
+ sprintf(buf, "/proc/%d", getpid());
+ GC_main_proc_fd = syscall(SYS_open, buf, O_RDONLY);
+ if (GC_main_proc_fd < 0) {
+ ABORT("/proc open failed");
+ }
+ }
+ if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0)
+ ABORT("Main PIOCSTATUS failed");
+ if (status.pr_nlwp < 1 || status.pr_nlwp > MAX_LWPS) {
+ ABORT("Too many lwps");
+ /* Only a heuristic. There seems to be no way to do this right, */
+ /* since there can be intervening forks. */
+ }
+ BZERO(GC_lwp_registers, sizeof GC_lwp_registers);
+ for (i = 0; i <= MAX_LWPS; i++) last_ids[i] = 0;
+ for (;;) {
+ if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCLWPIDS, GC_current_ids) < 0) {
+ ABORT("PIOCLWPIDS failed");
+ }
+ changed = FALSE;
+ for (i = 0; GC_current_ids[i] != 0; i++) {
+ if (GC_current_ids[i] != last_ids[i]
+ && GC_current_ids[i] != GC_read_lwp) {
+ changed = TRUE;
+ if (GC_current_ids[i] != me) {
+ /* PIOCSTOP doesn't work without a writable */
+ /* descriptor. And that makes the process */
+ /* undebuggable. */
+ if (_lwp_suspend(GC_current_ids[i]) < 0) {
+ /* Could happen if the lwp exited */
+ uncache_lwp(GC_current_ids[i]);
+ GC_current_ids[i] = me; /* ignore */
+ }
+ }
+ }
+ if (i >= MAX_LWPS) ABORT("Too many lwps");
+ }
+ /* All lwps in GC_current_ids != me have been suspended. Note */
+ /* that _lwp_suspend is idempotent. */
+ for (i = 0; GC_current_ids[i] != 0; i++) {
+ if (GC_current_ids[i] != last_ids[i]) {
+ if (GC_current_ids[i] != me
+ && GC_current_ids[i] != GC_read_lwp) {
+ lwp_fd = open_lwp(GC_current_ids[i]);
+ /* LWP should be stopped. Empirically it sometimes */
+ /* isn't, and more frequently the PR_STOPPED flag */
+ /* is not set. Wait for PR_STOPPED. */
+ if (syscall(SYS_ioctl, lwp_fd,
+ PIOCSTATUS, &status) < 0) {
+ /* Possible if the descriptor was stale, or */
+ /* we encountered the 2.3 _lwp_suspend bug. */
+ uncache_lwp(GC_current_ids[i]);
+ GC_current_ids[i] = me; /* handle next time. */
+ } else {
+ while (!(status.pr_flags & PR_STOPPED)) {
+ GC_msec_sleep(1);
+ if (syscall(SYS_ioctl, lwp_fd,
+ PIOCSTATUS, &status) < 0) {
+ ABORT("Repeated PIOCSTATUS failed");
+ }
+ if (status.pr_flags & PR_STOPPED) break;
+
+ GC_msec_sleep(20);
+ if (syscall(SYS_ioctl, lwp_fd,
+ PIOCSTATUS, &status) < 0) {
+ ABORT("Repeated PIOCSTATUS failed");
+ }
+ }
+ if (status.pr_who != GC_current_ids[i]) {
+ ABORT("Wrong lwp");
+ }
+ /* Save registers where collector can */
+ /* find them. */
+ BCOPY(status.pr_reg, GC_lwp_registers[i],
+ sizeof (prgregset_t));
+ }
+ }
+ }
+ }
+ if (!changed) break;
+ for (i = 0; i <= MAX_LWPS; i++) last_ids[i] = GC_current_ids[i];
+ }
+}
+
+/* Restart all lwps in process. Assumes preemption is off. */
+static void restart_all_lwps()
+{
+ int lwp_fd;
+ register int i;
+ bool changed;
+ lwpid_t me = _lwp_self();
+# define PARANOID
+
+ for (i = 0; GC_current_ids[i] != 0; i++) {
+# ifdef PARANOID
+ if (GC_current_ids[i] != me && GC_current_ids[i] != GC_read_lwp) {
+ int lwp_fd = open_lwp(GC_current_ids[i]);
+ prstatus_t status;
+ gwindows_t windows;
+
+ if (lwp_fd < 0) ABORT("open_lwp failed");
+ if (syscall(SYS_ioctl, lwp_fd,
+ PIOCSTATUS, &status) < 0) {
+ ABORT("PIOCSTATUS failed in restart_all_lwps");
+ }
+ if (memcmp(status.pr_reg, GC_lwp_registers[i],
+ sizeof (prgregset_t)) != 0) {
+ ABORT("Register contents changed");
+ }
+ if (!status.pr_flags & PR_STOPPED) {
+ ABORT("lwp no longer stopped");
+ }
+ if (syscall(SYS_ioctl, lwp_fd,
+ PIOCGWIN, &windows) < 0) {
+ ABORT("PIOCSTATUS failed in restart_all_lwps");
+ }
+ if (windows.wbcnt > 0) ABORT("unsaved register windows");
+ }
+# endif /* PARANOID */
+ if (GC_current_ids[i] == me) continue;
+ if (_lwp_continue(GC_current_ids[i]) < 0) {
+ ABORT("Failed to restart lwp");
+ }
+ }
+ if (i >= MAX_LWPS) ABORT("Too many lwps");
+}
+
+
+void GC_stop_world()
+{
+ preempt_off();
+ stop_all_lwps();
+}
+
+void GC_start_world()
+{
+ restart_all_lwps();
+ preempt_on();
+}
bool GC_thr_initialized = FALSE;
@@ -44,6 +298,72 @@ size_t GC_min_stack_sz;
size_t GC_page_sz;
+
+
+/* Variables for communication between GC_read_from_fixed_lwp */
+/* and GC_read_daemon. */
+struct {
+ lwp_mutex_t ml;
+ lwp_cond_t cv;
+ int fd;
+ char * buf;
+ int nbytes;
+ int result;
+ bool request_pending;
+} GC_read_params = {0};
+
+
+/* Empirically it helps to read /proc from a single lwp. Otherwise it */
+/* appears to be unreliable, at least in 2.3. (Of course, it may be */
+/* unreliable even from a single lwp ...) */
+/* We assume the caller holds the allocation lock. */
+int GC_read_from_fixed_lwp(int fd, char *buf, int nbytes)
+{
+ int result;
+
+ if (!GC_thr_initialized) GC_thr_init();
+ (void) _lwp_mutex_lock(&GC_read_params.ml);
+ if (GC_read_params.request_pending) ABORT("Concurrent read requests");
+ GC_read_params.fd = fd;
+ GC_read_params.buf = buf;
+ GC_read_params.nbytes = nbytes;
+ GC_read_params.request_pending = TRUE;
+ (void) _lwp_cond_signal(&GC_read_params.cv);
+ while (GC_read_params.request_pending) {
+ (void)_lwp_cond_wait(&GC_read_params.cv, &GC_read_params.ml);
+ }
+ result = GC_read_params.result;
+ (void) _lwp_mutex_unlock(&GC_read_params.ml);
+ return(result);
+}
+
+void * GC_read_daemon(void *arg)
+{
+ GC_read_lwp = _lwp_self();
+ (void) _lwp_mutex_lock(&GC_read_params.ml);
+ for (;;) {
+ while (!GC_read_params.request_pending) {
+ (void)_lwp_cond_wait(&GC_read_params.cv, &GC_read_params.ml);
+ }
+ GC_read_params.result = syscall(SYS_read,
+ GC_read_params.fd,
+ GC_read_params.buf,
+ GC_read_params.nbytes);
+ GC_read_params.request_pending = FALSE;
+ (void) _lwp_cond_signal(&GC_read_params.cv);
+ }
+}
+
+
+void GC_read_init()
+{
+ if (thr_create(0, 0, GC_read_daemon, 0,
+ THR_BOUND | THR_DETACHED | THR_DAEMON, 0) != 0) {
+ ABORT("Couldn't fork read daemon");
+ }
+ while (GC_read_lwp == 0) { thr_yield(); GC_msec_sleep(10); thr_yield();}
+}
+
# define N_FREE_LISTS 25
ptr_t GC_stack_free_lists[N_FREE_LISTS] = { 0 };
/* GC_stack_free_lists[i] is free list for stacks of */
@@ -52,7 +372,7 @@ ptr_t GC_stack_free_lists[N_FREE_LISTS] = { 0 };
/* Return a stack of size at least *stack_size. *stack_size is */
/* replaced by the actual stack size. */
-/* Caller holds GC_thr_lock. */
+/* Caller holds allocation lock. */
ptr_t GC_stack_alloc(size_t * stack_size)
{
register size_t requested_sz = *stack_size;
@@ -83,7 +403,7 @@ ptr_t GC_stack_alloc(size_t * stack_size)
return(result);
}
-/* Caller holds GC_thr_lock. */
+/* Caller holds allocationlock. */
void GC_stack_free(ptr_t stack, size_t size)
{
register int index = 0;
@@ -102,6 +422,7 @@ void GC_my_stack_limits();
/* Notify virtual dirty bit implementation that known empty parts of */
/* stacks do not contain useful data. */
+/* Caller holds allocation lock. */
void GC_old_stacks_are_fresh()
{
register int i;
@@ -153,8 +474,7 @@ typedef struct GC_Thread_Rep {
volatile GC_thread GC_threads[THREAD_TABLE_SZ];
/* Add a thread to GC_threads. We assume it wasn't already there. */
-/* Caller holds GC_thr_lock if there is > 1 thread. */
-/* Initial caller may hold allocation lock. */
+/* Caller holds allocation lock. */
GC_thread GC_new_thread(thread_t id)
{
int hv = ((word)id) % THREAD_TABLE_SZ;
@@ -167,7 +487,8 @@ GC_thread GC_new_thread(thread_t id)
first_thread_used = TRUE;
/* Dont acquire allocation lock, since we may already hold it. */
} else {
- result = GC_NEW(struct GC_Thread_Rep);
+ result = (struct GC_Thread_Rep *)
+ GC_generic_malloc_inner(sizeof(struct GC_Thread_Rep), NORMAL);
}
if (result == 0) return(0);
result -> id = id;
@@ -180,7 +501,7 @@ GC_thread GC_new_thread(thread_t id)
/* Delete a thread from GC_threads. We assume it is there. */
/* (The code intentionally traps if it wasn't.) */
-/* Caller holds GC_thr_lock. */
+/* Caller holds allocation lock. */
void GC_delete_thread(thread_t id)
{
int hv = ((word)id) % THREAD_TABLE_SZ;
@@ -200,7 +521,7 @@ void GC_delete_thread(thread_t id)
/* Return the GC_thread correpsonding to a given thread_t. */
/* Returns 0 if it's not there. */
-/* Caller holds GC_thr_lock. */
+/* Caller holds allocation lock. */
GC_thread GC_lookup_thread(thread_t id)
{
int hv = ((word)id) % THREAD_TABLE_SZ;
@@ -211,6 +532,7 @@ GC_thread GC_lookup_thread(thread_t id)
}
/* Notify dirty bit implementation of unused parts of my stack. */
+/* Caller holds allocation lock. */
void GC_my_stack_limits()
{
int dummy;
@@ -238,46 +560,14 @@ void GC_my_stack_limits()
}
-/* Caller holds allocation lock. */
-void GC_stop_world()
-{
- thread_t my_thread = thr_self();
- register int i;
- register GC_thread p;
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> id != my_thread && !(p -> flags & SUSPENDED)) {
- if (thr_suspend(p -> id) < 0) ABORT("thr_suspend failed");
- }
- }
- }
-}
-
-/* Caller holds allocation lock. */
-void GC_start_world()
-{
- thread_t my_thread = thr_self();
- register int i;
- register GC_thread p;
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> id != my_thread && !(p -> flags & SUSPENDED)) {
- if (thr_continue(p -> id) < 0) ABORT("thr_continue failed");
- }
- }
- }
-}
-
+extern ptr_t GC_approx_sp();
+/* We hold allocation lock. We assume the world is stopped. */
void GC_push_all_stacks()
{
- /* We assume the world is stopped. */
register int i;
register GC_thread p;
- word dummy;
- register ptr_t sp = (ptr_t) (&dummy);
+ register ptr_t sp = GC_approx_sp();
register ptr_t bottom, top;
struct rlimit rl;
@@ -286,7 +576,7 @@ void GC_push_all_stacks()
GC_push_dirty((bottom), (top), GC_page_was_ever_dirty, \
GC_push_all_stack); \
} else { \
- GC_push_all((bottom), (top)); \
+ GC_push_all_stack((bottom), (top)); \
}
if (!GC_thr_initialized) GC_thr_init();
for (i = 0; i < THREAD_TABLE_SZ; i++) {
@@ -318,47 +608,47 @@ void * GC_thr_daemon(void * dummy)
for(;;) {
start:
result = thr_join((thread_t)0, &departed, &status);
- mutex_lock(&GC_thr_lock);
+ LOCK();
if (result != 0) {
/* No more threads; wait for create. */
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (t = GC_threads[i]; t != 0; t = t -> next) {
if (!(t -> flags & (DETACHED | FINISHED))) {
- mutex_unlock(&GC_thr_lock);
+ UNLOCK();
goto start; /* Thread started just before we */
/* acquired the lock. */
}
}
}
- cond_wait(&GC_create_cv, &GC_thr_lock);
- mutex_unlock(&GC_thr_lock);
- goto start;
- }
- t = GC_lookup_thread(departed);
- if (!(t -> flags & CLIENT_OWNS_STACK)) {
- GC_stack_free(t -> stack, t -> stack_size);
- }
- if (t -> flags & DETACHED) {
- GC_delete_thread(departed);
+ cond_wait(&GC_create_cv, &GC_allocate_ml);
+ UNLOCK();
} else {
- t -> status = status;
- t -> flags |= FINISHED;
- cond_signal(&(t -> join_cv));
- cond_broadcast(&GC_prom_join_cv);
+ t = GC_lookup_thread(departed);
+ if (!(t -> flags & CLIENT_OWNS_STACK)) {
+ GC_stack_free(t -> stack, t -> stack_size);
+ }
+ if (t -> flags & DETACHED) {
+ GC_delete_thread(departed);
+ } else {
+ t -> status = status;
+ t -> flags |= FINISHED;
+ cond_signal(&(t -> join_cv));
+ cond_broadcast(&GC_prom_join_cv);
+ }
+ UNLOCK();
}
- mutex_unlock(&GC_thr_lock);
}
}
+/* We hold the allocation lock. */
GC_thr_init()
{
GC_thread t;
- /* This gets called from the first thread creation, so */
- /* mutual exclusion is not an issue. */
+
GC_thr_initialized = TRUE;
+ GC_read_init();
GC_min_stack_sz = ((thr_min_stack() + HBLKSIZE-1) & ~(HBLKSIZE - 1));
GC_page_sz = sysconf(_SC_PAGESIZE);
- mutex_init(&GC_thr_lock, USYNC_THREAD, 0);
cond_init(&GC_prom_join_cv, USYNC_THREAD, 0);
cond_init(&GC_create_cv, USYNC_THREAD, 0);
/* Add the initial thread, so we can stop it. */
@@ -375,12 +665,13 @@ GC_thr_init()
/* We acquire the allocation lock to prevent races with */
/* stopping/starting world. */
+/* This is no more correct than the underlying Solaris 2.X */
+/* implementation. Under 2.3 THIS IS BROKEN. */
int GC_thr_suspend(thread_t target_thread)
{
GC_thread t;
int result;
- mutex_lock(&GC_thr_lock);
LOCK();
result = thr_suspend(target_thread);
if (result == 0) {
@@ -389,7 +680,6 @@ int GC_thr_suspend(thread_t target_thread)
t -> flags |= SUSPENDED;
}
UNLOCK();
- mutex_unlock(&GC_thr_lock);
return(result);
}
@@ -398,7 +688,6 @@ int GC_thr_continue(thread_t target_thread)
GC_thread t;
int result;
- mutex_lock(&GC_thr_lock);
LOCK();
result = thr_continue(target_thread);
if (result == 0) {
@@ -407,7 +696,6 @@ int GC_thr_continue(thread_t target_thread)
t -> flags &= ~SUSPENDED;
}
UNLOCK();
- mutex_unlock(&GC_thr_lock);
return(result);
}
@@ -416,7 +704,7 @@ int GC_thr_join(thread_t wait_for, thread_t *departed, void **status)
register GC_thread t;
int result = 0;
- mutex_lock(&GC_thr_lock);
+ LOCK();
if (wait_for == 0) {
register int i;
register bool thread_exists;
@@ -437,7 +725,7 @@ int GC_thr_join(thread_t wait_for, thread_t *departed, void **status)
result = ESRCH;
goto out;
}
- cond_wait(&GC_prom_join_cv, &GC_thr_lock);
+ cond_wait(&GC_prom_join_cv, &GC_allocate_ml);
}
} else {
t = GC_lookup_thread(wait_for);
@@ -450,7 +738,7 @@ int GC_thr_join(thread_t wait_for, thread_t *departed, void **status)
goto out;
}
while (!(t -> flags & FINISHED)) {
- cond_wait(&(t -> join_cv), &GC_thr_lock);
+ cond_wait(&(t -> join_cv), &GC_allocate_ml);
}
}
@@ -460,7 +748,7 @@ int GC_thr_join(thread_t wait_for, thread_t *departed, void **status)
cond_destroy(&(t -> join_cv));
GC_delete_thread(t -> id);
out:
- mutex_unlock(&GC_thr_lock);
+ UNLOCK();
return(result);
}
@@ -476,13 +764,13 @@ GC_thr_create(void *stack_base, size_t stack_size,
word my_flags = 0;
void * stack = stack_base;
+ LOCK();
if (!GC_thr_initialized) GC_thr_init();
- mutex_lock(&GC_thr_lock);
if (stack == 0) {
if (stack_size == 0) stack_size = GC_min_stack_sz;
stack = (void *)GC_stack_alloc(&stack_size);
if (stack == 0) {
- mutex_unlock(&GC_thr_lock);
+ UNLOCK();
return(ENOMEM);
}
} else {
@@ -503,7 +791,7 @@ GC_thr_create(void *stack_base, size_t stack_size,
} else if (!(my_flags & CLIENT_OWNS_STACK)) {
GC_stack_free(stack, stack_size);
}
- mutex_unlock(&GC_thr_lock);
+ UNLOCK();
return(result);
}
@@ -514,3 +802,4 @@ GC_thr_create(void *stack_base, size_t stack_size,
#endif
# endif /* SOLARIS_THREADS */
+
diff --git a/stubborn.c b/stubborn.c
index e674977b..0d09de8f 100644
--- a/stubborn.c
+++ b/stubborn.c
@@ -11,7 +11,7 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, May 19, 1994 2:11 pm PDT */
+/* Boehm, July 28, 1994 10:01 am PDT */
#include "gc_priv.h"
@@ -77,7 +77,9 @@ bool GC_compact_changing_list()
{
register extern_ptr_t *p, *q;
register word count = 0;
- word old_size = GC_changing_list_limit-GC_changing_list_start+1;
+ word old_size = (char **)GC_changing_list_limit
+ - (char **)GC_changing_list_start+1;
+ /* The casts are needed as a workaround for an Amiga bug */
register word new_size = old_size;
extern_ptr_t * new_list;
@@ -198,7 +200,7 @@ DCL_LOCK_STATE;
# ifdef MERGE_SIZES
lw = GC_size_map[lb];
# else
- lw = ROUNDED_UP_WORDS(lb);
+ lw = ALIGNED_WORDS(lb);
# endif
opp = &(GC_sobjfreelist[lw]);
FASTLOCK();
diff --git a/test.c b/test.c
index 070d892e..4a88350a 100644
--- a/test.c
+++ b/test.c
@@ -8,7 +8,7 @@
* Permission is hereby granted to copy this garbage collector for any purpose,
* provided the above notices are retained on all copies.
*/
-/* Boehm, May 6, 1994 3:32 pm PDT */
+/* Boehm, July 27, 1994 9:45 am PDT */
/* An incomplete test for the garbage collector. */
/* Some more obscure entry points are not tested at all. */
@@ -64,6 +64,7 @@ typedef struct SEXPR * sexpr;
extern sexpr cons();
+# undef nil
# define nil ((sexpr) 0)
# define car(x) ((x) -> sexpr_car)
# define cdr(x) ((x) -> sexpr_cdr)
@@ -190,12 +191,12 @@ int low, up;
if ((int)(car(car(list))) != low) {
(void)GC_printf0(
"List reversal produced incorrect list - collector is broken\n");
- exit(1);
+ FAIL;
}
if (low == up) {
if (cdr(list) != nil) {
(void)GC_printf0("List too long - collector is broken\n");
- exit(1);
+ FAIL;
}
} else {
check_ints(cdr(list), low+1, up);
@@ -211,12 +212,12 @@ int low, up;
if ((int)(car(car(list))) != low) {
(void)GC_printf0(
"Uncollectable list corrupted - collector is broken\n");
- exit(1);
+ FAIL;
}
if (low == up) {
if (UNCOLLECTABLE_CDR(list) != nil) {
(void)GC_printf0("Uncollectable ist too long - collector is broken\n");
- exit(1);
+ FAIL;
}
} else {
check_uncollectable_ints(UNCOLLECTABLE_CDR(list), low+1, up);
@@ -258,13 +259,14 @@ void reverse_test()
sexpr c;
sexpr d;
sexpr e;
-# if defined(MSWIN32)
+# if defined(MSWIN32) || defined(MACOS)
/* Win32S only allows 128K stacks */
# define BIG 1000
# else
# define BIG 4500
# endif
+ A.dummy = 17;
a = ints(1, 49);
b = ints(1, 50);
c = ints(1, BIG);
@@ -278,10 +280,14 @@ void reverse_test()
# else
GC_FREE((char *)e);
# endif
+ check_ints(b,1,50);
+ check_ints(a,1,49);
for (i = 0; i < 50; i++) {
+ check_ints(b,1,50);
b = reverse(reverse(b));
}
check_ints(b,1,50);
+ check_ints(a,1,49);
for (i = 0; i < 60; i++) {
/* This maintains the invariant that a always points to a list of */
/* 49 integers. Thus this is thread safe without locks. */
@@ -301,7 +307,10 @@ void reverse_test()
d = (sexpr)((char *)d - sizeof(char *));
check_ints(c,1,BIG);
check_uncollectable_ints(d, 1, 100);
- a = b = c = 0;
+# ifndef THREADS
+ a = 0;
+# endif
+ b = c = 0;
}
/*
@@ -351,7 +360,14 @@ int dropped_something = 0;
size_t counter = 0;
# define MAX_FINALIZED 8000
-GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0};
+
+# if !defined(MACOS)
+ GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0};
+#else
+ /* Too big for THINK_C. have to allocate it dynamically. */
+ GC_word *live_indicators = 0;
+#endif
+
int live_indicators_count = 0;
tn * mktree(n)
@@ -359,6 +375,16 @@ int n;
{
tn * result = (tn *)GC_MALLOC(sizeof(tn));
+#if defined(MACOS)
+ /* get around static data limitations. */
+ if (!live_indicators)
+ live_indicators =
+ (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
+ if (!live_indicators) {
+ (void)GC_printf0("Out of memory\n");
+ exit(1);
+ }
+#endif
if (n == 0) return(0);
if (result == 0) {
(void)GC_printf0("Out of memory\n");
@@ -397,8 +423,12 @@ int n;
GC_REGISTER_FINALIZER((void_star)result, finalizer, (void_star)n,
(GC_finalization_proc *)0, (void_star *)0);
+ if (my_index >= MAX_FINALIZED) {
+ GC_printf0("live_indicators overflowed\n");
+ FAIL;
+ }
live_indicators[my_index] = 13;
- if (GC_general_register_disappearing_link(
+ if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
(void_star *)(&(live_indicators[my_index])),
(void_star)result) != 0) {
GC_printf0("GC_general_register_disappearing_link failed\n");
@@ -410,7 +440,7 @@ int n;
GC_printf0("GC_unregister_disappearing_link failed\n");
FAIL;
}
- if (GC_general_register_disappearing_link(
+ if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
(void_star *)(&(live_indicators[my_index])),
(void_star)result) != 0) {
GC_printf0("GC_general_register_disappearing_link failed 2\n");
@@ -489,22 +519,27 @@ int n;
}
}
+# if defined(THREADS) && defined(GC_DEBUG)
+# define TREE_HEIGHT 15
+# else
+# define TREE_HEIGHT 16
+# endif
void tree_test()
{
tn * root;
register int i;
- root = mktree(16);
+ root = mktree(TREE_HEIGHT);
alloc_small(5000000);
- chktree(root, 16);
+ chktree(root, TREE_HEIGHT);
if (finalized_count && ! dropped_something) {
(void)GC_printf0("Premature finalization - collector is broken\n");
FAIL;
}
dropped_something = 1;
- root = mktree(16);
- chktree(root, 16);
- for (i = 16; i >= 0; i--) {
+ root = mktree(TREE_HEIGHT);
+ chktree(root, TREE_HEIGHT);
+ for (i = TREE_HEIGHT; i >= 0; i--) {
root = mktree(i);
chktree(root, i);
}
@@ -606,7 +641,7 @@ void check_heap_stats()
if (sizeof(char *) > 4) {
max_heap_sz = 13000000;
} else {
- max_heap_sz = 10000000;
+ max_heap_sz = 11000000;
}
# ifdef GC_DEBUG
max_heap_sz *= 2;
@@ -616,6 +651,7 @@ void check_heap_stats()
# endif
/* Garbage collect repeatedly so that all inaccessible objects */
/* can be finalized. */
+ while (GC_collect_a_little()) { }
for (i = 0; i < 16; i++) {
GC_gcollect();
}
@@ -659,6 +695,24 @@ void check_heap_stats()
(void)GC_printf0("Collector appears to work\n");
}
+#if defined(MACOS)
+void SetMinimumStack(long minSize)
+{
+ long newApplLimit;
+
+ if (minSize > LMGetDefltStack())
+ {
+ newApplLimit = (long) GetApplLimit()
+ - (minSize - LMGetDefltStack());
+ SetApplLimit((Ptr) newApplLimit);
+ MaxApplZone();
+ }
+}
+
+#define cMinStackSpace (512L * 1024L)
+
+#endif
+
#if !defined(PCR) && !defined(SOLARIS_THREADS) || defined(LINT)
#ifdef MSWIN32
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
@@ -667,6 +721,13 @@ void check_heap_stats()
#endif
{
n_tests = 0;
+
+# if defined(MACOS)
+ /* Make sure we have lots and lots of stack space. */
+ SetMinimumStack(cMinStackSpace);
+ /* Cheat and let stdio initialize toolbox for us. */
+ printf("Testing GC Macintosh port.\n");
+# endif
# if defined(MPROTECT_VDB) || defined(PROC_VDB)
GC_enable_incremental();
(void) GC_printf0("Switched to incremental mode\n");
@@ -690,7 +751,7 @@ void check_heap_stats()
GC_debug_free, GC_debug_realloc, GC_generic_malloc_words_small,
GC_init, GC_make_closure, GC_debug_invoke_finalizer,
GC_page_was_ever_dirty, GC_is_fresh,
- GC_malloc_ignore_off_page);
+ GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page);
# endif
return(0);
}
@@ -728,6 +789,11 @@ void * thr_run_one_test(void * arg)
run_one_test();
return(0);
}
+
+#ifdef GC_DEBUG
+# define GC_free GC_debug_free
+#endif
+
main()
{
thread_t th1;
diff --git a/typd_mlc.c b/typd_mlc.c
index b04cbbeb..1c4bd93a 100644
--- a/typd_mlc.c
+++ b/typd_mlc.c
@@ -11,7 +11,7 @@
* modified is included with the above copyright notice.
*
*/
-/* Boehm, May 19, 1994 2:06 pm PDT */
+/* Boehm, July 13, 1994 12:34 pm PDT */
/*
@@ -343,10 +343,6 @@ ptr_t * GC_eobjfreelist;
ptr_t * GC_arobjfreelist;
-struct hblk ** GC_ereclaim_list;
-
-struct hblk ** GC_arreclaim_list;
-
mse * GC_typed_mark_proc();
mse * GC_array_mark_proc();
@@ -377,14 +373,9 @@ void GC_init_explicit_typing()
GC_generic_malloc_inner((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
if (GC_eobjfreelist == 0) ABORT("Couldn't allocate GC_eobjfreelist");
BZERO(GC_eobjfreelist, (MAXOBJSZ+1)*sizeof(ptr_t));
- GC_ereclaim_list = (struct hblk **)
- GC_generic_malloc_inner((MAXOBJSZ+1)*sizeof(struct hblk *), PTRFREE);
- if (GC_ereclaim_list == 0)
- ABORT("Couldn't allocate GC_ereclaim_list");
- BZERO(GC_ereclaim_list, (MAXOBJSZ+1)*sizeof(struct hblk *));
GC_explicit_kind = GC_n_kinds++;
GC_obj_kinds[GC_explicit_kind].ok_freelist = GC_eobjfreelist;
- GC_obj_kinds[GC_explicit_kind].ok_reclaim_list = GC_ereclaim_list;
+ GC_obj_kinds[GC_explicit_kind].ok_reclaim_list = 0;
GC_obj_kinds[GC_explicit_kind].ok_descriptor =
(((word)WORDS_TO_BYTES(-1)) | DS_PER_OBJECT);
GC_obj_kinds[GC_explicit_kind].ok_relocate_descr = TRUE;
@@ -399,11 +390,6 @@ void GC_init_explicit_typing()
GC_generic_malloc_inner((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
if (GC_arobjfreelist == 0) ABORT("Couldn't allocate GC_arobjfreelist");
BZERO(GC_arobjfreelist, (MAXOBJSZ+1)*sizeof(ptr_t));
- GC_arreclaim_list = (struct hblk **)
- GC_generic_malloc_inner((MAXOBJSZ+1)*sizeof(struct hblk *), PTRFREE);
- if (GC_arreclaim_list == 0) ABORT("Couldn't allocate GC_arreclaim_list");
- BZERO(GC_arreclaim_list, (MAXOBJSZ+1)*sizeof(struct hblk *));
- if (GC_arreclaim_list == 0) ABORT("Couldn't allocate GC_arreclaim_list");
if (GC_n_mark_procs >= MAX_MARK_PROCS)
ABORT("No slot for array mark proc");
GC_array_mark_proc_index = GC_n_mark_procs++;
@@ -411,7 +397,7 @@ void GC_init_explicit_typing()
ABORT("No kind available for array objects");
GC_array_kind = GC_n_kinds++;
GC_obj_kinds[GC_array_kind].ok_freelist = GC_arobjfreelist;
- GC_obj_kinds[GC_array_kind].ok_reclaim_list = GC_arreclaim_list;
+ GC_obj_kinds[GC_array_kind].ok_reclaim_list = 0;
GC_obj_kinds[GC_array_kind].ok_descriptor =
MAKE_PROC(GC_array_mark_proc_index, 0);;
GC_obj_kinds[GC_array_kind].ok_relocate_descr = FALSE;
@@ -662,7 +648,7 @@ DCL_LOCK_STATE;
# ifdef MERGE_SIZES
lw = GC_size_map[lb];
# else
- lw = ROUNDED_UP_WORDS(lb);
+ lw = ALIGNED_WORDS(lb);
# endif
opp = &(GC_eobjfreelist[lw]);
FASTLOCK();
@@ -723,7 +709,7 @@ DCL_LOCK_STATE;
# ifdef MERGE_SIZES
lw = GC_size_map[lb];
# else
- lw = ROUNDED_UP_WORDS(lb);
+ lw = ALIGNED_WORDS(lb);
# endif
opp = &(GC_arobjfreelist[lw]);
FASTLOCK();