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
<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 */
#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.
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);
}
(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	c(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-m2aSR*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*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!!!!!:
# 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.
# 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.
# 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
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,
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
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
$(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 *~
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,
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
!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
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)
+
+
+
# 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
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 -
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
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
--- /dev/null
+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.)
+
+
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
* 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"
}
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);
* 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
# 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
*
* 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
* 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.
*/
# 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. */
/* 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);
/* 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);
/* 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. */
*
* 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>
#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)))
}
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]);
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) {
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;
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;
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 {
/* 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 {
/* 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));
}
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");
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;
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);
}
}
{
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
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);
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;
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;
/* 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;
/* 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"
/* 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);
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) {
* 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>
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++) {
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);
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;
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);
}
* 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
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;
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(;;) {
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;
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 {
}
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)]);
}
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 */
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");
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");
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));
}
}
do_command(c);
}
done:
+ move(LINES-1, 0);
+ clrtoeol();
+ refresh();
+ nl();
+ echo();
endwin();
exit(0);
usage:
* 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 */
* 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);
/* 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 */);
/* 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 */
/* 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);
# 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)
# 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 */
/* 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 */
/* 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 */
/* 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))
# 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. */
/* 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);
#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 */
* 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 */
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
/* 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);
}
* 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>
#endif
-#ifdef SUNOS5
+#ifdef SUNOS5DL
#ifdef LINT
Elf32_Dyn _DYNAMIC;
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 ) {
#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
}
# 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();
((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;
* 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))
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;
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;
} 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) {
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;
# 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()
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++) {
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. */
* 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 */
* 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);
/* 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 */);
/* 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 */
/* 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);
# 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)
# 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 */
/* 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 */
/* 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 */
/* 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))
# 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. */
#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 */
+++ /dev/null
-
-/****************************************************************************
-
-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
-
/*************************************************************************
-
-
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.
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 */
+
--- /dev/null
+#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 */
+
* 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
# 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. */
/* 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 */);
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.*/
* 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
# 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. */
* 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
/* */
/*********************************/
-#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)
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()
# 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)
/* 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. */
* 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:
} else if (index_p->index[j] == 0) {
j--;
} else {
- j -= (int)(index_p->index[j]);
+ j -= (word)(index_p->index[j]);
}
}
}
/* 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>
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]);
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+# 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 */
/*
* 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>
/* 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 */
/* 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 */
/*
* 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);
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 */);
/* 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
/* 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 */
/* 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. */
# 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)
# 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 */
# 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 */
# 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 */
/* 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. */
/* 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 */
/* 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 */
/* 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))
# 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 */
--- /dev/null
+# include "gc_cpp.h"
--- /dev/null
+#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 */
+
+/*
+ * 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.
* 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
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. */
/* 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);
--- /dev/null
+/*
+ * 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
* 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 */
# endif
# if defined(M68K) && defined(MACOS)
+# if defined(THINK_C)
# define PushMacReg(reg) \
move.l reg,(sp) \
jsr GC_push_one
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");
__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
# 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 */
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
/* 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:");
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
# 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 */
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*/
* 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 */
}
# 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;
{
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;
}
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 */
}
#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
}
+#ifndef UNALIGNED
+
/* Push all objects reachable from marked objects in the given block */
/* of size 2 objects. */
void GC_push_marked2(h, hhdr)
# undef GC_least_plausible_heap_addr
}
+#endif UNALIGNED
+
#endif /* SMALL_CONFIG */
/* Push all objects reachable from marked objects in the given block */
}
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;
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);
* 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"
/* 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 */
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();
}
* 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>
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] */
register word r;
register struct hblk *h;
register hdr *candidate_hdr;
+ register word limit;
r = (word)p;
h = HBLKPTR(r);
/* 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);
}
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.) */
word dummy;
if (GC_is_initialized) return;
- GC_is_initialized = TRUE;
# ifdef MSWIN32
GC_init_win32();
# endif
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
# 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
}
# 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()
{
}
#endif
-#ifdef OS2
+#if defined(OS2) || defined(MACOS)
void GC_set_files()
{
if (GC_stdout == NULL) {
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))
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))
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))
* 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"
/* 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))
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;
}
word dummy;
ptr_t result;
-# define STACKBOTTOM_ALIGNMENT_M1 0xffffff
+# define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
# ifdef STACKBOTTOM
return(STACKBOTTOM);
# 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 */
# 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));
}
# endif
+
void GC_register_data_segments()
{
# if !defined(NEXT) && !defined(MACOS)
# 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. */
#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;
# 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
# 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 =
# 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;
}
}
}
}
+
+#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");
# 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
}
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();
}
(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:");
}
}
}
#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()
# 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
gc.man
pc_excludes
barrett_diagram
+include/gc_c++.h
+include/gc_inline.h
\ No newline at end of file
--- /dev/null
+/*
+ * 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);
+}
+
* 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()
}
#endif
-#if defined(SUNOS5)
-#define _CLASSIC_XOPEN_TYPES
+#if defined(SUNOS5) || defined(DRSNX)
#include <unistd.h>
int
getpagesize()
* 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)
/* 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 */
}
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 */
/* 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 */
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;
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 */
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;
}
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);
* 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"
struct SEXPR * sexpr_cdr;
};
+
# ifdef __STDC__
typedef void * void_star;
# else
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)
exit(1);
}
r -> sexpr_car = x;
- r -> sexpr_cdr = (sexpr) (~(unsigned long)y);
+ r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
return(r);
}
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)));
}
}
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)));
}
}
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 */
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)
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--) {
}
}
+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
/* 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");
/* 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,
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);
--- /dev/null
+/****************************************************************************
+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 );}
+
+