DIRECTORY Allocator USING [NHeaderP, NormalHeader, RefCount, BlockSizeIndex, FNHeaderP], AllocatorOps USING [PlausibleRef, REFToNHP, sizeToBSI, bsiToSize, ExpandNormalFreeList, FreeObject], Basics USING [Byte, BITAND, BITOR, BITSHIFT, BITXOR, CARD, LowHalf, LongNumber], CedarMicrocode USING [RECLAIMABLEREF, DISABLEMICROCODE, ENABLEMICROCODE], Collector USING [InternalReclaim, Disposition, Reclaim], DebuggerSwap USING [CallDebugger], PrincOps USING [ControlLink, StateVector, zRET], PrincOpsUtils USING [Codebase, GetReturnLink, MyLocalFrame], RCMap USING [nullIndex], RCMicrocodeOps USING [FOSTableHash, ASSIGNREF, OnZ, CREATEREF, RECLAIMABLEREF, RECLAIMEDREF, DISABLEMICROCODE, ENABLEMICROCODE, RCOverflowOccurred, RCUnderflowOccurred, LookFurtherAtReclaimedRef, ZCTFull, rcMicrocodeExists, rcMicrocodeWasEnabled, ALLOCATE, FREEPLEASE, NormalFreeListEmpty], RTFrameHeapSnapshot USING [AcquireFrameHeapSnapshot, MapUncountedBodies, ReleaseFrameHeapSnapshot], RTTypesBasicPrivate USING [MapTiTd], SafeStorage USING [Type, nullType], StorageTraps USING [], TrapSupport USING [BumpPC, GetTrapParam], VM USING [Allocate, Free, Interval, AddressForPageNumber], ZCT USING [fosEmpty, FOSTableIndex, FOSTableObject, FOSTableResidue, HandleRCOverflow, HandleRCUnderflow, InitializeCleanup, logZCTBlockPages, TryToQItForFinalization, zct, zctBlockPages, zctBlockWords, ZCTObject, ZeroCountTable]; ZCTImpl: MONITOR IMPORTS AllocatorOps, Basics, CedarMicrocode, Collector, DebuggerSwap, PrincOpsUtils, RCMicrocodeOps, RTFrameHeapSnapshot, RTTypesBasicPrivate, TrapSupport, VM, ZCT EXPORTS RCMicrocodeOps, StorageTraps, ZCT = BEGIN OPEN Allocator, AllocatorOps, Collector, RCMicrocodeOps, ZCT; CARD: TYPE = Basics.CARD; checking: BOOL = FALSE; takingStatistics: BOOL = TRUE; Bump: PROC [p: POINTER TO INT, delta: INT _ 1] = INLINE { IF takingStatistics THEN p^ _ p^+delta; }; StatsRec: TYPE = RECORD [ nExpandZCTCalls: INT _ 0, nZCTBlocks: INT _ 0 ]; stats: StatsRec _ []; -- the one and only SoftwareCreateRef: PUBLIC PROC [nhp: NHeaderP] = { DO { DoCreateRef[nhp ! ZCTFull => GOTO zctFull]; EXIT; EXITS zctFull => ExpandZCT[]; }; ENDLOOP; }; AssignRefNew: PROC [rhs: REF ANY, lhs: LONG POINTER TO REF ANY] = { IF checking AND lhs^ # NIL THEN ERROR; AssignRef[rhs, lhs]; }; AssignRef: --PUBLIC-- PROC [rhs: REF, lhs: LONG POINTER TO REF] = { DO { DoAssignRef[rhs, lhs ! -- PageFault => {SatisfyPageFault[]; RETRY}; RCUnderflowOccurred => GOTO handleRCUnderflow; RCOverflowOccurred => GOTO handleRCOverflow; ZCTFull => GOTO zctFull; ]; RETURN; EXITS handleRCUnderflow => HandleRCUnderflow[lhs^]; handleRCOverflow => HandleRCOverflow[rhs]; zctFull => ExpandZCT[]; }; ENDLOOP; }; SoftwareReclaimedRef: PUBLIC PROC [ref: REF ANY] RETURNS [ans: REF ANY _ NIL] = { DO { ans _ DoReclaimedRef[ref -- if a signal, the decrement was NOT DONE ! RCUnderflowOccurred => GOTO handleRCUnderflow; ZCTFull => GOTO zctFull; LookFurtherAtReclaimedRef => GOTO lookFurther; ]; RETURN; EXITS zctFull => ExpandZCT[]; handleRCUnderflow => HandleRCUnderflow[ref]; }; ENDLOOP; EXITS lookFurther => FinalizeReclaimedRef[ref]; }; SoftwareAllocate: PUBLIC PROC [size: CARDINAL, type: SafeStorage.Type] RETURNS [r: REF _ NIL] = { DO { r _ SoftwareAllocateEntry[size, type ! NormalFreeListEmpty => GOTO expandNormalFreeList; ZCTFull => GOTO zctFull]; RETURN; EXITS expandNormalFreeList => ExpandNormalFreeList[sizeToBSI[size]]; zctFull => ExpandZCT[]; }; ENDLOOP; }; SoftwareFree: PUBLIC PROC [nhp: NHeaderP] RETURNS [success: BOOL] = { success _ SoftwareFreeEntry[nhp]; }; ScanTheFrameHeap: PUBLIC PROC = { PlausibleRefFoundOnStack: PROC [lc: CARD] = { index: FOSTableIndex; residue: FOSTableResidue; fosTable: LONG POINTER TO FOSTableObject = LOOPHOLE[zct+SIZE[ZCTObject], LONG POINTER TO FOSTableObject]; [index, residue] _ FOSTableHash[LOOPHOLE[lc - SIZE[NormalHeader], NHeaderP--maybe bogus--]]; SELECT fosTable[index] FROM fosEmpty => fosTable[index] _ residue; residue => { }; ENDCASE => fosTable[index] _ Basics.BITOR[fosEmpty, Basics.BITOR[fosTable[index], residue]]; }; ConservativeScanner: PROC [d: LONG DESCRIPTOR FOR ARRAY OF WORD] = { pa: LONG POINTER TO CARD = LOOPHOLE[BASE[d], LONG POINTER TO CARD]; nWords: CARDINAL = LENGTH[d]; IF nWords >= SIZE[REF] THEN FOR i: CARDINAL IN [0..nWords-SIZE[REF]] DO addr: CARD = (pa+i)^; IF PlausibleRef[addr] THEN PlausibleRefFoundOnStack[addr]; ENDLOOP; }; RTFrameHeapSnapshot.AcquireFrameHeapSnapshot[]; RTFrameHeapSnapshot.MapUncountedBodies[ConservativeScanner ! UNWIND => RTFrameHeapSnapshot.ReleaseFrameHeapSnapshot[]]; RTFrameHeapSnapshot.ReleaseFrameHeapSnapshot[]; }; MapReclaimableObjects: PUBLIC PROC [reclaim: PROC [NHeaderP]] = { wp: LONG POINTER TO NHeaderP = ReadWP[]; IF reclaim # NIL THEN ERROR; FOR nhp: NHeaderP _ PullNextEntry[wp, FALSE], PullNextEntry[wp, FALSE] UNTIL nhp = NIL DO d: Disposition; IF nhp.refCount # 0 THEN DO { OnZEntry[nhp ! ZCTFull => GOTO zctFull]; d _ continue; EXIT; EXITS zctFull => ExpandZCT[]; }; ENDLOOP ELSE DO { d _ ReclaimableRef[nhp ! ZCTFull => GOTO zctFull]; EXIT; EXITS zctFull => ExpandZCT[]; }; ENDLOOP; SELECT d FROM continue => NULL; -- either it was re-queued on zct or left off reclaimIt => IF RTTypesBasicPrivate.MapTiTd[nhp.type].rcmx = RCMap.nullIndex THEN AllocatorOps.FreeObject[nhp] ELSE Collector.Reclaim[nhp]; finalizeIt => IF NOT TryToQItForFinalization[nhp] THEN DO { OnZEntry[nhp ! ZCTFull => GOTO zctFull]; EXIT; EXITS zctFull => ExpandZCT[]; }; ENDLOOP; ENDCASE => ERROR; ENDLOOP; }; ReclaimableRef: PROC [nhp: NHeaderP] RETURNS [Disposition] = { IF rcMicrocodeExists THEN RETURN [CedarMicrocode.RECLAIMABLEREF[nhp]] ELSE RETURN [SoftwareReclaimableRef[nhp]]; }; SoftwareReclaimableRef: PROC [nhp: NHeaderP] RETURNS [d: Disposition] = { DO { d _ DoReclaimableRef[nhp ! ZCTFull => GOTO zctFull]; RETURN; EXITS zctFull => ExpandZCT[]; }; ENDLOOP; }; ResetStackBits: PUBLIC PROC = { -- and compactify zct wp: LONG POINTER TO NHeaderP = ReadWP[]; FOR nhp: NHeaderP _ PullNextEntry[wp, TRUE], PullNextEntry[wp, TRUE] UNTIL nhp = NIL DO IF nhp.refCount = 0 AND NOT nhp.rcOverflowed THEN DO { OnZEntry[nhp ! ZCTFull => GOTO zctFull]; EXIT; EXITS zctFull => ExpandZCT[]; }; ENDLOOP; ENDLOOP; ClearFOSTable[]; }; PullNextEntry: PROC [wp: LONG POINTER TO NHeaderP, clearOnStack: BOOL] RETURNS [nhp: NHeaderP _ NIL] = { DO n: CARDINAL; IF zct.rp = wp THEN RETURN [NIL]; -- nomore nhp _ zct.rp^; IF checking AND nhp = NIL THEN ERROR; n _ Basics.BITAND[Basics.LowHalf[LOOPHOLE[zct.rp, CARD]], zctBlockWords-1]; IF n = zctBlockWords - SIZE[LONG POINTER] -- rp points to the link; nhp has it THEN { zct.rp^ _ NIL; -- clears the link to the next zctBlock. [] _ DoExpandZCT[zct.rp + SIZE[LONG POINTER] - zctBlockWords, FALSE]; zct.rp _ LOOPHOLE[nhp, LONG POINTER TO NHeaderP]; } ELSE { zct.rp _ zct.rp + SIZE[LONG POINTER]; nhp.inZCT _ FALSE; -- was TRUE (no race!!) IF clearOnStack THEN nhp.maybeOnStack _ FALSE; -- called from ResetStackBits IF nhp.refCount = 0 OR (~clearOnStack AND nhp.maybeOnStack) THEN RETURN; }; ENDLOOP; }; ExpandZCT: PUBLIC PROC = { success: BOOL; zbInterval: VM.Interval = VM.Allocate[count: zctBlockPages, alignment: logZCTBlockPages]; p: LONG POINTER _ VM.AddressForPageNumber[zbInterval.page]; Bump[@stats.nExpandZCTCalls]; InternalReclaim[reason: rcTableOverflow, suspendMe: FALSE]; -- just poke it LOOPHOLE[p + zctBlockWords - SIZE[LONG POINTER], LONG POINTER TO NHeaderP]^ _ NIL; -- clear the link success _ DoExpandZCT[p, TRUE]; IF success THEN Bump[@stats.nZCTBlocks] ELSE VM.Free[zbInterval]; }; ClearFOSTable: PROC = { LOOPHOLE[zct+SIZE[ZCTObject], LONG POINTER TO FOSTableObject]^ _ ALL[fosEmpty]; }; Enter: PUBLIC ENTRY PROC = {ENABLE UNWIND => NULL; NULL}; EnterAndCallBack: PUBLIC ENTRY PROC [proc: PROC] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; proc[]; [] _ EnableMicrocode[zct]; }; DoAssignRef: ENTRY PROC [rhs: REF, lhs: LONG POINTER TO REF] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; ASSIGNREF[rhs, lhs]; [] _ EnableMicrocode[zct]; }; DoCreateRef: ENTRY PROC [nhp: NHeaderP] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; CREATEREF[nhp]; [] _ EnableMicrocode[zct]; }; StartMarkingDecrements: PUBLIC ENTRY PROC = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; zct.markingDecrements _ TRUE; zct.residueMask _ Basics.BITOR[Basics.BITSHIFT[zct.residueMask, 3], Basics.BITSHIFT[zct.residueMask, -13]]; [] _ EnableMicrocode[zct]; }; StopMarkingDecrements: PUBLIC ENTRY PROC = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; zct.markingDecrements _ FALSE; [] _ EnableMicrocode[zct]; }; DoReclaimableRef: ENTRY PROC [nhp: NHeaderP] RETURNS [d: Disposition] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; d _ RECLAIMABLEREF[nhp]; -- The only call on RECLAIMABLEREF [] _ EnableMicrocode[zct]; }; DoReclaimedRef: ENTRY PROC [ref: REF ANY] RETURNS [ans: REF ANY _ NIL] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; ans _ RECLAIMEDREF[ref]; [] _ EnableMicrocode[zct]; }; ReadWP: ENTRY PROC RETURNS [wp: LONG POINTER TO Allocator.NHeaderP] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; wp _ zct.wp; [] _ EnableMicrocode[zct]; }; FinalizeReclaimedRef: PROC [ref: REF] = { nhp: NHeaderP = REFToNHP[ref]; IF Basics.LowHalf[LOOPHOLE[nhp]] MOD 2 = 1 THEN DebuggerSwap.CallDebugger["ZCT disaster"L]; DO { DecrementForFinalizeReclaimedRef[nhp ! RCUnderflowOccurred => GOTO handleRCUnderflow]; EXIT; EXITS handleRCUnderflow => HandleRCUnderflow[ref]; }; ENDLOOP; IF NOT TryToQItForFinalization[nhp] THEN DO { OnZEntry[nhp ! ZCTFull => GOTO zctFull]; EXIT; EXITS zctFull => ExpandZCT[]; }; ENDLOOP; }; DecrementForFinalizeReclaimedRef: ENTRY PROC [nhp: NHeaderP] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; rc: RefCount; DisableMicrocode[zct]; rc _ nhp.refCount; IF checking AND rc = 0 AND NOT nhp.rcOverflowed THEN ERROR; IF rc = 0 AND nhp.rcOverflowed THEN ERROR RCUnderflowOccurred; -- no changes have been made nhp.refCount _ rc - 1; [] _ EnableMicrocode[zct]; }; DoEnableFinalization: PUBLIC ENTRY PROC [npr: NAT, nhp: NHeaderP] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; rc: RefCount; DisableMicrocode[zct]; IF checking AND nhp.f THEN ERROR; rc _ nhp.refCount; IF checking AND rc < npr AND NOT nhp.rcOverflowed THEN ERROR; IF rc < npr AND nhp.rcOverflowed THEN ERROR RCUnderflowOccurred; IF rc = npr AND NOT nhp.rcOverflowed THEN OnZ[nhp]; -- might raise ZCTFull nhp.refCount _ rc - npr; nhp.f _ TRUE; nhp.maybeOnStack _ zct.markingDecrements; [] _ EnableMicrocode[zct]; }; DisableFinalization: PUBLIC ENTRY PROC [npr: NAT, nhp: NHeaderP] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; rc: RefCount; DisableMicrocode[zct]; IF checking AND NOT nhp.f THEN ERROR; rc _ nhp.refCount; FOR i: NAT IN [0..npr) DO IF rc + i = LAST[RefCount] THEN ERROR RCOverflowOccurred; ENDLOOP; nhp.refCount _ rc + npr; nhp.f _ FALSE; nhp.maybeOnStack _ FALSE; [] _ EnableMicrocode[zct]; }; DecrForOverflow: PUBLIC ENTRY PROC [rcDelta: NAT, nhp: NHeaderP] RETURNS [success: BOOL _ FALSE] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; IF nhp.refCount = LAST[RefCount] THEN { nhp.refCount _ nhp.refCount - rcDelta; success _ TRUE; }; [] _ EnableMicrocode[zct]; }; IncrForUnderflow: PUBLIC ENTRY PROC [rcDelta: NAT, nhp: NHeaderP] RETURNS [success: BOOL _ FALSE] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; IF nhp.refCount = 0 THEN { nhp.refCount _ nhp.refCount + rcDelta; success _ TRUE; }; [] _ EnableMicrocode[zct]; }; DoExpandZCT: ENTRY PROC [newZCTBlock: LONG POINTER, onlyIfNeeded: BOOL] RETURNS [success: BOOL _ TRUE] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; IF NOT onlyIfNeeded OR zct.lastNP = ComputeLastNP[zct.wp] THEN { zct.lastNP^ _ newZCTBlock; zct.lastNP _ LOOPHOLE[ newZCTBlock + zctBlockWords-SIZE[LONG POINTER], LONG POINTER TO LONG POINTER]; } ELSE success _ FALSE; [] _ EnableMicrocode[zct]; }; ComputeLastNP: INTERNAL PROC [wp: LONG POINTER TO NHeaderP] RETURNS [lastNP: LONG POINTER TO LONG POINTER] = { n: Basics.LongNumber _ LOOPHOLE[wp, Basics.LongNumber]; n.lowbits _ Basics.BITXOR[n.lowbits, Basics.BITAND[n.lowbits, zctBlockWords-1]]; RETURN [LOOPHOLE[n, LONG POINTER TO NHeaderP] + zctBlockWords - SIZE[LONG POINTER] ]; }; SoftwareAllocateEntry: ENTRY PROC [size: CARDINAL, type: SafeStorage.Type] RETURNS [r: REF _ NIL] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; r _ RCMicrocodeOps.ALLOCATE[size, type]; [] _ EnableMicrocode[zct]; }; SoftwareFreeEntry: ENTRY PROC [nhp: NHeaderP] RETURNS [success: BOOL] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; success _ RCMicrocodeOps.FREEPLEASE[nhp]; [] _ EnableMicrocode[zct]; }; InsertQuanta: PUBLIC ENTRY PROC [bsi: BlockSizeIndex, first, last: FNHeaderP] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; last.nextFree _ zct.bsiToFreeList[bsi]; zct.bsiToFreeList[bsi] _ first; [] _ EnableMicrocode[zct]; }; DoFREE: PUBLIC ENTRY PROC [fnhp: FNHeaderP, bsi: BlockSizeIndex] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; fnhp.fnh.type _ SafeStorage.nullType; -- mark the object as free fnhp.nextFree _ zct.bsiToFreeList[bsi]; zct.bsiToFreeList[bsi] _ fnhp; [] _ EnableMicrocode[zct]; }; Initialize: ENTRY PROC = { ENABLE UNWIND => NULL; zct.rp _ zct.wp _ LOOPHOLE[ VM.AddressForPageNumber[ VM.Allocate[count: zctBlockPages, alignment: logZCTBlockPages].page ], LONG POINTER TO Allocator.NHeaderP ]; zct.lastNP _ LOOPHOLE[ zct.wp+zctBlockWords-SIZE[LONG POINTER], LONG POINTER TO LONG POINTER]; zct.lastNP^ _ NIL; ClearFOSTable[]; zct.markingDecrements _ FALSE; zct.residueMask _ 76031B; zct.bsiToFreeList _ ALL[NIL]; zct.sizeToBSI _ sizeToBSI^; zct.bsiToSize _ bsiToSize^; InitializeCleanup[]; }; OnZEntry: ENTRY PROC [nhp: NHeaderP] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; OnZ[nhp]; [] _ EnableMicrocode[zct]; }; DisableMicrocode: INTERNAL PROC [zct: ZeroCountTable] = { IF rcMicrocodeExists THEN CedarMicrocode.DISABLEMICROCODE[zct] ELSE DISABLEMICROCODE[zct]; rcMicrocodeWasEnabled _ FALSE; }; EnableMicrocode: INTERNAL PROC [zct: ZeroCountTable] RETURNS [ucVersion: NAT] = { IF rcMicrocodeExists THEN ucVersion _ CedarMicrocode.ENABLEMICROCODE[zct] ELSE ucVersion _ ENABLEMICROCODE[zct]; rcMicrocodeWasEnabled _ TRUE; }; DisableMicrocodeTrap: PUBLIC PROC [zct: ZeroCountTable] = { state: PrincOps.StateVector; state _ STATE; -- incantation SELECT (IF rcMicrocodeExists THEN TrapSupport.GetTrapParam[] ELSE 0) FROM 0 => NULL; -- no microcode ENDCASE => ERROR; TrapSupport.BumpPC[2]; -- length of opcode state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation }; EnableMicrocodeTrap: PUBLIC PROC [zct: ZeroCountTable] RETURNS [ucVersion: NAT _ 0] = { state: PrincOps.StateVector; state _ STATE; -- incantation SELECT (IF rcMicrocodeExists THEN TrapSupport.GetTrapParam[] ELSE 0) FROM 0 => NULL; -- no microcode ENDCASE => ERROR; TrapSupport.BumpPC[2]; -- length of opcode state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation }; ReclaimableRefTrap: PUBLIC PROC [nhp: NHeaderP] RETURNS [d: Disposition] = { state: PrincOps.StateVector; state _ STATE; -- incantation SELECT (IF rcMicrocodeExists THEN TrapSupport.GetTrapParam[] ELSE 0) FROM 0 => d _ SoftwareReclaimableRef[nhp]; 2 => { p: PROC [nhp: NHeaderP] = MACHINE CODE{PrincOps.zRET}; Enter[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[nhp]; -- try again }; 4 => { p: PROC [nhp: NHeaderP] = MACHINE CODE{PrincOps.zRET}; ExpandZCT[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[nhp]; }; 5 => DebuggerSwap.CallDebugger["ZCT disaster"L]; -- DISASTER ENDCASE => ERROR; TrapSupport.BumpPC[2]; -- length of opcode state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation }; ReclaimedRefTrap: PUBLIC PROC [ref: REF ANY] RETURNS [ans: REF ANY _ NIL] = { p: PROC [ref: REF ANY] = MACHINE CODE{PrincOps.zRET}; state: PrincOps.StateVector; state _ STATE; -- incantation SELECT (IF rcMicrocodeExists THEN TrapSupport.GetTrapParam[] ELSE 0) FROM 0 => ans _ SoftwareReclaimedRef[ref]; -- no microcode 2 => { Enter[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[ref]; -- try again }; 3 => { HandleRCUnderflow[ref]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[ref]; -- try again }; 4 => { ExpandZCT[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[ref]; }; 5 => DebuggerSwap.CallDebugger["ZCT disaster"L]; -- DISASTER 6 => FinalizeReclaimedRef[ref]; -- LookFurtherAtReclaimedRef ENDCASE => ERROR; TrapSupport.BumpPC[2]; -- length of opcode state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation }; CreateRefTrap: PUBLIC PROC [nhp: NHeaderP] = { state: PrincOps.StateVector; state _ STATE; -- incantation SELECT (IF rcMicrocodeExists THEN TrapSupport.GetTrapParam[] ELSE 0) FROM 0 => SoftwareCreateRef[nhp]; -- no microcode 2 => { p: PROC [nhp: NHeaderP] = MACHINE CODE{PrincOps.zRET}; Enter[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[nhp]; }; 4 => { p: PROC [nhp: NHeaderP] = MACHINE CODE{PrincOps.zRET}; ExpandZCT[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[nhp]; }; ENDCASE => ERROR; TrapSupport.BumpPC[2]; -- length of opcode state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation }; AssignRefTrap: PUBLIC PROC [refNew: REF, ptrRef: LONG POINTER TO REF] = { state: PrincOps.StateVector; alphaRef: LONG POINTER TO REF; p: PROC [refNew: REF, ptrRef: LONG POINTER TO REF] = MACHINE CODE { PrincOps.zRET; }; state _ STATE; -- incantation alphaRef _ AddAlphaByte[ptrRef, PrincOpsUtils.GetReturnLink[]]; SELECT (IF rcMicrocodeExists THEN TrapSupport.GetTrapParam[] ELSE 0) FROM 0 => AssignRef[refNew, alphaRef]; -- no microcode 1 => { HandleRCOverflow[refNew]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[refNew, ptrRef]; -- try again }; 2 => { Enter[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[refNew, ptrRef]; -- try again }; 3 => { HandleRCUnderflow[alphaRef^]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[refNew, ptrRef]; -- try again }; 4 => { ExpandZCT[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[refNew, ptrRef]; -- try again }; 5 => DebuggerSwap.CallDebugger["ZCT disaster"L]; -- DISASTER ENDCASE => ERROR; TrapSupport.BumpPC[2]; -- length of opcode state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation }; AddAlphaByte: PROC [ptrRef: LONG POINTER TO REF, ctL: PrincOps.ControlLink] RETURNS [LONG POINTER TO REF] = { codeB: LONG POINTER TO PACKED ARRAY OF Basics.Byte _ LOOPHOLE[PrincOpsUtils.Codebase[LOOPHOLE[ctL.frame.accesslink]]]; alpha: Basics.Byte _ codeB[ctL.frame.pc + 1]; RETURN [LOOPHOLE[ptrRef + alpha]]; }; Initialize[]; END. ZCTImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Implementation of the Zero Count Table for the Cedar incremental collector created by Paul Rovner, January 18, 1984 9:36:15 am PST Russ Atkinson (RRA) October 29, 1985 10:17:50 am PST protects the ZeroCountTable and object headers, notably their refCounts CONSTANTS STATISTICS usage: Bump[@stats.nExpandZCTCalls]; PROCEDURES REFERENCE COUNTING See CREATEREF, the ucode replacement for this guy See ASSIGNREF, the ucode replacement for this guy See ASSIGNREF, the ucode replacement for this guy this is the only catch for RCOverflowOccurred increment, assnmt were NOT DONE See RECLAIMEDREF, the ucode replacement for this guy ReclaimedRef is called by the reclaimer on each (non-NIL) ref that it finds within an object being reclaimed. ReclaimedRef will decrement the reference count on ref^ and return a non-NIL result (= ref) if the referenced object can be reclaimed (it will not enter it in the zct in this case). If ref^ can't be reclaimed, ReclaimedRef will return NIL. ReclaimedRef will queue ref^ for finalization if necessary. It will deal with rc underflow. It is possible (a finalized object, no room on its finalization queue) that ReclaimedRef will enter the ref on the zct. If the zct is full, ReclaimedRef will expand the zct. ALLOCATION AND RECLAMATION COLLECTOR, ZCT There was no previous entry, so just store the residue We just found the single same thing that was there before A collision, so OR in the bits from the new residue (also OR in the fosEmpty value to show the collision). and compactify zct nhp has been removed from zct put it back on the ZCT so that ResetStackBits will eliminate it and clean the maybeOnStack bit rc = 0 & not onstack & ~f: reclaim it (it was removed from zct)! rc = 0 & ~ not onstack & f finalization q is full it should stay in the zct This may raise ZCTFull. Ifso, no changes have been made This is called only from MapReclaimableObjects See RECLAIMABLEREF, the ucode replacement for this guy This is called only from ReclaimableRef nhp has been removed from zct - put it back This is called by MapReclaimableObjects and ResetStackBits This is the only proc that sets nhp.inZCT _ FALSE or reads or writes zct.rp wp will never point to a link This returns NIL if there are no more ZCT entries to read This is the next good candidate for implementation in microcode Here with non-NIL nhp; maybe a link we're done with this zctBlock and go around again to scrutinize this guy further ENTRY PROCS 0. Enter ... used by trap handlers and TraceAndSweepImpl 1. AssignRef This is called only from AssignRef This may raise ZCTFull, RCOverflowOccurred, RCUnderflowOccurred 2. CreateRef This is called only from SoftwareCreateRef DoCreateRef may raise ZCTFull 3. Collector and reclaimer This is called only from SoftwareReclaimableRef This is called only from SoftwareReclaimedRef This may raise ZCTFull, RCUnderflowOccurred, LookFurtherAtReclaimedRef 4. Finalization ... called from FQImpl Called from ReclaimedRefTrap and from SoftwareReclaimedRef refCount = 1 & ~ rcOverflowed & ~ maybeOnStack & ~ inZCT & f i.e. if the object has npr + 1 REFs, is referenced from an object that is being reclaimed and is to be finalized. Decrement its rc and try to q it. This must NOT be odd! finalization q is full it should stay in the zct called only from FinalizeReclaimedRef. May raise RCUnderflowOccurred. called only from FQImpl.EnableFinalization. May raise ZCTFull or RCUnderflowOccurred. no changes have been made NOTE if npr > 1 then this will be reported as a finalization error but shouldn't be. The (implementation) problem is that an RCUnderflowOccurred handler can't deal with npr > 1 called only from FQImpl.TryToQItForFinalization. May raise RCOverflowOccurred. NOTE if npr > 1 then this will be reported as a finalization error but shouldn't be. The (implementation) problem is that an RCOverflowOccurred handler can't deal with npr > 1 increment was NOT done The handler for RCOverflowOccurred makes adjustments, not changes 5. RC overflow ... called from RCOvImpl called only from RCOvImpl.HandleRCOverflow called only from RCOvImpl.HandleRCUnderflow 6. ZCT expansion. These are called during recovery from a ZCTFull signal. called from ExpandZCT and from PullNextEntry zct.lastNP^ = NIL 7. Allocation, reclamation See AllocatorImpl.TAndSDoFreeNormalFragment 8. Utilities This may raise ZCTFull. See DISABLEMICROCODE, the ucode replacement for this guy cause rc operations to trap (except EnableMicrocode) See ENABLEMICROCODE, the ucode replacement for this guy TRAP HANDLERS no microcode uCode is disabled; someone is inside this monitor zctFull uCode is disabled; someone is inside this monitor handleRCUnderflow: decrement was NOT DONE zctFull uCode is disabled; someone is inside this monitor zctFull handleRCOverflow: rc ops and assnmt were NOT DONE uCode is disabled; someone is inside this monitor handleRCUnderflow: decrement, assnmt were NOT DONE (this does the decrement, assigns NIL, then goes around again) zctFull read the alpha byte for the trapping opcode & add it to ptrRef Κ₯˜codešœ ™ Kšœ Οmœ1™˜>Kšœ˜—K˜—Kšžœ˜—Kšœ˜—K˜š Οb œžœžœžœ žœ˜EKšœ!˜!Kšœ˜—K˜—šœ™K˜šŸœž œ˜!šŸœžœžœ˜-Kšœ˜Kšœ˜šœ žœžœžœ˜(Kš œžœžœ žœžœžœ˜@—šœ˜Kšœžœžœ œ˜K—šžœž˜šœ ˜ Kšœ6™6Kšœ˜—šœ ˜ Kšœ9™9Kšœ˜—šžœ˜ Kšœj™jKšœžœžœ˜Q——Kšœ˜—šŸœžœžœž œžœžœžœžœ˜Dšœžœžœžœž˜Kš œžœžœžœžœžœžœ˜*—Kšœžœžœ˜šžœ žœžœž˜š žœžœžœ žœžœž˜+Kšœžœ ˜Kšžœžœ ˜:Kšžœ˜——Kšœ˜—Kšœ/˜/šœ:˜:Kšœžœ4˜<—Kšœ/˜/Kšœ˜—K˜šŸœžœžœ žœ˜AKšœ™Kšœžœžœžœ˜(Kšžœ žœžœžœ˜š žœ#žœžœžœžœž˜YKšœ™Kšœ˜šžœ˜šžœž˜šœ˜šœžœ ˜(Kšœ^™^—Kšœ ˜ Kšžœ˜Kšžœ˜K˜—Kšž˜—šžœž˜šœ˜Kšœ$žœ ˜2Kšžœ˜Kšžœ˜K˜—Kšžœ˜——šžœž˜ Kšœ žœ -˜@šœ ˜ šžœ=˜?Kšžœžœ˜>—Kšœ@™@—šœ ˜ Kšœ™šžœžœžœž˜+Kšœ™šœ˜Kšœ™Kšœžœ ˜(Kšžœ˜Kšžœ˜K˜—Kšžœ˜——Kšžœžœ˜—Kšžœ˜—Kšœ˜K˜—šŸœžœžœ˜>Kšœ7™7Kšœ.™.šžœ˜Kšžœžœžœ˜0Kšžœžœ˜*—Kšœ˜—K™šΠbnœžœžœ˜IKšœžœ$™6Kšœ'™'šž˜šœ˜Kšœ&žœ ˜4Kšžœ˜Kšžœ˜Kšœ˜—Kšžœ˜—Kšœ˜K™—šŸœžœžœ ˜5Kšœžœžœžœ˜(š žœ#žœžœžœžœž˜WKšœ™š žœžœžœžœž˜4šœ˜Kšœ ™ Kšœžœ ˜(Kšžœ˜Kšžœ˜K˜—Kšžœ˜—Kšžœ˜—Kšœ˜Kšœ˜—K˜šŸ œžœžœžœžœžœžœžœ˜hKšœ:™:Kšœ,žœ™KK™Kšœ9™9Kšœ?™?šž˜Kšœžœ˜ Kš žœ žœžœžœ  ˜,Kšœ˜Kš žœ žœžœžœžœ˜%Kšœ#™#Kšœ žœžœ žœ˜Kš žœžœžœžœ $˜Ošžœ˜Kšœ™Kšœ žœ (˜8Kš œžœžœžœžœ˜EKš œ žœžœžœžœ ˜1Kšœ™Kšœ˜—šžœ˜Kšœžœžœžœ˜%Kšœ žœ ˜+Kšžœžœžœ ˜Mš žœžœžœžœžœ˜HKšœ™—Kšœ˜——Kšž˜—Kšœ˜—K™šŸ œž œ˜Kšœ žœ˜Kšœ žœ žœ=˜YKšœžœžœžœ'˜;Kšœ˜Kšœ4žœ ˜LKšžœžœžœžœžœžœžœžœ ˜eKšœžœ˜Kšžœ žœžœ˜AKšœ˜—K˜šŸ œžœ˜Kš žœžœ žœžœžœžœ ˜OKšœ˜—K˜—šœ ™ K™šœ8™8K˜KšŸœž œžœžœžœžœžœ˜9K˜š Ÿœžœžœžœžœ˜4Kšžœžœ˜+Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K™—šœ ™ K˜šŸ œžœžœžœžœžœžœžœ˜@Kšœ"™"KšœΟi £™?Kšžœžœ˜+Kšœ˜Kšž œ ˜Kšœ˜Kšœ˜—K˜—šœ ™ K˜šŸ œžœžœ˜+Kšœ*™*Kšœ™Kšžœžœ˜+Kšœ˜Kšž œ˜Kšœ˜Kšœ˜K˜—K™—šœ™K™šŸœžœž œ˜-Kšžœžœ˜+Kšœ˜Kšœžœ˜Kšœžœžœžœ˜kKšœ˜Kšœ˜—K˜šŸœžœž œ˜,Kšžœžœ˜+Kšœ˜Kšœžœ˜Kšœ˜Kšœ˜—K˜šŸœžœžœžœ˜IKšœ/™/Kšžœžœ˜+Kšœ˜Kšœžœ "˜—Kšœ˜Kšœ˜Kšœ˜—K˜šŸœž œžœžœ˜EKšœU™UKšžœžœ˜+Kšœ ˜ Kšœ˜Kšžœ žœžœžœ˜!Kšœ˜Kš žœ žœ ž œžœžœ˜=š žœ žœ žœžœ˜@Kš œ™Kšœ°™°—Kšžœ ž œžœ  ˜KKšœ˜Kšœžœ˜ Kšœ)˜)Kšœ˜Kšœ˜—K˜šŸœž œžœžœ˜DKšœO™OKšžœžœ˜+Kšœ ˜ Kšœ˜Kš žœ žœžœžœžœ˜%Kšœ˜šžœžœžœ ž˜Kšžœ žœ žœžœ˜9Kšžœ˜Kšœ―™―Kšœ™KšœA™A—Kšœ˜Kšœžœ˜Kšœžœ˜Kšœ˜Kšœ˜—K˜—šœ'™'K™š’œžœžœžœ žœžœ žœžœ˜dKšœ*™*Kšžœžœ˜+Kšœ˜šžœžœ žœ˜'Kšœ&˜&Kšœ žœ˜Kšœ˜—Kšœ˜Kšœ˜—K˜š’œžœžœžœ žœžœ žœžœ˜eKšœ+™+Kšžœžœ˜+Kšœ˜šžœ žœ˜Kšœ&˜&Kšœ žœ˜Kšœ˜—Kšœ˜Kšœ˜K˜—K˜—šœI™IK˜šŸ œžœžœžœžœžœžœ žœžœ˜jKšœ,™,Kšžœžœ˜+Kšœ˜šžœžœžœ#˜9šžœ˜Kšœ™Kšœ˜Kšœ žœžœžœžœžœžœžœžœžœ˜eKšœ˜—Kšžœ žœ˜—Kšœ˜Kšœ˜K˜—šŸ œžœžœžœžœžœ žœ žœžœžœžœžœ˜nKšœžœ˜7Kšœžœžœ˜Pš žœžœžœžœžœ ˜-Kšœ˜Kšœžœžœžœ˜Kšœ˜—Kšœ˜—K˜—šœ™K˜š Ÿœžœžœžœžœž œ˜eKšžœžœ˜+Kšœ˜Kšœžœ ˜(Kšœ˜Kšœ˜—K˜š ‘ Ÿœžœžœžœ žœ˜IKšžœžœ˜+Kšœ˜Kšœžœž œ˜)Kšœ˜Kšœ˜—K˜šŸ œž œžœ2˜QKšžœžœ˜+Kšœ˜Kšœ'˜'Kšœ˜Kšœ˜K˜—K˜šŸœž œžœ+˜DKšœ+™+Kšžœžœ˜+Kšœ˜Kšœ' ˜AKšœ'˜'Kšœ˜Kšœ˜K˜—K˜—šœ ™ K˜šŸ œžœžœ˜Kšžœžœžœ˜šœžœ˜šžœ˜KšœC˜CKšœ˜—Kšžœžœžœ˜"Kšœ˜—Kšœ žœžœžœžœžœžœžœžœžœ˜^Kšœžœ˜Kšœ˜Kšœžœ˜Kšœ˜Kšœžœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜š’œžœžœ˜(Kšœ™Kšžœžœ˜+Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜—K™šŸœžœžœ˜9Kšœžœ$™8Kšœ4™4šžœ˜Kšžœžœ˜)Kšžœžœ˜—Kšœžœ˜Kšœ˜—K™š Ÿœžœžœžœ žœ˜QKšœžœ$™7šžœ˜Kšžœžœ˜4Kšžœ žœ˜&—Kšœžœ˜Kšœ˜—K™——™ K˜šŸœžœžœ˜;Kšœ˜Kšœžœ ˜š žœžœžœžœž˜IKšœžœ ˜Kšžœžœ˜—Kšœ& ˜9Kšœ žœ˜4Kšžœžœ  ˜%Kšœ˜—K˜š Ÿœžœžœžœ žœ ˜WKšœ˜Kšœžœ ˜š žœžœžœžœž˜IKšœžœ ˜Kšžœžœ˜—Kšœ ˜*Kšœ žœ˜4Kšžœžœ  ˜%Kšœ˜—K˜šŸœžœžœžœ˜LKšœ˜Kšœžœ ˜š žœžœžœžœž˜Išœ%˜%Kšœ ™ —šœ˜Kšœ1™1Kšœžœžœžœ˜6K˜Kšœ žœ˜4Kšžœžœ  ˜%Kšœ   ˜K˜—šœ˜Kšœ™Kšœžœžœžœ˜6Kšœ ˜ Kšœ žœ˜4Kšžœžœ  ˜%Kšœ˜K˜—Kšœ1  ˜Kšžœžœ˜—Kšœ& ˜9Kšœ žœ˜4Kšžœžœ  ˜%Kšœ˜—K˜šŸ œžœžœ˜.Kšœ˜Kšœžœ ˜š žœžœžœžœž˜IKšœ ˜.šœ˜Kšœ1™1Kšœžœžœžœ˜6K˜Kšœ žœ˜4Kšžœžœ  ˜%Kšœ˜K˜—šœ˜Kšœ™Kšœžœžœžœ˜6Kšœ ˜ Kšœ žœ˜4Kšžœžœ  ˜%Kšœ˜K˜—Kšžœžœ˜—Kšœ ˜*Kšœ žœ˜4Kšžœžœ  ˜%Kšœ˜—K˜šŸ œžœžœ žœ žœžœžœžœ˜IKšœ˜Kš œ žœžœžœžœ˜šœžœ žœ žœžœžœžœžœžœ˜CKšœ˜Kšœ˜—Kšœžœ ˜Kšœ?˜?š žœžœžœžœž˜IKšœ$ ˜3šœ˜Kšœ1™1Kšœ˜Kšœ žœ˜4Kšžœžœ  ˜%Kšœ  ˜ K˜—šœ˜Kšœ1™1K˜Kšœ žœ˜4Kšžœžœ  ˜%Kšœ  ˜ K˜—šœ˜Kšœq™qKšœ˜Kšœ žœ˜4Kšžœžœ  ˜%Kšœ  ˜ K˜—šœ˜Kšœ™Kšœ ˜ Kšœ žœ˜4Kšžœžœ  ˜%Kšœ  ˜ K˜—Kšœ0  ˜=Kšžœžœ˜—Kšœ& ˜9Kšœ žœ˜4Kšžœžœ  ˜%Kšœ˜—K˜šŸ œžœ žœžœžœžœžœžœžœžœžœ˜mKšœ>™>š œžœžœžœžœžœžœ ˜2Kšœžœžœ˜C—Kšœ-˜-Kšžœžœ˜"Kšœ˜K˜——K˜ K˜—Kšžœ˜K˜K˜—…—L ί