-- RTRefCounts.Mesa
-- last edited 13-Oct-81 16:32:05 by Willie-Sue
-- last edited May 19, 1982 8:01 pm by Paul Rovner

DIRECTORY
  Environment USING[wordsPerPage],
  Inline USING[LongNumber, BITXOR, BITSHIFT],
  MiscAlpha USING[alpha],
  Mopcodes USING[zMISC],
  RTQuanta USING[LASTAddress],
  RTTypesBasic USING[maxNPackageRefs],
  RTTypesBasicPrivate USING[RMapTiTd],
  RTZones USING[RMapQZf, RMapSziSz, PMapZiZn, ZoneIndex],
  SafeStorage USING[ReclamationReason];

RTRefCounts: DEFINITIONS
  IMPORTS Inline
= BEGIN

-- P A R A M E T E R S   and   T Y P E S

-- Reference count table parameters and TYPEs

  AMapPiRce: TYPE = ARRAY ProbeIndex OF RCEntry; -- the TYPE of the reference count table

  ProbeSize: CARDINAL = 100000B;  -- NOTE ucode & the 3 MapPi fns depend on this!!
  ProbeIndex: TYPE = [0..ProbeSize);  -- "pi"

  RCEntry: TYPE = MACHINE DEPENDENT RECORD		  -- "rce"  (setup for microcode)
   [ rcentry(0:0..15):
      SELECT eType(0:0..0): entryType FROM
        normal =>   [ rc(0:1..7): RefCt,		  -- eType = 0
		      onStack(0:8..8): uBoolean ← false,
		      res(0:9..15): Residue],
        overflow => [ oi(0:1..14): MapOiOeIndex,	  -- eType = 1
      		      fill(0:15..15): [0..1] ← 0],
       ENDCASE];

  nRCEntry: TYPE = normal RCEntry;
  oRCEntry: TYPE = overflow RCEntry;

  entryType: TYPE = MACHINE DEPENDENT { normal(0), overflow(1) };
  RefCt: TYPE = [0..(LAST[CARDINAL]/4)/ResidueSize]; 
                -- "rc" (7 bits) so normal RCEntry fits in one word
  rcFinalize: CARDINAL = RTTypesBasic.maxNPackageRefs+1;
  rcAbsent: CARDINAL = rcFinalize + 1;
  absentRCEntry: nRCEntry = [normal [rc: rcAbsent, onStack: false, res: 0]];	-- res a don't care
  nrcEntry: nRCEntry = [normal [rc: LAST[RefCt], onStack: true, res: LAST[Residue]]];
  nrceMask: CARDINAL = LOOPHOLE[nrcEntry];
  rceEmpty: oRCEntry = LOOPHOLE[177777B, oRCEntry];
       --  empty is overflow entry that is odd; making it all ones simplifies the microcode  


  uBoolean: TYPE = MACHINE DEPENDENT { false(0), true(1) };
                -- "don't depend on Mesa's representation of TRUE/FALSE
  Residue: TYPE = [0..ResidueSize);  -- "res", 7 bits
  ResidueSize: CARDINAL =
                LOOPHOLE[(RTQuanta.LASTAddress+1)/ProbeSize, Inline.LongNumber].lowbits;
                          -- nonsense, should be NARROW[(LASTAddress+1)/ProbeSize]

-- Reference count overflow table parameters and TYPEs

  AMapOiOe: TYPE = ARRAY MapOiOeIndex OF OverflowEntry; -- the TYPE of the overflow table

  MapOiOeIndex: TYPE = [0..mapOiOeLimit + mapOiOeStart);
       -- depends on the layout of AGCState. Indexing cleverness simplifies the microcode.

  OverflowEntry: TYPE = MACHINE DEPENDENT RECORD          -- "oe"
   [ rce(0:0..15): nRCEntry, oe1(1:0..15): RCEntry];

  OverflowFreeListEntry: TYPE = MACHINE DEPENDENT RECORD
   [ link(0:0..15): oRCEntry, oe1(1:0..15): RCEntry];

       --  Entries at the end of overflow chains contain two normal entries:
       --  EndOfChainOE: TYPE = MACHINE DEPENDENT RECORD [ rce: nRCEntry, oe1: nRCEntry]

       --  Entries in the middle of overflow chains contain a normal and an overflow entry
       --  MiddleOfChainOE: TYPE = MACHINE DEPENDENT RECORD [ rce: nRCEntry, oe1: oRCEntry]

       --  NOTE the microcode uses all 16 bits of an overflow RCEntry as an index into MapOiOe,
       --       which is really based at GCState. The mesa code uses only the middle 14 bits,
       --       adds in an offset (see MapOiOeIndex) and multiplies by SIZE[OverflowEntry],
       --       which is known to be 2.
       --  The software's value of MapOiOe will be greater than the ucode's
       --  by ProbeSize/SIZE[OverflowEntry]


  mapOiOePages: INTEGER = 80;
  OverflowEntrySize: CARDINAL = 2;  -- needed to avoid circular defs

  mapOiOeStart: CARDINAL = AGCStateSize/OverflowEntrySize;
  mapOiOeLimit: CARDINAL = mapOiOePages*Environment.wordsPerPage/OverflowEntrySize;

       --  The freelist in the overflow table is threaded through the even words.
       --  The contents of the odd words are ignored: [ rce: oRCEntry, oe1: don't care]

	
-- Access (for the microcode) to runtime tables: parameters and TYPEs
  AGCStateSize: CARDINAL = Environment.wordsPerPage;
       -- using a full page simplifies the microcode

  AGCState: TYPE = MACHINE DEPENDENT RECORD
   [
    GCStateBasic: aGCStateBasic,
    toBeUsedLater: toBeUsedSpace,
    GCEventCounters: aGCEventCounters,
    rceToReclaim: RCEToReclaimVec,  -- communication from the microcode to the collector
    dumpTable: gcDumpTable
--    MapPiRce: AMapPiRce	 an array 32K long
--    MapOiOe: AMapOiOe		 an array 20K long
   ];

  aGCStateBasic: TYPE = MACHINE DEPENDENT RECORD
   [
      -- these two goodies plus rcFnzCount are kept in microcode
      -- registers, and moved to memory via
      --    RTMOVESTATUS[toMemory, 0],
      -- from memory via
      --    RTMOVESTATUS[toUCodeRegisters, Inline.HighHalf[GCState]
    mapOiOeFrList(0:0..15): oRCEntry,  -- the overflow FreeList chain
    nOiFree(1:0..15): INTEGER,         -- (length of FreeList chain) - gcThresholdNOiFree 

      -- these two goodies are kept in microcode registers, and
      -- are ALWAYS moved there by RTMOVESTATUS
      -- (e.g. RTMOVESTATUS[toMemory, 0] does it). Groan.
    reclaimState(2:0..15): gcRState ← gcReady,
    collector(3:0..15): PROCESS ← NIL,

    mapQZf(4:0..31): LONG POINTER TO RTZones.RMapQZf ← NIL,
    mapSziSz(6:0..31): LONG POINTER TO RTZones.RMapSziSz ← NIL,
    mapZiZn(10B:0..31): LONG POINTER TO RTZones.PMapZiZn ← NIL,
    mapTiTd(12B:0..31): LONG POINTER TO RTTypesBasicPrivate.RMapTiTd ← NIL,
    rcFnzCount(14B:0..15): CARDINAL← 0,
    tba1(15B:0..15): CARDINAL← 0,
    tba2(16B:0..15): CARDINAL← 0,
    tba3(17B:0..15): CARDINAL← 0
  ];

  gcThresholdNOiFree: CARDINAL = mapOiOeLimit/4;
        -- enuff extra (hopefully!!) for expansion during collection

  gcRState: TYPE = MACHINE DEPENDENT RECORD  -- software status, encoded to simplify ucode
   [ fill0(0:0..0): [0..1]← 0,
     rcMask(0:1..7): RefCt ← LAST[RefCt],
     useStack(0:8..8): uBoolean,
     fill(0:9..15): [0..177B] ← 0
   ];
  gcReady: gcRState = [ useStack: false];                  -- 77400B
  gcRunning: gcRState = [ useStack: true];                -- 77600B
  gcStopped: gcRState = [ fill0: 1, useStack: false];     -- 1xxxxx

  toBeUsedSize: CARDINAL = 2*rceReclaimLimit-SIZE[aGCStateBasic]-SIZE[aGCEventCounters];
  toBeUsedSpace: TYPE = ARRAY[0..toBeUsedSize) OF CARDINAL;
  
  aGCEventCounters: TYPE = MACHINE DEPENDENT RECORD
   [
    AlterCountNIL: LONG INTEGER,		-- AlterCount with NIL or odd arg
    AlterCountZeroChange: LONG INTEGER,		-- AlterCount w/o changing RefCt
    AlterCountDecrement: LONG INTEGER,		-- AlterCount decrementing RefCt
    AlterCountIncrement: LONG INTEGER,		-- AlterCount incrementing RefCt
    OTCellDelete: LONG INTEGER,			-- OT cell deletions
    OTCellCreate: LONG INTEGER,			-- OT cell creations
    HTCellDelete: LONG INTEGER,			-- HT cell deletions
    HTCellCreate: LONG INTEGER,			-- HT cell creations
    ReclaimedRefNIL: LONG INTEGER,		-- ReclaimedRef with NIL result
    ReclaimedRefNoDel: LONG INTEGER,		-- ReclaimedRef completions (not deleted)
    ReclaimedRefDel: LONG INTEGER,		-- ReclaimedRef completions (already deleted)
    ResetOnStackC: LONG INTEGER,		-- ResetOnStack completions
    ReclaimAllC: LONG INTEGER,			-- ReclaimAll completions
    CreateRefC: LONG INTEGER,			-- CreateRef completions
    AssignRefC: LONG INTEGER,			-- AssignRef+AssignRefNew completions
    AssignRefNewI:  LONG INTEGER,		-- AssignRefNew inititations
      -- (= AssignRefNew completions with page fault restarts as an error term)
    RefOldEQNIL: LONG INTEGER,			-- RefOld=NIL in AssignRef
      -- (plus page fault restarts & collector disabled AssignRefs as an error term)
    RefNewEQNil: LONG INTEGER,			-- RefNew=NIL in AssignRef(New)
    RefOldEQRefNew: LONG INTEGER		-- RefOld=RefNew in AssignRef
   ];
   
  RCEToReclaimVec: TYPE = ARRAY[0..rceReclaimLimit) OF nRCEntry;
       --  RCEToReclaimVec is big enough to hold the longest possible chain of overflow entries,
       --  which is 64 entries (REFs are even)
  rceReclaimLimit: CARDINAL = (LAST[Residue] + 1)/2;


  gcDumpTable: TYPE = ARRAY[0..rceReclaimLimit) OF CARDINAL;	-- for microcode debugging

-- Miscellany
  uCodeDirection: TYPE = MACHINE DEPENDENT  -- used by RTMOVESTATUSTrap and InitializeCleanup
  		{ toMemory(0),  -- this is badly named, but means "move info about overflow free list to memory, and move other status info from memory to microcode.
		  toUCodeRegisters(177777B)};


-- Parameter bundle for the microcode (AlterCount), for use with bit tweezers
  rcoState: TYPE = MACHINE DEPENDENT RECORD
   [ fill0(0:0..0): [0..1]← 0,
     rcChange(0:1..7): [0..177B],
     onStack(0:8..8): uBoolean,
     fill(0:9..15): [0..177B]← 0
   ];

  rcoAddRef: rcoState = [ rcChange: 1, onStack: true];		--   600B
  rcoDeleteRef: rcoState = [ rcChange: 177B, onStack: true];	-- 77600B
  rcoJustCreated: rcoState = [ rcChange: 177B, onStack: true];	-- 77600B
  rcoFinalizedRef: rcoState = [ rcChange: 1, onStack: false];	--   400B
  rcoNilifyRef: rcoState = [ rcChange: 177B, onStack: false];	-- 77400B
  rcoFoundOnStack: rcoState = [ rcChange: 0, onStack: true];	--   200B

  rcoChangeMask: rcoState = [rcChange: 177B, onStack: false];
  rcoOnstackMask: rcoState = [rcChange: 0,  onStack: true];
  rcoReclaimedRef: rcoState = [rcChange: 177B, onStack: false];
  reclaimedRefDelta: CARDINAL = LOOPHOLE[rcoReclaimedRef];    


-- V A R I A B L E S
  GCMicrocodeExists:  BOOLEAN;
  useUCodedGC:  BOOLEAN;
  nObjectsReclaimed:  LONG CARDINAL;
  nWordsReclaimed:  LONG CARDINAL;
  GCState:  LONG POINTER TO AGCState;
  frameBodyBufferPages: CARDINAL;


-- P R O C E D U R E S

  StuffZi: PROC[zi: RTZones.ZoneIndex, zone: ZONE];
  StuffMapZiZn: PROC[p: LONG POINTER TO RTZones.PMapZiZn];
  StuffMapSziSz: PROC[p: LONG POINTER TO RTZones.RMapSziSz];
  StuffMapQZf: PROC[p: LONG POINTER TO RTZones.RMapQZf];

  IsTraceAndSweepEnabled: PROC RETURNS[BOOLEAN];
  DoTraceAndSweepCollection: PROC;
  ReclaimForQuanta: PROC RETURNS[LONG CARDINAL];  -- returns number of objects reclaimed
  MapReclaimableObjects: PROC;

  InternalReclaim: PROC[reason: SafeStorage.ReclamationReason, suspendMe: BOOLEAN ← FALSE, doStack: BOOLEAN ← TRUE];


  aCREATEREF: MiscAlpha.alpha = 67B;
  CREATEREF: PROC[npr: rcoState, ref: REF] =
    MACHINE CODE {Mopcodes.zMISC, aCREATEREF };

  CreateRef: PROC[npr: CARDINAL, refNew: REF] =  -- called by the allocator
    INLINE
      {IF useUCodedGC
        THEN {rco: rcoState ← [rcChange: npr, onStack: false]; [] ← CREATEREF[rco, refNew]}
        ELSE SoftwareCreateRef[npr, refNew]};
    
  SoftwareCreateRef: PROC[npr: CARDINAL, refNew: REF];

  ClearRCTable: PROC;  -- called by the TraceAndSweep collector
  IncrementReferenceCount: PUBLIC PROC[ref: REF];  -- called by the TraceAndSweep collector
  DecrementReferenceCount: PUBLIC PROC[ref: REF];  -- called by the TraceAndSweep collector

--  used when the microcode traps or there is no microcode support
  RTMOVESTATUSTrap: PROC[direction: uCodeDirection, gcStateBank: CARDINAL]
        RETURNS[CARDINAL];
  AssignRefTrap: PROC[refNew: REF, ptrRef: LONG POINTER TO REF];
  AssignRefNewTrap: PROC[refNew: REF, ptrRef: LONG POINTER TO REF];
  CREATEOutOfOverflowTable: PROC[npr: rcoState, refNew: REF ANY];
  ReclaimedRefOutOfOverflowTable: PROC;
  ALTERCOUNTOutOfOverflowTable: PROC;
  ClobberedOverflowTable: PROC;
  ReadUCodeRegsTrap: PROC RETURNS[f: CARDINAL];
  
  DisableRC: PROC;
  AlterCountEntry:  PROC[rcv: rcoState, ref: REF];
  ReclaimedRef: PROC[ref: REF] RETURNS[REF]; 
  IsPiReclaimable: PROC[pi: ProbeIndex] RETURNS [fpi: ProbeIndex, npi: CARDINAL];
  MapRcePiRef: PROC[rce: nRCEntry, pi: ProbeIndex] RETURNS[REF] = INLINE
    { OPEN Inline;
      res: Residue = rce.res;
      RETURN[LOOPHOLE[LongNumber[num[highbits: res,
      				 lowbits: BITSHIFT[BITXOR[pi, res], 1]]]]]};
  IsOiCushion: PROC RETURNS[BOOLEAN];

  GetMapPiRce: PROC RETURNS[LONG POINTER TO AMapPiRce];
  GetMapOiOe: PROC RETURNS[LONG POINTER TO AMapOiOe];
  InitializeCleanup: PROC[gcStateBank: CARDINAL];

  SetAlwaysTrim: PROC[sense: BOOLEAN];



-- statistics stuff for performance analysis (VOLATILE)

Count: TYPE = LONG CARDINAL;
AllocatorTrapStatsRec: TYPE = RECORD
    [ NoUCodeTraps: Count← 0,
      OldUCodeTraps: Count← 0,
      ZoneLockedTraps: Count← 0,
      NoBlockFoundTraps: Count← 0,
      LongFreeListTraps: Count← 0,
      UnKnownTraps: Count← 0
    ];

PrefixedAllocatorTrapStats, QuantizedAllocatorTrapStats: AllocatorTrapStatsRec;

END.