DIRECTORY Allocator USING[NHeaderP], AllocatorOps USING[ReferentType, REFToNHP], AtomPrivate, Process, RCMapOps USING[GetBase], RCMap USING[Index, Base], RecursivelyNIL, Rope USING[RopeRep], RTCommon USING[FetchField], RTTypesBasicPrivate USING[MapTiTd], SafeStorage USING[ReclaimCollectibleObjects, Type]; RecursivelyNILImpl: PROGRAM IMPORTS AllocatorOps, Process, RCMapOps, RTCommon, RTTypesBasicPrivate, SafeStorage EXPORTS RecursivelyNIL SHARES Rope = BEGIN rcmb: RCMap.Base = RCMapOps.GetBase[].base; lastREF: CARDINAL = 19; REFBlockRec: TYPE = RECORD [ prev: REFBlock _ NIL, next: REFBlock _ NIL, refs: ARRAY [0..lastREF] OF REF ANY _ ALL[NIL] ]; REFBlock: TYPE = REF REFBlockRec; phonyREFRec: TYPE = RECORD [ theREF: REF ANY _ NIL]; NILRef: PUBLIC PROC[root: REF ANY, checkProc: RecursivelyNIL.CheckProc _ NIL] = { pushBlock: REFBlock _ NIL ; pushBlockIndex: CARDINAL _ 0; currentRef: REF ANY; nilledRefs: INT _ 0 ; countForAbort: INT _ 0 ; phonyREF: REF phonyREFRec _ NEW[phonyREFRec]; ropeRepType: SafeStorage.Type = CODE[Rope.RopeRep]; atomRecType: SafeStorage.Type = CODE[AtomPrivate.AtomRec]; addRef: PROC [parentREF: REF ANY, refToAdd: REF ANY] RETURNS[NILit: BOOL _ TRUE] = INLINE { refToAddType: SafeStorage.Type = AllocatorOps.ReferentType[refToAdd]; IF refToAdd = NIL OR refToAddType = ropeRepType OR refToAddType = atomRecType THEN RETURN[FALSE]; IF checkProc # NIL AND ~checkProc[parentREF, AllocatorOps.ReferentType[parentREF], refToAdd, refToAddType] THEN RETURN[FALSE]; nilledRefs _ nilledRefs +1; IF nilledRefs > 2000 THEN { nilledRefs _ 0 ; SafeStorage.ReclaimCollectibleObjects[suspendMe: FALSE, traceAndSweep: FALSE] }; countForAbort _ countForAbort +1 ; IF countForAbort > 200 THEN { Process.CheckForAbort[]; }; IF pushBlock = NIL THEN pushBlock _ NEW[REFBlockRec]; IF pushBlockIndex > lastREF THEN { newBlock: REFBlock ; IF pushBlock.next = NIL THEN { newBlock _ NEW[REFBlockRec]; pushBlock.next _ newBlock } ELSE newBlock _ pushBlock.next; IF pushBlock # NIL THEN { newBlock.prev _ pushBlock; }; pushBlockIndex _ 0; pushBlock _ newBlock; }; pushBlock.refs[pushBlockIndex] _ refToAdd; pushBlockIndex _ pushBlockIndex + 1 ; }; popRef: PROC RETURNS [refPoped: REF ANY] = { IF pushBlockIndex = 0 THEN { IF pushBlock.prev = NIL THEN RETURN[NIL] ELSE { nowBlock: REFBlock _ pushBlock.prev; pushBlock.prev _ NIL; pushBlock _ nowBlock; pushBlockIndex _ lastREF; refPoped _ pushBlock.refs[pushBlockIndex]; pushBlock.refs[pushBlockIndex] _ NIL ; }; } ELSE { pushBlockIndex _ pushBlockIndex - 1; refPoped _ pushBlock.refs[pushBlockIndex]; pushBlock.refs[pushBlockIndex] _ NIL ; }; }; smashComponents: PROC[ref: REF ANY, ptr: LONG POINTER, rcmx: RCMap.Index] = { WITH rcmr: rcmb[rcmx] SELECT FROM null => NULL; oneRef => { IF addRef[ref, LOOPHOLE[ptr+rcmr.offset, LONG POINTER TO REF ANY]^] THEN { LOOPHOLE[phonyREF.theREF, LONG POINTER] _ LOOPHOLE[ptr+rcmr.offset, LONG POINTER TO LONG POINTER]^; -- copies the REF but does not change the reference count LOOPHOLE[ptr+rcmr.offset, LONG POINTER TO REF ANY]^ _ NIL ; -- NILs the REF to the object, but does not decrement the reference count=> reference count is now correct phonyREF.theREF _ NIL; -- nil the REF and decrement the reference count }; }; simple => FOR i: CARDINAL IN [0..rcmr.length) DO IF rcmr.refs[i] THEN { IF addRef[ref, LOOPHOLE[ptr+i, LONG POINTER TO REF ANY]^] THEN { LOOPHOLE[phonyREF.theREF, LONG POINTER] _ LOOPHOLE[ptr+i, LONG POINTER TO LONG POINTER]^; -- copies the REF but does not change the reference count LOOPHOLE[ptr+i, LONG POINTER TO REF ANY]^ _ NIL ; -- NILs the REF to the object, but does not decrement the reference count=> reference count is now correct phonyREF.theREF _ NIL; -- nil the REF and decrement the reference count }; }; ENDLOOP; ref => { IF addRef[ref, LOOPHOLE[ptr, LONG POINTER TO REF ANY]^] THEN { LOOPHOLE[phonyREF.theREF, LONG POINTER] _ LOOPHOLE[ptr, LONG POINTER TO LONG POINTER]^; -- copies the REF but does not change the reference count LOOPHOLE[ptr, LONG POINTER TO REF ANY]^ _ NIL ; -- NILs the REF to the object, but does not decrement the reference count=> reference count is now correct phonyREF.theREF _ NIL; -- nil the REF and decrement the reference count }; }; nonVariant => { FOR i: CARDINAL IN [0..rcmr.nComponents) DO smashComponents[ref, ptr + rcmr.components[i].wordOffset, rcmr.components[i].rcmi]; ENDLOOP; }; variant => { v: CARDINAL = RTCommon.FetchField[ptr + rcmr.fdTag.wordOffset, [bitFirst: rcmr.fdTag.bitFirst, bitCount: rcmr.fdTag.bitCount]]; smashComponents[ref, ptr, rcmr.variants[v]]; }; array => { FOR i: CARDINAL IN [0..rcmr.nElements) DO smashComponents[ref, ptr + i * rcmr.wordsPerElement, rcmr.rcmi]; ENDLOOP; }; sequence => { length: CARDINAL = RTCommon.FetchField[ptr+rcmr.fdLength.wordOffset, [bitFirst: rcmr.fdLength.bitFirst, bitCount: rcmr.fdLength.bitCount]]; smashComponents[ref, ptr, rcmr.commonPart]; FOR i: CARDINAL IN [0..length) DO smashComponents[ref, ptr + rcmr.dataOffset + i * rcmr.wordsPerElement, rcmr.rcmi]; ENDLOOP; }; ENDCASE => ERROR; }; currentRef _ root; WHILE currentRef # NIL DO i: INT _ 0 ; refType: SafeStorage.Type _ LOOPHOLE[AllocatorOps.ReferentType[currentRef], SafeStorage.Type]; nhp: Allocator.NHeaderP _ AllocatorOps.REFToNHP[currentRef]; rcmx: RCMap.Index = RTTypesBasicPrivate.MapTiTd[refType].rcmx; ptr: LONG POINTER = LOOPHOLE[currentRef, LONG POINTER]; IF ~nhp.f THEN smashComponents[currentRef, ptr, rcmx] ELSE {i _ i + 1}; currentRef _ popRef[]; ENDLOOP; pushBlock _ NIL; }; END. ®RecursivelyNILImpl.Mesa Copyright c 1985 by Xerox Corporation. All rights reserved. last edited On July 10, 1985 3:55:57 pm PDT by Bob Hagmann Given a REF ANY, process it and all reachable collectable objects from it and NIL out all REF containing fields. If an reachable object is finalizable, NIL out the ref to it, but do not process the object itself (possible violation of the package reference counts => ZCT Disaster). The internals of ROPEs are never processed. If a CheckProc is given, it is consulted every time a field is about to be NILed. If a TRUE is returned, the field is NILed and the previous REF is added to the processing. If FALSE is returned, the field is not NILed and the field's REF is not processed. A NIL checkProc means to always process. Although the module name is RecursivelyNILImpl, the implementation is not recursive. This is because it would consume too much MDS space. For all REFs inside of the currentRef, add to the queue. Then pop the end of the queue into currentRef. Done if NIL. Bob Hagmann May 20, 1985 8:29:38 am PDT modified: convert to Cedar 6.0 Bob Hagmann July 10, 1985 3:55:57 pm PDT modified: now will not destroy inside of ATOMs Êý˜šœ™Icodešœ Ïmœ1™<—Jšœ:™:J˜šÏk ˜ J˜Jšœ žœ ˜Jšœ žœ˜+Jšœ ˜ J˜Jšœ žœ ˜Jšœžœ˜Jšœ˜Jšœžœ ˜Jšœ žœ ˜Jšœžœ ˜#Jšœ žœ"˜3—J˜šœž˜JšžœL˜SJšžœ˜Jšžœ˜ —šœžœ˜J˜Jšœ+˜+J˜Jšœ žœ˜J˜šœ žœžœ˜Jšœžœ˜Jšœžœ˜Jš œžœžœžœžœžœžœ˜.J˜—J˜Jšœ žœžœ ˜!J˜Jš œ žœžœ žœžœžœ˜4J˜˜Jšœžœžœ?žœ žœ<žœpžœ’žœ2žœ!žœ5žœžœžœ#™ôJšœ€žœ™ŠJ˜—š Ïnœžœžœžœžœ(žœ˜QJšœžœ˜Jšœžœ˜Jšœ žœžœ˜Jšœ žœ˜Jšœžœ˜Jšœ žœžœ˜-Jšœ žœ˜3Jšœ žœ˜:J˜šÏbœžœ žœžœ žœžœžœžœžœžœ˜\JšœE˜EJšžœ žœžœžœžœžœžœ˜aJš žœ žœžœUžœžœžœ˜~J˜šžœžœ˜J˜Jšœ1žœžœ˜MJ˜—Jšœ"˜"šžœžœ˜Jšœ˜J˜—Jšžœ žœžœ žœ˜5šžœžœ˜"Jšœ˜šžœžœžœ˜Jšœ žœ˜Jšœ˜Jšœ˜—Jšœžœ˜ šžœ žœžœ˜J˜J˜—J˜J˜J˜—Jšœ*˜*Jšœ%˜%J˜J˜—š  œžœžœ žœžœ˜,šžœžœ˜Jš žœžœžœžœžœ˜(šœžœ˜J˜$Jšœžœ˜J˜Jšœ˜Jšœ*˜*Jšœ!žœ˜&J˜—J˜—šœžœ˜Jšœ$˜$Jšœ*˜*Jšœ!žœ˜&J˜—J˜—J˜š  œžœžœžœžœžœ˜Mšžœžœž˜!Jšœžœ˜ šœ ˜ šžœ žœžœžœžœžœžœžœ˜JJšžœžœžœžœžœžœžœžœžœÏc9˜žJšžœžœžœžœžœžœžœ¡j˜§Jšœžœ¡0˜HJ˜—J˜—šœ ˜ šžœžœžœž˜&Jšžœ ˜šžœ˜šžœ žœžœžœžœžœžœžœ˜@Jšžœžœžœžœžœžœžœžœžœ¡9˜”Jšžœžœžœžœžœžœžœ¡j˜Jšœžœ¡0˜HJ˜—J˜——Jšžœ˜—šœ˜šžœ žœžœžœžœžœžœžœ˜>Jšžœžœžœžœžœžœžœžœžœ¡9˜’Jšžœžœžœžœžœžœžœ¡j˜›Jšœžœ¡0˜HJ˜—J˜—šœ˜šžœžœžœž˜+JšœS˜SJšžœ˜—Jšœ˜—šœ ˜ Jšœžœ˜›Jšœ,˜,Jšœ˜—šœ ˜ šžœžœžœž˜)Jšœ@˜@Jšžœ˜—Jšœ˜—šœ ˜ Jšœžœ—˜§Jšœ+˜+šžœžœžœ ž˜!JšœR˜RJšžœ˜—Jšœ˜—Jšžœžœ˜—J˜—J˜Jšœ˜šžœžœž˜Jšœu™uJšœžœ˜ Jšœžœ:˜^Jšœ=˜=Jšœ>˜>Jš œžœžœžœ žœžœ˜7Jšžœžœ)žœ ˜HJšœ˜Jšžœ˜—Jšœ žœ˜J˜J˜J˜——J˜Jšžœ˜™'Kšœ™—™(Kšœ.™.—K™K™—…—Æ"q