<> <> <> <> DIRECTORY Allocator USING[NHeaderP, NormalHeader, RefCount, BlockSizeIndex, FNHeaderP], AllocatorOps USING[PlausibleRef, REFToNHP, sizeToBSI, bsiToSize, ExpandNormalFreeList, FreeObject], Basics USING[Byte, BITAND, BITOR, BITSHIFT, BITXOR, 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 -- protects the ZeroCountTable and object headers, notably their refCounts IMPORTS AllocatorOps, Basics, CedarMicrocode, Collector, DebuggerSwap, PrincOpsUtils, RCMicrocodeOps, RTFrameHeapSnapshot, RTTypesBasicPrivate, TrapSupport, VM, ZCT EXPORTS RCMicrocodeOps, StorageTraps, ZCT = BEGIN OPEN Allocator, AllocatorOps, Collector, RCMicrocodeOps, ZCT; <> 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]; -- increment, assnmt were NOT DONE 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: LONG CARDINAL] = { 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--]]; IF fosTable[index] = fosEmpty THEN fosTable[index] _ residue ELSE IF fosTable[index] # residue THEN fosTable[index] _ Basics.BITOR[fosEmpty, Basics.BITOR[fosTable[index], residue]]; }; ConservativeScanner: PROC[d: LONG DESCRIPTOR FOR ARRAY OF WORD] = { pa: LONG POINTER TO LONG CARDINAL = LOOPHOLE[BASE[d], LONG POINTER TO LONG CARDINAL]; nWords: CARDINAL = LENGTH[d]; IF nWords >= SIZE[REF] THEN FOR i: CARDINAL IN [0..nWords-SIZE[REF]] DO addr: LONG CARDINAL = (pa+i)^; IF PlausibleRef[addr] THEN PlausibleRefFoundOnStack[addr]; ENDLOOP; }; RTFrameHeapSnapshot.AcquireFrameHeapSnapshot[]; RTFrameHeapSnapshot.MapUncountedBodies[ConservativeScanner ! UNWIND => RTFrameHeapSnapshot.ReleaseFrameHeapSnapshot[]]; RTFrameHeapSnapshot.ReleaseFrameHeapSnapshot[]; }; -- end ScanTheFrameHeap MapReclaimableObjects: PUBLIC PROC[reclaim: PROC[NHeaderP]] = { -- and compactify zct 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]; -- put it back on the ZCT so that ResetStackBits will eliminate it and clean the maybeOnStack bit 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 => --rc = 0 & ~ not onstack & f IF NOT TryToQItForFinalization[nhp] THEN -- finalization q is full DO { <> OnZEntry[nhp ! ZCTFull => GOTO zctFull]; EXIT; EXITS zctFull => ExpandZCT[]; }; ENDLOOP; ENDCASE => ERROR; ENDLOOP; }; -- end MapReclaimableObjects <> <> 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, LONG CARDINAL]], zctBlockWords-1]; IF n = zctBlockWords - SIZE[LONG POINTER] -- rp points to the link; nhp has it THEN { -- we're done with this zctBlock 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; --to scrutinize this guy further }; 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]; DO { DecrementForFinalizeReclaimedRef[nhp ! RCUnderflowOccurred => GOTO handleRCUnderflow]; EXIT; EXITS handleRCUnderflow => HandleRCUnderflow[ref]; }; ENDLOOP; IF NOT TryToQItForFinalization[nhp] THEN -- finalization q is full 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] -- zct.lastNP^ = NIL 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]; -- no microcode 2 => { -- uCode is disabled; someone is inside this monitor p: PROC[nhp: NHeaderP] = MACHINE CODE{PrincOps.zRET}; Enter[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[nhp]; -- try again }; 4 => { -- zctFull 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: ReclaimableRef"]; -- 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] = { state: PrincOps.StateVector; state _ STATE; -- incantation SELECT (IF rcMicrocodeExists THEN TrapSupport.GetTrapParam[] ELSE 0) FROM 0 => ans _ SoftwareReclaimedRef[ref]; -- no microcode 2 => { -- uCode is disabled; someone is inside this monitor p: PROC[ref: REF ANY] = MACHINE CODE{PrincOps.zRET}; Enter[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[ref]; -- try again }; 3 => { <> p: PROC[ref: REF ANY] = MACHINE CODE{PrincOps.zRET}; HandleRCUnderflow[ref]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[ref]; -- try again }; 4 => { -- zctFull p: PROC[ref: REF ANY] = MACHINE CODE{PrincOps.zRET}; ExpandZCT[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[ref]; }; 5 => DebuggerSwap.CallDebugger["ZCT disaster: ReclaimedRef"]; -- 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 => { -- uCode is disabled; someone is inside this monitor p: PROC[nhp: NHeaderP] = MACHINE CODE{PrincOps.zRET}; Enter[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[nhp]; }; 4 => { -- zctFull 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; 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: rc ops and assnmt were NOT DONE p: PROC[refNew: REF, ptrRef: LONG POINTER TO REF] = MACHINE CODE{PrincOps.zRET}; HandleRCOverflow[refNew]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[refNew, ptrRef]; -- try again }; 2 => { -- uCode is disabled; someone is inside this monitor p: PROC[refNew: REF, ptrRef: LONG POINTER TO REF] = MACHINE CODE{PrincOps.zRET}; Enter[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[refNew, ptrRef]; -- try again }; 3 => { <> p: PROC[refNew: REF, ptrRef: LONG POINTER TO REF] = MACHINE CODE{PrincOps.zRET}; HandleRCUnderflow[alphaRef^]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[refNew, ptrRef]; -- try again }; 4 => { -- zctFull p: PROC[refNew: REF, ptrRef: LONG POINTER TO REF] = MACHINE CODE{PrincOps.zRET}; ExpandZCT[]; state.dest _ LOOPHOLE[PrincOpsUtils.MyLocalFrame[]]; TRANSFER WITH state; -- incantation p[refNew, ptrRef]; -- try again }; 5 => DebuggerSwap.CallDebugger["ZCT disaster: AssignRef"]; -- 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.