]> granicus.if.org Git - gc/commitdiff
gc4.3 tarball import gc4_3
authorHans Boehm <boehm@acm.org>
Fri, 23 Dec 1994 00:00:00 +0000 (00:00 +0000)
committerIvan Maidanski <ivmai@mail.ru>
Sat, 17 May 2014 13:11:20 +0000 (17:11 +0400)
50 files changed:
EMX_MAKEFILE
MacOS.c
MacProjects.sit.hqx
Makefile
NT_MAKEFILE
OS2_MAKEFILE
README
README.debugging [new file with mode: 0644]
README.win32
alloc.c
config.h
cord/cord.h
cord/cordbscs.c
cord/cordprnt.c
cord/cordtest.c
cord/cordxtra.c
cord/de.c
cord/gc.h
dbg_mlc.c
dyn_load.c
finalize.c
gc.h
gc_c++.h [deleted file]
gc_cpp.cc [moved from gc_c++.cc with 66% similarity]
gc_cpp.h [new file with mode: 0644]
gc_mark.h
gc_priv.h
headers.c
if_mach.c
include/cord.h [new file with mode: 0644]
include/ec.h [new file with mode: 0644]
include/gc.h
include/gc_c++.h [new file with mode: 0644]
include/gc_cpp.h [new file with mode: 0644]
include/gc_inl.h [moved from gc_inl.h with 100% similarity]
include/gc_inline.h [moved from gc_inline.h with 100% similarity]
include/gc_typed.h
include/private/cord_pos.h [new file with mode: 0644]
mach_dep.c
malloc.c
mark.c
mark_rts.c
misc.c
os_dep.c
pc_excludes
ptr_chck.c [new file with mode: 0644]
setjmp_t.c
solaris_threads.c
test.c
test_cpp.cc [new file with mode: 0644]

index 7447781752a183cdb68e81588eb822e1a5ba91fd..7eed701ead5d497e43d335a1afc1d1a1c35851e2 100644 (file)
@@ -49,7 +49,7 @@ RANLIB= ar s
 srcdir = .
 VPATH = $(srcdir)
 
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o
 
 CORD_OBJS=  cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
 
diff --git a/MacOS.c b/MacOS.c
index 90c249b8f7b1cd33915da40af440c4ab09b97fdf..18d347759cbd53f77c056508dd056034693df3ec 100644 (file)
--- a/MacOS.c
+++ b/MacOS.c
@@ -6,6 +6,9 @@
        
        <Revision History>
        
+       11/22/94  pcb  StripAddress the temporary memory handle for 24-bit mode.
+       11/30/94  pcb  Tracking all memory usage so we can deallocate it all at once.
+       
        by Patrick C. Beard.
  */
 /* Boehm, July 28, 1994 10:35 am PDT */
@@ -14,6 +17,7 @@
 #include <Memory.h>
 #include <LowMem.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 // use 'CODE' resource 0 to get exact location of the beginning of global space.
@@ -38,18 +42,57 @@ void* GC_MacGetDataStart()
        return 0;
 }
 
+/* track the use of temporary memory so it can be freed all at once. */
+
+typedef struct TemporaryMemoryBlock TemporaryMemoryBlock, **TemporaryMemoryHandle;
+
+struct TemporaryMemoryBlock {
+       TemporaryMemoryHandle nextBlock;
+       char data[];
+};
+
+TemporaryMemoryHandle theTemporaryMemory = NULL;
+
+static void GC_MacFreeTemporaryMemory(void);
+
 Ptr GC_MacTemporaryNewPtr(Size size, Boolean clearMemory)
 {
+       static Boolean firstTime = true;
        OSErr result;
-       Handle tempHandle;
-       Ptr tempPtr;
-       
-       tempHandle = TempNewHandle(size, &result);
-       if (tempHandle && result == noErr) {
-               HLockHi(tempHandle);
-               tempPtr = *tempHandle;
+       TemporaryMemoryHandle tempMemBlock;
+       Ptr tempPtr = nil;
+
+       tempMemBlock = (TemporaryMemoryHandle)TempNewHandle(size + sizeof(TemporaryMemoryBlock), &result);
+       if (tempMemBlock && result == noErr) {
+               HLockHi((Handle)tempMemBlock);
+               tempPtr = (**tempMemBlock).data;
                if (clearMemory) memset(tempPtr, 0, size);
-               return tempPtr;
+               tempPtr = StripAddress(tempPtr);
+
+               // keep track of the allocated blocks.
+               (**tempMemBlock).nextBlock = theTemporaryMemory;
+               theTemporaryMemory = tempMemBlock;
+       }
+       
+       // install an exit routine to clean up the memory used at the end.
+       if (firstTime) {
+               atexit(&GC_MacFreeTemporaryMemory);
+               firstTime = false;
+       }
+       
+       return tempPtr;
+}
+
+static void GC_MacFreeTemporaryMemory()
+{
+       long totalMemoryUsed = 0;
+       TemporaryMemoryHandle tempMemBlock = theTemporaryMemory;
+       while (tempMemBlock != NULL) {
+               TemporaryMemoryHandle nextBlock = (**tempMemBlock).nextBlock;
+               totalMemoryUsed += GetHandleSize((Handle)tempMemBlock);
+               DisposeHandle((Handle)tempMemBlock);
+               tempMemBlock = nextBlock;
        }
-       return nil;
+       theTemporaryMemory = NULL;
+       fprintf(stdout, "[total memory used:  %ld bytes.]\n", totalMemoryUsed);
 }
index 85a73d7b614905b2aabeb4986737b86c1d4190f5..65fc5a1f93f5fff87d98a21b0e370568451bb6fe 100644 (file)
 (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!!:
-
-
-\0\0\0\b\0\0
-\0\9dÊ\0:\0\0\ 2\95\10NewlineDelimiter\ 1
-\99\0I\adefault\98·±\ 2\97\0\85\97\0\0\0\0\98¸\0\0\98ú\0\0
\ No newline at end of file
+:$deKBe"bEfTPBh4c,R0TG!"6594%8dP8)3#3""V-!*!%4@*6593K!!%!!"V-FNa
+KG3)!N!3@!!!J)!Y0B@03FQpUC@0dF`#3&!G[!*!$LJ(+!Si$f3#3!`-!N!q'!!!
+"B2q3"!%!U`6XdUX%l2d!N!Cc$`#3"KT'!*!+@[X0$3KRBbif1%XZZ3#3&fPF!*!
+4&J!!"lJ!N!-@rj!%68e38Ne03d-"!+X%l)@V"1bY!!!'-3!!%SJ!!!'j!!!&#Eh
+-,*i!N!Dq`b0%$L)UANhN3L9rR8XNRRb5*ZE3hhmM64*pDB+1%rh3qA4mVL`Cmbe
+D[0VhjciRj-CeKVXl1`-"32ChKH0khh,pp%+LmEZ)5KURjA*%m"FLH[$AAr6`3Tp
+m-SG(2L"kb#0-p*!!ad$4Jekik%&[N!$S35rL56a!"SXHp#*&"hT$4!pk8D)([@L
+,6DK"X%%[9S!m1FZ%kHI)GH!2SIh,Zh'$B8Ukq@m!q2KrhdiNbVN`TiAr**+FIai
+BdQ('A%mLPq0#qVQ!Z%%dmd$h4AUHD"k,Mp!U,'Y05DHQ5M(YMfSme9+jii[1iC(
+H2B6BQ+K)p2QEE8lqCSGi#!9CEF6)*1SlT9KAC%0-8a0bdTIk[@HYE8Tk[[!QiA)
+26bFF!bj6(UFLFPUEDSC2NA[rffKi(YKNl9j`3chLQ#YLV$e-MV0fM$!9b*['U%D
+)cV&bR&,Nk6N26IL@0@L(b*(4H3)$i*YCbh9`YK89EKeih!`,SeF)p`%,SjF)0e0
+Jc"@f#Q,X2EC4LMAEU`%aEV+&U5`X`cC&XAal)9"XYKdFaF5K9`U-Af4KHbc-18E
+X(D)cK(9Y)iqC$,PCC8ep(`!!$2L,QD2m[+k*jr($FmT2MjqG+f[N4BiV1GC*11@
+%%DD%V9cPjeP(q8V`!H4k5M9G18"A-Sq6!58$6KJCF$,Mj"MK%NEi%8k18m)*`h0
+bR$`r`L866MMKj$Nj2L!6IS366Sk6ii56%6mbB)56!5I(#DINQ*`F!qKG!5J!1EE
+bYkIi"P*mj$KKK%BB33`(*RJIUqra!'0$NL5CISFNDG$p2NE[N[6E4Pqjlk4Ze6#
+!RM(bFH"HreQ1I1+-l*'mL[R8$NV&B!hT8UHATJ9e%p1D-953!$FXZkleBd&e2D,
+9!h3)mPDTB2f,GBimZ8030r[8,Lf65aH-QNI1U(&D80ZC3ePNUJCDJ)&$`le*3He
+J@R@SDT!!V2P$U6[IqN931jR@JJVdY!D,JGEPPrF+DKG,AN)&4kIUbAXhTQU#fZe
+61`[VJA81IrD'S2Eie2D#5S+qi&&6*lmAe#hF9j*2%cZ)Jc2qp3&"lDeS49DMS8M
+1EamY#fSIdfV#FMVXAXrr+UMp,+mi-jXZU%(`+(8k,kKE@BD`e8LVQeIV!d%GB&S
+*")D+#M@Y)kpq++L$c&I,,Q8bQ*L"Vc1cR`[U0NDejiYDSqR4P&m5e1fdQlXGaE)
+eK10k,ANVleh`pAPe%r-e"p*&JZB#VJ-'CD(eCTrDPJ0eS5led,&h"28@hk&1kT!
+!"V-eXV0bEPSiG#[,+m"Q&ZAUe1A5+d,VED`j6q*b!KCUe2-[A9S8@RHXTN(Ak!3
+3T1()m(DKGHHUV`E+0(ep8@JGmURY0LV!4SUFP6I("A@BDbA)E+4KjGc6JRUlIpI
+R64[T@T+FPCp5`YFlr'0(DVi)DeQJe0Gh$3QY#QYLKl#T)4YK1S&4f34A&C`r2Fk
+Q'DrZp)mp#A3+DJQXV8@LQYH4LN0%,6BFUP,[mSrGe#'EB#-!9kPh-iHH+5'3!0H
+)@VlQd#lrf-qT+AM+rSYFTBibkQ(60Sj"#jF)q$Z"9HSB5d-#QU8EDEL(GFURjU"
+*Tlb06RQ[Iq`k1[@XM@S4qS1kQcNdJBaQ4kP5lf0DTf"Z%U[DKYEl+eTTbQpShF2
+53)F'61D[Tb(1($U16!fAVkGKlqUdiBhQ`E3Kcc`ZZ[)$c#%,fV1&BRd#5$V[#kd
+2XZl9k#CA(AUS-QfJ('hMGDdM[mm)kX0-Dj*J+Y6Dd2S)QhTT'ZMJ#i1B1r),hiN
+d2-SG@S$TUieee5%JU2YmDPFCk#UTBprHmmQ)S1jR$K9YNJBkD1j5"&AD[%KRm`R
+hNA$lfVEZ#Sh@2bTDfcYHRZH"LYBfMpHQTSV@GSpA@e0&DpZh'Uh3d@MlakXpp#,
+D"[,U#,f)YS1m1X1N4pY#APe0&DhY)DrZTSV@0T&A6j5,F,[)DmZk&q[E4PkpS4I
+4pT&AApJ[SQdNVri`Sp&fNYI@d0(r*K@[pSH14MY2AJ1K&p%1P0GJU#,DLI,DaQr
+FU@FITFITcC!!Y#"r'fZ6,llfXhaam1$"aE1MmMHl2k@%!bj*rP)SL&8f)p+5*(r
+aBbcV*ABT"UN9ChiiF8AZ%kB##F&%`3#8#058XNjA(-SF*#Jl6aGeLUdM5bN52!Z
+"2@BTBmAR)"P6#*['imG6iVe#Vh$*9R"@d93EaK8PD8$9JNUTk0j6,C!!SmV)eVd
+(rPZLf23[%IIe(0,S$+dPS-dXS[q,p*a06KL@D-dAh1Nd1@P9''k)plRH*qQZjI*
+PH[295ET('D$rQFL5qmC0iIm0$3KRBbj38%-ZZ3#3&f''!*!4KJ!!%'i!N!-@rj!
+%68e38Ne33d-"!+VhXBZV"1br!!!'-3!!)ZJ!!!'p!!!'LI9pFkF!N!BJc50%$L)
+UANhN3L9rV@9B`f#c2p$XpAVVCc-[`k20Y5bJ+CTHPScj`Z'!lmpp6XL0k`ahGiB
+$!AM)F3b$m"((pEEqqNmZ*DTjPDLNN5GNPE-0l@Sredh,(lT2REr3kjdHcj0cZD5
+-842'U'1i'FRf4U9HKG[Ni@2NLCQiC2+`20JT@CQQcPrmAUET#)6&4fJm&6R%+-#
+6HhJkX"#A+Bp6%6RGkB&kM%'jh2YHZRpqbIRhIkPrk-F16L+Aiel(A!&aJjMU352
+-6)bkTU468k@BpNFl2095ZH1,cZ'4[[24@6#*b5!8h@acmMFla%-Sb'SMi%0mqNi
+TeKAC%028K*cdTAl[@@ZEXLI!PSRq1A)Gq$F!TZ2'$BBTkHDr(6"Xrr-aidGQ`E2
+-8f$QkG5VX96PYa1M`VQ`A3[r5GRc`!,pedPfZXC&Hc[pA%#iD%Rr1kF8ShhLZ8N
+K)#Ek&MNb1NrJR2$0V18k10ZS+*G$Vl5mm"CQXXH#BT'f5BV"UB6H%@-@@4KVBC-
+X6'9Kbk`FqP[B24B@DQ&V,@bJ`&MlA&%+M#C'k(%,@f*T$,#`,ld6Z5'XDaYjc'6
+)c5TVk[X!N!-0q)ZCJfaN)hXl2*0l(RHbXP&Hj,JABCf%fdQBaefj*cp2rVCbI*l
+8Nakq-`E3PF`kFP`bi)54!5Fc6SjG%Nli%8k15cKKH%k1NqG(q"&1RK011(P1MJr
+)L"011$P1MK01MT2R4`D-F$,Jj$MKNQ0bFJbi#jJ#V!#%Zc+jj*MiRZ9kj$MKK"e
+K"#Pi`S%*(JJ[8)F&2##'ipL+SUM`ADiSh5r#pbcm5m#h#Eili'9FLF(ENqThX5E
+eiUZrUKFlpZ`jGDj(rAEGjq#`#liap@Y3%a&6lX8rjaAeUjpM3mSFpLp')-dc2ak
+96K!2j64#U8-eac!+P*KD-@2C4"XPe"SDXh*TcFYBVTDRcM!a[&jAkmdr4@L[4SR
+V&+K"iNF'j(X0IMN&6h1'0&2h5&c6%ME4AD)9mZ`rj%+%9G(b-[a"m*CU(T!!`&k
+2@LBaifBrmD#5+LG$QD(EYT&*f50aifVj-(cek"Q91b%"r&m,Z$V'P#9c(6`r+&f
+RBDiT@cG'E0HVj[UTG'd+A0Z0$$&'h%,@[@(V(hKiUA5G(VLfQDPd-QYADZ6hf+H
+PDc0@D-M+kECeNS39kTU9N!#Z,CKVKZJQS92e!GGPErdQA9XaekaZC*)QbBHjART
+KNh4Y3r,kGH2Ji5TjlmCd8lV1#&aEXlH!pIGrmBCdE3pFQl-k$IX#GaeiqJIT1P2
+8PBiNU4ILi1rqCTGdR6@4UqA@'SVLrr(**HNk'h20N@,bRqlec1r5G3lbkU5'NeN
+p"!pF"dHNkeaNb(&VY$*Hh3qNkcc-P4,$eUeX*GIZ9ck8VKeB9pFVT&)1cB9e26E
+mTA5GMklH@0kX06fJr,*dA3$GR(88ec-Y*jkTN!!hrYj(3Aim&Q*GddBb6kh4d0F
+h1P5Ckk,!Y5PY9"0PVRX2[50G&`F9DS8+Q@5SiZb2[ciS+l3%H6@Fh*!!PDkkALU
+m,(2Ya1EFja6l5EELHZ(ij9-bek8P'M)Q6!!K$3Hk&XKFPjAUDPZTQh9p6ZDk2("
+YpU`XU9(NMlqj@lTfL9`T$*dhFhe8ZUi)rXhQddDb3T)rrXZ!V1[+3,B-M19*K39
+`I@h0FTQVKNeXVj-c,FpbB!+$Y+P6cZ$#kGdicI"B&FMfIZX%-IXGF`U*-UrG%a@
+LHVj@SE,V2B'F!4AbU'1(aQAAe9LK*`U@-@*5[IKIKGB%FSj`(5!R[,qGbkipk,S
+rjpQ(F)0`[8aPeekNSCrN#RGT`"e)kb1M*!G6hZe1Z6D3!'d($crT@4@%VVQZ``V
+YJpA*h3UYae`2Nh5ISjZhFpd`N5Y3IMIAM8J$$!d1(EY$3a`VG-6+Q8la$JfE5Y-
+'(mh$D8-ppS$XbTZa3LlaKV2jkJ53!2$IPlPZ`Hj9kbEA+l4eBYU`dY$'UlPfrhP
+-ZQl$A"28J86GflPZakNAD)$"&cCE0l,ee@HrPc6F*bTdNL5[0pC5K3cTZL0`E5X
+D'Ce@EGrHq&QhG0f*&FTl0'PNM*Zl&1QU,2a*@D!bDR%+#`ai*[9Yh98h#)e266$
+"F(DJGk0HKhS$kKl8RDJhSZj&[3Ve@Y5V8Dp"[4leBMk,`fk"E`eJdZ8c,%bKI,k
+%'CC2Tc#(SGp+2JY#2m6r5pK8$RS4f`5!AXSQCiB%fbF`)YM%b5KQI$)Z'A&3l[J
+0AKTl5K'FlJPHAVS5m!+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+
+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`+Dm`,k,elf2kr
+fU'b+kjVX,r80VBKTN3qm4#C`SMc1l`9`kehLT,'6&X%Z$9KJIL&hM@feL1R4+0c
+jCm0qhYM2LfL1$1&N%j[P'l`!('&IU9mQL'L*61NV1p6lfG3jf9IUYaJL@L-E10R
+-YM24$I-LF01XXXTh6XlAp@X8%@f4#paX+I-6mK*b%[ECUEQNF9mMJZeL)P6f$!$
+(9,pYA"D*D)mFiHA12"I1[rAE+K%cSf2kc+fV-K'c)KYifFSfiG%,h)$Qh135P6j
+6[kX6-6YbTFq%HjEk4D%)GLmFME*RH9$G`kSm15IAEbK&c)dmi'4E0%9I,['Ml&-
+HimaFkm[rAT,`f)QQ8rfpFC8UBPj86(p[h11+k)K-kHrK(V9qJ5aLIQ3)*pIf1G[
+CY9QYVc03MUrY!l8#PP[R%[YX&pqBX,6jQ0eq*ITFV`5+bUkMBJQiC,ab46b#0kV
+#hM$UrJF!!!d0$feh,fGMG'9cG#j38%-ZZ3#3%"(-!*!3"lJ!!"TF!*!$&[q3"%e
+08&*08%0$!3#UphHTU`6Xc!!!"M%!!#X-!!!"S3!!"pd+IEMl!*!'pedM4!iL+Pj
+0j%)PIdhl9fbRBC!!DR1(JAFp3hUJ2KNcZ@(k`Z'!lmqGi)cV$(GhKJ-"1#NqKM,
+$lcRBqZZ"I96dfK5LNXCFMR,r8%Ar'-lrp9!IFkbM)YTq#&@*UN"9A8$E'HSmZbF
+dRSSFHCpb$dm(&Z)bjA(i)1k4p2q[8*,a8X2K$U)b@[phXr(IIZcJ*()jlRA-&6(
+@(LE(@6X%L4F0Lir3+Nb$TU468k@BpNG62095ZH1,cZ'4[[24L6#*q5!8h@acmMF
+la%-Sb'SME1[`p*e5V#Zb)DDT#6RT5rhHXrEST22N,"2pFq3km'm!c-L0'`a6d[r
+AJI83m*Ma)l2J@HBT#M1[&UY9HM[&U(L2V&N"4dDhXQZ0LKAhfj6praE#*$XAlL3
+X`&FF*`L)'m61'[61+F9SRhKZ8JL)LEj&MSc1%cJUI$0VZ3l10LV#N5-rhX)#l,'
+J@*K0T0JTfcYLc#),BbeXNS@T,)`ZHfkkKGeMBD%@YYE#"JU-lEAdP!,$a1$YXE!
+PPXB!#r[5@0V(4@-)kpT'(M-CFV2+Q[Sq!*!$$IMVbPPfHI+*jd#@dFkVArPjQCG
+4,MN@SI`Nr!MA@VN@B4&1q*'9i22T+G1hm&QAR$$#"i3ri@6!#5HF((pbr#JRa`N
+RcmRaFq9(MT2MK(@%NqG(MK&11(P1RT2M4jk6jq6i8fi[H8jQR($#bA%**ja`#J3
+JhK@!i5QrPG0,6Xp"K#SCF#p##5I(#4)i16cK`!6BpB!k,1",['UD#8Q5C13f5GV
+b%[+lq#f#A)0m!LSX"D5f"NfaPBbY@2DA&2M[A$KZhB%KG@,2XhXIF,cQh#Bd5EU
+lfh&Vf'I%,-8bp-b#QbbGPU4GBEK*8RFGki5HdXUem8j)i9!SNY#9M"l+TQ'UKqb
+i(NTEjQ&GY80MKKfR2cMrY8)f5'$r(M8dA3YVrEU0hXL-M*UH4L@4811aa("BrE2
+BefSqRj3C3di`AlM@`G98&baRAB1mePK#8BF6'EYFkdRAYFCaE9,MZMUFb5BcmlC
+`rGTeAH'i0QLaS@Jb8HT4`E@@GfM35#N*ihlpA)IUH+eaAG&dDk%rj2U9keV2Ddd
+UDMbUkHP5VC-IZki0R,aq4EeMS%*H30&FedE(Y6kj"'b"KLE(Y6DT@-@jF,D[cD+
+[eR$8XSXi&&aAjQXe-T@"!YI[iUjV#kmeTBp&PkEA0+qV1+pQl(!dU46"qm0e0AH
+eG$@K'-Q+kr6-Zi"h+'0RBc(65T8l0%hH'Nk$VCHQ*(IpcR9GbfZeap0DCHJ9DQh
+06dTRkbL@Qr[*HYpe[C!!6f@a0Fhl`[8&er8L2SI-6'ALdF`,Z+iA-e&cAmY0q`G
+Z#r@&)j'q-"DUf9VI1$6LZPj#VNHEEdYKq4P89(h18j+1RBSqlETHbX5+$eVk$r8
+Gb+CX)kR2ehV2$aYGeh91AeYS+NG9-c9S$)AMFp2V$GGe25G[5)fQ,@2dV''Hefp
+GecE(Y@C),4VQAEpaAGZC#$jFRl%e64mX1HFLapqMAGQ*$XHeERa85@6+jHCHHI%
+Zel@68elL)0qK,l[F$S@SeVIVpjPMrAUbj(TXj1H(h&Sh1+je"mI6qQ+(RZmLERK
+FjVLZl606QQ%E*VBpS'ZCK3U12EkE0LFH'ahATRlML+leQjSqAfqK3jIR1f3Tk8U
+(#UjGMQXM1Q4ECJQqJZXQhU%lXiBkV&R+f&mGfZbiVK+Z"r8MpUac`E@EZf+q*Jl
+S'60VUA-%&Pal1!hpHLUl6--@2KYZ'G96f#M2ciBV(0H'1`EZXShbr#UiAXNlY0G
+),%k8JZY9[0B"I@LIU@MRDfA[293V+&qZp@T1!mDNDBhr6F-e[%1(M*4QM[e0`pB
+c1dTF`p['Z4eP'p9+fdE#L#eZ'j0ZVGFkVV@dGC9hQecNVAYFeqfL9XY)PEH0A15
+G2DlVGBjV(6TNQ*@piG9(D*[KX50IUfiI6UBVYHEHG&ehRQ')RP,+$*eb'EVHiE@
+T-P[2mVSVhb&M#%[0)RP2ZUihm&SMPSP#-qGVlHA[$HJVRKc`TMKIE@%fh-K%c9'
+mB0RaqCAFUIAacAfZkfjHDpUfSQTFVEcd6'qp8YX*E0RXVCGH,(R3,pl,KBJ,Z9j
+(flXTEj,CjY11LRkVahY"rGd0F4RE,KqFNVSB9G"EZ,k5kc$Ah9b(Z,kDkakZ0h*
+p"GHEZ0l-p99FYl2G([Sk0Y1JYl(T#lfG68ESDpPFKEkFqfeJ1c2d0Ich$VEP3hH
+b[4fkME%'[CAa$EfHDq,N`DNL*pkEXBLm,h'L6MLF3"-Rd-3*0(%#6Ca!%bI3a!N
+dF3*0R%!6*p$%#64a!NfF3"-Rd-3*0(%#6Ca!%bI3a!NdF3*0R%!6*p$%#64a!Nf
+F3"-Rd-5*1L&hb1cPSfeQRP4Ib88%I4mim6hJ3pV2jhH"$qmH3!5lmK$cZmbEGbN
+JBSAI#@qPrDCk%b'LeRH%MjeX,eqHfpi9L)Jkhj-j%TECLe2(c"bThVZ)U2GYi'-
+(HlhaBpJ$T9m*MdYQpZAUTBq)"Ym&AUi[F&2Na11MZRGi0dXL'Re6hP8@jUThT5@
+LbEH%%pV6PYqK[2Xd%Fhq,h0Pk5*2a%VI"NjfXEGX2iRh6Hm@885,EmTF+Ek69+m
+[4DcbIH$%ri#2(6+lp1LFfAZV0j)L,[)pi1-'hihj@ld3%E(EGf5Zr,[rHRI-)PE
+l[H`ThZ@fL!Ym6rD8i[Y!p8CGa"VINcR5HiiAlcTIa&VINreNMKF0M16[Q6J[hY@
+r#2T+!')[A@fh-PlN%Hd%rpG*H@6`He`[YMUm5+hbL,+DILGHS)NAD1)&QRL"*Pk
+JL4GSiJ@DH)%QAU#*&fML"CTiJ5CHS)NAD1)&QRL"lXcpP(d-ZLhAGq!9k+fjfpY
+ESAIQj2YkSGIRe$8bG'p1[[Fck(A`1ihq-9ld@9kmlaf)S1mM,2%#cDiefIiBBEa
+!(d&q!ZGBq*C1i'ENZj(aICd![UN6["IraIGeT12)(b*rJB`DC&aJbDK@aQ@e[!I
+j)$*14H@Mb%mK[icm$[*(b#H4Id3pZ2i)B(i'(N*q"[P9j%q3!%mKieXj3Ec+"V'
+["A(p'l`91Bhm+2*cb+rr`iYhKbU#lPEp+hJ*SJrr-I-R,h2cZ2TP$"(d*3h%IYm
+5AU6JTp1mL$[&r,fKZ#YFqUk+L&DZqCda&6$5JrTPI)@MH6+b0j(Kr`%,+hpKYmf
+4I4Rl6!%bQ*%#%Ab"B'T+r!RrN5Af(pD0r`%K)3Y0B@03FQpUC@0dF`#3'BS"bJ+
+1!pN!N!-"!!!3EJ#3"aB!N!1'!!!"B2q3"!%!U`6XdUX%l2d!N!Cc$`#3"KR@!*!
++d@2eN!!!!!:
index 3c8772756da131e90c1655c60f96b9d363c8bbf6..5694728499d811847f14cccbba166291258e5c4e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,10 +6,11 @@
 #        some tests of collector and cords.  Does not add cords or c++ interface to gc.a
 # cord/de - builds dumb editor based on cords.
 CC= cc
-CXX=g++
+CXX=g++ -ansi
 # Needed only for "make c++", which adds the c++ interface
+AS=as
 
-CFLAGS= -O -DALL_INTERIOR_POINTERS -DSILENT
+CFLAGS= -O -DSILENT -DALL_INTERIOR_POINTERS -DNO_SIGNALS
 # Setjmp_test may yield overly optimistic results when compiled
 # without optimization.
 # -DSILENT disables statistics printing, and improves performance.
@@ -19,9 +20,10 @@ CFLAGS= -O -DALL_INTERIOR_POINTERS -DSILENT
 #   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.)
+#   gc.h before performing thr_ or dl* or GC_ operations.)
+#   This is broken on nonSPARC machines.
 # -DALL_INTERIOR_POINTERS allows all pointers to the interior
-#   of objects to be recognized.  (See gc_private.h for consequences.)
+#   of objects to be recognized.  (See gc_priv.h for consequences.)
 # -DSMALL_CONFIG tries to tune the collector for small heap sizes,
 #   usually causing it to use less space in such situations.
 #   Incremental collection no longer works in this case.
@@ -31,32 +33,44 @@ CFLAGS= -O -DALL_INTERIOR_POINTERS -DSILENT
 #   an object can be recognized.  This can be expensive.  (The padding
 #   is normally more than one byte due to alignment constraints.)
 #   -DDONT_ADD_BYTE_AT_END disables the padding.
+# -DNO_SIGNALS does not disable signals during critical parts of
+#   the GC process.  This is no less correct than many malloc 
+#   implementations, and it sometimes has a significant performance
+#   impact.  However, it is dangerous for many not-quite-ANSI C
+#   programs that call things like printf in asynchronous signal handlers.
+# -DOPERATOR_NEW_ARRAY declares that the C++ compiler supports the
+#   new syntax "operator new[]" for allocating and deleting arrays.
+#   See gc_cpp.h for details.  No effect on the C part of the collector.
 
 AR= ar
 RANLIB= ranlib
 
 
 # Redefining srcdir allows object code for the nonPCR version of the collector
-# to be generated in different directories
+# to be generated in different directories.  In this case, the destination directory
+# should contain a copy of the original include directory.
 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 solaris_threads.o typd_mlc.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o
 
-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
+CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c
 
 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
 
-SRCS= $(CSRCS) mips_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s sparc_mach_dep.s gc.h gc_typed.h gc_hdrs.h gc_priv.h gc_private.h config.h gc_mark.h gc_inl.h gc_inline.h gc.man if_mach.c if_not_there.c gc_c++.cc gc_c++.h $(CORD_SRCS)
+SRCS= $(CSRCS) mips_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s sparc_mach_dep.s gc.h gc_typed.h gc_hdrs.h gc_priv.h gc_private.h config.h gc_mark.h include/gc_inl.h include/gc_inline.h gc.man if_mach.c if_not_there.c gc_cpp.cc gc_cpp.h $(CORD_SRCS)
 
 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 cord/gc.h include/gc.h \
-           include/gc_typed.h README.QUICK callprocs pc_excludes \
-           barrett_diagram README.OS2 README.Mac MacProjects.sit.hqx \
-           MacOS.c EMX_MAKEFILE makefile.depend
+           README test.c test_cpp.cc setjmp_t.c SMakefile.amiga \
+           SCoptions.amiga README.amiga README.win32 cord/README \
+           cord/gc.h include/gc.h include/gc_typed.h include/cord.h \
+           include/ec.h include/private/cord_pos.h include/gc_c++.h \
+           README.QUICK callprocs pc_excludes barrett_diagram \
+           README.OS2 README.Mac MacProjects.sit.hqx MacOS.c \
+           EMX_MAKEFILE makefile.depend README.debugging \
+           include/gc_cpp.h
 
 CORD_INCLUDE_FILES= $(srcdir)/gc.h $(srcdir)/cord/cord.h $(srcdir)/cord/ec.h \
            $(srcdir)/cord/cord_pos.h
@@ -84,7 +98,7 @@ pcr: PCR-Makefile gc_private.h gc_hdrs.h gc.h config.h mach_dep.o $(SRCS)
        make -f PCR-Makefile depend
        make -f PCR-Makefile
 
-$(OBJS) test.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
+$(OBJS) test.o dyn_load.o dyn_load_sunos53.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
     $(srcdir)/config.h $(srcdir)/gc_typed.h Makefile
 # The dependency on Makefile is needed.  Changing
 # options such as -DSILENT affects the size of GC_arrays,
@@ -92,32 +106,51 @@ $(OBJS) test.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
 
 mark.o typd_mlc.o finalize.o: $(srcdir)/gc_mark.h
 
-gc.a: $(OBJS)
-       $(AR) ru gc.a $(OBJS)
-       $(RANLIB) gc.a || cat /dev/null
+gc.a: $(OBJS) dyn_load.o
+       rm -f on_sparc_sunos5
+       ./if_mach SPARC SUNOS5 touch on_sparc_sunos5
+       ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(OBJS) dyn_load.o
+       ./if_not_there on_sparc_sunos5 $(AR) ru gc.a $(OBJS) dyn_load.o
+       ./if_not_there on_sparc_sunos5 $(RANLIB) gc.a || cat /dev/null
 #      ignore ranlib failure; that usually means it doesn't exist, and isn't needed
 
 cords: $(CORD_OBJS) cord/cordtest
-       $(AR) ru gc.a $(CORD_OBJS)
-       $(RANLIB) gc.a || cat /dev/null
-       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
+       rm -f on_sparc_sunos5
+       ./if_mach SPARC SUNOS5 touch on_sparc_sunos5
+       ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(CORD_OBJS)
+       ./if_not_there on_sparc_sunos5 $(AR) ru gc.a $(CORD_OBJS)
+       ./if_not_there on_sparc_sunos5 $(RANLIB) gc.a || cat /dev/null
+
+gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/gc_cpp.h $(srcdir)/gc.h Makefile
+       $(CXX) -c -O $(srcdir)/gc_cpp.cc
        
-c++: gc_c++.o $(srcdir)/gc_c++.h
-       $(AR) ru gc.a gc_c++.o
-       $(RANLIB) gc.a || cat /dev/null
-       cp $(srcdir)/gc_c++.h include/gc_c++.h 
+test_gc_c++: $(srcdir)/test_cpp.cc $(srcdir)/gc_cpp.h gc_cpp.o $(srcdir)/gc.h gc.a
+       $(CXX) -O -o test_gc_c++ $(srcdir)/test_cpp.cc gc_cpp.o gc.a
+
+c++: gc_cpp.o $(srcdir)/gc_cpp.h test_gc_c++
+       rm -f on_sparc_sunos5
+       ./if_mach SPARC SUNOS5 touch on_sparc_sunos5
+       ./if_mach SPARC SUNOS5 $(AR) rus gc.a gc_cpp.o
+       ./if_not_there on_sparc_sunos5 $(AR) ru gc.a gc_cpp.o
+       ./if_not_there on_sparc_sunos5 $(RANLIB) gc.a || cat /dev/null
+       ./test_gc_c++ 1
+
+dyn_load_sunos53.o: dyn_load.c
+       $(CC) $(CFLAGS) -DSUNOS53_SHARED_LIB -c dyn_load.c -o $@
+
+# SunOS5 shared library version of the collector
+libgc.so: $(OBJS) dyn_load_sunos53.o
+       $(CC) -G -o libgc.so $(OBJS) dyn_load_sunos53.o -ldl
 
 mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_mach_dep.s $(srcdir)/rs6000_mach_dep.s if_mach if_not_there
        rm -f mach_dep.o
-       ./if_mach MIPS "" as -o mach_dep.o $(srcdir)/mips_mach_dep.s
-       ./if_mach RS6000 "" as -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
-       ./if_mach ALPHA "" as -o mach_dep.o $(srcdir)/alpha_mach_dep.s
-       ./if_mach SPARC SUNOS5 as -o mach_dep.o $(srcdir)/sparc_mach_dep.s
+       ./if_mach MIPS "" $(AS) -o mach_dep.o $(srcdir)/mips_mach_dep.s
+#  The above doesn't work with gas, which doesn't run cpp.
+#  Rename the above file to end in .S, and then use
+#  gcc -c -o mach_dep.o mips_mach_dep.S instead.
+       ./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
+       ./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.s
+       ./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.s
        ./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
 
 mark_rts.o: $(srcdir)/mark_rts.c if_mach if_not_there
@@ -141,14 +174,17 @@ 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_mach SPARC SUNOS5 $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -lthread -ldl
+       ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -lucb
        ./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
+cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
        rm -f cord/de
-       ./if_mach SPARC SUNOS5 $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a $(CURSES) -lthread
-       ./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a -lcurses
-       ./if_not_there cord/de $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a $(CURSES)
+       ./if_mach SPARC SUNOS5 $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lthread -ldl
+       ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb
+       ./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
+       ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
+       ./if_not_there cord/de $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES)
 
 if_mach: $(srcdir)/if_mach.c $(srcdir)/config.h
        $(CC) $(CFLAGS) -o if_mach $(srcdir)/if_mach.c
@@ -157,7 +193,8 @@ if_not_there: $(srcdir)/if_not_there.c
        $(CC) $(CFLAGS) -o if_not_there $(srcdir)/if_not_there.c
 
 clean: 
-       rm -f gc.a test.o gctest output-local output-diff $(OBJS) \
+       rm -f gc.a test.o gctest $(OBJS) dyn_load.o dyn_load_sunos53.o \
+                 gctest_dyn_link \
              setjmp_test  mon.out gmon.out a.out core if_not_there if_mach \
              $(CORD_OBJS) cord/cordtest cord/de
        -rm -f *~
@@ -165,7 +202,8 @@ clean:
 gctest: test.o gc.a if_mach if_not_there
        rm -f gctest
        ./if_mach ALPHA "" $(CC) $(CFLAGS) -o gctest $(ALPHACFLAGS) test.o gc.a
-       ./if_mach SPARC SUNOS5 $(CC) $(CFLAGS) -o gctest $(CFLAGS) test.o gc.a -lthread
+       ./if_mach SPARC SUNOS5 $(CC) $(CFLAGS) -o gctest  test.o gc.a -lthread -ldl
+       ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o gctest  test.o gc.a -lucb
        ./if_not_there gctest $(CC) $(CFLAGS) -o gctest test.o gc.a
 
 # If an optimized setjmp_test generates a segmentation fault,
@@ -204,3 +242,10 @@ gc.tar.Z: gc.tar
 
 lint: $(CSRCS) test.c
        lint -DLINT $(CSRCS) test.c | egrep -v "possible pointer alignment problem|abort|exit|sbrk|mprotect|syscall"
+       
+# BTL: added to test shared library version of collector.
+# Currently works only under SunOS5.  Requires GC_INIT call from statically
+# loaded client code.
+ABSDIR = `pwd`
+gctest_dyn_link: test.o libgc.so
+       $(CC) -L$(ABSDIR) -R$(ABSDIR) -o gctest_dyn_link test.o -lgc -ldl -lthread
index 2817aa5b1ce8cb596b98a2510940ef8d539d23ff..cf01084703cfb2f1a5b3c0f8117f68532996caef 100644 (file)
@@ -4,25 +4,28 @@
 
 !include <ntwin32.mak>
 
-# We also haven't figured out how to do partial links or build static libraries.  Hence a
-# client currently needs to link against all of the following:
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj
 
-OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj
-
-all: gctest.exe cord\de.exe
+all: gctest.exe cord\de.exe test_cpp.exe
 
 .c.obj:
        $(cc) $(cdebug) $(cflags) $(cvars) -DSMALL_CONFIG -DSILENT -DALL_INTERIOR_POINTERS $*.c /Fo$*.obj
 
+.cpp.obj:
+       $(cc) $(cdebug) $(cflags) $(cvars) -DSMALL_CONFIG -DSILENT -DALL_INTERIOR_POINTERS $*.CPP /Fo$*.obj
+
 $(OBJS) test.obj: gc_priv.h gc_hdrs.h gc.h
 
 gc.lib: $(OBJS)
-       lib32 /MACHINE:i386 /out:gc.lib $(OBJS)
+       lib /MACHINE:i386 /out:gc.lib $(OBJS)
+# The original NT SDK used lib32 instead of lib
 
 gctest.exe: test.obj gc.lib
 #      The following works for win32 debugging.  For win32s debugging use debugtype:coff
 #      and add mapsympe line.
-       $(link) -debug:full -debugtype:cv $(guiflags) -stack:131072 -out:$*.exe test.obj $(conlibs) gc.lib
+#  This produces a "GUI" applications that opens no windows and writes to the log file
+#  "gc.log".  This is done to make the result runnable under win32s.
+       $(link) -debug:full -debugtype:cv $(guiflags) -stack:131072 -out:$*.exe test.obj $(guilibs) gc.lib
 #      mapsympe -n -o gctest.sym gctest.exe
 
 cord\de_win.rbj: cord\de_win.res
@@ -33,5 +36,24 @@ cord\de.obj cord\de_win.obj: cord\cord.h cord\cord_pos.h cord\de_win.h cord\de_c
 cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
        $(rc) $(rcvars) -r -fo cord\de_win.res $(cvars) cord\de_win.rc
 
+# Cord/de is a real win32 gui application.
 cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib
-       $(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe  cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
\ No newline at end of file
+       $(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe  cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
+
+gc_cpp.obj: gc_cpp.h gc.h
+
+gc_cpp.cpp: gc_cpp.cc
+       copy gc_cpp.cc gc_cpp.cpp
+
+test_cpp.cpp: test_cpp.cc
+       copy test_cpp.cc test_cpp.cpp
+
+# This generates the C++ test executable.  The executable expects
+# a single numeric argument, which is the number of iterations.
+# Unlike the other test programs, this is currently a console application,
+# and hence does not run under win32s.
+test_cpp.exe: test_cpp.obj gc_cpp.h gc.h gc.lib
+       $(link) -debug:full -debugtype:cv $(conflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(conlibs)
+
+
+
index 6e0a0ac72b7040a3049623ab7cea31cbe7662173..ba6025d3f48f4c350e90cd9a727e15113cca5f00 100644 (file)
@@ -6,7 +6,7 @@
 # We also haven't figured out how to do partial links or build static libraries.  Hence a
 # client currently needs to link against all of the following:
 
-OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj typd_mlc.obj
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj typd_mlc.obj ptr_chck.obj
 
 CORDOBJS= cord\cordbscs.obj cord\cordxtra.obj cord\cordprnt.obj
 
diff --git a/README b/README
index aa4e2b0801b3bb52511e05099e5fdcd1ce2753e8..4402054996f8014811e6b2ca5e3e81e90e384509 100644 (file)
--- 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.2 of a conservative garbage collector for C and C++.
+This is version 4.3 of a conservative garbage collector for C and C++.
 
 HISTORY -
 
@@ -32,6 +32,7 @@ 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.
+Douglas Steel (doug@wg.icl.co.uk) provided ICL DRS6000 code.
 Bill Janssen (janssen@parc.xerox.com) supplied the SunOS dynamic loader
 specific code. Manuel Serrano (serrano@cornas.inria.fr) supplied linux and
 Sony News specific code.  Al Dosser provided Alpha/OSF/1 code.  He and
@@ -893,4 +894,99 @@ Since version 4.1:
   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
+- Fixed PCR-Makefile for upcoming PPCR release.
+
+Since version 4.2:
+- Fixed SPARC alignment problem with GC_DEBUG.
+- Fixed Solaris threads /proc workaround.  The real
+  problem was an interaction with mprotect.
+- Incorporated fix from Patrick Beard for gc_c++.h.
+- Slightly improved allocator space utilization by
+  fixing the GC_size_map mechanism.
+- Integrated some Sony News and MIPS RISCos 4.51
+  patches.  (Thanks to Nobuyuki Hikichi of
+  Software Research Associates, Inc. Japan)
+- Fixed HP_PA alignment problem.  (Thanks to
+  xjam@cork.cs.berkeley.edu.)
+- Added GC_same_obj and friends.  Changed GC_base
+  to return 0 for pointers past the end of large objects.
+  Improved GC_base performance with ALL_INTERIOR_POINTERS
+  on machines with a slow integer mod operation.
+  Added GC_PTR_ADD, GC_PTR_STORE, etc. to prepare
+  for preprocessor.
+- changed the default on most UNIX machines to be that
+  signals are not disabled during critical GC operations.
+  This is still ANSI-conforming, though somewhat dangerous
+  in the presence of signal handlers. But the performance
+  cost of the alternative is sometimes problematic.
+  Can be changed back with a minor Makefile edit.
+- renamed IS_STRING in gc.h, to CORD_IS_STRING, thus
+  following my own naming convention.  Added the function
+  CORD_to_const_char_star.
+- Fixed a gross bug in GC_finalize.  Symptom: occasional
+  address faults in that function.  (Thanks to Anselm
+  Baird-Smith (Anselm.BairdSmith@inria.fr)
+- Added port to ICL DRS6000 running DRS/NX.  Restructured
+  things a bit to factor out common code, and remove obsolete
+  code.  Collector should now run under SUNOS5 with either
+  mprotect or /proc dirty bits.  (Thanks to Douglas Steel
+  (doug@wg.icl.co.uk)).
+- More bug fixes and workarounds for Solaris 2.X.  (These were
+  mostly related to putting the collector in a dynamic library,
+  which didn't really work before.  Also SOLARIS_THREADS
+  didn't interact well with dl_open.)  Thanks to btlewis@eng.sun.com.
+- Fixed a serious performance bug on the DEC Alpha.  The text
+  segment was getting registered as part of the root set.
+  (Amazingly, the result was still fast enough that the bug
+  was not conspicuous.) The fix works on OSF/1, version 1.3.
+  Hopefully it also works on other versions of OSF/1 ...
+- Fixed a bug in GC_clear_roots.
+- Fixed a bug in GC_generic_malloc_words_small that broke
+  gc_inl.h.  (Reported by Antoine de Maricourt.  I broke it
+  in trying to tweak the Mac port.) 
+- Fixed some problems with cord/de under Linux.
+- Fixed some cord problems, notably with CORD_riter4.
+- Added DG/UX port.
+  Thanks to Ben A. Mesander (ben@piglet.cr.usgs.gov)
+- Added finalization registration routines with weaker ordering
+  constraints.  (This is necessary for C++ finalization with
+  multiple inheritance, since the compiler often adds self-cycles.)
+- Filled the holes in the SCO port. (Thanks to Michael Arnoldus
+  <chime@proinf.dk>.)
+- John Ellis' additions to the C++ support:  From John:
+
+* I completely rewrote the documentation in the interface gc_c++.h.
+I've tried to make it both clearer and more precise.
+
+* The definition of accessibility now ignores pointers from an
+finalizable object (an object with a clean-up function) to itself.
+This allows objects with virtual base classes to be finalizable by the
+collector.  Compilers typically implement virtual base classes using
+pointers from an object to itself, which under the old definition of
+accessibility prevented objects with virtual base classes from ever
+being collected or finalized.
+
+* gc_cleanup now includes gc as a virtual base.  This was enabled by
+the change in the definition of accessibility.
+
+* I added support for operator new[].  Since most (all?) compilers
+don't yet support operator new[], it is conditionalized on
+-DOPERATOR_NEW_ARRAY.  The code is untested, but its trivial and looks
+correct.
+
+* The test program test_gc_c++ tries to test for the C++-specific
+functionality not tested by the other programs.
+- Added <unistd.h> include to misc.c.  (Needed for ppcr.)
+- Added PowerMac port. (Thanks to Patrick Beard again.)
+- Fixed "srcdir"-related Makefile problems.  Changed things so
+  that all externally visible include files always appear in the
+  include subdirectory of the source.  Made gc.h directly
+  includable from C++ code.  (These were at Per
+  Bothner's suggestion.)
+- Changed Intel code to also mark from ebp (Kevin Warne's
+  suggestion).
+- Renamed C++ related files so they could live in a FAT
+  file system. (Charles Fiterman's suggestion.)
+- Changed Windoes NT Makefile to include C++ support in
+  gc.lib.  Added C++ test as Makefile target.
+  
\ No newline at end of file
diff --git a/README.debugging b/README.debugging
new file mode 100644 (file)
index 0000000..9219c5c
--- /dev/null
@@ -0,0 +1,28 @@
+Debugging suggestions:
+
+If the collector dies in GC_malloc while trying to remove a free list element:
+
+1) With > 99% probability, you wrote past the end of an allocated object.  Try setting GC_DEBUG and using the debugging facilities in gc.h.
+
+
+If the heap grows too much:
+
+1) Consider using GC_malloc_atomic for objects containing nonpointers.  This is especially important for large arrays containg compressed data, pseudo-random numbers, and the like.  (This isn't all that likely to solve your problem, but it's a useful and easy optimization anyway, and this is a good time to try it.)   If you allocate large objects containg only one or two pointers at the beginning, either try the typed allocation primitives is gc.h, or separate out the pointerfree component.
+2) If you are using the collector in its default mode, with interior pointer recognition enabled, consider using GC_malloc_ignore_off_page to allocate large objects.  (See gc.h for details.  Large means > 100K in most environments.)  You can determine whether this is necessary by compiling the collector with logging on (without -DSILENT).  If the collector expands the heap many times, without intervening colllections, it is unable to find a sufficiently large chunk of memory that is not "referenced" by "false pointers".  In that case, use GC_malloc_ignore_off_page.
+3) GC_print_block_list() will print a list of all currently allocated heap blocks and what size objects they contain.  GC_print_hblkfreelist() will print a list of free heap blocks, and whether they are blacklisted.
+4) Write a tool that traces back references to the appropriate root.  Send me the code.  (I have code that does this for old PCR.)
+
+
+If the collector appears to be losing objects:
+
+1) Replace all calls to GC_malloc_atomic and typed allocation by GC_malloc calls.  If this fixes the problem, gradually reinsert your optimizations.
+2) You may also want to try the safe(r) pointer manipulation primitives in gc.h.  But those are hard to use until the preprocessor becomes available.
+3) Try using the GC_DEBUG facilities.  This is lless likely to be successful here than if the collector crashes.
+[The rest of these are primarily for wizards.  You shouldn't need them unless you're doing something really strange, or debugging a collector port.]
+4) Don't turn on incremental collection.  If that fixes the problem, suspect a bug in the dirty bit implementation.  Try compiling with -DCHECKSUMS to check for modified, but supposedly clean, pages.
+5) On a SPARC, in a single-threaded environment, GC_print_callers(GC_arrays._last_stack) prints a cryptic stack trace as of the time of the last collection.  (You will need a debugger to decipher the result.)  The question to ask then is "why should this object have been accessible at the time of the last collection?  Where was a pointer to it stored?".  This facility should be easy to add for some other collector ports (namely if it's easy to traverse stack frames), but will be hard for others.
+6) "print *GC_find_header(p)" in dbx or gdb will print the garbage collector block header information associated with the object p (e.g. object size, etc.)
+7) GC_is_marked(p) determines whether p is the base address of a marked object.  Note that objects allocated since the last collection should not be marked, and that unmarked objects are reclaimed incrementally.
+8) Look at the tracing facility in mark.c.  (Ignore this suggestion unless you are very familiar with collector internals.)
+
+
index 1eb77668a6e823a13c50b1bef34eeedccd6c8a67..53d378e3229ccf25cb10f9d84abcca16dd1fd6a1 100644 (file)
@@ -3,7 +3,7 @@ is good reason to believe this is fixable.  (SRC M3 works with
 NT threads.)
 
 The collector has only been compiled under Windows NT, with the
-Microsoft tools.
+original Microsoft SDK and Visual C++ 2.0.
 
 It runs under both win32s and win32, but with different semantics.
 Under win32, all writable pages outside of the heaps and stack are
diff --git a/alloc.c b/alloc.c
index ee30d656bc29bf35bc854f28ad8d1b4b5e7526d8..1b7c4af401660040f8a15679e0cf2b1eef11cb63 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -12,7 +12,7 @@
  * modified is included with the above copyright notice.
  *
  */
-/* Boehm, July 25, 1994 1:22 pm PDT */
+/* Boehm, November 21, 1994 4:35 pm PST */
 
 
 # include "gc_priv.h"
@@ -621,13 +621,16 @@ word needed_blocks;
       }
       if (!GC_expand_hp_inner(blocks_to_get)
         && !GC_expand_hp_inner(needed_blocks)) {
-       if (count++ < 5) {
+       if (count++ < 10) {
            WARN("Out of Memory!  Trying to continue ...\n");
            GC_gcollect_inner();
        } else {
            WARN("Out of Memory!  Returning NIL!\n");
            return(FALSE);
        }
+      } else if (count) {
+          WARN("Memory available again! Continue ...\n");
+          count = 0;
       }
     }
     return(TRUE);
index ce8411ab8fc9a59a3f33defd4567099f6e83290b..1f844e6fabd0d4309199a354b81d4bb010337f93 100644 (file)
--- 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, July 28, 1994 11:03 am PDT */
+/* Boehm, November 22, 1994 11:55 am PST */
  
 #ifndef CONFIG_H
 
@@ -42,9 +42,9 @@
 #    endif
 #    define mach_type_known
 # endif
-# if defined(mips)
+# if defined(mips) || defined(__mips)
 #    define MIPS
-#    ifdef ultrix
+#    if defined(ultrix) || defined(__ultrix)
 #      define ULTRIX
 #    else
 #      ifdef _SYSTYPE_SVR4
 #     endif
 #   define mach_type_known
 # endif
+# if defined(sparc) && defined(unix) && !defined(sun)
+#   define SPARC
+#   define DRSNX
+#   define mach_type_known
+# endif
 # if defined(_IBMR2)
 #   define RS6000
 #   define mach_type_known
 # endif
-# if defined(SCO)
+# if defined(_M_XENIX) && defined(_M_SYSV) && defined(_M_I386)
+       /* The above test may need refinement   */
 #   define I386
 #   define SCO
 #   define mach_type_known
-/*     --> incompletely implemented */
 # endif
 # if defined(_AUX_SOURCE)
 #   define M68K
 #   define AMIGA
 #   define mach_type_known
 # endif
-# if defined(THINK_C)
+# if defined(THINK_C) || defined(__MWERKS__) && !defined(__powerc)
 #   define M68K
 #   define MACOS
 #   define mach_type_known
 # endif
+# if defined(__MWERKS__) && defined(__powerc)
+#   define POWERPC
+#   define MACOS
+# endif
 # if defined(NeXT) && defined(mc68000)
 #   define M68K
 #   define NEXT
 #   define CX_UX
 #   define mach_type_known
 # endif
+# if defined(DGUX)
+#   define M88K
+    /* DGUX defined */
+#   define mach_type_known
+# endif
 # if defined(_MSDOS) && (_M_IX86 == 300) || (_M_IX86 == 400)
 #   define I386
 #   define MSWIN32     /* or Win32s */
                     /*                 (RISCOS, ULTRIX variants)       */
                     /*            VAX        ==> DEC VAX               */
                     /*                 (BSD, ULTRIX variants)          */
-                    /*            RS6000     ==> IBM RS/6000 AIX3.1    */
+                    /*            RS6000     ==> IBM RS/6000 AIX3.X    */
                     /*            RT         ==> IBM PC/RT             */
                     /*            HP_PA      ==> HP9000/700 & /800     */
                     /*                           HP/UX                 */
                    /*             SPARC      ==> SPARC under SunOS     */
-                   /*                  (SUNOS4, SUNOS5 variants)       */
+                   /*                  (SUNOS4, SUNOS5,                */
+                   /*                   DRSNX variants)                */
                    /*             ALPHA      ==> DEC Alpha OSF/1       */
                    /*             M88K       ==> Motorola 88XX0        */
-                   /*                  (CX/UX so far)                  */
+                   /*                  (CX_UX and DGUX)                */
 
 
 /*
  * If either of the last two macros are defined, then STACKBOTTOM is computed
  * during collector startup using one of the following two heuristics:
  * HEURISTIC1:  Take an address inside GC_init's frame, and round it up to
- *             the next multiple of 16 MB.
+ *             the next multiple of STACK_GRAN.
  * HEURISTIC2:  Take an address inside GC_init's frame, increment it repeatedly
  *             in small steps (decrement if STACK_GROWS_UP), and read the value
  *             at each location.  Remember the value when the first
  */
 
 
+# define STACK_GRAN 0x1000000
 # ifdef M68K
 #   define MACH_TYPE "M68K"
 #   define ALIGNMENT 2
                /* in os_dep.c                                  */
 #   endif
 #   ifdef MACOS
+#     ifndef __LOWMEM__
 #     include <LowMem.h>
+#     endif
 #     define OS_TYPE "MACOS"
-#     define DATASTART ((ptr_t) LMGetCurStackBase())
-                               /* globals begin above stack. */
-#     define DATAEND ((ptr_t) LMGetCurrentA5())
-                               /* and end at a5. */
+                       /* see os_dep.c for details of global data segments. */
 #     define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
 #   endif
 #   ifdef NEXT
     extern int etext;
 #   ifdef SUNOS5
 #      define OS_TYPE "SUNOS5"
-       extern char * GC_SysVGetDataStart(int max_page_size);
-#       define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000)
+       extern int etext;
+       extern char * GC_SysVGetDataStart();
+#       define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext)
 #      define PROC_VDB
+#      define HEURISTIC1
 #   endif
 #   ifdef SUNOS4
 #      define OS_TYPE "SUNOS4"
        /* This assumes ZMAGIC, i.e. demand-loadable executables.       */
 #       define DATASTART ((ptr_t)(*(int *)0x2004+0x2000))
 #      define MPROTECT_VDB
+#      define HEURISTIC1
+#   endif
+#   ifdef DRSNX
+#       define CPP_WORDSZ 32
+#      define OS_TYPE "DRSNX"
+       extern char * GC_SysVGetDataStart();
+       extern int etext;
+#       define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext)
+#      define MPROTECT_VDB
+#       define STACKBOTTOM ((ptr_t) 0xdfff0000)
 #   endif
-#   define HEURISTIC1
 #   define DYNAMIC_LOADING
 # endif
 
 #   endif
 #   ifdef SUNOS5
 #      define OS_TYPE "SUNOS5"
-       extern int etext;
-       extern ptr_t GC_SysVGetDataStart(int max_page_size);
-#       define DATASTART GC_SysVGetDataStart(0x1000)
+       extern int etext, _start;
+       extern char * GC_SysVGetDataStart();
+#       define DATASTART GC_SysVGetDataStart(0x1000, &etext)
 #      define STACKBOTTOM ((ptr_t)(&_start))
 #      define PROC_VDB
 #   endif
 #   ifdef SCO
 #      define OS_TYPE "SCO"
+       extern int etext;
 #      define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \
                                  & ~0x3fffff) \
                                 +((word)&etext & 0xfff))
 #   ifdef IRIX5
 #      define OS_TYPE "IRIX5"
 #      define MPROTECT_VDB
+               /* The above is dubious.  Mprotect and signals do work, */
+               /* and dirty bits are implemented under IRIX5.  But,    */
+               /* at least under IRIX5.2, mprotect seems to be so      */
+               /* slow relative to the hardware that incremental       */
+               /* collection is likely to be rarely useful.            */
 #      define DYNAMIC_LOADING
 #   endif
 # endif
 #   define ALIGNMENT 8
 #   define DATASTART ((ptr_t) 0x140000000)
 #   define HEURISTIC2
+       /* Normally HEURISTIC2 is too conervative, since                */
+       /* the text segment immediately follows the stack.              */
+       /* Hence we give an upper pound.                                */
+    extern __start;
+#   define HEURISTIC2_LIMIT ((ptr_t)((word)(&__start) & ~(getpagesize()-1)))
 #   define CPP_WORDSZ 64
 #   define MPROTECT_VDB
 # endif
 # ifdef M88K
 #   define MACH_TYPE "M88K"
 #   define ALIGNMENT 4
-#   define DATASTART ((((word)&etext + 0x3fffff) & ~0x3fffff) + 0x10000)
+#   ifdef CX_UX
+#       define DATASTART ((((word)&etext + 0x3fffff) & ~0x3fffff) + 0x10000)
+#   endif
+#   ifdef  DGUX
+       extern char * GC_SysVGetDataStart();
+#       define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext)
+#   endif
 #   define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */
 # endif
 
 #   define OS_TYPE ""
 # endif
 
+# if defined(SUNOS5) || defined(DRSNX)
+    /* OS has SVR4 generic features.  Probably others also qualify.    */
+#   define SVR4
+# endif
+
+# if defined(SUNOS5) || defined(DRSNX)
+    /* OS has SUNOS5 style semi-undocumented interface to dynamic      */
+    /* loader.                                                         */
+#   define SUNOS5DL
+    /* OS has SUNOS5 style signal handlers.                            */
+#   define SUNOS5SIGS
+# endif
+
 # if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
    -> bad word size
 # endif
index d6f58adaacac38cbd3dfa59243f2aa93584119f1..405a051f50a857f966f4a97f07c1e0f65a472cf6 100644 (file)
@@ -12,7 +12,7 @@
  *
  * Author: Hans-J. Boehm (boehm@parc.xerox.com)
  */
-/* Boehm, May 19, 1994 2:22 pm PDT */
+/* Boehm, October 4, 1994 5:34 pm PDT */
  
 /*
  * Cords are immutable character strings.  A number of operations
@@ -51,7 +51,7 @@
  * 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.
+ * CORD_to_char_star(cord) - convert to C string.
  *   (Non-NULL C constant strings are cords.)
  * CORD_printf (etc.) - cord version of printf. Use %r for cords.
  */
@@ -72,7 +72,7 @@ typedef const char * CORD;
 # define CORD_EMPTY 0
 
 /* Is a nonempty cord represented as a C string? */
-#define IS_STRING(s) (*(s) != '\0')
+#define CORD_IS_STRING(s) (*(s) != '\0')
 
 /* Concatenate two cords.  If the arguments are C strings, they may    */
 /* not be subsequently altered.                                                */
@@ -168,7 +168,7 @@ int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
        /* Fetch the character located at the given position:
        char CORD_pos_fetch(CORD_pos p);
        
-       /* Initialize the position to refer to the give cord and index.
+       /* Initialize the position to refer to the given cord and index.
        /* Note that this is the most expensive function on positions:
        void CORD_set_pos(CORD_pos p, CORD x, size_t i);
        
@@ -203,6 +203,9 @@ void CORD_dump(CORD x);
 /* Concatenate a character to the end of a cord.       */
 CORD CORD_cat_char(CORD x, char c);
 
+/* Concatenate n cords.        */
+CORD CORD_catn(int n, /* CORD */ ...);
+
 /* Return the character in CORD_substr(x, i, 1)        */
 char CORD_fetch(CORD x, size_t i);
 
@@ -255,6 +258,10 @@ CORD CORD_from_file_lazy(FILE * f);
 /* x, and is thus modifiable.                                          */
 char * CORD_to_char_star(CORD x);
 
+/* Identical to the above, but the result may share structure with     */
+/* the argument and is thus not modifiable.                            */
+const char * CORD_to_const_char_star(CORD x); 
+
 /* Write a cord to a file, starting at the current position.  No       */
 /* trailing NULs are newlines are added.                               */
 /* Returns EOF if a write error occurs, 1 otherwise.                   */
index 98cdbb3925f699da32ffb7ec5cb44e46d4829dc9..bbcc92addc3d7760088df4de089da91709ec9118 100644 (file)
@@ -12,7 +12,7 @@
  *
  * Author: Hans-J. Boehm (boehm@parc.xerox.com)
  */
-/* Boehm, June 9, 1994 2:22 pm PDT */
+/* Boehm, October 3, 1994 5:19 pm PDT */
 # include "gc.h"
 # include "cord.h"
 # include <stdlib.h>
@@ -87,11 +87,11 @@ typedef union {
 
 #define LEN(s) (((CordRep *)s) -> generic.len)
 #define DEPTH(s) (((CordRep *)s) -> generic.depth)
-#define GEN_LEN(s) (IS_STRING(s) ? strlen(s) : LEN(s))
+#define GEN_LEN(s) (CORD_IS_STRING(s) ? strlen(s) : LEN(s))
 
 #define LEFT_LEN(c) ((c) -> left_len != 0? \
                                (c) -> left_len \
-                               : (IS_STRING((c) -> left) ? \
+                               : (CORD_IS_STRING((c) -> left) ? \
                                        (c) -> len - GEN_LEN((c) -> right) \
                                        : LEN((c) -> left)))
 
@@ -110,7 +110,7 @@ void CORD_dump_inner(CORD x, unsigned n)
     }
     if (x == 0) {
        fputs("NIL\n", stdout);
-    } else if (IS_STRING(x)) {
+    } else if (CORD_IS_STRING(x)) {
         for (i = 0; i <= SHORT_LIMIT; i++) {
             if (x[i] == '\0') break;
             putchar(x[i]);
@@ -152,7 +152,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
     
     if (x == CORD_EMPTY) return(y);
     if (leny == 0) return(x);
-    if (IS_STRING(x)) {
+    if (CORD_IS_STRING(x)) {
         lenx = strlen(x);
         result_len = lenx + leny;
         if (result_len <= SHORT_LIMIT) {
@@ -176,9 +176,9 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
        
         if (leny <= SHORT_LIMIT/2
            && IS_CONCATENATION(x)
-            && IS_STRING(right = ((CordRep *)x) -> concatenation.right)) {
+            && CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) {
             /* Merge y into right part of x. */
-            if (!IS_STRING(left = ((CordRep *)x) -> concatenation.left)) {
+            if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) {
                right_len = lenx - LEN(left);
             } else if (((CordRep *)x) -> concatenation.left_len != 0) {
                 right_len = lenx - ((CordRep *)x) -> concatenation.left_len;
@@ -197,7 +197,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
                lenx -= right_len;
                /* Now fall through to concatenate the two pieces: */
             }
-            if (IS_STRING(x)) {
+            if (CORD_IS_STRING(x)) {
                 depth = 1;
             } else {
                 depth = DEPTH(x) + 1;
@@ -236,9 +236,9 @@ CORD CORD_cat(CORD x, CORD y)
     
     if (x == CORD_EMPTY) return(y);
     if (y == CORD_EMPTY) return(x);
-    if (IS_STRING(y)) {
+    if (CORD_IS_STRING(y)) {
         return(CORD_cat_char_star(x, y, strlen(y)));
-    } else if (IS_STRING(x)) {
+    } else if (CORD_IS_STRING(x)) {
         lenx = strlen(x);
         depth = DEPTH(y) + 1;
     } else {
@@ -356,7 +356,7 @@ CORD CORD_substr_closure(CORD x, size_t i, size_t n, CORD_fn f)
 /* A version of CORD_substr that assumes i >= 0, n > 0, and i + n < length(x).*/
 CORD CORD_substr_checked(CORD x, size_t i, size_t n)
 {
-    if (IS_STRING(x)) {
+    if (CORD_IS_STRING(x)) {
         if (n > SUBSTR_LIMIT) {
             return(CORD_substr_closure(x, i, n, CORD_index_access_fn));
         } else {
@@ -448,9 +448,11 @@ CORD CORD_substr(CORD x, size_t i, size_t n)
        /* n < 0 is impossible in a correct C implementation, but       */
        /* quite possible  under SunOS 4.X.                             */
     if (i + n > len) n = len - i;
-    if (i < 0) ABORT("CORD_substr: second arg. negative");
+#   ifndef __STDC__
+      if (i < 0) ABORT("CORD_substr: second arg. negative");
        /* Possible only if both client and C implementation are buggy. */
        /* But empirically this happens frequently.                     */
+#   endif
     return(CORD_substr_checked(x, i, n));
 }
 
@@ -459,7 +461,7 @@ int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
                         CORD_batched_iter_fn f2, void * client_data)
 {
     if (x == 0) return(0);
-    if (IS_STRING(x)) {
+    if (CORD_IS_STRING(x)) {
        register const char *p = x+i;
        
        if (*p == '\0') ABORT("2nd arg to CORD_iter5 too big");
@@ -512,7 +514,7 @@ int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data)
 int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
 {
     if (x == 0) return(0);
-    if (IS_STRING(x)) {
+    if (CORD_IS_STRING(x)) {
        register const char *p = x + i;
        register char c;
                
@@ -542,12 +544,12 @@ int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
         register struct Function * f = &(((CordRep *)x) -> function);
         register size_t j;
         
-        for (j = i; j >= 0; j--) {
+        for (j = i; ; j--) {
             if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) {
                 return(1);
             }
+            if (j == 0) return(0);
         }
-        return(0);
     }
 }
 
@@ -682,7 +684,7 @@ void CORD_balance_insert(CORD x, size_t len, ForestElement * forest)
 {
     register int depth;
     
-    if (IS_STRING(x)) {
+    if (CORD_IS_STRING(x)) {
         CORD_add_forest(forest, x, len);
     } else if (IS_CONCATENATION(x)
                && ((depth = DEPTH(x)) >= MAX_DEPTH
@@ -705,7 +707,7 @@ CORD CORD_balance(CORD x)
     register size_t len;
     
     if (x == 0) return(0);
-    if (IS_STRING(x)) return(x);
+    if (CORD_IS_STRING(x)) return(x);
     if (!min_len_init) CORD_init_min_len();
     len = LEN(x);
     CORD_init_forest(forest, len);
@@ -730,7 +732,7 @@ void CORD__extend_path(register CORD_pos p)
      register size_t top_len = GEN_LEN(top);
      
      /* Fill in the rest of the path. */
-       while(!IS_STRING(top) && IS_CONCATENATION(top)) {
+       while(!CORD_IS_STRING(top) && IS_CONCATENATION(top)) {
         register struct Concatenation * conc =
                        &(((CordRep *)top) -> concatenation);
         register size_t left_len;
@@ -749,7 +751,7 @@ void CORD__extend_path(register CORD_pos p)
         p[0].path_len++;
        }
      /* Fill in leaf description for fast access. */
-       if (IS_STRING(top)) {
+       if (CORD_IS_STRING(top)) {
          p[0].cur_leaf = top;
          p[0].cur_start = top_pos;
          p[0].cur_end = top_pos + top_len;
@@ -778,7 +780,7 @@ void CORD__next(register CORD_pos p)
     
     /* Leaf is not a string or we're at end of leaf */
     p[0].cur_pos = cur_pos;
-    if (!IS_STRING(leaf)) {
+    if (!CORD_IS_STRING(leaf)) {
        /* Function leaf        */
        register struct Function * f = &(((CordRep *)leaf) -> function);
        register size_t start_pos = current_pe -> pe_start_pos;
index e4e053045bc23b9bede070ffd0c3b4f6bd6c41de..e27c1e93fe844eb921f76ad149ee76a2d25a7633 100644 (file)
@@ -20,7 +20,7 @@
 /* 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, July 25, 1994 3:42 pm PDT */
+/* Boehm, October 3, 1994 5:15 pm PDT */
 
 #include "cord.h"
 #include "ec.h"
@@ -258,6 +258,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
                        /* The above does not appear to be sanctioned   */
                        /* by the ANSI C standard.                      */
                    int max_size = 0;
+                   int res;
                        
                    if (width == VARIABLE) width = va_arg(args, int);
                    if (prec == VARIABLE) prec = va_arg(args, int);
@@ -301,11 +302,12 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
                        default:
                            return(-1);
                    }
-                   len = (size_t)vsprintf(buf, conv_spec, vsprintf_args);
-                   if ((char *)len == buf) {
+                   res = vsprintf(buf, conv_spec, vsprintf_args);
+                   len = (size_t)res;
+                   if ((char *)res == buf) {
                        /* old style vsprintf */
                        len = strlen(buf);
-                   } else if (len < 0) {
+                   } else if (res < 0) {
                        return(-1);
                    }
                    if (buf != result[0].ec_bufptr) {
index 2b35772b8d950bdcc6ef40d9e8ebc6c2e2e60415..1280da9c22a34060dd70c3607eff5edf10330295 100644 (file)
@@ -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, July 25, 1994 3:24 pm PDT */
+/* Boehm, August 24, 1994 11:58 am PDT */
 # include "cord.h"
 # include <string.h>
 # include <stdio.h>
@@ -55,7 +55,7 @@ void test_basics()
     CORD_pos p;
     
     x = CORD_cat(x,x);
-    if (!IS_STRING(x)) ABORT("short cord should usually be a string");
+    if (!CORD_IS_STRING(x)) ABORT("short cord should usually be a string");
     if (strcmp(x, "abab") != 0) ABORT("bad CORD_cat result");
     
     for (i = 1; i < 16; i++) {
@@ -79,15 +79,15 @@ void test_basics()
     if (count != 64*1024 + 2) ABORT("Position based iteration failed");
     
     y = CORD_substr(x, 1023, 5);
-    if (!IS_STRING(y)) ABORT("short cord should usually be a string");
+    if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
     if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
     
     y = CORD_substr(x, 1024, 8);
-    if (!IS_STRING(y)) ABORT("short cord should usually be a string");
+    if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
     if (strcmp(y, "abababab") != 0) ABORT("bad CORD_substr result");
     
     y = CORD_substr(x, 128*1024-1, 8);
-    if (!IS_STRING(y)) ABORT("short cord should usually be a string");
+    if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
     if (strcmp(y, "bc") != 0) ABORT("bad CORD_substr result");
     
     x = CORD_balance(x);
@@ -100,7 +100,7 @@ void test_basics()
     if (count != 64*1024 + 2) ABORT("CORD_iter5 failed");
     
     y = CORD_substr(x, 1023, 5);
-    if (!IS_STRING(y)) ABORT("short cord should usually be a string");
+    if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
     if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
     y = CORD_from_fn(id_cord_fn, 0, 13);
     i = 0;
@@ -132,6 +132,9 @@ void test_extras()
     FILE *f;
     FILE *f1a, *f1b, *f2;
     
+    w = CORD_cat(CORD_cat(y,y),y);
+    z = CORD_catn(3,y,y,y);
+    if (CORD_cmp(w,z) != 0) ABORT("CORD_catn comparison wrong");
     for (i = 1; i < 100; i++) {
         x = CORD_cat(x, y);
     }
index ff8c8b5093cf926c17948e0566d46ad90dafb885..e39612c8eec3a8bd715c86a62456dce9a20ebac7 100644 (file)
  * implementation.  They serve also serve as example client code for
  * cord_basics.
  */
-/* Boehm, July 25, 1994 3:46 pm PDT */
+/* Boehm, October 3, 1994 5:10 pm PDT */
 # include <stdio.h>
 # include <string.h>
 # include <stdlib.h>
+# include <stdarg.h>
 # include "cord.h"
 # include "ec.h"
 # define I_HIDE_POINTERS       /* So we get access to allocation lock. */
                                /* of the threads primitives.           */
 # include "gc.h"
 
+/* For now we assume that pointer reads and writes are atomic,         */
+/* i.e. another thread always sees the state before or after   */
+/* a write.  This might be false on a Motorola M68K with       */
+/* pointers that are not 32-bit aligned.  But there probably   */
+/* aren't too many threads packages running on those.          */
+# define ATOMIC_WRITE(x,y) (x) = (y)
+# define ATOMIC_READ(x) (*(x))
+
 /* The standard says these are in stdio.h, but they aren't always: */
 # ifndef SEEK_SET
 #   define SEEK_SET 0
@@ -58,6 +67,21 @@ CORD CORD_cat_char(CORD x, char c)
     return(CORD_cat_char_star(x, string, 1));
 }
 
+CORD CORD_catn(int nargs, ...)
+{
+    register CORD result = CORD_EMPTY;
+    va_list args;
+    register int i;
+
+    va_start(args, nargs);
+    for (i = 0; i < nargs; i++) {
+        register CORD next = va_arg(args, CORD);
+        result = CORD_cat(result, next);
+    }
+    va_end(args);
+    return(result);
+}
+
 typedef struct {
        size_t len;
        size_t count;
@@ -117,7 +141,7 @@ int CORD_cmp(CORD x, CORD y)
     
     if (y == CORD_EMPTY) return(x != CORD_EMPTY);
     if (x == CORD_EMPTY) return(-1);
-    if (IS_STRING(y) && IS_STRING(x)) return(strcmp(x,y));
+    if (CORD_IS_STRING(y) && CORD_IS_STRING(x)) return(strcmp(x,y));
     CORD_set_pos(xpos, x, 0);
     CORD_set_pos(ypos, y, 0);
     for(;;) {
@@ -211,6 +235,13 @@ char * CORD_to_char_star(CORD x)
     return(result);
 }
 
+const char * CORD_to_const_char_star(CORD x)
+{
+    if (x == 0) return("");
+    if (CORD_IS_STRING(x)) return((const char *)x);
+    return(CORD_to_char_star(x));
+}
+
 char CORD_fetch(CORD x, size_t i)
 {
     CORD_pos xpos;
@@ -330,7 +361,7 @@ size_t CORD_str(CORD x, size_t start, CORD s)
     register size_t match_pos;
     
     if (s == CORD_EMPTY) return(start);
-    if (IS_STRING(s)) {
+    if (CORD_IS_STRING(s)) {
         s_start = s;
         slen = strlen(s);
     } else {
@@ -484,7 +515,7 @@ refill_data * client_data;
     }
     new_cache -> tag = DIV_LINE_SZ(file_pos);
     /* Store barrier goes here. */
-    state -> lf_cache[line_no] = new_cache;
+    ATOMIC_WRITE(state -> lf_cache[line_no], new_cache);
     state -> lf_current = line_start + LINE_SZ;
     return(new_cache->data[MOD_LINE_SZ(file_pos)]);
 }
@@ -492,7 +523,9 @@ refill_data * client_data;
 char CORD_lf_func(size_t i, void * client_data)
 {
     register lf_state * state = (lf_state *)client_data;
-    register cache_line * cl = state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))];
+    register cache_line * volatile * cl_addr =
+               &(state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))]);
+    register cache_line * cl = (cache_line *)ATOMIC_READ(cl_addr);
     
     if (cl == 0 || cl -> tag != DIV_LINE_SZ(i)) {
        /* Cache miss */
@@ -533,7 +566,7 @@ CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
 
 CORD CORD_from_file_lazy(FILE * f)
 {
-    register size_t len;
+    register long len;
     
     if (fseek(f, 0l, SEEK_END) != 0) {
         ABORT("Bad fd argument - fseek failed");
@@ -542,14 +575,14 @@ CORD CORD_from_file_lazy(FILE * f)
         ABORT("Bad fd argument - ftell failed");
     }
     rewind(f);
-    return(CORD_from_file_lazy_inner(f, len));
+    return(CORD_from_file_lazy_inner(f, (size_t)len));
 }
 
 # define LAZY_THRESHOLD (128*1024 + 1)
 
 CORD CORD_from_file(FILE * f)
 {
-    register size_t len;
+    register long len;
     
     if (fseek(f, 0l, SEEK_END) != 0) {
         ABORT("Bad fd argument - fseek failed");
@@ -561,6 +594,6 @@ CORD CORD_from_file(FILE * f)
     if (len < LAZY_THRESHOLD) {
         return(CORD_from_file_eager(f));
     } else {
-        return(CORD_from_file_lazy_inner(f, len));
+        return(CORD_from_file_lazy_inner(f, (size_t)len));
     }
 }
index 5f8fd3b52c77740c854110a14be6a81b903434f9..c561d29e4869c9706eaf6f0bd07a60935df82906 100644 (file)
--- a/cord/de.c
+++ b/cord/de.c
@@ -574,6 +574,11 @@ char ** argv;
            do_command(c);
     }
 done:
+    move(LINES-1, 0);
+    clrtoeol();
+    refresh();
+    nl();
+    echo();
     endwin();
     exit(0);
 usage:
index 34e56bf4d4cfab9ced7cab91cbab3699a43390cb..1827162bc4bf35c4cafd6fa846a1df385d2a2fea 100644 (file)
--- a/cord/gc.h
+++ b/cord/gc.h
  * 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 */
+/* Boehm, December 7, 1994 12:09 pm PST */
+
+/*
+ * Note that this defines a large number of tuning hooks, which can
+ * safely be ignored in nearly all cases.  For normal use it suffices
+ * to call only GC_MALLOC and perhaps GC_REALLOC.
+ * For better performance, also look at GC_MALLOC_ATOMIC, and
+ * GC_enable_incremental.  If you need an action to be performed
+ * immediately before an object is collected, look at GC_register_finalizer.
+ * If you are using Solaris threads, look at the end of this file.
+ * Everything else is best ignored unless you encounter performance
+ * problems.
+ */
  
 #ifndef _GC_H
 
 # define _GC_H
 
+# ifdef __cplusplus
+    extern "C" {
+# endif
+
 # include <stddef.h>
 
 /* Define word and signed_word to be unsigned and signed types of the  */
@@ -84,7 +100,7 @@ extern GC_word GC_free_space_divisor;
  * collectable.  GC_malloc_uncollectable and GC_free called on the resulting
  * object implicitly update GC_non_gc_bytes appropriately.
  */
-#if defined(__STDC__) || defined(__cplusplus)
+# 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);
@@ -108,7 +124,7 @@ extern GC_word GC_free_space_divisor;
 /* 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)
+# if defined(__STDC__) || defined(__cplusplus)
   extern void GC_free(void * object_addr);
 # else
   extern void GC_free(/* object_addr */);
@@ -170,10 +186,10 @@ void GC_end_stubborn_change(/* p */);
 /* Returns 0 on failure, 1 on success.  */
 extern int GC_expand_hp(/* number_of_bytes */);
 
-/* Clear the set of root segments */
+/* Clear the set of root segments.  Wizards only. */
 extern void GC_clear_roots(NO_PARAMS);
 
-/* Add a root segment */
+/* Add a root segment.  Wizards only. */
 extern void GC_add_roots(/* low_address, high_address_plus_1 */);
 
 /* Add a displacement to the set of those considered valid by the      */
@@ -188,7 +204,11 @@ extern void GC_add_roots(/* low_address, high_address_plus_1 */);
 /* 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 */);
+void GC_register_displacement(/* GC_word n */);
+
+/* The following version should be used if any debugging allocation is */
+/* being done.                                                         */
+void GC_debug_register_displacement(/* GC_word n */);
 
 /* Explicitly trigger a full, world-stop collection.   */
 void GC_gcollect(NO_PARAMS);
@@ -280,10 +300,17 @@ void GC_debug_end_stubborn_change(/* 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_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+       GC_register_finalizer_ignore_self( \
+             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)
+#   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+       GC_general_register_disappearing_link(link, GC_base(obj))
+#   define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n)
 # else
 #   define GC_MALLOC(sz) GC_malloc(sz)
 #   define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
@@ -292,9 +319,14 @@ void GC_debug_end_stubborn_change(/* p */);
 #   define GC_FREE(p) GC_free(p)
 #   define GC_REGISTER_FINALIZER(p, f, d, of, od) \
        GC_register_finalizer(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+       GC_register_finalizer_ignore_self(p, f, d, of, od)
 #   define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
 #   define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
 #   define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
+#   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+       GC_general_register_disappearing_link(link, obj)
+#   define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n)
 # endif
 /* The following are included because they are often convenient, and   */
 /* reduce the chance for a misspecifed size argument.  But calls may   */
@@ -355,7 +387,26 @@ void GC_debug_end_stubborn_change(/* p */);
        /* 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.                                */
+
+/* Another versions of the above follow.  It ignores           */
+/* self-cycles, i.e. pointers from a finalizable object to     */
+/* itself.  There is a stylistic argument that this is wrong,  */
+/* but it's unavoidable for C++, since the compiler may                */
+/* silently introduce these.  It's also benign in that specific        */
+/* case.                                                       */
+# if defined(__STDC__) || defined(__cplusplus)
+    void GC_register_finalizer_ignore_self(void * obj,
+                              GC_finalization_proc fn, void * cd,
+                              GC_finalization_proc *ofn, void ** ocd);
+# else 
+    void GC_register_finalizer_ignore_self(/* void * obj,
+                                 GC_finalization_proc fn, void * cd,
+                                 GC_finalization_proc *ofn, void ** ocd */);
+# endif
 
 /* The following routine may be used to break cycles between   */
 /* finalizable objects, thus causing cyclic finalizable                */
@@ -388,8 +439,10 @@ int GC_general_register_disappearing_link(/* void ** link, void * obj */);
        /* 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           */
+       /* holding a disguised pointer to obj.  (A pointer      */
+       /* inside an "atomic" object is effectively             */
+       /* disguised.)   In this way soft                       */
+       /* pointers are broken before any object                */
        /* reachable from them are finalized.  Each link        */
        /* May be registered only once, i.e. with one obj       */
        /* value.  This was added after a long email discussion */
@@ -420,6 +473,9 @@ int GC_unregister_disappearing_link(/* void ** link */);
 /* that finalization code will arrange for hidden pointers to  */
 /* disappear.  Otherwise objects can be accessed after they    */
 /* have been collected.                                                */
+/* Note that putting pointers in atomic objects or in          */
+/* nonpointer slots of "typed" objects is equivalent to        */
+/* disguising them in this way, and may have other advantages. */
 # ifdef I_HIDE_POINTERS
 #   if defined(__STDC__) || defined(__cplusplus)
 #     define HIDE_POINTER(p) (~(size_t)(p))
@@ -441,6 +497,76 @@ int GC_unregister_disappearing_link(/* void ** link */);
 #   endif
 # endif
 
+/* Check that p and q point to the same object.                */
+/* Fail conspicuously if they don't.                           */
+/* Returns the first argument.                                 */
+/* Succeeds if neither p nor q points to the heap.             */
+/* May succeed if both p and q point to between heap objects.  */
+#ifdef __STDC__
+  void * GC_same_obj(register void *p, register void *q);
+#else
+  char * GC_same_obj(/* char * p, char * q */);
+#endif
+
+/* Check that p is visible                                             */
+/* to the collector as a possibly pointer containing location.         */
+/* If it isn't fail conspicuously.                                     */
+/* Returns the argument in all cases.  May erroneously succeed         */
+/* in hard cases.  (This is intended for debugging use with            */
+/* untyped allocations.  The idea is that it should be possible, though        */
+/* slow, to add such a call to all indirect pointer stores.)           */
+/* Currently useless for multithreaded worlds.                         */
+#ifdef __STDC__
+  void * GC_is_visible(void *p);
+#else
+  char *GC_is_visible(/* char * p */);
+#endif
+
+/* Check that if p is a pointer to a heap page, then it points to      */
+/* a valid displacement within a heap object.                          */
+/* Fail conspicuously if this property does not hold.                  */
+/* Uninteresting with ALL_INTERIOR_POINTERS.                           */
+/* Always returns its argument.                                                */
+#ifdef __STDC__
+  void * GC_is_valid_displacement(void *p);
+#else
+  char *GC_is_valid_displacement(/* char * p */);
+#endif
+
+/* Safer, but slow, pointer addition.  Probably useful mainly with     */
+/* a preprocessor.  Useful only for heap pointers.                     */
+#ifdef GC_DEBUG
+#   define GC_PTR_ADD3(x, n, type_of_result) \
+       ((type_of_result)GC_same_obj((x)+(n), (x)))
+#   ifdef __GNUC__
+#       define GC_PTR_ADD(x, n) \
+           ((typeof(x))GC_same_obj((x)+(n), (x)))
+#   else
+       /* We can't do this right without typeof, which ANSI    */
+       /* decided was not sufficiently useful.  Repeatedly     */
+       /* mentioning the arguments seems too dangerous to be   */
+       /* useful.  So does not casting the result.             */
+#      define GC_PTR_ADD(x, n) ((x)+(n))
+#   endif
+#else  /* !GC_DEBUG */
+#   define GC_PTR_ADD3(x, n, type_of_result) ((x)+(n))
+#   define GC_PTR_ADD(x, n) ((x)+(n))
+#endif
+
+/* Safer assignment of a pointer to a nonstack location.       */
+#ifdef GC_DEBUG
+# ifdef __STDC__
+#   define GC_PTR_STORE(p, q) \
+       (*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# else
+#   define GC_PTR_STORE(p, q) \
+       (*(char **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# endif
+#else /* !GC_DEBUG */
+#   define GC_PTR_STORE(p, q) *((p) = (q))
+#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.                        */
@@ -449,6 +575,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);
@@ -472,4 +599,21 @@ void * GC_malloc_many(size_t lb);
 
 #endif /* SOLARIS_THREADS */
 
+/*
+ * If you are planning on putting
+ * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
+ * from the statically loaded program section.
+ * This circumvents a Solaris 2.X (X<=4) linker bug.
+ */
+#ifdef sparc
+#   define GC_INIT() { extern end, etext; \
+                      GC_noop(&end, &etext); }
+#else
+#   define GC_INIT()
+#endif
+
+#ifdef __cplusplus
+    }  /* end of extern "C" */
+#endif
+
 #endif /* _GC_H */
index f9c7ff0dc3a47504507d95e428603e275f59b20f..0baa7c6bc32d38f4126c204c55fe4460579e7c9a 100644 (file)
--- a/dbg_mlc.c
+++ b/dbg_mlc.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, June 16, 1994 4:54 pm PDT */
+/* Boehm, October 27, 1994 9:57 am PDT */
 # include "gc_priv.h"
 
 /* Do we want to and know how to save the call stack at the time of    */
@@ -165,6 +165,13 @@ void GC_start_debugging()
     GC_register_displacement((word)sizeof(oh));
 }
 
+void GC_debug_register_displacement(n)
+word n;
+{
+    GC_register_displacement(n);
+    GC_register_displacement((word)sizeof(oh) + n);
+}
+
 # ifdef __STDC__
     extern_ptr_t GC_debug_malloc(size_t lb, char * s, int i)
 # else
@@ -443,6 +450,11 @@ word dummy;
 /* I hold the allocation lock. Normally called by collector.           */
 void GC_check_heap_proc()
 {
+#   ifndef SMALL_CONFIG
+       if (sizeof(oh) & (2 * sizeof(word) - 1) != 0) {
+           ABORT("Alignment problem: object header has inappropriate size\n");
+       }
+#   endif
     GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
 }
 
index caec398e1824a146aa768ceccdb54af0874e955a..a48a3021281c34c715ef927bf621d37cf223a665 100644 (file)
@@ -13,7 +13,7 @@
  * Original author: Bill Janssen
  * Heavily modified by Hans Boehm and others
  */
-/* Boehm, June 7, 1994 4:35 pm PDT */
+/* Boehm, September 12, 1994 4:27 pm PDT */
 
 /*
  * This is incredibly OS specific code for tracking down data sections in
 #endif
 #include "gc_priv.h"
 
+/* BTL: avoid circular redefinition of dlopen if SOLARIS_THREADS defined */
+# if defined(SOLARIS_THREADS) && defined(dlopen)
+    /* To support threads in Solaris, gc.h interposes on dlopen by       */
+    /* defining "dlopen" to be "GC_dlopen", which is implemented below.  */
+    /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the   */
+    /* real system dlopen() in their implementation. We first remove     */
+    /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
+#   undef dlopen
+#   define GC_must_restore_redefined_dlopen
+# else
+#   undef GC_must_restore_redefined_dlopen
+# endif
+
 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR)
-#if !defined(SUNOS4) && !defined(SUNOS5) && !defined(IRIX5) && !defined(MSWIN32)
+#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && !defined(MSWIN32)
  --> We only know how to find data segments of dynamic libraries under SunOS,
- --> IRIX5 and Win32.  Additional SVR4 variants might not be too hard to add.
+ --> IRIX5, DRSNX and Win32.  Additional SVR4 variants might not be too
+ --> hard to add.
 #endif
 
 #include <stdio.h>
-#ifdef SUNOS5
+#ifdef SUNOS5DL
 #   include <sys/elf.h>
 #   include <dlfcn.h>
 #   include <link.h>
@@ -54,7 +68,7 @@
 #endif
 
 
-#ifdef SUNOS5
+#ifdef SUNOS5DL
 
 #ifdef LINT
     Elf32_Dyn _DYNAMIC;
@@ -67,8 +81,23 @@ GC_FirstDLOpenedLinkMap()
     Elf32_Dyn *dp;
     struct r_debug *r;
     static struct link_map * cachedResult = 0;
+    static Elf32_Dyn *dynStructureAddr = 0;
+                       /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
+
+#   ifdef SUNOS53_SHARED_LIB
+       /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */
+       /* up properly in dynamically linked .so's. This means we have  */
+       /* to use its value in the set of original object files loaded  */
+       /* at program startup.                                          */
+       if( dynStructureAddr == 0 ) {
+         void* startupSyms = dlopen(0, RTLD_LAZY);
+         dynStructureAddr = (Elf32_Dyn*)dlsym(startupSyms, "_DYNAMIC");
+               }
+#   else
+       dynStructureAddr = &_DYNAMIC;
+#   endif
 
-    if( &_DYNAMIC == 0) {
+    if( dynStructureAddr == 0) {
         return(0);
     }
     if( cachedResult == 0 ) {
@@ -127,7 +156,7 @@ static ptr_t GC_first_common()
 
 #endif
 
-# if defined(SUNOS4) || defined(SUNOS5)
+# if defined(SUNOS4) || defined(SUNOS5DL)
 /* Add dynamic library data sections to the root set.          */
 # if !defined(PCR) && !defined(SOLARIS_THREADS) && defined(THREADS)
 #   ifndef SRC_M3
@@ -154,6 +183,11 @@ void * GC_dlopen(const char *path, int mode)
 }
 # endif
 
+/* BTL: added to fix circular dlopen definition if SOLARIS_THREADS defined */
+# if defined(GC_must_restore_redefined_dlopen)
+#   define dlopen GC_dlopen
+# endif
+
 void GC_register_dynamic_libraries()
 {
   struct link_map *lm = GC_FirstDLOpenedLinkMap();
@@ -170,7 +204,7 @@ void GC_register_dynamic_libraries()
                    ((char *) (N_DATOFF(*e) + lm->lm_addr)),
                    ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)));
 #     endif
-#     ifdef SUNOS5
+#     ifdef SUNOS5DL
        Elf32_Ehdr * e;
         Elf32_Phdr * p;
         unsigned long offset;
index 031021ee697a617391e81b96e235626b86014f26..3102b28a7703ca0e8bfdee744ad29f96fbf89f68 100644 (file)
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, June 9, 1994 2:17 pm PDT */
+/* Boehm, November 8, 1994 5:35 pm PST */
 # define I_HIDE_POINTERS
-# include "gc.h"
 # include "gc_priv.h"
 # include "gc_mark.h"
 
+/* Type of mark procedure used for marking from finalizable object.    */
+/* This procedure normally does not mark the object, only its          */
+/* descendents.                                                                */
+typedef void finalization_mark_proc(/* ptr_t finalizable_obj_ptr */); 
+
 # define HASH3(addr,size,log_size) \
     ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \
     & ((size) - 1))
@@ -57,6 +61,7 @@ static struct finalizable_object {
     GC_finalization_proc fo_fn;        /* Finalizer.                   */
     ptr_t fo_client_data;
     word fo_object_size;       /* In bytes.                    */
+    finalization_mark_proc * fo_mark_proc;     /* Mark-through procedure */
 } **fo_head = 0;
 
 struct finalizable_object * GC_finalize_now = 0;
@@ -228,22 +233,60 @@ out:
     return(0);
 }
 
+/* Possible finalization_marker procedures.  Note that mark stack      */
+/* overflow is handled by the caller, and is not a disaster.           */
+void GC_normal_finalize_mark_proc(p)
+ptr_t p;
+{
+    hdr * hhdr = HDR(p);
+    
+    PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
+            &(GC_mark_stack[GC_mark_stack_size]));
+}
+
+/* This only pays very partial attention to the mark descriptor.       */
+/* It does the right thing for normal and atomic objects, and treats   */
+/* most others as normal.                                              */
+void GC_ignore_self_finalize_mark_proc(p)
+ptr_t p;
+{
+    hdr * hhdr = HDR(p);
+    word descr = hhdr -> hb_descr;
+    ptr_t q, r;
+    ptr_t limit;
+    
+    if ((descr & DS_TAGS) == DS_LENGTH) {
+       limit = p + descr - sizeof(word);
+    } else {
+       limit = p + WORDS_TO_BYTES(hhdr -> hb_sz - 1);
+    }
+    for (q = p; q <= limit; q += ALIGNMENT) {
+       r = *(ptr_t *)q;
+       if (r < p || r > limit) {
+           GC_PUSH_ONE_HEAP((word)r);
+       }
+    }
+}
+
+/*ARGSUSED*/
+void GC_null_finalize_mark_proc(p)
+ptr_t p;
+{
+}
+
+
+
 /* Register a finalization function.  See gc.h for details.    */
 /* in the nonthreads case, we try to avoid disabling signals,  */
 /* since it can be expensive.  Threads packages typically      */
 /* make it cheaper.                                            */
-# 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
+void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
+extern_ptr_t obj;
+GC_finalization_proc fn;
+extern_ptr_t cd;
+GC_finalization_proc * ofn;
+extern_ptr_t * ocd;
+finalization_mark_proc * mp;
 {
     ptr_t base;
     struct finalizable_object * curr_fo, * prev_fo;
@@ -300,6 +343,7 @@ out:
             } else {
                 curr_fo -> fo_fn = fn;
                 curr_fo -> fo_client_data = (ptr_t)cd;
+                curr_fo -> fo_mark_proc = mp;
                /* Reinsert it.  We deleted it first to maintain        */
                /* consistency in the event of a signal.                */
                if (prev_fo == 0) {
@@ -337,6 +381,7 @@ out:
        new_fo -> fo_fn = fn;
        new_fo -> fo_client_data = (ptr_t)cd;
        new_fo -> fo_object_size = GC_size(base);
+       new_fo -> fo_mark_proc = mp;
        fo_set_next(new_fo, fo_head[index]);
        GC_fo_entries++;
        fo_head[index] = new_fo;
@@ -349,6 +394,58 @@ out:
 #   endif
 }
 
+# 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
+{
+    GC_register_finalizer_inner(obj, fn, cd, ofn,
+                               ocd, GC_normal_finalize_mark_proc);
+}
+
+# if defined(__STDC__)
+    void GC_register_finalizer_ignore_self(void * obj,
+                              GC_finalization_proc fn, void * cd,
+                              GC_finalization_proc *ofn, void ** ocd)
+# else
+    void GC_register_finalizer_ignore_self(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
+{
+    GC_register_finalizer_inner(obj, fn, cd, ofn,
+                               ocd, GC_ignore_self_finalize_mark_proc);
+}
+
+# if defined(__STDC__)
+    void GC_register_finalizer_no_order(void * obj,
+                              GC_finalization_proc fn, void * cd,
+                              GC_finalization_proc *ofn, void ** ocd)
+# else
+    void GC_register_finalizer_no_order(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
+{
+    GC_register_finalizer_inner(obj, fn, cd, ofn,
+                               ocd, GC_null_finalize_mark_proc);
+}
+
+
 /* Called with world stopped.  Cause disappearing links to disappear,  */
 /* and invoke finalizers.                                              */
 void GC_finalize()
@@ -357,8 +454,8 @@ void GC_finalize()
     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
     ptr_t real_ptr, real_link;
     register int i;
-    int dl_size = 1 << log_dl_table_size;
-    int fo_size = 1 << log_fo_table_size;
+    int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
+    int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
     
   /* Make disappearing links disappear */
     for (i = 0; i < dl_size; i++) {
@@ -393,10 +490,7 @@ void GC_finalize()
       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
         if (!GC_is_marked(real_ptr)) {
-            hdr * hhdr = HDR(real_ptr);
-            
-            PUSH_OBJ((word *)real_ptr, hhdr, GC_mark_stack_top,
-                    &(GC_mark_stack[GC_mark_stack_size]));
+            (*(curr_fo -> fo_mark_proc))(real_ptr);
             while (!GC_mark_stack_empty()) GC_mark_from_mark_stack();
             if (GC_mark_state != MS_NONE) {
                 /* Mark stack overflowed. Very unlikely. */
diff --git a/gc.h b/gc.h
index ca7eb506b0bcdc3d72aff897e62ac74054228d5e..1827162bc4bf35c4cafd6fa846a1df385d2a2fea 100644 (file)
--- a/gc.h
+++ b/gc.h
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, July 7, 1994 11:32 am PDT */
+/* Boehm, December 7, 1994 12:09 pm PST */
+
+/*
+ * Note that this defines a large number of tuning hooks, which can
+ * safely be ignored in nearly all cases.  For normal use it suffices
+ * to call only GC_MALLOC and perhaps GC_REALLOC.
+ * For better performance, also look at GC_MALLOC_ATOMIC, and
+ * GC_enable_incremental.  If you need an action to be performed
+ * immediately before an object is collected, look at GC_register_finalizer.
+ * If you are using Solaris threads, look at the end of this file.
+ * Everything else is best ignored unless you encounter performance
+ * problems.
+ */
  
 #ifndef _GC_H
 
 # define _GC_H
 
+# ifdef __cplusplus
+    extern "C" {
+# endif
+
 # include <stddef.h>
 
 /* Define word and signed_word to be unsigned and signed types of the  */
@@ -84,7 +100,7 @@ extern GC_word GC_free_space_divisor;
  * collectable.  GC_malloc_uncollectable and GC_free called on the resulting
  * object implicitly update GC_non_gc_bytes appropriately.
  */
-#if defined(__STDC__) || defined(__cplusplus)
+# 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);
@@ -108,7 +124,7 @@ extern GC_word GC_free_space_divisor;
 /* 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)
+# if defined(__STDC__) || defined(__cplusplus)
   extern void GC_free(void * object_addr);
 # else
   extern void GC_free(/* object_addr */);
@@ -170,10 +186,10 @@ void GC_end_stubborn_change(/* p */);
 /* Returns 0 on failure, 1 on success.  */
 extern int GC_expand_hp(/* number_of_bytes */);
 
-/* Clear the set of root segments */
+/* Clear the set of root segments.  Wizards only. */
 extern void GC_clear_roots(NO_PARAMS);
 
-/* Add a root segment */
+/* Add a root segment.  Wizards only. */
 extern void GC_add_roots(/* low_address, high_address_plus_1 */);
 
 /* Add a displacement to the set of those considered valid by the      */
@@ -188,7 +204,11 @@ extern void GC_add_roots(/* low_address, high_address_plus_1 */);
 /* 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 */);
+void GC_register_displacement(/* GC_word n */);
+
+/* The following version should be used if any debugging allocation is */
+/* being done.                                                         */
+void GC_debug_register_displacement(/* GC_word n */);
 
 /* Explicitly trigger a full, world-stop collection.   */
 void GC_gcollect(NO_PARAMS);
@@ -280,12 +300,17 @@ void GC_debug_end_stubborn_change(/* 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_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+       GC_register_finalizer_ignore_self( \
+             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)
 #   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
        GC_general_register_disappearing_link(link, GC_base(obj))
+#   define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n)
 # else
 #   define GC_MALLOC(sz) GC_malloc(sz)
 #   define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
@@ -294,11 +319,14 @@ void GC_debug_end_stubborn_change(/* p */);
 #   define GC_FREE(p) GC_free(p)
 #   define GC_REGISTER_FINALIZER(p, f, d, of, od) \
        GC_register_finalizer(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+       GC_register_finalizer_ignore_self(p, f, d, of, od)
 #   define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
 #   define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
 #   define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
 #   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
        GC_general_register_disappearing_link(link, obj)
+#   define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n)
 # endif
 /* The following are included because they are often convenient, and   */
 /* reduce the chance for a misspecifed size argument.  But calls may   */
@@ -364,6 +392,22 @@ void GC_debug_end_stubborn_change(/* p */);
        /* by cd will be considered accessible until the        */
        /* finalizer is invoked.                                */
 
+/* Another versions of the above follow.  It ignores           */
+/* self-cycles, i.e. pointers from a finalizable object to     */
+/* itself.  There is a stylistic argument that this is wrong,  */
+/* but it's unavoidable for C++, since the compiler may                */
+/* silently introduce these.  It's also benign in that specific        */
+/* case.                                                       */
+# if defined(__STDC__) || defined(__cplusplus)
+    void GC_register_finalizer_ignore_self(void * obj,
+                              GC_finalization_proc fn, void * cd,
+                              GC_finalization_proc *ofn, void ** ocd);
+# else 
+    void GC_register_finalizer_ignore_self(/* void * obj,
+                                 GC_finalization_proc fn, void * cd,
+                                 GC_finalization_proc *ofn, void ** ocd */);
+# endif
+
 /* 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     */
@@ -395,8 +439,10 @@ int GC_general_register_disappearing_link(/* void ** link, void * obj */);
        /* 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           */
+       /* holding a disguised pointer to obj.  (A pointer      */
+       /* inside an "atomic" object is effectively             */
+       /* disguised.)   In this way soft                       */
+       /* pointers are broken before any object                */
        /* reachable from them are finalized.  Each link        */
        /* May be registered only once, i.e. with one obj       */
        /* value.  This was added after a long email discussion */
@@ -427,6 +473,9 @@ int GC_unregister_disappearing_link(/* void ** link */);
 /* that finalization code will arrange for hidden pointers to  */
 /* disappear.  Otherwise objects can be accessed after they    */
 /* have been collected.                                                */
+/* Note that putting pointers in atomic objects or in          */
+/* nonpointer slots of "typed" objects is equivalent to        */
+/* disguising them in this way, and may have other advantages. */
 # ifdef I_HIDE_POINTERS
 #   if defined(__STDC__) || defined(__cplusplus)
 #     define HIDE_POINTER(p) (~(size_t)(p))
@@ -448,6 +497,76 @@ int GC_unregister_disappearing_link(/* void ** link */);
 #   endif
 # endif
 
+/* Check that p and q point to the same object.                */
+/* Fail conspicuously if they don't.                           */
+/* Returns the first argument.                                 */
+/* Succeeds if neither p nor q points to the heap.             */
+/* May succeed if both p and q point to between heap objects.  */
+#ifdef __STDC__
+  void * GC_same_obj(register void *p, register void *q);
+#else
+  char * GC_same_obj(/* char * p, char * q */);
+#endif
+
+/* Check that p is visible                                             */
+/* to the collector as a possibly pointer containing location.         */
+/* If it isn't fail conspicuously.                                     */
+/* Returns the argument in all cases.  May erroneously succeed         */
+/* in hard cases.  (This is intended for debugging use with            */
+/* untyped allocations.  The idea is that it should be possible, though        */
+/* slow, to add such a call to all indirect pointer stores.)           */
+/* Currently useless for multithreaded worlds.                         */
+#ifdef __STDC__
+  void * GC_is_visible(void *p);
+#else
+  char *GC_is_visible(/* char * p */);
+#endif
+
+/* Check that if p is a pointer to a heap page, then it points to      */
+/* a valid displacement within a heap object.                          */
+/* Fail conspicuously if this property does not hold.                  */
+/* Uninteresting with ALL_INTERIOR_POINTERS.                           */
+/* Always returns its argument.                                                */
+#ifdef __STDC__
+  void * GC_is_valid_displacement(void *p);
+#else
+  char *GC_is_valid_displacement(/* char * p */);
+#endif
+
+/* Safer, but slow, pointer addition.  Probably useful mainly with     */
+/* a preprocessor.  Useful only for heap pointers.                     */
+#ifdef GC_DEBUG
+#   define GC_PTR_ADD3(x, n, type_of_result) \
+       ((type_of_result)GC_same_obj((x)+(n), (x)))
+#   ifdef __GNUC__
+#       define GC_PTR_ADD(x, n) \
+           ((typeof(x))GC_same_obj((x)+(n), (x)))
+#   else
+       /* We can't do this right without typeof, which ANSI    */
+       /* decided was not sufficiently useful.  Repeatedly     */
+       /* mentioning the arguments seems too dangerous to be   */
+       /* useful.  So does not casting the result.             */
+#      define GC_PTR_ADD(x, n) ((x)+(n))
+#   endif
+#else  /* !GC_DEBUG */
+#   define GC_PTR_ADD3(x, n, type_of_result) ((x)+(n))
+#   define GC_PTR_ADD(x, n) ((x)+(n))
+#endif
+
+/* Safer assignment of a pointer to a nonstack location.       */
+#ifdef GC_DEBUG
+# ifdef __STDC__
+#   define GC_PTR_STORE(p, q) \
+       (*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# else
+#   define GC_PTR_STORE(p, q) \
+       (*(char **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# endif
+#else /* !GC_DEBUG */
+#   define GC_PTR_STORE(p, q) *((p) = (q))
+#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.                        */
@@ -480,4 +599,21 @@ void * GC_malloc_many(size_t lb);
 
 #endif /* SOLARIS_THREADS */
 
+/*
+ * If you are planning on putting
+ * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
+ * from the statically loaded program section.
+ * This circumvents a Solaris 2.X (X<=4) linker bug.
+ */
+#ifdef sparc
+#   define GC_INIT() { extern end, etext; \
+                      GC_noop(&end, &etext); }
+#else
+#   define GC_INIT()
+#endif
+
+#ifdef __cplusplus
+    }  /* end of extern "C" */
+#endif
+
 #endif /* _GC_H */
diff --git a/gc_c++.h b/gc_c++.h
deleted file mode 100644 (file)
index d9d703b..0000000
--- a/gc_c++.h
+++ /dev/null
@@ -1,173 +0,0 @@
-
-/****************************************************************************
-
-Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
-THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
-Permission is hereby granted to use or copy this program
-for any purpose,  provided the above notices are retained on all copies.
-Permission to modify the code and to distribute modified code is granted,
-provided the above notices are retained, and a notice that the code was
-modified is included with the above copyright notice.
-
-C++ Interface to the Boehm Collector
-
-    Jesse Hull and John Ellis
-    Last modified on Tue Feb 15 14:43:02 PST 1994 by ellis
-
-This interface provides access to the Boehm collector (versions 3.6
-and later).  It is intended to provide facilities similar to those
-described in the Ellis-Detlefs proposal for C++ garbage collection.
-
-To make a class collectable, derive it from the base class "gc":
-
-    class MyClass: gc {...}
-
-Then, "new MyClass" will allocate intances that will be automatically
-garbage collected.
-
-Collected objects can be explicitly deleted with "delete", e.g.
-
-    MyClass* m = ...;
-    delete m;
-
-This will free the object's storage immediately.
-
-Collected instances of non-class types can be allocated using
-placement syntax with the argument "GC":
-
-    typedef int A[ 10 ];
-    A* a = new (GC) A;
-
-The built-in "operator new" continues to allocate non-collectible
-objects that the programmer must explicitly delete.  Collected object
-may freely point at non-collected objects, and vice versa.
-
-Object clean-up (finalization) can be specified using class
-"gc_cleanup".  When an object derived from "gc_cleanup" is discovered
-to be inaccessible by the collector, or when it is explicitly deleted,
-its destructors will be invoked first.
-
-Clean-up functions for non-class types can be specified as additional
-placement arguments:
-
-    A* a = new (GC, MyCleanup) A;
-
-An object is considered "accessible" by the collector if it can be
-reached by a path of pointers from static variables, automatic
-variables of active functions, or from another object with clean-up
-enabled.  This implies that if object A and B both have clean-up
-enabled, and A points at B, B will be considered accessible, and A's
-clean-up will be be invoked before B's.  If A points at B and B points
-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
-#define GC_CPP_H
-
-extern "C" {
-#include "gc.h"
-}
-
-enum GCPlacement {GC, NoGC};
-
-class gc {
-public:
-    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
-    specified. */
-
-class gc_cleanup: public gc {
-public:
-    inline gc_cleanup();
-    inline virtual ~gc_cleanup();
-private:
-    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
-    discovers an instance is inaccessible (see above) or when the
-    instance is explicitly deleted, its destructors will be invoked.
-    NOTE: Only one instance of "gc_cleanup" should occur in the
-    inheritance heirarchy -- i.e. it should always be a virtual
-    base. */
-
-inline void* operator new( 
-    size_t size, 
-    GCPlacement gcp,
-    void (*cleanup)( void*, void* ) = 0,
-    void* clientData = 0 );
-    /*
-    If "gcp = GC", then this "operator new" allocates in the collected
-    heap, otherwise in the non-collected heap.  When the allocated
-    object "obj" becomes inaccessible, the collector will invoke the
-    function "cleanup( obj, clientData )".  It is an error to specify
-    a non-null "cleanup" when "gcp = NoGC". */
-
-/****************************************************************************
-
-Inline implementation
-
-****************************************************************************/
-
-inline void* gc::operator new( size_t size ) {
-    return GC_MALLOC( size ); }
-    
-inline void* gc::operator new( size_t size, GCPlacement gcp ) {
-    if (gcp == GC) 
-        return GC_MALLOC( size );
-    else
-        return GC_MALLOC_UNCOLLECTABLE( size ); }
-
-inline void gc::operator delete( void* obj ) {
-    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* ),
-    void* clientData )
-{
-    void* obj;
-
-    if (gcp == GC) {
-        obj = GC_MALLOC( size );
-        if (cleanup != 0) 
-            GC_REGISTER_FINALIZER( obj, cleanup, clientData, 0, 0 ); }
-    else {
-        obj = GC_MALLOC_UNCOLLECTABLE( size ); };
-    return obj; }
-        
-
-#endif
-
similarity index 66%
rename from gc_c++.cc
rename to gc_cpp.cc
index 592d91da58dc90dbf14c79554f0e0086445ef35e..a766a01a328ce168f14db6d04f90c27e4f27adb5 100644 (file)
--- a/gc_c++.cc
+++ b/gc_cpp.cc
@@ -1,11 +1,12 @@
 /*************************************************************************
-
-
 Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
  
 THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  
+    Last modified on Sat Nov 19 19:31:14 PST 1994 by ellis
+                  on Sat Jun  8 15:10:00 PST 1994 by boehm
+
 Permission is hereby granted to copy this code for any purpose,
 provided the above notices are retained on all copies.
 
@@ -18,18 +19,28 @@ 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
+Authors: John R. Ellis and Jesse Hull
 
 **************************************************************************/
-/* Boehm, June 8, 1994 3:10 pm PDT */
+/* Boehm, December 20, 1994 7:26 pm PST */
 
-#include "gc_c++.h"
+#include "gc_cpp.h"
 
 void* operator new( size_t size ) {
-    return GC_MALLOC_UNCOLLECTABLE( size ); }
+    return GC_MALLOC_UNCOLLECTABLE( size );}
   
 void operator delete( void* obj ) {
-    GC_FREE( obj ); }
+    GC_FREE( obj );}
   
 
+#ifdef OPERATOR_NEW_ARRAY
+
+void* operator new[]( size_t size ) {
+    return GC_MALLOC_UNCOLLECTABLE( size );}
+  
+void operator delete[]( void* obj ) {
+    GC_FREE( obj );}
+
+#endif /* OPERATOR_NEW_ARRAY */
+
 
diff --git a/gc_cpp.h b/gc_cpp.h
new file mode 100644 (file)
index 0000000..86ad2ec
--- /dev/null
+++ b/gc_cpp.h
@@ -0,0 +1,267 @@
+#ifndef GC_CPP_H
+#define GC_CPP_H
+/****************************************************************************
+Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
+THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+Permission is hereby granted to use or copy this program for any
+purpose, provided the above notices are retained on all copies.
+Permission to modify the code and to distribute modified code is
+granted, provided the above notices are retained, and a notice that
+the code was modified is included with the above copyright notice.
+****************************************************************************
+
+C++ Interface to the Boehm Collector
+
+    John R. Ellis and Jesse Hull 
+    Last modified on Thu Dec  8 12:41:07 PST 1994 by ellis
+
+This interface provides access to the Boehm collector.  It provides
+basic facilities similar to those described in "Safe, Efficient
+Garbage Collection for C++", by John R. Elis and David L. Detlefs
+(ftp.parc.xerox.com:/pub/ellis/gc).
+
+All heap-allocated objects are either "collectable" or
+"uncollectable".  Programs must explicitly delete uncollectable
+objects, whereas the garbage collector will automatically delete
+collectable objects when it discovers them to be inaccessible.
+Collectable objects may freely point at uncollectable objects and vice
+versa.
+
+Objects allocated with the built-in "::operator new" are uncollectable.
+
+Objects derived from class "gc" are collectable.  For example:
+
+    class A: gc {...};
+    A* a = new A;       // a is collectable. 
+
+Collectable instances of non-class types can be allocated using the GC
+placement:
+
+    typedef int A[ 10 ];
+    A* a = new (GC) A;
+
+Uncollectable instances of classes derived from "gc" can be allocated
+using the NoGC placement:
+
+    class A: gc {...};
+    A* a = new (NoGC) A;   // a is uncollectable.
+
+Both uncollectable and collectable objects can be explicitly deleted
+with "delete", which invokes an object's destructors and frees its
+storage immediately.
+
+A collectable object may have a clean-up function, which will be
+invoked when the collector discovers the object to be inaccessible.
+An object derived from "gc_cleanup" or containing a member derived
+from "gc_cleanup" has a default clean-up function that invokes the
+object's destructors.  Explicit clean-up functions may be specified as
+an additional placement argument:
+
+    A* a = ::new (GC, MyCleanup) A;
+
+An object is considered "accessible" by the collector if it can be
+reached by a path of pointers from static variables, automatic
+variables of active functions, or from some object with clean-up
+enabled; pointers from an object to itself are ignored.
+
+Thus, if objects A and B both have clean-up functions, and A points at
+B, B is considered accessible.  After A's clean-up is invoked and its
+storage released, B will then become inaccessible and will have its
+clean-up invoked.  If A points at B and B points to A, forming a
+cycle, then that's considered a storage leak, and neither will be
+collectable.  See the interface gc.h for low-level facilities for
+handling such cycles of objects with clean-up.
+
+The collector cannot guarrantee that it will find all inaccessible
+objects.  In practice, it finds almost all of them.
+
+
+Cautions:
+
+1. Be sure the collector has been augmented with "make c++".
+
+2.  If your compiler supports the new "operator new[]" syntax, then
+add -DOPERATOR_NEW_ARRAY to the Makefile.
+
+If your compiler doesn't support "operator new[]", beware that an
+array of type T, where T is derived from "gc", will by default be
+allocated as an uncollectable object.  Use the explicit GC placement
+to make the array collectable.  For example:
+
+    class A: gc {...};
+    A* a1 = new A[ 10 ];        // uncollectable
+    A* a2 = new (GC) A[ 10 ];   // collectable
+
+3. Arrays of objects derived from "gc_cleanup" do not have default
+clean-up functions.  For example:
+
+    class A: gc_cleanup {...};
+    A* a = new (GC) A[ 10 ];
+
+The elements of "a" will not have their destructors invoked when the
+collector frees "a".  You must supply an explicit clean-up function
+for that to occur.
+
+4. Compiler bugs:
+
+    Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
+    destructors of classes derived from gc_cleanup won't be invoked.
+    You'll have to explicitly register a clean-up function with
+    new-placement syntax.
+
+    Evidently cfront 3.0 does not allow destructors to be explicitly
+    invoked using the ANSI-conforming syntax t->~T().  If you're using
+    cfront 3.0, you'll have to comment out the class gc_cleanup, which
+    uses explicit invocation.
+
+****************************************************************************/
+
+#include "gc.h"
+
+#ifndef THINK_CPLUS
+#define _cdecl
+#endif
+
+enum GCPlacement {GC, NoGC};
+
+class gc {public:
+    inline void* operator new( size_t size );
+    inline void* operator new( size_t size, GCPlacement gcp );
+    inline void operator delete( void* obj );
+
+#ifdef OPERATOR_NEW_ARRAY
+    inline void* operator new[]( size_t size );
+    inline void* operator new[]( size_t size, GCPlacement gcp );
+    inline void operator delete[]( void* obj );
+#endif /* OPERATOR_NEW_ARRAY */
+    };    
+    /*
+    Instances of classes derived from "gc" will be allocated in the 
+    collected heap by default, unless an explicit NoGC placement is
+    specified. */
+
+class gc_cleanup: virtual public gc {public:
+    inline gc_cleanup();
+    inline virtual ~gc_cleanup();
+private:
+    inline static void _cdecl cleanup( void* obj, void* clientData );};
+    /*
+    Instances of classes derived from "gc_cleanup" will be allocated
+    in the collected heap by default.  When the collector discovers an
+    inaccessible object derived from "gc_cleanup" or containing a
+    member derived from "gc_cleanup", its destructors will be
+    invoked. */
+
+extern "C" {typedef void (*GCCleanUpFunc)( void* obj, void* clientData );}
+
+inline void* operator new( 
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup = 0,
+    void* clientData = 0 );
+    /*
+    Allocates a collectable or uncollected object, according to the
+    value of "gcp".
+
+    For collectable objects, if "cleanup" is non-null, then when the
+    allocated object "obj" becomes inaccessible, the collector will
+    invoke the function "cleanup( obj, clientData )" but will not
+    invoke the object's destructors.  It is an error to explicitly
+    delete an object allocated with a non-null "cleanup".
+
+    It is an error to specify a non-null "cleanup" with NoGC or for
+    classes derived from "gc_cleanup" or containing members derived
+    from "gc_cleanup". */
+
+#ifdef OPERATOR_NEW_ARRAY
+
+inline void* operator new[](
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup = 0,
+    void* clientData = 0 );
+    /*
+    The operator new for arrays, identical to the above. */
+
+#endif /* OPERATOR_NEW_ARRAY */
+
+/****************************************************************************
+
+Inline implementation
+
+****************************************************************************/
+
+inline void* gc::operator new( size_t size ) {
+    return GC_MALLOC( size );}
+    
+inline void* gc::operator new( size_t size, GCPlacement gcp ) {
+    if (gcp == GC) 
+        return GC_MALLOC( size );
+    else
+        return GC_MALLOC_UNCOLLECTABLE( size );}
+
+inline void gc::operator delete( void* obj ) {
+    GC_FREE( obj );}
+    
+
+#ifdef OPERATOR_NEW_ARRAY
+
+inline void* gc::operator new[]( size_t size ) {
+    return gc::operator new( size );}
+    
+inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
+    return gc::operator new( size, gcp );}
+
+inline void gc::operator delete[]( void* obj ) {
+    gc::operator delete( obj );}
+    
+#endif /* OPERATOR_NEW_ARRAY */
+
+
+inline gc_cleanup::~gc_cleanup() {
+    GC_REGISTER_FINALIZER_IGNORE_SELF( 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_IGNORE_SELF( 
+        base, cleanup, (void*) ((char*) this - (char*) base), 0, 0 );}
+
+inline void* operator new( 
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup,
+    void* clientData )
+{
+    void* obj;
+
+    if (gcp == GC) {
+        obj = GC_MALLOC( size );
+        if (cleanup != 0) 
+            GC_REGISTER_FINALIZER_IGNORE_SELF( 
+                obj, cleanup, clientData, 0, 0 );}
+    else {
+        obj = GC_MALLOC_UNCOLLECTABLE( size );};
+    return obj;}
+        
+
+#ifdef OPERATOR_NEW_ARRAY
+
+inline void* operator new[]( 
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup,
+    void* clientData )
+{
+    return ::operator new( size, gcp, cleanup, clientData );}
+
+#endif /* OPERATOR_NEW_ARRAY */
+
+
+#endif /* GC_CPP_H */
+
index b1a7c37e785dda4a1eb8fcffd06f446f9ae65ee5..e01cf46a7848c3ef7c4896c2706b408add4661f5 100644 (file)
--- a/gc_mark.h
+++ b/gc_mark.h
@@ -11,7 +11,7 @@
  * modified is included with the above copyright notice.
  *
  */
-/* Boehm, May 19, 1994 2:15 pm PDT */
+/* Boehm, November 7, 1994 4:56 pm PST */
 
 /*
  * Declarations of mark stack.  Needed by marker and client supplied mark
@@ -21,7 +21,6 @@
 # define GC_MARK_H
 
 /* A client supplied mark procedure.  Returns new mark stack pointer.  */
-/* Not currently used for predefined object kinds.                     */
 /* Primary effect should be to push new entries on the mark stack.     */
 /* Mark stack pointer values are passed and returned explicitly.       */
 /* Global variables decribing mark stack are not necessarily valid.    */
@@ -35,7 +34,9 @@
 /* overflows.                                                          */
 /* This procedure is always called with at least one empty entry on the */
 /* mark stack.                                                         */
-/* Boehm, March 15, 1994 2:38 pm PST */
+/* Currently we require that mark procedures look for pointers in a    */
+/* subset of the places the conservative marker would.  It must be safe        */
+/* to invoke the normal mark procedure instead.                                */
 # define PROC_BYTES 100
 typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr,
                                          mark_stack_limit, env */);
@@ -160,6 +161,36 @@ mse * GC_signal_mark_stack_overflow();
             mark_stack_top, mark_stack_limit) \
 }
 
+/*
+ * Push a single value onto mark stack. Mark from the object pointed to by p.
+ * GC_push_one is normally called by GC_push_regs, and thus must be defined.
+ * P is considered valid even if it is an interior pointer.
+ * Previously marked objects are not pushed.  Hence we make progress even
+ * if the mark stack overflows.
+ */
+# define GC_PUSH_ONE_STACK(p) \
+    if ((ptr_t)(p) >= GC_least_plausible_heap_addr     \
+        && (ptr_t)(p) < GC_greatest_plausible_heap_addr) {     \
+        GC_push_one_checked(p,TRUE);   \
+    }
+
+/*
+ * As above, but interior pointer recognition as for
+ * normal for heap pointers.
+ */
+# ifdef ALL_INTERIOR_POINTERS
+#   define AIP TRUE
+# else
+#   define AIP FALSE
+# endif
+# define GC_PUSH_ONE_HEAP(p) \
+    if ((ptr_t)(p) >= GC_least_plausible_heap_addr     \
+        && (ptr_t)(p) < GC_greatest_plausible_heap_addr) {     \
+        GC_push_one_checked(p,AIP);    \
+    }
+
+
+
 extern bool GC_mark_stack_too_small;
                                /* We need a larger mark stack.  May be */
                                /* set by client supplied mark routines.*/
index d8fbb7268163d82f7a2a2418b94d7a1a73bd7fd6..d4cf878e6c1791a1eb55a9eef77e45fea26c65ed 100644 (file)
--- a/gc_priv.h
+++ b/gc_priv.h
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, July 28, 1994 10:35 am PDT */
+/* Boehm, November 8, 1994 5:49 pm PST */
  
 
 # ifndef GC_PRIVATE_H
 # define GC_PRIVATE_H
 
+#if defined(mips) && defined(SYSTYPE_BSD) && defined(sony_news)
+    /* sony RISC NEWS, NEWSOS 4 */
+#   define BSD_TIME
+    typedef long ptrdiff_t;
+#endif
+
+#if defined(mips) && defined(SYSTYPE_BSD43)
+    /* MIPS RISCOS 4 */
+#   define BSD_TIME
+#endif
+
+#ifdef BSD_TIME
+#   include <sys/types.h>
+#   include <sys/time.h>
+#   include <sys/resource.h>
+#endif /* BSD_TIME */
+
 # ifndef GC_H
 #   include "gc.h"
 # endif
@@ -151,7 +168,7 @@ typedef char * ptr_t;       /* A generic pointer to which we can add        */
 #   define THREADS
 # endif
 
-#ifdef SPARC
+#if defined(SPARC) || defined(HP_PA)
 #   define ALIGN_DOUBLE  /* Align objects of size > 1 word on 2 word   */
                         /* boundaries.  Wasteful of memory, but       */
                         /* apparently required by SPARC architecture. */
@@ -200,8 +217,9 @@ typedef char * ptr_t;       /* A generic pointer to which we can add        */
  * 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. */
+#   define NFRAMES 6   /* Number of frames to save. Even for           */
+                       /* alignment reasons.                           */
+#   define NARGS 2     /* Mumber of arguments to save for each call.   */
 
 
 #ifdef SAVE_CALL_CHAIN
@@ -225,27 +243,43 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
 /*                               */
 /*********************************/
 
-#include <time.h>
-#if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4)
-   clock_t clock();    /* Not in time.h, where it belongs      */
-#endif
-#if !defined(CLOCKS_PER_SEC)
-#   define CLOCKS_PER_SEC 1000000
+#ifdef BSD_TIME
+#   undef CLOCK_TYPE
+#   undef GET_TIME
+#   undef MS_TIME_DIFF
+#   define CLOCK_TYPE struct timeval
+#   define GET_TIME(x) { struct rusage rusage; \
+                        getrusage (RUSAGE_SELF,  &rusage); \
+                        x = rusage.ru_utime; }
+#   define MS_TIME_DIFF(a,b) ((double) (a.tv_sec - b.tv_sec) * 1000.0 \
+                               + (double) (a.tv_usec - b.tv_usec) / 1000.0)
+#else /* !BSD_TIME */
+#   include <time.h>
+#   if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4)
+      clock_t clock(); /* Not in time.h, where it belongs      */
+#   endif
+#   if defined(FREEBSD) && !defined(CLOCKS_PER_SEC)
+#     include <machine/limits.h>
+#     define CLOCKS_PER_SEC CLK_TCK
+#   endif
+#   if !defined(CLOCKS_PER_SEC)
+#     define CLOCKS_PER_SEC 1000000
 /*
  * This is technically a bug in the implementation.  ANSI requires that
  * CLOCKS_PER_SEC be defined.  But at least under SunOS4.1.1, it isn't.
  * Also note that the combination of ANSI C and POSIX is incredibly gross
  * here. The type clock_t is used by both clock() and times().  But on
- * some machines thes use different notions of a clock tick,  CLOCKS_PER_SEC
+ * some machines these use different notions of a clock tick,  CLOCKS_PER_SEC
  * seems to apply only to clock.  Hence we use it here.  On many machines,
  * including SunOS, clock actually uses units of microseconds (which are
  * not really clock ticks).
  */
-#endif
-#define CLOCK_TYPE clock_t
-#define GET_TIME(x) x = clock()
-#define MS_TIME_DIFF(a,b) ((unsigned long) \
+#   endif
+#   define CLOCK_TYPE clock_t
+#   define GET_TIME(x) x = clock()
+#   define MS_TIME_DIFF(a,b) ((unsigned long) \
                (1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC))
+#endif /* !BSD_TIME */
 
 /* We use bzero and bcopy internally.  They may not be available.      */
 # if defined(SPARC) && defined(SUNOS4)
@@ -396,9 +430,8 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
                PCR_Th_SetSigMask(&GC_old_sig_mask, NIL)
 # else
 #   if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \
-       || defined(MSWIN32) || defined(MACOS)
-                       /* Also useful for debugging, and unusually     */
-                       /* correct client code.                         */
+       || defined(MSWIN32) || defined(MACOS) || defined(NO_SIGNALS)
+                       /* Also useful for debugging.           */
        /* Should probably use thr_sigsetmask for SOLARIS_THREADS. */
 #     define DISABLE_SIGNALS()
 #     define ENABLE_SIGNALS()
@@ -465,14 +498,20 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
 #  define WORDS_TO_BYTES(x)   ((x)<<2)
 #  define BYTES_TO_WORDS(x)   ((x)>>2)
 #  define LOGWL               ((word)5)    /* log[2] of CPP_WORDSZ */
-#  define modWORDSZ(n) ((n) & 0x1f)          /* n mod size of word         */
+#  define modWORDSZ(n) ((n) & 0x1f)        /* n mod size of word           */
+#  if ALIGNMENT != 4
+#      define UNALIGNED
+#  endif
 #endif
 
 #if CPP_WORDSZ == 64
 #  define WORDS_TO_BYTES(x)   ((x)<<3)
 #  define BYTES_TO_WORDS(x)   ((x)>>3)
 #  define LOGWL               ((word)6)    /* log[2] of CPP_WORDSZ */
-#  define modWORDSZ(n) ((n) & 0x3f)          /* n mod size of word         */
+#  define modWORDSZ(n) ((n) & 0x3f)        /* n mod size of word           */
+#  if ALIGNMENT != 8
+#      define UNALIGNED
+#  endif
 #endif
 
 #define WORDSZ ((word)CPP_WORDSZ)
@@ -994,6 +1033,9 @@ bool GC_stopped_mark(); /* Stop world and mark from all roots      */
                        /* and rescuers.                        */
 void GC_clear_hdr_marks(/* hhdr */);  /* Clear the mark bits in a header */
 void GC_add_roots_inner();
+bool GC_is_static_root(/* ptr_t p */);
+               /* Is the address p in one of the registered static     */
+               /* root sections?                                       */
 void GC_register_dynamic_libraries();
                /* Add dynamic library data sections to the root set. */
 
index 696362d91dabf5057aeb8555e0674ecb49bfb5b8..9fac0bf0f78016437d36d05e2e649996e01013d8 100644 (file)
--- 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, June 8, 1994 12:27 pm PDT */
+/* Boehm, October 7, 1994 9:54 pm PDT */
  
 /*
  * This implements:
@@ -229,7 +229,7 @@ word client_data;
              } else if (index_p->index[j] == 0) {
                 j--;
              } else {
-                j -= (int)(index_p->index[j]);
+                j -= (word)(index_p->index[j]);
              }
          }
      }
index 7359a4f78bd60db0aaaeb637ff26cb65383be1ca..f339ab3e66d460c246f1ac92866b02f6cc6cd36d 100644 (file)
--- a/if_mach.c
+++ b/if_mach.c
@@ -1,4 +1,5 @@
 /* Conditionally execute a command based on machine and OS from config.h */
+/* Boehm, November 21, 1994 1:40 pm PST */
 # include "config.h"
 # include <stdio.h>
 
@@ -12,6 +13,7 @@ char ** envp;
     if (strcmp(OS_TYPE, "") != 0 && strcmp(argv[2], "") != 0
         && strcmp(OS_TYPE, argv[2]) != 0) return(0);
     execvp(argv[3], argv+3);
+    perror("Couldn't execute");
     
 Usage:
     fprintf(stderr, "Usage: %s mach_type os_type command\n", argv[0]);
diff --git a/include/cord.h b/include/cord.h
new file mode 100644 (file)
index 0000000..405a051
--- /dev/null
@@ -0,0 +1,321 @@
+/* 
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ * Author: Hans-J. Boehm (boehm@parc.xerox.com)
+ */
+/* Boehm, October 4, 1994 5:34 pm PDT */
+/*
+ * Cords are immutable character strings.  A number of operations
+ * on long cords are much more efficient than their strings.h counterpart.
+ * In particular, concatenation takes constant time independent of the length
+ * of the arguments.  (Cords are represented as trees, with internal
+ * nodes representing concatenation and leaves consisting of either C
+ * strings or a functional description of the string.)
+ *
+ * The following are reasonable applications of cords.  They would perform
+ * unacceptably if C strings were used:
+ * - A compiler that produces assembly language output by repeatedly
+ *   concatenating instructions onto a cord representing the output file.
+ * - A text editor that converts the input file to a cord, and then
+ *   performs editing operations by producing a new cord representing
+ *   the file after echa character change (and keeping the old ones in an
+ *   edit history)
+ *
+ * For optimal performance, cords should be built by
+ * concatenating short sections.
+ * This interface is designed for maximum compatibility with C strings.
+ * ASCII NUL characters may be embedded in cords using CORD_from_fn.
+ * This is handled correctly, but CORD_to_char_star will produce a string
+ * with embedded NULs when given such a cord. 
+ *
+ * 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_star(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
+
+# define CORD_H
+# include <stddef.h>
+# include <stdio.h>
+/* Cords have type const char *.  This is cheating quite a bit, and not        */
+/* 100% portable.  But it means that nonempty character string         */
+/* constants may be used as cords directly, provided the string is     */
+/* never modified in place.  The empty cord is represented by, and     */
+/* can be written as, 0.                                               */
+
+typedef const char * CORD;
+
+/* An empty cord is always represented as nil  */
+# define CORD_EMPTY 0
+
+/* Is a nonempty cord represented as a C string? */
+#define CORD_IS_STRING(s) (*(s) != '\0')
+
+/* Concatenate two cords.  If the arguments are C strings, they may    */
+/* not be subsequently altered.                                                */
+CORD CORD_cat(CORD x, CORD y);
+
+/* Concatenate a cord and a C string with known length.  Except for the        */
+/* empty string case, this is a special case of CORD_cat.  Since the   */
+/* length is known, it can be faster.                                  */
+CORD CORD_cat_char_star(CORD x, const char * y, size_t leny);
+
+/* Compute the length of a cord */
+size_t CORD_len(CORD x);
+
+/* Cords may be represented by functions defining the ith character */
+typedef char (* CORD_fn)(size_t i, void * client_data);
+
+/* Turn a functional description into a cord.  */
+CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len);
+
+/* Return the substring (subcord really) of x with length at most n,   */
+/* starting at position i.  (The initial character has position 0.)    */
+CORD CORD_substr(CORD x, size_t i, size_t n);
+
+/* Return the argument, but rebalanced to allow more efficient         */
+/* character retrieval, substring operations, and comparisons.         */
+/* This is useful only for cords that were built using repeated        */
+/* concatenation.  Guarantees log time access to the result, unless    */
+/* x was obtained through a large number of repeated substring ops     */
+/* or the embedded functional descriptions take longer to evaluate.    */
+/* May reallocate significant parts of the cord.  The argument is not  */
+/* modified; only the result is balanced.                              */
+CORD CORD_balance(CORD x);
+
+/* The following traverse a cord by applying a function to each        */
+/* character.  This is occasionally appropriate, especially where      */
+/* speed is crucial.  But, since C doesn't have nested functions,      */
+/* clients of this sort of traversal are clumsy to write.  Consider    */
+/* the functions that operate on cord positions instead.               */
+
+/* Function to iteratively apply to individual characters in cord.     */
+typedef int (* CORD_iter_fn)(char c, void * client_data);
+
+/* Function to apply to substrings of a cord.  Each substring is a     */
+/* a C character string, not a general cord.                           */
+typedef int (* CORD_batched_iter_fn)(const char * s, void * client_data);
+# define CORD_NO_FN ((CORD_batched_iter_fn)0)
+
+/* Apply f1 to each character in the cord, in ascending order,         */
+/* starting at position i. If                                          */
+/* f2 is not CORD_NO_FN, then multiple calls to f1 may be replaced by  */
+/* a single call to f2.  The parameter f2 is provided only to allow    */
+/* some optimization by the client.  This terminates when the right    */
+/* end of this string is reached, or when f1 or f2 return != 0.  In the        */
+/* latter case CORD_iter returns != 0.  Otherwise it returns 0.                */
+/* The specified value of i must be < CORD_len(x).                     */
+int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
+              CORD_batched_iter_fn f2, void * client_data);
+
+/* A simpler version that starts at 0, and without f2: */
+int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data);
+# define CORD_iter(x, f1, cd) CORD_iter5(x, 0, f1, CORD_NO_FN, cd)
+
+/* Similar to CORD_iter5, but end-to-beginning.        No provisions for       */
+/* CORD_batched_iter_fn.                                               */
+int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data);
+
+/* A simpler version that starts at the end:   */
+int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
+
+/* Functions that operate on cord positions.  The easy way to traverse */
+/* cords.  A cord position is logically a pair consisting of a cord    */
+/* and an index into that cord.  But it is much faster to retrieve a   */
+/* charcter based on a position than on an index.  Unfortunately,      */
+/* positions are big (order of a few 100 bytes), so allocate them with */
+/* caution.                                                            */
+/* Things in cord_pos.h should be treated as opaque, except as         */
+/* described below.  Also note that                                    */
+/* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function        */
+/* definitions.  The former may evaluate their argument more than once. */
+# include "cord_pos.h"
+
+/*
+       Visible definitions from above:
+       
+       typedef <OPAQUE but fairly big> CORD_pos[1];
+       
+       /* Extract the cord from a position:
+       CORD CORD_pos_to_cord(CORD_pos p);
+       
+       /* Extract the current index from a position:
+       size_t CORD_pos_to_index(CORD_pos p);
+       
+       /* Fetch the character located at the given position:
+       char CORD_pos_fetch(CORD_pos p);
+       
+       /* Initialize the position to refer to the given cord and index.
+       /* Note that this is the most expensive function on positions:
+       void CORD_set_pos(CORD_pos p, CORD x, size_t i);
+       
+       /* Advance the position to the next character.
+       /* P must be initialized and valid.
+       /* Invalidates p if past end:
+       void CORD_next(CORD_pos p);
+       
+       /* Move the position to the preceding character.
+       /* P must be initialized and valid.
+       /* Invalidates p if past beginning:
+       void CORD_prev(CORD_pos p);
+       
+       /* Is the position valid, i.e. inside the cord?
+       int CORD_pos_valid(CORD_pos p);
+*/
+# define CORD_FOR(pos, cord) \
+    for (CORD_set_pos(pos, cord, 0); CORD_pos_valid(pos); CORD_next(pos))
+
+                       
+/* An out of memory handler to call.  May be supplied by client.       */
+/* Must not return.                                                    */
+extern void (* CORD_oom_fn)(void);
+
+/* Dump the representation of x to stdout in an implementation defined */
+/* manner.  Intended for debugging only.                               */
+void CORD_dump(CORD x);
+
+/* The following could easily be implemented by the client.  They are  */
+/* provided in cord_xtra.c for convenience.                            */
+
+/* Concatenate a character to the end of a cord.       */
+CORD CORD_cat_char(CORD x, char c);
+
+/* Concatenate n cords.        */
+CORD CORD_catn(int n, /* CORD */ ...);
+
+/* Return the character in CORD_substr(x, i, 1)        */
+char CORD_fetch(CORD x, size_t i);
+
+/* Return < 0, 0, or > 0, depending on whether x < y, x = y, x > y     */
+int CORD_cmp(CORD x, CORD y);
+
+/* A generalization that takes both starting positions for the                 */
+/* comparison, and a limit on the number of characters to be compared. */
+int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len);
+
+/* Find the first occurrence of s in x at position start or later.     */
+/* Return the position of the first character of s in x, or            */
+/* CORD_NOT_FOUND if there is none.                                    */
+size_t CORD_str(CORD x, size_t start, CORD s);
+
+/* Return a cord consisting of i copies of (possibly NUL) c.  Dangerous        */
+/* in conjunction with CORD_to_char_star.                              */
+/* The resulting representation takes constant space, independent of i.        */
+CORD CORD_chars(char c, size_t i);
+# define CORD_nul(i) CORD_chars('\0', (i))
+
+/* Turn a file into cord.  The file must be seekable.  Its contents    */
+/* must remain constant.  The file may be accessed as an immediate     */
+/* result of this call and/or as a result of subsequent accesses to    */
+/* the cord.  Short files are likely to be immediately read, but       */
+/* long files are likely to be read on demand, possibly relying on     */
+/* stdio for buffering.                                                        */
+/* We must have exclusive access to the descriptor f, i.e. we may      */
+/* read it at any time, and expect the file pointer to be              */
+/* where we left it.  Normally this should be invoked as               */
+/* CORD_from_file(fopen(...))                                          */
+/* CORD_from_file arranges to close the file descriptor when it is no  */
+/* longer needed (e.g. when the result becomes inaccessible).          */ 
+/* The file f must be such that ftell reflects the actual character    */
+/* position in the file, i.e. the number of characters that can be     */
+/* or were read with fread.  On UNIX systems this is always true.  On  */
+/* MS Windows systems, f must be opened in binary mode.                        */
+CORD CORD_from_file(FILE * f);
+
+/* Equivalent to the above, except that the entire file will be read   */
+/* and the file pointer will be closed immediately.                    */
+/* The binary mode restriction from above does not apply.              */
+CORD CORD_from_file_eager(FILE * f);
+
+/* Equivalent to the above, except that the file will be read on demand.*/
+/* The binary mode restriction applies.                                        */
+CORD CORD_from_file_lazy(FILE * f);
+
+/* Turn a cord into a C string.        The result shares no structure with     */
+/* x, and is thus modifiable.                                          */
+char * CORD_to_char_star(CORD x);
+
+/* Identical to the above, but the result may share structure with     */
+/* the argument and is thus not modifiable.                            */
+const char * CORD_to_const_char_star(CORD x); 
+
+/* Write a cord to a file, starting at the current position.  No       */
+/* trailing NULs are newlines are added.                               */
+/* Returns EOF if a write error occurs, 1 otherwise.                   */
+int CORD_put(CORD x, FILE * f);
+
+/* "Not found" result for the following two functions.                 */
+# define CORD_NOT_FOUND ((size_t)(-1))
+
+/* A vague analog of strchr.  Returns the position (an integer, not    */
+/* a pointer) of the first occurrence of (char) c inside x at position         */
+/* i or later. The value i must be < CORD_len(x).                      */
+size_t CORD_chr(CORD x, size_t i, int c);
+
+/* A vague analog of strrchr.  Returns index of the last occurrence    */
+/* of (char) c inside x at position i or earlier. The value i          */
+/* must be < CORD_len(x).                                              */
+size_t CORD_rchr(CORD x, size_t i, int c);
+
+
+/* The following are also not primitive, but are implemented in        */
+/* cordprnt.c.  They provide functionality similar to the ANSI C       */
+/* functions with corresponding names, but with the following          */
+/* additions and changes:                                              */
+/* 1. A %r conversion specification specifies a CORD argument.  Field  */
+/*    width, precision, etc. have the same semantics as for %s.                */
+/*    (Note that %c,%C, and %S were already taken.)                    */
+/* 2. The format string is represented as a CORD.                      */
+/* 3. CORD_sprintf and CORD_vsprintf assign the result through the 1st */      /*    argument. Unlike their ANSI C versions, there is no need to guess */
+/*    the correct buffer size.                                         */
+/* 4. Most of the conversions are implement through the native                 */
+/*    vsprintf.  Hence they are usually no faster, and                         */
+/*    idiosyncracies of the native printf are preserved.  However,     */
+/*    CORD arguments to CORD_sprintf and CORD_vsprintf are NOT copied; */
+/*    the result shares the original structure.  This may make them    */
+/*    very efficient in some unusual applications.                     */
+/*    The format string is copied.                                     */
+/* All functions return the number of characters generated or -1 on    */
+/* error.  This complies with the ANSI standard, but is inconsistent   */
+/* with some older implementations of sprintf.                         */
+
+/* The implementation of these is probably less portable than the rest */
+/* of this package.                                                    */
+
+#ifndef CORD_NO_IO
+
+#include <stdarg.h>
+
+int CORD_sprintf(CORD * out, CORD format, ...);
+int CORD_vsprintf(CORD * out, CORD format, va_list args);
+int CORD_fprintf(FILE * f, CORD format, ...);
+int CORD_vfprintf(FILE * f, CORD format, va_list args);
+int CORD_printf(CORD format, ...);
+int CORD_vprintf(CORD format, va_list args);
+
+#endif /* CORD_NO_IO */
+
+# endif /* CORD_H */
diff --git a/include/ec.h b/include/ec.h
new file mode 100644 (file)
index 0000000..c829b83
--- /dev/null
@@ -0,0 +1,70 @@
+# ifndef EC_H
+# define EC_H
+
+# ifndef CORD_H
+#  include "cord.h"
+# endif
+
+/* Extensible cords are strings that may be destructively appended to. */
+/* They allow fast construction of cords from characters that are      */
+/* being read from a stream.                                           */
+/*
+ * A client might look like:
+ *
+ *     {
+ *         CORD_ec x;
+ *         CORD result;
+ *         char c;
+ *         FILE *f;
+ *
+ *         ...
+ *         CORD_ec_init(x);
+ *         while(...) {
+ *             c = getc(f);
+ *             ...
+ *             CORD_ec_append(x, c);
+ *         }
+ *         result = CORD_balance(CORD_ec_to_cord(x));
+ *
+ * If a C string is desired as the final result, the call to CORD_balance
+ * may be replaced by a call to CORD_to_char_star.
+ */
+
+# ifndef CORD_BUFSZ
+#   define CORD_BUFSZ 128
+# endif
+
+typedef struct CORD_ec_struct {
+    CORD ec_cord;
+    char * ec_bufptr;
+    char ec_buf[CORD_BUFSZ+1];
+} CORD_ec[1];
+
+/* This structure represents the concatenation of ec_cord with         */
+/* ec_buf[0 ... (ec_bufptr-ec_buf-1)]                                  */
+
+/* Flush the buffer part of the extended chord into ec_cord.   */
+/* Note that this is almost the only real function, and it is  */
+/* implemented in 6 lines in cordxtra.c                                */
+void CORD_ec_flush_buf(CORD_ec x);
+      
+/* Convert an extensible cord to a cord. */
+# define CORD_ec_to_cord(x) (CORD_ec_flush_buf(x), (x)[0].ec_cord)
+
+/* Initialize an extensible cord. */
+# define CORD_ec_init(x) ((x)[0].ec_cord = 0, (x)[0].ec_bufptr = (x)[0].ec_buf)
+
+/* Append a character to an extensible cord.   */
+# define CORD_ec_append(x, c) \
+    {  \
+       if ((x)[0].ec_bufptr == (x)[0].ec_buf + CORD_BUFSZ) { \
+               CORD_ec_flush_buf(x); \
+       } \
+       *((x)[0].ec_bufptr)++ = (c); \
+    }
+
+/* Append a cord to an extensible cord.  Structure remains shared with         */
+/* original.                                                           */
+void CORD_ec_append_cord(CORD_ec x, CORD s);
+
+# endif /* EC_H */
index 8c3560ddd8d63e135a5127e3289deaac709c8ebb..1827162bc4bf35c4cafd6fa846a1df385d2a2fea 100644 (file)
@@ -1,17 +1,37 @@
 /* 
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
- * Copyright (c) 1991 by Xerox Corporation.  All rights reserved.
+ * 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 copy this garbage collector for any purpose,
- * provided the above notices are retained on all copies.
+ * 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, December 7, 1994 12:09 pm PST */
+
+/*
+ * Note that this defines a large number of tuning hooks, which can
+ * safely be ignored in nearly all cases.  For normal use it suffices
+ * to call only GC_MALLOC and perhaps GC_REALLOC.
+ * For better performance, also look at GC_MALLOC_ATOMIC, and
+ * GC_enable_incremental.  If you need an action to be performed
+ * immediately before an object is collected, look at GC_register_finalizer.
+ * If you are using Solaris threads, look at the end of this file.
+ * Everything else is best ignored unless you encounter performance
+ * problems.
  */
  
-#ifndef GC_H
+#ifndef _GC_H
 
-# define GC_H
+# define _GC_H
+
+# ifdef __cplusplus
+    extern "C" {
+# endif
 
 # include <stddef.h>
 
@@ -28,13 +48,9 @@ typedef long GC_signed_word;
 
 /* Public read-only variables */
 
-extern GC_word GC_heapsize;       /* Heap size in bytes */
-
 extern GC_word GC_gc_no;/* Counter incremented per collection.         */
                        /* Includes empty GCs at startup.               */
                        
-extern int GC_incremental;  /* Using incremental/generational collection. */
-
 
 /* Public R/W variables */
 
@@ -67,9 +83,10 @@ extern GC_word GC_free_space_divisor;
                        /* Increasing its value will use less space     */
                        /* but more collection time.  Decreasing it     */
                        /* will appreciably decrease collection time    */
-                       /* at the expens of space.                      */
+                       /* at the expense of space.                     */
                        /* GC_free_space_divisor = 1 will effectively   */
                        /* disable collections.                         */
+
                        
 /* Public procedures */
 /*
@@ -83,7 +100,7 @@ extern GC_word GC_free_space_divisor;
  * collectable.  GC_malloc_uncollectable and GC_free called on the resulting
  * object implicitly update GC_non_gc_bytes appropriately.
  */
-#if defined(__STDC__) || defined(__cplusplus)
+# 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);
@@ -95,12 +112,19 @@ 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. */
 /* An object should not be enable for finalization when it is          */
 /* explicitly deallocated.                                             */
-#if defined(__STDC__) || defined(__cplusplus)
+/* 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 */);
@@ -150,6 +174,7 @@ void GC_end_stubborn_change(/* p */);
 /* 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
@@ -159,12 +184,12 @@ void GC_end_stubborn_change(/* p */);
 
 /* Explicitly increase the heap size.  */
 /* Returns 0 on failure, 1 on success.  */
-extern int GC_expand_hp(/* number_of_4K_blocks */);
+extern int GC_expand_hp(/* number_of_bytes */);
 
-/* Clear the set of root segments */
-extern void GC_clear_roots();
+/* Clear the set of root segments.  Wizards only. */
+extern void GC_clear_roots(NO_PARAMS);
 
-/* Add a root segment */
+/* Add a root segment.  Wizards only. */
 extern void GC_add_roots(/* low_address, high_address_plus_1 */);
 
 /* Add a displacement to the set of those considered valid by the      */
@@ -177,17 +202,63 @@ extern void GC_add_roots(/* low_address, high_address_plus_1 */);
 /* Preferably, this should be called before any other GC procedures.   */
 /* Calling it later adds to the probability of excess memory           */
 /* retention.                                                          */
-void GC_register_displacement(/* n */);
+/* 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(/* GC_word n */);
 
-/* Explicitly trigger a collection.    */
-void GC_gcollect();
+/* The following version should be used if any debugging allocation is */
+/* being done.                                                         */
+void GC_debug_register_displacement(/* GC_word 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.             */
-void GC_enable_incremental();
+/* 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.                  */
@@ -229,10 +300,17 @@ void GC_debug_end_stubborn_change(/* 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_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+       GC_register_finalizer_ignore_self( \
+             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)
+#   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+       GC_general_register_disappearing_link(link, GC_base(obj))
+#   define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n)
 # else
 #   define GC_MALLOC(sz) GC_malloc(sz)
 #   define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
@@ -241,9 +319,14 @@ void GC_debug_end_stubborn_change(/* p */);
 #   define GC_FREE(p) GC_free(p)
 #   define GC_REGISTER_FINALIZER(p, f, d, of, od) \
        GC_register_finalizer(p, f, d, of, od)
+#   define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
+       GC_register_finalizer_ignore_self(p, f, d, of, od)
 #   define GC_MALLOC_STUBBORN(sz) GC_malloc_stubborn(sz)
 #   define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
 #   define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
+#   define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
+       GC_general_register_disappearing_link(link, obj)
+#   define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n)
 # endif
 /* The following are included because they are often convenient, and   */
 /* reduce the chance for a misspecifed size argument.  But calls may   */
@@ -252,7 +335,7 @@ void GC_debug_end_stubborn_change(/* p */);
 # 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_NEW_UNCOLLECTABLE(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                */
@@ -266,10 +349,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    */
@@ -281,10 +370,7 @@ void GC_register_finalizer(/* void * obj,
        /* pointers will not be finalized (or collected).       */
        /* Thus cycles involving finalizable objects should     */
        /* be avoided, or broken by disappearing links.         */
-       /* fn is invoked with the allocation lock held.  It may */
-       /* not allocate.  (Any storage it might need            */
-       /* should be preallocated and passed as part of cd.)    */
-       /* fn should terminate as quickly as possible, and      */
+       /* Fn should terminate as quickly as possible, and      */
        /* defer extended computation.                          */
        /* All but the last finalizer registered for an object  */
        /* is ignored.                                          */
@@ -296,6 +382,31 @@ void GC_register_finalizer(/* void * obj,
        /* pointers only if the allocation lock is held, and    */
        /* such conversions are not performed by finalization   */
        /* routines.                                            */
+       /* If GC_register_finalizer is aborted as a result of   */
+       /* a signal, the object may be left with no             */
+       /* finalization, even if neither the old nor new        */
+       /* finalizer were NULL.                                 */
+       /* Obj should be the nonNULL starting address of an     */
+       /* object allocated by GC_malloc or friends.            */
+       /* Note that any garbage collectable object referenced  */
+       /* by cd will be considered accessible until the        */
+       /* finalizer is invoked.                                */
+
+/* Another versions of the above follow.  It ignores           */
+/* self-cycles, i.e. pointers from a finalizable object to     */
+/* itself.  There is a stylistic argument that this is wrong,  */
+/* but it's unavoidable for C++, since the compiler may                */
+/* silently introduce these.  It's also benign in that specific        */
+/* case.                                                       */
+# if defined(__STDC__) || defined(__cplusplus)
+    void GC_register_finalizer_ignore_self(void * obj,
+                              GC_finalization_proc fn, void * cd,
+                              GC_finalization_proc *ofn, void ** ocd);
+# else 
+    void GC_register_finalizer_ignore_self(/* void * obj,
+                                 GC_finalization_proc fn, void * cd,
+                                 GC_finalization_proc *ofn, void ** ocd */);
+# endif
 
 /* The following routine may be used to break cycles between   */
 /* finalizable objects, thus causing cyclic finalizable                */
@@ -328,12 +439,19 @@ int GC_general_register_disappearing_link(/* void ** link, void * obj */);
        /* 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           */
+       /* holding a disguised pointer to obj.  (A pointer      */
+       /* inside an "atomic" object is effectively             */
+       /* disguised.)   In this way soft                       */
+       /* pointers are broken before any object                */
        /* reachable from them are finalized.  Each link        */
        /* May be registered only once, i.e. with one obj       */
        /* value.  This was added after a long email discussion */
        /* with John Ellis.                                     */
+       /* Obj must be a pointer to the first word of an object */
+       /* we allocated.  It is unsafe to explicitly deallocate */
+       /* the object containing link.  Explicitly deallocating */
+       /* obj may or may not cause link to eventually be       */
+       /* cleared.                                             */
 int GC_unregister_disappearing_link(/* void ** link */);
        /* Returns 0 if link was not actually registered.       */
        /* Undoes a registration by either of the above two     */
@@ -355,6 +473,9 @@ int GC_unregister_disappearing_link(/* void ** link */);
 /* that finalization code will arrange for hidden pointers to  */
 /* disappear.  Otherwise objects can be accessed after they    */
 /* have been collected.                                                */
+/* Note that putting pointers in atomic objects or in          */
+/* nonpointer slots of "typed" objects is equivalent to        */
+/* disguising them in this way, and may have other advantages. */
 # ifdef I_HIDE_POINTERS
 #   if defined(__STDC__) || defined(__cplusplus)
 #     define HIDE_POINTER(p) (~(size_t)(p))
@@ -376,4 +497,123 @@ int GC_unregister_disappearing_link(/* void ** link */);
 #   endif
 # endif
 
+/* Check that p and q point to the same object.                */
+/* Fail conspicuously if they don't.                           */
+/* Returns the first argument.                                 */
+/* Succeeds if neither p nor q points to the heap.             */
+/* May succeed if both p and q point to between heap objects.  */
+#ifdef __STDC__
+  void * GC_same_obj(register void *p, register void *q);
+#else
+  char * GC_same_obj(/* char * p, char * q */);
+#endif
+
+/* Check that p is visible                                             */
+/* to the collector as a possibly pointer containing location.         */
+/* If it isn't fail conspicuously.                                     */
+/* Returns the argument in all cases.  May erroneously succeed         */
+/* in hard cases.  (This is intended for debugging use with            */
+/* untyped allocations.  The idea is that it should be possible, though        */
+/* slow, to add such a call to all indirect pointer stores.)           */
+/* Currently useless for multithreaded worlds.                         */
+#ifdef __STDC__
+  void * GC_is_visible(void *p);
+#else
+  char *GC_is_visible(/* char * p */);
+#endif
+
+/* Check that if p is a pointer to a heap page, then it points to      */
+/* a valid displacement within a heap object.                          */
+/* Fail conspicuously if this property does not hold.                  */
+/* Uninteresting with ALL_INTERIOR_POINTERS.                           */
+/* Always returns its argument.                                                */
+#ifdef __STDC__
+  void * GC_is_valid_displacement(void *p);
+#else
+  char *GC_is_valid_displacement(/* char * p */);
 #endif
+
+/* Safer, but slow, pointer addition.  Probably useful mainly with     */
+/* a preprocessor.  Useful only for heap pointers.                     */
+#ifdef GC_DEBUG
+#   define GC_PTR_ADD3(x, n, type_of_result) \
+       ((type_of_result)GC_same_obj((x)+(n), (x)))
+#   ifdef __GNUC__
+#       define GC_PTR_ADD(x, n) \
+           ((typeof(x))GC_same_obj((x)+(n), (x)))
+#   else
+       /* We can't do this right without typeof, which ANSI    */
+       /* decided was not sufficiently useful.  Repeatedly     */
+       /* mentioning the arguments seems too dangerous to be   */
+       /* useful.  So does not casting the result.             */
+#      define GC_PTR_ADD(x, n) ((x)+(n))
+#   endif
+#else  /* !GC_DEBUG */
+#   define GC_PTR_ADD3(x, n, type_of_result) ((x)+(n))
+#   define GC_PTR_ADD(x, n) ((x)+(n))
+#endif
+
+/* Safer assignment of a pointer to a nonstack location.       */
+#ifdef GC_DEBUG
+# ifdef __STDC__
+#   define GC_PTR_STORE(p, q) \
+       (*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# else
+#   define GC_PTR_STORE(p, q) \
+       (*(char **)GC_is_visible(p) = GC_is_valid_displacement(q))
+# endif
+#else /* !GC_DEBUG */
+#   define GC_PTR_STORE(p, q) *((p) = (q))
+#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>
+# 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);
+  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 */
+
+/*
+ * If you are planning on putting
+ * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
+ * from the statically loaded program section.
+ * This circumvents a Solaris 2.X (X<=4) linker bug.
+ */
+#ifdef sparc
+#   define GC_INIT() { extern end, etext; \
+                      GC_noop(&end, &etext); }
+#else
+#   define GC_INIT()
+#endif
+
+#ifdef __cplusplus
+    }  /* end of extern "C" */
+#endif
+
+#endif /* _GC_H */
diff --git a/include/gc_c++.h b/include/gc_c++.h
new file mode 100644 (file)
index 0000000..8e842aa
--- /dev/null
@@ -0,0 +1 @@
+# include "gc_cpp.h"
diff --git a/include/gc_cpp.h b/include/gc_cpp.h
new file mode 100644 (file)
index 0000000..a4b5b59
--- /dev/null
@@ -0,0 +1,260 @@
+#ifndef GC_CPP_H
+#define GC_CPP_H
+/****************************************************************************
+Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
+THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+Permission is hereby granted to use or copy this program for any
+purpose, provided the above notices are retained on all copies.
+Permission to modify the code and to distribute modified code is
+granted, provided the above notices are retained, and a notice that
+the code was modified is included with the above copyright notice.
+****************************************************************************
+
+C++ Interface to the Boehm Collector
+
+    John R. Ellis and Jesse Hull 
+    Last modified on Sun Nov 20 17:37:45 PST 1994 by ellis
+
+This interface provides access to the Boehm collector.  It provides
+basic facilities similar to those described in "Safe, Efficient
+Garbage Collection for C++", by John R. Elis and David L. Detlefs
+(ftp.parc.xerox.com:/pub/ellis/gc).
+
+All heap-allocated objects are either "collectable" or
+"uncollectable".  Programs must explicitly delete uncollectable
+objects, whereas the garbage collector will automatically delete
+collectable objects when it discovers them to be inaccessible.
+Collectable objects may freely point at uncollectable objects and vice
+versa.
+
+Objects allocated with the built-in "::operator new" are uncollectable.
+
+Objects derived from class "gc" are collectable.  For example:
+
+    class A: gc {...};
+    A* a = new A;       // a is collectable. 
+
+Collectable instances of non-class types can be allocated using the GC
+placement:
+
+    typedef int A[ 10 ];
+    A* a = new (GC) A;
+
+Uncollectable instances of classes derived from "gc" can be allocated
+using the NoGC placement:
+
+    class A: gc {...};
+    A* a = new (NoGC) A;   // a is uncollectable.
+
+Both uncollectable and collectable objects can be explicitly deleted
+with "delete", which invokes an object's destructors and frees its
+storage immediately.
+
+A collectable object may have a clean-up function, which will be
+invoked when the collector discovers the object to be inaccessible.
+An object derived from "gc_cleanup" or containing a member derived
+from "gc_cleanup" has a default clean-up function that invokes the
+object's destructors.  Explicit clean-up functions may be specified as
+an additional placement argument:
+
+    A* a = ::new (GC, MyCleanup) A;
+
+An object is considered "accessible" by the collector if it can be
+reached by a path of pointers from static variables, automatic
+variables of active functions, or from some object with clean-up
+enabled; pointers from an object to itself are ignored.
+
+Thus, if objects A and B both have clean-up functions, and A points at
+B, B is considered accessible.  After A's clean-up is invoked and its
+storage released, B will then become inaccessible and will have its
+clean-up invoked.  If A points at B and B points to A, forming a
+cycle, then that's considered a storage leak, and neither will be
+collectable.  See the interface gc.h for low-level facilities for
+handling such cycles of objects with clean-up.
+
+The collector cannot guarrantee that it will find all inaccessible
+objects.  In practice, it finds almost all of them.
+
+
+Cautions:
+
+1. Be sure the collector has been augmented with "make c++".
+
+2.  If your compiler supports the new "operator new[]" syntax, then
+add -DOPERATOR_NEW_ARRAY to the Makefile.
+
+If your compiler doesn't support "operator new[]", beware that an
+array of type T, where T is derived from "gc", will by default be
+allocated as an uncollectable object.  Use the explicit GC placement
+to make the array collectable.  For example:
+
+    class A: gc {...};
+    A* a1 = new A[ 10 ];        // uncollectable
+    A* a2 = new (GC) A[ 10 ];   // collectable
+
+3. Arrays of objects derived from "gc_cleanup" do not have default
+clean-up functions.  For example:
+
+    class A: gc_cleanup {...};
+    A* a = new (GC) A[ 10 ];
+
+The elements of "a" will not have their destructors invoked when the
+collector frees "a".  You must supply an explicit clean-up function
+for that to occur.
+
+3. Evidently cfront 3.0 does not allow destructors to be explicitly
+invoked using the ANSI-conforming syntax t->~T().  If you're using
+cfront 3.0, you'll have to comment out the class gc_cleanup, which
+uses explicit invocation.
+
+****************************************************************************/
+
+#include "gc.h"
+
+#ifndef THINK_CPLUS
+#define _cdecl
+#endif
+
+enum GCPlacement {GC, NoGC};
+
+class gc {public:
+    inline void* operator new( size_t size );
+    inline void* operator new( size_t size, GCPlacement gcp );
+    inline void operator delete( void* obj );
+
+#ifdef OPERATOR_NEW_ARRAY
+    inline void* operator new[]( size_t size );
+    inline void* operator new[]( size_t size, GCPlacement gcp );
+    inline void operator delete[]( void* obj );
+#endif OPERATOR_NEW_ARRAY
+    };    
+    /*
+    Instances of classes derived from "gc" will be allocated in the 
+    collected heap by default, unless an explicit NoGC placement is
+    specified. */
+
+class gc_cleanup: virtual public gc {public:
+    inline gc_cleanup();
+    inline virtual ~gc_cleanup();
+private:
+    inline static void _cdecl cleanup( void* obj, void* clientData );};
+    /*
+    Instances of classes derived from "gc_cleanup" will be allocated
+    in the collected heap by default.  When the collector discovers an
+    inaccessible object derived from "gc_cleanup" or containing a
+    member derived from "gc_cleanup", its destructors will be
+    invoked. */
+
+extern "C" {typedef void (*GCCleanUpFunc)( void* obj, void* clientData );}
+
+inline void* operator new( 
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup = 0,
+    void* clientData = 0 );
+    /*
+    Allocates a collectable or uncollected object, according to the
+    value of "gcp".
+
+    For collectable objects, if "cleanup" is non-null, then when the
+    allocated object "obj" becomes inaccessible, the collector will
+    invoke the function "cleanup( obj, clientData )" but will not
+    invoke the object's destructors.  It is an error to explicitly
+    delete an object allocated with a non-null "cleanup".
+
+    It is an error to specify a non-null "cleanup" with NoGC or for
+    classes derived from "gc_cleanup" or containing members derived
+    from "gc_cleanup". */
+
+#ifdef OPERATOR_NEW_ARRAY
+
+inline void* operator new[](
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup = 0,
+    void* clientData = 0 );
+    /*
+    The operator new for arrays, identical to the above. */
+
+#endif /* OPERATOR_NEW_ARRAY */
+
+/****************************************************************************
+
+Inline implementation
+
+****************************************************************************/
+
+inline void* gc::operator new( size_t size ) {
+    return GC_MALLOC( size );}
+    
+inline void* gc::operator new( size_t size, GCPlacement gcp ) {
+    if (gcp == GC) 
+        return GC_MALLOC( size );
+    else
+        return GC_MALLOC_UNCOLLECTABLE( size );}
+
+inline void gc::operator delete( void* obj ) {
+    GC_FREE( obj );}
+    
+
+#ifdef OPERATOR_NEW_ARRAY
+
+inline void* gc::operator new[]( size_t size ) {
+    return gc::operator new( size );}
+    
+inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
+    return gc::operator new( size, gcp );}
+
+inline void gc::operator delete[]( void* obj ) {
+    gc::operator delete( obj );}
+    
+#endif /* OPERATOR_NEW_ARRAY */
+
+
+inline gc_cleanup::~gc_cleanup() {
+    GC_REGISTER_FINALIZER_IGNORE_SELF( 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_IGNORE_SELF( 
+        base, cleanup, (void*) ((char*) this - (char*) base), 0, 0 );}
+
+inline void* operator new( 
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup,
+    void* clientData )
+{
+    void* obj;
+
+    if (gcp == GC) {
+        obj = GC_MALLOC( size );
+        if (cleanup != 0) 
+            GC_REGISTER_FINALIZER_IGNORE_SELF( 
+                obj, cleanup, clientData, 0, 0 );}
+    else {
+        obj = GC_MALLOC_UNCOLLECTABLE( size );};
+    return obj;}
+        
+
+#ifdef OPERATOR_NEW_ARRAY
+
+inline void* operator new[]( 
+    size_t size, 
+    GCPlacement gcp,
+    GCCleanUpFunc cleanup,
+    void* clientData )
+{
+    return ::operator new( size, gcp, cleanup, clientData );}
+
+#endif OPERATOR_NEW_ARRAY
+
+
+#endif /* GC_CPP_H */
+
similarity index 100%
rename from gc_inl.h
rename to include/gc_inl.h
similarity index 100%
rename from gc_inline.h
rename to include/gc_inline.h
index 401fd062d5f63b94e53c82a8f2b17ff1a9d93122..f7cc2f2244ef42a0cac369bff6186a018581bbf5 100644 (file)
@@ -1,3 +1,16 @@
+/* 
+ * 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.
+ */
 /*
  * Some simple primitives for allocation with explicit type information.
  * Facilities for dynamic type inference may be added later.
@@ -6,7 +19,7 @@
  * Note that this is implemented completely separately from the rest
  * of the collector, and is not linked in unless referenced.
  */
-/* Boehm, March 31, 1994 4:43 pm PST */
+/* Boehm, May 19, 1994 2:13 pm PDT */
 
 #ifndef _GC_TYPED_H
 # define _GC_TYPED_H
@@ -26,9 +39,9 @@ typedef GC_word * GC_bitmap;
 typedef GC_word GC_descr;
 
 #if defined(__STDC__) || defined(__cplusplus)
-  extern GC_descr GC_make_decriptor(GC_bitmap bm, size_t len);
+  extern GC_descr GC_make_descriptor(GC_bitmap bm, size_t len);
 #else
-  extern GC_descr GC_make_decriptor(/* GC_bitmap bm, size_t len */);
+  extern GC_descr GC_make_descriptor(/* GC_bitmap bm, size_t len */);
 #endif
                /* Return a type descriptor for the object whose layout */
                /* is described by the argument.                        */
@@ -39,7 +52,12 @@ typedef GC_word GC_descr;
                /* may be larger (but not smaller).  Any additional     */
                /* words in the object are assumed not to contain       */
                /* pointers.                                            */
-               /* Returns (GC_descr)(-1) on failure (no memory).       */
+               /* Returns a conservative approximation in the          */
+               /* (unlikely) case of insufficient memory to build      */
+               /* the descriptor.  Calls to GC_make_descriptor         */
+               /* may consume some amount of a finite resource.  This  */
+               /* is intended to be called once per type, not once     */
+               /* per allocation.                                      */
 
 #if defined(__STDC__) || defined(__cplusplus)
   extern void * GC_malloc_explicitly_typed(size_t size_in_bytes, GC_descr d);
diff --git a/include/private/cord_pos.h b/include/private/cord_pos.h
new file mode 100644 (file)
index 0000000..a07d07f
--- /dev/null
@@ -0,0 +1,118 @@
+/* 
+ * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, May 19, 1994 2:23 pm PDT */
+# ifndef CORD_POSITION_H
+
+/* The representation of CORD_position.  This is private to the        */
+/* implementation, but the ise is known to clients.  Also      */
+/* the implementation of some exported macros relies on it.    */
+/* Don't use anything defined here and not in cord.h.          */
+
+# define MAX_DEPTH 48
+       /* The maximum depth of a balanced cord + 1.            */
+       /* We don't let cords get deeper than MAX_DEPTH.        */
+
+struct CORD_pe {
+    CORD pe_cord;
+    size_t pe_start_pos;
+};
+
+/* A structure describing an entry on the path from the root   */
+/* to current position.                                                */
+typedef struct CORD_pos {
+    size_t cur_pos;
+    int path_len;
+#      define CORD_POS_INVALID (0x55555555)
+               /* path_len == INVALID <==> position invalid */
+    const char *cur_leaf;      /* Current leaf, if it is a string.     */
+                               /* If the current leaf is a function,   */
+                               /* then this may point to function_buf  */
+                               /* containing the next few characters.  */
+                               /* Always points to a valid string      */
+                               /* containing the current character     */
+                               /* unless cur_end is 0.                 */
+    size_t cur_start;  /* Start position of cur_leaf   */
+    size_t cur_end;    /* Ending position of cur_leaf  */
+                       /* 0 if cur_leaf is invalid.    */
+    struct CORD_pe path[MAX_DEPTH + 1];
+       /* path[path_len] is the leaf corresponding to cur_pos  */
+       /* path[0].pe_cord is the cord we point to.             */
+#   define FUNCTION_BUF_SZ 8
+    char function_buf[FUNCTION_BUF_SZ];        /* Space for next few chars     */
+                                       /* from function node.          */
+} CORD_pos[1];
+
+/* Extract the cord from a position:   */
+CORD CORD_pos_to_cord(CORD_pos p);
+       
+/* Extract the current index from a position:  */
+size_t CORD_pos_to_index(CORD_pos p);
+       
+/* Fetch the character located at the given position:  */
+char CORD_pos_fetch(CORD_pos p);
+       
+/* Initialize the position to refer to the give cord and index.        */
+/* Note that this is the most expensive function on positions: */
+void CORD_set_pos(CORD_pos p, CORD x, size_t i);
+       
+/* Advance the position to the next character. */
+/* P must be initialized and valid.            */
+/* Invalidates p if past end:                  */
+void CORD_next(CORD_pos p);
+
+/* Move the position to the preceding character.       */
+/* P must be initialized and valid.                    */
+/* Invalidates p if past beginning:                    */
+void CORD_prev(CORD_pos p);
+       
+/* Is the position valid, i.e. inside the cord?                */
+int CORD_pos_valid(CORD_pos p);
+
+char CORD__pos_fetch(CORD_pos);
+void CORD__next(CORD_pos);
+void CORD__prev(CORD_pos);
+
+#define CORD_pos_fetch(p)      \
+    (((p)[0].cur_end != 0)? \
+       (p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \
+       : CORD__pos_fetch(p))
+
+#define CORD_next(p)   \
+    (((p)[0].cur_pos + 1 < (p)[0].cur_end)? \
+       (p)[0].cur_pos++ \
+       : (CORD__next(p), 0))
+
+#define CORD_prev(p)   \
+    (((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start)? \
+       (p)[0].cur_pos-- \
+       : (CORD__prev(p), 0))
+
+#define CORD_pos_to_index(p) ((p)[0].cur_pos)
+
+#define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord)
+
+#define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID)
+
+/* Some grubby stuff for performance-critical friends: */
+#define CORD_pos_chars_left(p) ((long)((p)[0].cur_end) - (long)((p)[0].cur_pos))
+       /* Number of characters in cache.  <= 0 ==> none        */
+
+#define CORD_pos_advance(p,n) ((p)[0].cur_pos += (n) - 1, CORD_next(p))
+       /* Advance position by n characters     */
+       /* 0 < n < CORD_pos_chars_left(p)       */
+
+#define CORD_pos_cur_char_addr(p) \
+       (p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start)
+       /* address of current character in cache.       */
+
+#endif
index 4cbf54abcc5b5a97249877ddd7d8844cfeff4160..29536d3ae49514e050269dfc8e10bd059ff39b75 100644 (file)
@@ -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, July 25, 1994 3:39 pm PDT */
+/* Boehm, December 12, 1994 5:03 pm PST */
 # include "gc_priv.h"
 # include <stdio.h>
 # include <setjmp.h>
 #   include <dos.h>
 # endif
 
+#if defined(__MWERKS__) && !defined(POWERPC)
+
+asm static void PushMacRegisters()
+{
+       sub.w   #4,sp                   // reserve space for one parameter.
+    move.l  a2,(sp)
+    jsr                GC_push_one
+    move.l  a3,(sp)
+    jsr                GC_push_one
+    move.l  a4,(sp)
+    jsr                GC_push_one
+       // skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
+    move.l  d2,(sp)
+    jsr                GC_push_one
+    move.l  d3,(sp)
+    jsr                GC_push_one
+    move.l  d4,(sp)
+    jsr                GC_push_one
+    move.l  d5,(sp)
+    jsr                GC_push_one
+    move.l  d6,(sp)
+    jsr                GC_push_one
+    move.l  d7,(sp)
+    jsr                GC_push_one
+       add.w   #4,sp                   // fix stack.
+       rts
+}
+
+#endif /* __MWERKS__ */
 
 /* Routine to mark from registers that are preserved by the C compiler. */
 /* This must be ported to every new architecture.  There is a generic   */
@@ -110,6 +139,7 @@ void GC_push_regs()
 #       endif
 
 #      if defined(M68K) && defined(MACOS)
+#      if defined(THINK_C)
 #         define PushMacReg(reg) \
               move.l  reg,(sp) \
               jsr             GC_push_one
@@ -128,9 +158,13 @@ void GC_push_regs()
               add.w   #4,sp                   ; fix stack.
          }
 #        undef PushMacReg
-#       endif  /* Macintosh */
+#      endif /* THINK_C */
+#      if defined(__MWERKS__)
+         PushMacRegisters();
+#      endif   /* __MWERKS__ */
+#   endif      /* MACOS */
 
-#       if defined(I386) &&!defined(OS2) &&!defined(SUNOS5) &&!defined(MSWIN32)
+#       if defined(I386) &&!defined(OS2) &&!defined(SVR4) &&!defined(MSWIN32) && !defined(SCO)
        /* I386 code, generic code does not appear to work */
        /* It does appear to work under OS2, and asms dont */
          asm("pushl %eax");  asm("call _GC_push_one"); asm("addl $4,%esp");
@@ -146,31 +180,35 @@ void GC_push_regs()
          __asm  push eax
          __asm  call GC_push_one
          __asm  add esp,4
+         __asm  push ebx
+         __asm  call GC_push_one
+         __asm  add esp,4
          __asm  push ecx
          __asm  call GC_push_one
          __asm  add esp,4
          __asm  push edx
          __asm  call GC_push_one
          __asm  add esp,4
-         __asm  push esi
+         __asm  push ebp
          __asm  call GC_push_one
          __asm  add esp,4
-         __asm  push edi
+         __asm  push esi
          __asm  call GC_push_one
          __asm  add esp,4
-         __asm  push ebx
+         __asm  push edi
          __asm  call GC_push_one
          __asm  add esp,4
 #       endif
 
-#       if defined(I386) && defined(SUNOS5)
+#       if defined(I386) && (defined(SVR4) || defined(SCO))
        /* I386 code, SVR4 variant, generic code does not appear to work */
          asm("pushl %eax");  asm("call GC_push_one"); asm("addl $4,%esp");
+         asm("pushl %ebx");  asm("call GC_push_one"); asm("addl $4,%esp");
          asm("pushl %ecx");  asm("call GC_push_one"); asm("addl $4,%esp");
          asm("pushl %edx");  asm("call GC_push_one"); asm("addl $4,%esp");
+         asm("pushl %ebp");  asm("call GC_push_one"); asm("addl $4,%esp");
          asm("pushl %esi");  asm("call GC_push_one"); asm("addl $4,%esp");
          asm("pushl %edi");  asm("call GC_push_one"); asm("addl $4,%esp");
-         asm("pushl %ebx");  asm("call GC_push_one"); asm("addl $4,%esp");
 #       endif
 
 #       ifdef NS32K
@@ -247,7 +285,7 @@ void GC_push_regs()
 #       endif /* M68K/SYSV */
 
 
-#     if defined(HP_PA) || defined(M88K) || (defined(I386) && defined(OS2))
+#     if defined(HP_PA) || defined(M88K) || defined(POWERPC) || (defined(I386) && defined(OS2))
        /* Generic code                          */
        /* The idea is due to Parag Patel at HP. */
        /* We're not sure whether he would like  */
@@ -262,7 +300,11 @@ void GC_push_regs()
                for (; (char *)i < lim; i++) {
                    *i = 0;
                }
-           (void) _setjmp(regs);
+#          ifdef POWERPC
+               (void) setjmp(regs);
+#          else
+               (void) _setjmp(regs);
+#          endif
            GC_push_all_stack((ptr_t)regs, lim);
        }
 #     endif
@@ -281,9 +323,10 @@ void GC_push_regs()
 /* the stack.  Return sp.                                              */
 # ifdef SPARC
     asm("      .seg    \"text\"");
-#   ifdef SUNOS5
+#   ifdef SVR4
       asm("    .globl  GC_save_regs_in_stack");
       asm("GC_save_regs_in_stack:");
+      asm("    .type GC_save_regs_in_stack,#function");
 #   else
       asm("    .globl  _GC_save_regs_in_stack");
       asm("_GC_save_regs_in_stack:");
@@ -292,7 +335,10 @@ void GC_push_regs()
     asm("      mov     %sp,%o0");
     asm("      retl");
     asm("      nop");
-    
+#   ifdef SVR4
+      asm("    .GC_save_regs_in_stack_end:");
+      asm("    .size GC_save_regs_in_stack,.GC_save_regs_in_stack_end-GC_save_regs_in_stack");
+#   endif
 #   ifdef LINT
        word GC_save_regs_in_stack() { return(0 /* sp really */);}
 #   endif
@@ -313,6 +359,7 @@ void GC_push_regs()
 # else
     asm(".globl GC_clear_stack_inner");
     asm("GC_clear_stack_inner:");
+    asm(".type GC_save_regs_in_stack,#function");
 # endif
   asm("mov %sp,%o2");          /* Save sp      */
   asm("add %sp,-8,%o3");       /* p = sp-8     */
@@ -329,6 +376,10 @@ void GC_push_regs()
   asm("retl");
     asm("mov %o2,%sp");                /* Restore sp., delay slot      */
   /* First argument = %o0 = return value */
+#   ifdef SVR4
+      asm("    .GC_clear_stack_inner_end:");
+      asm("    .size GC_clear_stack_inner,.GC_clear_stack_inner_end-GC_clear_stack_inner");
+#   endif
   
 # ifdef LINT
     /*ARGSUSED*/
index dcf386af35c327e1dc9b084745d4e77ca6991c34..72d934ea7cd5ef9b3c6f81be22104d46047c5852 100644 (file)
--- 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, July 13, 1994 12:32 pm PDT */
+/* Boehm, September 19, 1994 4:18 pm PDT */
  
 #include <stdio.h>
 #include "gc_priv.h"
 extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
 void GC_extend_size_map();     /* in misc.c. */
 
+/* Allocate reclaim list for kind:     */
+/* Return TRUE on success              */
+bool GC_alloc_reclaim_list(kind)
+register struct obj_kind * kind;
+{
+    struct hblk ** result = (struct hblk **)
+               GC_scratch_alloc((MAXOBJSZ+1) * sizeof(struct hblk *));
+    if (result == 0) return(FALSE);
+    BZERO(result, (MAXOBJSZ+1)*sizeof(struct hblk *));
+    kind -> ok_reclaim_list = result;
+    return(TRUE);
+}
+
 /* allocate lb bytes for an object of kind.    */
 /* Should not be used to directly to allocate  */
 /* objects such as STUBBORN objects that       */
@@ -56,12 +69,7 @@ register ptr_t *opp;
              }
 #          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;
+               if (!GC_alloc_reclaim_list(kind)) goto out;
            }
            op = GC_allocobj(lw, k);
            if (op == 0) goto out;
@@ -197,16 +205,20 @@ register int k;
 {
 register ptr_t op;
 register ptr_t *opp;
+register struct obj_kind * kind = GC_obj_kinds + k;
 DCL_LOCK_STATE;
 
     GC_invoke_finalizers();
     DISABLE_SIGNALS();
     LOCK();
-    opp = &(GC_obj_kinds[k].ok_freelist[lw]);
+    opp = &(kind -> ok_freelist[lw]);
     if( (op = *opp) == 0 ) {
         if (!GC_is_initialized) {
             GC_init_inner();
         }
+       if (kind -> ok_reclaim_list == 0) {
+           if (!GC_alloc_reclaim_list(kind)) goto out;
+       }
        op = GC_clear_stack(GC_allocobj(lw, k));
        if (op == 0) goto out;
     }
diff --git a/mark.c b/mark.c
index a3ed7d301830d2ff731139755490ef14af401701..5fd71916c1676c6eadc8bc81a96ebb808d279077 100644 (file)
--- a/mark.c
+++ b/mark.c
@@ -340,7 +340,7 @@ register hdr * hhdr;
            
            current = (word)HBLKPTR(current) + HDR_BYTES;
            do {
-             current = current - HBLKSIZE*(int)hhdr;
+             current = current - HBLKSIZE*(word)hhdr;
              hhdr = HDR(current);
            } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
            /* current points to the start of the large object */
@@ -624,34 +624,6 @@ ptr_t top;
 }
 #endif
 
-/*
- * Push a single value onto mark stack. Mark from the object pointed to by p.
- * GC_push_one is normally called by GC_push_regs, and thus must be defined.
- * P is considered valid even if it is an interior pointer.
- * Previously marked objects are not pushed.  Hence we make progress even
- * if the mark stack overflows.
- */
-# define GC_PUSH_ONE_STACK(p) \
-    if ((ptr_t)(p) >= GC_least_plausible_heap_addr     \
-        && (ptr_t)(p) < GC_greatest_plausible_heap_addr) {     \
-        GC_push_one_checked(p,TRUE);   \
-    }
-
-/*
- * As above, but interior pointer recognition as for
- * normal for heap pointers.
- */
-# ifdef ALL_INTERIOR_POINTERS
-#   define AIP TRUE
-# else
-#   define AIP FALSE
-# endif
-# define GC_PUSH_ONE_HEAP(p) \
-    if ((ptr_t)(p) >= GC_least_plausible_heap_addr     \
-        && (ptr_t)(p) < GC_greatest_plausible_heap_addr) {     \
-        GC_push_one_checked(p,AIP);    \
-    }
-
 # ifdef MSWIN32
   void __cdecl GC_push_one(p)
 # else
@@ -843,6 +815,8 @@ register hdr * hhdr;
 }
 
 
+#ifndef UNALIGNED
+
 /* Push all objects reachable from marked objects in the given block */
 /* of size 2 objects.                                               */
 void GC_push_marked2(h, hhdr)
@@ -929,6 +903,8 @@ register hdr * hhdr;
 #   undef GC_least_plausible_heap_addr        
 }
 
+#endif UNALIGNED
+
 #endif /* SMALL_CONFIG */
 
 /* Push all objects reachable from marked objects in the given block */
@@ -957,10 +933,12 @@ register hdr * hhdr;
     }
     
     switch(sz) {
-#   ifndef SMALL_CONFIG    
+#   if !defined(SMALL_CONFIG)    
      case 1:
        GC_push_marked1(h, hhdr);
        break;
+#   endif
+#   if !defined(SMALL_CONFIG) && !defined(UNALIGNED)
      case 2:
        GC_push_marked2(h, hhdr);
        break;
@@ -972,7 +950,10 @@ register hdr * hhdr;
       GC_mark_stack_top_reg = GC_mark_stack_top;
       for (p = (word *)h + HDR_WORDS, word_no = HDR_WORDS; p <= lim;
          p += sz, word_no += sz) {
-         /* This needs manual optimization: */
+         /* This ignores user specified mark procs.  This currently    */
+         /* doesn't matter, since marking from the whole object                */
+         /* is always sufficient, and we will eventually use the user  */
+         /* mark proc to avoid any bogus pointers.                     */
          if (mark_bit_from_hdr(hhdr, word_no)) {
            /* Mark from fields inside the object */
              PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
index 17210313aa3db01dacfb5f32629d0cc33d325735..e0a6d9c4ade13bd0d2542e9cbbf3f0acdc2a4288 100644 (file)
@@ -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, July 4, 1994 10:46 am PDT */
+/* Boehm, September 15, 1994 2:15 pm PDT */
 # include <stdio.h>
 # include "gc_priv.h"
 
@@ -45,6 +45,28 @@ static int n_root_sets = 0;
 
        /* static_roots[0..n_root_sets) contains the valid root sets. */
 
+/* Primarily for debugging support:    */
+/* Is the address p in one of the registered static                    */
+/* root sections?                                                      */
+bool GC_is_static_root(p)
+ptr_t p;
+{
+    static int last_root_set = 0;
+    register int i;
+    
+    
+    if (p >= static_roots[last_root_set].r_start
+        && p < static_roots[last_root_set].r_end) return(TRUE);
+    for (i = 0; i < n_root_sets; i++) {
+       if (p >= static_roots[i].r_start
+            && p < static_roots[i].r_end) {
+            last_root_set = i;
+            return(TRUE);
+        }
+    }
+    return(FALSE);
+}
+
 #ifndef MSWIN32
 #   define LOG_RT_SIZE 6
 #   define RT_SIZE (1 << LOG_RT_SIZE)  /* Power of 2, may be != MAX_ROOT_SETS */
@@ -218,6 +240,13 @@ void GC_clear_roots(NO_PARAMS)
     LOCK();
     n_root_sets = 0;
     GC_root_size = 0;
+#   ifndef MSWIN32
+    {
+       register int i;
+       
+       for (i = 0; i < RT_SIZE; i++) root_index[i] = 0;
+    }
+#   endif
     UNLOCK();
     ENABLE_SIGNALS();
 }
diff --git a/misc.c b/misc.c
index 5a35915090e543e8ac1f43f871e4bc3a416c5faa..7a6b1604c7ae779e7208105479d796fb8bc97565 100644 (file)
--- a/misc.c
+++ b/misc.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, July 11, 1994 4:41 pm PDT */
+/* Boehm, November 8, 1994 5:53 pm PST */
 
 
 #include <stdio.h>
@@ -125,6 +125,16 @@ extern signed_word GC_mem_found;
        if (word_sz > MAXOBJSZ) {
            word_sz = MAXOBJSZ;
        }
+       /* If we can fit the same number of larger objects in a block,  */
+       /* do so.                                                       */ 
+       {
+#          ifdef ALIGN_DOUBLE
+#              define INCR 2
+#          else
+#              define INCR 1
+#          endif
+           while (BODY_SZ/word_sz == BODY_SZ/(word_sz + INCR)) word_sz += INCR;
+       }
        byte_sz = WORDS_TO_BYTES(word_sz);
 #      ifdef ADD_BYTE_AT_END
            /* We need one extra byte; don't fill in GC_size_map[byte_sz] */
@@ -277,6 +287,7 @@ ptr_t arg;
     register word r;
     register struct hblk *h;
     register hdr *candidate_hdr;
+    register word limit;
     
     r = (word)p;
     h = HBLKPTR(r);
@@ -285,7 +296,7 @@ ptr_t arg;
     /* If it's a pointer to the middle of a large object, move it      */
     /* to the beginning.                                               */
        while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
-          h = h - (int)candidate_hdr;
+          h = FORWARDED_ADDR(h,candidate_hdr);
           r = (word)h + HDR_BYTES;
           candidate_hdr = HDR(h);
        }
@@ -294,20 +305,36 @@ ptr_t arg;
        r &= ~(WORDS_TO_BYTES(1) - 1);
         {
            register int offset =
-                       (word *)r - (word *)(HBLKPTR(r)) - HDR_WORDS;
+                       (char *)r - (char *)(HBLKPTR(r)) - HDR_BYTES;
            register signed_word sz = candidate_hdr -> hb_sz;
-           register int correction;
-               
-           correction = offset % sz;
-           r -= (WORDS_TO_BYTES(correction));
-           if (((word *)r + sz) > (word *)(h + 1)
+           
+#          ifdef ALL_INTERIOR_POINTERS
+             register map_entry_type map_entry;
+             
+             map_entry = MAP_ENTRY((candidate_hdr -> hb_map), offset);
+             if (map_entry == OBJ_INVALID) {
+               return(0);
+              }
+              r -= WORDS_TO_BYTES(map_entry);
+              limit = r + WORDS_TO_BYTES(sz);
+#          else
+             register int correction;
+             
+             offset = BYTES_TO_WORDS(offset - HDR_BYTES);
+             correction = offset % sz;
+             r -= (WORDS_TO_BYTES(correction));
+             limit = r + WORDS_TO_BYTES(sz);
+             if (limit > (word)(h + 1)
                && sz <= BYTES_TO_WORDS(HBLKSIZE) - HDR_WORDS) {
                return(0);
-           }
+             }
+#          endif
+           if ((word)p >= limit) return(0);
        }
     return((extern_ptr_t)r);
 }
 
+
 /* Return the size of an object, given a pointer to its base.          */
 /* (For small obects this also happens to work from interior pointers, */
 /* but that shouldn't be relied upon.)                                 */
@@ -357,7 +384,6 @@ void GC_init_inner()
     word dummy;
     
     if (GC_is_initialized) return;
-    GC_is_initialized = TRUE;
 #   ifdef MSWIN32
        GC_init_win32();
 #   endif
@@ -442,7 +468,12 @@ void GC_init_inner()
       GC_init_size_map();
 #   endif
 #   ifdef PCR
-      PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever);
+      if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
+          != PCR_ERes_okay) {
+          ABORT("Can't lock load state\n");
+      } else if (PCR_IL_Unlock() != PCR_ERes_okay) {
+          ABORT("Can't unlock load state\n");
+      }
       PCR_IL_Unlock();
       GC_pcr_install();
 #   endif
@@ -451,15 +482,18 @@ void GC_init_inner()
 #   ifdef STUBBORN_ALLOC
        GC_stubborn_init();
 #   endif
+    GC_is_initialized = TRUE;
     /* Convince lint that some things are used */
 #   ifdef LINT
       {
           extern char * GC_copyright[];
-          extern GC_read();
+          extern int GC_read();
+          extern void GC_register_finalizer_no_order();
           
           GC_noop(GC_copyright, GC_find_header, GC_print_block_list,
                   GC_push_one, GC_call_with_alloc_lock, GC_read,
-                  GC_print_hblkfreelist, GC_dont_expand);
+                  GC_print_hblkfreelist, GC_dont_expand,
+                  GC_register_finalizer_no_order);
       }
 #   endif
 }
@@ -498,11 +532,16 @@ out:
 # endif
 }
 
-#if defined(OS2) || defined(MSWIN32)
+#if defined(OS2) || defined(MSWIN32) || defined(MACOS)
     FILE * GC_stdout = NULL;
     FILE * GC_stderr = NULL;
+#else
+#   if !defined(AMIGA)
+#       include <unistd.h>
+#   endif
 #endif
 
+
 #ifdef MSWIN32
   void GC_set_files()
   {
@@ -515,7 +554,7 @@ out:
   }
 #endif
 
-#ifdef OS2
+#if defined(OS2) || defined(MACOS)
   void GC_set_files()
   {
       if (GC_stdout == NULL) {
@@ -549,7 +588,7 @@ long a, b, c, d, e, f;
     buf[1024] = 0x15;
     (void) sprintf(buf, format, a, b, c, d, e, f);
     if (buf[1024] != 0x15) ABORT("GC_printf clobbered stack");
-#   if defined(OS2) || defined(MSWIN32)
+#   if defined(OS2) || defined(MSWIN32) || defined(MACOS)
       GC_set_files();
       /* We hope this doesn't allocate */
       if (fwrite(buf, 1, strlen(buf), GC_stdout) != strlen(buf))
@@ -569,7 +608,7 @@ long a, b, c, d, e, f;
     buf[1024] = 0x15;
     (void) sprintf(buf, format, a, b, c, d, e, f);
     if (buf[1024] != 0x15) ABORT("GC_err_printf clobbered stack");
-#   if defined(OS2) || defined(MSWIN32)
+#   if defined(OS2) || defined(MSWIN32) || defined(MACOS)
       GC_set_files();
       /* We hope this doesn't allocate */
       if (fwrite(buf, 1, strlen(buf), GC_stderr) != strlen(buf))
@@ -583,7 +622,7 @@ long a, b, c, d, e, f;
 void GC_err_puts(s)
 char *s;
 {
-#   if defined(OS2) || defined(MSWIN32)
+#   if defined(OS2) || defined(MSWIN32) || defined(MACOS)
       GC_set_files();
       /* We hope this doesn't allocate */
       if (fwrite(s, 1, strlen(s), GC_stderr) != strlen(s))
index 4e7dbdbf28fe7d8c6f78f79f2f789c423f69a741..5a5ca8b86304569f7d90f05c7c097fda1fc71778 100644 (file)
--- a/os_dep.c
+++ b/os_dep.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, July 28, 1994 11:11 am PDT */
+/* Boehm, November 4, 1994 4:23 pm PST */
 
 # include "gc_priv.h"
 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)
 # include <sys/uio.h>
 #endif
 
+#ifdef SUNOS5SIGS
+# include <sys/siginfo.h>
+#endif
+
 #ifdef PCR
 # include "il/PCR_IL.h"
 # include "th/PCR_ThCtl.h"
@@ -374,12 +378,21 @@ ptr_t GC_get_stack_base()
                /* static since it's only called once, with the         */
                /* allocation lock held.                                */
 
-        static handler old_segv_handler, old_bus_handler;
+#      ifdef SUNOS5SIGS
+         struct sigaction      act, oldact;
+
+         act.sa_handler                = GC_fault_handler;
+         act.sa_flags          = SA_RESTART | SA_SIGINFO;
+         (void) sigemptyset(&act.sa_mask);
+         (void) sigaction(SIGSEGV, &act, &oldact);
+#      else
+          static handler old_segv_handler, old_bus_handler;
                /* See above for static declaration.                    */
 
-       old_segv_handler = signal(SIGSEGV, GC_fault_handler);
-#      ifdef SIGBUS
-          old_bus_handler = signal(SIGBUS, GC_fault_handler);
+         old_segv_handler = signal(SIGSEGV, GC_fault_handler);
+#        ifdef SIGBUS
+           old_bus_handler = signal(SIGBUS, GC_fault_handler);
+#        endif
 #      endif
        if (setjmp(GC_jmp_buf) == 0) {
            result = (ptr_t)(((word)(p))
@@ -393,10 +406,14 @@ ptr_t GC_get_stack_base()
                GC_noop(*result);
            }
        }
-       (void) signal(SIGSEGV, old_segv_handler);
-#      ifdef SIGBUS
+#       ifdef SUNOS5SIGS
+         (void) sigaction(SIGSEGV, &oldact, 0);
+#       else
+         (void) signal(SIGSEGV, old_segv_handler);
+#        ifdef SIGBUS
            (void) signal(SIGBUS, old_bus_handler);
-#      endif
+#        endif
+#       endif
        if (!up) {
            result += MIN_PAGE_SIZE;
        }
@@ -410,7 +427,7 @@ ptr_t GC_get_stack_base()
     word dummy;
     ptr_t result;
 
-#   define STACKBOTTOM_ALIGNMENT_M1 0xffffff
+#   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
 
 #   ifdef STACKBOTTOM
        return(STACKBOTTOM);
@@ -428,9 +445,22 @@ ptr_t GC_get_stack_base()
 #      ifdef HEURISTIC2
 #          ifdef STACK_GROWS_DOWN
                result = GC_find_limit((ptr_t)(&dummy), TRUE);
+#              ifdef HEURISTIC2_LIMIT
+                   if (result > HEURISTIC2_LIMIT
+                       && (ptr_t)(&dummy) < HEURISTIC2_LIMIT) {
+                           result = HEURISTIC2_LIMIT;
+                   }
+#              endif
 #          else
                result = GC_find_limit((ptr_t)(&dummy), FALSE);
+#              ifdef HEURISTIC2_LIMIT
+                   if (result < HEURISTIC2_LIMIT
+                       && (ptr_t)(&dummy) > HEURISTIC2_LIMIT) {
+                           result = HEURISTIC2_LIMIT;
+                   }
+#              endif
 #          endif
+
 #      endif /* HEURISTIC2 */
        return(result);
 #   endif /* STACKBOTTOM */
@@ -683,11 +713,13 @@ void GC_register_data_segments()
 
 # else
 
-# if defined(SUNOS5) || defined(AUX)
-char * GC_SysVGetDataStart(int max_page_size)
+# if defined(SVR4) || defined(AUX) || defined(DGUX)
+char * GC_SysVGetDataStart(max_page_size, etext_addr)
+int max_page_size;
+int * etext_addr;
 {
-    extern int etext;
-    word text_end = ((word)(&etext) + sizeof(word) - 1) & ~(sizeof(word) - 1);
+    word text_end = ((word)(etext_addr) + 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));
@@ -697,6 +729,7 @@ char * GC_SysVGetDataStart(int max_page_size)
 }
 # endif
 
+
 void GC_register_data_segments()
 {
 #   if !defined(NEXT) && !defined(MACOS)
@@ -711,12 +744,19 @@ void GC_register_data_segments()
 #   endif
 #   if defined(MACOS)
     {
+#   if defined(THINK_C)
        extern void* GC_MacGetDataStart(void);
        /* globals begin above stack and end at a5. */
        GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
                           (ptr_t)LMGetCurrentA5());
-    }
+#   else
+#     if defined(__MWERKS__)
+       extern long __datastart, __dataend;
+       GC_add_roots_inner((ptr_t)&__datastart, (ptr_t)&__dataend);
+#     endif
 #   endif
+    }
+#   endif /* MACOS */
 
     /* Dynamic libraries are added at every collection, since they may  */
     /* change.                                                         */
@@ -1097,13 +1137,16 @@ word addr;
 #if defined(SUNOS4) || defined(FREEBSD)
     typedef void (* SIG_PF)();
 #endif
-
-#if defined(ALPHA) /* OSF1 */
+#if defined(SUNOS5SIGS) || defined(ALPHA) /* OSF1 */
     typedef void (* SIG_PF)(int);
 #endif
+
 #if defined(IRIX5) || defined(ALPHA) /* OSF1 */
     typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
 #endif
+#if defined(SUNOS5SIGS)
+    typedef void (* REAL_SIG_PF)(int, struct siginfo *, void *);
+#endif
 
 SIG_PF GC_old_bus_handler;
 SIG_PF GC_old_segv_handler;
@@ -1136,6 +1179,11 @@ SIG_PF GC_old_segv_handler;
 #     define CODE_OK (code == EACCES)
 #   endif
 # endif
+# if defined(SUNOS5SIGS)
+    void GC_write_fault_handler(int sig, struct siginfo *scp, void * context)
+#   define SIG_OK (sig == SIGSEGV)
+#   define CODE_OK (scp -> si_code == SEGV_ACCERR)
+# endif
 {
     register int i;
 #   ifdef IRIX5
@@ -1144,6 +1192,9 @@ SIG_PF GC_old_segv_handler;
 #   ifdef ALPHA
        char * addr = (char *) (scp -> sc_traparg_a0);
 #   endif
+#   ifdef SUNOS5SIGS
+       char * addr = (char *) (scp -> si_addr);
+#   endif
     
     if (SIG_OK && CODE_OK) {
         register struct hblk * h =
@@ -1163,7 +1214,11 @@ SIG_PF GC_old_segv_handler;
 #              if defined (SUNOS4) || defined(FREEBSD)
                  (*old_handler) (sig, code, scp, addr);
 #              else
-                 (*(REAL_SIG_PF)old_handler) (sig, code, scp);
+#                if defined (SUNOS5SIGS)
+                   (*(REAL_SIG_PF)old_handler) (sig, scp, context);
+#                else
+                   (*(REAL_SIG_PF)old_handler) (sig, code, scp);
+#                endif
 #              endif
                return;
             }
@@ -1212,11 +1267,28 @@ struct hblk *h;
        }
     }
 }
+
+#if defined(SUNOS5) || defined(DRSNX)
+#include <unistd.h>
+int
+GC_getpagesize()
+{
+    return sysconf(_SC_PAGESIZE);
+}
+#else
+# define GC_getpagesize() getpagesize()
+#endif
                                 
 void GC_dirty_init()
 {
+#if defined(SUNOS5SIGS)
+    struct sigaction   act, oldact;
+    act.sa_sigaction   = GC_write_fault_handler;
+    act.sa_flags       = SA_RESTART | SA_SIGINFO;
+    (void)sigemptyset(&act.sa_mask); 
+#endif
     GC_dirty_maintained = TRUE;
-    GC_page_size = getpagesize();
+    GC_page_size = GC_getpagesize();
     if (GC_page_size % HBLKSIZE != 0) {
         GC_err_printf0("Page size not multiple of HBLKSIZE\n");
         ABORT("Page size not multiple of HBLKSIZE");
@@ -1245,6 +1317,23 @@ void GC_dirty_init()
 #      endif
       }
 #   endif
+#   if defined(SUNOS5SIGS)
+      sigaction(SIGSEGV, &act, &oldact);
+      if (oldact.sa_flags & SA_SIGINFO) {
+          GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
+      } else {
+          GC_old_segv_handler = oldact.sa_handler;
+      }
+      if (GC_old_segv_handler == SIG_IGN) {
+            GC_err_printf0("Previously ignored segmentation violation!?");
+            GC_old_segv_handler == SIG_DFL;
+      }
+      if (GC_old_segv_handler != SIG_DFL) {
+#       ifdef PRINTSTATS
+         GC_err_printf0("Replaced other SIGSEGV handler\n");
+#       endif
+      }
+#    endif
 }
 
 
@@ -1276,9 +1365,9 @@ void GC_protect_heap()
 
 void GC_read_dirty()
 {
-    BCOPY(GC_dirty_pages, GC_grungy_pages,
+    BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
           (sizeof GC_dirty_pages));
-    BZERO(GC_dirty_pages, (sizeof GC_dirty_pages));
+    BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
     GC_protect_heap();
 }
 
@@ -1334,7 +1423,7 @@ word len;
                 (int)((ptr_t)end_block - (ptr_t)start_block)
                 + HBLKSIZE,
                 PROT_WRITE | PROT_READ | PROT_EXEC) < 0) {
-       ABORT("mprotect failed in GC_unprotect_range");
+       ABORT("mprotect failed in GC_unprotect_range:");
     }
 }
 
@@ -1493,10 +1582,9 @@ 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
+#   define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)
 #else
-#   define READ read
+#   define READ(fd,buf,nbytes) read(fd, buf, nbytes)
 #endif
 
 void GC_read_dirty()
@@ -1713,7 +1801,11 @@ struct hblk *h;
 #   if defined(SUNOS4)
 #     include <machine/frame.h>
 #   else
-#     include <sys/frame.h>
+#     if defined (DRSNX)
+#      include <sys/sparc/frame.h>
+#     else
+#       include <sys/frame.h>
+#     endif
 #   endif
 #   if NARGS > 6
        --> We only know how to to get the first 6 arguments
index 58639886b3cf6d47325e059604f571082b84d2f6..52da43110cf425e48c17e6bf4175c30de0e23fd6 100644 (file)
@@ -11,3 +11,5 @@ callprocs
 gc.man
 pc_excludes
 barrett_diagram
+include/gc_c++.h
+include/gc_inline.h
\ No newline at end of file
diff --git a/ptr_chck.c b/ptr_chck.c
new file mode 100644 (file)
index 0000000..834d013
--- /dev/null
@@ -0,0 +1,276 @@
+/* 
+ * 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, September 20, 1994 11:51 am PDT */
+
+#include "gc_priv.h"
+#include "gc_mark.h"
+
+void GC_default_same_obj_print_proc(p,q)
+ptr_t p, q;
+{
+    GC_err_printf2("0x%lx and 0x%lx are not in the same object\n",
+                  (unsigned long)p, (unsigned long)q);
+    ABORT("GC_same_obj test failed");
+}
+
+void (*GC_same_obj_print_proc)() = GC_default_same_obj_print_proc;
+
+/* Check that p and q point to the same object.  Call          */
+/* *GC_same_obj_print_proc if they don't.                      */
+/* Returns the first argument.  (Return value may be hard      */
+/* to use,due to typing issues.  But if we had a suitable      */
+/* preprocessor ...)                                           */
+/* Succeeds if neither p nor q points to the heap.             */
+/* We assume this is performance critical.  (It shouldn't      */
+/* be called by production code, but this can easily make      */
+/* debugging intolerably slow.)                                        */
+#ifdef __STDC__
+  void * GC_same_obj(register void *p, register void *q)
+#else
+  char * GC_same_obj(p, q)
+  register char *p, *q;
+#endif
+{
+    register struct hblk *h;
+    register hdr *hhdr;
+    register ptr_t base, limit;
+    register word sz;
+    
+    if (!GC_is_initialized) GC_init();
+    hhdr = HDR((word)p);
+    if (hhdr == 0) {
+       if (divHBLKSZ((word)p) != divHBLKSZ((word)q)
+           && HDR((word)q) != 0) {
+           goto fail;
+       }
+       return(p);
+    }
+    /* If it's a pointer to the middle of a large object, move it      */
+    /* to the beginning.                                               */
+    if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+       h = HBLKPTR(p) - (int)hhdr;
+       hhdr = HDR(h);
+       while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+          h = FORWARDED_ADDR(h, hhdr);
+          hhdr = HDR(h);
+       }
+       limit = (ptr_t)((word *)h + HDR_WORDS + hhdr -> hb_sz);
+       if ((ptr_t)p >= limit || (ptr_t)q >= limit || (ptr_t)q < (ptr_t)h ) {
+           goto fail;
+       }
+       return(p);
+    }
+    sz = WORDS_TO_BYTES(hhdr -> hb_sz);
+    if (sz > WORDS_TO_BYTES(MAXOBJSZ)) {
+      base = (ptr_t)HBLKPTR(p);
+      limit = base + sz;
+      if ((ptr_t)p >= limit) {
+        goto fail;
+      }
+    } else {
+#     ifdef ALL_INTERIOR_POINTERS
+       register map_entry_type map_entry;
+       register int pdispl;
+       
+       pdispl = HBLKDISPL(p);
+       map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
+       if (map_entry == OBJ_INVALID) {
+            goto fail;
+        } else {
+            base = (char *)((word)p & ~(WORDS_TO_BYTES(1) - 1));
+            base -= WORDS_TO_BYTES(map_entry);
+       }
+#     else
+       register int offset = HBLKDISPL(p) - HDR_BYTES;
+       register word correction = offset % sz;
+       
+       if (HBLKPTR(p) != HBLKPTR(q)) {
+           /* The following computation otherwise fails in this case */
+           goto fail;
+       }
+       base = (ptr_t)p - correction;
+#     endif
+      limit = base + sz;
+    }
+    /* [base, limit) delimits the object containing p, if any. */
+    /* If p is not inside a valid object, then either q is     */
+    /* also outside any valid object, or it is outside                 */
+    /* [base, limit).                                          */
+    if ((ptr_t)q >= limit || (ptr_t)q < base) {
+       goto fail;
+    }
+    return(p);
+fail:
+    (*GC_same_obj_print_proc)((ptr_t)p, (ptr_t)q);
+    return(p);
+}
+
+
+void GC_default_is_valid_displacement_print_proc(p)
+ptr_t p;
+{
+    GC_err_printf1("0x%lx does not point to valid object displacement\n",
+                  (unsigned long)p);
+    ABORT("GC_is_valid_displacement test failed");
+}
+
+void (*GC_is_valid_displacement_print_proc)() = 
+       GC_default_is_valid_displacement_print_proc;
+
+/* Check that if p is a pointer to a heap page, then it points to      */
+/* a valid displacement within a heap object.                          */
+/* Uninteresting with ALL_INTERIOR_POINTERS.                           */
+/* Always returns its argument.                                                */
+/* Note that we don't lock, since nothing relevant about the header    */
+/* should change while we have a valid object pointer to the block.    */
+#ifdef __STDC__
+  void * GC_is_valid_displacement(void *p)
+#else
+  char *GC_is_valid_displacement(p)
+  char *p;
+#endif
+{
+    register hdr *hhdr;
+    register word pdispl;
+    register struct hblk *h;
+    register map_entry_type map_entry;
+    register word sz;
+    
+    if (!GC_is_initialized) GC_init();
+    hhdr = HDR((word)p);
+    if (hhdr == 0) return(p);
+    h = HBLKPTR(p);
+#   ifdef ALL_INTERIOR_POINTERS
+       while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+          h = FORWARDED_ADDR(h, hhdr);
+          hhdr = HDR(h);
+       }
+#   endif
+    if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
+       goto fail;
+    }
+    sz = WORDS_TO_BYTES(hhdr -> hb_sz);
+    pdispl = HBLKDISPL(p);
+    map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
+    if (map_entry == OBJ_INVALID
+       || sz > MAXOBJSZ && (ptr_t)p >= (ptr_t)h + sz) {
+       goto fail;
+    }
+    return(p);
+fail:
+    (*GC_is_valid_displacement_print_proc)((ptr_t)p);
+    return(p);
+}
+
+
+void GC_default_is_visible_print_proc(p)
+ptr_t p;
+{
+    GC_err_printf1("0x%lx is not a GC visible pointer location\n",
+                  (unsigned long)p);
+    ABORT("GC_is_visible test failed");
+}
+
+void (*GC_is_visible_print_proc)() = 
+       GC_default_is_visible_print_proc;
+
+/* Check that p is visible                                             */
+/* to the collector as a possibly pointer containing location.         */
+/* If it isn't invoke *GC_is_visible_print_proc.                       */
+/* Returns the argument in all cases.  May erroneously succeed         */
+/* in hard cases.  (This is intended for debugging use with            */
+/* untyped allocations.  The idea is that it should be possible, though        */
+/* slow, to add such a call to all indirect pointer stores.)           */
+/* Currently useless for multithreaded worlds.                         */
+#ifdef __STDC__
+  void * GC_is_visible(void *p)
+#else
+  char *GC_is_visible(p)
+  char *p;
+#endif
+{
+    register hdr *hhdr;
+    int dummy;
+    
+    if ((word)p & (ALIGNMENT - 1)) goto fail;
+    if (!GC_is_initialized) GC_init();
+#   ifdef THREADS
+       hhdr = HDR((word)p);
+        if (hhdr != 0 && GC_base(p) == 0) {
+            goto fail;
+        } else {
+            /* May be inside thread stack.  We can't do much. */
+            return(p);
+        }
+#   else
+       /* Check stack first: */
+#        ifdef STACK_GROWS_DOWN
+           if ((ptr_t)p >= (ptr_t)(&dummy) && (ptr_t)p < GC_stackbottom ) {
+               return(p);
+           }
+#        else
+           if ((ptr_t)p <= (ptr_t)(&dummy) && (ptr_t)p > GC_stackbottom ) {
+               return(p);
+           }
+#        endif
+       hhdr = HDR((word)p);
+       if (hhdr == 0) {
+           bool result;
+           
+           if (GC_is_static_root(p)) return(p);
+           /* Else do it again correctly:      */
+#           if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(PCR)) \
+                && !defined(SRC_M3)
+               DISABLE_SIGNALS();
+               GC_register_dynamic_libraries();
+               result = GC_is_static_root(p);
+               ENABLE_SIGNALS();
+               if (result) return(p);
+#          endif
+           goto fail;
+       } else {
+           /* p points to the heap. */
+           word descr;
+           ptr_t base = GC_base(p);    /* Should be manually inlined? */
+           
+           if (base == 0) goto fail;
+           if (HBLKPTR(base) != HBLKPTR(p)) hhdr = HDR((word)p);
+           descr = hhdr -> hb_descr;
+    retry:
+           switch(descr & DS_TAGS) {
+               case DS_LENGTH:
+                   if ((ptr_t)p - (ptr_t)base > (word)descr) goto fail;
+                   break;
+               case DS_BITMAP:
+                   if ((ptr_t)p - (ptr_t)base
+                        >= WORDS_TO_BYTES(BITMAP_BITS)
+                        || ((word)p & (sizeof(word) - 1))) goto fail;
+                   if (!((1 << (WORDSZ - ((ptr_t)p - (ptr_t)base) - 1))
+                         & descr)) goto fail;
+                   break;
+               case DS_PROC:
+                   /* We could try to decipher this partially.         */
+                   /* For now we just punt.                            */
+                   break;
+               case DS_PER_OBJECT:
+                   descr = *(word *)((ptr_t)base + (descr & ~DS_TAGS));
+                   goto retry;
+           }
+           return(p);
+       }
+#   endif
+fail:
+    (*GC_is_visible_print_proc)((ptr_t)p);
+    return(p);
+}
+
index 13c4ffea7b3404582ed309173e5720409278eb0a..c877074e7a81406d600423504598b50e30fa99d2 100644 (file)
@@ -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, July 25, 1994 2:34 pm PDT */
+/* Boehm, September 12, 1994 3:39 pm PDT */
  
 /* Check whether setjmp actually saves registers in jmp_buf. */
 /* If it doesn't, the generic mark_regs code won't work.     */
 #include "config.h"
 
 #ifdef __hpux
-/* X/OPEN PG3 defines "void* sbrk();" and this clashes with the definition */
-/* in gc_private.h, so we set the clock backwards with _CLASSIC_XOPEN_TYPES. */
-/* This is for HP-UX 8.0.
-/* sbrk() is not used in this file, of course.  W. Underwood, 15 Jun 1992 */
-#define _CLASSIC_XOPEN_TYPES
 #include <unistd.h>
 int
 getpagesize()
@@ -40,8 +35,7 @@ getpagesize()
 }
 #endif
 
-#if defined(SUNOS5)
-#define _CLASSIC_XOPEN_TYPES
+#if defined(SUNOS5) || defined(DRSNX)
 #include <unistd.h>
 int
 getpagesize()
index 19c63b3072781505e8b92582756b2d3251a6bb99..08bf013181f288c9dbb6259bd68802eee2943a37 100644 (file)
@@ -14,7 +14,7 @@
  * Support code for Solaris threads.  Provides functionality we wish Sun
  * had provided.  Relies on some information we probably shouldn't rely on.
  */
-/* Boehm, July 23, 1994 11:11 am PDT */
+/* Boehm, September 14, 1994 4:44 pm PDT */
 
 # if defined(SOLARIS_THREADS)
 
@@ -47,8 +47,6 @@ 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  */
@@ -173,8 +171,7 @@ static void stop_all_lwps()
         }
         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) {
+            if (GC_current_ids[i] != last_ids[i]) {
                 changed = TRUE;
                 if (GC_current_ids[i] != me) {
                    /* PIOCSTOP doesn't work without a writable         */
@@ -193,8 +190,7 @@ static void stop_all_lwps()
         /* 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) {
+                if (GC_current_ids[i] != me) {
                     lwp_fd = open_lwp(GC_current_ids[i]);
                    /* LWP should be stopped.  Empirically it sometimes */
                    /* isn't, and more frequently the PR_STOPPED flag   */
@@ -247,7 +243,7 @@ static void restart_all_lwps()
 
     for (i = 0; GC_current_ids[i] != 0; i++) {
 #      ifdef PARANOID
-         if (GC_current_ids[i] != me && GC_current_ids[i] != GC_read_lwp) {
+         if (GC_current_ids[i] != me) {
            int lwp_fd = open_lwp(GC_current_ids[i]);
            prstatus_t status;
            gwindows_t windows;
@@ -299,71 +295,6 @@ 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    */
@@ -395,7 +326,9 @@ ptr_t GC_stack_alloc(size_t * stack_size)
         result = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_sz);
         result = (ptr_t)(((word)result + GC_page_sz) & ~(GC_page_sz - 1));
         /* Protect hottest page to detect overflow. */
-        mprotect(result, GC_page_sz, PROT_NONE);
+#      ifdef SOLARIS23_MPROTECT_BUG_FIXED
+            mprotect(result, GC_page_sz, PROT_NONE);
+#      endif
         GC_is_fresh((struct hblk *)result, divHBLKSZ(search_sz));
         result += GC_page_sz;
     }
@@ -646,8 +579,8 @@ GC_thr_init()
     GC_thread t;
 
     GC_thr_initialized = TRUE;
-    GC_read_init();
-    GC_min_stack_sz = ((thr_min_stack() + HBLKSIZE-1) & ~(HBLKSIZE - 1));
+    GC_min_stack_sz = ((thr_min_stack() + 128*1024 + HBLKSIZE-1)
+                      & ~(HBLKSIZE - 1));
     GC_page_sz = sysconf(_SC_PAGESIZE);
     cond_init(&GC_prom_join_cv, USYNC_THREAD, 0);
     cond_init(&GC_create_cv, USYNC_THREAD, 0);
diff --git a/test.c b/test.c
index 4a88350a91d733d33fde250dec69393f47391b89..52152dc9ed3316090c0d72cb5f61944034bda771 100644 (file)
--- a/test.c
+++ b/test.c
@@ -5,14 +5,21 @@
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  *
- * Permission is hereby granted to copy this garbage collector for any purpose,
- * provided the above notices are retained on all copies.
+ * 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, July 27, 1994 9:45 am PDT */
+/* Boehm, November 8, 1994 5:50 pm PST */
 /* An incomplete test for the garbage collector.               */
 /* Some more obscure entry points are not tested at all.       */
 
-# include <stdlib.h>
+# if defined(mips) && defined(SYSTYPE_BSD43)
+    /* MIPS RISCOS 4 */
+# else
+#   include <stdlib.h>
+# endif
 # include <stdio.h>
 # include "gc.h"
 # include "gc_typed.h"
@@ -54,6 +61,7 @@ struct SEXPR {
     struct SEXPR * sexpr_cdr;
 };
 
+
 # ifdef __STDC__
     typedef void * void_star;
 # else
@@ -62,10 +70,12 @@ struct SEXPR {
 
 typedef struct SEXPR * sexpr;
 
+# define INT_TO_SEXPR(x) ((sexpr)(unsigned long)(x))
+
 extern sexpr cons();
 
 # undef nil
-# define nil ((sexpr) 0)
+# define nil (INT_TO_SEXPR(0))
 # define car(x) ((x) -> sexpr_car)
 # define cdr(x) ((x) -> sexpr_cdr)
 # define is_nil(x) ((x) == nil)
@@ -140,7 +150,7 @@ sexpr y;
         exit(1);
     }
     r -> sexpr_car = x;
-    r -> sexpr_cdr = (sexpr) (~(unsigned long)y);
+    r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
     return(r);
 }
 
@@ -167,7 +177,7 @@ int low, up;
     if (low > up) {
        return(nil);
     } else {
-        return(small_cons(small_cons((sexpr)low, (sexpr)0), ints(low+1, up)));
+        return(small_cons(small_cons(INT_TO_SEXPR(low), nil), ints(low+1, up)));
     }
 }
 
@@ -179,7 +189,7 @@ int low, up;
     if (low > up) {
        return(nil);
     } else {
-        return(small_cons_uncollectable(small_cons((sexpr)low, (sexpr)0),
+        return(small_cons_uncollectable(small_cons(INT_TO_SEXPR(low), nil),
                uncollectable_ints(low+1, up)));
     }
 }
@@ -290,7 +300,8 @@ void reverse_test()
     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.          */
+       /* 49 integers.  Thus this is thread safe without locks,          */
+       /* assuming atomic pointer assignments.                           */
         a = reverse(reverse(a));
 #      if !defined(AT_END) && !defined(THREADS)
          /* This is not thread safe, since realloc explicitly deallocates */
@@ -325,7 +336,7 @@ typedef struct treenode {
 
 int finalizable_count = 0;
 int finalized_count = 0;
-int dropped_something = 0;
+VOLATILE int dropped_something = 0;
 
 # ifdef __STDC__
   void finalizer(void * obj, void * client_data)
@@ -537,6 +548,8 @@ void tree_test()
         FAIL;
     }
     dropped_something = 1;
+    GC_noop(root);     /* Root needs to remain live until      */
+                       /* dropped_something is set.            */
     root = mktree(TREE_HEIGHT);
     chktree(root, TREE_HEIGHT);
     for (i = TREE_HEIGHT; i >= 0; i--) {
@@ -606,18 +619,77 @@ void typed_test()
     }
 }
 
+int fail_count = 0;
+
+/*ARGSUSED*/
+void fail_proc(x)
+ptr_t x;
+{
+    fail_count++;
+}
+
+extern void (*GC_is_valid_displacement_print_proc)();
+
+extern void (*GC_is_visible_print_proc)();
+
+#ifdef THREADS
+#   define TEST_FAIL_COUNT(n) 1
+#else 
+#   define TEST_FAIL_COUNT(n) (fail_count >= (n))
+#endif
+
 void run_one_test()
 {
+    char *x;
+#   ifdef LINT
+       char *y = 0;
+#   else
+       char *y = (char *)fail_proc;
+#   endif
     DCL_LOCK_STATE;
     
-#   ifndef GC_DEBUG
-       if (GC_size(GC_MALLOC(7)) != 8
-           || GC_size(GC_MALLOC(15)) != 16) {
+    if (GC_size(GC_malloc(7)) != 8
+       || GC_size(GC_malloc(15)) != 16) {
            (void)GC_printf0("GC_size produced unexpected results\n");
            FAIL;
-       }
+    }
+    GC_is_valid_displacement_print_proc = fail_proc;
+    GC_is_visible_print_proc = fail_proc;
+    x = GC_malloc(16);
+    if (GC_base(x + 13) != x || GC_base(y) != 0) {
+       (void)GC_printf0("GC_base produced incorrect result\n");
+       FAIL;
+    }
+    if (GC_same_obj(x+5, x) != x + 5) {
+       (void)GC_printf0("GC_same_obj produced incorrect result\n");
+       FAIL;
+    }
+    if (GC_is_visible(y) != y || GC_is_visible(x) != x) {
+       (void)GC_printf0("GC_is_visible produced incorrect result\n");
+       FAIL;
+    }
+    if (!TEST_FAIL_COUNT(1)) {
+       (void)GC_printf0("GC_is_visible produced wrong failure indication\n");
+       FAIL;
+    }
+    if (GC_is_valid_displacement(y) != y
+        || GC_is_valid_displacement(x) != x
+        || GC_is_valid_displacement(x + 3) != x + 3) {
+       (void)GC_printf0(
+               "GC_is_valid_displacement produced incorrect result\n");
+       FAIL;
+    }
+#   ifndef ALL_INTERIOR_POINTERS
+      if (!TEST_FAIL_COUNT(2)) {
+       (void)GC_printf0("GC_is_valid_displacement produced wrong failure indication\n");
+       FAIL;
+      }
 #   endif
-    reverse_test();
+    /* Test floating point alignment */
+       *(double *)GC_MALLOC(sizeof(double)) = 1.0;
+       *(double *)GC_MALLOC(sizeof(double)) = 1.0;
+    /* Repeated list reversal test. */
+       reverse_test();
 #   ifdef PRINTSTATS
        GC_printf0("-------------Finished reverse_test\n");
 #   endif
@@ -728,6 +800,7 @@ void SetMinimumStack(long minSize)
        /* Cheat and let stdio initialize toolbox for us.       */
        printf("Testing GC Macintosh port.\n");
 #   endif
+    GC_INIT(); /* Only needed if gc is dynamic library.        */
 #   if defined(MPROTECT_VDB) || defined(PROC_VDB)
       GC_enable_incremental();
       (void) GC_printf0("Switched to incremental mode\n");
@@ -746,6 +819,8 @@ void SetMinimumStack(long minSize)
        /* This is a bit SunOS4 specific.                                  */                   
        GC_noop(GC_expand_hp, GC_add_roots, GC_clear_roots,
                GC_register_disappearing_link,
+               GC_register_finalizer_ignore_self,
+               GC_debug_register_displacement,
                GC_print_obj, GC_debug_change_stubborn,
                GC_debug_end_stubborn_change, GC_debug_malloc_uncollectable,
                GC_debug_free, GC_debug_realloc, GC_generic_malloc_words_small,
@@ -801,6 +876,7 @@ main()
     int code;
 
     n_tests = 0;
+    GC_INIT(); /* Only needed if gc is dynamic library.        */
     GC_enable_incremental();
     if (thr_keycreate(&fl_key, GC_free) != 0) {
         (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
diff --git a/test_cpp.cc b/test_cpp.cc
new file mode 100644 (file)
index 0000000..9361f6f
--- /dev/null
@@ -0,0 +1,168 @@
+/****************************************************************************
+Copyright (c) 1994 by Xerox Corporation.  All rights reserved.
+THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+Permission is hereby granted to use or copy this program for any
+purpose, provided the above notices are retained on all copies.
+Permission to modify the code and to distribute modified code is
+granted, provided the above notices are retained, and a notice that
+the code was modified is included with the above copyright notice.
+****************************************************************************
+
+usage: test_gc_c++ number-of-iterations
+
+This program tries to test the specific C++ functionality provided by
+gc_c++.h that isn't tested by the more general test routines of the
+collector.
+
+A recommended value for number-of-iterations is 10, which will take a
+few minutes to complete.
+
+***************************************************************************/
+/* Boehm, December 20, 1994 7:27 pm PST */
+
+#include "gc_cpp.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+class A {public:
+    /* An uncollectable class. */
+
+    A( int iArg ): i( iArg ) {}
+    void Test( int iArg ) {
+        assert( i == iArg );} 
+    int i;};
+
+
+class B: public gc, public A {public:
+    /* A collectable class. */
+
+    B( int j ): A( j ) {}
+    ~B() {
+        assert( deleting );}
+    static void Deleting( int on ) {
+        deleting = on;}
+    static int deleting;};
+
+int B::deleting = 0;
+
+
+class C: public gc_cleanup, public A {public:
+    /* A collectable class with cleanup and virtual multiple inheritance. */
+
+    C( int levelArg ): A( levelArg ), level( levelArg ) {
+        nAllocated++;
+        if (level > 0) {
+            left = new C( level - 1 );
+            right = new C( level - 1 );}
+        else {
+            left = right = 0;}}
+    ~C() {
+        this->A::Test( level );
+        nFreed++;
+        assert( level == 0 ? 
+                   left == 0 && right == 0 :
+                   level == left->level + 1 && level == right->level + 1 );
+        left = right = 0;
+        level = -123456;}
+    static void Test() {
+        assert( nFreed <= nAllocated && nFreed >= .8 * nAllocated );}
+
+    static int nFreed;
+    static int nAllocated;
+    int level;
+    C* left;
+    C* right;};
+
+int C::nFreed = 0;
+int C::nAllocated = 0;
+
+
+class D: public gc {public:
+    /* A collectable class with a static member function to be used as
+    an explicit clean-up function supplied to ::new. */
+
+    D( int iArg ): i( iArg ) {
+        nAllocated++;}
+    static void CleanUp( void* obj, void* data ) {
+        D* self = (D*) obj;
+        nFreed++;
+        assert( self->i == (int) data );}
+    static void Test() {
+        assert( nFreed >= .8 * nAllocated );}
+       
+    int i;
+    static int nFreed;
+    static int nAllocated;};
+
+int D::nFreed = 0;
+int D::nAllocated = 0;
+
+
+long Disguise( void* p ) {
+    return ~ (long) p;}
+
+void* Undisguise( long i ) {
+    return (void*) ~ i;}
+
+
+int main( int argc, char* argv[] ) {
+    int i, iters, n;
+
+    if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
+        fprintf( stderr, "usage: test_gc_c++ number-of-iterations\n" );
+        exit( 1 );}
+        
+    for (iters = 1; iters <= n; iters++) {
+        printf( "Starting iteration %d\n", iters );
+
+            /* Allocate some uncollectable As and disguise their pointers.
+            Later we'll check to see if the objects are still there.  We're
+            checking to make sure these objects really are uncollectable. */
+        long as[ 1000 ];
+        long bs[ 1000 ];
+        for (i = 0; i < 1000; i++) {
+            as[ i ] = Disguise( new (NoGC) A( i ) );
+            bs[ i ] = Disguise( new (NoGC) B( i ) );}
+
+            /* Allocate a fair number of finalizable Cs and Ds.  Later we'll
+            check to make sure they've gone away. */
+        for (i = 0; i < 1000; i++) {
+            C* c = new C( 2 );
+            D* d = ::new (GC, D::CleanUp, (void*) i) D( i );
+            if (0 == i % 10) delete c;}
+
+            /* Allocate a very large number of collectable As and Bs and
+            drop the references to them immediately, forcing many
+            collections. */
+        for (i = 0; i < 1000000; i++) {
+            A* a = new (GC) A( i );
+            B* b = new B( i );
+            b = new (GC) B( i );
+            if (0 == i % 10) {
+                B::Deleting( 1 );
+                delete b;
+                B::Deleting( 0 );}}
+
+            /* Make sure the uncollectable As and Bs are still there. */
+        for (i = 0; i < 1000; i++) {
+            A* a = (A*) Undisguise( as[ i ] );
+            B* b = (B*) Undisguise( bs[ i ] );
+            a->Test( i );
+            delete a;
+            b->Test( i );
+            B::Deleting( 1 );
+            delete b;
+            B::Deleting( 0 );}
+
+            /* Make sure most of the finalizable Cs and Ds have gone away. */
+        C::Test();
+        D::Test();}
+
+    printf( "The test appears to have succeeded.\n" );
+    return( 0 );}
+    
+