ZCTImpl.mesa
Implementation of the Zero Count Table for the Cedar incremental collector
Paul Rovner, December 2, 1983 3:31 pm
DIRECTORY
Allocator USING[NHeaderP, NormalHeader, RefCount, BlockSizeIndex, FNHeaderP],
AllocatorOps USING[PlausibleRef, REFToNHP, sizeToBSI, bsiToSize, ExpandNormalFreeList],
Basics USING[Byte, BITAND, BITXOR, LowHalf, LongNumber],
CedarMicrocode USING[RECLAIMABLEREF, DISABLEMICROCODE, ENABLEMICROCODE],
Collector USING[InternalReclaim, Disposition],
DebuggerSwap USING[CallDebugger],
PrincOps USING[ControlLink, StateVector, zRET],
PrincOpsUtils USING[Codebase, GetReturnLink, MyLocalFrame],
RCMicrocodeOps USING[FOSTableHash, ASSIGNREF, OnZ, CREATEREF, RECLAIMABLEREF, RECLAIMEDREF, DISABLEMICROCODE, ENABLEMICROCODE, RCOverflowOccurred, RCUnderflowOccurred, LookFurtherAtReclaimedRef, ZCTFull, rcMicrocodeExists, rcMicrocodeWasEnabled, ALLOCATE, FREEPLEASE, NormalFreeListEmpty],
RTFrameHeapSnapshot USING[AcquireFrameHeapSnapshot, MapUncountedBodies, ReleaseFrameHeapSnapshot],
SafeStorage USING[Type, nullType],
StorageTraps USING[],
TrapSupport USING[BumpPC, GetTrapParam],
VM USING[Allocate, Free, Interval, AddressForPageNumber],
ZCT USING[fosEmpty, FOSTableIndex, FOSTableObject, FOSTableResidue, fosWildCard, 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, TrapSupport, VM, ZCT
EXPORTS
RCMicrocodeOps, StorageTraps, ZCT
= BEGIN OPEN Allocator, AllocatorOps, Collector, RCMicrocodeOps, ZCT;
CONSTANTS
checking: BOOL = TRUE;
PROCEDURES
REFERENCE COUNTING
See CREATEREF, the ucode replacement for this guy
SoftwareCreateRef: PUBLIC PROC[nhp: NHeaderP] = {
DO {
DoCreateRef[nhp ! ZCTFull => GOTO zctFull];
EXIT;
EXITS zctFull => ExpandZCT[];
};
ENDLOOP;
};
See ASSIGNREF, the ucode replacement for this guy
AssignRefNew: PROC[rhs: REF ANY, lhs: LONG POINTER TO REF ANY] = {
IF checking AND lhs^ # NIL THEN ERROR;
AssignRef[rhs, lhs];
};
See ASSIGNREF, the ucode replacement for this guy
AssignRef: --PUBLIC-- PROC[rhs: REF, lhs: LONG POINTER TO REF] = {
DO {
DoAssignRef[rhs, lhs
! -- PageFault => {SatisfyPageFault[]; RETRY};
RCUnderflowOccurred => GOTO handleRCUnderflow;
RCOverflowOccurred => GOTO handleRCOverflow;
this is the only catch for RCOverflowOccurred
ZCTFull => GOTO zctFull;
];
RETURN;
EXITS
handleRCUnderflow => HandleRCUnderflow[lhs^];
handleRCOverflow => HandleRCOverflow[rhs]; -- increment, assnmt were NOT DONE
zctFull => ExpandZCT[];
};
ENDLOOP;
};
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.
SoftwareReclaimedRef: PUBLIC PROC[ref: REF ANY] RETURNS[ans: REF ANYNIL] = {
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];
};
END REFERENCE COUNTING
ALLOCATION AND RECLAMATION
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]};
END ALLOCATION AND RECLAMATION
COLLECTOR, ZCT
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 fosTable[index] ← fosWildCard;
};
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[];
FOR nhp: NHeaderP ← PullNextEntry[wp, FALSE], PullNextEntry[wp, FALSE]
UNTIL nhp = NIL DO
nhp has been removed from zct
d: Disposition;
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 => reclaim[nhp];
rc = 0 & not onstack & ~f: reclaim it (it was removed from zct)!
finalizeIt => --rc = 0 & ~ not onstack & f
IF NOT TryToQItForFinalization[nhp] THEN -- finalization q is full
DO {
it should stay in the zct
OnZEntry[nhp ! ZCTFull => GOTO zctFull];
EXIT;
EXITS zctFull => ExpandZCT[];
};
ENDLOOP;
ENDCASE => ERROR;
ENDLOOP;
}; -- end MapReclaimableObjects
This may raise ZCTFull. Ifso, no changes have been made
This is called only from MapReclaimableObjects
ReclaimableRef: PROC[nhp: NHeaderP] RETURNS[Disposition] = {
IF rcMicrocodeExists
THEN RETURN[CedarMicrocode.RECLAIMABLEREF[nhp]]
ELSE RETURN[SoftwareReclaimableRef[nhp]];
};
See RECLAIMABLEREF, the ucode replacement for this guy
This is called only from ReclaimableRef
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
nhp has been removed from zct
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[];
};
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
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;
Here with non-NIL nhp; maybe a link
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];
and go around again
}
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 THEN RETURN; --to scrutinize this guy further
};
ENDLOOP;
};
ExpandZCT: PUBLIC PROC = {
success: BOOL;
zbInterval: VM.Interval = VM.Allocate[count: zctBlockPages, alignment: logZCTBlockPages];
p: LONG POINTERVM.AddressForPageNumber[zbInterval.page];
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 NOT success THEN VM.Free[zbInterval];
};
ClearFOSTable: PROC = {
LOOPHOLE[zct+SIZE[ZCTObject], LONG POINTER TO FOSTableObject]^ ← ALL[fosEmpty]};
END COLLECTOR, ZCT
ENTRY PROCS
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
This is called only from AssignRef
This may raise ZCTFull, RCOverflowOccurred, RCUnderflowOccurred
DoAssignRef: ENTRY PROC[rhs: REF, lhs: LONG POINTER TO REF] = {
ENABLE UNWIND => [] ← EnableMicrocode[zct];
DisableMicrocode[zct];
ASSIGNREF[rhs, lhs];
[] ← EnableMicrocode[zct];
};
2. CreateRef
This is called only from SoftwareCreateRef
DoCreateRef may raise ZCTFull
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;
[] ← EnableMicrocode[zct];
};
StopMarkingDecrements: PUBLIC ENTRY PROC = {
ENABLE UNWIND => [] ← EnableMicrocode[zct];
DisableMicrocode[zct];
zct.markingDecrements ← FALSE;
[] ← EnableMicrocode[zct];
};
This is called only from SoftwareReclaimableRef
DoReclaimableRef: ENTRY PROC[nhp: NHeaderP] RETURNS[d: Disposition] = {
ENABLE UNWIND => [] ← EnableMicrocode[zct];
DisableMicrocode[zct];
d ← RECLAIMABLEREF[nhp]; -- The only call on RECLAIMABLEREF
[] ← EnableMicrocode[zct];
};
This is called only from SoftwareReclaimedRef
This may raise ZCTFull, RCUnderflowOccurred, LookFurtherAtReclaimedRef
DoReclaimedRef: ENTRY PROC[ref: REF ANY] RETURNS[ans: REF ANYNIL] = {
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
Called from ReclaimedRefTrap and from SoftwareReclaimedRef
FinalizeReclaimedRef: PROC[ref: REF] = {
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.
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 {
it should stay in the zct
OnZEntry[nhp ! ZCTFull => GOTO zctFull];
EXIT;
EXITS zctFull => ExpandZCT[];
};
ENDLOOP;
};
called only from FinalizeReclaimedRef. May raise RCUnderflowOccurred.
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];
};
called only from FQImpl.EnableFinalization. May raise ZCTFull or RCUnderflowOccurred.
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;
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
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];
};
called only from FQImpl.TryToQItForFinalization. May raise RCOverflowOccurred.
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;
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
nhp.refCount ← rc + npr;
nhp.f ← FALSE;
nhp.maybeOnStack ← FALSE;
[] ← EnableMicrocode[zct];
};
5. RC overflow ... called from RCOvImpl
called only from RCOvImpl.HandleRCOverflow
DecrForOverflow: PUBLIC ENTRY PROC[rcDelta: NAT, nhp: NHeaderP]
RETURNS[success: BOOLFALSE] = {
ENABLE UNWIND => [] ← EnableMicrocode[zct];
DisableMicrocode[zct];
IF nhp.refCount = LAST[RefCount] THEN {
nhp.refCount ← nhp.refCount - rcDelta;
success ← TRUE;
};
[] ← EnableMicrocode[zct];
};
called only from RCOvImpl.HandleRCUnderflow
IncrForUnderflow: PUBLIC ENTRY PROC[rcDelta: NAT, nhp: NHeaderP]
RETURNS[success: BOOLFALSE] = {
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.
called from ExpandZCT and from PullNextEntry
DoExpandZCT: ENTRY PROC[newZCTBlock: LONG POINTER, onlyIfNeeded: BOOL]
RETURNS[success: BOOLTRUE] = {
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];
successRCMicrocodeOps.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];
};
See AllocatorImpl.TAndSDoFreeNormalFragment
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.bsiToFreeList ← ALL[NIL];
zct.sizeToBSI ← sizeToBSI^;
zct.bsiToSize ← bsiToSize^;
InitializeCleanup[];
};
This may raise ZCTFull.
OnZEntry: ENTRY PROC[nhp: NHeaderP] = {
ENABLE UNWIND => [] ← EnableMicrocode[zct];
DisableMicrocode[zct];
OnZ[nhp];
[] ← EnableMicrocode[zct];
};
See DISABLEMICROCODE, the ucode replacement for this guy
DisableMicrocode: INTERNAL PROC[zct: ZeroCountTable] = {
cause rc operations to trap (except EnableMicrocode)
IF rcMicrocodeExists
THEN CedarMicrocode.DISABLEMICROCODE[zct]
ELSE DISABLEMICROCODE[zct];
rcMicrocodeWasEnabled ← FALSE;
};
See ENABLEMICROCODE, the ucode replacement for this guy
EnableMicrocode: INTERNAL PROC[zct: ZeroCountTable] RETURNS[ucVersion: NAT] = {
IF rcMicrocodeExists
THEN ucVersion ← CedarMicrocode.ENABLEMICROCODE[zct]
ELSE ucVersion ← ENABLEMICROCODE[zct];
rcMicrocodeWasEnabled ← TRUE;
};
END ENTRY PROCS
TRAP HANDLERS
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 ANYNIL] = {
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 => {
handleRCUnderflow: decrement was NOT DONE
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 => {
handleRCUnderflow: decrement, assnmt were NOT DONE (this does the decrement, assigns NIL, then goes around again)
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
};
read the alpha byte for the trapping opcode & add it to ptrRef
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]];
};
END TRAP HANDLERS
Initialize[];
END.