*-----------------------------------------------------------
Title[DMesaAlloc.mc...March 11, 1983  1:33 PM...WSH];
*-----------------------------------------------------------
** version for PILOT only
*-----------------------------------------------------------
** allocating Quantized Node
     rme[mAsz, rcv];
     rme[hcode, residue];
     rme[SzSize, entry];
     rme[szfl, oiPrev0];

** freeing Quantized Node
     rme[zoneIndex, entry];
     rme[szflLo, onStack];
     rme[szflHi, oiPrev1];

** allocating Prefixed Node
     rme[pLengthLo, rcv];
     rme[pLengthHi, residue];
     rme[pSize, entry];
     rme[pfnFirstLo, onStack];
     rme[pfnFirstHi, oiPrev1];
     rme[znpfn, oiPrev0];

** freeing Prefixed Node
     rme[pfnPrevLo, rcv];
     rme[pfnPrevHi, residue];
     rme[pfnLo, entry];
     rme[pfnHi, oiPrev0];
     rme[pfnNextLo, onStack];
     rme[pfnNextHi, oiPrev1];

   top level;
*-----------------------------------------------------------
*
* GetReferentType[ref: REF ANY] RETURNS[Type]
*-----------------------------------------------------------
GetRefType: MiscTable[71];
   Stack&-2, call[getRef];   * T has Stack-1
   Stack-1← T, IFUNext0;

*-----------------------------------------------------------
*
* GetCanonicalReferentType[ref: REF ANY] RETURNS[Type]
*-----------------------------------------------------------
* GetCRefType: MiscTable[72],
*    Stack&-2;
*    call[getRef];   * T has Stack-1
** returns from call with pd← T test
*    branch[.+2, alu#0], membase← gcStateBR;
*    IFUNext0, Stack-1← T;     * nullType
*       knowrbase[gcTemp];
*   gcTemp← T + T + 1;
*   T← (fetch← MapTiTdOffset) + 1, call[loadLPtr];
*    fetch← 0s, T← Stack, call[checkSize];
**  MapTiTd is a SEQUENCE of LONG POINTERs
*   T← (fetch← gcTemp) + 1, call[loadLPtr];
*   fetch← eqvTypeSc;
*   pd← Md;
*    branch[.+2, alu#0];
*    branch[agcTrap], T← 1C;     * not canonicalized yet
*   Stack-1← Md, IFUNext0;

*-----------------------------------------------------------
*
* GetCanonicalReferentType[ref: REF ANY] RETURNS[Type]
*  canonical referenttype is now kept in (ref-1)↑
*-----------------------------------------------------------
   KnowRBase[rTemp0];
GetCRefType: MiscTable[72],
   Stack&-2;
   membase← LPtr, pd← (Stack) OR T;
     branch[.+2, alu#0], pd← Stack;	* Stack is refLo
   		Stack← T, IFUNext0;		* ref was NIL => type 0
   rTemp0← (Stack) - 1, branch[.+2, alu#0];
    T← T - 1;		* T is refHi
   BrLo← rTemp0;
   BrHi← T;
   fetch← 0s;
   rTemp0← Md;
    branch[.+2, R<0], T← (rTemp0) AND (37777C);	* mask for type field
   Stack← T, IFUNext0;
   branch[cats], T← 10C;		* referent on free list
*-----------------------------------------------------------
     subroutine;
getRef:
   rbase← rbase[rcv];   * T has Stack-1
   pd← (Stack) OR (Q← T);    * Q has hi part of Pointer
    branch[.+2, alu#0], membase← GCStateBR, T← Stack&+1;
    T← T - T, return;    * Pointer was NIL => type=nullType=0
   glink← Link;
      top level;

   gcTemp2← T;     * save ptrLo
   T← (fetch← MapPtrMzOffset) + 1, call[loadLPtr];

   T← Q;
   T← RCY[T, gctemp2, qiShift];   * quantumIndex
   gctemp← T, fetch← 0s, call[checkSize];
** size was OK
**  MapPtrMz is a SEQUENCE of one-word items
   T← (gcTemp) + 1;
   fetch← T, T← Q;
   probe← pd← Md;
    branch[subzone, alu<0], pd← gcTemp2;

*-----------------------------------------------------------
* RealZone => RETURN[(ptr-SIZE[Type])↑] where SIZE[Type]=1
* ptr is in T,,gcTemp2
*-----------------------------------------------------------
   gcTemp2← (gcTemp2) - 1, branch[.+2, alu#0];   * pd← gcTemp2
    T← T - 1;    * decrement hi part of ptr if low part = 0
   BrLo← gcTemp2;
   BrHi← T, branch[endGRT];

*-----------------------------------------------------------
* SubZone => RETURN[GetSzType[mz.szi]]
*  which is MapSziSz[SzSize lshift 1 + 1]↑
*-----------------------------------------------------------
subzone:
   membase← gcStateBR, SzSize← Md;
   SzSize← (SzSize) and (77777C);   * mask off hi bit so size check will work
   T← (fetch← MapSziSzOffset) + 1, call[loadLPtr];
    fetch← 0s, T← SzSize, call[checkSize];
**  MapSziSz is a SEQUENCE of LONG POINTERs
   T← (SzSize) + (SzSize) + 1;
   T← (fetch← T) + 1, call[loadLPtr];
endGRT: fetch← 0s;
   link← gLink;
     subroutine;
   gcTemp← Md;
    branch[.+2, R<0], T← (gcTemp) AND (37777C);	* mask for type field
   pd← T, return;
   branch[cats], T← 10C;		* referent on free list

   top level;
*-----------------------------------------------------------
*
* AllocateQuantizedNode[zn:PRealZone, size: CARDINAL, t: Type]
*     RETURNS[ptr: Pointer]
*-----------------------------------------------------------
AllocQNode: MiscTable[73], Stack&-3;
  membase← ScratchBR;
  T← zn.LOCK, call[checkMLock];
**----------- returns with gcTemp holding the Monitor lock
 knowrbase[gcTemp];
   branch[.+2, R even], gcTemp, T← zn.mAsz;
   branch[agcTrap], T← 2C;    * lock was set
** we have the zone
  fetch← T, Stack&+2;
  mAsz← (Md) + (Md);
  mAsz← ((mAsz) + Md) lsh 1;   * hi end of SubZoneArray
  T← (Stack) AND Md;    * forming hash code
  hcode← T + T;   * 2*T
  hcode← ((hcode) + T) lsh 1;     * 6*T  --SubZoneRec is 6 words long
  T← zn.pAsz;
  T← (fetch← T) + 1, call[loadBaseReg];   * overwrite current BR
**  arrive here with StkP pointing to size parameter
 aqLoop:
  T← (sz.vacant) + (hcode);
* ScratchBR has pointer to SubZoneArray
  fetch← T, Stack&+1;
  pd← Md;
   branch[.+2, alu#0], T← (fetch← hcode) + 1;  * fetch← ((sz.type)+(hcode))
   T← 3C, Stack&+1, branch[agcTrap];    * vacant
  pd← (Stack&-1) XOR Md;
   branch[.+2, alu=0], szfl← (fetch← T) + 1;   * fetch← ((sz.size)+(hcode))
    pd← hcode, branch[aqNext];    * types didn't match
  pd← (Stack) XOR Md;
   branch[aqNext, alu#0], pd← hcode;
**------- we have a ptr to allocate, maybe
  T← (fetch← szfl) + 1;   * fetch← ((sz.fl)+(hcode))
  Fetch← T, T← Q← Md;
   pd← T OR (Md), membase← LPtr;
    branch[.+2, alu#0], BrLo← T, gcTemp2← Md;   * branch if FreeList#NIL
    T← 3C, branch[agcTrap];    * vacant
  BrHi← gcTemp2;
** LPtr (gcTemp2,,Q) contains the Pointer to allocate
  T← (fetch← obj.FreeList1) - 1;
  fetch← T, gcTemp← Md;
**  store 0's on top of the old free list
  T← (store← T) + 1, dbuf← 0C;
  T← (store← T) - 1, dbuf← 0C;
** update sz.fl    ** gcTemp(Hi),,Md(Lo) is new FreeList
  membase← ScratchBR, Stack&-1;
  T← (store← szfl) + 1, dbuf← Md;
  store← T, dbuf← gcTemp;
  T← gcTemp2;
  Stack&-1← T;
  Stack&+1← Q, IFUNext0;

 aqNext: T← (Hcode) - (6C), branch[.+2, alu#0];
   T← mAsz;
   hcode← T, b← Md, branch[aqLoop];

*-----------------------------------------------------------
*
* AllocatePrefixedNode[zn:PRealZone, size: CARDINAL, t: Type]
*     RETURNS[ptr: Pointer]
*-----------------------------------------------------------
AllocPNode: MiscTable[74], Stack&-3;
  membase← ScratchBR;
  T← zn.LOCK, call[checkMLock];
**----------- returns with gcTemp holding the Monitor lock
   branch[.+2, R even], gcTemp, T← MinBlockSize;
    branch[agcTrap], T← 2C;    * lock was set
   Stack&+2;
   branch[apn0, R EVEN], pd← (Stack) - T;
   Stack← (Stack) + 1;
    branch[.+3, alu#0];
	  Stack← (Stack) - 1;
     branch[agcTrap], T← 5C;   * size too big
   pd← (Stack) - T;
apn0: branch[.+2, carry], T← (Stack&+1) + (pNodeOverhead);
     pSize← FreeNodeSize, branch[doneSize];
    branch[.+2, carry'], pSize← T;
     branch[agcTrap], T← 5C;   * size too big

doneSize:    * pSize has node size, ScratchBR has zn
   T← znpfn← zn.pfn;
   T← (fetch← T) + 1;
   gcTemp← 100C;
   Cnt← gcTemp;
   fetch← T, pfnFirstLo← Md;
   membase← LPtr, T← Md;
   BrLo← pfnFirstLo;
   pfnFirstHi← BrHi← T;
* LPtr has PFreeNode
 apLoop:
   T← (fetch← pnode.sizeHi) - 1;
   pLengthHi← Md, fetch← T;
  apL2: pLengthHi← (pLengthHi) AND (377C), branch[.+2, R <0];
    branch[cats], T← 5C;     * node on free list is not free
    pd← pLengthHi, T← Md;
   branch[sizeOK, alu#0], T← T - (pSize);  * branch if pLengthHi # 0
    branch[.+2, carry'];   * skip if pSize > pLengthLo
    pLengthLo← T, branch[szOK1];

** this node is too small, check interrupts, count and then try another
**  undate rover pointer in zone
   T← (fetch← pnode.pfnNextHi) - 1;
   pLengthHi← Md, fetch← T;
   membase← ScratchBR, T← (znpfn) + 1;
   T← (store← T) - 1, dbuf← pLengthHi;
   store← T, dbuf← Md, T← Md, branch[.+2, Cnt#0&-1];
    branch[agcTrap], T← 4C;    * looked at 20B nodes
**  check if have gone all the way around a short list
   branch[.+2, ReSchedule'], membase← LPtr;
    branch[MesaReschedTrap];   * priority interrupt
   pd← (BrLo← T) XOR (pfnFirstLo);
    branch[apLoop, alu#0], T← BrHi← pLengthHi;
   pd← T xor (pfnFirstHi);
    branch[.+2, alu=0], T← (fetch← pnode.sizeHi) - 1;
    branch[apL2], pLengthHi← Md, fetch← T;
     branch[agcTrap], T← 3C;    * all the way around
*-----------------------------------------------------------
 sizeOK:
   pLengthLo← T, branch[.+2, carry'];
    branch[splitBlock];    * know plengthHi > 0 => split
   pLengthHi← (pLengthHi) - 1;    * borrow
     branch[splitblock, alu>0];
** pLengthHi,,pLengthLo has length of leftover node
 szOK1:
   pd← (pLengthLo) - (4MinBlockSize);
   branch[.+2, carry'];
    branch[splitBlock];    * need to split the block
* take the whole block off the free list - don't need to change the size
** need to access both next and previous block in linked list before
** taking this node off the chain (page faults)
   T← (fetch← pnode.pfnNext) + 1;
   T← Md, fetch← T;
   membase← BBSrcBR;    * use BitBlt's 2 base registers
   pfnFirstLo← BrLo← T, T← Md;
   pfnFirstHi← BrHi← T;
   T← (fetch← pnode.pfnPrev) + 1;
   T← Md, fetch← T;
   membase← LPtr, b← Md;
   T← (fetch← pnode.pfnPrev) + 1;
   T← Md, fetch← T;
   membase← BBDstBR;
   gcTemp← BrLo← T, T← Md;
   gcTemp2← BrHi← T;
   T← (fetch← pnode.pfnNext) + 1;
   b← Md;
   T← (store← T) - 1, dbuf← pfnFirstHi;
   store← T, dbuf← pfnFirstLo, flipmembase;
   T← (store← pnode.pfnPrev) + 1, dbuf← gcTemp;
   store← T, dbuf← gcTemp2;
*-------- update zn.pfn
   membase← ScratchBR, T← pfnFirstLo;
   T← (store← znpfn) + 1, dbuf← T;
   store← T, dbuf← pfnFirstHi;
*-------- mark the node as inuse by storing the type into pnode.SizeHi field
   membase← LPtr;
   store← pnode.type, dbuf← Stack&-3;
 endPAlloc:
*-------- clear the freeList pointers (can't cause page fault)
   T← A0;
   store← pnode.pfnPrevHi, dbuf← T;
   store← pnode.pfnPrev, dbuf← T;
   store← pnode.pfnNextHi, dbuf← T;
   store← pnode.ref, dbuf← T;		* same as pnode.pfnNext
   gcTemp← Md, T← 377C;	** get memory in good state
   Stack&+1← VaLo;
   Stack← T AND (VaHi), IFUNext0;
*--------- split the block - pLengthHi,,pLengthLo has length of leftover node
*  need to access the part of pnode that will be returned as the new node
** this is to take care of page faults
**  LPtr has the node to allocate from, scratchBR is not needed
 splitBlock:
   fetch← pnode.SizeLo;
   T← VaLo;
   Q← T;
   T← VaHi;
   fetch← pnode.ref;    * page fault insurance
   gcTemp← (pLengthLo) + Q;
   T← T + (pLengthHi), XORSavedCarry;
   pfnFirstHi← T AND (377C);
   membase← ScratchBR;
   BrLo← gcTemp;
   BrHi← pfnFirstHi;
   T← (store← pnode.sizeLo) + 1, dbuf← pSize;
   store← T, dbuf← Stack&-3;   * store type
* must change size of original node
   membase← LPtr;
   store← pnode.sizeLo, dbuf← pLengthLo;
   pLengthHi← (pLengthHi) OR (100000C);		* mark as free
   store← pnode.sizeHi, dbuf← pLengthHi;
   membase← ScratchBR, branch[endPAlloc];

*-----------------------------------------------------------
*
* DoFreeObject[ptr: Pointer]
*-----------------------------------------------------------
FreeObject:  MiscTable[75], Stack&-2;
  call[getRef];
   knowrbase[gcTemp];   * membase unknown, probe has MapQMz entry
  branch[freePN, R>=0], probe;

** subzone => quantized node to be freed, and membase is LPtr
* LPtr points to the subZone, ptr is in Stack-1,,Stack
** need to get the zone and check the monitor lock (sigh)
freeQN: fetch← sz.zi;
  zoneIndex← Md, membase← gcstateBR;
  T← (fetch← MapZiZnOffset) + 1;
  T← Md, fetch← T;
  membase← BBSrcBR, zoneIndex← (zoneIndex) + (zoneIndex) + 1;
  BrLo← T, T← Md;
  BrHi← T;
  T← (fetch← zoneIndex) + 1, call[loadBaseReg];
 freeQN1: fetch← zn.MLOCK;
  gcTemp← Md;
   branch[.+2, R even], gcTemp, membase← LPtr;
    branch[agcTrap], T← 2C;   * lock was set, so take trap

*  LOOPHOLE[ptr, FreeList]↑← sz.fl;
*  sz.fl← ptr;

   T← (fetch← sz.fl) + 1;
   szflLo← Md, fetch← T;
   szflHi← Md, membase← ScratchBR;
   BrHi← Stack&-1;
   BrLo← Stack;
   T← (fetch← obj.FreeList) + 1;
   T← (store← T) - 1, dbuf← szflHi;
   store← T, dbuf← szflLo;
   membase← LPtr;
   T← (store← sz.fl) + 1, dbuf← Stack&+1;
   store← T, dbuf← Stack&-2, IFUNext0CF;

* probe has zn.zi
*  pfn, pfnPrev: PFreeNode;
*  pfnNext: PFreeNode← pfnPrev.pfnNext;
*  pfn.body← free[pfnPrev: pfnPrev, pfnNext: pfnNext];
*  pfnNext.pfnPrev← pfn;
*  pfnPrev.pfnNext← pfn
freePN: membase← GCstateBR, Stack&-1;
   T← (fetch← MapZiZnOffset) + 1, call[loadLPtr];
   fetch← 0s, T← probe, call[checkSize];
   T← (probe) + (probe) + 1;
   T← (fetch← T) + 1, call[loadBaseReg];
 * LPtr now holds the zone, StkP points to ptrLo
   T← pNodeOverhead;    * node+type overhead
freePN1: T← (Stack&+1) - T;   * need to subtract overhead
   pfnLo← pd← T, branch[.+2, carry];
    T← (Stack) - 1, branch[.+2];
    T← Stack;
   pfnHi← T;
 * StkP points to ptrHi, membase is LPtr
   fetch← zn.MLock, Stack&-2;   * don't need StkP anymore
   gcTemp← Md;
    branch[.+2, R even], gcTemp, T← zn.fnd;
     branch[agcTrap], T← 2C;    * zone is locked

* must reference pfnPrev and pfnNext before any stores
* can do stores into pfn, since its neither free nor used
   DummyRef← T, b← Md;
   T← VaLo;
   BrLo← T;
   T← VaHi;
   T← T AND (377C);
   BrHi← T;
* LPtr holds pfnPrev
   T← (fetch← pnode.pfnNext) + 1;
   pfnNextLo← Md, fetch← T;
   pfnNextHi← Md, membase← BBDstBR;
   BrLo← pfnNextLo;
   BrHi← pfnNextHi;
   T← (fetch← pnode.pfnPrev) + 1;
   pfnPrevLo← Md, fetch← T;
   pfnPrevHi← Md, membase← scratchBR;
**  fix up the new free node to be inserted
   BrHi← pfnHi;
   BrLo← pfnLo;
   fetch← pnode.sizeHi;
   pd← Md;
    branch[.+2, alu>=0], T← 6C;
    branch[cats];		* node already on free list
   T← (store← pnode.pfnNext) + 1, dbuf← pfnNextLo;
   store← T, dbuf← pfnNextHi;
   T← (store← pnode.pfnPrev) + 1, dbuf← pfnPrevLo;
   store← T, dbuf← pfnPrevHi;
   T← 100000C;     * mark node as free
   store← pnode.sizeHi, dbuf← T;
   membase← BBDstBR;
   T← (store← pnode.pfnPrev) + 1, dbuf← pfnLo;
   store← T, dbuf← pfnHi;
   membase← LPtr;
   T← (store← pnode.pfnNext) + 1, dbuf← pfnLo;
   store← T, dbuf← pfnHi, IFUNext0CF;
*** debugging
*   membase← scratchBR;
*   fetch← pnode.sizeHi;
*    gcTemp← Md;
*   branch[.+2, r ODD], gcTemp;   * check if inserted node is marked free
*   branch[cats];
*   IFUNext0;
*** debugging
*-----------------------------------------------------------
*
* FreeQuantizedNode[ptr: Pointer, zn:PRealZone]
*-----------------------------------------------------------
FreeQNode:  MiscTable[76], Stack&-3;
  call[getRef], T← Stack&-1;
   knowrbase[gcTemp];   * membase unknown
  Stack&+2, membase← BBSrcBR;
  BrHi← Stack&-1;
  BrLo← Stack&-1, branch[freeQN1];

*-----------------------------------------------------------
*
* FreePrefixedNode[ptr: Pointer, zn:PRealZone]
*-----------------------------------------------------------
FreePNode:  MiscTable[77], Stack&-3;
  call[getRef], T← Stack&-1;
   knowrbase[gcTemp];   * membase unknown
  Stack&+2, membase← LPtr;
  BrHi← Stack&-1;
  BrLo← Stack&-2;  *Lptr holds zone, StkP -> ptrLo
  T← pNodeOverhead, branch[freePN1];   * node overhead

*-----------------------------------------------------------
     subroutine;
*  T← (fetch← xx) + 1, call[loadLPtr]
*-----------------------------------------------------------
loadLPtr:
  T← Md, fetch← T;
  membase← LPtr;
 llpt1: BrLo← T, T← Md;
  BrHi← T, return;

*-----------------------------------------------------------
*  T← (fetch← xx) + 1, call[loadBaseReg]
*-----------------------------------------------------------
loadBaseReg:
  T← Md, fetch← T, branch[llpt1];

*-----------------------------------------------------------
*
*  fetch← 0s, T← xx, call[checkSize]
*-----------------------------------------------------------
checkSize:
  pd← T - Md;
  branch[.+2, alu<0];
   T← 7C, branch[cats];    * bounds fault
  return;
*-----------------------------------------------------------
*  T has offset of word in zone/record to fetch
*  ptr (zone/record) is on top of stack
*  sets rbase to Allocator/Collector region
*
*  membase← xx, T← yy, call[checkMLock]
*-----------------------------------------------------------
checkMLock:
  BrHi← Stack&-1;
  BrLo← Stack;
  fetch← T;
  rbase← rbase[rcv];
  gcTemp← Md, return;
*-----------------------------------------------------------

    top level;

agcTrap: rbase← rbase[RTemp0], global;
  TrapParam← T, branch[MiscOpCodeTrap];