<> <> <> <> <> <> DIRECTORY Allocator USING [FNHeaderP, NHeaderP, RefCount, maxSmallBlockSize, BlockSizeIndex, bsiEscape, NormalHeader], AllocatorOps USING [NHPToREF, REFToNHP], Basics USING [BITAND, BITOR, BITSHIFT, BITXOR, HighHalf, LowHalf], Collector USING [Disposition], PrincOpsUtils USING [LongZero], RCMicrocodeOps USING [], RCMicrocodeStats USING [Stats, StatsPtr], SafeStorage USING [Type, nullType], UnsafeStorage USING [GetSystemUZone], ZCT USING [FOSTableIndex, FOSTableLength, FOSTableResidue, zctBlockWords, ZeroCountTable, zct, ZCTObject, FOSTableObject]; RCMicrocodeImpl: PROGRAM <> IMPORTS AllocatorOps, Basics, PrincOpsUtils, UnsafeStorage, ZCT--zct-- EXPORTS RCMicrocodeOps = BEGIN OPEN Allocator, Collector, RCMicrocodeStats, ZCT; <<>> <> checking: BOOL = FALSE; <> <<>> <> keepingStats: BOOL _ TRUE; stats: PUBLIC StatsPtr _ UnsafeStorage.GetSystemUZone[].NEW[Stats _ []]; oldStats: StatsPtr _ UnsafeStorage.GetSystemUZone[].NEW[Stats _ stats^]; elems: NAT = SIZE[Stats]/SIZE[INT]; SampleStats: PUBLIC PROC RETURNS [delta: Stats] = { new: LONG POINTER TO ARRAY [0..elems) OF INT _ LOOPHOLE[LONG[@delta]]; old: LONG POINTER TO ARRAY [0..elems) OF INT _ LOOPHOLE[oldStats]; delta _ stats^; FOR i: [0..elems) IN [0..elems) DO new[i] _ new[i] - old[i]; ENDLOOP; oldStats^ _ stats^; }; <> RCOverflowOccurred: PUBLIC ERROR = CODE; RCUnderflowOccurred: PUBLIC ERROR = CODE; LookFurtherAtReclaimedRef: PUBLIC ERROR = CODE; ZCTFull: PUBLIC ERROR = CODE; NormalFreeListEmpty: PUBLIC ERROR = CODE; <<>> <> ALLOCATE: PUBLIC PROC [size: CARDINAL, type: SafeStorage.Type] RETURNS[r: REF _ NIL] = { <> <> < Allocator.maxSmallBlockSize>> <> <> IF size <= maxSmallBlockSize THEN { bsi: BlockSizeIndex = zct.sizeToBSI[size]; fnhp: FNHeaderP _ zct.bsiToFreeList[bsi]; nhp: NHeaderP; IF fnhp = NIL THEN ERROR NormalFreeListEmpty; <> nhp _ @fnhp.fnh; r _ AllocatorOps.NHPToREF[nhp]; <<>> <> OnZ[nhp]; -- may pageFault or raise ZCTFull; ifso, no changes have been made <<>> <> zct.bsiToFreeList[bsi] _ fnhp.nextFree; fnhp.nextFree _ NIL; -- CLEAR THE NEW OBJECT nhp.type _ type; nhp.maybeOnStack _ zct.markingDecrements; IF keepingStats THEN stats.createRef _ stats.createRef + 1; }; }; FREEPLEASE: PUBLIC PROC [nhp: NHeaderP] RETURNS[success: BOOL _ FALSE] = { <> <> <> <> bsi: BlockSizeIndex = nhp.blockSizeIndex; IF (success _ bsi # bsiEscape) THEN { fnhp: FNHeaderP = LOOPHOLE[nhp, FNHeaderP]; PrincOpsUtils.LongZero[nhp + SIZE[NormalHeader], zct.bsiToSize[bsi] - SIZE[NormalHeader]]; fnhp.fnh.type _ SafeStorage.nullType; -- mark the object as free fnhp.nextFree _ zct.bsiToFreeList[bsi]; zct.bsiToFreeList[bsi] _ fnhp; }; }; ASSIGNREF: PUBLIC PROC [rhs: REF, lhs: LONG POINTER TO REF] = { <> <> <> <> <> lhsRef: REF _ lhs^; SELECT TRUE FROM rhs = lhsRef => { IF keepingStats THEN IF rhs = NIL THEN stats.assignRefNil _ stats.assignRefNil + 1 ELSE stats.assignRefEq _ stats.assignRefEq + 1; }; rhs = NIL => { <> marking: BOOL = zct.markingDecrements; lnhp: NHeaderP = AllocatorOps.REFToNHP[lhsRef]; lrc: RefCount _ lnhp.refCount; <> SELECT lrc FROM 0 => IF lnhp.rcOverflowed THEN ERROR RCUnderflowOccurred <> ELSE ERROR; <> 1 => { <> IF marking OR NOT lnhp.rcOverflowed THEN OnZ[lnhp]; }; ENDCASE => IF marking THEN OnZ[lnhp]; IF keepingStats THEN { stats.assignRefLeft _ stats.assignRefLeft + 1; IF NOT lnhp.rcOverflowed THEN SELECT lrc FROM 1 => stats.downToZero _ stats.downToZero + 1; 2 => stats.downToOne _ stats.downToOne + 1; ENDCASE; }; <> lnhp.maybeOnStack _ marking; lnhp.refCount _ lrc - 1; lhs^ _ rhs; -- NOT counted }; lhsRef = NIL => { <> rnhp: NHeaderP _ AllocatorOps.REFToNHP[rhs]; -- subtract 2 rrc: RefCount _ rnhp.refCount; IF rrc = LAST[RefCount] THEN ERROR RCOverflowOccurred; <> IF keepingStats THEN { stats.assignRefRight _ stats.assignRefRight + 1; IF NOT rnhp.rcOverflowed THEN SELECT rrc FROM 0 => stats.upToOne _ stats.upToOne + 1; 1 => stats.upToTwo _ stats.upToTwo + 1; ENDCASE; }; <> rnhp.refCount _ rrc + 1; rnhp.maybeOnStack _ FALSE; lhs^ _ rhs; -- NOT counted }; ENDCASE => { <> marking: BOOL = zct.markingDecrements; lnhp: NHeaderP = AllocatorOps.REFToNHP[lhsRef]; lrc: RefCount _ lnhp.refCount; rnhp: NHeaderP _ AllocatorOps.REFToNHP[rhs]; rrc: RefCount _ rnhp.refCount; IF rrc = LAST[RefCount] THEN ERROR RCOverflowOccurred; <> <> SELECT lrc FROM 0 => IF lnhp.rcOverflowed THEN ERROR RCUnderflowOccurred <> ELSE ERROR; <> 1 => { <> IF marking OR NOT lnhp.rcOverflowed THEN OnZ[lnhp]; }; ENDCASE => IF marking THEN OnZ[lnhp]; <> IF keepingStats THEN { stats.assignRefBoth _ stats.assignRefBoth + 1; IF NOT rnhp.rcOverflowed THEN SELECT rrc FROM 0 => stats.upToOne _ stats.upToOne + 1; 1 => stats.upToTwo _ stats.upToTwo + 1; ENDCASE; IF NOT lnhp.rcOverflowed THEN SELECT lrc FROM 1 => stats.downToZero _ stats.downToZero + 1; 2 => stats.downToOne _ stats.downToOne + 1; ENDCASE; }; lnhp.maybeOnStack _ marking; lnhp.refCount _ lrc - 1; rnhp.refCount _ rrc + 1; rnhp.maybeOnStack _ FALSE; lhs^ _ rhs; -- NOT counted }; IF keepingStats THEN stats.assignRef _ stats.assignRef + 1; }; <<>> OnZ: PUBLIC PROC [nhp: NHeaderP] = { <> <> <> <> <> <> IF NOT nhp.inZCT THEN { wp: LONG POINTER TO NHeaderP _ zct.wp; wp^ _ nhp; <> <> <> IF Basics.BITAND[Basics.LowHalf[LOOPHOLE[wp, LONG CARDINAL]], zctBlockWords - 1] = zctBlockWords - 2*SIZE[LONG POINTER] THEN { <> wp _ LOOPHOLE[(wp+SIZE[LONG POINTER])^, LONG POINTER TO NHeaderP]; IF wp = NIL THEN ERROR ZCTFull -- i.e. XXX TRAP with trapParam = 4 ELSE zct.wp _ wp; <> } ELSE zct.wp _ wp + SIZE[LONG POINTER]; -- will NOT pageFault IF keepingStats THEN stats.onZCT _ stats.onZCT + 1; nhp.inZCT _ TRUE; -- will NOT pagefault (in microcode) }; }; <<>> CREATEREF: PUBLIC PROC [nhp: NHeaderP] = { <> <> IF checking AND (nhp.refCount # 0 OR nhp.rcOverflowed) THEN ERROR; OnZ[nhp]; -- may pageFault or raise ZCTFull; ifso, no changes have been made nhp.maybeOnStack _ zct.markingDecrements; IF keepingStats THEN stats.createRef _ stats.createRef + 1; }; RECLAIMABLEREF: PUBLIC PROC [nhp: NHeaderP] RETURNS[Disposition] = { <> <> <> RETURN[MCRECLAIMABLEREF[nhp, FALSE]]; }; <<>> MCRECLAIMABLEREF: PROC [nhp: NHeaderP, decrPending: BOOL] RETURNS[d: Disposition _ continue] = { <> <> <> rc: RefCount _ nhp.refCount; IF decrPending THEN rc _ rc - 1; -- won't underflow IF rc # 0 OR nhp.inZCT OR nhp.rcOverflowed THEN RETURN; -- leave it alone IF nhp.maybeOnStack OR FoundInFHSnapshot[nhp] THEN OnZ[nhp] -- put it back; this may pageFault or raise ZCTFull ELSE d _ (IF nhp.f THEN finalizeIt ELSE reclaimIt); }; <<>> FoundInFHSnapshot: PROC [nhp: NHeaderP] RETURNS[found: BOOL _ FALSE] = { <> <> index: FOSTableIndex; residue, entry: FOSTableResidue; fosTable: LONG POINTER TO FOSTableObject = LOOPHOLE[zct+SIZE[ZCTObject]]; [index, residue] _ FOSTableHash[nhp]; entry _ fosTable[index]; RETURN[residue = Basics.BITAND[residue,entry]]; }; FOSTableHash: PUBLIC PROC [nhp: NHeaderP--maybe bogus--] RETURNS[x: FOSTableIndex, r: FOSTableResidue] = { <> OPEN Basics; lc: LONG CARDINAL = LOOPHOLE[nhp, LONG CARDINAL]; u: FOSTableResidue; r _ BITOR[BITSHIFT[HighHalf[lc], 3], BITSHIFT[LowHalf[lc], -13]]; <> u _ BITAND[r, zct.residueMask]; x _ BITAND[BITXOR[BITSHIFT[LowHalf[lc], -1], u], FOSTableLength-1]; <> <> }; <<>> RECLAIMEDREF: PUBLIC PROC [ref: REF] RETURNS [ans: REF ANY _ NIL] = { <> <> <> <> nhp: NHeaderP = AllocatorOps.REFToNHP[ref]; <> CheckForRCUnderflow[nhp]; -- might raise RCUnderflowOccurred SELECT MCRECLAIMABLEREF[nhp, TRUE] FROM continue => NULL; reclaimIt => ans _ ref; finalizeIt => ERROR LookFurtherAtReclaimedRef; <> ENDCASE => ERROR; IF keepingStats THEN { stats.reclaimedRef _ stats.reclaimedRef + 1; SELECT nhp.refCount FROM 1 => stats.downToZero _ stats.downToZero + 1; 2 => stats.downToOne _ stats.downToOne + 1; ENDCASE; }; nhp.refCount _ nhp.refCount - 1; }; <<>> CheckForRCUnderflow: PROC [nhp: NHeaderP] = { <> <> rc: RefCount _ nhp.refCount; IF checking AND rc = 0 AND NOT nhp.rcOverflowed THEN ERROR; <> IF rc = 0 --was RCMicrocodeOps.rcBottom-- AND nhp.rcOverflowed THEN ERROR RCUnderflowOccurred; -- no changes have been made <> }; DISABLEMICROCODE: PUBLIC PROC [z: ZeroCountTable] = { <> <> <> NULL; -- the real uc: ucDisabled _ TRUE }; <<>> ENABLEMICROCODE: PUBLIC PROC [z: ZeroCountTable] RETURNS [ucVersion: NAT] = { <> <> RETURN[0]; -- the real uc: ucDisabled _ FALSE }; END.