<> <> <> <> <> 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 { <<- put it back>> 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]; }; <> <<>> <<0. Enter ... used by trap handlers and TraceAndSweepImpl>> Enter: PUBLIC ENTRY PROC = {ENABLE UNWIND => NULL; NULL}; EnterAndCallBack: PUBLIC ENTRY PROC [proc: PROC] = { ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; proc[]; [] _ EnableMicrocode[zct]; }; <<>> <<1. AssignRef>> DoAssignRef: ENTRY PROC [rhs: REF, lhs: LONG POINTER TO REF] = { <> <> ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; ASSIGNREF[rhs, lhs]; [] _ EnableMicrocode[zct]; }; <<2. CreateRef>> DoCreateRef: ENTRY PROC [nhp: NHeaderP] = { <> <> ENABLE UNWIND => [] _ EnableMicrocode[zct]; DisableMicrocode[zct]; CREATEREF[nhp]; [] _ EnableMicrocode[zct]; }; <<>> <<3. Collector and reclaimer>> <<>> 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]; }; <<4. Finalization ... called from FQImpl>> 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; <> < 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>> 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; < 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>> <> <> nhp.refCount _ rc + npr; nhp.f _ FALSE; nhp.maybeOnStack _ FALSE; [] _ EnableMicrocode[zct]; }; <<5. RC overflow ... called from RCOvImpl>> <<>> 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]; }; <<6. ZCT expansion. These are called during recovery from a ZCTFull signal.>> 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] ]; }; <<7. Allocation, reclamation>> 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]; }; <<8. Utilities>> 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.